mpegtsdemux: always try to seek for to a keyframe

keyframe is expected to lie in the the next ~2500 ms
This commit is contained in:
Janne Grunau 2011-03-31 14:36:02 +02:00 committed by Edward Hervey
parent 9352cfc478
commit ae2e7624d6

View file

@ -545,11 +545,6 @@ gst_ts_demux_perform_auxiliary_seek (MpegTSBase * base, GstClockTime seektime,
(flags & GST_SEEK_FLAG_ACCURATE) ? "accurate" : "", (flags & GST_SEEK_FLAG_ACCURATE) ? "accurate" : "",
(flags & GST_SEEK_FLAG_KEY_UNIT) ? "key_unit" : ""); (flags & GST_SEEK_FLAG_KEY_UNIT) ? "key_unit" : "");
if ((flags & GST_SEEK_FLAG_KEY_UNIT) && !auxiliary_seek_fn) {
GST_ERROR ("key_unit seek for unkown video codec");
goto beach;
}
mpegts_packetizer_flush (base->packetizer); mpegts_packetizer_flush (base->packetizer);
while (!done && scan_offset <= length) { while (!done && scan_offset <= length) {
@ -577,8 +572,9 @@ gst_ts_demux_perform_auxiliary_seek (MpegTSBase * base, GstClockTime seektime,
if (packet.payload_unit_start_indicator) { if (packet.payload_unit_start_indicator) {
guint64 pts = 0; guint64 pts = 0;
res = gst_ts_demux_parse_pes_header_pts (demux, &packet, &pts); GstFlowReturn ok =
if (res == GST_FLOW_OK) { gst_ts_demux_parse_pes_header_pts (demux, &packet, &pts);
if (ok == GST_FLOW_OK) {
GstClockTime time = calculate_gsttime (pcroffset, pts * 300); GstClockTime time = calculate_gsttime (pcroffset, pts * 300);
GST_DEBUG ("packet has PTS: %" GST_TIME_FORMAT, GST_DEBUG ("packet has PTS: %" GST_TIME_FORMAT,
@ -596,7 +592,7 @@ gst_ts_demux_perform_auxiliary_seek (MpegTSBase * base, GstClockTime seektime,
state = 0xffffffff; state = 0xffffffff;
} }
if (flags & GST_SEEK_FLAG_KEY_UNIT) { if (auxiliary_seek_fn) {
gboolean is_keyframe = auxiliary_seek_fn (&state, &packet); gboolean is_keyframe = auxiliary_seek_fn (&state, &packet);
if (is_keyframe) { if (is_keyframe) {
found_keyframe = TRUE; found_keyframe = TRUE;
@ -606,30 +602,30 @@ gst_ts_demux_perform_auxiliary_seek (MpegTSBase * base, GstClockTime seektime,
GST_TIME_ARGS (pcroffset->gsttime), GST_TIME_ARGS (pcroffset->gsttime),
GST_TIME_ARGS (pcroffset->pcr), pcroffset->offset); GST_TIME_ARGS (pcroffset->pcr), pcroffset->offset);
} }
} else {
/* if we don't have a payload parsing function
* every frame is a keyframe */
found_keyframe = TRUE;
} }
} }
switch (flags & (GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT)) { if (flags & GST_SEEK_FLAG_ACCURATE)
case GST_SEEK_FLAG_ACCURATE | GST_SEEK_FLAG_KEY_UNIT: done = found_accurate && found_keyframe;
done = found_accurate && found_keyframe; else
*pcroffset = key_pos; done = found_keyframe;
break; if (done)
case GST_SEEK_FLAG_ACCURATE: *pcroffset = key_pos;
done = found_accurate;
break;
case GST_SEEK_FLAG_KEY_UNIT:
done = found_keyframe;
break;
}
next: next:
mpegts_packetizer_clear_packet (base->packetizer, &packet); mpegts_packetizer_clear_packet (base->packetizer, &packet);
} }
scan_offset += 50 * MPEGTS_MAX_PACKETSIZE; scan_offset += 50 * MPEGTS_MAX_PACKETSIZE;
} }
beach:
if (done) if (done)
res = GST_FLOW_OK; res = GST_FLOW_OK;
else if (GST_FLOW_OK == res)
res = GST_FLOW_CUSTOM_ERROR_1;
beach:
mpegts_packetizer_flush (base->packetizer); mpegts_packetizer_flush (base->packetizer);
return res; return res;
} }
@ -785,10 +781,10 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
/* use correct seek position for the auxiliary search */ /* use correct seek position for the auxiliary search */
seektime += SEEK_TIMESTAMP_OFFSET; seektime += SEEK_TIMESTAMP_OFFSET;
if (segment->flags & GST_SEEK_FLAG_ACCURATE {
|| segment->flags & GST_SEEK_FLAG_KEY_UNIT) {
payload_parse_keyframe keyframe_seek = NULL; payload_parse_keyframe keyframe_seek = NULL;
MpegTSBaseProgram *program = demux->program; MpegTSBaseProgram *program = demux->program;
guint64 avg_bitrate, length;
if (program->streams[pid]) { if (program->streams[pid]) {
switch (program->streams[pid]->stream_type) { switch (program->streams[pid]->stream_type) {
@ -807,11 +803,29 @@ gst_ts_demux_perform_seek (MpegTSBase * base, GstSegment * segment, guint16 pid)
} }
} else } else
GST_WARNING ("no stream info for PID: 0x%04x", pid); GST_WARNING ("no stream info for PID: 0x%04x", pid);
seekpcroffset.pcr = pcr_start.pcr;
seekpcroffset.offset = pcr_start.offset; avg_bitrate =
(pcr_stop.offset -
pcr_start.offset) * 1000 * GST_MSECOND / (pcr_stop.gsttime -
pcr_start.gsttime);
seekpcroffset = pcr_start;
/* search in 2500ms for a keyframe */
length =
MIN (demux->last_pcr.offset - pcr_start.offset,
(avg_bitrate * 25) / 10);
res = res =
gst_ts_demux_perform_auxiliary_seek (base, seektime, &seekpcroffset, gst_ts_demux_perform_auxiliary_seek (base, seektime, &seekpcroffset,
pcr_stop.offset - pcr_start.offset, pid, segment->flags, keyframe_seek); length, pid, segment->flags, keyframe_seek);
if (res == GST_FLOW_CUSTOM_ERROR_1) {
GST_ERROR ("no keyframe found in %" G_GUINT64_FORMAT
" bytes starting from %" G_GUINT64_FORMAT, length,
seekpcroffset.offset);
res = GST_FLOW_ERROR;
}
if (res != GST_FLOW_OK)
goto done;
} }