📄 avilib.c
字号:
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 = 0; 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|_O_BINARY ); 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( strncmp(data ,"RIFF",4) !=0 || strncmp(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(strncmp(data,"LIST",4) == 0) { if( _read(AVI->fdes,data,4) != 4 ) ERR_EXIT(AVI_ERR_READ) n -= 4; if(strncmp(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(strncmp(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(strncmp(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 ) { _lseek(AVI->fdes,0,SEEK_CUR); ERR_EXIT(AVI_ERR_READ) break; } } 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(strncmp(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(strncmp(hdrl_data+i,"strh",4)==0) { i += 8; if(strncmp(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 (strncmp (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(strncmp(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) { //_lseek(AVI->fdes,0,SEEK_SET); //AVI->video_pos = 0; 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( strncmp(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( strncmp(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( strncmp(data,AVI->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 */ } if(idx_type == 0) { /* we must search through the file to get the index */ _lseek(AVI->fdes, AVI->movi_start, SEEK_SET); AVI->n_idx = 0; while(1) { if( _read(AVI->fdes,data,8) != 8 ) break; n = str2ulong(data+4); /* The movi list may contain sub-lists, ignore them */ if(strncmp(data,"LIST",4)==0) { _lseek(AVI->fdes,4,SEEK_CUR); continue; } /* Check if we got a tag ##db, ##dc or ##wb */ 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') ) ) { avi_add_index_entry(AVI,data,0,_lseek(AVI->fdes,0,SEEK_CUR)-8,n); } _lseek(AVI->fdes,PAD_EVEN(n),SEEK_CUR); } idx_type = 1; } /* Now generate the video index and audio index arrays */ nvi = 0; nai = 0; for(i=0;i<AVI->n_idx;i++) { if(strncmp(AVI->idx[i],AVI->video_tag,3) == 0) nvi++; if(strncmp(AVI->idx[i],AVI->audio_tag,4) == 0) nai++; } AVI->video_frames = nvi; AVI->audio_chunks = nai; if(AVI->video_frames==0) ERR_EXIT(AVI_ERR_NO_VIDS) AVI->video_index = (video_index_entry *) malloc(nvi*sizeof(video_index_entry)); if(AVI->video_index==0) ERR_EXIT(AVI_ERR_NO_MEM) if(AVI->audio_chunks) { AVI->audio_index = (audio_index_entry *) malloc(nai*sizeof(audio_index_entry)); if(AVI->audio_index==0) ERR_EXIT(AVI_ERR_NO_MEM) } nvi = 0; nai = 0; tot = 0; ioff = idx_type == 1 ? 8 : AVI->movi_start+4; for(i=0;i<AVI->n_idx;i++) { if(strncmp(AVI->idx[i],AVI->video_tag,3) == 0) { AVI->video_index[nvi].pos = str2ulong(AVI->idx[i]+ 8)+ioff; AVI->video_index[nvi].len = str2ulong(AVI->idx[i]+12); nvi++; } if(strncmp(AVI->idx[i],AVI->audio_tag,4) == 0) { AVI->audio_index[nai].pos = str2ulong(AVI->idx[i]+ 8)+ioff; AVI->audio_index[nai].len = str2ulong(AVI->idx[i]+12); AVI->audio_index[nai].tot = tot; tot += AVI->audio_index[nai].len; nai++; } } AVI->audio_bytes = tot; /* Reposition the file */ _lseek(AVI->fdes,AVI->movi_start,SEEK_SET); AVI->video_pos = 0; return AVI;}long 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_video_frame_rate(avi_t *AVI){ return AVI->fps;}char* AVI_video_compressor(avi_t *AVI){ return AVI->compressor;}int AVI_audio_channels(avi_t *AVI){ return AVI->a_chans;}int AVI_audio_bits(avi_t *AVI){ return AVI->a_bits;}int AVI_audio_format(avi_t *AVI){ return AVI->a_fmt;}long AVI_audio_rate(avi_t *AVI){ return AVI->a_rate;}long AVI_audio_bytes(avi_t *AVI){ return AVI->audio_bytes;}long AVI_frame_size(avi_t *AVI, long 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(AVI->video_index[frame].len);}int AVI_seek_start(avi_t *AVI){ if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } _lseek(AVI->fdes,AVI->movi_start,SEEK_SET); AVI->video_pos = 0; AVI->audio_posc = 0; AVI->audio_posb = 0; return 0;}int AVI_set_video_position(avi_t *AVI, long frame, long *frame_len){ 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; if (frame_len != NULL) *frame_len = AVI->video_index[frame].len; return 0;} long AVI_read_frame(avi_t *AVI, char *vidbuf){ long 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 0; n = AVI->video_index[AVI->video_pos].len; _lseek(AVI->fdes, AVI->video_index[AVI->video_pos].pos, SEEK_SET); if (_read(AVI->fdes,vidbuf,n) != n) { AVI_errno = AVI_ERR_READ; return -1; } AVI->video_pos++; return n;}int AVI_set_audio_position(avi_t *AVI, long byte){ long n0, n1, n; if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } if(!AVI->audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } if(byte < 0) byte = 0; /* Binary search in the audio chunks */ n0 = 0; n1 = AVI->audio_chunks; while(n0<n1-1) { n = (n0+n1)/2; if(AVI->audio_index[n].tot>byte) n1 = n; else n0 = n; } AVI->audio_posc = n0; AVI->audio_posb = byte - AVI->audio_index[n0].tot; return 0;}int AVI_set_audio_frame (avi_t *AVI, long frame, long *frame_len){ if (AVI->audio_posc >= AVI->audio_chunks - 1) { return -1; } AVI->audio_posc = frame; AVI->audio_posb = 0; if (frame_len != NULL) *frame_len = AVI->audio_index[frame].len; return 0;}long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes){ long nr, pos, left, todo; if(AVI->mode==AVI_MODE_WRITE) { AVI_errno = AVI_ERR_NOT_PERM; return -1; } if(!AVI->audio_index) { AVI_errno = AVI_ERR_NO_IDX; return -1; } nr = 0; /* total number of bytes _read */
if(AVI->audio_posc>=AVI->audio_chunks-1) return nr;
nr = _read(AVI->fdes,audbuf,AVI->audio_index[AVI->audio_posc].len);
AVI->audio_posc ++;
return nr;
/* while(bytes>0) { left = AVI->audio_index[AVI->audio_posc].len - AVI->audio_posb; if(left==0) { if(AVI->audio_posc>=AVI->audio_chunks-1) return nr; AVI->audio_posc++; AVI->audio_posb = 0; continue; } if(bytes<left) todo = bytes; else todo = left; pos = AVI->audio_index[AVI->audio_posc].pos + AVI->audio_posb; _lseek(AVI->fdes, pos, SEEK_SET); if (_read(AVI->fdes,audbuf+nr,todo) != todo) { AVI_errno = AVI_ERR_READ; return -1; } bytes -= todo; nr += todo; AVI->audio_posb += todo; }
*/
return nr;}/* AVI_read_data: Special routine for reading the next audio or video chunk without having an index of the file. */int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf, char *audbuf, long max_audbuf, long *len){/* * Return codes: * * 1 = video data _read * 2 = audio data _read * 0 = reached EOF * -1 = video buffer too small * -2 = audio buffer too small */ int n; char data[8]; if(AVI->mode==AVI_MODE_WRITE) return 0; while(1) { /* Read tag and length */
//_lseek(AVI->fdes,-3,SEEK_CUR); if( _read(AVI->fdes,data,4) != 4 ) return 0; /* if we got a list tag, ignore it *//* if(strncmp(data,"LIST",4) == 0) { _lseek(AVI->fdes,4,SEEK_CUR); continue; }*/ if(strncmp(data,AVI->video_tag,3) == 0) { if( _read(AVI->fdes,data,4) != 4 ) return 0; n = PAD_EVEN(str2ulong(data)); *len = n; AVI->video_pos++; if(n>max_vidbuf) { _lseek(AVI->fdes,n,SEEK_CUR); return -1; } if(_read(AVI->fdes,vidbuf,n) != n ) return 0; return 1; } else if(strncmp(data,AVI->audio_tag,4) == 0) { if( _read(AVI->fdes,data,4) != 4 ) return 0; n = PAD_EVEN(str2ulong(data)); *len = n; if(n>max_audbuf) { _lseek(AVI->fdes,n,SEEK_CUR); return -2; } _lseek(AVI->fdes,0,SEEK_CUR); if(read(AVI->fdes,audbuf,n) != n ) return 0; return 2; break; } else if(_lseek(AVI->fdes,-3,SEEK_CUR)<0) return 0; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -