#include <strings.h>
#include "libavutil/intreadwrite.h"
#include "libavutil/bswap.h"
+#include "libavutil/opt.h"
#include "avformat.h"
#include "avi.h"
#include "dv.h"
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;
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' },
/* check RIFF header */
avio_read(pb, header, 4);
avi->riff_end = avio_rl32(pb); /* RIFF chunk size */
- avi->riff_end += url_ftell(pb); /* RIFF chunk end */
+ avi->riff_end += avio_tell(pb); /* RIFF chunk end */
avio_read(pb, header+4, 4);
for(i=0; avi_headers[i][0]; i++)
AVIStream *ast;
int i;
int64_t last_pos= -1;
- int64_t filesize= url_fsize(s->pb);
+ int64_t filesize= avio_size(s->pb);
#ifdef DEBUG_SEEK
av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16"PRIX64"\n",
if(url_feof(pb))
return -1;
- pos = url_ftell(pb);
+ pos = avio_tell(pb);
if(avi->odml_depth > MAX_ODML_DEPTH){
av_log(s, AV_LOG_ERROR, "Too deeply nested ODML indexes\n");
static void avi_read_info(AVFormatContext *s, uint64_t end)
{
- while (url_ftell(s->pb) < end) {
+ while (avio_tell(s->pb) < end) {
uint32_t tag = avio_rl32(s->pb);
uint32_t size = avio_rl32(s->pb);
avi_read_tag(s, NULL, tag, size);
static void avi_read_nikon(AVFormatContext *s, uint64_t end)
{
- while (url_ftell(s->pb) < end) {
+ while (avio_tell(s->pb) < end) {
uint32_t tag = avio_rl32(s->pb);
uint32_t size = avio_rl32(s->pb);
switch (tag) {
case MKTAG('n', 'c', 't', 'g'): { /* Nikon Tags */
- uint64_t tag_end = url_ftell(s->pb) + size;
- while (url_ftell(s->pb) < tag_end) {
+ uint64_t tag_end = avio_tell(s->pb) + size;
+ while (avio_tell(s->pb) < tag_end) {
uint16_t tag = avio_rl16(s->pb);
uint16_t size = avio_rl16(s->pb);
const char *name = NULL;
}
if (name)
av_metadata_set2(&s->metadata, name, buffer, 0);
- avio_seek(s->pb, size, SEEK_CUR);
+ avio_skip(s->pb, size);
}
break;
}
default:
- avio_seek(s->pb, size, SEEK_CUR);
+ avio_skip(s->pb, size);
break;
}
}
int avih_width=0, avih_height=0;
int amv_file_format=0;
uint64_t list_end = 0;
+ int ret;
avi->stream_index= -1;
if (get_riff(s, pb) < 0)
return -1;
- avi->fsize = url_fsize(pb);
+ 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;
switch(tag) {
case MKTAG('L', 'I', 'S', 'T'):
- list_end = url_ftell(pb) + size;
+ list_end = avio_tell(pb) + size;
/* Ignored, except at start of video packets. */
tag1 = avio_rl32(pb);
print_tag("list", tag1, 0);
if (tag1 == MKTAG('m', 'o', 'v', 'i')) {
- avi->movi_list = url_ftell(pb) - 4;
+ avi->movi_list = avio_tell(pb) - 4;
if(size) avi->movi_end = avi->movi_list + size + (size & 1);
- else avi->movi_end = url_fsize(pb);
+ else avi->movi_end = avio_size(pb);
av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end);
goto end_of_header;
}
unsigned char date[64] = {0};
size += (size & 1);
size -= avio_read(pb, date, FFMIN(size, sizeof(date)-1));
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
avi_metadata_creation_time(&s->metadata, date);
break;
}
case MKTAG('d', 'm', 'l', 'h'):
avi->is_odml = 1;
- avio_seek(pb, size + (size & 1), SEEK_CUR);
+ avio_skip(pb, size + (size & 1));
break;
case MKTAG('a', 'm', 'v', 'h'):
amv_file_format=1;
avio_rl32(pb);
avi->non_interleaved |= avio_rl32(pb) & AVIF_MUSTUSEINDEX;
- avio_seek(pb, 2 * 4, SEEK_CUR);
+ avio_skip(pb, 2 * 4);
avio_rl32(pb);
avio_rl32(pb);
avih_width=avio_rl32(pb);
avih_height=avio_rl32(pb);
- avio_seek(pb, size - 10 * 4, SEEK_CUR);
+ avio_skip(pb, size - 10 * 4);
break;
case MKTAG('s', 't', 'r', 'h'):
/* stream header */
handler = avio_rl32(pb); /* codec tag */
if(tag1 == MKTAG('p', 'a', 'd', 's')){
- avio_seek(pb, size - 8, SEEK_CUR);
+ avio_skip(pb, size - 8);
break;
}else{
stream_index++;
goto fail;
}
s->streams[0]->priv_data = ast;
- avio_seek(pb, 3 * 4, SEEK_CUR);
+ avio_skip(pb, 3 * 4);
ast->scale = avio_rl32(pb);
ast->rate = avio_rl32(pb);
- avio_seek(pb, 4, SEEK_CUR); /* start time */
+ avio_skip(pb, 4); /* start time */
dv_dur = avio_rl32(pb);
if (ast->scale > 0 && ast->rate > 0 && dv_dur > 0) {
*/
stream_index = s->nb_streams - 1;
- avio_seek(pb, size - 9*4, SEEK_CUR);
+ avio_skip(pb, size - 9*4);
break;
}
if(ast->sample_size == 0)
st->duration = st->nb_frames;
ast->frame_offset= ast->cum_len;
- avio_seek(pb, size - 12 * 4, SEEK_CUR);
+ avio_skip(pb, size - 12 * 4);
break;
case MKTAG('s', 't', 'r', 'f'):
/* stream header */
if (stream_index >= (unsigned)s->nb_streams || avi->dv_demux) {
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
} else {
- uint64_t cur_pos = url_ftell(pb);
+ uint64_t cur_pos = avio_tell(pb);
if (cur_pos < list_end)
size = FFMIN(size, list_end - cur_pos);
st = s->streams[stream_index];
st->codec->height=avih_height;
st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
st->codec->codec_id = CODEC_ID_AMV;
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
break;
}
tag1 = ff_get_bmp_header(pb, st);
/* This code assumes that extradata contains only palette. */
/* This is true for all paletted codecs implemented in FFmpeg. */
if (st->codec->extradata_size && (st->codec->bits_per_coded_sample <= 8)) {
- st->codec->palctrl = av_mallocz(sizeof(AVPaletteControl));
+ int pal_size = (1 << st->codec->bits_per_coded_sample) << 2;
+ const uint8_t *pal_src;
+
+ pal_size = FFMIN(pal_size, st->codec->extradata_size);
+ pal_src = st->codec->extradata + st->codec->extradata_size - pal_size;
#if HAVE_BIGENDIAN
- for (i = 0; i < FFMIN(st->codec->extradata_size, AVPALETTE_SIZE)/4; i++)
- st->codec->palctrl->palette[i] = av_bswap32(((uint32_t*)st->codec->extradata)[i]);
+ for (i = 0; i < pal_size/4; i++)
+ ast->pal[i] = AV_RL32(pal_src+4*i);
#else
- memcpy(st->codec->palctrl->palette, st->codec->extradata,
- FFMIN(st->codec->extradata_size, AVPALETTE_SIZE));
+ memcpy(ast->pal, pal_src, pal_size);
#endif
- st->codec->palctrl->palette_changed = 1;
+ ast->has_pal = 1;
}
print_tag("video", tag1, 0);
}
st->codec->height= FFABS(st->codec->height);
-// avio_seek(pb, size - 5 * 4, SEEK_CUR);
+// avio_skip(pb, size - 5 * 4);
break;
case AVMEDIA_TYPE_AUDIO:
- ff_get_wav_header(pb, st->codec, size);
+ ret = ff_get_wav_header(pb, st->codec, size);
+ if (ret < 0)
+ return ret;
ast->dshow_block_align= st->codec->block_align;
if(ast->sample_size && st->codec->block_align && ast->sample_size != st->codec->block_align){
av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, st->codec->block_align);
ast->sample_size= st->codec->block_align;
}
if (size&1) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */
- avio_seek(pb, 1, SEEK_CUR);
+ avio_skip(pb, 1);
/* Force parsing as several audio frames can be in
* one packet and timestamps refer to packet start. */
st->need_parsing = AVSTREAM_PARSE_TIMESTAMPS;
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;
st->codec->codec_id= CODEC_ID_NONE;
st->codec->codec_tag= 0;
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
break;
}
}
break;
case MKTAG('i', 'n', 'd', 'x'):
- i= url_ftell(pb);
- if(!url_is_streamed(pb) && !(s->flags & AVFMT_FLAG_IGNIDX)){
+ i= avio_tell(pb);
+ if(pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && avi->use_odml){
read_braindead_odml_indx(s, 0);
}
avio_seek(pb, i+size, SEEK_SET);
}
size -= 9*4;
}
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
break;
case MKTAG('s', 't', 'r', 'n'):
if(s->nb_streams){
if(size > 1000000){
av_log(s, AV_LOG_ERROR, "Something went wrong during header parsing, "
"I will ignore it and try to continue anyway.\n");
- avi->movi_list = url_ftell(pb) - 4;
- avi->movi_end = url_fsize(pb);
+ avi->movi_list = avio_tell(pb) - 4;
+ avi->movi_end = avio_size(pb);
goto end_of_header;
}
/* skip tag */
size += (size & 1);
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
break;
}
}
return -1;
}
- if(!avi->index_loaded && !url_is_streamed(pb))
+ 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;
goto error;
ret = avio_get_str16le(pb, desc_len, desc, sizeof(desc));
- avio_seek(pb, desc_len - ret, SEEK_CUR);
+ avio_skip(pb, desc_len - ret);
if (*desc)
av_metadata_set2(&st->metadata, "title", desc, 0);
if(size > ast->remaining)
size= ast->remaining;
- avi->last_pkt_pos= url_ftell(pb);
+ avi->last_pkt_pos= avio_tell(pb);
err= av_get_packet(pb, pkt, size);
if(err<0)
return err;
if(ast->has_pal && pkt->data && pkt->size<(unsigned)INT_MAX/2){
- void *ptr= av_realloc(pkt->data, pkt->size + 4*256 + FF_INPUT_BUFFER_PADDING_SIZE);
- if(ptr){
- ast->has_pal=0;
- pkt->size += 4*256;
- pkt->data= ptr;
- memcpy(pkt->data + pkt->size - 4*256, ast->pal, 4*256);
- }else
- av_log(s, AV_LOG_ERROR, "Failed to append palette\n");
+ uint8_t *pal;
+ pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
+ if(!pal){
+ av_log(s, AV_LOG_ERROR, "Failed to allocate data for palette\n");
+ }else{
+ memcpy(pal, ast->pal, AVPALETTE_SIZE);
+ ast->has_pal = 0;
+ }
}
if (CONFIG_DV_DEMUXER && avi->dv_demux) {
ast->packet_size= 0;
}
+ if(!avi->non_interleaved && ast->seek_pos > pkt->pos){
+ av_free_packet(pkt);
+ goto resync;
+ }
+ ast->seek_pos= 0;
+
return size;
}
memset(d, -1, sizeof(int)*8);
- for(i=sync=url_ftell(pb); !url_feof(pb); i++) {
+ for(i=sync=avio_tell(pb); !url_feof(pb); i++) {
int j;
for(j=0; j<7; j++)
//parse JUNK
||(d[0] == 'J' && d[1] == 'U' && d[2] == 'N' && d[3] == 'K')
||(d[0] == 'i' && d[1] == 'd' && d[2] == 'x' && d[3] == '1')){
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
//av_log(s, AV_LOG_DEBUG, "SKIP\n");
goto resync;
}
//parse stray LIST
if(d[0] == 'L' && d[1] == 'I' && d[2] == 'S' && d[3] == 'T'){
- avio_seek(pb, 4, SEEK_CUR);
+ avio_skip(pb, 4);
goto resync;
}
//detect ##ix chunk and skip
if(d[2] == 'i' && d[3] == 'x' && n < s->nb_streams){
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
goto resync;
}
/*|| (st->discard >= AVDISCARD_NONKEY && !(pkt->flags & AV_PKT_FLAG_KEY))*/ //FIXME needs a little reordering
|| st->discard >= AVDISCARD_ALL){
ast->frame_offset += get_duration(ast, size);
- avio_seek(pb, size, SEEK_CUR);
+ avio_skip(pb, size);
goto resync;
}
ast->remaining= size;
if(size || !ast->sample_size){
- uint64_t pos= url_ftell(pb) - 8;
+ uint64_t pos= avio_tell(pb) - 8;
if(!st->index_entries || !st->nb_index_entries || st->index_entries[st->nb_index_entries - 1].pos < pos){
av_add_index_entry(st, pos, ast->frame_offset, size, 0, AVINDEX_KEYFRAME);
}
int i;
int64_t last_start=0;
int64_t first_end= INT64_MAX;
- int64_t oldpos= url_ftell(s->pb);
+ int64_t oldpos= avio_tell(s->pb);
for(i=0; i<s->nb_streams; i++){
AVStream *st = s->streams[i];
AVIContext *avi = s->priv_data;
AVIOContext *pb = s->pb;
uint32_t tag, size;
- int64_t pos= url_ftell(pb);
+ int64_t pos= avio_tell(pb);
int ret = -1;
if (avio_seek(pb, avi->movi_end, SEEK_SET) < 0)
default:
skip:
size += (size & 1);
- if (avio_seek(pb, size, SEEK_CUR) < 0)
+ if (avio_skip(pb, size) < 0)
goto the_end; // something is wrong here
break;
}
AVIContext *avi = s->priv_data;
AVStream *st;
int i, index;
- int64_t pos;
+ int64_t pos, pos_min;
AVIStream *ast;
if (!avi->index_loaded) {
return 0;
}
+ pos_min= pos;
for(i = 0; i < s->nb_streams; i++) {
AVStream *st2 = s->streams[i];
AVIStream *ast2 = st2->priv_data;
flags | AVSEEK_FLAG_BACKWARD);
if(index<0)
index=0;
-
- 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(s, AV_LOG_DEBUG, "%"PRId64" %d %"PRId64"\n", timestamp, index, st2->index_entries[index].timestamp);
- /* extract the current frame number */
+ ast2->seek_pos= st2->index_entries[index].pos;
+ pos_min= FFMIN(pos_min,ast2->seek_pos);
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;
}
for(i=0;i<s->nb_streams;i++) {
AVStream *st = s->streams[i];
AVIStream *ast = st->priv_data;
- av_free(st->codec->palctrl);
if (ast) {
if (ast->sub_ctx) {
av_freep(&ast->sub_ctx->pb);
avi_read_packet,
avi_read_close,
avi_read_seek,
+ .priv_class = &demuxer_class,
};