Bug 480063 - Update liboggz and liboggplay to fix infinite loop bug - rs=roc
authorChris Double <chris.double@double.co.nz>
Wed, 20 May 2009 17:18:17 +1200
changeset 25509 f36ba0a4386438c584b4a77451b034c9f90bdf1c
parent 25508 6a9466041221faf1b912b1599e504e7e3f43c5a9
child 25510 a97dd51a989d2c8eb0c999925d277c044fd7b999
push id1472
push userrocallahan@mozilla.com
push dateWed, 20 May 2009 05:42:12 +0000
reviewersroc
bugs480063
milestone1.9.1b5pre
Bug 480063 - Update liboggz and liboggplay to fix infinite loop bug - rs=roc
media/liboggplay/README_MOZILLA
media/liboggplay/src/liboggplay/oggplay.c
media/liboggplay/trac466.patch
media/liboggplay/update.sh
media/liboggz/AUTHORS
media/liboggz/README
media/liboggz/README_MOZILLA
media/liboggz/include/oggz/config.h
media/liboggz/src/liboggz/metric_internal.c
media/liboggz/src/liboggz/oggz.c
media/liboggz/src/liboggz/oggz_auto.c
media/liboggz/src/liboggz/oggz_byteorder.h
media/liboggz/src/liboggz/oggz_private.h
media/liboggz/src/liboggz/oggz_read.c
media/liboggz/src/liboggz/oggz_seek.c
media/liboggz/update.sh
--- a/media/liboggplay/README_MOZILLA
+++ b/media/liboggplay/README_MOZILLA
@@ -9,8 +9,9 @@ The git commit ID used was b4a7efa06d465
 
 The following local patches have been applied:
 
 bug485291_yuv_align: only use optimized YUV routines if video dimensions are a multiple of the
                      optimized routine's supported alignment.
 
 endian: pick up NSPR's little/big endian defines in oggplay's config.h.
 
+trac466: Fix for infinite loop in liboggplay when running decoder on its own thread.
--- a/media/liboggplay/src/liboggplay/oggplay.c
+++ b/media/liboggplay/src/liboggplay/oggplay.c
@@ -703,24 +703,25 @@ read_more_data:
 
   /*
    * clean the data lists
    */
   for (i = 0; i < me->num_tracks; i++) {
     oggplay_data_clean_list (me->decode_data[i]);
   }
 
+  if (me->shutdown) {
+    return E_OGGPLAY_OK;
+  }
+
   if (info == NULL) {
     goto read_more_data;
   }
 
   me->target += me->callback_period;
-  if (me->shutdown) {
-    return E_OGGPLAY_OK;
-  }
   if (r == -1) {
     return E_OGGPLAY_USER_INTERRUPT;
   }
 
   return E_OGGPLAY_CONTINUE;
 
 }
 
new file mode 100644
--- /dev/null
+++ b/media/liboggplay/trac466.patch
@@ -0,0 +1,23 @@
+diff --git a/media/liboggplay/src/liboggplay/oggplay.c b/media/liboggplay/src/liboggplay/oggplay.c
+index 3296fea..d6256c6 100644
+--- a/media/liboggplay/src/liboggplay/oggplay.c
++++ b/media/liboggplay/src/liboggplay/oggplay.c
+@@ -708,14 +708,15 @@ read_more_data:
+     oggplay_data_clean_list (me->decode_data[i]);
+   }
+ 
++  if (me->shutdown) {
++    return E_OGGPLAY_OK;
++  }
++
+   if (info == NULL) {
+     goto read_more_data;
+   }
+ 
+   me->target += me->callback_period;
+-  if (me->shutdown) {
+-    return E_OGGPLAY_OK;
+-  }
+   if (r == -1) {
+     return E_OGGPLAY_USER_INTERRUPT;
+   }
--- a/media/liboggplay/update.sh
+++ b/media/liboggplay/update.sh
@@ -41,9 +41,9 @@ sed 's/#include <config.h>/#ifdef WIN32\
 #include "config_win32.h"\
 #else\
 #include <config.h>\
 #endif/g' ./src/liboggplay/oggplay_private.h1 >./src/liboggplay/oggplay_private.h
 rm ./src/liboggplay/oggplay_private.h1
 sed s/\#ifdef\ HAVE_INTTYPES_H/\#if\ HAVE_INTTYPES_H/g $1/src/liboggplay/oggplay_data.c >./src/liboggplay/oggplay_data.c
 patch -p3 < bug485291_yuv_align.patch
 patch -p3 < endian.patch
-
+patch -p3 < trac466.patch
--- a/media/liboggz/AUTHORS
+++ b/media/liboggz/AUTHORS
@@ -18,16 +18,19 @@ Tahseen Mohammad
 
 Kangyuan Niu <kangyuan.niu@gmail.com>
         - oggz-comment tool
 
 Ian Malone
         - oggz_comment_generate(), oggz_comment_set_vendor(),
           oggz_packet_destroy(), FLAC header fixes
 
+ogg.k.ogg.k
+	- Kate support, many bugfixes
+
 Mike Smith
         - examples/fix-eos.c, page-level validation in oggz-validate
 
 Ralph Giles <giles@xiph.org>
         - Build system fixes
 
 Erik de Castro Lopo <erikd@mega-nerd.com>
         - compiler flags and warnings
--- a/media/liboggz/README
+++ b/media/liboggz/README
@@ -105,18 +105,18 @@ and mux and demux examples can be read o
     http://www.annodex.net/software/liboggz/html/
 
 oggz tool
 ---------
 
 Usage: oggz <subcommand> [options] filename ...
 
 oggz is a commandline tool for manipulating Ogg files. It supports
-multiplexed files conformant with RFC3533. Oggz can parse headers for
-CELT, CMML, FLAC, Kate, PCM, Speex, Theora and Vorbis, and can read and write
+multiplexed files conformant with RFC3533. Oggz can parse headers for CELT,
+CMML, Dirac, FLAC, Kate, PCM, Speex, Theora and Vorbis, and can read and write
 Ogg Skeleton logical bitstreams.
 
 Commands:
   help          Display help for a specific subcommand (eg. "oggz help chop")
 
 Reporting:
   diff          Hexdump the packets of two Ogg files and output differences.
   dump          Hexdump packets of an Ogg file, or revert an Ogg file from
--- a/media/liboggz/README_MOZILLA
+++ b/media/liboggz/README_MOZILLA
@@ -1,14 +1,14 @@
 The source from this directory was copied from the liboggz git 
 source repository using the update.sh script. The only changes made
 were those applied by update.sh, which applies patches described
 below, and the addition/upate of Makefile.in files for the
 Mozilla build system.
 
-The git commit id used was ef3b0e from git://git.xiph.org/liboggz.git
+The git commit id used was 7df1eb from git://git.xiph.org/liboggz.git
 
 endian.patch is applied to fix bug 452698.
 
 The oggz_off_t.patch fixes a compile error on Solaris see bug 449754
 for details
 
 The wince.patch addresses the lack of posix file IO suppor on windows ce see bug 461844 for details.
--- a/media/liboggz/include/oggz/config.h
+++ b/media/liboggz/include/oggz/config.h
@@ -1,14 +1,17 @@
 /* config.h.  Generated from config.h.in by configure.  */
 /* config.h.in.  Generated from configure.ac by autoheader.  */
 
 /* Define if building universal (internal helper macro) */
 /* #undef AC_APPLE_UNIVERSAL_BUILD */
 
+/* Define if the compiler implements enums as signed values. */
+/* #undef ALLOW_SIGNED_ENUMS */
+
 /* Define to 1 if you have the <dlfcn.h> header file. */
 #define HAVE_DLFCN_H 1
 
 /* Define to 1 if you have the <fcntl.h> header file. */
 #define HAVE_FCNTL_H 1
 
 /* Define to 1 if you have the 'getopt_long' function */
 #define HAVE_GETOPT_LONG /**/
@@ -62,17 +65,17 @@
 
 /* Do not build writing support */
 #define OGGZ_CONFIG_WRITE 1
 
 /* Set to maximum allowed value of sf_count_t type. */
 #define OGGZ_OFF_MAX 0x7FFFFFFFFFFFFFFFLL
 
 /* Define if <ogg/ogg.h> is const-correct */
-/* #undef OGG_H_CONST_CORRECT */
+#define OGG_H_CONST_CORRECT /**/
 
 /* Name of package */
 #define PACKAGE "liboggz"
 
 /* Define to the address where bug reports for this package should be sent. */
 #define PACKAGE_BUGREPORT ""
 
 /* Define to the full name of this package. */
@@ -101,17 +104,17 @@
 
 /* The size of `ssize_t', as computed by sizeof. */
 #define SIZEOF_SSIZE_T 4
 
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
 
 /* Version number of package */
-#define VERSION "0.9.8"
+#define VERSION "0.9.9"
 
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
 #if defined AC_APPLE_UNIVERSAL_BUILD
 # if defined __BIG_ENDIAN__
 #  define WORDS_BIGENDIAN 1
 # endif
 #else
--- a/media/liboggz/src/liboggz/metric_internal.c
+++ b/media/liboggz/src/liboggz/metric_internal.c
@@ -33,16 +33,18 @@
 #ifdef WIN32
 #include "config_win32.h"
 #else
 #include "config.h"
 #endif
 
 #include "oggz_private.h"
 
+#include <oggz/oggz_stream.h>
+
 static ogg_int64_t
 oggz_metric_dirac (OGGZ * oggz, long serialno,
                    ogg_int64_t granulepos, void * user_data)
 {
   oggz_stream_t * stream;
   ogg_int64_t iframe, pframe;
   ogg_uint32_t pt;
   ogg_uint16_t dist;
--- a/media/liboggz/src/liboggz/oggz.c
+++ b/media/liboggz/src/liboggz/oggz.c
@@ -657,13 +657,17 @@ oggz_content_type (OggzStreamContent con
    *   values of all the members of the declaration."
    *
    * -- http://gcc.gnu.org/ml/gcc-bugs/2000-09/msg00271.html
    *
    *  Hence, we cannot remove the (content < 0) guard, even though current
    *  GCC gives a warning for it -- other compilers (including earlier GCC
    *  versions) may use a signed type for enum OggzStreamContent.
    */
-  if (content < 0 || content >= OGGZ_CONTENT_UNKNOWN)
+  if (
+#ifdef ALLOW_SIGNED_ENUMS
+      content < OGGZ_CONTENT_THEORA ||
+#endif
+      content >= OGGZ_CONTENT_UNKNOWN)
     return NULL;
 
   return oggz_auto_codec_ident[content].content_type;
 }
--- a/media/liboggz/src/liboggz/oggz_auto.c
+++ b/media/liboggz/src/liboggz/oggz_auto.c
@@ -59,17 +59,16 @@ int oggz_set_metric_internal (OGGZ * ogg
 			      void * user_data, int internal);
 
 int oggz_set_metric_linear (OGGZ * oggz, long serialno,
 			    ogg_int64_t granule_rate_numerator,
 			    ogg_int64_t granule_rate_denominator);
 
 #define INT16_BE_AT(x) _be_16((*(ogg_int32_t *)(x)))
 #define INT32_LE_AT(x) _le_32((*(ogg_int32_t *)(x)))
-#define INT32_BE_AT(x) _be_32((*(ogg_int32_t *)(x)))
 #define INT64_LE_AT(x) _le_64((*(ogg_int64_t *)(x)))
 
 static int
 oggz_stream_set_numheaders (OGGZ * oggz, long serialno, int numheaders)
 {
   oggz_stream_t * stream;
 
   if (oggz == NULL) return OGGZ_ERR_BAD_OGGZ;
@@ -145,18 +144,18 @@ auto_theora (OGGZ * oggz, long serialno,
   unsigned char * header = data;
   ogg_int32_t fps_numerator, fps_denominator;
   char keyframe_granule_shift = 0;
   int keyframe_shift;
 
   /* TODO: this should check against 42 for the relevant version numbers */
   if (length < 41) return 0;
 
-  fps_numerator = INT32_BE_AT(&header[22]);
-  fps_denominator = INT32_BE_AT(&header[26]);
+  fps_numerator = int32_be_at(&header[22]);
+  fps_denominator = int32_be_at(&header[26]);
 
   /* Very old theora versions used a value of 0 to mean 1.
    * Unfortunately theora hasn't incremented its version field,
    * hence we hardcode this workaround for old or broken streams.
    */
   if (fps_numerator == 0) fps_numerator = 1;
 
 #if USE_THEORA_PRE_ALPHA_3_FORMAT
@@ -264,17 +263,17 @@ auto_flac (OGGZ * oggz, long serialno, u
 static int
 auto_oggpcm2 (OGGZ * oggz, long serialno, unsigned char * data, long length, void * user_data)
 {
   unsigned char * header = data;
   ogg_int64_t granule_rate;
 
   if (length < 28) return 0;
 
-  granule_rate = (ogg_int64_t) INT32_BE_AT(&header[16]);
+  granule_rate = (ogg_int64_t) int32_be_at(&header[16]);
 #ifdef DEBUG
   printf ("Got OggPCM2 rate %d\n", (int)granule_rate);
 #endif
 
   oggz_set_granulerate (oggz, serialno, granule_rate, OGGZ_AUTO_MULT);
 
   oggz_stream_set_numheaders (oggz, serialno, 3);
 
--- a/media/liboggz/src/liboggz/oggz_byteorder.h
+++ b/media/liboggz/src/liboggz/oggz_byteorder.h
@@ -112,9 +112,15 @@ static  ogg_int64_t
   temp = ucptr [3] ;
   ucptr [3] = ucptr [4] ;
   ucptr [4] = temp ;
 
 #endif
   return (*(ogg_int64_t *)ucptr);
 }
 
+static ogg_int32_t
+int32_be_at (unsigned char *c)
+{
+  return (c [0] <<  24) + (c [1] <<  16) + (c [2] <<  8) + c [3] ;
+}
+
 #endif /* __OGGZ_BYTEORDER_H__ */
--- a/media/liboggz/src/liboggz/oggz_private.h
+++ b/media/liboggz/src/liboggz/oggz_private.h
@@ -134,16 +134,17 @@ struct _OggzReader {
   void * read_user_data;
 
   OggzReadPage read_page;
   void * read_page_user_data;
 
   ogg_int64_t current_unit;
   ogg_int64_t current_granulepos;
 
+  long current_page_bytes;
 #if 0
   oggz_off_t offset_page_end; /* offset of end of current page */
 #endif
 };
 
 /**
  * Bundle a packet with the stream it is being queued for; used in
  * the packet_queue vector
--- a/media/liboggz/src/liboggz/oggz_read.c
+++ b/media/liboggz/src/liboggz/oggz_read.c
@@ -85,16 +85,18 @@ oggz_read_init (OGGZ * oggz)
   reader->read_packet = NULL;
   reader->read_user_data = NULL;
 
   reader->read_page = NULL;
   reader->read_page_user_data = NULL;
 
   reader->current_unit = 0;
 
+  reader->current_page_bytes = 0;
+
   return oggz;
 }
 
 OGGZ *
 oggz_read_close (OGGZ * oggz)
 {
   OggzReader * reader = &oggz->x.reader;
 
@@ -182,47 +184,57 @@ oggz_set_read_page (OGGZ * oggz, long se
 static oggz_off_t
 oggz_read_get_next_page (OGGZ * oggz, ogg_page * og)
 {
   OggzReader * reader = &oggz->x.reader;
   long bytes = 0, more;
   oggz_off_t page_offset = 0, ret;
   int found = 0;
 
+  /* Increment oggz->offset by length of the last page processed */
+  oggz->offset += reader->current_page_bytes;
+
   do {
     more = ogg_sync_pageseek (&reader->ogg_sync, og);
 
     if (more == 0) {
+      /* No page available */
       page_offset = 0;
       return -2;
     } else if (more < 0) {
 #ifdef DEBUG_VERBOSE
       printf ("get_next_page: skipped %ld bytes\n", -more);
 #endif
-      page_offset -= more;
+      page_offset += (-more);
+      oggz->offset += (-more);
     } else {
 #ifdef DEBUG_VERBOSE
       printf ("get_next_page: page has %ld bytes\n", more);
 #endif
+      reader->current_page_bytes = more;
       found = 1;
     }
 
   } while (!found);
 
+#if 0 /* This is now done by the increment at the top of the file */
   /* Calculate the byte offset of the page which was found */
   if (bytes > 0) {
     oggz->offset = oggz_io_tell (oggz) - bytes + page_offset;
     ret = oggz->offset;
   } else {
     /* didn't need to do any reading -- accumulate the page_offset */
     ret = oggz->offset + page_offset;
     oggz->offset += page_offset + more;
   }
 
   return ret;
+#else
+  return oggz->offset;
+#endif
 }
 
 typedef struct {
   ogg_packet      packet;
   ogg_int64_t     calced_granulepos;
   oggz_stream_t * stream;
   OggzReader    * reader;
   OGGZ          * oggz;
@@ -359,18 +371,20 @@ oggz_read_sync (OGGZ * oggz)
         /*
          * libogg flags "holes in the data" (which are really inconsistencies
          * in the page sequence number) by returning -1.
          */
         if(result == -1) {
 #ifdef DEBUG
           printf ("oggz_read_sync: hole in the data\n");
 #endif
-          /* We can't tolerate holes in headers, so bail out. */
-          if (stream->packetno < 3) return OGGZ_ERR_HOLE_IN_DATA;
+          /* We can't tolerate holes in headers, so bail out. NB. as stream->packetno
+           * has not yet been incremented, the current value refers to how many packets
+           * have been processed prior to this one. */
+          if (stream->packetno < 2) return OGGZ_ERR_HOLE_IN_DATA;
 
           /* Holes in content occur in some files and pretty much don't matter,
            * so we silently swallow the notification and reget the packet.
            */
           result = ogg_stream_packetout(os, op);
           if (result == -1) {
             /* If the result is *still* -1 then something strange is
              * happening.
--- a/media/liboggz/src/liboggz/oggz_seek.c
+++ b/media/liboggz/src/liboggz/oggz_seek.c
@@ -478,18 +478,16 @@ oggz_scan_for_page (OGGZ * oggz, ogg_pag
       serialno = ogg_page_serialno (og);
       granule_at = ogg_page_granulepos (og);
       unit_at = oggz_get_unit (oggz, serialno, granule_at);
 
       break;
 #else
       do {
         offset_at = oggz_get_prev_start_page(oggz, og, &granule_at, &serialno);
-        if (offset_at == -1)
-          return -1;
         unit_at = oggz_get_unit(oggz, serialno, granule_at);
       } while (unit_at > unit_target);
       return offset_at;
 #endif
     } else if (unit_at == unit_target) {
 #ifdef DEBUG
       printf (" scan: (%lld) == (%lld)\n", unit_at, unit_target);
 #endif
@@ -507,19 +505,25 @@ guess (ogg_int64_t unit_at, ogg_int64_t 
        ogg_int64_t unit_begin, ogg_int64_t unit_end,
        oggz_off_t offset_begin, oggz_off_t offset_end)
 {
   ogg_int64_t guess_ratio;
   oggz_off_t offset_guess;
 
   if (unit_at == unit_begin) return offset_begin;
 
-  guess_ratio =
-    GUESS_MULTIPLIER * (unit_target - unit_begin) /
-    (unit_at - unit_begin);
+  if (unit_end != -1) {
+    guess_ratio =
+      GUESS_MULTIPLIER * (unit_target - unit_begin) /
+      (unit_end - unit_begin);
+  } else {
+    guess_ratio =
+      GUESS_MULTIPLIER * (unit_target - unit_begin) /
+      (unit_at - unit_begin);
+  }
 
 #ifdef DEBUG
   printf ("oggz_seek::guess: guess_ratio %lld = (%lld - %lld) / (%lld - %lld)\n",
 	  guess_ratio, unit_target, unit_begin, unit_at, unit_begin);
 #endif
   
   offset_guess = offset_begin +
     (oggz_off_t)(((offset_end - offset_begin) * guess_ratio) /
@@ -546,19 +550,16 @@ oggz_seek_guess (ogg_int64_t unit_at, og
     printf ("oggz_seek_guess: unit_end <= unit_begin (ERROR)\n");
 #endif
     offset_guess = -1;
   } else {
     offset_guess = guess (unit_at, unit_target, unit_begin, unit_end,
 			  offset_begin, offset_end);
   }
 
-  if (offset_end != -1 && guess >= offset_end)
-    offset_guess = offset_begin + (offset_end - offset_begin)/2;
-
 #ifdef DEBUG
     printf ("oggz_seek_guess: guessed %" PRI_OGGZ_OFF_T "d\n", offset_guess);
 #endif
 
   return offset_guess;
 }
 
 static oggz_off_t
@@ -670,17 +671,26 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t 
   if (offset_at == -1) return -1;
 
   offset_orig = oggz->offset;
 
   offset_begin = 0;
 
   unit_at = reader->current_unit;
   unit_begin = 0;
-  unit_end = -1;
+
+  og = &oggz->current_page;
+
+  if (oggz_seek_raw (oggz, 0, SEEK_END) >= 0) {
+    ogg_int64_t granulepos;
+
+    if (oggz_get_prev_start_page (oggz, og, &granulepos, &serialno) >= 0) {
+      unit_end = oggz_get_unit (oggz, serialno, granulepos);
+    }
+  }
 
   og = &oggz->current_page;
 
   for ( ; ; ) {
 
     unit_last_iter = unit_at;
     hit_eof = 0;
 
@@ -695,16 +705,20 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t 
 				    offset_begin, offset_end);
     if (offset_guess == -1) break;
 
     if (offset_guess == offset_at) {
       /* Already there, looping */
       break;
     }
 
+    if (offset_guess > offset_end) {
+      offset_guess = offset_end;
+    }
+
     offset_at = oggz_seek_raw (oggz, offset_guess, SEEK_SET);
     if (offset_at == -1) {
       goto notfound;
     }
 
     offset_next = oggz_get_next_start_page (oggz, og);
 
 #ifdef DEBUG
@@ -767,18 +781,16 @@ oggz_seek_set (OGGZ * oggz, ogg_int64_t 
     } else {
       break;
     }
   }
 
  found:
   do {
     offset_at = oggz_get_prev_start_page (oggz, og, &granule_at, &serialno);
-    if (offset_at == -1)
-      break;
     unit_at = oggz_get_unit (oggz, serialno, granule_at);
   } while (unit_at > unit_target);
 
   if (offset_at < 0) {
     oggz_reset (oggz, offset_orig, -1, SEEK_SET);
     return -1;
   }
 
--- a/media/liboggz/update.sh
+++ b/media/liboggz/update.sh
@@ -39,11 +39,10 @@ sed s/\#include\ \"config.h\"/\#ifdef\ W
 sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/oggz_vector.c >./src/liboggz/oggz_vector.c
 sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/oggz_seek.c >./src/liboggz/oggz_seek.c
 cp $1/src/liboggz/oggz_dlist.h ./src/liboggz/oggz_dlist.h
 sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/metric_internal.c >./src/liboggz/metric_internal.c
 cp $1/src/liboggz/dirac.h ./src/liboggz/dirac.h
 sed s/\#include\ \"config.h\"/\#ifdef\ WIN32\\n\#include\ \"config_win32.h\"\\n\#else\\n\#include\ \"config.h\"\\n\#endif/g $1/src/liboggz/dirac.c >./src/liboggz/dirac.c
 cp $1/AUTHORS ./AUTHORS
 patch -p3 <endian.patch
-patch -p4 <seek.patch
 patch -p3 <oggz_off_t.patch
 patch -p3 <wince.patch