From bbea34bb6e3a7ac15c3c3ac2dc7b4d49a8782819 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Mon, 22 Jun 2015 14:35:52 -0400 Subject: [PATCH] flvmux: Insert AVC end of sequence This FLV specific mark is needed to prevent Flow Player (most likely all Flash base player) from going into buffering state when near EOS. https://bugzilla.gnome.org/show_bug.cgi?id=751320 --- gst/flv/gstflvmux.c | 74 +++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/gst/flv/gstflvmux.c b/gst/flv/gstflvmux.c index 5f56266b6e..6694caf5eb 100644 --- a/gst/flv/gstflvmux.c +++ b/gst/flv/gstflvmux.c @@ -1005,8 +1005,8 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, GstMapInfo map; guint size; guint32 pts, dts, cts; - guint8 *data, *bdata; - gsize bsize; + guint8 *data, *bdata = NULL; + gsize bsize = 0; if (!GST_CLOCK_STIME_IS_VALID (cpad->dts)) { pts = dts = cpad->last_timestamp / GST_MSECOND; @@ -1029,9 +1029,11 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, GST_LOG_OBJECT (mux, "got pts %i dts %i cts %i\n", pts, dts, cts); - gst_buffer_map (buffer, &map, GST_MAP_READ); - bdata = map.data; - bsize = map.size; + if (buffer != NULL) { + gst_buffer_map (buffer, &map, GST_MAP_READ); + bdata = map.data; + bsize = map.size; + } size = 11; if (cpad->video) { @@ -1064,7 +1066,7 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, data[8] = data[9] = data[10] = 0; if (cpad->video) { - if (GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) + if (buffer && GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) data[11] |= 2 << 4; else data[11] |= 1 << 4; @@ -1075,6 +1077,10 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, if (is_codec_data) { data[12] = 0; GST_WRITE_UINT24_BE (data + 13, 0); + } else if (bsize == 0) { + /* AVC end of sequence */ + data[12] = 2; + GST_WRITE_UINT24_BE (data + 13, 0); } else { /* ACV NALU */ data[12] = 1; @@ -1099,24 +1105,29 @@ gst_flv_mux_buffer_to_tag_internal (GstFlvMux * mux, GstBuffer * buffer, } } - gst_buffer_unmap (buffer, &map); + if (buffer) + gst_buffer_unmap (buffer, &map); GST_WRITE_UINT32_BE (data + size - 4, size - 4); GST_BUFFER_PTS (tag) = GST_CLOCK_TIME_NONE; GST_BUFFER_DTS (tag) = GST_CLOCK_TIME_NONE; GST_BUFFER_DURATION (tag) = GST_CLOCK_TIME_NONE; - GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET (buffer); - GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_END (buffer); - /* mark the buffer if it's an audio buffer and there's also video being muxed - * or it's a video interframe */ - if ((mux->have_video && !cpad->video) || - GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) + if (buffer) { + GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET (buffer); + GST_BUFFER_OFFSET_END (tag) = GST_BUFFER_OFFSET_END (buffer); + + /* mark the buffer if it's an audio buffer and there's also video being muxed + * or it's a video interframe */ + if ((mux->have_video && !cpad->video) || + GST_BUFFER_FLAG_IS_SET (buffer, GST_BUFFER_FLAG_DELTA_UNIT)) + GST_BUFFER_FLAG_SET (tag, GST_BUFFER_FLAG_DELTA_UNIT); + } else { GST_BUFFER_FLAG_SET (tag, GST_BUFFER_FLAG_DELTA_UNIT); - - GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_END (tag) = - GST_BUFFER_OFFSET_NONE; + GST_BUFFER_OFFSET (tag) = GST_BUFFER_OFFSET_END (tag) = + GST_BUFFER_OFFSET_NONE; + } return tag; } @@ -1135,6 +1146,12 @@ gst_flv_mux_codec_data_buffer_to_tag (GstFlvMux * mux, GstBuffer * buffer, return gst_flv_mux_buffer_to_tag_internal (mux, buffer, cpad, TRUE); } +static inline GstBuffer * +gst_flv_mux_eos_to_tag (GstFlvMux * mux, GstFlvPad * cpad) +{ + return gst_flv_mux_buffer_to_tag_internal (mux, NULL, cpad, FALSE); +} + static void gst_flv_mux_put_buffer_in_streamheader (GValue * streamheader, GstBuffer * buffer) @@ -1344,6 +1361,29 @@ gst_flv_mux_determine_duration (GstFlvMux * mux) return duration; } +static GstFlowReturn +gst_flv_mux_write_eos (GstFlvMux * mux) +{ + GstBuffer *tag; + GstFlvPad *video_pad = NULL; + GSList *l = mux->collect->data; + + if (!mux->have_video) + return GST_FLOW_OK; + + for (; l; l = l->next) { + GstFlvPad *cpad = l->data; + if (cpad && cpad->video) { + video_pad = cpad; + break; + } + } + + tag = gst_flv_mux_eos_to_tag (mux, video_pad); + + return gst_flv_mux_push (mux, tag); +} + static GstFlowReturn gst_flv_mux_rewrite_header (GstFlvMux * mux) { @@ -1550,6 +1590,8 @@ gst_flv_mux_handle_buffer (GstCollectPads * pads, GstCollectData * cdata, if (best) { return gst_flv_mux_write_buffer (mux, best, buffer); } else { + /* FIXME check return values */ + gst_flv_mux_write_eos (mux); gst_flv_mux_rewrite_header (mux); gst_pad_push_event (mux->srcpad, gst_event_new_eos ()); return GST_FLOW_EOS;