diff options
Diffstat (limited to 'libavformat/avidec.c')
-rw-r--r-- | libavformat/avidec.c | 122 |
1 files changed, 90 insertions, 32 deletions
diff --git a/libavformat/avidec.c b/libavformat/avidec.c index 2ea156e..b28d39b 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -2,20 +2,20 @@ * AVI demuxer * Copyright (c) 2001 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -23,6 +23,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/bswap.h" +#include "libavutil/opt.h" #include "libavutil/dict.h" #include "avformat.h" #include "avi.h" @@ -53,9 +54,12 @@ typedef struct AVIStream { AVFormatContext *sub_ctx; AVPacket sub_pkt; uint8_t *sub_buffer; + + int64_t seek_pos; } AVIStream; typedef struct { + const AVClass *class; int64_t riff_end; int64_t movi_end; int64_t fsize; @@ -67,9 +71,24 @@ typedef struct { int stream_index; DVDemuxContext* dv_demux; int odml_depth; + int use_odml; #define MAX_ODML_DEPTH 1000 } AVIContext; + +static const AVOption options[] = { + { "use_odml", "use odml index", offsetof(AVIContext, use_odml), FF_OPT_TYPE_INT, 1, -1, 1, AV_OPT_FLAG_DECODING_PARAM}, + { NULL }, +}; + +static const AVClass demuxer_class = { + "AVI demuxer", + av_default_item_name, + options, + LIBAVUTIL_VERSION_INT, +}; + + static const char avi_headers[][8] = { { 'R', 'I', 'F', 'F', 'A', 'V', 'I', ' ' }, { 'R', 'I', 'F', 'F', 'A', 'V', 'I', 'X' }, @@ -172,9 +191,10 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ int key= len >= 0; len &= 0x7FFFFFFF; - av_dlog(s, "pos:%"PRId64", len:%X\n", pos, len); - - if(pb->eof_reached) +#ifdef DEBUG_SEEK + av_log(s, AV_LOG_ERROR, "pos:%"PRId64", len:%X\n", pos, len); +#endif + if(url_feof(pb)) return -1; if(last_pos == pos || pos == base - 8) @@ -191,7 +211,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ avio_rl32(pb); /* size */ duration = avio_rl32(pb); - if(pb->eof_reached) + if(url_feof(pb)) return -1; pos = avio_tell(pb); @@ -348,6 +368,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) if (get_riff(s, pb) < 0) return -1; + av_log(avi, AV_LOG_DEBUG, "use odml:%d\n", avi->use_odml); + avi->fsize = avio_size(pb); if(avi->fsize<=0) avi->fsize= avi->riff_end == 8 ? INT64_MAX : avi->riff_end; @@ -357,7 +379,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) codec_type = -1; frame_period = 0; for(;;) { - if (pb->eof_reached) + if (url_feof(pb)) goto fail; tag = avio_rl32(pb); size = avio_rl32(pb); @@ -403,7 +425,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) /* AVI header */ /* using frame_period is bad idea */ frame_period = avio_rl32(pb); - avio_skip(pb, 4); + avio_rl32(pb); /* max. bytes per second */ avio_rl32(pb); avi->non_interleaved |= avio_rl32(pb) & AVIF_MUSTUSEINDEX; @@ -533,8 +555,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) codec_type = AVMEDIA_TYPE_DATA; break; default: - av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1); - goto fail; + av_log(s, AV_LOG_INFO, "unknown stream type %X\n", tag1); } if(ast->sample_size == 0) st->duration = st->nb_frames; @@ -584,7 +605,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) /* Extract palette from extradata if bpp <= 8. */ /* This code assumes that extradata contains only palette. */ - /* This is true for all paletted codecs implemented in Libav. */ + /* This is true for all paletted codecs implemented in FFmpeg. */ if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) { int pal_size = (1 << st->codec->bits_per_coded_sample) << 2; const uint8_t *pal_src; @@ -593,7 +614,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) pal_src = st->codec->extradata + st->codec->extradata_size - pal_size; #if HAVE_BIGENDIAN for (i = 0; i < pal_size/4; i++) - ast->pal[i] = av_bswap32(((uint32_t*)pal_src)[i]); + ast->pal[i] = AV_RL32(pal_src+4*i); #else memcpy(ast->pal, pal_src, pal_size); #endif @@ -654,7 +675,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) break; case AVMEDIA_TYPE_SUBTITLE: st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - st->codec->codec_id = CODEC_ID_PROBE; + st->request_probe= 1; break; default: st->codec->codec_type = AVMEDIA_TYPE_DATA; @@ -667,7 +688,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) break; case MKTAG('i', 'n', 'd', 'x'): i= avio_tell(pb); - if(pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX)){ + if(pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && avi->use_odml){ read_braindead_odml_indx(s, 0); } avio_seek(pb, i+size, SEEK_SET); @@ -726,12 +747,16 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) if(!avi->index_loaded && pb->seekable) avi_load_index(s); avi->index_loaded = 1; - avi->non_interleaved |= guess_ni_flag(s); + avi->non_interleaved |= guess_ni_flag(s) | (s->flags & AVFMT_FLAG_SORT_DTS); for(i=0; i<s->nb_streams; i++){ AVStream *st = s->streams[i]; if(st->nb_index_entries) break; } + // DV-in-AVI cannot be non-interleaved, if set this must be + // a mis-detection. + if(avi->dv_demux) + avi->non_interleaved=0; if(i==s->nb_streams && avi->non_interleaved) { av_log(s, AV_LOG_WARNING, "non-interleaved AVI without index, switching to interleaved\n"); avi->non_interleaved=0; @@ -847,7 +872,7 @@ static int avi_sync(AVFormatContext *s, int exit_early) start_sync: memset(d, -1, sizeof(int)*8); - for(i=sync=avio_tell(pb); !pb->eof_reached; i++) { + for(i=sync=avio_tell(pb); !url_feof(pb); i++) { int j; for(j=0; j<7; j++) @@ -1076,7 +1101,7 @@ resync: if (CONFIG_DV_DEMUXER && avi->dv_demux) { dstr = pkt->destruct; size = dv_produce_packet(avi->dv_demux, pkt, - pkt->data, pkt->size); + pkt->data, pkt->size, pkt->pos); pkt->destruct = dstr; pkt->flags |= AV_PKT_FLAG_KEY; if (size < 0) @@ -1105,6 +1130,23 @@ resync: e= &st->index_entries[index]; if(index >= 0 && e->timestamp == ast->frame_offset){ + if (index == st->nb_index_entries-1){ + int key=1; + int i; + uint32_t state=-1; + for(i=0; i<FFMIN(size,256); i++){ + if(st->codec->codec_id == CODEC_ID_MPEG4){ + if(state == 0x1B6){ + key= !(pkt->data[i]&0xC0); + break; + } + }else + break; + state= (state<<8) + pkt->data[i]; + } + if(!key) + e->flags &= ~AVINDEX_KEYFRAME; + } if (e->flags & AVINDEX_KEYFRAME) pkt->flags |= AV_PKT_FLAG_KEY; } @@ -1119,6 +1161,12 @@ resync: ast->packet_size= 0; } + if(!avi->non_interleaved && pkt->pos >= 0 && ast->seek_pos > pkt->pos){ + av_free_packet(pkt); + goto resync; + } + ast->seek_pos= 0; + return size; } @@ -1176,7 +1224,7 @@ static int avi_read_idx1(AVFormatContext *s, int size) av_dlog(s, "%d cum_len=%"PRId64"\n", len, ast->cum_len); - if(pb->eof_reached) + if(url_feof(pb)) return -1; if(last_pos == pos) @@ -1232,7 +1280,7 @@ static int avi_load_index(AVFormatContext *s) goto the_end; // maybe truncated file av_dlog(s, "movi_end=0x%"PRIx64"\n", avi->movi_end); for(;;) { - if (pb->eof_reached) + if (url_feof(pb)) break; tag = avio_rl32(pb); size = avio_rl32(pb); @@ -1273,7 +1321,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp AVIContext *avi = s->priv_data; AVStream *st; int i, index; - int64_t pos; + int64_t pos, pos_min; AVIStream *ast; if (!avi->index_loaded) { @@ -1310,6 +1358,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp return 0; } + pos_min= pos; for(i = 0; i < s->nb_streams; i++) { AVStream *st2 = s->streams[i]; AVIStream *ast2 = st2->priv_data; @@ -1330,24 +1379,32 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp index = av_index_search_timestamp( st2, av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1), - flags | AVSEEK_FLAG_BACKWARD); + flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0)); if(index<0) index=0; + ast2->seek_pos= st2->index_entries[index].pos; + pos_min= FFMIN(pos_min,ast2->seek_pos); + } + for(i = 0; i < s->nb_streams; i++) { + AVStream *st2 = s->streams[i]; + AVIStream *ast2 = st2->priv_data; - if(!avi->non_interleaved){ - while(index>0 && st2->index_entries[index].pos > pos) - index--; - while(index+1 < st2->nb_index_entries && st2->index_entries[index].pos < pos) - index++; - } + if (ast2->sub_ctx || st2->nb_index_entries <= 0) + continue; -// av_log(s, AV_LOG_DEBUG, "%"PRId64" %d %"PRId64"\n", timestamp, index, st2->index_entries[index].timestamp); - /* extract the current frame number */ + index = av_index_search_timestamp( + st2, + av_rescale_q(timestamp, st->time_base, st2->time_base) * FFMAX(ast2->sample_size, 1), + flags | AVSEEK_FLAG_BACKWARD | (st2->codec->codec_type != AVMEDIA_TYPE_VIDEO ? AVSEEK_FLAG_ANY : 0)); + if(index<0) + index=0; + while(index>0 && st2->index_entries[index-1].pos >= pos_min) + index--; ast2->frame_offset = st2->index_entries[index].timestamp; } /* do the seek */ - avio_seek(s->pb, pos, SEEK_SET); + avio_seek(s->pb, pos_min, SEEK_SET); avi->stream_index= -1; return 0; } @@ -1397,4 +1454,5 @@ AVInputFormat ff_avi_demuxer = { avi_read_packet, avi_read_close, avi_read_seek, + .priv_class = &demuxer_class, }; |