📄 avilib.c
字号:
/* * Some utilities for writing and reading AVI files. * These are not intended to serve for a full blown * AVI handling software (this would be much too complex) * The only intention is to _write out MJPEG encoded * AVIs with sound and to be able to _read them back again. * These utilities should work with other types of codecs too, however. * * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> * * This program 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 of the License, or * (at your option) any later version. * * This program 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 this program; if not, _write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *///#include "mpeg4ip.h"#include "avilib.h"/* The following variable indicates the kind of error */long AVI_errno = 0;/******************************************************************* * * * Utilities for writing an AVI File * * * *******************************************************************//* AVI_MAX_LEN: The maximum length of an AVI file, we stay a bit below the 2GB limit (Remember: 2*10^9 is smaller than 2 GB) */#define AVI_MAX_LEN 2000000000/* HEADERBYTES: The number of bytes to reserve for the header */#define HEADERBYTES 2048#define PAD_EVEN(x) ( ((x)+1) & ~1 )/* Copy n into dst as a 4 byte, little endian number. Should also work on big endian machines */static void long2str(unsigned char *dst, int n){ dst[0] = (n )&0xff; dst[1] = (n>> 8)&0xff; dst[2] = (n>>16)&0xff; dst[3] = (n>>24)&0xff;}/* Convert a string of 4 or 2 bytes to a number, also working on big endian machines */static unsigned long str2ulong(unsigned char *str){ return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );}static unsigned long str2ushort(unsigned char *str){ return ( str[0] | (str[1]<<8) );}/* Calculate audio sample size from number of bits and number of channels. This may have to be adjusted for eg. 12 bits and stereo */static int avi_sampsize(avi_t *AVI){ int s; s = ((AVI->a_bits+7)/8)*AVI->a_chans; if(s==0) s=1; /* avoid possible zero divisions */ return s;}/* Add a chunk (=tag and data) to the AVI file, returns -1 on _write error, 0 on success */static int avi_add_chunk(avi_t *AVI, unsigned char *tag, unsigned char *data, int length){ unsigned char c[8]; /* Copy tag and length int c, so that we need only 1 _write system call for these two values */ memcpy(c,tag,4); long2str(c+4,length); /* Output tag, length and data, restore previous position if the _write fails */ length = PAD_EVEN(length); if( _write(AVI->fdes,c,8) != 8 || _write(AVI->fdes,data,length) != length ) { _lseek(AVI->fdes,AVI->pos,SEEK_SET); AVI_errno = AVI_ERR_WRITE; return -1; } /* Update file position */ AVI->pos += 8 + length; return 0;}static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, long pos, long len){ void *ptr; if(AVI->n_idx>=AVI->max_idx) { ptr = 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; } /* Add index entry */ memcpy(AVI->idx[AVI->n_idx],tag,4); long2str(AVI->idx[AVI->n_idx]+ 4,flags); long2str(AVI->idx[AVI->n_idx]+ 8,pos); long2str(AVI->idx[AVI->n_idx]+12,len); /* Update counter */ AVI->n_idx++; return 0;}//////////////////////////////////////////////////////////
avi_t* AVI_open_output_file(char * filename){ avi_t *AVI; int i; unsigned char AVI_header[HEADERBYTES]; /* Allocate the avi_t struct and zero it */
// printf("entery the aviopenoutputfile!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"); AVI = (avi_t *) malloc(sizeof(avi_t)); if(AVI==0) { AVI_errno = AVI_ERR_NO_MEM; return 0; } memset((void *)AVI,0,sizeof(avi_t)); /* Since Linux needs a long time when deleting big files, we do not truncate the file when we _open it. Instead it is truncated when the AVI file is closed */ AVI->fdes = _open(filename,_O_RDWR | _O_CREAT | _O_BINARY); if (AVI->fdes < 0) { AVI_errno = AVI_ERR_OPEN; free(AVI); return 0; } /* Write out HEADERBYTES bytes, the header will go here when we are finished with writing */ for (i=0;i<HEADERBYTES;i++) AVI_header[i] = 0; i = _write(AVI->fdes,AVI_header,HEADERBYTES);
if (i != HEADERBYTES) { close(AVI->fdes); AVI_errno = AVI_ERR_WRITE; free(AVI); return 0; } AVI->pos = HEADERBYTES;
AVI->mode = AVI_MODE_WRITE; /* _open for writing */
printf("open end !!!!!!\n"); return AVI;}///////////////////////////////////////////////////////////////
void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor){ /* may only be called if file is _open for writing */ if(AVI->mode==AVI_MODE_READ) return; AVI->width = width; AVI->height = height; AVI->fps = fps; memcpy(AVI->compressor,compressor,4); AVI->compressor[4] = 0;}void AVI_set_audio(avi_t *AVI, int channels, long samplepersec, long rate, int bits, int format){ /* may only be called if file is _open for writing */ if(AVI->mode==AVI_MODE_READ) return; AVI->a_chans = channels; AVI->a_rate = rate/8;
AVI->a_samplepersec = samplepersec; AVI->a_bits = bits; AVI->a_fmt = format;
AVI->a_cbsize = 12; //MPEGLAYER3_WFX_EXTRA_BYTES 12
AVI->a_wID = 1; //MPEGLAYER3_ID_MPEG ==1
////#define MPEGLAYER3_FLAG_PADDING_OFF 0x00000002
AVI->a_fdwFlags = 2; // These values based on an old Usenet post!!
AVI->a_nBlockSize = 731; //AVI->a_nBlockSize = 576; // this value COMPUTE later...
AVI->a_nFramesPerBlock = 1; //
AVI->a_nCodecDelay = 0; // AVI->a_nCodecDelay = 1393; // 0x571 for F-IIS MP3 Codec}#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,n); nhb += 4#define OUTSHRT(n) \ if(nhb<=HEADERBYTES-2) { \ AVI_header[nhb ] = (n )&0xff; \ AVI_header[nhb+1] = (n>>8)&0xff; \ } \ nhb += 2/* Write the header of an AVI file and close it. returns 0 on success, -1 on _write error.*/static int avi_close_output_file(avi_t *AVI){ int ret, njunk, sampsize, hasIndex, ms_per_frame, idxerror, flag; int movi_len, hdrl_start, strl_start; unsigned char AVI_header[HEADERBYTES]; long nhb;
long ntime;
//return 0; /* Calculate length of movi list */ movi_len = AVI->pos - HEADERBYTES + 4; /* Try to ouput the index entries. This may fail e.g. if no space is left on device. We will report this as an error, but we still try to _write the header correctly (so that the file still may be readable in the most cases */ idxerror = 0; ret = avi_add_chunk(AVI,"idx1",(void*)AVI->idx,AVI->n_idx*16); hasIndex = (ret==0); if(ret) { idxerror = 1; AVI_errno = AVI_ERR_WRITE_INDEX; } /* Calculate Microseconds per frame */
ntime=1000*AVI->video_frames/AVI->fps;
if(AVI->fps < 0.001) ms_per_frame = 0; else
ms_per_frame = 1000000./AVI->fps + 0.5;
printf("ms_per_frame==%d\n",ms_per_frame); /* Prepare the file header */ nhb = 0; /* The RIFF header */ OUT4CC ("RIFF"); OUTLONG(AVI->pos - 8); /* # of bytes to follow */ OUT4CC ("AVI "); /* Start the header list */ OUT4CC ("LIST"); OUTLONG(0); /// Length of list in bytes, don't know yet 现在还不知道它的长度,在后面通过 long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);设置长度 hdrl_start = nhb; // Store start position OUT4CC ("hdrl"); /* The main AVI header */ /* The Flags in AVI File header */#define AVIF_HASINDEX 0x00000010 /* Index at end of file */#define AVIF_MUSTUSEINDEX 0x00000020#define AVIF_ISINTERLEAVED 0x00000100#define AVIF_TRUSTCKTYPE 0x00000800 /* Use CKType to find key frames */#define AVIF_WASCAPTUREFILE 0x00010000#define AVIF_COPYRIGHTED 0x00020000 OUT4CC ("avih"); OUTLONG(56); /* # of bytes to follow */ OUTLONG(ms_per_frame); /* Microseconds per frame */
OUTLONG(10000000);// OUTLONG(1244160);//OUTLONG(10000000); /* MaxBytesPerSec, I hope this will never be used */ OUTLONG(0); //OUTLONG(0); /* PaddingGranularity (whatever that might be) */ /* Other sources call it 'reserved' */ flag = AVIF_WASCAPTUREFILE; if(hasIndex) flag |= AVIF_HASINDEX;//////////////////// if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX; OUTLONG(flag); /* Flags */
OUTLONG(AVI->video_frames); /* TotalFrames *///////
printf("AVI->video_frames==%d\n",AVI->video_frames);
OUTLONG(0); /* InitialFrames */ if (AVI->audio_bytes) {
OUTLONG(2);
} /* Streams */ else {
OUTLONG(1);
} /* Streams */ OUTLONG(0); //OUTLONG(10000); // OUTLONG(0); /* SuggestedBufferSize *///!!!!!! OUTLONG(AVI->width); /* Width */ OUTLONG(AVI->height); /* Height */ /* MS calls the following 'reserved': */ OUTLONG(ms_per_frame); //OUTLONG(ms_per_frame); /* TimeScale: Unit used to measure time */ OUTLONG(0); /* DataRate: Data rate of playback */ OUTLONG(0); /* StartTime: Starting time of AVI data */ OUTLONG(0); /* DataLength: Size of AVI data chunk */ /* Start the video stream list ---------------------------------- */ OUT4CC ("LIST"); OUTLONG(0); /// Length of list in bytes, don't know yet ,现在还不知道它的长度,在后面通过 long2str(AVI_header+hdrl_start-4,nhb-hdrl_start);设置长度 strl_start = nhb; /// Store start position OUT4CC ("strl"); /// The video stream header OUT4CC ("strh"); OUTLONG(56); // # of bytes to follow OUT4CC ("vids"); // / Type OUT4CC (AVI->compressor); /// Handler OUTLONG(0); /// Flags OUTLONG(0); /// Reserved, MS says: wPriority, wLanguage OUTLONG(0); /// InitialFrames OUTLONG(ms_per_frame); /// Scale ////一个小整体的时间植,如一帧所使用的时间,单位毫秒;
OUTLONG(ms_per_frame*AVI->fps);//OUTLONG(AVI->width*AVI->height);// OUTLONG(AVI->width*AVI->height/ms_per_frame);/// Rate: Rate/Scale == samples/second 每秒多少个象素点
// printf("AVI->width*AVI->height/ms_per_frame==%d\n",AVI->width*AVI->height/ms_per_frame); OUTLONG(0); /// Start
OUTLONG(AVI->video_frames); /// Length
OUTLONG(1000000); /// SuggestedBufferSize OUTLONG(-1); /// Quality OUTLONG(0); /// SampleSize
OUTLONG(0);
OUTSHRT(0);
OUTSHRT(0);
// /// Frame //OUTLONG(0); /// Frame //OUTLONG(0); /// Frame //OUTLONG(0); /// Frame //The video stream format OUT4CC ("strf"); OUTLONG(40); //# of bytes to follow OUTLONG(40); ///Size OUTLONG(AVI->width); ///Width OUTLONG(AVI->height); // Height OUTSHRT(1); OUTSHRT(24); // Planes, Count OUT4CC (AVI->compressor); /// Compression OUTLONG(AVI->width*AVI->height); //OUTLONG(608256); ///OUTLONG(AVI->width*AVI->height); /// SizeImage (in bytes?) OUTLONG(0); // / XPelsPerMeter OUTLONG(0); // / YPelsPerMeter OUTLONG(0); /// ClrUsed: Number of colors used OUTLONG(0); ///ClrImportant: Number of colors important
///Finish stream list, i.e. put number of bytes in the list to proper pos long2str(AVI_header+strl_start-4,nhb-strl_start); if (AVI->a_chans && AVI->audio_bytes) { sampsize = avi_sampsize(AVI);
/* Start the audio stream list ---------------------------------- */ OUT4CC ("LIST"); OUTLONG(0); /* Length of list in bytes, don't know yet */ strl_start = nhb; /* Store start position */ OUT4CC ("strl"); /* The audio stream header */ OUT4CC ("strh"); OUTLONG(64); /* # of bytes to follow */ OUT4CC ("auds"); OUT4CC ("\0\0\0\0");/// OUT4CC ("\0\0\0\0");//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! OUTLONG(0); /* Flags */ OUTLONG(0); /* Reserved, MS says: wPriority, wLanguage */ OUTLONG(0); /* InitialFrames */
OUTLONG(1); //OUTLONG(ntime); // OUTLONG(1); /* Scale */
OUTLONG(AVI->a_rate); //OUTLONG(AVI->a_rate/8); /* Rate: Rate/Scale == samples/second *///!!!!!???????????????
printf("AVI->a_rate==%d\n",AVI->a_rate);
OUTLONG(0); /* Start */ OUTLONG(AVI->audio_bytes/sampsize); /* Length */ OUTLONG(0); /* SuggestedBufferSize */ OUTLONG(-1); // 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(30); /* # of bytes to follow */ OUTSHRT(AVI->a_fmt); /* Format */ OUTSHRT(AVI->a_chans); /* Number of channels */
OUTLONG(AVI->a_samplepersec); /* SamplesPerSec */ OUTLONG(AVI->a_rate);// OUTLONG(AVI->a_rate/8); /* AvgBytesPerSec */ OUTSHRT(sampsize); /* BlockAlign */ OUTSHRT(AVI->a_bits); /* BitsPerSample */
OUTSHRT(AVI->a_cbsize);
OUTSHRT(AVI->a_wID);
OUTLONG(AVI->a_fdwFlags);
OUTSHRT(AVI->a_nBlockSize);
OUTSHRT(AVI->a_nFramesPerBlock);
OUTSHRT(AVI->a_nCodecDelay); /* 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);///设置hdrl的长度 /* 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 _WIN32 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)//audio==1 -->audio , audio==0 -->video{ 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,"00dc",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,"00dc",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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -