flvmux: Don't refuse caps changes after starting to write headers in streamable mode.

Flv does support changing the stream type and stream properties
after the headers were started to be written, and for example H264
codec_data changes can be supported.

https://bugzilla.gnome.org/show_bug.cgi?id=797256
This commit is contained in:
Yeongjin Jeong 2018-10-05 17:16:26 +09:00 committed by Olivier Crête
parent faee020994
commit 8cae95a22d
2 changed files with 110 additions and 12 deletions

View file

@ -324,6 +324,7 @@ gst_flv_mux_reset (GstElement * element)
mux->first_timestamp = GST_CLOCK_STIME_NONE;
mux->state = GST_FLV_MUX_STATE_HEADER;
mux->sent_header = FALSE;
/* tags */
gst_tag_setter_reset_tags (GST_TAG_SETTER (mux));
@ -397,6 +398,12 @@ gst_flv_mux_video_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
gboolean ret = TRUE;
GstStructure *s;
guint old_codec;
GstBuffer *old_codec_data = NULL;
old_codec = pad->codec;
if (pad->codec_data)
old_codec_data = gst_buffer_ref (pad->codec_data);
s = gst_caps_get_structure (caps, 0);
@ -419,8 +426,35 @@ gst_flv_mux_video_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
if (val)
gst_buffer_replace (&pad->codec_data, gst_value_get_buffer (val));
else if (!val && pad->codec_data)
gst_buffer_unref (pad->codec_data);
}
if (ret && mux->streamable && mux->state != GST_FLV_MUX_STATE_HEADER) {
if (old_codec != pad->codec) {
pad->info_changed = TRUE;
}
if (old_codec_data && pad->codec_data) {
GstMapInfo map;
gst_buffer_map (old_codec_data, &map, GST_MAP_READ);
if (map.size != gst_buffer_get_size (pad->codec_data) ||
gst_buffer_memcmp (pad->codec_data, 0, map.data, map.size))
pad->info_changed = TRUE;
gst_buffer_unmap (old_codec_data, &map);
} else if (!old_codec_data && pad->codec_data) {
pad->info_changed = TRUE;
}
if (pad->info_changed)
mux->state = GST_FLV_MUX_STATE_HEADER;
}
if (old_codec_data)
gst_buffer_unref (old_codec_data);
gst_object_unref (mux);
return ret;
@ -432,6 +466,15 @@ gst_flv_mux_audio_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
GstFlvMux *mux = GST_FLV_MUX (gst_pad_get_parent (pad));
gboolean ret = TRUE;
GstStructure *s;
guint old_codec, old_rate, old_width, old_channels;
GstBuffer *old_codec_data = NULL;
old_codec = pad->codec;
old_rate = pad->rate;
old_width = pad->width;
old_channels = pad->channels;
if (pad->codec_data)
old_codec_data = gst_buffer_ref (pad->codec_data);
s = gst_caps_get_structure (caps, 0);
@ -560,8 +603,36 @@ gst_flv_mux_audio_pad_setcaps (GstFlvMuxPad * pad, GstCaps * caps)
if (val)
gst_buffer_replace (&pad->codec_data, gst_value_get_buffer (val));
else if (!val && pad->codec_data)
gst_buffer_unref (pad->codec_data);
}
if (ret && mux->streamable && mux->state != GST_FLV_MUX_STATE_HEADER) {
if (old_codec != pad->codec || old_rate != pad->rate ||
old_width != pad->width || old_channels != pad->channels) {
pad->info_changed = TRUE;
}
if (old_codec_data && pad->codec_data) {
GstMapInfo map;
gst_buffer_map (old_codec_data, &map, GST_MAP_READ);
if (map.size != gst_buffer_get_size (pad->codec_data) ||
gst_buffer_memcmp (pad->codec_data, 0, map.data, map.size))
pad->info_changed = TRUE;
gst_buffer_unmap (old_codec_data, &map);
} else if (!old_codec_data && pad->codec_data) {
pad->info_changed = TRUE;
}
if (pad->info_changed)
mux->state = GST_FLV_MUX_STATE_HEADER;
}
if (old_codec_data)
gst_buffer_unref (old_codec_data);
gst_object_unref (mux);
return ret;
@ -579,6 +650,7 @@ gst_flv_mux_reset_pad (GstFlvMuxPad * pad)
pad->rate = G_MAXUINT;
pad->width = G_MAXUINT;
pad->channels = G_MAXUINT;
pad->info_changed = FALSE;
gst_flv_mux_pad_flush (GST_AGGREGATOR_PAD_CAST (pad), NULL);
}
@ -1371,29 +1443,48 @@ gst_flv_mux_write_header (GstFlvMux * mux)
gst_query_unref (query);
}
caps = gst_flv_mux_prepare_src_caps (mux,
&header, &metadata, &video_codec_data, &audio_codec_data);
if (!mux->streamable) {
caps = gst_flv_mux_prepare_src_caps (mux,
&header, &metadata, &video_codec_data, &audio_codec_data);
} else {
if (!mux->sent_header) {
caps = gst_flv_mux_prepare_src_caps (mux,
&header, &metadata, &video_codec_data, &audio_codec_data);
} else {
caps = gst_flv_mux_prepare_src_caps (mux,
NULL, NULL,
(mux->video_pad->info_changed ? &video_codec_data : NULL),
(mux->audio_pad->info_changed ? &audio_codec_data : NULL));
}
}
gst_aggregator_set_src_caps (GST_AGGREGATOR_CAST (mux), caps);
gst_caps_unref (caps);
/* push the header buffer, the metadata and the codec info, if any */
ret = gst_flv_mux_push (mux, header);
if (ret != GST_FLOW_OK)
goto failure_header;
ret = gst_flv_mux_push (mux, metadata);
if (ret != GST_FLOW_OK)
goto failure_metadata;
if (header != NULL) {
ret = gst_flv_mux_push (mux, header);
if (ret != GST_FLOW_OK)
goto failure_header;
mux->sent_header = TRUE;
}
if (metadata != NULL) {
ret = gst_flv_mux_push (mux, metadata);
if (ret != GST_FLOW_OK)
goto failure_metadata;
}
if (video_codec_data != NULL) {
ret = gst_flv_mux_push (mux, video_codec_data);
if (ret != GST_FLOW_OK)
goto failure_video_codec_data;
mux->video_pad->info_changed = FALSE;
}
if (audio_codec_data != NULL) {
ret = gst_flv_mux_push (mux, audio_codec_data);
if (ret != GST_FLOW_OK)
goto failure_audio_codec_data;
mux->audio_pad->info_changed = FALSE;
}
return GST_FLOW_OK;
@ -1722,10 +1813,13 @@ gst_flv_mux_aggregate (GstAggregator * aggregator, gboolean timeout)
mux->state = GST_FLV_MUX_STATE_DATA;
best = gst_flv_mux_find_best_pad (aggregator, &ts);
if (best && GST_CLOCK_STIME_IS_VALID (ts))
mux->first_timestamp = ts;
else
mux->first_timestamp = 0;
if (!mux->streamable || mux->first_timestamp == GST_CLOCK_STIME_NONE) {
if (best && GST_CLOCK_STIME_IS_VALID (ts))
mux->first_timestamp = ts;
else
mux->first_timestamp = 0;
}
} else {
best = gst_flv_mux_find_best_pad (aggregator, &ts);
}

View file

@ -66,6 +66,8 @@ struct _GstFlvMuxPad
GstClockTime last_timestamp;
gint64 pts;
gint64 dts;
gboolean info_changed;
};
typedef struct _GstFlvMuxPadClass {
@ -96,6 +98,8 @@ typedef struct _GstFlvMux {
guint64 byte_count;
guint64 duration;
gint64 first_timestamp;
gboolean sent_header;
} GstFlvMux;
typedef struct _GstFlvMuxClass {