summaryrefslogtreecommitdiff
path: root/libavformat/avidec.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavformat/avidec.c')
-rw-r--r--libavformat/avidec.c127
1 files changed, 93 insertions, 34 deletions
diff --git a/libavformat/avidec.c b/libavformat/avidec.c
index 7e509ce8ce..366914a64b 100644
--- a/libavformat/avidec.c
+++ b/libavformat/avidec.c
@@ -2,26 +2,27 @@
* 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
*/
#include <strings.h>
#include "libavutil/intreadwrite.h"
#include "libavutil/bswap.h"
+#include "libavutil/opt.h"
#include "libavutil/dict.h"
#include "avformat.h"
#include "avi.h"
@@ -52,9 +53,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;
@@ -66,9 +70,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' },
@@ -171,9 +190,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)
@@ -190,7 +210,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);
@@ -347,6 +367,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;
@@ -356,7 +378,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);
@@ -402,7 +424,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;
@@ -532,8 +554,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;
@@ -583,7 +604,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;
@@ -592,7 +613,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
@@ -653,7 +674,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;
@@ -666,7 +687,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);
@@ -725,12 +746,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;
@@ -846,7 +871,7 @@ static int avi_sync(AVFormatContext *s)
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++)
@@ -1071,7 +1096,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)
@@ -1100,6 +1125,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;
}
@@ -1114,6 +1156,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;
}
@@ -1157,9 +1205,10 @@ static int avi_read_idx1(AVFormatContext *s, int size)
st = s->streams[index];
ast = st->priv_data;
- av_dlog(s, "%d cum_len=%"PRId64"\n", len, ast->cum_len);
-
- if(pb->eof_reached)
+#if defined(DEBUG_SEEK)
+ av_log(s, AV_LOG_DEBUG, "%d cum_len=%"PRId64"\n", len, ast->cum_len);
+#endif
+ if(url_feof(pb))
return -1;
if(last_pos == pos)
@@ -1215,7 +1264,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);
@@ -1260,7 +1309,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) {
@@ -1297,6 +1346,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;
@@ -1317,24 +1367,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;
}
@@ -1384,4 +1442,5 @@ AVInputFormat ff_avi_demuxer = {
avi_read_packet,
avi_read_close,
avi_read_seek,
+ .priv_class = &demuxer_class,
};