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.
This commit is contained in:
Tim-Philipp Müller 2005-11-14 16:00:38 +00:00
parent b91552ca4a
commit b094df3973
3 changed files with 215 additions and 179 deletions

View file

@ -1,3 +1,11 @@
2005-11-14 Tim-Philipp Müller <tim at centricular dot net>
* 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 <thomas at apestaart dot org>
* configure.ac: back to HEAD

2
common

@ -1 +1 @@
Subproject commit 959da4a43c2e6218eb4f43e8c7e29c1db4157db1
Subproject commit 657b549dfb640a76f3d7ab7676e453c801a83dca

View file

@ -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;
@ -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;
@ -366,7 +369,7 @@ gst_ffmpegdec_event (GstPad * pad, GstEvent * event)
}
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));
@ -480,8 +483,7 @@ gst_ffmpegdec_setcaps (GstPad * pad, GstCaps * caps)
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;
@ -541,12 +543,11 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
switch (context->codec_type) {
case CODEC_TYPE_VIDEO:
avcodec_align_dimensions(context, &width, &height);
avcodec_align_dimensions (context, &width, &height);
bufsize = avpicture_get_size (context->pix_fmt,
width, height);
bufsize = avpicture_get_size (context->pix_fmt, width, height);
if((width != context->width) || (height != context->height)) {
if ((width != context->width) || (height != context->height)) {
#ifdef FORCE_OUR_GET_BUFFER
context->width = width;
context->height = height;
@ -555,7 +556,7 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
ffmpegdec->context->get_buffer = avcodec_default_get_buffer;
ffmpegdec->context->release_buffer = avcodec_default_release_buffer;
return avcodec_default_get_buffer(context, picture);
return avcodec_default_get_buffer (context, picture);
#endif
}
@ -563,7 +564,7 @@ gst_ffmpegdec_get_buffer (AVCodecContext * context, AVFrame * picture)
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);
return avcodec_default_get_buffer (context, picture);
}
if (gst_pad_alloc_buffer (ffmpegdec->srcpad, GST_BUFFER_OFFSET_NONE,
@ -678,20 +679,17 @@ gst_ffmpegdec_negotiate (GstFFMpegDec * ffmpegdec)
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);
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_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));
@ -721,9 +719,9 @@ 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++;
@ -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;
}
@ -757,7 +754,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
((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_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);
gst_buffer_unref (ffmpegdec->last_buffer);
have_data = 0;
/* don´t break here! Timestamps are updated below */
}
@ -793,13 +791,18 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
ffmpegdec->last_buffer = NULL;
} else {
AVPicture pic;
gint fsize = gst_ffmpeg_avpicture_get_size (ffmpegdec->context->pix_fmt,
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 ((*ret =
gst_pad_alloc_buffer (ffmpegdec->srcpad,
GST_BUFFER_OFFSET_NONE, fsize,
GST_PAD_CAPS (ffmpegdec->srcpad),
&outbuf)) != GST_FLOW_OK)
return -1;
/* original ffmpeg code does not handle odd sizes correctly.
@ -814,8 +817,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
gst_ffmpeg_img_convert (&pic, ffmpegdec->context->pix_fmt,
(AVPicture *) ffmpegdec->picture,
ffmpegdec->context->pix_fmt,
ffmpegdec->context->width,
ffmpegdec->context->height);
ffmpegdec->context->width, ffmpegdec->context->height);
}
ffmpegdec->waiting_for_key = FALSE;
@ -839,7 +841,8 @@ 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_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 {
@ -867,7 +870,7 @@ gst_ffmpegdec_frame (GstFFMpegDec * ffmpegdec,
/* Take repeat_pict into account */
dur += dur * ffmpegdec->picture->repeat_pict / 2;
GST_DEBUG_OBJECT (ffmpegdec,
"Advancing next_ts by dur:%"GST_TIME_FORMAT,
"Advancing next_ts by dur:%" GST_TIME_FORMAT,
GST_TIME_ARGS (dur));
ffmpegdec->next_ts += dur;
} else {
@ -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
@ -1034,8 +1063,9 @@ gst_ffmpegdec_chain (GstPad * pad, GstBuffer * inbuf)
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)),
"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 */
@ -1068,8 +1098,7 @@ 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);
@ -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,
@ -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;
}