|
Packit |
a38265 |
/*
|
|
Packit |
a38265 |
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
|
|
Packit |
a38265 |
Organisation (CSIRO) Australia
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
Redistribution and use in source and binary forms, with or without
|
|
Packit |
a38265 |
modification, are permitted provided that the following conditions
|
|
Packit |
a38265 |
are met:
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions of source code must retain the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Redistributions in binary form must reproduce the above copyright
|
|
Packit |
a38265 |
notice, this list of conditions and the following disclaimer in the
|
|
Packit |
a38265 |
documentation and/or other materials provided with the distribution.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
- Neither the name of CSIRO Australia nor the names of its
|
|
Packit |
a38265 |
contributors may be used to endorse or promote products derived from
|
|
Packit |
a38265 |
this software without specific prior written permission.
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
a38265 |
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
a38265 |
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
Packit |
a38265 |
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
|
|
Packit |
a38265 |
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
Packit |
a38265 |
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
Packit |
a38265 |
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
Packit |
a38265 |
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
Packit |
a38265 |
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
Packit |
a38265 |
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
Packit |
a38265 |
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "config.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include <stdio.h>
|
|
Packit |
a38265 |
#include <stdlib.h>
|
|
Packit |
a38265 |
#include <string.h>
|
|
Packit |
a38265 |
#include "oggz/oggz.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#include "oggz_tools.h"
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* #define DEBUG */
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
ogg_int64_t delta;
|
|
Packit |
a38265 |
int nr_packets;
|
|
Packit |
a38265 |
} OBTrackData;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
typedef struct {
|
|
Packit |
a38265 |
ogg_int64_t base_units;
|
|
Packit |
a38265 |
OggzTable * tracks;
|
|
Packit |
a38265 |
} OBData;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static ogg_int64_t
|
|
Packit |
a38265 |
_le_64 (ogg_int64_t l)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
ogg_int64_t ret=l;
|
|
Packit |
a38265 |
unsigned char *ucptr = (unsigned char *)&ret;
|
|
Packit |
a38265 |
#ifdef WORDS_BIGENDIAN
|
|
Packit |
a38265 |
unsigned char temp;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
temp = ucptr [0] ;
|
|
Packit |
a38265 |
ucptr [0] = ucptr [7] ;
|
|
Packit |
a38265 |
ucptr [7] = temp ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
temp = ucptr [1] ;
|
|
Packit |
a38265 |
ucptr [1] = ucptr [6] ;
|
|
Packit |
a38265 |
ucptr [6] = temp ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
temp = ucptr [2] ;
|
|
Packit |
a38265 |
ucptr [2] = ucptr [5] ;
|
|
Packit |
a38265 |
ucptr [5] = temp ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
temp = ucptr [3] ;
|
|
Packit |
a38265 |
ucptr [3] = ucptr [4] ;
|
|
Packit |
a38265 |
ucptr [4] = temp ;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
return (*(ogg_int64_t *)ucptr);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#define INT64_LE_AT(x) _le_64((*(ogg_int64_t *)(x)))
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/********** OBTrackData **********/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static OBTrackData *
|
|
Packit |
a38265 |
or_track_data_new (void)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OBTrackData * ort;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ort = malloc (sizeof (OBTrackData));
|
|
Packit |
a38265 |
if (ort == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ort->delta = -1;
|
|
Packit |
a38265 |
ort->nr_packets = 0;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return ort;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
or_track_data_delete (OBTrackData * ort)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
free (ort);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/********** OBData **********/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static OBData *
|
|
Packit |
a38265 |
or_data_new (void)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OBData * ord;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ord = malloc (sizeof (OBData));
|
|
Packit |
a38265 |
if (ord == NULL) return NULL;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ord->base_units = -1;
|
|
Packit |
a38265 |
ord->tracks = oggz_table_new ();
|
|
Packit |
a38265 |
if (ord->tracks == NULL) {
|
|
Packit |
a38265 |
free (ord);
|
|
Packit |
a38265 |
return NULL;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return ord;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
or_data_delete (OBData * ord)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int i, n;
|
|
Packit |
a38265 |
OBTrackData * ort;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
n = oggz_table_size (ord->tracks);
|
|
Packit |
a38265 |
for (i=0; i
|
|
Packit |
a38265 |
ort = oggz_table_nth (ord->tracks, i, NULL);
|
|
Packit |
a38265 |
or_track_data_delete (ort);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
oggz_table_delete (ord->tracks);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/********** checked_fwrite **********/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static void
|
|
Packit |
a38265 |
checked_fwrite (const void *data, size_t size, size_t count, FILE *stream)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
int n = fwrite (data, size, count, stream);
|
|
Packit |
a38265 |
if ((size_t)n != count) {
|
|
Packit |
a38265 |
perror ("write failed");
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/********** Filter **********/
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
filter_page (OGGZ * oggz, const ogg_page * og, long serialno, OBData * ord)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OBTrackData * ort;
|
|
Packit |
a38265 |
ogg_int64_t granulepos, new_granulepos;
|
|
Packit |
a38265 |
ogg_int64_t iframe, pframe;
|
|
Packit |
a38265 |
int granuleshift;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ort = oggz_table_lookup (ord->tracks, serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
granulepos = ogg_page_granulepos ((ogg_page *)og);
|
|
Packit |
a38265 |
granuleshift = oggz_get_granuleshift (oggz, serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
iframe = granulepos >> granuleshift;
|
|
Packit |
a38265 |
pframe = granulepos - (iframe << granuleshift);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
iframe -= ort->delta;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
new_granulepos = (iframe << granuleshift) + pframe;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "old gp %lld, new gp %lld", granulepos, new_granulepos);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
*(ogg_int64_t *)(&og->header[6]) = _le_64(new_granulepos);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, ", totally new gp %lld\n", INT64_LE_AT(&og->header[6]));
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* AFTER making any changes to the page, recalculate the page checksum */
|
|
Packit |
a38265 |
ogg_page_checksum_set ((ogg_page *)og);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
static int
|
|
Packit |
a38265 |
read_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
OBData * ord = (OBData *)user_data;
|
|
Packit |
a38265 |
OBTrackData * ort;
|
|
Packit |
a38265 |
ogg_int64_t gr_n, gr_d;
|
|
Packit |
a38265 |
int numheaders;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (ogg_page_bos ((ogg_page *)og)) {
|
|
Packit |
a38265 |
if ((ort = or_track_data_new ()) == NULL)
|
|
Packit |
a38265 |
return OGGZ_STOP_ERR;
|
|
Packit |
a38265 |
oggz_table_insert (ord->tracks, serialno, ort);
|
|
Packit |
a38265 |
} else {
|
|
Packit |
a38265 |
ort = oggz_table_lookup (ord->tracks, serialno);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "--------\n");
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
numheaders = oggz_stream_get_numheaders (oggz, serialno);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* If this is the first data page of any track, use its timestamp
|
|
Packit |
a38265 |
* as the delta by which to shift all tracks. Hence this page will
|
|
Packit |
a38265 |
* get shifted to timestamp 0, and all other pages in the stream will
|
|
Packit |
a38265 |
* be shifted relatively.
|
|
Packit |
a38265 |
*/
|
|
Packit |
a38265 |
if (ord->base_units == -1 && ort->nr_packets >= numheaders) {
|
|
Packit |
a38265 |
ord->base_units = oggz_tell_units (oggz);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "BASE UNITS: %lld\n", ord->base_units);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* If this is the first data page of a track, calculate the delta
|
|
Packit |
a38265 |
* by which to shift all pages of this track */
|
|
Packit |
a38265 |
if (ord->base_units != -1 && ort->nr_packets >= numheaders && ort->delta == -1) {
|
|
Packit |
a38265 |
oggz_get_granulerate (oggz, serialno, &gr_n, &gr_d);
|
|
Packit |
a38265 |
ort->delta = (ord->base_units * gr_n) / (gr_d);
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "%010lu: DELTA %lld (gr: %lld/%lld)\n",
|
|
Packit |
a38265 |
serialno, ort->delta, gr_n, gr_d);
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
/* header pages have a granulepos 0 and should not have it changed */
|
|
Packit |
a38265 |
if (ogg_page_granulepos ((ogg_page *) og) != 0) {
|
|
Packit |
a38265 |
filter_page (oggz, og, serialno, ord);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ort->nr_packets += ogg_page_packets ((ogg_page *)og);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
#ifdef DEBUG
|
|
Packit |
a38265 |
fprintf (stderr, "%010lu: %d packets, gp %lld\n",
|
|
Packit |
a38265 |
serialno, ort->nr_packets, ogg_page_granulepos ((ogg_page *)og));
|
|
Packit |
a38265 |
#endif
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
checked_fwrite (og->header, 1, og->header_len, stdout);
|
|
Packit |
a38265 |
checked_fwrite (og->body, 1, og->body_len, stdout);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
usage (char * progname)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
printf ("usage: %s filename\n", progname);
|
|
Packit |
a38265 |
printf ("Shift timestamps on all pages such that the stream starts at 0.\n");
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
return 0;
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
int
|
|
Packit |
a38265 |
main (int argc, char ** argv)
|
|
Packit |
a38265 |
{
|
|
Packit |
a38265 |
char * progname = argv[0];
|
|
Packit |
a38265 |
OGGZ * oggz;
|
|
Packit |
a38265 |
OBData * ord;
|
|
Packit |
a38265 |
int ret;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (argc < 2) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
return (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!strncmp (argv[1], "-?", 2)) {
|
|
Packit |
a38265 |
printf ("-h --help\n");
|
|
Packit |
a38265 |
exit (0);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (!strcmp (argv[1], "-h") || !strcmp (argv[1], "--help")) {
|
|
Packit |
a38265 |
usage (progname);
|
|
Packit |
a38265 |
return (0);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ord = or_data_new ();
|
|
Packit |
a38265 |
if (ord == NULL) goto oom;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if ((oggz = oggz_open ((char *)argv[1], OGGZ_READ | OGGZ_AUTO)) == NULL) {
|
|
Packit |
a38265 |
printf ("unable to open file %s\n", argv[1]);
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_set_read_page (oggz, -1, read_page, ord);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
ret = oggz_run (oggz);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oggz_close (oggz);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
or_data_delete (ord);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
if (ret == OGGZ_ERR_STOP_ERR) goto oom;
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
exit (0);
|
|
Packit |
a38265 |
|
|
Packit |
a38265 |
oom:
|
|
Packit |
a38265 |
fprintf (stderr, "%s: out of memory\n", progname);
|
|
Packit |
a38265 |
exit (1);
|
|
Packit |
a38265 |
}
|