ext/ffmpeg/gstffmpegmux.c: Only set the mux->opened flag after we've successfully written the header. This way we don...

Original commit message from CVS:
* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_request_new_pad),
(gst_ffmpegmux_setcaps), (gst_ffmpegmux_collected):
Only set the mux->opened flag after we've successfully written the
header. This way we don't crash in mysterious ways if we can't write
the header for some reason (e.g. due to having accepted caps the
format doesn't really allow), then return a GST_FLOW_ERROR, and
then still receive another buffer afterwards despite having previously
returned FLOW_ERROR (#403168).
Also some minor logging improvements.
This commit is contained in:
Tim-Philipp Müller 2007-02-09 16:17:50 +00:00
parent 5ad0d8bfee
commit a23114785a
3 changed files with 83 additions and 64 deletions

View file

@ -1,3 +1,15 @@
2007-02-09 Tim-Philipp Müller <tim at centricular dot net>
* ext/ffmpeg/gstffmpegmux.c: (gst_ffmpegmux_request_new_pad),
(gst_ffmpegmux_setcaps), (gst_ffmpegmux_collected):
Only set the mux->opened flag after we've successfully written the
header. This way we don't crash in mysterious ways if we can't write
the header for some reason (e.g. due to having accepted caps the
format doesn't really allow), then return a GST_FLOW_ERROR, and
then still receive another buffer afterwards despite having previously
returned FLOW_ERROR (#403168).
Also some minor logging improvements.
2007-01-26 Wim Taymans <wim@fluendo.com> 2007-01-26 Wim Taymans <wim@fluendo.com>
Patch by: Mark Nauwelaerts <manauw@skynet.be> Patch by: Mark Nauwelaerts <manauw@skynet.be>

2
common

@ -1 +1 @@
Subproject commit 8ba5dffb5ee7e7daea1030f6b34bfef10f9801a3 Subproject commit de43a8f3c629983e0bea0b8eb617e52ed35a6cda

View file

@ -59,9 +59,9 @@ struct _GstFFMpegMux
gint videopads, audiopads; gint videopads, audiopads;
/*< private >*/ /*< private > */
/* event_function is the collectpads default eventfunction */ /* event_function is the collectpads default eventfunction */
GstPadEventFunction event_function; GstPadEventFunction event_function;
}; };
typedef struct _GstFFMpegMuxClassParams typedef struct _GstFFMpegMuxClassParams
@ -107,13 +107,15 @@ static GHashTable *global_plugins;
/* A number of functon prototypes are given so we can refer to them later. */ /* A number of functon prototypes are given so we can refer to them later. */
static void gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass); static void gst_ffmpegmux_class_init (GstFFMpegMuxClass * klass);
static void gst_ffmpegmux_base_init (gpointer g_class); static void gst_ffmpegmux_base_init (gpointer g_class);
static void gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux, GstFFMpegMuxClass * g_class); static void gst_ffmpegmux_init (GstFFMpegMux * ffmpegmux,
GstFFMpegMuxClass * g_class);
static void gst_ffmpegmux_finalize (GObject * object); static void gst_ffmpegmux_finalize (GObject * object);
static gboolean gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps); static gboolean gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps);
static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element, static GstPad *gst_ffmpegmux_request_new_pad (GstElement * element,
GstPadTemplate * templ, const gchar * name); GstPadTemplate * templ, const gchar * name);
static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data); static GstFlowReturn gst_ffmpegmux_collected (GstCollectPads * pads,
gpointer user_data);
static gboolean gst_ffmpegmux_sink_event (GstPad * pad, GstEvent * event); static gboolean gst_ffmpegmux_sink_event (GstPad * pad, GstEvent * event);
@ -265,20 +267,22 @@ gst_ffmpegmux_request_new_pad (GstElement * element,
/* create pad */ /* create pad */
pad = gst_pad_new_from_template (templ, padname); pad = gst_pad_new_from_template (templ, padname);
collect_pad = (GstFFMpegMuxPad *) collect_pad = (GstFFMpegMuxPad *)
gst_collect_pads_add_pad (ffmpegmux->collect, pad, sizeof (GstFFMpegMuxPad)); gst_collect_pads_add_pad (ffmpegmux->collect, pad,
sizeof (GstFFMpegMuxPad));
collect_pad->padnum = ffmpegmux->context->nb_streams; collect_pad->padnum = ffmpegmux->context->nb_streams;
/* small hack to put our own event pad function and chain up to collect pad */ /* small hack to put our own event pad function and chain up to collect pad */
ffmpegmux->event_function = GST_PAD_EVENTFUNC(pad); ffmpegmux->event_function = GST_PAD_EVENTFUNC (pad);
gst_pad_set_event_function (pad, gst_ffmpegmux_sink_event); gst_pad_set_event_function (pad,
GST_DEBUG_FUNCPTR (gst_ffmpegmux_sink_event));
gst_pad_set_setcaps_function (pad, gst_ffmpegmux_setcaps); gst_pad_set_setcaps_function (pad, GST_DEBUG_FUNCPTR (gst_ffmpegmux_setcaps));
gst_element_add_pad (element, pad); gst_element_add_pad (element, pad);
/* AVStream needs to be created */ /* AVStream needs to be created */
st = av_new_stream (ffmpegmux->context, collect_pad->padnum); st = av_new_stream (ffmpegmux->context, collect_pad->padnum);
st->codec->codec_type = type; st->codec->codec_type = type;
st->codec->codec_id = CODEC_ID_NONE; /* this is a check afterwards */ st->codec->codec_id = CODEC_ID_NONE; /* this is a check afterwards */
st->stream_copy = 1; /* we're not the actual encoder */ st->stream_copy = 1; /* we're not the actual encoder */
st->codec->bit_rate = bitrate; st->codec->bit_rate = bitrate;
st->codec->frame_size = framesize; st->codec->frame_size = framesize;
@ -315,9 +319,11 @@ gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps)
/* for the format-specific guesses, we'll go to /* for the format-specific guesses, we'll go to
* our famous codec mapper */ * our famous codec mapper */
if (gst_ffmpeg_caps_to_codecid (caps, st->codec) != CODEC_ID_NONE) { if (gst_ffmpeg_caps_to_codecid (caps, st->codec) != CODEC_ID_NONE) {
GST_LOG_OBJECT (pad, "accepted caps %" GST_PTR_FORMAT, caps);
return TRUE; return TRUE;
} }
GST_LOG_OBJECT (pad, "rejecting caps %" GST_PTR_FORMAT, caps);
return FALSE; return FALSE;
} }
@ -325,21 +331,21 @@ gst_ffmpegmux_setcaps (GstPad * pad, GstCaps * caps)
static gboolean static gboolean
gst_ffmpegmux_sink_event (GstPad * pad, GstEvent * event) gst_ffmpegmux_sink_event (GstPad * pad, GstEvent * event)
{ {
GstFFMpegMux * ffmpegmux = (GstFFMpegMux*) gst_pad_get_parent(pad); GstFFMpegMux *ffmpegmux = (GstFFMpegMux *) gst_pad_get_parent (pad);
gboolean res = TRUE; gboolean res = TRUE;
switch (GST_EVENT_TYPE (event)) { switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_TAG: { case GST_EVENT_TAG:{
GstTagList * taglist = NULL; GstTagList *taglist = NULL;
gst_event_parse_tag (event, &taglist); gst_event_parse_tag (event, &taglist);
ffmpegmux->tags = gst_tag_list_merge(ffmpegmux->tags, taglist, ffmpegmux->tags = gst_tag_list_merge (ffmpegmux->tags, taglist,
GST_TAG_MERGE_PREPEND); GST_TAG_MERGE_PREPEND);
break; break;
} }
default: default:
break; break;
} }
/* chaining up to collectpads default event function */ /* chaining up to collectpads default event function */
@ -379,31 +385,31 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
} }
/* set framerate for audio */ /* set framerate for audio */
if (st->codec->codec_type == CODEC_TYPE_AUDIO) { if (st->codec->codec_type == CODEC_TYPE_AUDIO) {
switch (st->codec->codec_id) { switch (st->codec->codec_id) {
case CODEC_ID_PCM_S16LE: case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S16BE: case CODEC_ID_PCM_S16BE:
case CODEC_ID_PCM_U16LE: case CODEC_ID_PCM_U16LE:
case CODEC_ID_PCM_U16BE: case CODEC_ID_PCM_U16BE:
case CODEC_ID_PCM_S8: case CODEC_ID_PCM_S8:
case CODEC_ID_PCM_U8: case CODEC_ID_PCM_U8:
st->codec->frame_size = 1; st->codec->frame_size = 1;
break; break;
default: default:
{ {
GstBuffer *buffer; GstBuffer *buffer;
/* FIXME : This doesn't work for RAW AUDIO... /* FIXME : This doesn't work for RAW AUDIO...
* in fact I'm wondering if it even works for any kind of audio... */ * in fact I'm wondering if it even works for any kind of audio... */
buffer = gst_collect_pads_peek (ffmpegmux->collect, buffer = gst_collect_pads_peek (ffmpegmux->collect,
(GstCollectData *)collect_pad); (GstCollectData *) collect_pad);
if (buffer) { if (buffer) {
st->codec->frame_size = st->codec->frame_size =
st->codec->sample_rate * st->codec->sample_rate *
GST_BUFFER_DURATION (buffer) / GST_SECOND; GST_BUFFER_DURATION (buffer) / GST_SECOND;
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
} }
} }
} }
} }
} }
@ -415,7 +421,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
gchar *s; gchar *s;
tags = gst_tag_list_merge (iface_tags, ffmpegmux->tags, tags = gst_tag_list_merge (iface_tags, ffmpegmux->tags,
GST_TAG_MERGE_APPEND); GST_TAG_MERGE_APPEND);
/* get the interesting ones */ /* get the interesting ones */
if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) { if (gst_tag_list_get_string (tags, GST_TAG_TITLE, &s)) {
@ -449,8 +455,8 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
} }
/* set the streamheader flag for gstffmpegprotocol if codec supports it */ /* set the streamheader flag for gstffmpegprotocol if codec supports it */
if (!strcmp (ffmpegmux->context->oformat->name, "flv") ) { if (!strcmp (ffmpegmux->context->oformat->name, "flv")) {
open_flags |= GST_FFMPEG_URL_STREAMHEADER; open_flags |= GST_FFMPEG_URL_STREAMHEADER;
} }
if (url_fopen (&ffmpegmux->context->pb, if (url_fopen (&ffmpegmux->context->pb,
@ -466,9 +472,6 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
/* we're now opened */
ffmpegmux->opened = TRUE;
/* now open the mux format */ /* now open the mux format */
if (av_write_header (ffmpegmux->context) < 0) { if (av_write_header (ffmpegmux->context) < 0) {
GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL), GST_ELEMENT_ERROR (ffmpegmux, LIBRARY, SETTINGS, (NULL),
@ -476,6 +479,9 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
return GST_FLOW_ERROR; return GST_FLOW_ERROR;
} }
/* we're now opened */
ffmpegmux->opened = TRUE;
/* flush the header so it will be used as streamheader */ /* flush the header so it will be used as streamheader */
put_flush_packet (&ffmpegmux->context->pb); put_flush_packet (&ffmpegmux->context->pb);
} }
@ -488,7 +494,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
collected = g_slist_next (collected)) { collected = g_slist_next (collected)) {
GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data; GstFFMpegMuxPad *collect_pad = (GstFFMpegMuxPad *) collected->data;
GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect, GstBuffer *buffer = gst_collect_pads_peek (ffmpegmux->collect,
(GstCollectData *)collect_pad); (GstCollectData *) collect_pad);
/* if there's no buffer, just continue */ /* if there's no buffer, just continue */
if (buffer == NULL) { if (buffer == NULL) {
@ -508,7 +514,7 @@ gst_ffmpegmux_collected (GstCollectPads * pads, gpointer user_data)
best_pad = collect_pad; best_pad = collect_pad;
} }
next_pad: next_pad:
gst_buffer_unref (buffer); gst_buffer_unref (buffer);
/* Mux buffers with invalid timestamp first */ /* Mux buffers with invalid timestamp first */
@ -524,7 +530,7 @@ next_pad:
/* push out current buffer */ /* push out current buffer */
buf = gst_collect_pads_pop (ffmpegmux->collect, buf = gst_collect_pads_pop (ffmpegmux->collect,
(GstCollectData *)best_pad); (GstCollectData *) best_pad);
ffmpegmux->context->streams[best_pad->padnum]->codec->frame_number++; ffmpegmux->context->streams[best_pad->padnum]->codec->frame_number++;
@ -541,7 +547,9 @@ next_pad:
pkt.flags |= PKT_FLAG_KEY; pkt.flags |= PKT_FLAG_KEY;
if (GST_BUFFER_DURATION_IS_VALID (buf)) if (GST_BUFFER_DURATION_IS_VALID (buf))
pkt.duration = gst_util_uint64_scale_int(GST_BUFFER_DURATION (buf), AV_TIME_BASE, GST_SECOND); pkt.duration =
gst_util_uint64_scale_int (GST_BUFFER_DURATION (buf), AV_TIME_BASE,
GST_SECOND);
else else
pkt.duration = 0; pkt.duration = 0;
av_write_frame (ffmpegmux->context, &pkt); av_write_frame (ffmpegmux->context, &pkt);
@ -573,9 +581,9 @@ gst_ffmpegmux_change_state (GstElement * element, GstStateChange transition)
break; break;
case GST_STATE_CHANGE_PAUSED_TO_PLAYING: case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
break; break;
case GST_STATE_CHANGE_PAUSED_TO_READY: case GST_STATE_CHANGE_PAUSED_TO_READY:
gst_collect_pads_stop (ffmpegmux->collect); gst_collect_pads_stop (ffmpegmux->collect);
break; break;
default: default:
break; break;
} }
@ -634,7 +642,7 @@ gst_ffmpegmux_register (GstPlugin * plugin)
(GInstanceInitFunc) gst_ffmpegmux_init, (GInstanceInitFunc) gst_ffmpegmux_init,
}; };
static const GInterfaceInfo tag_setter_info = { static const GInterfaceInfo tag_setter_info = {
NULL, NULL, NULL NULL, NULL, NULL
}; };
GType type; GType type;
AVOutputFormat *in_plugin; AVOutputFormat *in_plugin;
@ -656,7 +664,7 @@ gst_ffmpegmux_register (GstPlugin * plugin)
goto next; goto next;
} }
if (!gst_ffmpeg_formatid_get_codecids (in_plugin->name, if (!gst_ffmpeg_formatid_get_codecids (in_plugin->name,
&video_ids, &audio_ids)) { &video_ids, &audio_ids)) {
gst_caps_unref (srccaps); gst_caps_unref (srccaps);
goto next; goto next;
} }
@ -697,8 +705,7 @@ gst_ffmpegmux_register (GstPlugin * plugin)
/* create the type now */ /* create the type now */
type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0); type = g_type_register_static (GST_TYPE_ELEMENT, type_name, &typeinfo, 0);
g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, g_type_add_interface_static (type, GST_TYPE_TAG_SETTER, &tag_setter_info);
&tag_setter_info);
if (!gst_element_register (plugin, type_name, GST_RANK_NONE, type)) { if (!gst_element_register (plugin, type_name, GST_RANK_NONE, type)) {
g_free (type_name); g_free (type_name);
gst_caps_unref (srccaps); gst_caps_unref (srccaps);