Index: theoraenc.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-base/ext/theora/theoraenc.c,v
retrieving revision 1.63
diff -u -p -r1.63 theoraenc.c
--- theoraenc.c	5 Jun 2007 15:59:00 -0000	1.63
+++ theoraenc.c	7 Jan 2008 09:07:37 -0000
@@ -69,6 +69,15 @@
 #define GST_CAT_DEFAULT theoraenc_debug
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 
+/* With libtheora-1.0beta1 the granulepos scheme was changed:
+ * where earlier the granulepos refered to the index/beginning
+ * of a frame, it now refers to the end, which matches the use
+ * in vorbis/speex. There don't seem to be defines for the
+ * theora version we're compiling against, so we'll just use
+ * a run-time check for now. See theora_enc_get_ogg_packet_end_time().
+ */
+static gboolean use_old_granulepos;
+
 #define GST_TYPE_BORDER_MODE (gst_border_mode_get_type())
 static GType
 gst_border_mode_get_type (void)
@@ -258,6 +267,8 @@ gst_theora_enc_class_init (GstTheoraEncC
 
   gstelement_class->change_state = theora_enc_change_state;
   GST_DEBUG_CATEGORY_INIT (theoraenc_debug, "theoraenc", 0, "Theora encoder");
+
+  use_old_granulepos = (theora_version_number () <= 0x00030200);
 }
 
 static void
@@ -540,6 +551,25 @@ theora_set_header_on_caps (GstCaps * cap
   return caps;
 }
 
+static GstClockTime
+theora_enc_get_ogg_packet_end_time (GstTheoraEnc * enc, ogg_packet * op)
+{
+  ogg_int64_t end_granule;          
+
+  /* FIXME: remove this hack once we depend on libtheora >= 1.0beta1 */
+  if (G_UNLIKELY (use_old_granulepos)) {
+    /* This is where we hack around theora's broken idea of what granulepos
+     * is -- normally we wouldn't need to add the 1, because granulepos
+     * should be the presentation time of the last sample in the packet, but
+     * theora starts with 0 instead of 1... (update: this only applies to old
+     * bitstream/theora versions, this is fixed with bitstream version 3.2.1) */
+    end_granule = granulepos_add (op->granulepos, 1, enc->granule_shift);
+  } else {
+    end_granule = op->granulepos;
+  }
+  return theora_granule_time (&enc->state, end_granule) * GST_SECOND;
+}
+
 static gboolean
 theora_enc_sink_event (GstPad * pad, GstEvent * event)
 {
@@ -554,11 +584,9 @@ theora_enc_sink_event (GstPad * pad, Gst
       if (enc->initialised) {
         /* push last packet with eos flag */
         while (theora_encode_packetout (&enc->state, 1, &op)) {
-          /* See comment in the chain function */
-          GstClockTime next_time = theora_granule_time (&enc->state,
-              granulepos_add (op.granulepos, 1, enc->granule_shift)) *
-              GST_SECOND;
+          GstClockTime next_time;
 
+          next_time = theora_enc_get_ogg_packet_end_time (enc, &op);
           theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts);
           enc->next_ts = next_time;
         }
@@ -887,14 +915,9 @@ theora_enc_chain (GstPad * pad, GstBuffe
 
     ret = GST_FLOW_OK;
     while (theora_encode_packetout (&enc->state, 0, &op)) {
-      /* This is where we hack around theora's broken idea of what granulepos
-         is -- normally we wouldn't need to add the 1, because granulepos
-         should be the presentation time of the last sample in the packet, but
-         theora starts with 0 instead of 1... */
       GstClockTime next_time;
 
-      next_time = theora_granule_time (&enc->state,
-          granulepos_add (op.granulepos, 1, enc->granule_shift)) * GST_SECOND;
+      next_time = theora_enc_get_ogg_packet_end_time (enc, &op);
       ret =
           theora_push_packet (enc, &op, enc->next_ts, next_time - enc->next_ts);
       enc->next_ts = next_time;
