📄 avilib.c
字号:
OUT4CC ("\0\0\0\0"); OUTLONG(0); /* Flags */ OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ OUTLONG(0); /* InitialFrames */ OUTLONG(sampsize); /* Scale */ OUTLONG(sampsize*AVI->a_rate); /* Rate: Rate/Scale == samples/second */ OUTLONG(0); /* Start */ OUTLONG(AVI->audio_bytes/sampsize); /* Length */ OUTLONG(0); /* SuggestedBufferSize */ OUTLONG(-1); /* Quality */ OUTLONG(sampsize); /* SampleSize */ OUTLONG(0); /* Frame */ 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 || ftruncate(AVI->fdes,AVI->pos)<0 ) { 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(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,O_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, 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -