📄 avilib.c
字号:
OUTLONG(0); /* Frame */
OUTLONG(0); /* Frame */
OUTLONG(0); /* Frame */
/* The audio stream format */
OUT4CC ("strf");
OUTLONG(16); /* # of bytes to follow */
OUTSHRT(AVI->a_fmt); /* Format */
OUTSHRT(AVI->a_chans); /* Number of channels */
OUTLONG(AVI->a_rate); /* SamplesPerSec */
OUTLONG(sampsize*AVI->a_rate); /* AvgBytesPerSec */
OUTSHRT(sampsize); /* BlockAlign */
OUTSHRT(AVI->a_bits); /* BitsPerSample */
/* Finish stream list, i.e. put number of bytes in the list to proper pos */
long2str(AVI_header+strl_start-4,nhb-strl_start);
}
/* Finish header list */
long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);
/* Calculate the needed amount of junk bytes, output junk */
njunk = HEADERBYTES - nhb - 8 - 12;
/* Safety first: if njunk <= 0, somebody has played with
HEADERBYTES without knowing what (s)he did.
This is a fatal error */
if(njunk<=0)
{
fprintf(stderr,"AVI_close_output_file: # of header bytes too small\n");
exit(1);
}
OUT4CC ("JUNK");
OUTLONG(njunk);
memset(AVI_header+nhb,0,njunk);
nhb += njunk;
/* Start the movi list */
OUT4CC ("LIST");
OUTLONG(movi_len); /* Length of list in bytes */
OUT4CC ("movi");
/* Output the header, truncate the file to the number of bytes
actually written, report an error if someting goes wrong */
if ( lseek(AVI->fdes,0,SEEK_SET)<0 ||
write(AVI->fdes,AVI_header,HEADERBYTES)!=HEADERBYTES ||
#ifndef _WINDOWS
ftruncate(AVI->fdes,AVI->pos)<0
#else
_chsize(AVI->fdes,AVI->pos)<0
#endif
)
{
AVI_errno = AVI_ERR_CLOSE;
return -1;
}
if(idxerror) return -1;
return 0;
}
/*
AVI_write_data:
Add video or audio data to the file;
Return values:
0 No error;
-1 Error, AVI_errno is set appropriatly;
*/
static int avi_write_data(avi_t *AVI, char *data, long length, int audio)
{
int n;
/* Check for maximum file length */
if ( (AVI->pos + 8 + length + 8 + (AVI->n_idx+1)*16) > AVI_MAX_LEN )
{
AVI_errno = AVI_ERR_SIZELIM;
return -1;
}
/* Add index entry */
if(audio)
n = avi_add_index_entry(AVI,"01wb",0x00,AVI->pos,length);
else
n = avi_add_index_entry(AVI,"00db",0x10,AVI->pos,length);
if(n) return -1;
/* Output tag and data */
if(audio)
n = avi_add_chunk(AVI,"01wb",data,length);
else
n = avi_add_chunk(AVI,"00db",data,length);
if (n) return -1;
return 0;
}
int AVI_write_frame(avi_t *AVI, char *data, long bytes)
{
long 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) ) 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; /* No previous real frame */
if(avi_add_index_entry(AVI,"00db",0x10,AVI->last_pos,AVI->last_len)) return -1;
AVI->video_frames++;
AVI->must_use_index = 1;
return 0;
}
int AVI_write_audio(avi_t *AVI, char *data, long bytes)
{
if(AVI->mode==AVI_MODE_READ) { AVI_errno = AVI_ERR_NOT_PERM; return -1; }
if( avi_write_data(AVI,data,bytes,1) ) return -1;
AVI->audio_bytes += bytes;
return 0;
}
long 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));
}
/*******************************************************************
* *
* Utilities for reading video and audio from an AVI File *
* *
*******************************************************************/
int AVI_close(avi_t *AVI)
{
int ret;
/* If the file was open for writing, the header and index still have
to be written */
if(AVI->mode == AVI_MODE_WRITE)
ret = avi_close_output_file(AVI);
else
ret = 0;
/* Even if there happened a error, we first clean up */
close(AVI->fdes);
if(AVI->idx) free(AVI->idx);
if(AVI->video_index) free(AVI->video_index);
if(AVI->audio_index) free(AVI->audio_index);
free(AVI);
return ret;
}
#define ERR_EXIT(x) \
{ \
AVI_close(AVI); \
AVI_errno = x; \
return 0; \
}
avi_t *AVI_open_input_file(const char *filename, int getIndex)
{
avi_t *AVI;
long i, n, rate, scale, idx_type;
unsigned char *hdrl_data;
long hdrl_len;
long nvi, nai, ioff;
long tot;
int lasttag = 0;
int vids_strh_seen = 0;
int vids_strf_seen = 0;
int auds_strh_seen = 0;
int auds_strf_seen = 0;
int num_stream = 0;
char data[256];
/* Create avi_t structure */
AVI = (avi_t *) 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; /* open for reading */
/* Open the file */
AVI->fdes = open(filename,OPEN_RDONLY);
if(AVI->fdes < 0)
{
AVI_errno = AVI_ERR_OPEN;
free(AVI);
return 0;
}
/* Read first 12 bytes and check that this is an AVI file */
if( read(AVI->fdes,data,12) != 12 ) ERR_EXIT(AVI_ERR_READ)
if( strncasecmp(data ,"RIFF",4) !=0 ||
strncasecmp(data+8,"AVI ",4) !=0 ) ERR_EXIT(AVI_ERR_NO_AVI)
/* Go through the AVI file and extract the header list,
the start position of the 'movi' list and an optionally
present idx1 tag */
hdrl_data = 0;
while(1)
{
if( read(AVI->fdes,data,8) != 8 ) break; /* We assume it's EOF */
n = str2ulong(data+4);
n = PAD_EVEN(n);
if(strncasecmp(data,"LIST",4) == 0)
{
if( read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ)
n -= 4;
if(strncasecmp(data,"hdrl",4) == 0)
{
hdrl_len = n;
hdrl_data = (unsigned char *) malloc(n);
if(hdrl_data==0) ERR_EXIT(AVI_ERR_NO_MEM)
if( read(AVI->fdes,hdrl_data,n) != n ) ERR_EXIT(AVI_ERR_READ)
}
else if(strncasecmp(data,"movi",4) == 0)
{
AVI->movi_start = lseek(AVI->fdes,0,SEEK_CUR);
lseek(AVI->fdes,n,SEEK_CUR);
}
else
lseek(AVI->fdes,n,SEEK_CUR);
}
else if(strncasecmp(data,"idx1",4) == 0)
{
/* n must be a multiple of 16, but the reading does not
break if this is not the case */
AVI->n_idx = AVI->max_idx = n/16;
AVI->idx = (unsigned char((*)[16]) ) malloc(n);
if(AVI->idx==0) ERR_EXIT(AVI_ERR_NO_MEM)
if( read(AVI->fdes,AVI->idx,n) != n ) ERR_EXIT(AVI_ERR_READ)
}
else
lseek(AVI->fdes,n,SEEK_CUR);
}
if(!hdrl_data ) ERR_EXIT(AVI_ERR_NO_HDRL)
if(!AVI->movi_start) ERR_EXIT(AVI_ERR_NO_MOVI)
/* Interpret the header list */
for(i=0;i<hdrl_len;)
{
/* List tags are completly ignored */
if(strncasecmp(hdrl_data+i,"LIST",4)==0) { i+= 12; continue; }
n = str2ulong(hdrl_data+i+4);
n = PAD_EVEN(n);
/* Interpret the tag and its args */
if(strncasecmp(hdrl_data+i,"strh",4)==0)
{
i += 8;
if(strncasecmp(hdrl_data+i,"vids",4) == 0 && !vids_strh_seen)
{
memcpy(AVI->compressor,hdrl_data+i+4,4);
AVI->compressor[4] = 0;
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;
vids_strh_seen = 1;
lasttag = 1; /* vids */
}
else if (strncasecmp (hdrl_data+i,"auds",4) ==0 && ! auds_strh_seen)
{
AVI->audio_bytes = str2ulong(hdrl_data+i+32)*avi_sampsize(AVI);
AVI->audio_strn = num_stream;
auds_strh_seen = 1;
lasttag = 2; /* auds */
}
else
lasttag = 0;
num_stream++;
}
else if(strncasecmp(hdrl_data+i,"strf",4)==0)
{
i += 8;
if(lasttag == 1)
{
AVI->width = str2ulong(hdrl_data+i+4);
AVI->height = str2ulong(hdrl_data+i+8);
vids_strf_seen = 1;
}
else if(lasttag == 2)
{
AVI->a_fmt = str2ushort(hdrl_data+i );
AVI->a_chans = str2ushort(hdrl_data+i+2);
AVI->a_rate = str2ulong (hdrl_data+i+4);
AVI->a_bits = str2ushort(hdrl_data+i+14);
auds_strf_seen = 1;
}
lasttag = 0;
}
else
{
i += 8;
lasttag = 0;
}
i += n;
}
free(hdrl_data);
if(!vids_strh_seen || !vids_strf_seen || AVI->video_frames==0) 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';
/* Audio tag is set to "99wb" if no audio present */
if(!AVI->a_chans) AVI->audio_strn = 99;
AVI->audio_tag[0] = AVI->audio_strn/10 + '0';
AVI->audio_tag[1] = AVI->audio_strn%10 + '0';
AVI->audio_tag[2] = 'w';
AVI->audio_tag[3] = 'b';
lseek(AVI->fdes,AVI->movi_start,SEEK_SET);
/* get index if wanted */
if(!getIndex) return AVI;
/* if the file has an idx1, check if this is relative
to the start of the file or to the start of the movi list */
idx_type = 0;
if(AVI->idx)
{
long pos;
unsigned long len;
/* Search the first videoframe in the idx1 and look where
it is in the file */
for(i=0;i<AVI->n_idx;i++)
if( strncasecmp(AVI->idx[i],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);
lseek(AVI->fdes,pos,SEEK_SET);
if(read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
if( strncasecmp(data,AVI->idx[i],4)==0 && str2ulong(data+4)==len )
{
idx_type = 1; /* Index from start of file */
}
else
{
lseek(AVI->fdes,pos+AVI->movi_start-4,SEEK_SET);
if(read(AVI->fdes,data,8)!=8) ERR_EXIT(AVI_ERR_READ)
if( strncasecmp(data,AVI->idx[i],4)==0 && str2ulong(data+4)==len )
{
idx_type = 2; /* Index from start of movi list */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -