From b094df397309ab5a39b7f1cb2fa0c1d7192795d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim-Philipp=20M=C3=BCller?= Date: Mon, 14 Nov 2005 16:00:38 +0000 Subject: [PATCH] ext/ffmpeg/gstffmpegdec.c: Don't crash in debug message by dereferencing the NULL buffer gst_ffmpegdec_frame() gets p... Original commit message from CVS: * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_frame), (gst_ffmpegdec_sink_event): Don't crash in debug message by dereferencing the NULL buffer gst_ffmpegdec_frame() gets passed on EOS. Take STREAM_LOCK for EOS, TAG, NEWSEGMENT and FLUSH_STOP events. --- ChangeLog | 8 + common | 2 +- ext/ffmpeg/gstffmpegdec.c | 384 ++++++++++++++++++++------------------ 3 files changed, 215 insertions(+), 179 deletions(-) diff --git a/ChangeLog b/ChangeLog index d1831360a1..748ebb8715 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2005-11-14 Tim-Philipp Müller + + * ext/ffmpeg/gstffmpegdec.c: (gst_ffmpegdec_frame), + (gst_ffmpegdec_sink_event): + Don't crash in debug message by dereferencing the NULL buffer + gst_ffmpegdec_frame() gets passed on EOS. Take STREAM_LOCK for + EOS, TAG, NEWSEGMENT and FLUSH_STOP events. + 2005-11-11 Thomas Vander Stichele * configure.ac: back to HEAD diff --git a/common b/common index 959da4a43c..657b549dfb 160000 --- a/common +++ b/common @@ -1 +1 @@ -Subproject commit 959da4a43c2e6218eb4f43e8c7e29c1db4157db1 +Subproject commit 657b549dfb640a76f3d7ab7676e453c801a83dca diff --git a/ext/ffmpeg/gstffmpegdec.c b/ext/ffmpeg/gstffmpegdec.c index fc624542bc..65b85e988b 100644 --- a/ext/ffmpeg/gstffmpegdec.c +++ b/ext/ffmpeg/gstffmpegdec.c @@ -51,13 +51,16 @@ struct _GstFFMpegDec AVCodecContext *context; AVFrame *picture; gboolean opened; - union { - struct { + union + { + struct + { gint width, height; gdouble fps, old_fps; enum PixelFormat pix_fmt; } video; - struct { + struct + { gint channels, samplerate; } audio; } format; @@ -70,7 +73,7 @@ struct _GstFFMpegDec GstBuffer *last_buffer; - GValue *par; /* pixel aspect ratio of incoming data */ + GValue *par; /* pixel aspect ratio of incoming data */ gint hurry_up, lowres; }; @@ -119,7 +122,7 @@ static void gst_ffmpegdec_class_init (GstFFMpegDecClass * klass); static void gst_ffmpegdec_init (GstFFMpegDec * ffmpegdec); static void gst_ffmpegdec_dispose (GObject * object); -static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery *query); +static gboolean gst_ffmpegdec_query (GstPad * pad, GstQuery * query); static gboolean gst_ffmpegdec_event (GstPad * pad, GstEvent * event); static gboolean gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps); @@ -305,7 +308,7 @@ gst_ffmpegdec_dispose (GObject * object) } static gboolean -gst_ffmpegdec_query (GstPad * pad, GstQuery *query) +gst_ffmpegdec_query (GstPad * pad, GstQuery * query) { GstFFMpegDec *ffmpegdec; GstPad *peer; @@ -325,8 +328,8 @@ gst_ffmpegdec_query (GstPad * pad, GstQuery *query) #if 0 /* ok, do bitrate calc... */ if ((type != GST_QUERY_POSITION && type != GST_QUERY_TOTAL) || - *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 || - !gst_pad_query (peer, type, &bfmt, value)) + *fmt != GST_FORMAT_TIME || ffmpegdec->context->bit_rate == 0 || + !gst_pad_query (peer, type, &bfmt, value)) return FALSE; if (ffmpegdec->pcache && type == GST_QUERY_POSITION) @@ -347,13 +350,13 @@ gst_ffmpegdec_event (GstPad * pad, GstEvent * event) { GstFFMpegDec *ffmpegdec; GstPad *peer; - + ffmpegdec = (GstFFMpegDec *) GST_PAD_PARENT (pad); peer = GST_PAD_PEER (ffmpegdec->sinkpad); if (!peer) return FALSE; - + gst_event_ref (event); if (gst_pad_send_event (peer, event)) { gst_event_unref (event); @@ -362,11 +365,11 @@ gst_ffmpegdec_event (GstPad * pad, GstEvent * event) gst_event_unref (event); - return FALSE; /* .. */ + return FALSE; /* .. */ } static void -gst_ffmpegdec_close (GstFFMpegDec *ffmpegdec) +gst_ffmpegdec_close (GstFFMpegDec * ffmpegdec) { if (!ffmpegdec->opened) return; @@ -404,7 +407,7 @@ gst_ffmpegdec_close (GstFFMpegDec *ffmpegdec) } static gboolean -gst_ffmpegdec_open (GstFFMpegDec *ffmpegdec) +gst_ffmpegdec_open (GstFFMpegDec * ffmpegdec) { GstFFMpegDecClass *oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); @@ -472,16 +475,15 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps) /* set defaults */ avcodec_get_context_defaults (ffmpegdec->context); - /* set buffer functions */ + /* set buffer functions */ ffmpegdec->context->get_buffer = gst_ffmpegdec_get_buffer; - ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer; - + ffmpegdec->context->release_buffer = gst_ffmpegdec_release_buffer; + /* get size and so */ gst_ffmpeg_caps_with_codecid (oclass->in_plugin->id, oclass->in_plugin->type, caps, ffmpegdec->context); - if (!ffmpegdec->context->time_base.den || - !ffmpegdec->context->time_base.num) { + if (!ffmpegdec->context->time_base.den || !ffmpegdec->context->time_base.num) { GST_DEBUG ("forcing 25/1 framerate"); ffmpegdec->context->time_base.num = 1; ffmpegdec->context->time_base.den = 25; @@ -534,48 +536,47 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture) { GstBuffer *buf = NULL; gulong bufsize = 0; - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; - int width = context->width; + GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; + int width = context->width; int height = context->height; switch (context->codec_type) { case CODEC_TYPE_VIDEO: - - avcodec_align_dimensions(context, &width, &height); - - bufsize = avpicture_get_size (context->pix_fmt, - width, height); - - if((width != context->width) || (height != context->height)) { -#ifdef FORCE_OUR_GET_BUFFER - context->width = width; - context->height = height; -#else - /* revert to ffmpeg's default functions */ - ffmpegdec->context->get_buffer = avcodec_default_get_buffer; - ffmpegdec->context->release_buffer = avcodec_default_release_buffer; - return avcodec_default_get_buffer(context, picture); + avcodec_align_dimensions (context, &width, &height); + + bufsize = avpicture_get_size (context->pix_fmt, width, height); + + if ((width != context->width) || (height != context->height)) { +#ifdef FORCE_OUR_GET_BUFFER + context->width = width; + context->height = height; +#else + /* revert to ffmpeg's default functions */ + ffmpegdec->context->get_buffer = avcodec_default_get_buffer; + ffmpegdec->context->release_buffer = avcodec_default_release_buffer; + + return avcodec_default_get_buffer (context, picture); #endif - - } - - if (!gst_ffmpegdec_negotiate (ffmpegdec)) { - GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), - ("Failed to link ffmpeg decoder to next element")); - return avcodec_default_get_buffer(context, picture); + } - - if (gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, - bufsize, GST_PAD_CAPS (ffmpegdec->srcpad), &buf) != GST_FLOW_OK) + + if (!gst_ffmpegdec_negotiate (ffmpegdec)) { + GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), + ("Failed to link ffmpeg decoder to next element")); + return avcodec_default_get_buffer (context, picture); + } + + if (gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, + bufsize, GST_PAD_CAPS (ffmpegdec->srcpad), &buf) != GST_FLOW_OK) return -1; ffmpegdec->last_buffer = buf; - + gst_ffmpeg_avpicture_fill ((AVPicture *) picture, GST_BUFFER_DATA (buf), context->pix_fmt, context->width, context->height); break; - + case CODEC_TYPE_AUDIO: default: g_assert (0); @@ -603,8 +604,8 @@ gst_ffmpegdec_release_buffer (AVCodecContext * context, AVFrame * picture) { gint i; GstBuffer *buf = GST_BUFFER (picture->opaque); - GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; - + GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) context->opaque; + g_return_if_fail (buf != NULL); g_return_if_fail (picture->type == FF_BUFFER_TYPE_USER); @@ -632,7 +633,7 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec) if (ffmpegdec->format.video.width == ffmpegdec->context->width && ffmpegdec->format.video.height == ffmpegdec->context->height && ffmpegdec->format.video.fps == ffmpegdec->format.video.old_fps && - ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt) + ffmpegdec->format.video.pix_fmt == ffmpegdec->context->pix_fmt) return TRUE; GST_DEBUG ("Renegotiating video from %dx%d@%0.2ffps to %dx%d@%0.2ffps", ffmpegdec->format.video.width, ffmpegdec->format.video.height, @@ -645,7 +646,7 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec) break; case CODEC_TYPE_AUDIO: if (ffmpegdec->format.audio.samplerate == - ffmpegdec->context->sample_rate && + ffmpegdec->context->sample_rate && ffmpegdec->format.audio.channels == ffmpegdec->context->channels) return TRUE; GST_DEBUG ("Renegotiating audio from %dHz@%dchannels to %dHz@%dchannels", @@ -661,40 +662,37 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec) caps = gst_ffmpeg_codectype_to_caps (oclass->in_plugin->type, ffmpegdec->context); - if (caps) { - /* If a demuxer provided a framerate then use it (#313970) */ - if (ffmpegdec->format.video.fps != -1.0) { - gst_structure_set (gst_caps_get_structure (caps, 0), "framerate", - G_TYPE_DOUBLE, ffmpegdec->format.video.fps, NULL); - } + if (caps) { + /* If a demuxer provided a framerate then use it (#313970) */ + if (ffmpegdec->format.video.fps != -1.0) { + gst_structure_set (gst_caps_get_structure (caps, 0), "framerate", + G_TYPE_DOUBLE, ffmpegdec->format.video.fps, NULL); + } - /* Add pixel-aspect-ratio if we have it. Prefer - * ffmpeg PAR over sink PAR (since it's provided - * by the codec, which is more often correct). - */ - if (ffmpegdec->context->sample_aspect_ratio.num && - ffmpegdec->context->sample_aspect_ratio.den) { - GST_DEBUG ("setting ffmpeg provided pixel-aspect-ratio"); - gst_structure_set (gst_caps_get_structure (caps, 0), - "pixel-aspect-ratio", GST_TYPE_FRACTION, - ffmpegdec->context->sample_aspect_ratio.num, - ffmpegdec->context->sample_aspect_ratio.den, - NULL); + /* Add pixel-aspect-ratio if we have it. Prefer + * ffmpeg PAR over sink PAR (since it's provided + * by the codec, which is more often correct). + */ + if (ffmpegdec->context->sample_aspect_ratio.num && + ffmpegdec->context->sample_aspect_ratio.den) { + GST_DEBUG ("setting ffmpeg provided pixel-aspect-ratio"); + gst_structure_set (gst_caps_get_structure (caps, 0), + "pixel-aspect-ratio", GST_TYPE_FRACTION, + ffmpegdec->context->sample_aspect_ratio.num, + ffmpegdec->context->sample_aspect_ratio.den, NULL); } else if (ffmpegdec->par) { GST_DEBUG ("passing on pixel-aspect-ratio from sink"); gst_structure_set (gst_caps_get_structure (caps, 0), "pixel-aspect-ratio", GST_TYPE_FRACTION, - gst_value_get_fraction_numerator (ffmpegdec->par), - gst_value_get_fraction_denominator (ffmpegdec->par), - NULL); + gst_value_get_fraction_numerator (ffmpegdec->par), + gst_value_get_fraction_denominator (ffmpegdec->par), NULL); } } - if (caps == NULL || - !gst_pad_set_caps (ffmpegdec->srcpad, caps)) { + if (caps == NULL || !gst_pad_set_caps (ffmpegdec->srcpad, caps)) { GST_ELEMENT_ERROR (ffmpegdec, CORE, NEGOTIATION, (NULL), ("Failed to link ffmpeg decoder (%s) to next element", - oclass->in_plugin->name)); + oclass->in_plugin->name)); if (caps != NULL) gst_caps_unref (caps); @@ -721,18 +719,18 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, return -1; GST_DEBUG_OBJECT (ffmpegdec, - "data:%p, size:%d, *in_ts:%"GST_TIME_FORMAT" inbuf:%p inbuf.ts:%"GST_TIME_FORMAT, - data, size, GST_TIME_ARGS (*in_ts), inbuf, - GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf))); - + "data:%p, size:%d, *in_ts:%" GST_TIME_FORMAT " inbuf:%p inbuf.ts:%" + GST_TIME_FORMAT, data, size, GST_TIME_ARGS (*in_ts), inbuf, + GST_TIME_ARGS ((inbuf) ? GST_BUFFER_TIMESTAMP (inbuf) : 0)); + ffmpegdec->context->frame_number++; switch (oclass->in_plugin->type) { case CODEC_TYPE_VIDEO: - ffmpegdec->picture->pict_type = -1; /* in case we skip frames */ + ffmpegdec->picture->pict_type = -1; /* in case we skip frames */ ffmpegdec->context->opaque = ffmpegdec; - + len = avcodec_decode_video (ffmpegdec->context, ffmpegdec->picture, &have_data, data, size); GST_DEBUG_OBJECT (ffmpegdec, @@ -742,8 +740,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, if (ffmpegdec->picture->pict_type == FF_I_TYPE) { ffmpegdec->waiting_for_key = FALSE; } else { - GST_WARNING_OBJECT (ffmpegdec, - "Dropping non-keyframe (seek/init)"); + GST_WARNING_OBJECT (ffmpegdec, "Dropping non-keyframe (seek/init)"); have_data = 0; break; } @@ -755,10 +752,10 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, * and keep an internal counter based on FPS for the others. */ if (!(oclass->in_plugin->capabilities & CODEC_CAP_DELAY) || ((ffmpegdec->picture->pict_type == FF_I_TYPE || - !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) && - GST_CLOCK_TIME_IS_VALID (*in_ts))) { - GST_DEBUG_OBJECT (ffmpegdec, "setting next_ts to %"GST_TIME_FORMAT, - GST_TIME_ARGS (*in_ts)); + !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) && + GST_CLOCK_TIME_IS_VALID (*in_ts))) { + GST_DEBUG_OBJECT (ffmpegdec, "setting next_ts to %" GST_TIME_FORMAT, + GST_TIME_ARGS (*in_ts)); ffmpegdec->next_ts = *in_ts; *in_ts = GST_CLOCK_TIME_NONE; } @@ -769,11 +766,12 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, ffmpegdec->synctime = GST_CLOCK_TIME_NONE; } else { GST_WARNING_OBJECT (ffmpegdec, - "Dropping frame for synctime %" GST_TIME_FORMAT ", expected(next_ts) %" - GST_TIME_FORMAT, GST_TIME_ARGS (ffmpegdec->synctime), + "Dropping frame for synctime %" GST_TIME_FORMAT + ", expected(next_ts) %" GST_TIME_FORMAT, + GST_TIME_ARGS (ffmpegdec->synctime), GST_TIME_ARGS (ffmpegdec->next_ts)); - if (ffmpegdec->last_buffer) - gst_buffer_unref(ffmpegdec->last_buffer); + if (ffmpegdec->last_buffer) + gst_buffer_unref (ffmpegdec->last_buffer); have_data = 0; /* don´t break here! Timestamps are updated below */ } @@ -787,45 +785,49 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, * errors inside. This drives me crazy, so we let it allocate * its own buffers and copy to our own buffer afterwards... */ - if (ffmpegdec->picture->opaque != NULL) { - outbuf = (GstBuffer *) ffmpegdec->picture->opaque; + if (ffmpegdec->picture->opaque != NULL) { + outbuf = (GstBuffer *) ffmpegdec->picture->opaque; if (outbuf == ffmpegdec->last_buffer) ffmpegdec->last_buffer = NULL; - } else { - AVPicture pic; - gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt, - ffmpegdec->context->width, ffmpegdec->context->height); + } else { + AVPicture pic; + gint fsize = + gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt, + ffmpegdec->context->width, ffmpegdec->context->height); - if (!gst_ffmpegdec_negotiate (ffmpegdec)) - return -1; - - if ((*ret = gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE, fsize, GST_PAD_CAPS (ffmpegdec->srcpad), &outbuf)) != GST_FLOW_OK) + if (!gst_ffmpegdec_negotiate (ffmpegdec)) return -1; - /* original ffmpeg code does not handle odd sizes correctly. - * This patched up version does */ - gst_ffmpeg_avpicture_fill (&pic, GST_BUFFER_DATA (outbuf), - ffmpegdec->context->pix_fmt, - ffmpegdec->context->width, ffmpegdec->context->height); + if ((*ret = + gst_pad_alloc_buffer (ffmpegdec->srcpad, + GST_BUFFER_OFFSET_NONE, fsize, + GST_PAD_CAPS (ffmpegdec->srcpad), + &outbuf)) != GST_FLOW_OK) + return -1; - /* the original convert function did not do the right thing, this - * is a patched up version that adjust widht/height so that the - * ffmpeg one works correctly. */ - gst_ffmpeg_img_convert (&pic, ffmpegdec->context->pix_fmt, - (AVPicture *) ffmpegdec->picture, - ffmpegdec->context->pix_fmt, - ffmpegdec->context->width, - ffmpegdec->context->height); - } - - ffmpegdec->waiting_for_key = FALSE; + /* original ffmpeg code does not handle odd sizes correctly. + * This patched up version does */ + gst_ffmpeg_avpicture_fill (&pic, GST_BUFFER_DATA (outbuf), + ffmpegdec->context->pix_fmt, + ffmpegdec->context->width, ffmpegdec->context->height); - if (!ffmpegdec->picture->key_frame) { - GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); - } + /* the original convert function did not do the right thing, this + * is a patched up version that adjust widht/height so that the + * ffmpeg one works correctly. */ + gst_ffmpeg_img_convert (&pic, ffmpegdec->context->pix_fmt, + (AVPicture *) ffmpegdec->picture, + ffmpegdec->context->pix_fmt, + ffmpegdec->context->width, ffmpegdec->context->height); + } + + ffmpegdec->waiting_for_key = FALSE; + + if (!ffmpegdec->picture->key_frame) { + GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DELTA_UNIT); + } /* If we have used the framerate from the demuxer then - * also use the demuxer's timestamp information (#317596) */ + * also use the demuxer's timestamp information (#317596) */ if (ffmpegdec->format.video.fps != -1.0 && inbuf != NULL) { gst_buffer_stamp (outbuf, inbuf); } else { @@ -839,36 +841,37 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, /* Take repeat_pict into account */ GST_BUFFER_DURATION (outbuf) += GST_BUFFER_DURATION (outbuf) * ffmpegdec->picture->repeat_pict / 2; - GST_DEBUG_OBJECT (ffmpegdec, "advancing next_ts by duration of %"GST_TIME_FORMAT, - GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); + GST_DEBUG_OBJECT (ffmpegdec, + "advancing next_ts by duration of %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_DURATION (outbuf))); ffmpegdec->next_ts += GST_BUFFER_DURATION (outbuf); } else { ffmpegdec->next_ts = GST_CLOCK_TIME_NONE; } } } else if (ffmpegdec->picture->pict_type != -1 && - oclass->in_plugin->capabilities & CODEC_CAP_DELAY) { + oclass->in_plugin->capabilities & CODEC_CAP_DELAY) { /* update time for skip-frame */ - if ((!have_data) - || (ffmpegdec->picture->pict_type == FF_I_TYPE || - !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) - && GST_CLOCK_TIME_IS_VALID (*in_ts)) { - GST_DEBUG_OBJECT (ffmpegdec, "setting next_ts to *in_ts"); + if ((!have_data) + || (ffmpegdec->picture->pict_type == FF_I_TYPE || + !GST_CLOCK_TIME_IS_VALID (ffmpegdec->next_ts)) + && GST_CLOCK_TIME_IS_VALID (*in_ts)) { + GST_DEBUG_OBJECT (ffmpegdec, "setting next_ts to *in_ts"); ffmpegdec->next_ts = *in_ts; - *in_ts = GST_CLOCK_TIME_NONE; + *in_ts = GST_CLOCK_TIME_NONE; } - + if (ffmpegdec->context->time_base.num != 0 && ffmpegdec->context->time_base.den != 0) { - guint64 dur = GST_SECOND * - ffmpegdec->context->time_base.num / - ffmpegdec->context->time_base.den; + guint64 dur = GST_SECOND * + ffmpegdec->context->time_base.num / + ffmpegdec->context->time_base.den; /* Take repeat_pict into account */ dur += dur * ffmpegdec->picture->repeat_pict / 2; - GST_DEBUG_OBJECT (ffmpegdec, - "Advancing next_ts by dur:%"GST_TIME_FORMAT, - GST_TIME_ARGS (dur)); + GST_DEBUG_OBJECT (ffmpegdec, + "Advancing next_ts by dur:%" GST_TIME_FORMAT, + GST_TIME_ARGS (dur)); ffmpegdec->next_ts += dur; } else { ffmpegdec->next_ts = GST_CLOCK_TIME_NONE; @@ -889,10 +892,10 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, "Decode audio: len=%d, have_data=%d", len, have_data); if (len >= 0 && have_data > 0) { - if (!gst_ffmpegdec_negotiate (ffmpegdec)) { - gst_buffer_unref (outbuf); - return -1; - } + if (!gst_ffmpegdec_negotiate (ffmpegdec)) { + gst_buffer_unref (outbuf); + return -1; + } GST_BUFFER_SIZE (outbuf) = have_data; if (GST_CLOCK_TIME_IS_VALID (*in_ts)) { @@ -916,7 +919,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, g_assert (0); break; } - + if (len < 0 || have_data < 0) { GST_ERROR_OBJECT (ffmpegdec, "ffdec_%s: decoding error (len: %d, have_data: %d)", @@ -928,9 +931,9 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec, return 0; } else { /* this is where I lost my last clue on ffmpeg... */ - *got_data = 1; //(ffmpegdec->pctx || have_data) ? 1 : 0; + *got_data = 1; //(ffmpegdec->pctx || have_data) ? 1 : 0; } - + if (have_data) { GST_DEBUG_OBJECT (ffmpegdec, "Decoded data, now pushing (%" GST_TIME_FORMAT ")", GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (outbuf))); @@ -948,43 +951,65 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) GstFFMpegDec *ffmpegdec = (GstFFMpegDec *) GST_OBJECT_PARENT (pad); GstFFMpegDecClass *oclass = (GstFFMpegDecClass *) (G_OBJECT_GET_CLASS (ffmpegdec)); + gboolean unlock = FALSE; + gboolean ret; - GST_DEBUG_OBJECT (ffmpegdec, - "Handling event of type %d", GST_EVENT_TYPE (event)); + GST_DEBUG_OBJECT (ffmpegdec, "Handling %s event", + GST_EVENT_TYPE_NAME (event)); switch (GST_EVENT_TYPE (event)) { - case GST_EVENT_EOS: + case GST_EVENT_EOS:{ + GST_STREAM_LOCK (pad); + unlock = TRUE; + if (oclass->in_plugin->capabilities & CODEC_CAP_DELAY) { gint have_data, len, try = 0; + do { GstFlowReturn ret; + len = gst_ffmpegdec_frame (ffmpegdec, NULL, 0, &have_data, &ffmpegdec->next_ts, NULL, &ret); if (len < 0 || have_data == 0) break; } while (try++ < 10); } - goto forward; - case GST_EVENT_FLUSH_STOP: + break; + } + case GST_EVENT_TAG:{ + GST_STREAM_LOCK (pad); + unlock = TRUE; + break; + } + case GST_EVENT_FLUSH_STOP:{ + GST_STREAM_LOCK (pad); + unlock = TRUE; + if (ffmpegdec->opened) { avcodec_flush_buffers (ffmpegdec->context); } - goto forward; - case GST_EVENT_NEWSEGMENT: { + break; + } + case GST_EVENT_NEWSEGMENT:{ gint64 base, start, end; gdouble rate; GstFormat fmt; - gst_event_parse_newsegment (event, NULL, &rate, &fmt, &start, &end, &base); + GST_STREAM_LOCK (pad); + unlock = TRUE; + + gst_event_parse_newsegment (event, NULL, &rate, &fmt, &start, &end, + &base); if (fmt == GST_FORMAT_TIME) { ffmpegdec->next_ts = start; - GST_DEBUG_OBJECT (ffmpegdec, "Discont to time (next_ts) %" GST_TIME_FORMAT" -- %"GST_TIME_FORMAT, - GST_TIME_ARGS (start), GST_TIME_ARGS (end)); + GST_DEBUG_OBJECT (ffmpegdec, + "Discont to time (next_ts) %" GST_TIME_FORMAT " -- %" + GST_TIME_FORMAT, GST_TIME_ARGS (start), GST_TIME_ARGS (end)); } else if (ffmpegdec->context->bit_rate && fmt == GST_FORMAT_BYTES) { ffmpegdec->next_ts = start * GST_SECOND / ffmpegdec->context->bit_rate; GST_DEBUG_OBJECT (ffmpegdec, "Newsegment in bytes from byte %" G_GINT64_FORMAT - " (time %" GST_TIME_FORMAT ") to byte % "G_GINT64_FORMAT + " (time %" GST_TIME_FORMAT ") to byte % " G_GINT64_FORMAT " (time %" GST_TIME_FORMAT ")", start, GST_TIME_ARGS (ffmpegdec->next_ts), end, @@ -1009,14 +1034,18 @@ gst_ffmpegdec_sink_event (GstPad * pad, GstEvent * event) } ffmpegdec->waiting_for_key = TRUE; ffmpegdec->synctime = ffmpegdec->next_ts; - /* fall-through */ + break; } default: - forward: - return gst_pad_event_default (ffmpegdec->sinkpad, event); + break; } - return TRUE; + ret = gst_pad_event_default (ffmpegdec->sinkpad, event); + + if (unlock) + GST_STREAM_UNLOCK (pad); + + return ret; } static GstFlowReturn @@ -1032,16 +1061,17 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) if (!ffmpegdec->opened) goto not_negotiated; - + GST_DEBUG_OBJECT (ffmpegdec, - "Received new data of size %d, time %" GST_TIME_FORMAT " next_ts %"GST_TIME_FORMAT, - GST_BUFFER_SIZE (inbuf), GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), - GST_TIME_ARGS (ffmpegdec->next_ts)); + "Received new data of size %d, time %" GST_TIME_FORMAT " next_ts %" + GST_TIME_FORMAT, GST_BUFFER_SIZE (inbuf), + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (inbuf)), + GST_TIME_ARGS (ffmpegdec->next_ts)); /* parse cache joining */ if (ffmpegdec->pcache) { inbuf = gst_buffer_span (ffmpegdec->pcache, 0, inbuf, - GST_BUFFER_SIZE (ffmpegdec->pcache) + GST_BUFFER_SIZE (inbuf)); + GST_BUFFER_SIZE (ffmpegdec->pcache) + GST_BUFFER_SIZE (inbuf)); ffmpegdec->pcache = NULL; bdata = GST_BUFFER_DATA (inbuf); bsize = GST_BUFFER_SIZE (inbuf); @@ -1068,12 +1098,11 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) ffpts = gst_ffmpeg_time_gst_to_ff (in_ts, ffmpegdec->context->time_base); res = av_parser_parse (ffmpegdec->pctx, ffmpegdec->context, - &data, &size, bdata, bsize, - ffpts, ffpts); + &data, &size, bdata, bsize, ffpts, ffpts); GST_DEBUG_OBJECT (ffmpegdec, "Parsed video frame, res=%d, size=%d", res, size); - + in_ts = gst_ffmpeg_time_ff_to_gst (ffmpegdec->pctx->pts, ffmpegdec->context->time_base); if (res == 0 || size == 0) @@ -1088,7 +1117,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) } if ((len = gst_ffmpegdec_frame (ffmpegdec, data, size, - &have_data, &in_ts, inbuf, &ret)) < 0 || ret != GST_FLOW_OK) + &have_data, &in_ts, inbuf, &ret)) < 0 || ret != GST_FLOW_OK) break; if (!ffmpegdec->pctx) { @@ -1101,8 +1130,7 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf) } } while (bsize > 0); - if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) && - bsize > 0) { + if ((ffmpegdec->pctx || oclass->in_plugin->id == CODEC_ID_MP3) && bsize > 0) { GST_DEBUG_OBJECT (ffmpegdec, "Keeping %d bytes of data", bsize); ffmpegdec->pcache = gst_buffer_create_sub (inbuf, @@ -1136,7 +1164,7 @@ gst_ffmpegdec_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_PAUSED_TO_READY: gst_ffmpegdec_close (ffmpegdec); if (ffmpegdec->last_buffer != NULL) { - gst_buffer_unref (ffmpegdec->last_buffer); + gst_buffer_unref (ffmpegdec->last_buffer); ffmpegdec->last_buffer = NULL; } break; @@ -1155,8 +1183,7 @@ gst_ffmpegdec_set_property (GObject * object, switch (prop_id) { case ARG_LOWRES: - ffmpegdec->lowres = ffmpegdec->context->lowres = - g_value_get_enum (value); + ffmpegdec->lowres = ffmpegdec->context->lowres = g_value_get_enum (value); break; case ARG_SKIPFRAME: ffmpegdec->hurry_up = ffmpegdec->context->hurry_up = @@ -1228,8 +1255,7 @@ gst_ffmpegdec_register (GstPlugin * plugin) /* name */ if (!gst_ffmpeg_get_codecid_longname (in_plugin->id)) { - g_warning ("Add decoder %s (%d) please", - in_plugin->name, in_plugin->id); + g_warning ("Add decoder %s (%d) please", in_plugin->name, in_plugin->id); goto next; } @@ -1241,8 +1267,10 @@ gst_ffmpegdec_register (GstPlugin * plugin) srccaps = gst_ffmpeg_codectype_to_caps (in_plugin->type, NULL); } if (!sinkcaps || !srccaps) { - if (sinkcaps) gst_caps_unref (sinkcaps); - if (srccaps) gst_caps_unref (srccaps); + if (sinkcaps) + gst_caps_unref (sinkcaps); + if (srccaps) + gst_caps_unref (srccaps); goto next; } @@ -1280,7 +1308,7 @@ gst_ffmpegdec_register (GstPlugin * plugin) break; case CODEC_ID_WMV3: case CODEC_ID_VC9: - /* what's that? */ + /* what's that? */ case CODEC_ID_SP5X: rank = GST_RANK_NONE; break;