📄 avilib.c
字号:
/* * avilib.c * * Copyright (C) Thomas 謘treich - June 2001 * multiple audio track support Copyright (C) 2002 Thomas 謘treich * * Original code: * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> * * This file is part of transcode, a linux video stream processing tool * * transcode 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, or (at your option) * any later version. * * transcode 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 GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include "avilib.h"//#include <time.h>#define INFO_LIST/* The following variable indicates the kind of error */long AVI_errno;#define MAX_INFO_STRLEN 64static char id_str[MAX_INFO_STRLEN];#define FRAME_RATE_SCALE 1000000#ifndef PACKAGE#define PACKAGE "my"#define VERSION "0.00"#endif#ifndef O_BINARY/* win32 wants a binary flag to open(); this sets it to null on platforms that don't have it. */#define O_BINARY 0#endif/******************************************************************* * * * Utilities for writing an AVI File * * * *******************************************************************/static size_t avi_read(int fd, char *buf, size_t len){ size_t n = 0; size_t r = 0; while (r < len) { n = read (fd, buf + r, len - r); if (n <= 0) return r; r += n; } return r;}static size_t avi_write (int fd, char *buf, size_t len){ size_t n = 0; size_t r = 0; while (r < len) { n = write (fd, buf + r, len - r); if (n < 0) return n; r += n; } return r;}/* HEADERBYTES: The number of bytes to reserve for the header */#define HEADERBYTES 2048/* 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 (UINT_MAX-(1<<20)*16-HEADERBYTES)#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 j){ int s; s = ((AVI->track[j].a_bits+7)/8)*AVI->track[j].a_chans; // if(s==0) s=1; /* avoid possible zero divisions */ if(s<4) s=4; /* 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( avi_write(AVI->fdes,(char *)c,8) != 8 || avi_write(AVI->fdes,(char *)data,length) != length ) { lseek(AVI->fdes,AVI->pos,SEEK_SET); AVI_errno = AVI_ERR_WRITE; return -1; } /* Update file position */ AVI->pos += 8 + length; //fprintf(stderr, "pos=%lu %s\n", AVI->pos, tag); return 0;}static int avi_add_index_entry(avi_t *AVI, unsigned char *tag, long flags, unsigned long pos, unsigned 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 */ // fprintf(stderr, "INDEX %s %ld %lu %lu\n", tag, flags, pos, len); 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++; if(len>AVI->max_len) AVI->max_len=len; 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; int mask = 0; 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 */ /* mask = umask (0); umask (mask);*/ AVI->fdes = open(filename, O_RDWR|O_CREAT|O_BINARY, 0644 &~ mask); 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 = avi_write(AVI->fdes,(char *)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 */ //init AVI->anum = 0; AVI->aptr = 0; 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; if(strncmp(compressor, "RGB", 3)==0) { memset(AVI->compressor, 0, 4); } else { memcpy(AVI->compressor,compressor,4); } AVI->compressor[4] = 0; avi_update_header(AVI);}void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate){ /* may only be called if file is open for writing */ if(AVI->mode==AVI_MODE_READ) return; //inc audio tracks AVI->aptr=AVI->anum; ++AVI->anum; if(AVI->anum > AVI_MAX_TRACKS) { fprintf(stderr, "error - only %d audio tracks supported\n", AVI_MAX_TRACKS); exit(1); } AVI->track[AVI->aptr].a_chans = channels; AVI->track[AVI->aptr].a_rate = rate; AVI->track[AVI->aptr].a_bits = bits; AVI->track[AVI->aptr].a_fmt = format; AVI->track[AVI->aptr].mp3rate = mp3rate; avi_update_header(AVI);}#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//ThOe write preliminary AVI file header: 0 frames, max vid/aud sizeint avi_update_header(avi_t *AVI){ int njunk, sampsize, hasIndex, ms_per_frame, frate, flag; int movi_len, hdrl_start, strl_start, j; unsigned char AVI_header[HEADERBYTES]; long nhb; //assume max size movi_len = AVI_MAX_LEN - HEADERBYTES + 4; //assume index will be written hasIndex=1; if(AVI->fps < 0.001) { frate=0; ms_per_frame=0; } else { frate = (int) (FRAME_RATE_SCALE*AVI->fps + 0.5); ms_per_frame=(int) (1000000/AVI->fps + 0.5); } /* Prepare the file header */ nhb = 0; /* The RIFF header */ OUT4CC ("RIFF"); OUTLONG(movi_len); // assume max size 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 */ //ThOe ->0 // 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_ISINTERLEAVED; if(hasIndex) flag |= AVIF_HASINDEX; if(hasIndex && AVI->must_use_index) flag |= AVIF_MUSTUSEINDEX; OUTLONG(flag); /* Flags */ OUTLONG(0); // no frames yet OUTLONG(0); /* InitialFrames */ OUTLONG(AVI->anum+1); 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(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(FRAME_RATE_SCALE); /* Scale */ OUTLONG(frate); /* Rate: Rate/Scale == samples/second */ OUTLONG(0); /* Start */ OUTLONG(0); // no frames yet 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 */ // ThOe (*3) OUTLONG(AVI->width*AVI->height*3); /* 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); /* Start the audio stream list ---------------------------------- */ for(j=0; j<AVI->anum; ++j) { sampsize = avi_sampsize(AVI, j); OUT4CC ("LIST");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -