non interleaved avi support

various fixes/workarounds

Originally committed as revision 4038 to svn://svn.ffmpeg.org/ffmpeg/trunk
This commit is contained in:
Michael Niedermayer 2005-03-15 03:42:57 +00:00
parent 094147cd9c
commit 7c7f386677
1 changed files with 179 additions and 61 deletions

View File

@ -27,8 +27,11 @@
//#define DEBUG_SEEK
typedef struct AVIStream {
int frame_offset; /* current frame (video) or byte (audio) counter
int64_t frame_offset; /* current frame (video) or byte (audio) counter
(used to compute the pts) */
int remaining;
int packet_size;
int scale;
int rate;
int sample_size; /* audio only data */
@ -46,6 +49,8 @@ typedef struct {
offset_t movi_list;
int index_loaded;
int is_odml;
int non_interleaved;
int stream_index;
DVDemuxContext* dv_demux;
} AVIContext;
@ -92,6 +97,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap)
AVIStream *ast;
int xan_video = 0; /* hack to support Xan A/V */
avi->stream_index= -1;
if (get_riff(avi, pb) < 0)
return -1;
@ -389,8 +396,124 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt)
if (size >= 0)
return size;
}
if(avi->non_interleaved){
int best_stream_index;
AVStream *best_st= NULL;
AVIStream *best_ast;
int64_t best_ts= INT64_MAX;
int i;
for(i=0; i<s->nb_streams; i++){
AVStream *st = s->streams[i];
AVIStream *ast = st->priv_data;
int64_t ts= ast->frame_offset;
if(ast->sample_size)
ts /= ast->sample_size;
ts= av_rescale(ts, AV_TIME_BASE * (int64_t)st->time_base.num, st->time_base.den);
// av_log(NULL, AV_LOG_DEBUG, "%Ld %d/%d %Ld\n", ts, st->time_base.num, st->time_base.den, ast->frame_offset);
if(ts < best_ts){
best_ts= ts;
best_st= st;
best_stream_index= i;
}
}
best_ast = best_st->priv_data;
best_ts= av_rescale(best_ts, best_st->time_base.den, AV_TIME_BASE * (int64_t)best_st->time_base.num); //FIXME a little ugly
if(best_ast->remaining)
i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY | AVSEEK_FLAG_BACKWARD);
else
i= av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY);
// av_log(NULL, AV_LOG_DEBUG, "%d\n", i);
if(i>=0){
int64_t pos= best_st->index_entries[i].pos;
pos += avi->movi_list + best_ast->packet_size - best_ast->remaining;
url_fseek(&s->pb, pos, SEEK_SET);
// av_log(NULL, AV_LOG_DEBUG, "pos=%Ld\n", pos);
if(best_ast->remaining)
avi->stream_index= best_stream_index;
else
avi->stream_index= -1;
}
}
resync:
if(avi->stream_index >= 0){
AVStream *st= s->streams[ avi->stream_index ];
AVIStream *ast= st->priv_data;
int size;
assert(ast->remaining);
if(ast->sample_size == 0)
size= INT_MAX;
else if(ast->sample_size < 32)
size= 64*ast->sample_size;
else
size= ast->sample_size;
if(size > ast->remaining)
size= ast->remaining;
av_new_packet(pkt, size);
get_buffer(pb, pkt->data, size);
if (avi->dv_demux) {
dstr = pkt->destruct;
size = dv_produce_packet(avi->dv_demux, pkt,
pkt->data, pkt->size);
pkt->destruct = dstr;
pkt->flags |= PKT_FLAG_KEY;
} else {
/* XXX: how to handle B frames in avi ? */
pkt->dts = ast->frame_offset;
// pkt->dts += ast->start;
if(ast->sample_size)
pkt->dts /= ast->sample_size;
//av_log(NULL, AV_LOG_DEBUG, "dts:%Ld offset:%d %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, n, size);
pkt->stream_index = avi->stream_index;
if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
if(st->index_entries){
AVIndexEntry *e;
int index;
index= av_index_search_timestamp(st, pkt->dts, 0);
e= &st->index_entries[index];
if(e->timestamp == ast->frame_offset){
if (e->flags & AVINDEX_KEYFRAME)
pkt->flags |= PKT_FLAG_KEY;
}
} else {
/* if no index, better to say that all frames
are key frames */
pkt->flags |= PKT_FLAG_KEY;
}
} else {
pkt->flags |= PKT_FLAG_KEY;
}
if(ast->sample_size)
ast->frame_offset += pkt->size;
else
ast->frame_offset++;
}
ast->remaining -= size;
if(!ast->remaining){
avi->stream_index= -1;
ast->packet_size= 0;
if (size & 1) {
get_byte(pb);
size++;
}
}
return size;
}
memset(d, -1, sizeof(int)*8);
for(i=sync=url_ftell(pb); !url_feof(pb); i++) {
int j;
@ -436,7 +559,7 @@ resync:
}
//parse ##dc/##wb
if(n < s->nb_streams){
if(n < s->nb_streams && size){
AVStream *st;
AVIStream *ast;
st = s->streams[n];
@ -460,54 +583,11 @@ resync:
ast->prefix_count= 0;
}
av_new_packet(pkt, size);
get_buffer(pb, pkt->data, size);
if (size & 1) {
get_byte(pb);
size++;
}
if (avi->dv_demux) {
dstr = pkt->destruct;
size = dv_produce_packet(avi->dv_demux, pkt,
pkt->data, pkt->size);
pkt->destruct = dstr;
pkt->flags |= PKT_FLAG_KEY;
} else {
/* XXX: how to handle B frames in avi ? */
pkt->dts = ast->frame_offset;
// pkt->dts += ast->start;
if(ast->sample_size)
pkt->dts /= ast->sample_size;
//av_log(NULL, AV_LOG_DEBUG, "dts:%Ld offset:%d %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, n, size);
pkt->stream_index = n;
avi->stream_index= n;
ast->packet_size= size + 8;
ast->remaining= size;
goto resync;
if (st->codec.codec_type == CODEC_TYPE_VIDEO) {
if(st->index_entries){
AVIndexEntry *e;
int index;
index= av_index_search_timestamp(st, pkt->dts, 0);
e= &st->index_entries[index];
if(e->timestamp == ast->frame_offset){
if (e->flags & AVINDEX_KEYFRAME)
pkt->flags |= PKT_FLAG_KEY;
}
} else {
/* if no index, better to say that all frames
are key frames */
pkt->flags |= PKT_FLAG_KEY;
}
} else {
pkt->flags |= PKT_FLAG_KEY;
}
if(ast->sample_size)
ast->frame_offset += pkt->size;
else
ast->frame_offset++;
}
return size;
}
}
/* palette changed chunk */
@ -548,11 +628,13 @@ resync:
for each stream */
static int avi_read_idx1(AVFormatContext *s, int size)
{
AVIContext *avi = s->priv_data;
ByteIOContext *pb = &s->pb;
int nb_index_entries, i;
AVStream *st;
AVIStream *ast;
unsigned int index, tag, flags, pos, len;
unsigned last_pos= -1;
nb_index_entries = size / 16;
if (nb_index_entries <= 0)
@ -568,6 +650,9 @@ static int avi_read_idx1(AVFormatContext *s, int size)
av_log(NULL, AV_LOG_DEBUG, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/",
i, tag, flags, pos, len);
#endif
if(i==0 && pos > avi->movi_list)
avi->movi_list= 0; //FIXME better check
index = ((tag & 0xff) - '0') * 10;
index += ((tag >> 8) & 0xff) - '0';
if (index >= s->nb_streams)
@ -575,19 +660,44 @@ static int avi_read_idx1(AVFormatContext *s, int size)
st = s->streams[index];
ast = st->priv_data;
if(ast->sample_size)
len /= ast->sample_size;
else
len = 1;
#if defined(DEBUG_SEEK)
av_log(NULL, AV_LOG_DEBUG, "%d cum_len=%d\n", len, ast->cum_len);
#endif
av_add_index_entry(st, pos, ast->cum_len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
ast->cum_len += len;
if(len)
av_add_index_entry(st, pos, ast->cum_len, 0, (flags&AVIIF_INDEX) ? AVINDEX_KEYFRAME : 0);
if(ast->sample_size)
ast->cum_len += len / ast->sample_size;
else
ast->cum_len ++;
if(last_pos == pos)
avi->non_interleaved= 1;
last_pos= pos;
}
return 0;
}
static int guess_ni_flag(AVFormatContext *s){
AVIContext *avi = s->priv_data;
int i;
int64_t last_start=0;
int64_t first_end= INT64_MAX;
for(i=0; i<s->nb_streams; i++){
AVStream *st = s->streams[i];
AVIStream *ast = st->priv_data;
int n= st->nb_index_entries;
if(n <= 0)
continue;
if(st->index_entries[0].pos > last_start)
last_start= st->index_entries[0].pos;
if(st->index_entries[n-1].pos < first_end)
first_end= st->index_entries[n-1].pos;
}
return last_start > first_end;
}
static int avi_load_index(AVFormatContext *s)
{
AVIContext *avi = s->priv_data;
@ -627,6 +737,7 @@ static int avi_load_index(AVFormatContext *s)
}
}
the_end:
avi->non_interleaved |= guess_ni_flag(s);
url_fseek(pb, pos, SEEK_SET);
return 0;
}
@ -659,6 +770,10 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
for(i = 0; i < s->nb_streams; i++) {
AVStream *st2 = s->streams[i];
AVIStream *ast2 = st2->priv_data;
ast2->packet_size=
ast2->remaining= 0;
if (st2->nb_index_entries <= 0)
continue;
@ -671,12 +786,14 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
flags | AVSEEK_FLAG_BACKWARD);
if(index<0)
index=0;
#if 1
while(index>0 && st2->index_entries[index].pos > pos)
index--;
while(index+1 < st2->nb_index_entries && st2->index_entries[index].pos < pos)
index++;
#endif
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++;
}
// av_log(NULL, AV_LOG_DEBUG, "%Ld %d %Ld\n", timestamp, index, st2->index_entries[index].timestamp);
/* extract the current frame number */
ast2->frame_offset = st2->index_entries[index].timestamp;
@ -689,6 +806,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp
/* do the seek */
pos += avi->movi_list;
url_fseek(&s->pb, pos, SEEK_SET);
avi->stream_index= -1;
return 0;
}