oggdemux: fix quadratic search for last page

A crafted file with invalid pages will cause repeated searches from
earlier offsets in steps of 8500 bytes, but reading till the end of
the stream. Since we know the maximum size of an Ogg page, we can
bound the search for next page, to get a linear behavior (though
still not good enough as it will read the entire file backwards if
there's no valid page till then).
This commit is contained in:
Vincent Penquerc'h 2012-06-14 18:31:51 +01:00
parent ecb22ebd63
commit 492341db77

View file

@ -56,6 +56,10 @@
/* stop duration checks within this much of EOS */ /* stop duration checks within this much of EOS */
#define EOS_AVOIDANCE_THRESHOLD 8192 #define EOS_AVOIDANCE_THRESHOLD 8192
/* An Ogg page can not be larger than 255 segments of 255 bytes, plus
26 bytes of header */
#define MAX_OGG_PAGE_SIZE (255 * 255 + 26)
#define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR #define GST_FLOW_LIMIT GST_FLOW_CUSTOM_ERROR
#define GST_FLOW_SKIP_PUSH GST_FLOW_CUSTOM_SUCCESS_1 #define GST_FLOW_SKIP_PUSH GST_FLOW_CUSTOM_SUCCESS_1
@ -2397,10 +2401,18 @@ gst_ogg_demux_get_prev_page (GstOggDemux * ogg, ogg_page * og, gint64 * offset)
* start, we save it. It might not be the final page as there could be * start, we save it. It might not be the final page as there could be
* another page after this one. */ * another page after this one. */
while (ogg->offset < end) { while (ogg->offset < end) {
gint64 new_offset; gint64 new_offset, boundary;
ret = /* An Ogg page cannot be more than a bit less than 64 KB, so we can
gst_ogg_demux_get_next_page (ogg, og, end - ogg->offset, &new_offset); bound the boundary to that size when searching backwards if we
haven't found a page yet. So the most we have to look at is twice
the max page size, which is the worst case if we start scanning
just after a large page, after which also lies a large page. */
boundary = end - ogg->offset;
if (boundary > 2 * MAX_OGG_PAGE_SIZE)
boundary = 2 * MAX_OGG_PAGE_SIZE;
ret = gst_ogg_demux_get_next_page (ogg, og, boundary, &new_offset);
/* we hit the upper limit, offset contains the last page start */ /* we hit the upper limit, offset contains the last page start */
if (ret == GST_FLOW_LIMIT) { if (ret == GST_FLOW_LIMIT) {
GST_LOG_OBJECT (ogg, "hit limit"); GST_LOG_OBJECT (ogg, "hit limit");