[xiph-commits] r3382 - liboggz/trunk/src/tools

conrad at svn.annodex.net conrad at svn.annodex.net
Thu Jan 24 20:46:41 PST 2008


Author: conrad
Date: 2008-01-24 20:46:31 -0800 (Thu, 24 Jan 2008)
New Revision: 3382

Added:
   liboggz/trunk/src/tools/oggz-sort.c
Modified:
   liboggz/trunk/src/tools/Makefile.am
Log:
add oggz-sort tool: resorts the pages of a file in order or presentation
time (to fix badly muxed files)


Modified: liboggz/trunk/src/tools/Makefile.am
===================================================================
--- liboggz/trunk/src/tools/Makefile.am	2008-01-24 05:43:24 UTC (rev 3381)
+++ liboggz/trunk/src/tools/Makefile.am	2008-01-25 04:46:31 UTC (rev 3382)
@@ -14,7 +14,7 @@
 oggz_read_noinst_programs =
 
 if OGGZ_CONFIG_WRITE
-oggz_rw_programs = oggzmerge oggzrip oggz-validate oggz-comment
+oggz_rw_programs = oggzmerge oggzrip oggz-validate oggz-comment oggz-sort
 oggz_rw_noinst_programs = oggz-basetime
 endif
 
@@ -49,3 +49,7 @@
 
 oggz_scan_SOURCES = oggz-scan.c oggz_tools.c
 oggz_scan_LDADD = $(OGGZ_LIBS)
+
+oggz_sort_SOURCES = oggz-sort.c oggz_tools.c
+oggz_sort_LDADD = $(OGGZ_LIBS)
+

Added: liboggz/trunk/src/tools/oggz-sort.c
===================================================================
--- liboggz/trunk/src/tools/oggz-sort.c	                        (rev 0)
+++ liboggz/trunk/src/tools/oggz-sort.c	2008-01-25 04:46:31 UTC (rev 3382)
@@ -0,0 +1,420 @@
+/*
+   Copyright (C) 2007 Annodex Association
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   - Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+   - Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+   - Neither the name of the Annodex Association nor the names of its
+   contributors may be used to endorse or promote products derived from
+   this software without specific prior written permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+   PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE ASSOCIATION OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <getopt.h>
+#include <errno.h>
+
+#include <oggz/oggz.h>
+#include "oggz_tools.h"
+
+#define READ_SIZE 4096
+
+static void
+usage (char * progname)
+{
+  printf ("Usage: %s [options] filename ...\n", progname);
+  printf ("Resort the pages of an Ogg file in order of presentation time.\n");
+  printf ("\nMiscellaneous options\n");
+  printf ("  -o filename, --output filename\n");
+  printf ("                         Specify output filename\n");
+  printf ("  -h, --help             Display this help and exit\n");
+  printf ("  -v, --version          Output version information and exit\n");
+  printf ("  -V, --verbose          Verbose operation\n");
+  printf ("\n");
+  printf ("Please report bugs to <ogg-dev at xiph.org>\n");
+}
+
+typedef struct _OSData OSData;
+typedef struct _OSInput OSInput;
+typedef struct _OSITrack OSITrack;
+
+struct _OSData {
+  char * infilename;
+  OggzTable * inputs;
+  int verbose;
+};
+
+struct _OSInput {
+  OSData * osdata;
+  OGGZ * reader;
+  long serialno;
+  const ogg_page * og;
+};
+
+struct _OSITrack {
+  long output_serialno;
+};
+
+static ogg_page *
+_ogg_page_copy (const ogg_page * og)
+{
+  ogg_page * new_og;
+
+  new_og = malloc (sizeof (*og));
+  new_og->header = malloc (og->header_len);
+  new_og->header_len = og->header_len;
+  memcpy (new_og->header, og->header, og->header_len);
+  new_og->body = malloc (og->body_len);
+  new_og->body_len = og->body_len;
+  memcpy (new_og->body, og->body, og->body_len);
+
+  return new_og;
+}
+
+static int
+_ogg_page_free (const ogg_page * og)
+{
+  free (og->header);
+  free (og->body);
+  free ((ogg_page *)og);
+  return 0;
+}
+
+static void
+osinput_delete (OSInput * input)
+{
+  oggz_close (input->reader);
+
+  free (input);
+}
+
+static OSData *
+osdata_new (void)
+{
+  OSData * osdata;
+
+  osdata = (OSData *) malloc (sizeof (OSData));
+
+  osdata->inputs = oggz_table_new ();
+  osdata->verbose = 0;
+
+  return osdata;
+}
+
+static void
+osdata_delete (OSData * osdata)
+{
+  OSInput * input;
+  int i, ninputs;
+
+  ninputs = oggz_table_size (osdata->inputs);
+  for (i = 0; i < ninputs; i++) {
+    input = (OSInput *) oggz_table_nth (osdata->inputs, i, NULL);
+    osinput_delete (input);
+  }
+  oggz_table_delete (osdata->inputs);
+
+  free (osdata);
+}
+
+static int
+read_page (OGGZ * oggz, const ogg_page * og, long serialno, void * user_data)
+{
+  OSInput * input = (OSInput *) user_data;
+
+  /* If this is the serialno that this input is tracking, stash it;
+   * otherwise continue scanning the file */
+  if (serialno == input->serialno) {
+    input->og = _ogg_page_copy (og);
+    return OGGZ_STOP_OK;
+  } else {
+    return OGGZ_CONTINUE;
+  }
+}
+
+static int
+read_page_add_input (OGGZ * oggz, const ogg_page * og, long serialno,
+                     void * user_data)
+{
+  OSData * osdata = (OSData *)user_data;
+  OSInput * input;
+  int nfiles;
+
+  if (ogg_page_bos(og)) {
+    input = (OSInput *) malloc (sizeof (OSInput));
+    if (input == NULL) return -1;
+
+    input->osdata = osdata;
+    input->reader = oggz_open (osdata->infilename, OGGZ_READ|OGGZ_AUTO);
+    input->serialno = serialno;
+    input->og = NULL;
+
+    oggz_set_read_page (input->reader, -1, read_page, input);
+
+    nfiles = oggz_table_size (osdata->inputs);
+    if (!oggz_table_insert (osdata->inputs, nfiles++, input)) {
+      osinput_delete (input);
+      return -1;
+    }
+
+    return OGGZ_CONTINUE;
+  } else {
+    return OGGZ_STOP_OK;
+  }
+}
+
+static int
+osdata_add_file (OSData * osdata, char * infilename)
+{
+  OGGZ * reader;
+
+  osdata->infilename = infilename;
+
+  if ((reader = oggz_open (infilename, OGGZ_READ|OGGZ_AUTO)) != NULL) {
+    oggz_set_read_page (reader, -1, read_page_add_input, osdata);
+    oggz_run (reader);
+    oggz_close (reader);
+    return 0;
+  } else {
+    return -1;
+  }
+}
+
+static int
+oggz_sort (OSData * osdata, FILE * outfile)
+{
+  OSInput * input;
+  int ninputs, i, min_i;
+  long key, n;
+  ogg_int64_t units, min_units;
+  const ogg_page * og;
+  int active;
+
+  /* For theora+vorbis, ensure theora bos is first */
+  int careful_for_theora = 0;
+
+  int v;
+
+  if (oggz_table_size (osdata->inputs) == 2)
+    careful_for_theora = 1;
+
+  while ((ninputs = oggz_table_size (osdata->inputs)) > 0) {
+    min_units = -1;
+    min_i = -1;
+    active = 1;
+
+    if (osdata->verbose)
+      printf ("------------------------------------------------------------\n");
+
+    /* Reload all pages, and find the min (earliest) */
+    for (i = 0; active && i < oggz_table_size (osdata->inputs); i++) {
+      input = (OSInput *) oggz_table_nth (osdata->inputs, i, &key);
+      if (input != NULL) {
+	while (input && input->og == NULL) {
+	  n = oggz_read (input->reader, READ_SIZE);
+	  if (n == 0) {
+	    oggz_table_remove (osdata->inputs, key);
+	    osinput_delete (input);
+	    input = NULL;
+	  }
+	}
+	if (input && input->og) {
+	  if (ogg_page_bos ((ogg_page *)input->og)) {
+	    min_i = i;
+
+	    if (careful_for_theora) {
+	      const char * codec_name;
+	      int is_vorbis = 0;
+
+	      if ((codec_name = 
+                  ot_page_identify (input->reader, input->og, NULL)) != NULL)
+		is_vorbis = !strcmp (codec_name, "Vorbis");
+
+	      if (i == 0 && is_vorbis)
+		careful_for_theora = 0;
+	      else
+		active = 0;
+
+	    } else {
+	      active = 0;
+	    }
+          }
+	  units = oggz_tell_units (input->reader);
+
+	  if (osdata->verbose) {
+	    ot_fprint_time (stdout, (double)units/1000);
+	    printf (": Got index %d serialno %010d %lld units: ",
+		    i, ogg_page_serialno ((ogg_page *)input->og), units);
+	  }
+
+	  if (min_units == -1 || units == 0 ||
+	      (units > -1 && units < min_units)) {
+	    min_units = units;
+	    min_i = i;
+	    if (osdata->verbose)
+	      printf ("Min\n");
+	  } else {
+	    if (osdata->verbose)
+	      printf ("Moo\n");
+	  }
+	} else if (osdata->verbose) {
+	  if (input == NULL) {
+	    printf ("*** index %d NULL\n", i);
+	  } else {
+	    printf ("*** No page from index %d\n", i);
+	  }
+	}
+      }
+    }
+
+    if (osdata->verbose)
+      printf ("Min index %d\n", min_i);
+
+    /* Write the earliest page */
+    if (min_i != -1) {
+      input = (OSInput *) oggz_table_nth (osdata->inputs, min_i, &key);
+      og = input->og;
+      fwrite (og->header, 1, og->header_len, outfile);
+      fwrite (og->body, 1, og->body_len, outfile);
+
+      _ogg_page_free (og);
+      input->og = NULL;
+    }
+  }
+
+  return 0;
+}
+
+int
+main (int argc, char * argv[])
+{
+  int show_version = 0;
+  int show_help = 0;
+
+  char * progname;
+  char * infilename = NULL, * outfilename = NULL;
+  FILE * infile = NULL, * outfile = NULL;
+  OSData * osdata;
+  int i;
+
+  ot_init ();
+
+  progname = argv[0];
+
+  if (argc < 2) {
+    usage (progname);
+    return (1);
+  }
+
+  osdata = osdata_new();
+
+  while (1) {
+    char * optstring = "hvVo:";
+
+#ifdef HAVE_GETOPT_LONG
+    static struct option long_options[] = {
+      {"help", no_argument, 0, 'h'},
+      {"version", no_argument, 0, 'v'},
+      {"verbose", no_argument, 0, 'V'},
+      {"output", required_argument, 0, 'o'},
+      {0,0,0,0}
+    };
+
+    i = getopt_long (argc, argv, optstring, long_options, NULL);
+#else
+    i = getopt (argc, argv, optstring);
+#endif
+    if (i == -1) break;
+    if (i == ':') {
+      usage (progname);
+      goto exit_err;
+    }
+
+    switch (i) {
+    case 'h': /* help */
+      show_help = 1;
+      break;
+    case 'v': /* version */
+      show_version = 1;
+      break;
+    case 'o': /* output */
+      outfilename = optarg;
+      break;
+    case 'V': /* verbose */
+      osdata->verbose = 1;
+    default:
+      break;
+    }
+  }
+
+  if (show_version) {
+    printf ("%s version " VERSION "\n", progname);
+  }
+
+  if (show_help) {
+    usage (progname);
+  }
+
+  if (show_version || show_help) {
+    goto exit_ok;
+  }
+
+  if (optind >= argc) {
+    usage (progname);
+    goto exit_err;
+  }
+
+  if (optind >= argc) {
+    usage (progname);
+    goto exit_err;
+  }
+
+  infilename = argv[optind++];
+  osdata_add_file (osdata, infilename);
+
+  if (outfilename == NULL) {
+    outfile = stdout;
+  } else {
+    outfile = fopen (outfilename, "wb");
+    if (outfile == NULL) {
+      fprintf (stderr, "%s: unable to open output file %s\n",
+	       progname, outfilename);
+      goto exit_err;
+    }
+  }
+
+  oggz_sort (osdata, outfile);
+
+ exit_ok:
+  osdata_delete (osdata);
+  exit (0);
+
+ exit_err:
+  osdata_delete (osdata);
+  exit (1);
+}



More information about the commits mailing list