[xiph-commits] r3526 - liboggz/trunk/src/tools/oggz-chop

conrad at svn.annodex.net conrad at svn.annodex.net
Wed Mar 26 15:30:40 PDT 2008


Author: conrad
Date: 2008-03-26 15:30:39 -0700 (Wed, 26 Mar 2008)
New Revision: 3526

Modified:
   liboggz/trunk/src/tools/oggz-chop/oggz-chop.c
   liboggz/trunk/src/tools/oggz-chop/oggz-chop.h
Log:
oggz-chop: when chopping files with multiple granuleshift tracks (eg.
multiple video tracks), merge the pages before the cut point. Tested with
multiple Theora tracks, output passes oggz-validate.


Modified: liboggz/trunk/src/tools/oggz-chop/oggz-chop.c
===================================================================
--- liboggz/trunk/src/tools/oggz-chop/oggz-chop.c	2008-03-26 21:20:37 UTC (rev 3525)
+++ liboggz/trunk/src/tools/oggz-chop/oggz-chop.c	2008-03-26 22:30:39 UTC (rev 3526)
@@ -35,11 +35,28 @@
 #include <string.h>
 #include <getopt.h>
 #include <errno.h>
+#include <math.h>
 
 #include <oggz/oggz.h>
 
 #include "oggz-chop.h"
 
+/************************************************************
+ * OCTrackState
+ */
+
+typedef struct _OCTrackState {
+  OggzTable * page_accum;
+
+  int headers_remaining;
+
+  long start_granule;
+
+  /* Greatest previously inferred keyframe value */
+  ogg_int64_t prev_keyframe;
+
+} OCTrackState;
+
 static OCTrackState *
 track_state_new (void)
 {
@@ -48,7 +65,6 @@
   ts = (OCTrackState *) malloc (sizeof(*ts));
 
   memset (ts, 0, sizeof(*ts));
-  ts->page_accum = oggz_table_new();
 
   return ts;
 }
@@ -130,6 +146,51 @@
 }
 
 /************************************************************
+ * OCPageAccum
+ */
+
+typedef struct _OCPageAccum {
+  ogg_page * og;
+  double time;
+} OCPageAccum;
+
+static OCPageAccum *
+page_accum_new (ogg_page * og, double time)
+{
+  OCPageAccum * pa;
+
+  pa = malloc(sizeof (*pa));
+  pa->og = _ogg_page_copy (og);
+  pa->time = time;
+
+  return pa;
+}
+
+static void
+page_accum_delete (OCPageAccum * pa)
+{
+  if (pa == NULL) return;
+
+  _ogg_page_free (pa->og);
+  free (pa);
+}
+
+static void
+track_state_remove_page_accum (OCTrackState * ts)
+{
+  int i, accum_size;
+
+  if (ts == NULL || ts->page_accum == NULL) return;
+
+  accum_size = oggz_table_size (ts->page_accum);
+
+  for (i = accum_size; i >= 0; i--) {
+    page_accum_delete((OCPageAccum *)oggz_table_lookup (ts->page_accum, i));
+    oggz_table_remove (ts->page_accum, (long)i);
+  }
+}
+
+/************************************************************
  * chop
  */
 
@@ -170,6 +231,91 @@
   return OGGZ_CONTINUE;
 }
 
+static int
+write_accum (OCState * state)
+{
+  OCTrackState * ts;
+  OCPageAccum * pa;
+  OggzTable * candidates;
+  long serialno, min_serialno;
+  int i, ntracks, ncandidates=0, remaining=0, min_i, cn, min_cn;
+  ogg_page * og, * min_og;
+  double min_time;
+
+  if (state->written_accum) return -1;
+
+  /*
+   * We create a table of candidate tracks, which are all those which
+   * have a page_accum table, ie. for which granuleshift matters.
+   * We insert into this table the index of the next page_accum element
+   * to be merged for that track. All start at 0.
+   * The variable 'remaining' counts down the total number of accumulated
+   * pages to be written from all candidate tracks.
+   */
+
+  /* Prime candidates */
+  candidates = oggz_table_new ();
+  ntracks = oggz_table_size (state->tracks);
+  for (i=0; i < ntracks; i++) {
+    ts = oggz_table_nth (state->tracks, i, &serialno);
+    if (ts != NULL && ts->page_accum != NULL) {
+      ncandidates++;
+      /* XXX: we offset the candidate index by 7 to avoid storing 0, as
+       * OggzTable treats insertion of NULL as a deletion */
+      oggz_table_insert (candidates, serialno, (void *)0x7);
+      remaining += oggz_table_size (ts->page_accum);
+    }
+  }
+
+  /* Merge candidates */
+  while (remaining > 0) {
+    /* Find minimum page in all accum buffers */
+    min_time = 10e100;
+    min_cn = -1;
+    min_og = NULL;
+    min_serialno = -1;
+    for (i=0; i < ncandidates; i++) {
+      cn = ((int) oggz_table_nth (candidates, i, &serialno)) - 7;
+      ts = oggz_table_lookup (state->tracks, serialno);
+      if (ts && ts->page_accum) {
+        if (cn < oggz_table_size (ts->page_accum)) {
+          pa = oggz_table_nth (ts->page_accum, cn, NULL);
+
+          if (pa->time < min_time) {
+            min_i = i;
+            min_cn = cn;
+            min_og = pa->og;
+            min_serialno = serialno;
+            min_time = pa->time;
+          }
+        }
+      }
+    }
+
+    if (min_og) {
+      /* Increment index for minimum page */
+      oggz_table_insert (candidates, min_serialno, (void *)(min_cn+1+7));
+
+      /* Write out minimum page */
+      fwrite_ogg_page (state->outfile, min_og);
+    }
+
+    remaining--;
+  }
+
+  /* Cleanup */
+  for (i=0; i < ntracks; i++) {
+    ts = oggz_table_nth (state->tracks, i, &serialno);
+    track_state_remove_page_accum (ts);
+  }
+
+  oggz_table_delete (candidates);
+
+  state->written_accum = 1;
+ 
+  return 0;
+}
+
 /*
  * OggzReadPageCallback read_gs
  *
@@ -180,6 +326,7 @@
 {
   OCState * state = (OCState *)user_data;
   OCTrackState * ts;
+  OCPageAccum * pa;
   double page_time;
   ogg_int64_t granulepos, keyframe;
   int granuleshift, i, accum_size;
@@ -192,13 +339,7 @@
 
   if (page_time >= state->start) {
     /* Write out accumulated pages */
-    for (i = 0; i < accum_size; i++) {
-      accum_og = (ogg_page *)oggz_table_lookup (ts->page_accum, i);
-      fwrite_ogg_page (state->outfile, accum_og);
-      _ogg_page_free (accum_og);
-    }
-    oggz_table_delete (ts->page_accum);
-    ts->page_accum = NULL;
+    write_accum (state);
 
     /* Switch to the plain page reader */
     oggz_set_read_page (oggz, serialno, read_plain, state);
@@ -212,10 +353,13 @@
 
     if (keyframe != ts->prev_keyframe) {
       /* Clear the page accumulator */
+      track_state_remove_page_accum (ts);
+#if 0
       for (i = accum_size; i >= 0; i--) {
-        _ogg_page_free ((ogg_page *)oggz_table_lookup (ts->page_accum, i));
+        page_accum_delete((OCPageAccum *)oggz_table_lookup (ts->page_accum, i));
         oggz_table_remove (ts->page_accum, (long)i);
       }
+#endif
       accum_size = 0;
 
       /* Record this as prev_keyframe */
@@ -224,7 +368,8 @@
   }
 
   /* Add a copy of this to the page accumulator */
-  oggz_table_insert (ts->page_accum, accum_size, _ogg_page_copy (og));
+  pa = page_accum_new (og, page_time);
+  oggz_table_insert (ts->page_accum, accum_size, pa);
 
   return OGGZ_CONTINUE;
 }
@@ -249,6 +394,7 @@
     if (state->start == 0.0 || oggz_get_granuleshift (oggz, serialno) == 0) {
       oggz_set_read_page (oggz, serialno, read_plain, state);
     } else {
+      ts->page_accum = oggz_table_new();
       oggz_set_read_page (oggz, serialno, read_gs, state);
     }
   }
@@ -283,6 +429,7 @@
   OGGZ * oggz;
 
   state->tracks = oggz_table_new ();
+  state->written_accum = 0;
 
   if (strcmp (state->infilename, "-") == 0) {
     oggz = oggz_open_stdio (stdin, OGGZ_READ|OGGZ_AUTO);

Modified: liboggz/trunk/src/tools/oggz-chop/oggz-chop.h
===================================================================
--- liboggz/trunk/src/tools/oggz-chop/oggz-chop.h	2008-03-26 21:20:37 UTC (rev 3525)
+++ liboggz/trunk/src/tools/oggz-chop/oggz-chop.h	2008-03-26 22:30:39 UTC (rev 3526)
@@ -47,24 +47,11 @@
 
   double start;
   double end;
+
+  int written_accum;
 } OCState;
 
-/************************************************************
- * OCTrackState
- */
 
-typedef struct _OCTrackState {
-  OggzTable * page_accum;
-
-  int headers_remaining;
-
-  long start_granule;
-
-  /* Greatest previously inferred keyframe value */
-  ogg_int64_t prev_keyframe;
-
-} OCTrackState;
-
 int chop (OCState * state);
 
 #endif /* __OGGZ_CHOP_H__ */



More information about the commits mailing list