From e983197cbc93420b67aa7e811be47d7278c2c8a2 Mon Sep 17 00:00:00 2001 From: Lynne Date: Tue, 28 Apr 2020 12:55:17 +0100 Subject: oggdec: use ffio_ensure_seekback() to seek back on incorrect data This cleans up the code and simplifies it. It also speeds up parsing since the old pb position was incorrect. --- libavformat/oggdec.c | 68 +++++++++++++++++++++------------------------------- 1 file changed, 27 insertions(+), 41 deletions(-) (limited to 'libavformat/oggdec.c') diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index e0188c7c59..92dcafe2ed 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -206,59 +206,40 @@ static const struct ogg_codec *ogg_find_codec(uint8_t *buf, int size) * situation where a new audio stream spawn (identified with a new serial) and * must replace the previous one (track switch). */ -static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, int size) +static int ogg_replace_stream(AVFormatContext *s, uint32_t serial, char *magic) { struct ogg *ogg = s->priv_data; struct ogg_stream *os; const struct ogg_codec *codec; int i = 0; - if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) { - uint8_t magic[8]; - avio_seek(s->pb, -size, SEEK_CUR); - if (avio_read(s->pb, magic, sizeof(magic)) != sizeof(magic)) - return AVERROR_INVALIDDATA; - avio_seek(s->pb, size - sizeof(magic), SEEK_CUR); - codec = ogg_find_codec(magic, sizeof(magic)); - if (!codec) { - av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n"); - return AVERROR_INVALIDDATA; - } - for (i = 0; i < ogg->nstreams; i++) { - if (ogg->streams[i].codec == codec) - break; - } - if (i >= ogg->nstreams) - return ogg_new_stream(s, serial); - } else if (ogg->nstreams != 1) { + if (ogg->nstreams != 1) { avpriv_report_missing_feature(s, "Changing stream parameters in multistream ogg"); return AVERROR_PATCHWELCOME; } - os = &ogg->streams[i]; - - os->serial = serial; - return i; + /* Check for codecs */ + codec = ogg_find_codec(magic, 8); + if (!codec) { + av_log(s, AV_LOG_ERROR, "Cannot identify new stream\n"); + return AVERROR_INVALIDDATA; + } -#if 0 - buf = os->buf; - bufsize = os->bufsize; - codec = os->codec; + /* If the codec matches, then we assume its a replacement */ + for (i = 0; i < ogg->nstreams; i++) { + if (ogg->streams[i].codec == codec) + break; + } - if (!ogg->state || ogg->state->streams[i].private != os->private) - av_freep(&ogg->streams[i].private); + /* Otherwise, create a new stream */ + if (i >= ogg->nstreams) + return ogg_new_stream(s, serial); - /* Set Ogg stream settings similar to what is done in ogg_new_stream(). We - * also re-use the ogg_stream allocated buffer */ - memset(os, 0, sizeof(*os)); - os->serial = serial; - os->bufsize = bufsize; - os->buf = buf; - os->header = -1; - os->codec = codec; + os = &ogg->streams[i]; + os->serial = serial; + os->codec = codec; return i; -#endif } static int ogg_new_stream(AVFormatContext *s, uint32_t serial) @@ -325,6 +306,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid) uint32_t crc, crc_tmp; int size = 0, idx; int64_t version, page_pos; + int64_t start_pos; uint8_t sync[4]; uint8_t segments[255]; uint8_t *readout_buf; @@ -364,6 +346,10 @@ static int ogg_read_page(AVFormatContext *s, int *sid) /* 0x4fa9b05f = av_crc(AV_CRC_32_IEEE, 0x0, "OggS", 4) */ ffio_init_checksum(bc, ff_crc04C11DB7_update, 0x4fa9b05f); + /* To rewind if checksum is bad/check magic on switches - this is the max packet size */ + ffio_ensure_seekback(bc, MAX_PAGE_SIZE); + start_pos = avio_tell(bc); + version = avio_r8(bc); flags = avio_r8(bc); gp = avio_rl64(bc); @@ -414,7 +400,7 @@ static int ogg_read_page(AVFormatContext *s, int *sid) av_log(s, AV_LOG_ERROR, "CRC mismatch!\n"); if (idx < 0) av_free(readout_buf); - avio_seek(bc, -size, SEEK_CUR); + avio_seek(bc, start_pos, SEEK_SET); return 0; } @@ -424,14 +410,14 @@ static int ogg_read_page(AVFormatContext *s, int *sid) av_log(s, AV_LOG_ERROR, "Invalid Ogg vers!\n"); if (idx < 0) av_free(readout_buf); - avio_seek(bc, -size, SEEK_CUR); + avio_seek(bc, start_pos, SEEK_SET); return 0; } /* CRC is correct so we can be 99% sure there's an actual change here */ if (idx < 0) { if (data_packets_seen(ogg)) - idx = ogg_replace_stream(s, serial, size); + idx = ogg_replace_stream(s, serial, readout_buf); else idx = ogg_new_stream(s, serial); -- cgit v1.2.3