avilib.c
资源名称:NETVIDEO.rar [点击查看]
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:33k
源码类别:
流媒体/Mpeg4/MP4
开发平台:
Visual 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 "systems.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_open_output_file: Open an AVI File and write a bunch
- of zero bytes as space for the header.
- returns a pointer to avi_t on success, a zero pointer on error
- */
- 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 */
- 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,OPEN_RDWR|OPEN_CREAT,0600);
- 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 */
- 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 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;
- AVI->a_bits = bits;
- AVI->a_fmt = format;
- }
- #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;
- /* 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 */
- if(AVI->fps < 0.001)
- ms_per_frame = 0;
- else
- ms_per_frame = 1000000./AVI->fps + 0.5;
- /* 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 */
- 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); /* MaxBytesPerSec, I hope this will never be used */
- 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 */
- OUTLONG(0); /* InitialFrames */
- if (AVI->audio_bytes)
- { OUTLONG(2); } /* Streams */
- else
- { OUTLONG(1); } /* Streams */
- OUTLONG(0); /* SuggestedBufferSize */
- OUTLONG(AVI->width); /* Width */
- OUTLONG(AVI->height); /* Height */
- /* MS calls the following 'reserved': */
- OUTLONG(0); /* 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 */
- strl_start = nhb; /* Store start position */
- OUT4CC ("strl");
- /* The video stream header */
- OUT4CC ("strh");
- OUTLONG(64); /* # 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(1000000); /* Rate: Rate/Scale == samples/second */
- OUTLONG(0); /* Start */
- OUTLONG(AVI->video_frames); /* Length */
- OUTLONG(0); /* SuggestedBufferSize */
- OUTLONG(-1); /* Quality */
- OUTLONG(0); /* SampleSize */
- OUTLONG(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); /* 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 ("