flv: fix seqnum handling for seeks

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/1078>
This commit is contained in:
Vivienne Watermeier 2021-09-07 22:23:01 +02:00 committed by GStreamer Marge Bot
parent f441c72e5a
commit 44bfc00884
2 changed files with 96 additions and 37 deletions

View file

@ -902,6 +902,8 @@ gst_flv_demux_audio_negotiate (GstFlvDemux * demux, guint32 codec_tag,
"audio");
event = gst_event_new_stream_start (stream_id);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
if (have_group_id (demux))
gst_event_set_group_id (event, demux->group_id);
gst_pad_push_event (demux->audio_pad, event);
@ -983,26 +985,34 @@ gst_flv_demux_add_codec_tag (GstFlvDemux * demux, const gchar * tag,
static void
gst_flv_demux_push_tags (GstFlvDemux * demux)
{
GstEvent *tag_event;
gst_flv_demux_add_codec_tag (demux, GST_TAG_AUDIO_CODEC, demux->audio_pad);
gst_flv_demux_add_codec_tag (demux, GST_TAG_VIDEO_CODEC, demux->video_pad);
GST_DEBUG_OBJECT (demux, "pushing %" GST_PTR_FORMAT, demux->taglist);
gst_flv_demux_push_src_event (demux,
gst_event_new_tag (gst_tag_list_copy (demux->taglist)));
tag_event = gst_event_new_tag (gst_tag_list_copy (demux->taglist));
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (tag_event, demux->segment_seqnum);
gst_flv_demux_push_src_event (demux, tag_event);
if (demux->audio_pad) {
GST_DEBUG_OBJECT (demux->audio_pad, "pushing audio %" GST_PTR_FORMAT,
demux->audio_tags);
gst_pad_push_event (demux->audio_pad,
gst_event_new_tag (gst_tag_list_copy (demux->audio_tags)));
tag_event = gst_event_new_tag (gst_tag_list_copy (demux->audio_tags));
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (tag_event, demux->segment_seqnum);
gst_pad_push_event (demux->audio_pad, tag_event);
}
if (demux->video_pad) {
GST_DEBUG_OBJECT (demux->video_pad, "pushing video %" GST_PTR_FORMAT,
demux->video_tags);
gst_pad_push_event (demux->video_pad,
gst_event_new_tag (gst_tag_list_copy (demux->video_tags)));
tag_event = gst_event_new_tag (gst_tag_list_copy (demux->video_tags));
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (tag_event, demux->segment_seqnum);
gst_pad_push_event (demux->video_pad, tag_event);
}
}
@ -1050,6 +1060,8 @@ gst_flv_demux_sync_streams (GstFlvDemux * demux)
demux->last_audio_pts = (stop - demux->audio_time_offset) / GST_MSECOND;
event = gst_event_new_gap (start, stop - start);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
gst_pad_push_event (demux->audio_pad, event);
}
@ -1069,6 +1081,8 @@ gst_flv_demux_sync_streams (GstFlvDemux * demux)
demux->last_video_dts = (stop - demux->video_time_offset) / GST_MSECOND;
event = gst_event_new_gap (start, stop - start);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
gst_pad_push_event (demux->video_pad, event);
}
}
@ -1319,6 +1333,7 @@ gst_flv_demux_parse_tag_audio (GstFlvDemux * demux, GstBuffer * buffer)
GST_TIME_ARGS (demux->segment.stop));
demux->segment.start = demux->segment.time = demux->segment.position;
demux->new_seg_event = gst_event_new_segment (&demux->segment);
gst_event_set_seqnum (demux->new_seg_event, demux->segment_seqnum);
} else {
GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
}
@ -1470,6 +1485,8 @@ gst_flv_demux_video_negotiate (GstFlvDemux * demux, guint32 codec_tag)
gst_pad_create_stream_id (demux->video_pad, GST_ELEMENT_CAST (demux),
"video");
event = gst_event_new_stream_start (stream_id);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
g_free (stream_id);
if (have_group_id (demux))
@ -1757,6 +1774,8 @@ gst_flv_demux_parse_tag_video (GstFlvDemux * demux, GstBuffer * buffer)
GST_TIME_ARGS (demux->segment.stop));
demux->segment.start = demux->segment.time = demux->segment.position;
demux->new_seg_event = gst_event_new_segment (&demux->segment);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (demux->new_seg_event, demux->segment_seqnum);
} else {
GST_DEBUG_OBJECT (demux, "pushing pre-generated newsegment event");
}
@ -2045,6 +2064,7 @@ gst_flv_demux_cleanup (GstFlvDemux * demux)
demux->indexed = FALSE;
demux->upstream_seekable = FALSE;
demux->file_size = 0;
demux->segment_seqnum = 0;
demux->index_max_pos = 0;
demux->index_max_time = 0;
@ -2133,6 +2153,8 @@ flv_demux_seek_to_offset (GstFlvDemux * demux, guint64 offset)
gst_event_new_seek (1.0, GST_FORMAT_BYTES,
GST_SEEK_FLAG_FLUSH | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET, offset,
GST_SEEK_TYPE_NONE, -1);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
res = gst_pad_push_event (demux->sinkpad, event);
@ -2765,6 +2787,8 @@ gst_flv_demux_loop (GstPad * pad)
pause:
{
const gchar *reason = gst_flow_get_name (ret);
GstMessage *message;
GstEvent *event;
GST_LOG_OBJECT (demux, "pausing task, reason %s", reason);
gst_pad_pause_task (pad);
@ -2795,20 +2819,24 @@ pause:
if (demux->segment.rate >= 0) {
GST_LOG_OBJECT (demux, "Sending segment done, at end of segment");
gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_segment_done (GST_OBJECT_CAST (demux),
GST_FORMAT_TIME, stop));
gst_flv_demux_push_src_event (demux,
gst_event_new_segment_done (GST_FORMAT_TIME, stop));
message = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
GST_FORMAT_TIME, stop);
gst_message_set_seqnum (message, demux->segment_seqnum);
gst_element_post_message (GST_ELEMENT_CAST (demux), message);
event = gst_event_new_segment_done (GST_FORMAT_TIME, stop);
gst_event_set_seqnum (event, demux->segment_seqnum);
gst_flv_demux_push_src_event (demux, event);
} else { /* Reverse playback */
GST_LOG_OBJECT (demux, "Sending segment done, at beginning of "
"segment");
gst_element_post_message (GST_ELEMENT_CAST (demux),
gst_message_new_segment_done (GST_OBJECT_CAST (demux),
GST_FORMAT_TIME, demux->segment.start));
gst_flv_demux_push_src_event (demux,
gst_event_new_segment_done (GST_FORMAT_TIME,
demux->segment.start));
message = gst_message_new_segment_done (GST_OBJECT_CAST (demux),
GST_FORMAT_TIME, demux->segment.start);
gst_message_set_seqnum (message, demux->segment_seqnum);
gst_element_post_message (GST_ELEMENT_CAST (demux), message);
event = gst_event_new_segment_done (GST_FORMAT_TIME,
demux->segment.start);
gst_event_set_seqnum (event, demux->segment_seqnum);
gst_flv_demux_push_src_event (demux, event);
}
} else {
/* normal playback, send EOS to all linked pads */
@ -2818,15 +2846,23 @@ pause:
}
GST_LOG_OBJECT (demux, "Sending EOS, at end of stream");
if (!demux->audio_pad && !demux->video_pad)
if (!demux->audio_pad && !demux->video_pad) {
GST_ELEMENT_ERROR (demux, STREAM, FAILED,
("Internal data stream error."), ("Got EOS before any data"));
else if (!gst_flv_demux_push_src_event (demux, gst_event_new_eos ()))
} else {
event = gst_event_new_eos ();
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
if (!gst_flv_demux_push_src_event (demux, event))
GST_WARNING_OBJECT (demux, "failed pushing EOS on streams");
}
}
} else if (ret == GST_FLOW_NOT_LINKED || ret < GST_FLOW_EOS) {
GST_ELEMENT_FLOW_ERROR (demux, ret);
gst_flv_demux_push_src_event (demux, gst_event_new_eos ());
event = gst_event_new_eos ();
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (event, demux->segment_seqnum);
gst_flv_demux_push_src_event (demux, event);
}
gst_object_unref (demux);
return;
@ -2918,10 +2954,11 @@ flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
GST_DEBUG_OBJECT (demux, "generating an upstream seek at position %"
G_GUINT64_FORMAT, offset);
ret = gst_pad_push_event (demux->sinkpad,
gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
event = gst_event_new_seek (seeksegment.rate, GST_FORMAT_BYTES,
flags | GST_SEEK_FLAG_ACCURATE, GST_SEEK_TYPE_SET,
offset, GST_SEEK_TYPE_NONE, 0));
offset, GST_SEEK_TYPE_NONE, 0);
gst_event_set_seqnum (event, gst_event_get_seqnum (event));
ret = gst_pad_push_event (demux->sinkpad, event);
if (G_UNLIKELY (!ret)) {
GST_WARNING_OBJECT (demux, "upstream seek failed");
}
@ -2952,6 +2989,8 @@ flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
GST_TIME_ARGS (demux->segment.start),
GST_TIME_ARGS (demux->segment.stop));
demux->new_seg_event = gst_event_new_segment (&demux->segment);
if (demux->segment_seqnum != GST_SEQNUM_INVALID)
gst_event_set_seqnum (demux->new_seg_event, demux->segment_seqnum);
gst_event_unref (event);
} else {
ret = gst_pad_push_event (demux->sinkpad, event);
@ -2998,9 +3037,7 @@ gst_flv_demux_handle_seek_push (GstFlvDemux * demux, GstEvent * event)
demux->state = FLV_STATE_SEEK;
/* copy the event */
if (demux->seek_event)
gst_event_unref (demux->seek_event);
demux->seek_event = gst_event_ref (event);
gst_event_replace (&demux->seek_event, event);
/* set the building_index flag so that only one thread can setup the
* structures for index seeking. */
@ -3050,9 +3087,13 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
gdouble rate;
gboolean update, flush, ret = FALSE;
GstSegment seeksegment;
GstEvent *flush_event;
GstMessage *message;
guint32 seqnum;
gst_event_parse_seek (event, &rate, &format, &flags,
&start_type, &start, &stop_type, &stop);
seqnum = gst_event_get_seqnum (event);
if (format != GST_FORMAT_TIME)
goto wrong_format;
@ -3068,8 +3109,13 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
if (flush) {
/* Flush start up and downstream to make sure data flow and loops are
idle */
gst_flv_demux_push_src_event (demux, gst_event_new_flush_start ());
gst_pad_push_event (demux->sinkpad, gst_event_new_flush_start ());
flush_event = gst_event_new_flush_start ();
gst_event_set_seqnum (flush_event, seqnum);
gst_flv_demux_push_src_event (demux, flush_event);
flush_event = gst_event_new_flush_start ();
gst_event_set_seqnum (flush_event, seqnum);
gst_pad_push_event (demux->sinkpad, flush_event);
} else {
/* Pause the pulling task */
gst_pad_pause_task (demux->sinkpad);
@ -3077,10 +3123,13 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
/* Take the stream lock */
GST_PAD_STREAM_LOCK (demux->sinkpad);
demux->segment_seqnum = seqnum;
if (flush) {
/* Stop flushing upstream we need to pull */
gst_pad_push_event (demux->sinkpad, gst_event_new_flush_stop (TRUE));
flush_event = gst_event_new_flush_stop (TRUE);
gst_event_set_seqnum (flush_event, seqnum);
gst_pad_push_event (demux->sinkpad, flush_event);
}
/* Work on a copy until we are sure the seek succeeded. */
@ -3105,8 +3154,11 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
" index only up to %" GST_TIME_FORMAT,
GST_TIME_ARGS (demux->index_max_time));
/* stop flushing for now */
if (flush)
gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
if (flush) {
flush_event = gst_event_new_flush_stop (TRUE);
gst_event_set_seqnum (flush_event, seqnum);
gst_flv_demux_push_src_event (demux, flush_event);
}
/* delegate scanning and index building to task thread to avoid
* occupying main (UI) loop */
if (demux->seek_event)
@ -3129,7 +3181,9 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
if (flush) {
/* Stop flushing, the sinks are at time 0 now */
gst_flv_demux_push_src_event (demux, gst_event_new_flush_stop (TRUE));
flush_event = gst_event_new_flush_stop (TRUE);
gst_event_set_seqnum (flush_event, seqnum);
gst_flv_demux_push_src_event (demux, flush_event);
}
if (ret) {
@ -3138,9 +3192,10 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
/* Notify about the start of a new segment */
if (demux->segment.flags & GST_SEGMENT_FLAG_SEGMENT) {
gst_element_post_message (GST_ELEMENT (demux),
gst_message_new_segment_start (GST_OBJECT (demux),
demux->segment.format, demux->segment.position));
message = gst_message_new_segment_start (GST_OBJECT (demux),
demux->segment.format, demux->segment.position);
gst_message_set_seqnum (message, seqnum);
gst_element_post_message (GST_ELEMENT (demux), message);
}
gst_flow_combiner_reset (demux->flowcombiner);
@ -3158,6 +3213,7 @@ gst_flv_demux_handle_seek_pull (GstFlvDemux * demux, GstEvent * event,
GST_TIME_ARGS (demux->segment.start),
GST_TIME_ARGS (demux->segment.stop));
demux->new_seg_event = gst_event_new_segment (&demux->segment);
gst_event_set_seqnum (demux->new_seg_event, seqnum);
}
exit:
@ -3238,6 +3294,7 @@ gst_flv_demux_sink_activate_mode (GstPad * sinkpad, GstObject * parent,
case GST_PAD_MODE_PULL:
if (active) {
demux->random_access = TRUE;
demux->segment_seqnum = gst_util_seqnum_next ();
res = gst_pad_start_task (sinkpad, (GstTaskFunction) gst_flv_demux_loop,
sinkpad, NULL);
} else {
@ -3310,6 +3367,7 @@ gst_flv_demux_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
GST_DEBUG_OBJECT (demux, "received new segment");
gst_event_copy_segment (event, &in_segment);
demux->segment_seqnum = gst_event_get_seqnum (event);
if (in_segment.format == GST_FORMAT_TIME) {
/* time segment, this is perfect, copy over the values. */

View file

@ -145,6 +145,7 @@ struct _GstFlvDemux
gint64 file_size;
GstEvent *seek_event;
gint64 seek_time;
guint32 segment_seqnum;
GstClockTime index_max_time;
gint64 index_max_pos;