mpegpsdemux: limit the amount of scanning done on duration queries

Limit the amount of data scanned when looking for PTSes in duration queries as a
failsafe for kinda broken, potentially large files with sparse or no PTSes.
This commit is contained in:
Alessandro Decina 2012-01-18 12:04:52 +01:00
parent 0961e2f494
commit 8fb0beaf00

View file

@ -60,6 +60,8 @@
#define SEGMENT_THRESHOLD (300*GST_MSECOND) #define SEGMENT_THRESHOLD (300*GST_MSECOND)
#define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND) #define VIDEO_SEGMENT_THRESHOLD (500*GST_MSECOND)
#define DURATION_SCAN_LIMIT 4 * 1024 * 1024
typedef enum typedef enum
{ {
SCAN_SCR, SCAN_SCR,
@ -154,9 +156,9 @@ static GstStateChangeReturn gst_flups_demux_change_state (GstElement * element,
GstStateChange transition); GstStateChange transition);
static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, static inline gboolean gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux,
guint64 * pos, SCAN_MODE mode, guint64 * rts); guint64 * pos, SCAN_MODE mode, guint64 * rts, gint limit);
static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, static inline gboolean gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux,
guint64 * pos, SCAN_MODE mode, guint64 * rts); guint64 * pos, SCAN_MODE mode, guint64 * rts, gint limit);
static inline void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux, static inline void gst_flups_demux_send_segment_updates (GstFluPSDemux * demux,
GstClockTime new_time); GstClockTime new_time);
@ -1051,19 +1053,22 @@ gst_flups_demux_do_seek (GstFluPSDemux * demux, GstSegment * seeksegment)
MIN (gst_util_uint64_scale (scr - demux->first_scr, scr_rate_n, MIN (gst_util_uint64_scale (scr - demux->first_scr, scr_rate_n,
scr_rate_d), demux->sink_segment.stop); scr_rate_d), demux->sink_segment.stop);
found = gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr); found = gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
if (!found) { if (!found) {
found = gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr); found =
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
} }
while (found && fscr < scr) { while (found && fscr < scr) {
offset++; offset++;
found = gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr); found =
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
} }
while (found && fscr > scr && offset > 0) { while (found && fscr > scr && offset > 0) {
offset--; offset--;
found = gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr); found =
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &fscr, 0);
} }
GST_INFO_OBJECT (demux, "doing seek at offset %" G_GUINT64_FORMAT GST_INFO_OBJECT (demux, "doing seek at offset %" G_GUINT64_FORMAT
@ -2382,7 +2387,7 @@ beach:
static inline gboolean static inline gboolean
gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos, gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
SCAN_MODE mode, guint64 * rts) SCAN_MODE mode, guint64 * rts, gint limit)
{ {
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *buffer = NULL; GstBuffer *buffer = NULL;
@ -2398,6 +2403,9 @@ gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
if (offset + scan_sz > demux->sink_segment.stop) if (offset + scan_sz > demux->sink_segment.stop)
return FALSE; return FALSE;
if (limit && offset > *pos + limit)
return FALSE;
if (offset + to_read > demux->sink_segment.stop) if (offset + to_read > demux->sink_segment.stop)
to_read = demux->sink_segment.stop - offset; to_read = demux->sink_segment.stop - offset;
@ -2435,7 +2443,7 @@ gst_flups_demux_scan_forward_ts (GstFluPSDemux * demux, guint64 * pos,
static inline gboolean static inline gboolean
gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos, gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos,
SCAN_MODE mode, guint64 * rts) SCAN_MODE mode, guint64 * rts, gint limit)
{ {
GstFlowReturn ret = GST_FLOW_OK; GstFlowReturn ret = GST_FLOW_OK;
GstBuffer *buffer = NULL; GstBuffer *buffer = NULL;
@ -2451,6 +2459,9 @@ gst_flups_demux_scan_backward_ts (GstFluPSDemux * demux, guint64 * pos,
if (offset < scan_sz - 1) if (offset < scan_sz - 1)
return FALSE; return FALSE;
if (limit && offset < *pos - limit)
return FALSE;
if (offset > BLOCK_SZ) if (offset > BLOCK_SZ)
offset -= BLOCK_SZ; offset -= BLOCK_SZ;
else { else {
@ -2522,7 +2533,8 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
/* Scan for notorious SCR and PTS to calculate the duration */ /* Scan for notorious SCR and PTS to calculate the duration */
/* scan for first SCR in the stream */ /* scan for first SCR in the stream */
offset = demux->sink_segment.start; offset = demux->sink_segment.start;
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &demux->first_scr); gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &demux->first_scr,
DURATION_SCAN_LIMIT);
GST_DEBUG_OBJECT (demux, "First SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux, "First SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
" in packet starting at %" G_GUINT64_FORMAT, " in packet starting at %" G_GUINT64_FORMAT,
demux->first_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)), demux->first_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_scr)),
@ -2530,7 +2542,8 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
demux->first_scr_offset = offset; demux->first_scr_offset = offset;
/* scan for last SCR in the stream */ /* scan for last SCR in the stream */
offset = demux->sink_segment.stop; offset = demux->sink_segment.stop;
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR, &demux->last_scr); gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_SCR,
&demux->last_scr, 0);
GST_DEBUG_OBJECT (demux, "Last SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux, "Last SCR: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
" in packet starting at %" G_GUINT64_FORMAT, " in packet starting at %" G_GUINT64_FORMAT,
demux->last_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_scr)), demux->last_scr, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->last_scr)),
@ -2538,7 +2551,8 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
demux->last_scr_offset = offset; demux->last_scr_offset = offset;
/* scan for first PTS in the stream */ /* scan for first PTS in the stream */
offset = demux->sink_segment.start; offset = demux->sink_segment.start;
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_PTS, &demux->first_pts); gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_PTS, &demux->first_pts,
DURATION_SCAN_LIMIT);
GST_DEBUG_OBJECT (demux, "First PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT GST_DEBUG_OBJECT (demux, "First PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
" in packet starting at %" G_GUINT64_FORMAT, " in packet starting at %" G_GUINT64_FORMAT,
demux->first_pts, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_pts)), demux->first_pts, GST_TIME_ARGS (MPEGTIME_TO_GSTTIME (demux->first_pts)),
@ -2547,7 +2561,7 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
/* scan for last PTS in the stream */ /* scan for last PTS in the stream */
offset = demux->sink_segment.stop; offset = demux->sink_segment.stop;
gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_PTS, gst_flups_demux_scan_backward_ts (demux, &offset, SCAN_PTS,
&demux->last_pts); &demux->last_pts, DURATION_SCAN_LIMIT);
GST_DEBUG_OBJECT (demux, GST_DEBUG_OBJECT (demux,
"Last PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT "Last PTS: %" G_GINT64_FORMAT " %" GST_TIME_FORMAT
" in packet starting at %" G_GUINT64_FORMAT, demux->last_pts, " in packet starting at %" G_GUINT64_FORMAT, demux->last_pts,
@ -2560,7 +2574,7 @@ gst_flups_sink_get_duration (GstFluPSDemux * demux)
offset = demux->first_scr_offset; offset = demux->first_scr_offset;
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
offset++; offset++;
gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &scr); gst_flups_demux_scan_forward_ts (demux, &offset, SCAN_SCR, &scr, 0);
if (scr < demux->last_scr) { if (scr < demux->last_scr) {
demux->first_scr = scr; demux->first_scr = scr;
demux->first_scr_offset = offset; demux->first_scr_offset = offset;