This source file includes following definitions.
- avi_read
- avi_write
- long2str
- short2str
- str2ullong
- str2ulong
- str2ushort
- str2ulong_len
- str2ulong_key
- avi_sampsize
- avi_add_chunk
- avi_ixnn_entry
- avi_init_super_index
- avi_add_std_index
- avi_add_odml_index_entry_core
- avi_add_odml_index_entry
- avi_add_index_entry
- AVI_can_read_audio
- AVI_open_output_file
- AVI_set_video
- AVI_set_audio
- avi_update_header
- avi_close_output_file
- avi_write_data
- AVI_write_frame
- AVI_dup_frame
- AVI_write_audio
- AVI_append_audio
- AVI_bytes_remain
- AVI_bytes_written
- AVI_set_audio_track
- AVI_get_audio_track
- AVI_set_audio_vbr
- AVI_get_audio_vbr
- AVI_close
- AVI_open_input_file
- AVI_open_fd
- avi_parse_input_file
- AVI_video_frames
- AVI_video_width
- AVI_video_height
- AVI_frame_rate
- AVI_video_compressor
- AVI_max_video_chunk
- AVI_audio_tracks
- AVI_audio_channels
- AVI_audio_mp3rate
- AVI_audio_padrate
- AVI_audio_bits
- AVI_audio_format
- AVI_audio_rate
- AVI_frame_size
- AVI_audio_size
- AVI_get_video_position
- AVI_seek_start
- AVI_set_video_position
- AVI_set_audio_bitrate
- AVI_read_frame
- AVI_get_audio_position_index
- AVI_set_audio_position_index
- AVI_set_audio_position
- AVI_read_audio
- AVI_read_data
- AVI_max_size
#include <gpac/setup.h>
#ifndef GPAC_DISABLE_AVILIB
#include <gpac/internal/avilib.h>
#define PACKAGE "GPAC/avilib"
#define VERSION GPAC_FULL_VERSION
#define INFO_LIST
#define NEW_RIFF_THRES (1900*1024*1024)
#define NR_IXNN_CHUNKS 96
#define DEBUG_ODML
#undef DEBUG_ODML
int AVI_errno = 0;
#define MAX_INFO_STRLEN 64
static char id_str[MAX_INFO_STRLEN];
#define FRAME_RATE_SCALE 1000000
static u32 avi_read(FILE *fd, char *buf, u32 len)
{
s32 n = 0;
u32 r = 0;
while (r < len) {
n = (s32) fread(buf + r, 1, len - r, fd);
if (n == 0) break;
if (n < 0) return r;
r += n;
}
return r;
}
static u32 avi_write (FILE *fd, char *buf, u32 len)
{
s32 n = 0;
u32 r = 0;
while (r < len) {
n = (u32) gf_fwrite (buf + r, 1, len - r, fd);
if (n < 0)
return n;
r += n;
}
return r;
}
#define HEADERBYTES 2048
#define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-HEADERBYTES)
#define PAD_EVEN(x) ( ((x)+1) & ~1 )
static void long2str(unsigned char *dst, s32 n)
{
dst[0] = (n )&0xff;
dst[1] = (n>> 8)&0xff;
dst[2] = (n>>16)&0xff;
dst[3] = (n>>24)&0xff;
}
#ifdef WORDS_BIGENDIAN
static void short2str(unsigned char *dst, s32 n)
{
dst[0] = (n )&0xff;
dst[1] = (n>> 8)&0xff;
}
#endif
static u64 str2ullong(unsigned char *str)
{
u64 r = (str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24));
u64 s = (str[4] | (str[5]<<8) | (str[6]<<16) | (str[7]<<24));
#ifdef __GNUC__
return ((s<<32)&0xffffffff00000000ULL)|(r&0xffffffff);
#else
return ((s<<32)&0xffffffff00000000)|(r&0xffffffff);
#endif
}
static u32 str2ulong(unsigned char *str)
{
return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
}
static u32 str2ushort(unsigned char *str)
{
return ( str[0] | (str[1]<<8) );
}
static u32 str2ulong_len (unsigned char *str)
{
return str2ulong(str) & 0x7fffffff;
}
static u32 str2ulong_key (unsigned char *str)
{
u32 c = str2ulong(str);
c &= 0x80000000;
if (c == 0) return 0x10;
else return 0;
}
static int avi_sampsize(avi_t *AVI, int j)
{
int s;
s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans;
if(s<4) s=4;
return s;
}
static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, u32 length)
{
unsigned char c[8];
char p=0;
memcpy(c,tag,4);
long2str(c+4,length);
if( avi_write(AVI->fdes,(char *)c,8) != 8 ||
avi_write(AVI->fdes,(char *)data,length) != length ||
avi_write(AVI->fdes,&p,length&1) != (length&1))
{
gf_fseek(AVI->fdes,AVI->pos,SEEK_SET);
AVI_errno = AVI_ERR_WRITE;
return -1;
}
AVI->pos += 8 + PAD_EVEN(length);
return 0;
}
#define OUTD(n) long2str((unsigned char*) (ix00+bl),(s32)n); bl+=4
#define OUTW(n) ix00[bl] = (n)&0xff; ix00[bl+1] = (n>>8)&0xff; bl+=2
#define OUTC(n) ix00[bl] = (n)&0xff; bl+=1
#define OUTS(s) memcpy(ix00+bl,s,4); bl+=4
static int avi_ixnn_entry(avi_t *AVI, avistdindex_chunk *ch, avisuperindex_entry *en)
{
int bl;
u32 k;
unsigned int max = ch->nEntriesInUse * sizeof (u32) * ch->wLongsPerEntry + 24;
char *ix00 = (char *)gf_malloc (max);
char dfcc[5];
memcpy (dfcc, ch->fcc, 4);
dfcc[4] = 0;
bl = 0;
if (en) {
en->qwOffset = AVI->pos;
en->dwSize = max;
}
#ifdef DEBUG_ODML
#endif
OUTW(ch->wLongsPerEntry);
OUTC(ch->bIndexSubType);
OUTC(ch->bIndexType);
OUTD(ch->nEntriesInUse);
OUTS(ch->dwChunkId);
OUTD(ch->qwBaseOffset&0xffffffff);
OUTD((ch->qwBaseOffset>>32)&0xffffffff);
OUTD(ch->dwReserved3);
for (k = 0; k < ch->nEntriesInUse; k++) {
OUTD(ch->aIndex[k].dwOffset);
OUTD(ch->aIndex[k].dwSize);
}
avi_add_chunk (AVI, (unsigned char*)ch->fcc, (unsigned char*)ix00, max);
gf_free(ix00);
return 0;
}
#undef OUTS
#undef OUTW
#undef OUTD
#undef OUTC
static int avi_init_super_index(avi_t *AVI, unsigned char *idxtag, avisuperindex_chunk **si)
{
int k;
avisuperindex_chunk *sil = NULL;
if ((sil = (avisuperindex_chunk *) gf_malloc (sizeof (avisuperindex_chunk))) == NULL) {
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
memcpy (sil->fcc, "indx", 4);
sil->dwSize = 0;
sil->wLongsPerEntry = 4;
sil->bIndexSubType = 0;
sil->bIndexType = AVI_INDEX_OF_INDEXES;
sil->nEntriesInUse = 0;
memcpy (sil->dwChunkId, idxtag, 4);
memset (sil->dwReserved, 0, sizeof (sil->dwReserved));
sil->aIndex = (avisuperindex_entry *) gf_malloc (sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (void*));
if (!sil->aIndex) {
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
memset (sil->aIndex, 0, sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (u32));
sil->stdindex = (avistdindex_chunk **)gf_malloc (NR_IXNN_CHUNKS * sizeof (avistdindex_chunk *));
if (!sil->stdindex) {
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
for (k = 0; k < NR_IXNN_CHUNKS; k++) {
sil->stdindex[k] = (avistdindex_chunk *) gf_malloc (sizeof (avistdindex_chunk));
sil->stdindex[k]->qwBaseOffset = (u64)k * NEW_RIFF_THRES;
sil->stdindex[k]->aIndex = NULL;
}
*si = sil;
return 0;
}
static int avi_add_std_index(avi_t *AVI, unsigned char *idxtag, unsigned char *strtag,
avistdindex_chunk *stdil)
{
memcpy (stdil->fcc, idxtag, 4);
stdil->dwSize = 4096;
stdil->wLongsPerEntry = 2;
stdil->bIndexSubType = 0;
stdil->bIndexType = AVI_INDEX_OF_CHUNKS;
stdil->nEntriesInUse = 0;
memcpy(stdil->dwChunkId, strtag, 4);
stdil->aIndex = (avistdindex_entry *)gf_malloc(stdil->dwSize * sizeof (u32) * stdil->wLongsPerEntry);
if (!stdil->aIndex) {
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
return 0;
}
static int avi_add_odml_index_entry_core(avi_t *AVI, int flags, u64 pos, unsigned int len, avistdindex_chunk *si)
{
u32 cur_chunk_idx;
si->nEntriesInUse++;
cur_chunk_idx = si->nEntriesInUse-1;
if (cur_chunk_idx >= si->dwSize) {
si->dwSize += 4096;
si->aIndex = (avistdindex_entry *)gf_realloc ( si->aIndex, si->dwSize * sizeof (u32) * si->wLongsPerEntry);
}
if(len>AVI->max_len) AVI->max_len=len;
if (flags != 0x10) {
len |= 0x80000000;
}
si->aIndex [ cur_chunk_idx ].dwSize = len;
si->aIndex [ cur_chunk_idx ].dwOffset = (u32) (pos - si->qwBaseOffset + 8);
return 0;
}
static int avi_add_odml_index_entry(avi_t *AVI, unsigned char *tag, int flags, u64 pos, unsigned int len)
{
char fcc[5];
int audio = (strchr ((char*)tag, 'w')?1:0);
int video = !audio;
unsigned int cur_std_idx;
u32 audtr;
s64 towrite = 0;
if (video) {
if (!AVI->video_superindex) {
if (avi_init_super_index(AVI, (unsigned char *)"ix00", &AVI->video_superindex) < 0) return -1;
AVI->video_superindex->nEntriesInUse++;
cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
if (avi_add_std_index (AVI, (unsigned char *)"ix00", (unsigned char *)"00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0)
return -1;
}
}
if (audio) {
fcc[0] = 'i';
fcc[1] = 'x';
fcc[2] = tag[0];
fcc[3] = tag[1];
fcc[4] = '\0';
if (!AVI->track[AVI->aptr].audio_superindex) {
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] ODML: fcc = %s\n", fcc));
#endif
if (avi_init_super_index(AVI, (unsigned char *)fcc, &AVI->track[AVI->aptr].audio_superindex) < 0) return -1;
AVI->track[AVI->aptr].audio_superindex->nEntriesInUse++;
sprintf(fcc, "ix%02d", AVI->aptr+1);
if (avi_add_std_index (AVI, (unsigned char *)fcc, tag, AVI->track[AVI->aptr].audio_superindex->stdindex[
AVI->track[AVI->aptr].audio_superindex->nEntriesInUse - 1 ]) < 0
) return -1;
}
}
towrite = 0;
if (AVI->video_superindex) {
cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
towrite += AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
+ 4+4+2+1+1+4+4+8+4;
if (cur_std_idx == 0) {
towrite += AVI->n_idx*16 + 8;
towrite += HEADERBYTES;
}
}
for (audtr=0; audtr<AVI->anum; audtr++) {
if (AVI->track[audtr].audio_superindex) {
cur_std_idx = AVI->track[audtr].audio_superindex->nEntriesInUse-1;
towrite += AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
+ 4+4+2+1+1+4+4+8+4;
}
}
towrite += len + (len&1) + 8;
if (AVI->video_superindex &&
(s64)(AVI->pos+towrite) > (s64)((s64)NEW_RIFF_THRES*AVI->video_superindex->nEntriesInUse)) {
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] Adding a new RIFF chunk: %d\n", AVI->video_superindex->nEntriesInUse));
AVI->video_superindex->nEntriesInUse++;
cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
if (AVI->video_superindex->nEntriesInUse > NR_IXNN_CHUNKS) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Internal error in avilib - redefine NR_IXNN_CHUNKS\n"));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] cur_std_idx=%d NR_IXNN_CHUNKS=%d"
"POS=%"LLD" towrite=%"LLD"\n",
cur_std_idx,NR_IXNN_CHUNKS, AVI->pos, towrite));
return -1;
}
if (avi_add_std_index (AVI, (unsigned char *)"ix00", (unsigned char *)"00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0)
return -1;
for (audtr = 0; audtr < AVI->anum; audtr++) {
char aud[5];
if (!AVI->track[audtr].audio_superindex) {
continue;
}
AVI->track[audtr].audio_superindex->nEntriesInUse++;
sprintf(fcc, "ix%02d", audtr+1);
sprintf(aud, "0%01dwb", audtr+1);
if (avi_add_std_index (AVI, (unsigned char *)fcc, (unsigned char *)aud, AVI->track[audtr].audio_superindex->stdindex[
AVI->track[audtr].audio_superindex->nEntriesInUse - 1 ]) < 0
) return -1;
}
if (cur_std_idx > 0) {
avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx - 1],
&AVI->video_superindex->aIndex[cur_std_idx - 1]);
AVI->video_superindex->aIndex[cur_std_idx - 1].dwDuration =
AVI->video_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1;
for (audtr = 0; audtr < AVI->anum; audtr++) {
if (!AVI->track[audtr].audio_superindex) {
continue;
}
avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1],
&AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1]);
AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration =
AVI->track[audtr].audio_superindex->stdindex[cur_std_idx - 1]->nEntriesInUse - 1;
if (AVI->track[audtr].a_fmt == 0x1) {
AVI->track[audtr].audio_superindex->aIndex[cur_std_idx - 1].dwDuration *=
AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800;
}
}
if (cur_std_idx == 1) {
avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
}
avi_add_chunk(AVI, (unsigned char *)"RIFF", (unsigned char *)"AVIXLIST\0\0\0\0movi", 16);
AVI->video_superindex->stdindex[ cur_std_idx ]->qwBaseOffset = AVI->pos -16 -8;
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] ODML: RIFF No.%02d at Offset 0x%llX\n", cur_std_idx, AVI->pos -16 -8));
#endif
for (audtr = 0; audtr < AVI->anum; audtr++) {
if (AVI->track[audtr].audio_superindex)
AVI->track[audtr].audio_superindex->stdindex[ cur_std_idx ]->qwBaseOffset =
AVI->pos -16 -8;
}
AVI->is_opendml++;
}
}
if (video) {
avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len,
AVI->video_superindex->stdindex[ AVI->video_superindex->nEntriesInUse-1 ]);
AVI->total_frames++;
}
if (audio) {
avi_add_odml_index_entry_core(AVI, flags, AVI->pos, len,
AVI->track[AVI->aptr].audio_superindex->stdindex[
AVI->track[AVI->aptr].audio_superindex->nEntriesInUse-1 ]);
}
return 0;
}
static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, int flags, u64 pos, u64 len)
{
void *ptr;
if(AVI->n_idx>=AVI->max_idx) {
ptr = gf_realloc((void *)AVI->idx,(AVI->max_idx+4096)*16);
if(ptr == 0) {
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
AVI->max_idx += 4096;
AVI->idx = (unsigned char((*)[16]) ) ptr;
}
memcpy(AVI->idx[AVI->n_idx],tag,4);
long2str(AVI->idx[AVI->n_idx]+ 4,flags);
long2str(AVI->idx[AVI->n_idx]+ 8, (s32) pos);
long2str(AVI->idx[AVI->n_idx]+12, (s32) len);
AVI->n_idx++;
if(len>AVI->max_len) AVI->max_len=(u32) len;
return 0;
}
int AVI_can_read_audio(avi_t *AVI)
{
if(AVI->mode==AVI_MODE_WRITE) {
return -1;
}
if(!AVI->video_index) {
return -1;
}
if(!AVI->track[AVI->aptr].audio_index) {
return -1;
}
if (AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks) {
return 0;
}
if (AVI->video_pos >= AVI->video_frames) return 1;
if (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos < AVI->video_index[AVI->video_pos].pos) return 1;
else return 0;
}
GF_EXPORT
avi_t* AVI_open_output_file(char * filename)
{
avi_t *AVI;
int i;
unsigned char AVI_header[HEADERBYTES];
AVI = (avi_t *) gf_malloc(sizeof(avi_t));
if(AVI==0)
{
AVI_errno = AVI_ERR_NO_MEM;
return 0;
}
memset((void *)AVI,0,sizeof(avi_t));
AVI->fdes = gf_fopen(filename, "w+b");
if (!AVI->fdes )
{
AVI_errno = AVI_ERR_OPEN;
gf_free(AVI);
return 0;
}
for (i=0; i<HEADERBYTES; i++) AVI_header[i] = 0;
i = avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES);
if (i != HEADERBYTES)
{
gf_fclose(AVI->fdes);
AVI_errno = AVI_ERR_WRITE;
gf_free(AVI);
return 0;
}
AVI->pos = HEADERBYTES;
AVI->mode = AVI_MODE_WRITE;
AVI->anum = 0;
AVI->aptr = 0;
return AVI;
}
GF_EXPORT
void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor)
{
if(AVI->mode==AVI_MODE_READ) return;
AVI->width = width;
AVI->height = height;
AVI->fps = fps;
if(strncmp(compressor, "RGB", 3)==0) {
memset(AVI->compressor, 0, 4);
} else {
memcpy(AVI->compressor,compressor,4);
}
AVI->compressor[4] = 0;
avi_update_header(AVI);
}
GF_EXPORT
void AVI_set_audio(avi_t *AVI, int channels, int rate, int bits, int format, int mp3rate)
{
if(AVI->mode==AVI_MODE_READ) return;
AVI->aptr=AVI->anum;
++AVI->anum;
if(AVI->anum > AVI_MAX_TRACKS) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] error - only %d audio tracks supported\n", AVI_MAX_TRACKS));
exit(1);
}
AVI->track[AVI->aptr].a_chans = channels;
AVI->track[AVI->aptr].a_rate = rate;
AVI->track[AVI->aptr].a_bits = bits;
AVI->track[AVI->aptr].a_fmt = format;
AVI->track[AVI->aptr].mp3rate = mp3rate;
avi_update_header(AVI);
}
#define OUT4CC(s) \
if(nhb<=HEADERBYTES-4) memcpy(AVI_header+nhb,s,4); nhb += 4
#define OUTLONG(n) \
if(nhb<=HEADERBYTES-4) long2str(AVI_header+nhb, (s32)(n)); nhb += 4
#define OUTSHRT(n) \
if(nhb<=HEADERBYTES-2) { \
AVI_header[nhb ] = (u8) ((n )&0xff); \
AVI_header[nhb+1] = (u8) ((n>>8)&0xff); \
} \
nhb += 2
#define OUTCHR(n) \
if(nhb<=HEADERBYTES-1) { \
AVI_header[nhb ] = (n )&0xff; \
} \
nhb += 1
#define OUTMEM(d, s) \
{ \
u32 s_ = (u32) (s); \
if(nhb + s_ <= HEADERBYTES) \
memcpy(AVI_header+nhb, (d), s_); \
nhb += s_; \
}
int avi_update_header(avi_t *AVI)
{
int njunk, sampsize, hasIndex, ms_per_frame, frate, flag;
int movi_len, hdrl_start, strl_start;
u32 j;
unsigned char AVI_header[HEADERBYTES];
u32 nhb;
unsigned int xd_size, xd_size_align2;
movi_len = AVI_MAX_LEN - HEADERBYTES + 4;
hasIndex=1;
if(AVI->fps < 0.001) {
frate=0;
ms_per_frame=0;
} else {
frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
ms_per_frame=(int) (1000000/AVI->fps + 0.5);
}
nhb = 0;
OUT4CC ("RIFF");
OUTLONG(movi_len);
OUT4CC ("AVI ");
OUT4CC ("LIST");
OUTLONG(0);
hdrl_start = nhb;
OUT4CC ("hdrl");
#define AVIF_HASINDEX 0x00000010
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
OUT4CC ("avih");
OUTLONG(56);
OUTLONG(ms_per_frame);
OUTLONG(0);
OUTLONG(0);
flag = AVIF_ISINTERLEAVED;
if(hasIndex) flag |= AVIF_HASINDEX;
if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
OUTLONG(flag);
OUTLONG(0);
OUTLONG(0);
OUTLONG(AVI->anum+1);
OUTLONG(0);
OUTLONG(AVI->width);
OUTLONG(AVI->height);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUT4CC ("LIST");
OUTLONG(0);
strl_start = nhb;
OUT4CC ("strl");
OUT4CC ("strh");
OUTLONG(56);
OUT4CC ("vids");
OUT4CC (AVI->compressor);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(FRAME_RATE_SCALE);
OUTLONG(frate);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(-1);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
xd_size = AVI->extradata_size;
xd_size_align2 = (AVI->extradata_size+1) & ~1;
OUT4CC ("strf");
OUTLONG(40 + xd_size_align2);
OUTLONG(40 + xd_size);
OUTLONG(AVI->width);
OUTLONG(AVI->height);
OUTSHRT(1);
OUTSHRT(24);
OUT4CC (AVI->compressor);
OUTLONG(AVI->width*AVI->height*3);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
if (xd_size > 0 && AVI->extradata) {
OUTMEM(AVI->extradata, xd_size);
if (xd_size != xd_size_align2) {
OUTCHR(0);
}
}
long2str(AVI_header+strl_start-4,nhb-strl_start);
for(j=0; j<AVI->anum; ++j) {
sampsize = avi_sampsize(AVI, j);
OUT4CC ("LIST");
OUTLONG(0);
strl_start = nhb;
OUT4CC ("strl");
OUT4CC ("strh");
OUTLONG(56);
OUT4CC ("auds");
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(sampsize/4);
OUTLONG(1000*AVI->track[j].mp3rate/8);
OUTLONG(0);
OUTLONG(4*AVI->track[j].audio_bytes/sampsize);
OUTLONG(0);
OUTLONG(-1);
OUTLONG(sampsize/4);
OUTLONG(0);
OUTLONG(0);
OUT4CC ("strf");
OUTLONG(16);
OUTSHRT(AVI->track[j].a_fmt);
OUTSHRT(AVI->track[j].a_chans);
OUTLONG(AVI->track[j].a_rate);
OUTLONG(1000*AVI->track[j].mp3rate/8);
OUTSHRT(sampsize/4);
OUTSHRT(AVI->track[j].a_bits);
long2str(AVI_header+strl_start-4,nhb-strl_start);
}
long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
njunk = HEADERBYTES - nhb - 8 - 12;
if(njunk<=0)
{
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] AVI_close_output_file: # of header bytes too small\n"));
exit(1);
}
OUT4CC ("JUNK");
OUTLONG(njunk);
memset(AVI_header+nhb,0,njunk);
nhb += njunk;
OUT4CC ("LIST");
OUTLONG(movi_len);
OUT4CC ("movi");
if ( (gf_fseek(AVI->fdes, 0, SEEK_SET) ==(u64)-1) ||
avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES ||
(gf_fseek(AVI->fdes,AVI->pos,SEEK_SET)==(u64)-1)
) {
AVI_errno = AVI_ERR_CLOSE;
return -1;
}
return 0;
}
#ifndef S_IRUSR
#define S_IRWXU 00700
#define S_IRUSR 00400
#define S_IWUSR 00200
#define S_IXUSR 00100
#define S_IRWXG 00070
#define S_IRGRP 00040
#define S_IWGRP 00020
#define S_IXGRP 00010
#define S_IRWXO 00007
#define S_IROTH 00004
#define S_IWOTH 00002
#define S_IXOTH 00001
#endif
static int avi_close_output_file(avi_t *AVI)
{
int ret, njunk, sampsize, hasIndex, ms_per_frame, frate, idxerror, flag;
u64 movi_len;
int hdrl_start, strl_start;
u32 j;
unsigned char AVI_header[HEADERBYTES];
int nhb;
unsigned int xd_size, xd_size_align2;
#ifdef INFO_LIST
int info_len;
int id_len, real_id_len;
int info_start_pos;
#endif
if (AVI->is_opendml) {
int cur_std_idx = AVI->video_superindex->nEntriesInUse-1;
u32 audtr;
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] ODML dump the rest indices\n"));
#endif
avi_ixnn_entry (AVI, AVI->video_superindex->stdindex[cur_std_idx],
&AVI->video_superindex->aIndex[cur_std_idx]);
AVI->video_superindex->aIndex[cur_std_idx].dwDuration =
AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1;
for (audtr = 0; audtr < AVI->anum; audtr++) {
if (!AVI->track[audtr].audio_superindex) {
continue;
}
avi_ixnn_entry (AVI, AVI->track[audtr].audio_superindex->stdindex[cur_std_idx],
&AVI->track[audtr].audio_superindex->aIndex[cur_std_idx]);
AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration =
AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse - 1;
if (AVI->track[audtr].a_fmt == 0x1) {
AVI->track[audtr].audio_superindex->aIndex[cur_std_idx].dwDuration *=
AVI->track[audtr].a_bits*AVI->track[audtr].a_rate*AVI->track[audtr].a_chans/800;
}
}
AVI->video_superindex->stdindex[ cur_std_idx+1 ]->qwBaseOffset = AVI->pos;
}
if (AVI->is_opendml) {
movi_len = AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - HEADERBYTES+4 - AVI->n_idx*16 - 8;
} else {
movi_len = AVI->pos - HEADERBYTES + 4;
}
idxerror = 0;
hasIndex = 1;
if (!AVI->is_opendml) {
ret = avi_add_chunk(AVI, (unsigned char *)"idx1", (unsigned char *)AVI->idx, AVI->n_idx*16);
hasIndex = (ret==0);
if(ret) {
idxerror = 1;
AVI_errno = AVI_ERR_WRITE_INDEX;
}
}
if(AVI->fps < 0.001) {
frate=0;
ms_per_frame=0;
} else {
frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5);
ms_per_frame=(int) (1000000/AVI->fps + 0.5);
}
nhb = 0;
OUT4CC ("RIFF");
if (AVI->is_opendml) {
OUTLONG(AVI->video_superindex->stdindex[ 1 ]->qwBaseOffset - 8);
} else {
OUTLONG(AVI->pos - 8);
}
OUT4CC ("AVI ");
OUT4CC ("LIST");
OUTLONG(0);
hdrl_start = nhb;
OUT4CC ("hdrl");
#define AVIF_HASINDEX 0x00000010
#define AVIF_MUSTUSEINDEX 0x00000020
#define AVIF_ISINTERLEAVED 0x00000100
#define AVIF_TRUSTCKTYPE 0x00000800
#define AVIF_WASCAPTUREFILE 0x00010000
#define AVIF_COPYRIGHTED 0x00020000
OUT4CC ("avih");
OUTLONG(56);
OUTLONG(ms_per_frame);
OUTLONG(0);
OUTLONG(0);
flag = AVIF_ISINTERLEAVED;
if(hasIndex) flag |= AVIF_HASINDEX;
if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX;
OUTLONG(flag);
OUTLONG(AVI->video_frames);
OUTLONG(0);
OUTLONG(AVI->anum+1);
OUTLONG(0);
OUTLONG(AVI->width);
OUTLONG(AVI->height);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUT4CC ("LIST");
OUTLONG(0);
strl_start = nhb;
OUT4CC ("strl");
OUT4CC ("strh");
OUTLONG(56);
OUT4CC ("vids");
OUT4CC (AVI->compressor);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(FRAME_RATE_SCALE);
OUTLONG(frate);
OUTLONG(0);
OUTLONG(AVI->video_frames);
OUTLONG(AVI->max_len);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
xd_size = AVI->extradata_size;
xd_size_align2 = (AVI->extradata_size+1) & ~1;
OUT4CC ("strf");
OUTLONG(40 + xd_size_align2);
OUTLONG(40 + xd_size);
OUTLONG(AVI->width);
OUTLONG(AVI->height);
OUTSHRT(1);
OUTSHRT(24);
OUT4CC (AVI->compressor);
OUTLONG(AVI->width*AVI->height*3);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
if (xd_size > 0 && AVI->extradata) {
OUTMEM(AVI->extradata, xd_size);
if (xd_size != xd_size_align2) {
OUTCHR(0);
}
}
if (AVI->is_opendml) {
u32 k;
OUT4CC(AVI->video_superindex->fcc);
OUTLONG(2+1+1+4+4+3*4 + AVI->video_superindex->nEntriesInUse * (8+4+4));
OUTSHRT(AVI->video_superindex->wLongsPerEntry);
OUTCHR(AVI->video_superindex->bIndexSubType);
OUTCHR(AVI->video_superindex->bIndexType);
OUTLONG(AVI->video_superindex->nEntriesInUse);
OUT4CC(AVI->video_superindex->dwChunkId);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
for (k = 0; k < AVI->video_superindex->nEntriesInUse; k++) {
u32 r = (u32) ((AVI->video_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff);
u32 s = (u32) ((AVI->video_superindex->aIndex[k].qwOffset) & 0xffffffff);
OUTLONG(s);
OUTLONG(r);
OUTLONG(AVI->video_superindex->aIndex[k].dwSize);
OUTLONG(AVI->video_superindex->aIndex[k].dwDuration);
}
}
long2str(AVI_header+strl_start-4,nhb-strl_start);
for(j=0; j<AVI->anum; ++j) {
{
unsigned int nBlockAlign = 0;
unsigned int avgbsec = 0;
unsigned int scalerate = 0;
sampsize = avi_sampsize(AVI, j);
sampsize = AVI->track[j].a_fmt==0x1?sampsize*4:sampsize;
nBlockAlign = (AVI->track[j].a_rate<32000)?576:1152;
if (AVI->track[j].a_fmt==0x1) {
sampsize = (AVI->track[j].a_chans<2)?sampsize/2:sampsize;
avgbsec = AVI->track[j].a_rate*sampsize/4;
scalerate = AVI->track[j].a_rate*sampsize/4;
} else {
avgbsec = 1000*AVI->track[j].mp3rate/8;
scalerate = 1000*AVI->track[j].mp3rate/8;
}
OUT4CC ("LIST");
OUTLONG(0);
strl_start = nhb;
OUT4CC ("strl");
OUT4CC ("strh");
OUTLONG(56);
OUT4CC ("auds");
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) {
OUTLONG(nBlockAlign);
OUTLONG(AVI->track[j].a_rate);
OUTLONG(0);
OUTLONG(AVI->track[j].audio_chunks);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
} else {
OUTLONG(sampsize/4);
OUTLONG(scalerate);
OUTLONG(0);
OUTLONG(4*AVI->track[j].audio_bytes/sampsize);
OUTLONG(0);
OUTLONG(0xffffffff);
OUTLONG(sampsize/4);
OUTLONG(0);
OUTLONG(0);
}
OUT4CC ("strf");
if (AVI->track[j].a_fmt == 0x55 && AVI->track[j].a_vbr) {
OUTLONG(30);
OUTSHRT(AVI->track[j].a_fmt);
OUTSHRT(AVI->track[j].a_chans);
OUTLONG(AVI->track[j].a_rate);
OUTLONG(1000*AVI->track[j].mp3rate/8);
OUTSHRT(nBlockAlign);
OUTSHRT(AVI->track[j].a_bits);
OUTSHRT(12);
OUTSHRT(1);
OUTLONG(2);
OUTSHRT(nBlockAlign);
OUTSHRT(1);
OUTSHRT(0);
} else if (AVI->track[j].a_fmt == 0x55 && !AVI->track[j].a_vbr) {
OUTLONG(30);
OUTSHRT(AVI->track[j].a_fmt);
OUTSHRT(AVI->track[j].a_chans);
OUTLONG(AVI->track[j].a_rate);
OUTLONG(1000*AVI->track[j].mp3rate/8);
OUTSHRT(sampsize/4);
OUTSHRT(AVI->track[j].a_bits);
OUTSHRT(12);
OUTSHRT(1);
OUTLONG(2);
OUTSHRT(nBlockAlign);
OUTSHRT(1);
OUTSHRT(0);
} else {
OUTLONG(18);
OUTSHRT(AVI->track[j].a_fmt);
OUTSHRT(AVI->track[j].a_chans);
OUTLONG(AVI->track[j].a_rate);
OUTLONG(avgbsec);
OUTSHRT(sampsize/4);
OUTSHRT(AVI->track[j].a_bits);
OUTSHRT(0);
}
}
if (AVI->is_opendml) {
u32 k;
if (!AVI->track[j].audio_superindex) {
continue;
}
OUT4CC(AVI->track[j].audio_superindex->fcc);
OUTLONG(2+1+1+4+4+3*4 + AVI->track[j].audio_superindex->nEntriesInUse * (8+4+4));
OUTSHRT(AVI->track[j].audio_superindex->wLongsPerEntry);
OUTCHR(AVI->track[j].audio_superindex->bIndexSubType);
OUTCHR(AVI->track[j].audio_superindex->bIndexType);
OUTLONG(AVI->track[j].audio_superindex->nEntriesInUse);
OUT4CC(AVI->track[j].audio_superindex->dwChunkId);
OUTLONG(0);
OUTLONG(0);
OUTLONG(0);
for (k = 0; k < AVI->track[j].audio_superindex->nEntriesInUse; k++) {
u32 r = (u32) ((AVI->track[j].audio_superindex->aIndex[k].qwOffset >> 32) & 0xffffffff);
u32 s = (u32) ((AVI->track[j].audio_superindex->aIndex[k].qwOffset) & 0xffffffff);
OUTLONG(s);
OUTLONG(r);
OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwSize);
OUTLONG(AVI->track[j].audio_superindex->aIndex[k].dwDuration);
}
}
long2str(AVI_header+strl_start-4,nhb-strl_start);
}
if (AVI->is_opendml) {
OUT4CC("LIST");
OUTLONG(16);
OUT4CC("odml");
OUT4CC("dmlh");
OUTLONG(4);
OUTLONG(AVI->total_frames);
}
long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
#ifdef INFO_LIST
OUT4CC ("LIST");
info_start_pos = nhb;
info_len = MAX_INFO_STRLEN + 12;
OUTLONG(info_len);
OUT4CC ("INFO");
OUT4CC ("ISFT");
memset(id_str, 0, MAX_INFO_STRLEN);
sprintf(id_str, "%s-%s", PACKAGE, VERSION);
real_id_len = id_len = (u32) strlen(id_str)+1;
if (id_len&1) id_len++;
OUTLONG(real_id_len);
memset(AVI_header+nhb, 0, id_len);
memcpy(AVI_header+nhb, id_str, id_len);
nhb += id_len;
info_len = 0;
long2str(AVI_header+info_start_pos, info_len + id_len + 4+4+4);
nhb += info_len;
#endif
njunk = HEADERBYTES - nhb - 8 - 12;
if(njunk<=0)
{
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] AVI_close_output_file: # of header bytes too small\n"));
exit(1);
}
OUT4CC ("JUNK");
OUTLONG(njunk);
memset(AVI_header+nhb,0,njunk);
nhb += njunk;
OUT4CC ("LIST");
OUTLONG(movi_len);
OUT4CC ("movi");
if ( (gf_fseek(AVI->fdes,0,SEEK_SET)==(u64)-1) ||
avi_write(AVI->fdes,(char *)AVI_header,HEADERBYTES)!=HEADERBYTES
)
{
AVI_errno = AVI_ERR_CLOSE;
return -1;
}
if (AVI->is_opendml) {
u32 k;
char f[4];
u32 len;
for (k=1; k<AVI->video_superindex->nEntriesInUse; k++) {
gf_fseek(AVI->fdes, AVI->video_superindex->stdindex[k]->qwBaseOffset+4, SEEK_SET);
len = (u32) (AVI->video_superindex->stdindex[k+1]->qwBaseOffset - AVI->video_superindex->stdindex[k]->qwBaseOffset - 8);
long2str((unsigned char *)f, len);
avi_write(AVI->fdes, f, 4);
gf_fseek(AVI->fdes, 8, SEEK_CUR);
len -= 12;
long2str((unsigned char *)f, len);
avi_write(AVI->fdes, f, 4);
}
}
if(idxerror) return -1;
return 0;
}
static int avi_write_data(avi_t *AVI, char *data, unsigned int length, int audio, int keyframe)
{
int n = 0;
unsigned char astr[5];
#if 0
if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN ) {
AVI_errno = AVI_ERR_SIZELIM;
return -1;
}
#endif
sprintf((char *)astr, "0%1dwb", (int)(AVI->aptr+1));
if(audio) {
if (!AVI->is_opendml) n = avi_add_index_entry(AVI,astr,0x10,AVI->pos,length);
n += avi_add_odml_index_entry(AVI,astr,0x10,AVI->pos,length);
} else {
if (!AVI->is_opendml) n = avi_add_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
n += avi_add_odml_index_entry(AVI,(unsigned char *)"00db",((keyframe)?0x10:0x0),AVI->pos,length);
}
if(n) return -1;
if(audio)
n = avi_add_chunk(AVI,(unsigned char *)astr, (unsigned char *)data, length);
else
n = avi_add_chunk(AVI,(unsigned char *)"00db", (unsigned char *)data, length);
if (n) return -1;
return 0;
}
GF_EXPORT
int AVI_write_frame(avi_t *AVI, char *data, int bytes, int keyframe)
{
s64 pos;
if(AVI->mode==AVI_MODE_READ) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
pos = AVI->pos;
if(avi_write_data(AVI,data,bytes,0,keyframe)) return -1;
AVI->last_pos = pos;
AVI->last_len = bytes;
AVI->video_frames++;
return 0;
}
int AVI_dup_frame(avi_t *AVI)
{
if(AVI->mode==AVI_MODE_READ) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(AVI->last_pos==0) return 0;
if(avi_add_index_entry(AVI,(unsigned char *)"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
AVI->video_frames++;
AVI->must_use_index = 1;
return 0;
}
GF_EXPORT
int AVI_write_audio(avi_t *AVI, char *data, int bytes)
{
if(AVI->mode==AVI_MODE_READ) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if( avi_write_data(AVI,data,bytes,1,0) ) return -1;
AVI->track[AVI->aptr].audio_bytes += bytes;
AVI->track[AVI->aptr].audio_chunks++;
return 0;
}
int AVI_append_audio(avi_t *AVI, char *data, int bytes)
{
int i, length, pos;
unsigned char c[4];
if(AVI->mode==AVI_MODE_READ) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
--AVI->n_idx;
length = str2ulong(AVI->idx[AVI->n_idx]+12);
pos = str2ulong(AVI->idx[AVI->n_idx]+8);
long2str(AVI->idx[AVI->n_idx]+12,length+bytes);
++AVI->n_idx;
AVI->track[AVI->aptr].audio_bytes += bytes;
gf_fseek(AVI->fdes, pos+4, SEEK_SET);
long2str(c, length+bytes);
avi_write(AVI->fdes, (char *)c, 4);
gf_fseek(AVI->fdes, pos+8+length, SEEK_SET);
i=PAD_EVEN(length + bytes);
bytes = i - length;
avi_write(AVI->fdes, data, bytes);
AVI->pos = pos + 8 + i;
return 0;
}
u64 AVI_bytes_remain(avi_t *AVI)
{
if(AVI->mode==AVI_MODE_READ) return 0;
return ( AVI_MAX_LEN - (AVI->pos + 8 + 16*AVI->n_idx));
}
u64 AVI_bytes_written(avi_t *AVI)
{
if(AVI->mode==AVI_MODE_READ) return 0;
return (AVI->pos + 8 + 16*AVI->n_idx);
}
int AVI_set_audio_track(avi_t *AVI, u32 track)
{
if (track + 1 > AVI->anum) return(-1);
AVI->aptr=track;
return 0;
}
int AVI_get_audio_track(avi_t *AVI)
{
return(AVI->aptr);
}
void AVI_set_audio_vbr(avi_t *AVI, int is_vbr)
{
AVI->track[AVI->aptr].a_vbr = is_vbr;
}
int AVI_get_audio_vbr(avi_t *AVI)
{
return(AVI->track[AVI->aptr].a_vbr);
}
GF_EXPORT
int AVI_close(avi_t *AVI)
{
int ret;
u32 j;
if(AVI->mode == AVI_MODE_WRITE)
ret = avi_close_output_file(AVI);
else
ret = 0;
gf_fclose(AVI->fdes);
if(AVI->idx) gf_free(AVI->idx);
if(AVI->video_index) gf_free(AVI->video_index);
if(AVI->video_superindex) {
if(AVI->video_superindex->aIndex) gf_free(AVI->video_superindex->aIndex);
if (AVI->video_superindex->stdindex) {
for (j=0; j < NR_IXNN_CHUNKS; j++) {
if (AVI->video_superindex->stdindex[j]->aIndex)
gf_free(AVI->video_superindex->stdindex[j]->aIndex);
gf_free(AVI->video_superindex->stdindex[j]);
}
gf_free(AVI->video_superindex->stdindex);
}
gf_free(AVI->video_superindex);
}
for (j=0; j<AVI->anum; j++)
{
if(AVI->track[j].audio_index) gf_free(AVI->track[j].audio_index);
if(AVI->track[j].audio_superindex) {
avisuperindex_chunk *asi = AVI->track[j].audio_superindex;
if (asi->aIndex) gf_free(asi->aIndex);
if (asi->stdindex) {
for (j=0; j < NR_IXNN_CHUNKS; j++) {
if (asi->stdindex[j]->aIndex)
gf_free(asi->stdindex[j]->aIndex);
gf_free(asi->stdindex[j]);
}
gf_free(asi->stdindex);
}
gf_free(asi);
}
}
if (AVI->bitmap_info_header)
gf_free(AVI->bitmap_info_header);
for (j = 0; j < AVI->anum; j++)
if (AVI->wave_format_ex[j])
gf_free(AVI->wave_format_ex[j]);
gf_free(AVI);
AVI=NULL;
return ret;
}
#define ERR_EXIT(x) \
{ \
AVI_close(AVI); \
AVI_errno = x; \
return 0; \
}
avi_t *AVI_open_input_file(char *filename, int getIndex)
{
avi_t *AVI=NULL;
AVI = (avi_t *) gf_malloc(sizeof(avi_t));
if(AVI==NULL)
{
AVI_errno = AVI_ERR_NO_MEM;
return 0;
}
memset((void *)AVI,0,sizeof(avi_t));
AVI->mode = AVI_MODE_READ;
AVI->fdes = gf_fopen(filename,"rb");
if(!AVI->fdes )
{
AVI_errno = AVI_ERR_OPEN;
gf_free(AVI);
return 0;
}
AVI_errno = 0;
avi_parse_input_file(AVI, getIndex);
if (AVI != NULL && !AVI_errno) {
AVI->aptr=0;
}
if (AVI_errno) return NULL;
return AVI;
}
avi_t *AVI_open_fd(FILE *fd, int getIndex)
{
avi_t *AVI=NULL;
AVI = (avi_t *) gf_malloc(sizeof(avi_t));
if(AVI==NULL)
{
AVI_errno = AVI_ERR_NO_MEM;
return 0;
}
memset((void *)AVI,0,sizeof(avi_t));
AVI->mode = AVI_MODE_READ;
AVI->fdes = fd;
AVI_errno = 0;
avi_parse_input_file(AVI, getIndex);
if (AVI != NULL && !AVI_errno) {
AVI->aptr=0;
}
if (AVI_errno)
return AVI=NULL;
else
return AVI;
}
int avi_parse_input_file(avi_t *AVI, int getIndex)
{
int i, rate, scale, idx_type;
s64 n;
unsigned char *hdrl_data;
u64 header_offset=0;
int hdrl_len=0;
int nvi, nai[AVI_MAX_TRACKS], ioff;
u64 tot[AVI_MAX_TRACKS];
u32 j;
int lasttag = 0;
int vids_strh_seen = 0;
int vids_strf_seen = 0;
int auds_strh_seen = 0;
int num_stream = 0;
char data[256];
s64 oldpos=-1, newpos=-1;
int aud_chunks = 0;
if( avi_read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ)
if( strnicmp(data ,"RIFF",4) !=0 ||
strnicmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
hdrl_data = 0;
while(1)
{
if( avi_read(AVI->fdes,data,8) != 8 ) break;
newpos = gf_ftell(AVI->fdes);
if(oldpos==newpos) {
return -1;
}
oldpos=newpos;
n = str2ulong((unsigned char *)data+4);
n = PAD_EVEN(n);
if(strnicmp(data,"LIST",4) == 0)
{
if( avi_read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
n -= 4;
if(strnicmp(data,"hdrl",4) == 0)
{
hdrl_len = (u32) n;
hdrl_data = (unsigned char *) gf_malloc((u32)n);
if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM);
header_offset = gf_ftell(AVI->fdes);
if( avi_read(AVI->fdes,(char *)hdrl_data, (u32) n) != n ) ERR_EXIT(AVI_ERR_READ)
}
else if(strnicmp(data,"movi",4) == 0)
{
AVI->movi_start = gf_ftell(AVI->fdes);
if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break;
}
else if (gf_fseek(AVI->fdes,n,SEEK_CUR)==(u64)-1) break;
}
else if(strnicmp(data,"idx1",4) == 0)
{
AVI->n_idx = AVI->max_idx = (u32) (n/16);
AVI->idx = (unsigned char((*)[16]) ) gf_malloc((u32)n);
if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
if(avi_read(AVI->fdes, (char *) AVI->idx, (u32) n) != n ) {
gf_free( AVI->idx);
AVI->idx=NULL;
AVI->n_idx = 0;
}
}
else
gf_fseek(AVI->fdes,n,SEEK_CUR);
}
if(!hdrl_data ) ERR_EXIT(AVI_ERR_NO_HDRL)
if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
for(i=0; i<hdrl_len;)
{
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]));
#endif
if(strnicmp((char *)hdrl_data+i,"LIST",4)==0) {
i+= 12;
continue;
}
n = str2ulong(hdrl_data+i+4);
n = PAD_EVEN(n);
if(strnicmp((char *)hdrl_data+i,"strh",4)==0)
{
i += 8;
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] TAG %c%c%c%c\n", (hdrl_data+i)[0], (hdrl_data+i)[1], (hdrl_data+i)[2], (hdrl_data+i)[3]));
#endif
if(strnicmp((char *)hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
{
memcpy(AVI->compressor,hdrl_data+i+4,4);
AVI->compressor[4] = 0;
AVI->v_codech_off = header_offset + i+4;
scale = str2ulong(hdrl_data+i+20);
rate = str2ulong(hdrl_data+i+24);
if(scale!=0) AVI->fps = (double)rate/(double)scale;
AVI->video_frames = str2ulong(hdrl_data+i+32);
AVI->video_strn = num_stream;
AVI->max_len = 0;
vids_strh_seen = 1;
lasttag = 1;
memcpy(&AVI->video_stream_header, hdrl_data + i,
sizeof(alAVISTREAMHEADER));
}
else if (strnicmp ((char *)hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
{
AVI->aptr=AVI->anum;
++AVI->anum;
if(AVI->anum > AVI_MAX_TRACKS) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] error - only %d audio tracks supported\n", AVI_MAX_TRACKS));
return(-1);
}
AVI->track[AVI->aptr].audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI, 0);
AVI->track[AVI->aptr].audio_strn = num_stream;
AVI->track[AVI->aptr].a_vbr = !str2ulong(hdrl_data+i+44);
AVI->track[AVI->aptr].padrate = str2ulong(hdrl_data+i+24);
memcpy(&AVI->stream_headers[AVI->aptr], hdrl_data + i,
sizeof(alAVISTREAMHEADER));
lasttag = 2;
AVI->track[AVI->aptr].a_codech_off = header_offset + i;
}
else if (strnicmp ((char*)hdrl_data+i,"iavs",4) ==0 && ! auds_strh_seen) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] AVILIB: error - DV AVI Type 1 no supported\n"));
return (-1);
}
else
lasttag = 0;
num_stream++;
}
else if(strnicmp((char*)hdrl_data+i,"dmlh",4) == 0) {
AVI->total_frames = str2ulong(hdrl_data+i+8);
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] real number of frames %d\n", AVI->total_frames));
#endif
i += 8;
}
else if(strnicmp((char *)hdrl_data+i,"strf",4)==0)
{
i += 8;
if(lasttag == 1)
{
alBITMAPINFOHEADER bih;
memcpy(&bih, hdrl_data + i, sizeof(alBITMAPINFOHEADER));
AVI->bitmap_info_header = (alBITMAPINFOHEADER *)
gf_malloc(str2ulong((unsigned char *)&bih.bi_size));
if (AVI->bitmap_info_header != NULL)
memcpy(AVI->bitmap_info_header, hdrl_data + i,
str2ulong((unsigned char *)&bih.bi_size));
AVI->width = str2ulong(hdrl_data+i+4);
AVI->height = str2ulong(hdrl_data+i+8);
vids_strf_seen = 1;
AVI->v_codecf_off = header_offset + i+16;
memcpy(AVI->compressor2, hdrl_data+i+16, 4);
AVI->compressor2[4] = 0;
}
else if(lasttag == 2)
{
alWAVEFORMATEX *wfe;
char *nwfe;
int wfes;
if ((u32) (hdrl_len - i) < sizeof(alWAVEFORMATEX))
wfes = hdrl_len - i;
else
wfes = sizeof(alWAVEFORMATEX);
wfe = (alWAVEFORMATEX *)gf_malloc(sizeof(alWAVEFORMATEX));
if (wfe != NULL) {
memset(wfe, 0, sizeof(alWAVEFORMATEX));
memcpy(wfe, hdrl_data + i, wfes);
if (str2ushort((unsigned char *)&wfe->cb_size) != 0) {
nwfe = (char *)
gf_realloc(wfe, sizeof(alWAVEFORMATEX) +
str2ushort((unsigned char *)&wfe->cb_size));
if (nwfe != 0) {
s64 lpos = gf_ftell(AVI->fdes);
gf_fseek(AVI->fdes, header_offset + i + sizeof(alWAVEFORMATEX),
SEEK_SET);
wfe = (alWAVEFORMATEX *)nwfe;
nwfe = &nwfe[sizeof(alWAVEFORMATEX)];
avi_read(AVI->fdes, nwfe,
str2ushort((unsigned char *)&wfe->cb_size));
gf_fseek(AVI->fdes, lpos, SEEK_SET);
}
}
AVI->wave_format_ex[AVI->aptr] = wfe;
}
AVI->track[AVI->aptr].a_fmt = str2ushort(hdrl_data+i );
AVI->track[AVI->aptr].a_codecf_off = header_offset + i;
AVI->track[AVI->aptr].a_chans = str2ushort(hdrl_data+i+2);
AVI->track[AVI->aptr].a_rate = str2ulong (hdrl_data+i+4);
AVI->track[AVI->aptr].mp3rate = 8*str2ulong(hdrl_data+i+8)/1000;
AVI->track[AVI->aptr].a_bits = str2ushort(hdrl_data+i+14);
}
}
else if(strnicmp((char*)hdrl_data+i,"indx",4) == 0) {
char *a;
if(lasttag == 1)
{
a = (char*)hdrl_data+i;
AVI->video_superindex = (avisuperindex_chunk *) gf_malloc (sizeof (avisuperindex_chunk));
memset(AVI->video_superindex, 0, sizeof (avisuperindex_chunk));
memcpy (AVI->video_superindex->fcc, a, 4);
a += 4;
AVI->video_superindex->dwSize = str2ulong((unsigned char *)a);
a += 4;
AVI->video_superindex->wLongsPerEntry = str2ushort((unsigned char *)a);
a += 2;
AVI->video_superindex->bIndexSubType = *a;
a += 1;
AVI->video_superindex->bIndexType = *a;
a += 1;
AVI->video_superindex->nEntriesInUse = str2ulong((unsigned char *)a);
a += 4;
memcpy (AVI->video_superindex->dwChunkId, a, 4);
a += 4;
a += 4;
a += 4;
a += 4;
if (AVI->video_superindex->bIndexSubType != 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Invalid Header, bIndexSubType != 0\n"));
}
AVI->video_superindex->aIndex = (avisuperindex_entry*)
gf_malloc (AVI->video_superindex->wLongsPerEntry * AVI->video_superindex->nEntriesInUse * sizeof (u32));
for (j=0; j<AVI->video_superindex->nEntriesInUse; ++j) {
AVI->video_superindex->aIndex[j].qwOffset = str2ullong ((unsigned char*)a);
a += 8;
AVI->video_superindex->aIndex[j].dwSize = str2ulong ((unsigned char*)a);
a += 4;
AVI->video_superindex->aIndex[j].dwDuration = str2ulong ((unsigned char*)a);
a += 4;
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] 0x%llx 0x%lx %lu\n", j,
(unsigned int long)AVI->video_superindex->aIndex[j].qwOffset,
(unsigned long)AVI->video_superindex->aIndex[j].dwSize,
(unsigned long)AVI->video_superindex->aIndex[j].dwDuration));
#endif
}
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] FOURCC \"%c%c%c%c\"\n", AVI->video_superindex->fcc[0], AVI->video_superindex->fcc[1],
AVI->video_superindex->fcc[2], AVI->video_superindex->fcc[3]));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] LEN \"%ld\"\n", (long)AVI->video_superindex->dwSize));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] wLongsPerEntry \"%d\"\n", AVI->video_superindex->wLongsPerEntry));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexSubType \"%d\"\n", AVI->video_superindex->bIndexSubType));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexType \"%d\"\n", AVI->video_superindex->bIndexType));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] nEntriesInUse \"%ld\"\n", (long)AVI->video_superindex->nEntriesInUse));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] dwChunkId \"%c%c%c%c\"\n", AVI->video_superindex->dwChunkId[0], AVI->video_superindex->dwChunkId[1],
AVI->video_superindex->dwChunkId[2], AVI->video_superindex->dwChunkId[3]));
#endif
AVI->is_opendml = 1;
}
else if(lasttag == 2)
{
a = (char*) hdrl_data+i;
AVI->track[AVI->aptr].audio_superindex = (avisuperindex_chunk *) gf_malloc (sizeof (avisuperindex_chunk));
memcpy (AVI->track[AVI->aptr].audio_superindex->fcc, a, 4);
a += 4;
AVI->track[AVI->aptr].audio_superindex->dwSize = str2ulong((unsigned char*)a);
a += 4;
AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry = str2ushort((unsigned char*)a);
a += 2;
AVI->track[AVI->aptr].audio_superindex->bIndexSubType = *a;
a += 1;
AVI->track[AVI->aptr].audio_superindex->bIndexType = *a;
a += 1;
AVI->track[AVI->aptr].audio_superindex->nEntriesInUse = str2ulong((unsigned char*)a);
a += 4;
memcpy (AVI->track[AVI->aptr].audio_superindex->dwChunkId, a, 4);
a += 4;
a += 4;
a += 4;
a += 4;
if (AVI->track[AVI->aptr].audio_superindex->bIndexSubType != 0) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Invalid Header, bIndexSubType != 0\n"));
}
AVI->track[AVI->aptr].audio_superindex->aIndex = (avisuperindex_entry*)
gf_malloc (AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry *
AVI->track[AVI->aptr].audio_superindex->nEntriesInUse * sizeof (u32));
for (j=0; j<AVI->track[AVI->aptr].audio_superindex->nEntriesInUse; ++j) {
AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset = str2ullong ((unsigned char*)a);
a += 8;
AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize = str2ulong ((unsigned char*)a);
a += 4;
AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration = str2ulong ((unsigned char*)a);
a += 4;
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] [%d] 0x%llx 0x%lx %lu\n", j,
(unsigned int long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].qwOffset,
(unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwSize,
(unsigned long)AVI->track[AVI->aptr].audio_superindex->aIndex[j].dwDuration));
#endif
}
#ifdef DEBUG_ODML
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] FOURCC \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->fcc));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] LEN \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->dwSize));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] wLongsPerEntry \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->wLongsPerEntry));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexSubType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexSubType));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] bIndexType \"%d\"\n", AVI->track[AVI->aptr].audio_superindex->bIndexType));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] nEntriesInUse \"%ld\"\n", (long)AVI->track[AVI->aptr].audio_superindex->nEntriesInUse));
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] dwChunkId \"%.4s\"\n", AVI->track[AVI->aptr].audio_superindex->dwChunkId[0]));
#endif
}
i += 8;
}
else if((strnicmp((char*)hdrl_data+i,"JUNK",4) == 0) ||
(strnicmp((char*)hdrl_data+i,"strn",4) == 0) ||
(strnicmp((char*)hdrl_data+i,"vprp",4) == 0)) {
i += 8;
} else
{
i += 8;
lasttag = 0;
}
i += (u32) n;
}
gf_free(hdrl_data);
if(!vids_strh_seen || !vids_strf_seen) ERR_EXIT(AVI_ERR_NO_VIDS)
AVI->video_tag[0] = AVI->video_strn/10 + '0';
AVI->video_tag[1] = AVI->video_strn%10 + '0';
AVI->video_tag[2] = 'd';
AVI->video_tag[3] = 'b';
if(!AVI->track[0].a_chans) AVI->track[0].audio_strn = 99;
{
int i=0;
for(j=0; j<AVI->anum+1; ++j) {
if (j == AVI->video_strn) continue;
AVI->track[i].audio_tag[0] = j/10 + '0';
AVI->track[i].audio_tag[1] = j%10 + '0';
AVI->track[i].audio_tag[2] = 'w';
AVI->track[i].audio_tag[3] = 'b';
++i;
}
}
gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
if(!getIndex) return(0);
idx_type = 0;
if(AVI->idx)
{
s64 pos, len;
for(i=0; i<AVI->n_idx; i++)
if( strnicmp((char *)AVI->idx[i],(char *)AVI->video_tag,3)==0 ) break;
if(i>=AVI->n_idx) ERR_EXIT(AVI_ERR_NO_VIDS)
pos = str2ulong(AVI->idx[i]+ 8);
len = str2ulong(AVI->idx[i]+12);
gf_fseek(AVI->fdes,pos,SEEK_SET);
if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
{
idx_type = 1;
}
else
{
gf_fseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
if(avi_read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
if( strnicmp(data,(char *)AVI->idx[i],4)==0 && str2ulong((unsigned char *)data+4)==len )
{
idx_type = 2;
}
}
}
if(idx_type == 0 && !AVI->is_opendml && !AVI->total_frames)
{
gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET);
AVI->n_idx = 0;
while(1)
{
if( avi_read(AVI->fdes,data,8) != 8 ) break;
n = str2ulong((unsigned char *)data+4);
if(strnicmp(data,"LIST",4)==0)
{
gf_fseek(AVI->fdes,4,SEEK_CUR);
continue;
}
if( ( (data[2]=='d' || data[2]=='D') &&
(data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') )
|| ( (data[2]=='w' || data[2]=='W') &&
(data[3]=='b' || data[3]=='B') ) )
{
u64 __pos = gf_ftell(AVI->fdes) - 8;
avi_add_index_entry(AVI,(unsigned char *)data,0,__pos,n);
}
gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
}
idx_type = 1;
}
if (AVI->is_opendml) {
u64 offset = 0;
int hdrl_len = 4+4+2+1+1+4+4+8+4;
char *en, *chunk_start;
int k = 0;
u32 audtr = 0;
u32 nrEntries = 0;
AVI->video_index = NULL;
nvi = 0;
for(audtr=0; audtr<AVI->anum; ++audtr) {
nai[audtr] = 0;
tot[audtr] = 0;
}
for (j=0; j<AVI->video_superindex->nEntriesInUse; j++) {
chunk_start = en = (char*) gf_malloc ((u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len) );
if (gf_fseek(AVI->fdes, AVI->video_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) {
gf_free(chunk_start);
continue;
}
if (avi_read(AVI->fdes, en, (u32) (AVI->video_superindex->aIndex[j].dwSize+hdrl_len) ) <= 0) {
gf_free(chunk_start);
continue;
}
nrEntries = str2ulong((unsigned char*)en + 12);
#ifdef DEBUG_ODML
#endif
offset = str2ullong((unsigned char*)en + 20);
en += hdrl_len;
nvi += nrEntries;
AVI->video_index = (video_index_entry *) gf_realloc (AVI->video_index, nvi * sizeof (video_index_entry));
if (!AVI->video_index) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] out of mem (size = %ld)\n", nvi * sizeof (video_index_entry)));
exit(1);
}
while (k < nvi) {
AVI->video_index[k].pos = offset + str2ulong((unsigned char*)en);
en += 4;
AVI->video_index[k].len = str2ulong_len((unsigned char*)en);
AVI->video_index[k].key = str2ulong_key((unsigned char*)en);
en += 4;
if (AVI->video_index[k].pos-offset == 0 && AVI->video_index[k].len == 0) {
k--;
nvi--;
}
#ifdef DEBUG_ODML
#endif
k++;
}
gf_free(chunk_start);
}
AVI->video_frames = nvi;
if (AVI->video_frames == 0) {
AVI->is_opendml=0;
goto multiple_riff;
}
for(audtr=0; audtr<AVI->anum; ++audtr) {
k = 0;
if (!AVI->track[audtr].audio_superindex) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] (%s) cannot read audio index for track %d\n", __FILE__, audtr));
continue;
}
for (j=0; j<AVI->track[audtr].audio_superindex->nEntriesInUse; j++) {
chunk_start = en = (char*)gf_malloc ((u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len));
if (gf_fseek(AVI->fdes, AVI->track[audtr].audio_superindex->aIndex[j].qwOffset, SEEK_SET) == (u64)-1) {
gf_free(chunk_start);
continue;
}
if (avi_read(AVI->fdes, en, (u32) (AVI->track[audtr].audio_superindex->aIndex[j].dwSize+hdrl_len)) <= 0) {
gf_free(chunk_start);
continue;
}
nrEntries = str2ulong((unsigned char*)en + 12);
#ifdef DEBUG_ODML
#endif
offset = str2ullong((unsigned char*)en + 20);
en += hdrl_len;
nai[audtr] += nrEntries;
AVI->track[audtr].audio_index = (audio_index_entry *) gf_realloc (AVI->track[audtr].audio_index, nai[audtr] * sizeof (audio_index_entry));
while (k < nai[audtr]) {
AVI->track[audtr].audio_index[k].pos = offset + str2ulong((unsigned char*)en);
en += 4;
AVI->track[audtr].audio_index[k].len = str2ulong_len((unsigned char*)en);
en += 4;
AVI->track[audtr].audio_index[k].tot = tot[audtr];
tot[audtr] += AVI->track[audtr].audio_index[k].len;
#ifdef DEBUG_ODML
#endif
++k;
}
gf_free(chunk_start);
}
AVI->track[audtr].audio_chunks = nai[audtr];
AVI->track[audtr].audio_bytes = tot[audtr];
}
}
else if (AVI->total_frames && !AVI->is_opendml && idx_type==0) {
multiple_riff:
gf_fseek(AVI->fdes, AVI->movi_start, SEEK_SET);
AVI->n_idx = 0;
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] Reconstructing index..."));
nvi = AVI->video_frames = AVI->total_frames;
nai[0] = AVI->track[0].audio_chunks = AVI->total_frames;
for(j=1; j<AVI->anum; ++j) AVI->track[j].audio_chunks = 0;
AVI->video_index = (video_index_entry *) gf_malloc(nvi*sizeof(video_index_entry));
if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
for(j=0; j<AVI->anum; ++j) {
if(AVI->track[j].audio_chunks) {
AVI->track[j].audio_index = (audio_index_entry *) gf_malloc((nai[j]+1)*sizeof(audio_index_entry));
memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
}
}
nvi = 0;
for(j=0; j<AVI->anum; ++j) {
nai[j] = 0;
tot[j] = 0;
}
aud_chunks = AVI->total_frames;
while(1)
{
if (nvi >= AVI->total_frames) break;
if( avi_read(AVI->fdes,data,8) != 8 ) break;
n = str2ulong((unsigned char *)data+4);
j=0;
if (aud_chunks - nai[j] -1 <= 0) {
aud_chunks += AVI->total_frames;
AVI->track[j].audio_index = (audio_index_entry *)
gf_realloc( AVI->track[j].audio_index, (aud_chunks+1)*sizeof(audio_index_entry));
if (!AVI->track[j].audio_index) {
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] Internal error in avilib -- no mem\n"));
AVI_errno = AVI_ERR_NO_MEM;
return -1;
}
}
if(
(data[0]=='0' || data[1]=='0') &&
(data[2]=='d' || data[2]=='D') &&
(data[3]=='b' || data[3]=='B' || data[3]=='c' || data[3]=='C') ) {
AVI->video_index[nvi].key = 0x0;
AVI->video_index[nvi].pos = gf_ftell(AVI->fdes);
AVI->video_index[nvi].len = (u32) n;
nvi++;
gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
}
else if(
(data[0]=='0' || data[1]=='1') &&
(data[2]=='w' || data[2]=='W') &&
(data[3]=='b' || data[3]=='B') ) {
AVI->track[j].audio_index[nai[j]].pos = gf_ftell(AVI->fdes);
AVI->track[j].audio_index[nai[j]].len = (u32) n;
AVI->track[j].audio_index[nai[j]].tot = tot[j];
tot[j] += AVI->track[j].audio_index[nai[j]].len;
nai[j]++;
gf_fseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR);
}
else {
gf_fseek(AVI->fdes,-4,SEEK_CUR);
}
}
if (nvi < AVI->total_frames) {
GF_LOG(GF_LOG_WARNING, GF_LOG_CONTAINER, ("[avilib] Uh? Some frames seems missing (%ld/%d)\n",
nvi, AVI->total_frames));
}
AVI->video_frames = nvi;
AVI->track[0].audio_chunks = nai[0];
for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] done. nvi=%ld nai=%ld tot=%ld\n", nvi, nai[0], tot[0]));
}
else
{
nvi = 0;
for(j=0; j<AVI->anum; ++j) nai[j] = 0;
for(i=0; i<AVI->n_idx; i++) {
if(strnicmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) nvi++;
for(j=0; j<AVI->anum; ++j) if(strnicmp((char *)AVI->idx[i], AVI->track[j].audio_tag,4) == 0) nai[j]++;
}
AVI->video_frames = nvi;
for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_chunks = nai[j];
if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS);
AVI->video_index = (video_index_entry *) gf_malloc(nvi*sizeof(video_index_entry));
if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
for(j=0; j<AVI->anum; ++j) {
if(AVI->track[j].audio_chunks) {
AVI->track[j].audio_index = (audio_index_entry *) gf_malloc((nai[j]+1)*sizeof(audio_index_entry));
memset(AVI->track[j].audio_index, 0, (nai[j]+1)*(sizeof(audio_index_entry)));
if(AVI->track[j].audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM);
}
}
nvi = 0;
for(j=0; j<AVI->anum; ++j) {
nai[j] = 0;
tot[j] = 0;
}
ioff = idx_type == 1 ? 8 : (u32)AVI->movi_start+4;
for(i=0; i<AVI->n_idx; i++) {
if(strnicmp((char *)AVI->idx[i],AVI->video_tag,3) == 0) {
AVI->video_index[nvi].key = str2ulong(AVI->idx[i]+ 4);
AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12);
nvi++;
}
for(j=0; j<AVI->anum; ++j) {
if(strnicmp((char *)AVI->idx[i],AVI->track[j].audio_tag,4) == 0) {
AVI->track[j].audio_index[nai[j]].pos = str2ulong(AVI->idx[i]+ 8)+ioff;
AVI->track[j].audio_index[nai[j]].len = str2ulong(AVI->idx[i]+12);
AVI->track[j].audio_index[nai[j]].tot = tot[j];
tot[j] += AVI->track[j].audio_index[nai[j]].len;
nai[j]++;
}
}
}
for(j=0; j<AVI->anum; ++j) AVI->track[j].audio_bytes = tot[j];
}
gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
AVI->video_pos = 0;
return(0);
}
int AVI_video_frames(avi_t *AVI)
{
return AVI->video_frames;
}
int AVI_video_width(avi_t *AVI)
{
return AVI->width;
}
int AVI_video_height(avi_t *AVI)
{
return AVI->height;
}
double AVI_frame_rate(avi_t *AVI)
{
return AVI->fps;
}
char* AVI_video_compressor(avi_t *AVI)
{
return AVI->compressor2;
}
int AVI_max_video_chunk(avi_t *AVI)
{
return AVI->max_len;
}
int AVI_audio_tracks(avi_t *AVI)
{
return(AVI->anum);
}
int AVI_audio_channels(avi_t *AVI)
{
return AVI->track[AVI->aptr].a_chans;
}
int AVI_audio_mp3rate(avi_t *AVI)
{
return AVI->track[AVI->aptr].mp3rate;
}
int AVI_audio_padrate(avi_t *AVI)
{
return AVI->track[AVI->aptr].padrate;
}
int AVI_audio_bits(avi_t *AVI)
{
return AVI->track[AVI->aptr].a_bits;
}
int AVI_audio_format(avi_t *AVI)
{
return AVI->track[AVI->aptr].a_fmt;
}
int AVI_audio_rate(avi_t *AVI)
{
return AVI->track[AVI->aptr].a_rate;
}
int AVI_frame_size(avi_t *AVI, int frame)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->video_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
if(frame < 0 || frame >= AVI->video_frames) return 0;
return (u32) (AVI->video_index[frame].len);
}
int AVI_audio_size(avi_t *AVI, int frame)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->track[AVI->aptr].audio_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
if(frame < 0 || frame >= AVI->track[AVI->aptr].audio_chunks) return -1;
return (u32) (AVI->track[AVI->aptr].audio_index[frame].len);
}
u64 AVI_get_video_position(avi_t *AVI, int frame)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return (u64) -1;
}
if(!AVI->video_index) {
AVI_errno = AVI_ERR_NO_IDX;
return (u64) -1;
}
if(frame < 0 || frame >= AVI->video_frames) return 0;
return(AVI->video_index[frame].pos);
}
int AVI_seek_start(avi_t *AVI)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
gf_fseek(AVI->fdes,AVI->movi_start,SEEK_SET);
AVI->video_pos = 0;
return 0;
}
int AVI_set_video_position(avi_t *AVI, int frame)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->video_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
if (frame < 0 ) frame = 0;
AVI->video_pos = frame;
return 0;
}
int AVI_set_audio_bitrate(avi_t *AVI, int bitrate)
{
if(AVI->mode==AVI_MODE_READ) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
AVI->track[AVI->aptr].mp3rate = bitrate;
return 0;
}
int AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe)
{
int n;
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->video_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
if(AVI->video_pos < 0 || AVI->video_pos >= AVI->video_frames) return -1;
n = (u32) AVI->video_index[AVI->video_pos].len;
*keyframe = (AVI->video_index[AVI->video_pos].key==0x10) ? 1:0;
if (vidbuf == NULL) {
AVI->video_pos++;
return n;
}
gf_fseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET);
if (avi_read(AVI->fdes,vidbuf,n) != (u32) n)
{
AVI_errno = AVI_ERR_READ;
return -1;
}
AVI->video_pos++;
return n;
}
int AVI_get_audio_position_index(avi_t *AVI)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->track[AVI->aptr].audio_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
return (AVI->track[AVI->aptr].audio_posc);
}
int AVI_set_audio_position_index(avi_t *AVI, int indexpos)
{
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->track[AVI->aptr].audio_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
if(indexpos > AVI->track[AVI->aptr].audio_chunks) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
AVI->track[AVI->aptr].audio_posc = indexpos;
AVI->track[AVI->aptr].audio_posb = 0;
return 0;
}
int AVI_set_audio_position(avi_t *AVI, int byte)
{
int n0, n1, n;
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->track[AVI->aptr].audio_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
if(byte < 0) byte = 0;
n0 = 0;
n1 = AVI->track[AVI->aptr].audio_chunks;
while(n0<n1-1)
{
n = (n0+n1)/2;
if(AVI->track[AVI->aptr].audio_index[n].tot>(u32) byte)
n1 = n;
else
n0 = n;
}
AVI->track[AVI->aptr].audio_posc = n0;
AVI->track[AVI->aptr].audio_posb = (u32) (byte - AVI->track[AVI->aptr].audio_index[n0].tot);
return 0;
}
int AVI_read_audio(avi_t *AVI, char *audbuf, int bytes, int *continuous)
{
int nr, left, todo;
s64 pos;
if(AVI->mode==AVI_MODE_WRITE) {
AVI_errno = AVI_ERR_NOT_PERM;
return -1;
}
if(!AVI->track[AVI->aptr].audio_index) {
AVI_errno = AVI_ERR_NO_IDX;
return -1;
}
nr = 0;
if (bytes==0) {
AVI->track[AVI->aptr].audio_posc++;
AVI->track[AVI->aptr].audio_posb = 0;
}
*continuous = 1;
while(bytes>0)
{
s64 ret;
left = (int) (AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].len - AVI->track[AVI->aptr].audio_posb);
if(left==0)
{
if(AVI->track[AVI->aptr].audio_posc>=AVI->track[AVI->aptr].audio_chunks-1) return nr;
AVI->track[AVI->aptr].audio_posc++;
AVI->track[AVI->aptr].audio_posb = 0;
*continuous = 0;
continue;
}
if(bytes<left)
todo = bytes;
else
todo = left;
pos = AVI->track[AVI->aptr].audio_index[AVI->track[AVI->aptr].audio_posc].pos + AVI->track[AVI->aptr].audio_posb;
gf_fseek(AVI->fdes, pos, SEEK_SET);
if ( (ret = avi_read(AVI->fdes,audbuf+nr,todo)) != todo)
{
GF_LOG(GF_LOG_ERROR, GF_LOG_CONTAINER, ("[avilib] XXX pos = %"LLD", ret = %"LLD", todo = %ld\n", pos, ret, todo));
AVI_errno = AVI_ERR_READ;
return -1;
}
bytes -= todo;
nr += todo;
AVI->track[AVI->aptr].audio_posb += todo;
}
return nr;
}
int AVI_read_data(avi_t *AVI, char *vidbuf, int max_vidbuf,
char *audbuf, int max_audbuf,
int *len)
{
s64 n;
char data[8];
if(AVI->mode==AVI_MODE_WRITE) return 0;
while(1)
{
if( avi_read(AVI->fdes,data,8) != 8 ) return 0;
if(strnicmp(data,"LIST",4) == 0)
{
gf_fseek(AVI->fdes,4,SEEK_CUR);
continue;
}
n = PAD_EVEN(str2ulong((unsigned char *)data+4));
if(strnicmp(data,AVI->video_tag,3) == 0)
{
*len = (u32) n;
AVI->video_pos++;
if(n>max_vidbuf)
{
gf_fseek(AVI->fdes,n,SEEK_CUR);
return -1;
}
if(avi_read(AVI->fdes,vidbuf, (u32) n) != n ) return 0;
return 1;
}
else if(strnicmp(data,AVI->track[AVI->aptr].audio_tag,4) == 0)
{
*len = (u32) n;
if(n>max_audbuf)
{
gf_fseek(AVI->fdes,n,SEEK_CUR);
return -2;
}
if(avi_read(AVI->fdes,audbuf, (u32) n) != n ) return 0;
return 2;
break;
}
else if(gf_fseek(AVI->fdes,n,SEEK_CUR) == (u64) -1) return 0;
}
}
u64 AVI_max_size(void)
{
return((u64) AVI_MAX_LEN);
}
#endif