ext/theora/: Take a 2nd stab at handling libtheora granulepos changes in the decoder and parser by inspecting the bit...

Original commit message from CVS:
* ext/theora/gsttheoradec.h:
* ext/theora/gsttheoraparse.h:
* ext/theora/theoradec.c:
* ext/theora/theoraparse.c:
Take a 2nd stab at handling libtheora granulepos changes in the decoder
and parser by inspecting the bitstream version of the incoming data.
This commit is contained in:
Jan Schmidt 2008-01-14 17:00:03 +00:00
parent 3809775d31
commit 7ff360cea9
5 changed files with 53 additions and 23 deletions

View file

@ -1,3 +1,12 @@
2008-01-14 Jan Schmidt <jan.schmidt@sun.com>
* ext/theora/gsttheoradec.h:
* ext/theora/gsttheoraparse.h:
* ext/theora/theoradec.c:
* ext/theora/theoraparse.c:
Take a 2nd stab at handling libtheora granulepos changes in the decoder
and parser by inspecting the bitstream version of the incoming data.
2008-01-14 Sebastian Dröge <slomo@circular-chaos.org> 2008-01-14 Sebastian Dröge <slomo@circular-chaos.org>
* configure.ac: * configure.ac:

View file

@ -64,6 +64,7 @@ struct _GstTheoraDec
gboolean have_header; gboolean have_header;
gboolean sent_newsegment; gboolean sent_newsegment;
gboolean is_old_bitstream;
guint64 granulepos; guint64 granulepos;
guint64 granule_shift; guint64 granule_shift;

View file

@ -57,6 +57,7 @@ struct _GstTheoraParse {
guint packetno; guint packetno;
gboolean send_streamheader; gboolean send_streamheader;
gboolean streamheader_received; gboolean streamheader_received;
gboolean is_old_bitstream;
GstBuffer * streamheader[3]; GstBuffer * streamheader[3];
GQueue * event_queue; GQueue * event_queue;

View file

@ -51,15 +51,6 @@
#define GST_CAT_DEFAULT theoradec_debug #define GST_CAT_DEFAULT theoradec_debug
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); 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 THEORA_DEF_CROP TRUE #define THEORA_DEF_CROP TRUE
enum enum
{ {
@ -150,8 +141,6 @@ gst_theora_dec_class_init (GstTheoraDecClass * klass)
gstelement_class->change_state = theora_dec_change_state; gstelement_class->change_state = theora_dec_change_state;
GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder"); GST_DEBUG_CATEGORY_INIT (theoradec_debug, "theoradec", 0, "Theora decoder");
use_old_granulepos = (theora_version_number () <= 0x00030200);
} }
static void static void
@ -242,7 +231,7 @@ _theora_granule_frame (GstTheoraDec * dec, gint64 granulepos)
framenum += granulepos - (framenum << ilog); framenum += granulepos - (framenum << ilog);
/* This is 1-based for current libtheora, 0 based for old. Fix up. */ /* This is 1-based for current libtheora, 0 based for old. Fix up. */
if (!use_old_granulepos) if (!dec->is_old_bitstream)
framenum -= 1; framenum -= 1;
GST_DEBUG_OBJECT (dec, "framecount=%d, ilog=%u", framenum, ilog); GST_DEBUG_OBJECT (dec, "framecount=%d, ilog=%u", framenum, ilog);
@ -791,6 +780,7 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
gboolean eret; gboolean eret;
GstEvent *event; GstEvent *event;
guint32 bitstream_version;
GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d", GST_DEBUG_OBJECT (dec, "fps %d/%d, PAR %d/%d",
dec->info.fps_numerator, dec->info.fps_denominator, dec->info.fps_numerator, dec->info.fps_denominator,
@ -841,6 +831,16 @@ theora_handle_type_packet (GstTheoraDec * dec, ogg_packet * packet)
dec->granule_shift = _theora_ilog (dec->info.keyframe_frequency_force - 1); dec->granule_shift = _theora_ilog (dec->info.keyframe_frequency_force - 1);
/* 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. We check the bitstream version from the header so
* we know which way to interpret the incoming granuepos
*/
bitstream_version = (dec->info.version_major << 16) |
(dec->info.version_minor << 8) | dec->info.version_subminor;
dec->is_old_bitstream = (bitstream_version <= 0x00030200);
GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d", GST_DEBUG_OBJECT (dec, "after fixup frame dimension %dx%d, offset %d:%d",
dec->width, dec->height, dec->offset_x, dec->offset_y); dec->width, dec->height, dec->offset_x, dec->offset_y);

View file

@ -313,6 +313,7 @@ theora_parse_set_streamheader (GstTheoraParse * parse)
{ {
GstCaps *caps; GstCaps *caps;
gint i; gint i;
guint32 bitstream_version;
g_assert (!parse->streamheader_received); g_assert (!parse->streamheader_received);
@ -341,6 +342,16 @@ theora_parse_set_streamheader (GstTheoraParse * parse)
parse->fps_d = parse->info.fps_denominator; parse->fps_d = parse->info.fps_denominator;
parse->shift = _theora_ilog (parse->info.keyframe_frequency_force - 1); parse->shift = _theora_ilog (parse->info.keyframe_frequency_force - 1);
/* 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. We check the bitstream version from the header so
* we know which way to interpret the incoming granuepos
*/
bitstream_version = (parse->info.version_major << 16) |
(parse->info.version_minor << 8) | parse->info.version_subminor;
parse->is_old_bitstream = (bitstream_version <= 0x00030200);
parse->streamheader_received = TRUE; parse->streamheader_received = TRUE;
} }
@ -391,28 +402,36 @@ theora_parse_clear_queue (GstTheoraParse * parse)
} }
static gint64 static gint64
make_granulepos (gint64 keyframe, gint64 frame, gint shift) make_granulepos (GstTheoraParse * parse, gint64 keyframe, gint64 frame)
{ {
if (keyframe == -1) if (keyframe == -1)
keyframe = 0; keyframe = 0;
/* If using newer theora, offset the granulepos by +1, see comment
* in theora_parse_set_streamheader */
if (!parse->is_old_bitstream)
keyframe += 1;
g_return_val_if_fail (frame >= keyframe, -1); g_return_val_if_fail (frame >= keyframe, -1);
g_return_val_if_fail (frame - keyframe < 1 << shift, -1); g_return_val_if_fail (frame - keyframe < 1 << parse->shift, -1);
return (keyframe << shift) + (frame - keyframe); return (keyframe << parse->shift) + (frame - keyframe);
} }
static void static void
parse_granulepos (gint64 granulepos, gint shift, gint64 * keyframe, parse_granulepos (GstTheoraParse * parse, gint64 granulepos,
gint64 * frame) gint64 * keyframe, gint64 * frame)
{ {
gint64 kf; gint64 kf;
kf = granulepos >> shift; kf = granulepos >> parse->shift;
/* If using newer theora, offset the granulepos by -1, see comment
* in theora_parse_set_streamheader */
if (!parse->is_old_bitstream)
kf -= 1;
if (keyframe) if (keyframe)
*keyframe = kf; *keyframe = kf;
if (frame) if (frame)
*frame = kf + (granulepos & ((1 << shift) - 1)); *frame = kf + (granulepos & ((1 << parse->shift) - 1));
} }
static gboolean static gboolean
@ -474,7 +493,7 @@ theora_parse_push_buffer (GstTheoraParse * parse, GstBuffer * buf,
next_time = gst_util_uint64_scale_int (GST_SECOND * (frame + 1), next_time = gst_util_uint64_scale_int (GST_SECOND * (frame + 1),
parse->fps_d, parse->fps_n); parse->fps_d, parse->fps_n);
GST_BUFFER_OFFSET_END (buf) = make_granulepos (keyframe, frame, parse->shift); GST_BUFFER_OFFSET_END (buf) = make_granulepos (parse, keyframe, frame);
GST_BUFFER_OFFSET (buf) = this_time; GST_BUFFER_OFFSET (buf) = this_time;
GST_BUFFER_TIMESTAMP (buf) = this_time; GST_BUFFER_TIMESTAMP (buf) = this_time;
GST_BUFFER_DURATION (buf) = next_time - this_time; GST_BUFFER_DURATION (buf) = next_time - this_time;
@ -521,7 +540,7 @@ theora_parse_drain_queue_prematurely (GstTheoraParse * parse)
if (parse->prev_keyframe < 0) { if (parse->prev_keyframe < 0) {
if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) { if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
parse_granulepos (GST_BUFFER_OFFSET_END (buf), parse->shift, parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
&parse->prev_keyframe, NULL); &parse->prev_keyframe, NULL);
} else { } else {
/* No previous keyframe known; can't extract one from this frame. That /* No previous keyframe known; can't extract one from this frame. That
@ -550,7 +569,7 @@ theora_parse_drain_queue (GstTheoraParse * parse, gint64 granulepos)
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
gint64 keyframe, prev_frame, frame; gint64 keyframe, prev_frame, frame;
parse_granulepos (granulepos, parse->shift, &keyframe, &frame); parse_granulepos (parse, granulepos, &keyframe, &frame);
prev_frame = frame - g_queue_get_length (parse->buffer_queue); prev_frame = frame - g_queue_get_length (parse->buffer_queue);
if (prev_frame < parse->prev_frame) { if (prev_frame < parse->prev_frame) {
@ -606,7 +625,7 @@ theora_parse_queue_buffer (GstTheoraParse * parse, GstBuffer * buf)
if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) { if (GST_BUFFER_OFFSET_END_IS_VALID (buf)) {
if (parse->prev_keyframe < 0) { if (parse->prev_keyframe < 0) {
parse_granulepos (GST_BUFFER_OFFSET_END (buf), parse->shift, parse_granulepos (parse, GST_BUFFER_OFFSET_END (buf),
&parse->prev_keyframe, NULL); &parse->prev_keyframe, NULL);
} }
ret = theora_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf)); ret = theora_parse_drain_queue (parse, GST_BUFFER_OFFSET_END (buf));