You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

915 lines
23 KiB

/*
* aviindex.c
*
* extracts the index of an AVI file for easy seeking with --nav_seek
*
* Copyright (C) Tilmann Bitterberg - June 2003
*
* This file is part of transcode, a video stream processing tool
*
* transcode is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* transcode 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "transcode.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "libtc/xio.h"
#include "aud_scan.h"
#define EXE "aviindex"
/* AVI_info is no longer in avilib */
void AVI_info(avi_t *avifile);
void version(void)
{
printf("%s (%s v%s) (C) 2003-2004 Tilmann Bitterberg,"
" 2004-2010 Transcode Team\n",
EXE, PACKAGE, VERSION);
}
static void usage(int status)
{
version();
printf("\nUsage: %s [options]\n", EXE);
printf(" -o file output file\n");
printf(" -i file input file\n");
printf(" -f force the use of the existing index\n");
printf(" only to use when avi > 2GB, because\n");
printf(" the default is to -n with big files\n");
printf(" -n read index in \"smart\" mode: don't use the existing index\n");
printf(" -x don't use the existing index to generate the keyframes\n");
printf(" this flag forces -n\n");
printf(" -v print version\n");
exit(status);
}
#define PAD_EVEN(x) ( ((x)+1) & ~1 )
static unsigned long str2ulong(unsigned char *str)
{
return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );
}
#define AVI_MAX_LEN (UINT_MAX-(1<<20)*16-2048)
static inline uint32_t SWAP(uint32_t a) {
#ifdef WORDS_BIGENDIAN
return ( (a<<24&0xff000000) | (a<< 8&0x00ff0000) |
(a>> 8&0x0000ff00) | (a>>24&0x000000ff));
#else
return a;
#endif
}
static inline int avi_stream_id(unsigned int id){
unsigned char *p=(unsigned char *)&id;
unsigned char a,b;
#if WORDS_BIGENDIAN
a=p[3]-'0'; b=p[2]-'0';
#else
a=p[0]-'0'; b=p[1]-'0';
#endif
if(a>9 || b>9) return 100; // invalid ID
return a*10+b;
}
// returns 1 for video
// 2 for 1st audio
// 3 for 2nd audio
static int avi_stream_nr(int id)
{
unsigned char *p = (unsigned char *)&id;
#if WORDS_BIGENDIAN
if (p[1] == 'd') {
return 1;
} else {
int res = (p[3]-'0')+(p[2]-'0');
res = (res==0)?2:res+1;
return res;
}
#else
if (p[2] == 'd') {
return 1;
} else {
int res = (p[0]-'0')+(p[1]-'0');
res = (res==0)?2:res+1;
return res;
}
#endif
return 0;
}
const int LEN=10;
typedef enum {
UNKNOWN = 0,
RIFF,
AVIIDX1,
MPIDX1,
} ftype_t;
typedef struct {
uint32_t ckid;
uint32_t dwFlags;
uint32_t dwChunkOffset;
uint32_t dwChunkLength;
} AVIINDEXENTRY;
static int aviidx1_to_mpidx1(char *in_file, FILE *out_fd)
{
char *data;
FILE *in;
int size=0, i;
AVIINDEXENTRY *idx;
char line[255], d;
in = fopen (in_file, "r");
if (!in) return 1;
// skip header
fgets (line, 255, in);
fgets (line, 255, in);
while (fgets(line, 255, in)) {
d = line[5] - '1';
if (d == 0) {
size++;
} else if (d == 1 || d == 2 || d == 3 || d == 4 ||
d == 5 || d == 6 || d == 7 || d == 8 ) {
size++;
} else continue;
}
data = malloc (size * sizeof (AVIINDEXENTRY));
fseek(in, 0, SEEK_SET);
fgets (line, 255, in); fgets (line, 255, in);
i = size;
idx = &((AVIINDEXENTRY *)data)[0];
while (fgets(line, 255, in) && i--) {
char *c=line;
idx->ckid=*(int *)c;
idx->ckid=SWAP(idx->ckid);
c = strchr(c, ' ')+1; // type
c = strchr(c, ' ')+1; // chunk
c = strchr(c, ' ')+1; // chunk/type
c = strchr(c, ' ')+1; // pos
idx->dwChunkOffset = strtol(c, &c, 10);
idx->dwChunkLength = strtol(c+1, &c, 10);
idx->dwFlags = strtol(c+1, &c, 10);
idx->dwFlags = idx->dwFlags?0x10:0;
idx++;
}
fwrite ("MPIDX1", 6, 1, out_fd);
fwrite (&size, 4, 1, out_fd);
fwrite (data, sizeof(AVIINDEXENTRY), size, out_fd);
free(data);
fclose (in);
fclose(out_fd);
return 0;
}
static int mpidx1_to_aviidx1(char *in_file, FILE *out_fd)
{
char head[10];
char *data;
FILE *in;
int size, i;
AVIINDEXENTRY *idx;
int streams[100];
in = fopen (in_file, "r");
if (!in) return 1;
fread (head, 10, 1, in);
// header. Magic tag is AVIIDX1
fprintf(out_fd, "AVIIDX1 # Generated by %s (%s-%s)\n", EXE, PACKAGE, VERSION); // Magic
fprintf(out_fd, "TAG TYPE CHUNK CHUNK/TYPE POS LEN KEY MS\n");
size = *(int *)(head+6);
data = malloc (size * sizeof(AVIINDEXENTRY));
memset (streams, 0, sizeof(streams));
if (size != fread (data, sizeof(AVIINDEXENTRY), size, in)) {
perror("fread"); return 1;
}
for (i = 0; i<size; i++) {
uint32_t ckid;
idx = &((AVIINDEXENTRY *)data)[i];
ckid = SWAP(idx->ckid);
fprintf(out_fd,
"%.4s %d %d %d %d %d %d 0\n",
(char *)&ckid,
avi_stream_nr(idx->ckid),
i,
streams[avi_stream_id(idx->ckid)],
idx->dwChunkOffset,
idx->dwChunkLength,
idx->dwFlags?1:0);
streams[avi_stream_id(idx->ckid)]++;
}
free(data);
fclose (in);
fclose(out_fd);
return 0;
}
// data is only 8 bytes long
static int AVI_read_data_fast(avi_t *AVI, char *buf, off_t *pos, off_t *len, off_t *key, char *data)
{
/*
* Return codes:
*
* 0 = reached EOF
* 1 = video data read
* 2 = audio data read from track 0
* 3 = audio data read from track 1
* 4 = audio data read from track 2
* ....
* 10 = traditional idx1 chunk
*/
off_t n;
int rlen;
*key=(off_t)0;
if(AVI->mode==AVI_MODE_WRITE) return 0;
while(1)
{
/* Read tag and length */
if( xio_read(AVI->fdes,data,8) != 8 ) return 0;
n = PAD_EVEN(str2ulong(data+4));
if(strncasecmp(data,"LIST",4) == 0 ||
strncasecmp(data,"RIFF",4) == 0) { // prevents skipping extended RIFF chunks
if( xio_read(AVI->fdes,data,4) != 4 ) return 0;
n -= 4;
// put here tags of lists that need to be looked into
if(strncasecmp(data,"movi",4) == 0 ||
strncasecmp(data,"rec ",4) == 0 ||
strncasecmp(data,"AVI ",4) == 0 ||
strncasecmp(data,"AVIX",4) == 0) {
// xio_lseek(AVI->fdes,-4,SEEK_CUR);
continue; // proceed to look into it
} // otherwise seek over it later on
}
// the following list of comparisons should not include list tags;
// these should all go in the list above
if(strncasecmp(data,"IDX1",4) == 0)
{
// deal with it to extract keyframe info
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
//fprintf (stderr, "Found an index chunk at %lld len %lld\n", *pos, *len);
if(xio_lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) return 0;
return 10;
}
if(strncasecmp(data,AVI->video_tag,3) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->video_pos++;
rlen = n;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 1;
}
else if(AVI->anum>=1 && strncasecmp(data,AVI->track[0].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[0].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 2;
break;
}
else if(AVI->anum>=2 && strncasecmp(data,AVI->track[1].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[1].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 3;
break;
}
else if(AVI->anum>=3 && strncasecmp(data,AVI->track[2].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[2].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 4;
break;
}
else if(AVI->anum>=4 && strncasecmp(data,AVI->track[3].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[3].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 5;
break;
}
else if(AVI->anum>=5 && strncasecmp(data,AVI->track[4].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[4].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 6;
break;
}
else if(AVI->anum>=6 && strncasecmp(data,AVI->track[5].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[5].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 7;
break;
}
else if(AVI->anum>=7 && strncasecmp(data,AVI->track[6].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[6].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 8;
break;
}
else if(AVI->anum>=8 && strncasecmp(data,AVI->track[7].audio_tag,4) == 0)
{
*len = str2ulong(data+4);
*pos = xio_lseek(AVI->fdes, 0, SEEK_CUR)-(off_t)8;
AVI->track[7].audio_posc++;
rlen = (n<LEN)?n:LEN;
xio_read(AVI->fdes, buf, rlen);
if(xio_lseek(AVI->fdes,n-rlen,SEEK_CUR)==(off_t)-1) return 0;
return 9;
break;
} else {
if(xio_lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) return 0;
}
// else if(xio_lseek(AVI->fdes,n,SEEK_CUR)==(off_t)-1) return 0;
}
}
static int is_key(unsigned char *data, long size, char *codec)
{
if (strncasecmp(codec, "div3", 4) == 0) {
int32_t c=( (data[0]<<24) | (data[1]<<16) | (data[2]<<8) | (data[3]&0xff) );
if(c&0x40000000) return(0);
else return 1;
} else if (strncasecmp(codec, "xvid", 4) == 0 || strncasecmp(codec, "divx", 4) == 0
|| strncasecmp(codec, "dx50", 4) == 0 || strncasecmp(codec, "div4", 4) == 0
|| strncasecmp(codec, "mpg4", 4) == 0) {
int result = 0;
int i;
for(i = 0; i < size - 5; i++)
{
if( data[i] == 0x00 && data[i + 1] == 0x00 &&
data[i + 2] == 0x01 && data[i + 3] == 0xb6) {
if((data[i + 4] & 0xc0) == 0x0) return 1;
else return 0;
}
}
return result;
}
// mjpeg, uncompressed, etc
return 1;
}
int main(int argc, char *argv[])
{
avi_t *avifile1=NULL;
char *in_file=NULL, *out_file=NULL;
long frames;
double fps;
int track_num=0, aud_tracks;
int ret;
long i=0, chunk=0;
int ch;
int progress=0, old_progress=0;
long rate;
int format, chan, bits;
int aud_bitrate = 0;
FILE *out_fd = NULL;
int open_without_index=0,index_keyframes=0;
int force_with_index=0;
double vid_ms = 0.0, print_ms = 0.0;
double aud_ms [ AVI_MAX_TRACKS ];
char tag[8];
char *data;
int vid_chunks=0, aud_chunks[AVI_MAX_TRACKS];
off_t pos, len, key=0, index_pos=0, index_len=0,size=0;
struct stat st;
char *codec;
int idx_type=0;
off_t ioff;
char fcclen[8]; // FOURCC + len
ftype_t ftype;
FILE *idxfile;
ac_init(AC_ALL);
if(argc==1) usage(EXIT_FAILURE);
for (i=0; i<AVI_MAX_TRACKS; i++) {
aud_chunks[i] = 0;
aud_ms[i] = 0;
}
while ((ch = getopt(argc, argv, "a:vi:o:nxf?h")) != -1)
{
switch (ch) {
case 'i':
if(optarg[0]=='-') usage(EXIT_FAILURE);
in_file=optarg;
break;
case 'a':
if(optarg[0]=='-') usage(EXIT_FAILURE);
track_num = atoi(optarg);
if(track_num<0) usage(EXIT_FAILURE);
break;
case 'o':
if(optarg[0]=='-') usage(EXIT_FAILURE);
out_file=optarg;
break;
case 'n':
open_without_index=1;
break;
case 'x':
open_without_index=1;
index_keyframes=1;
break;
case 'f':
force_with_index=1;
break;
case 'v':
version();
exit(0);
break;
case 'h':
usage(EXIT_SUCCESS);
default:
usage(EXIT_FAILURE);
}
}
// check
if(in_file==NULL) usage(EXIT_FAILURE);
if (!out_file) out_fd = stdout;
else out_fd = fopen(out_file, "w+r");
if (!out_fd) {
perror("ERROR cannot open outputfile");
exit(1);
}
idxfile = fopen(in_file, "r");
fread (fcclen, 8, 1, idxfile);
if (strncasecmp(fcclen, "RIFF", 4) == 0) ftype = RIFF;
else if (strncasecmp(fcclen, "AVIIDX1", 7) == 0) ftype = AVIIDX1;
else if (strncasecmp(fcclen, "MPIDX1", 6) == 0) ftype = MPIDX1;
else ftype = UNKNOWN;
fclose (idxfile);
switch (ftype) {
case RIFF: fprintf(stderr, "[%s] Seems to be an AVI file.\n", EXE); break;
case AVIIDX1: fprintf(stderr, "[%s] Converting a transcode to an mplayer index file.\n", EXE);
return aviidx1_to_mpidx1(in_file, out_fd);
case MPIDX1: fprintf(stderr, "[%s] Converting an mplayer to a transcode index file.\n", EXE);
return mpidx1_to_aviidx1(in_file, out_fd);
default: fprintf(stderr, "[%s] Unrecognized format\n", EXE); return (1);
}
// if file is larger than 2GB, regen index
if (stat(in_file, &st)<0) {
perror("Stat input file");
return 1;
}
size = st.st_size;
if (size > (off_t)AVI_MAX_LEN/2)
if (!force_with_index) open_without_index = 1;
if (open_without_index)
if (index_keyframes) fprintf(stderr, "[%s] Open \"%s\" without index and don't use index for keyframes info\n",EXE, in_file);
else fprintf(stderr, "[%s] Open \"%s\" without index but use index (if any) for keyframes info\n",EXE, in_file);
else
fprintf(stderr, "[%s] Open \"%s\" with index (fast)\n", EXE, in_file);
// header. Magic tag is AVIIDX1
fprintf(out_fd, "AVIIDX1 # Generated by %s (%s-%s)\n", EXE, PACKAGE, VERSION); // Magic
fprintf(out_fd, "TAG TYPE CHUNK CHUNK/TYPE POS LEN KEY MS\n");
data = malloc (5*1024*1204);
if (open_without_index) {
// open file with index.
if(NULL == (avifile1 = AVI_open_input_file(in_file,0))) {
AVI_print_error("AVI open input file");
exit(1);
}
aud_tracks = frames = 0;
frames = AVI_video_frames(avifile1);
fps = AVI_frame_rate (avifile1);
codec = AVI_video_compressor(avifile1);
aud_tracks = AVI_audio_tracks(avifile1);
//printf("frames (%ld), aud_tracks (%d)\n", frames, aud_tracks);
pos = key = len = (off_t)0;
i = 0;
while ( (ret = AVI_read_data_fast (avifile1, data, &pos, &len, &key, fcclen)) != 0) {
int audtr = ret-2;
/* don't need this and it saves time
* */
if (audtr>=0 && audtr<=7) {
AVI_set_audio_track(avifile1, audtr);
format = AVI_audio_format (avifile1);
chan = AVI_audio_channels(avifile1);
rate = AVI_audio_rate (avifile1);
bits = AVI_audio_bits (avifile1);
bits = bits==0?16:bits;
if (tc_format_ms_supported(format)) {
aud_bitrate = format==0x1?1:0;
if (!aud_bitrate && tc_get_audio_header(data, LEN, format, NULL, NULL, &aud_bitrate)<0) {
aud_ms[audtr] = vid_ms;
} else
aud_ms[audtr] += (len*8.0)/(format==0x1?((double)(rate*chan*bits)/1000.0):aud_bitrate);
}
}
switch (ret) {
case 1: ac_memcpy(tag, fcclen, 4);
print_ms = vid_ms = (avifile1->video_pos)*1000.0/fps;
chunk = avifile1->video_pos;
key = is_key(data, len, codec);
break;
case 2: case 3:
case 4: case 5:
case 6: case 7:
case 8:
case 9: ac_memcpy(tag, fcclen, 4);
print_ms = aud_ms[audtr];
chunk = avifile1->track[audtr].audio_posc;
break;
case 10: tc_snprintf(tag, sizeof(tag), "idx1");
index_pos = pos;
index_len = len;
print_ms = 0.0;
chunk = 0;
break;
case 0:
default:
// never get here
break;
}
//if (index_pos != pos)
// tag, chunk_nr
fprintf(out_fd, "%.4s %d %ld %ld %lld %lld %lld %.2f\n",
tag, ret, i, chunk-1,
(long long)pos, (long long)len, (long long)key,
print_ms);
i++;
// don't update the counter every chunk
progress = (int)(pos*100/size)+1;
if (old_progress != progress) {
fprintf(stderr, "[%s] Scanning ... %d%%\r", EXE, progress);
old_progress = progress;
}
}
fprintf(stderr, "\n");
// check if we have found an index chunk to restore keyframe info
if (!index_pos || !index_len || index_keyframes)
goto aviout;
fprintf(stderr, "[%s] Found an index chunk. Using it to regenerate keyframe info.\n", EXE);
fseek (out_fd, 0, SEEK_SET);
fgets(data, 100, out_fd); // magic
fgets(data, 100, out_fd); // comment
len = (off_t)0;
vid_chunks = 0;
xio_lseek(avifile1->fdes, index_pos+8, SEEK_SET);
while (len<index_len) {
xio_read(avifile1->fdes, tag, 8);
// if its a keyframe and is a video chunk
if (str2ulong(tag+4) && tag[1] == '0') {
int typen, keyn;
long chunkn, chunkptypen;
long long posn, lenn;
char tagn[5];
double msn=0.0;
chunk = (long)(len/16);
i = 0;
//fprintf(stderr, "keyframe in chunk %ld\n", chunk);
// find line "chunk" in the logfile
while (i<chunk-vid_chunks) {
fgets(data, 100, out_fd);
i++;
}
vid_chunks += (chunk-vid_chunks);
posn = ftell(out_fd);
fgets(data, 100, out_fd);
fseek(out_fd, posn, SEEK_SET);
sscanf(data, "%s %d %ld %ld %lld %lld %d %lf",
tagn, &typen, &chunkn, &chunkptypen, &posn, &lenn, &keyn, &msn);
fprintf(out_fd, "%s %d %ld %ld %lld %lld %d %.2f",
tagn, typen, chunkn, chunkptypen, posn, lenn, 1, msn);
}
xio_lseek(avifile1->fdes, 8, SEEK_CUR);
len += 16;
}
} else { // with index
// open file with index.
if(NULL == (avifile1 = AVI_open_input_file(in_file,1))) {
AVI_print_error("AVI open input file");
exit(1);
}
i=0;
AVI_info(avifile1);
// idx1 contains only info for first chunk of opendml AVI
if(avifile1->idx && !avifile1->is_opendml)
{
off_t pos, len;
/* Search the first videoframe in the idx1 and look where
it is in the file */
for(i=0;i<avifile1->n_idx;i++)
if( strncasecmp(avifile1->idx[i],avifile1->video_tag,3)==0 ) break;
pos = str2ulong(avifile1->idx[i]+ 8);
len = str2ulong(avifile1->idx[i]+12);
xio_lseek(avifile1->fdes,pos,SEEK_SET);
if(xio_read(avifile1->fdes,data,8)!=8) return 1;
if( strncasecmp(data,avifile1->idx[i],4)==0 && str2ulong(data+4)==len )
{
idx_type = 1; /* Index from start of file */
}
else
{
xio_lseek(avifile1->fdes,pos+avifile1->movi_start-4,SEEK_SET);
if(xio_read(avifile1->fdes,data,8)!=8) return 1;
if( strncasecmp(data,avifile1->idx[i],4)==0 && str2ulong(data+4)==len )
{
idx_type = 2; /* Index from start of movi list */
}
}
/* idx_type remains 0 if neither of the two tests above succeeds */
ioff = idx_type == 1 ? 0 : avifile1->movi_start-4;
//fprintf(stderr, "index type (%d), ioff (%ld)\n", idx_type, (long)ioff);
i=0;
//printf("nr idx: %d\n", avifile1->n_idx);
while (i<avifile1->n_idx) {
ac_memcpy(tag, avifile1->idx[i], 4);
// tag
fprintf(out_fd, "%c%c%c%c",
avifile1->idx[i][0], avifile1->idx[i][1],
avifile1->idx[i][2], avifile1->idx[i][3]);
// type, absolute chunk number
fprintf(out_fd, " %c %ld", avifile1->idx[i][1]+1, i);
switch (avifile1->idx[i][1]) {
case '0':
fprintf(out_fd, " %d", vid_chunks);
vid_chunks++;
break;
case '1': case '2':
case '3': case '4':
case '5': case '6':
case '7': case '8':
// uhoh
ret = avifile1->idx[i][1]-'0';
fprintf(out_fd, " %d", aud_chunks[ret]);
aud_chunks[ret]++;
break;
default:
fprintf(out_fd, " %d", -1);
break;
}
pos = str2ulong(avifile1->idx[i]+ 8);
pos += ioff;
// pos
fprintf(out_fd, " %llu", (unsigned long long)pos);
// len
fprintf(out_fd, " %lu", str2ulong(avifile1->idx[i]+12));
// flags (keyframe?);
fprintf(out_fd, " %d", (str2ulong(avifile1->idx[i]+ 4))?1:0);
// ms (not available here)
fprintf(out_fd, " %.2f", 0.0);
fprintf(out_fd, "\n");
i++;
}
}
else
{ // try to extract from the index that AVILIB built,
// possibly from OpenDML superindex
long aud_entry [ AVI_MAX_TRACKS ] = { 0 };
long vid_entry = 0;
char* tagp;
off_t pos, len = 0;
i = chunk = 0;
while (1) {
ret = pos = 0;
int j = 0;
if(vid_entry < avifile1->video_frames) {
pos = avifile1->video_index[vid_entry].pos;
len = avifile1->video_index[vid_entry].len;
key = (avifile1->video_index[vid_entry].key) & 16 ? 1 : 0;
chunk = vid_entry;
ret = 1;
}
for(j = 0; j < AVI_audio_tracks(avifile1); ++j) {
if(aud_entry[j] < avifile1->track[j].audio_chunks) {
if(!ret || avifile1->track[j].audio_index[aud_entry[j]].pos < pos) {
pos = avifile1->track[j].audio_index[aud_entry[j]].pos;
len = avifile1->track[j].audio_index[aud_entry[j]].len;
key = 0;
chunk = aud_entry[j];
ret = j + 2;
}
}
}
if(!ret) // end of all index streams
break;
if (ret == 1)
{
++vid_entry;
tagp = avifile1->video_tag;
}
else
{
aud_entry[ret-2]++;
tagp = avifile1->track[ret-2].audio_tag;
}
// index points to data in chunk, but chunk offset is needed here
pos -= 8;
fprintf(out_fd, "%.4s %d %ld %ld %lld %lld %lld %.2f\n",
tagp, ret, i, chunk,
(long long)pos, (long long)len, (long long)key,
0.0);
i++;
}
}
}
aviout:
free(data);
if (out_fd!=stdout) fclose (out_fd);
AVI_close(avifile1);
return(0);
}
/*************************************************************************/
/*
* Local variables:
* c-file-style: "stroustrup"
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
* indent-tabs-mode: nil
* End:
*
* vim: expandtab shiftwidth=4:
*/