📄 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 Lesser 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */#include <gpac/internal/avilib.h>#ifndef GPAC_READ_ONLY#define PACKAGE "GPAC/avilib"#define VERSION GPAC_VERSION#define INFO_LIST// add a new riff chunk after XX MB//#define NEW_RIFF_THRES (1900*1024*1024)#define NEW_RIFF_THRES (1900*1024*1024)//#define NEW_RIFF_THRES (10*1024*1024)// Maximum number of indices per stream#define NR_IXNN_CHUNKS 32#define DEBUG_ODML#undef DEBUG_ODML/* The following variable indicates the kind of error */long AVI_errno = 0;#define MAX_INFO_STRLEN 64static char id_str[MAX_INFO_STRLEN];#define FRAME_RATE_SCALE 1000000/******************************************************************* * * * Utilities for writing an AVI File * * * *******************************************************************/static u32 avi_read(FILE *fd, char *buf, u32 len){ u32 n = 0; u32 r = 0; while (r < len) { n = fread(buf + r, 1, len - r, fd); if (n == 0) break; if (n < 0) return r; r += n; } return r;}static u32 avi_write (FILE *fd, char *buf, u32 len){ u32 n = 0; u32 r = 0; while (r < len) { n = fwrite (buf + r, 1, len - r, fd); 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 or 2 byte, little endian number. Should also work on big endian machines */static void long2str(unsigned char *dst, s32 n){ dst[0] = (n )&0xff; dst[1] = (n>> 8)&0xff; dst[2] = (n>>16)&0xff; dst[3] = (n>>24)&0xff;}#ifdef WORDS_BIGENDIANstatic void short2str(unsigned char *dst, s32 n){ dst[0] = (n )&0xff; dst[1] = (n>> 8)&0xff;}#endif/* Convert a string of 4 or 2 bytes to a number, also working on big endian machines */static u64 str2ullong(unsigned char *str){ u64 r = (str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24)); u64 s = (str[4] | (str[5]<<8) | (str[6]<<16) | (str[7]<<24));#ifdef __GNUC__ return ((s<<32)&0xffffffff00000000ULL)|(r&0xffffffff);#else return ((s<<32)&0xffffffff00000000)|(r&0xffffffff);#endif}static u32 str2ulong(unsigned char *str){ return ( str[0] | (str[1]<<8) | (str[2]<<16) | (str[3]<<24) );}static u32 str2ushort(unsigned char *str){ return ( str[0] | (str[1]<<8) );}// bit 31 denotes a keyframestatic u32 str2ulong_len (unsigned char *str){ return str2ulong(str) & 0x7fffffff;}// if bit 31 is 0, its a keyframestatic u32 str2ulong_key (unsigned char *str){ u32 c = str2ulong(str); c &= 0x80000000; if (c == 0) return 0x10; else return 0;}/* 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, u32 length){ unsigned char c[8]; char p=0; /* 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 */ if( avi_write(AVI->fdes,(char *)c,8) != 8 || avi_write(AVI->fdes,(char *)data,length) != length || avi_write(AVI->fdes,&p,length&1) != (length&1)) // if len is uneven, write a pad byte { gf_f64_seek(AVI->fdes,AVI->pos,SEEK_SET); AVI_errno = AVI_ERR_WRITE; return -1; } /* Update file position */ AVI->pos += 8 + PAD_EVEN(length); //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] pos=%lu %s\n", AVI->pos, tag)); return 0;}#define OUTD(n) long2str((unsigned char*) (ix00+bl),(s32)n); bl+=4#define OUTW(n) ix00[bl] = (n)&0xff; ix00[bl+1] = (n>>8)&0xff; bl+=2#define OUTC(n) ix00[bl] = (n)&0xff; bl+=1#define OUTS(s) memcpy(ix00+bl,s,4); bl+=4// this does the physical writeout of the ix## structurestatic int avi_ixnn_entry(avi_t *AVI, avistdindex_chunk *ch, avisuperindex_entry *en) { int bl; u32 k; unsigned int max = ch->nEntriesInUse * sizeof (u32) * ch->wLongsPerEntry + 24; // header char *ix00 = (char *)malloc (max); char dfcc[5]; memcpy (dfcc, ch->fcc, 4); dfcc[4] = 0; bl = 0; if (en) { en->qwOffset = AVI->pos; en->dwSize = max; //en->dwDuration = ch->nEntriesInUse -1; // NUMBER OF stream ticks == frames for video/samples for audio }#ifdef DEBUG_ODML //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] ODML Write %s: Entries %ld size %d \n", dfcc, ch->nEntriesInUse, max));#endif //OUTS(ch->fcc); //OUTD(max); OUTW(ch->wLongsPerEntry); OUTC(ch->bIndexSubType); OUTC(ch->bIndexType); OUTD(ch->nEntriesInUse); OUTS(ch->dwChunkId); OUTD(ch->qwBaseOffset&0xffffffff); OUTD((ch->qwBaseOffset>>32)&0xffffffff); OUTD(ch->dwReserved3); for (k = 0; k < ch->nEntriesInUse; k++) { OUTD(ch->aIndex[k].dwOffset); OUTD(ch->aIndex[k].dwSize); } avi_add_chunk (AVI, (unsigned char*)ch->fcc, (unsigned char*)ix00, max); free(ix00); return 0;}#undef OUTS#undef OUTW#undef OUTD#undef OUTC// inits a super index structure including its enclosed stdindexstatic int avi_init_super_index(avi_t *AVI, unsigned char *idxtag, avisuperindex_chunk **si){ int k; avisuperindex_chunk *sil = NULL; if ((sil = (avisuperindex_chunk *) malloc (sizeof (avisuperindex_chunk))) == NULL) { AVI_errno = AVI_ERR_NO_MEM; return -1; } memcpy (sil->fcc, "indx", 4); sil->dwSize = 0; // size of this chunk sil->wLongsPerEntry = 4; sil->bIndexSubType = 0; sil->bIndexType = AVI_INDEX_OF_INDEXES; sil->nEntriesInUse = 0; // none are in use memcpy (sil->dwChunkId, idxtag, 4); memset (sil->dwReserved, 0, sizeof (sil->dwReserved)); // NR_IXNN_CHUNKS == allow 32 indices which means 32 GB files -- arbitrary sil->aIndex = (avisuperindex_entry *) malloc (sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (void*)); if (!sil->aIndex) { AVI_errno = AVI_ERR_NO_MEM; return -1; } memset (sil->aIndex, 0, sil->wLongsPerEntry * NR_IXNN_CHUNKS * sizeof (u32)); sil->stdindex = (avistdindex_chunk **)malloc (NR_IXNN_CHUNKS * sizeof (avistdindex_chunk *)); if (!sil->stdindex) { AVI_errno = AVI_ERR_NO_MEM; return -1; } for (k = 0; k < NR_IXNN_CHUNKS; k++) { sil->stdindex[k] = (avistdindex_chunk *) malloc (sizeof (avistdindex_chunk)); // gets rewritten later sil->stdindex[k]->qwBaseOffset = (u64)k * NEW_RIFF_THRES; sil->stdindex[k]->aIndex = NULL; } *si = sil; return 0;}// fills an alloc'ed stdindex structure and mallocs some entries for the actual chunksstatic int avi_add_std_index(avi_t *AVI, unsigned char *idxtag, unsigned char *strtag, avistdindex_chunk *stdil){ memcpy (stdil->fcc, idxtag, 4); stdil->dwSize = 4096; stdil->wLongsPerEntry = 2; //sizeof(avistdindex_entry)/sizeof(u32); stdil->bIndexSubType = 0; stdil->bIndexType = AVI_INDEX_OF_CHUNKS; stdil->nEntriesInUse = 0; // cp 00db ChunkId memcpy(stdil->dwChunkId, strtag, 4); //stdil->qwBaseOffset = AVI->video_superindex->aIndex[ cur_std_idx ]->qwOffset; stdil->aIndex = (avistdindex_entry *)malloc(stdil->dwSize * sizeof (u32) * stdil->wLongsPerEntry); if (!stdil->aIndex) { AVI_errno = AVI_ERR_NO_MEM; return -1; } return 0;}static int avi_add_odml_index_entry_core(avi_t *AVI, long flags, u64 pos, unsigned long len, avistdindex_chunk *si) { u32 cur_chunk_idx; // put new chunk into index si->nEntriesInUse++; cur_chunk_idx = si->nEntriesInUse-1; // need to fetch more memory if (cur_chunk_idx >= si->dwSize) { si->dwSize += 4096; si->aIndex = (avistdindex_entry *)realloc ( si->aIndex, si->dwSize * sizeof (u32) * si->wLongsPerEntry); } if(len>AVI->max_len) AVI->max_len=len; // if bit 31 is set, it is NOT a keyframe if (flags != 0x10) { len |= 0x80000000; } si->aIndex [ cur_chunk_idx ].dwSize = len; si->aIndex [ cur_chunk_idx ].dwOffset = (u32) (pos - si->qwBaseOffset + 8); //GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] ODML: POS: 0x%lX\n", si->aIndex [ cur_chunk_idx ].dwOffset)); return 0;}static int avi_add_odml_index_entry(avi_t *AVI, unsigned char *tag, long flags, u64 pos, unsigned long len) { char fcc[5]; int audio = (strchr ((char*)tag, 'w')?1:0); int video = !audio; unsigned int cur_std_idx; u32 audtr; s64 towrite = 0; if (video) { if (!AVI->video_superindex) { if (avi_init_super_index(AVI, (unsigned char *)"ix00", &AVI->video_superindex) < 0) return -1; AVI->video_superindex->nEntriesInUse++; cur_std_idx = AVI->video_superindex->nEntriesInUse-1; if (avi_add_std_index (AVI, (unsigned char *)"ix00", (unsigned char *)"00db", AVI->video_superindex->stdindex[ cur_std_idx ]) < 0) return -1; } // init } // video if (audio) { fcc[0] = 'i'; fcc[1] = 'x'; fcc[2] = tag[0]; fcc[3] = tag[1]; fcc[4] = '\0'; if (!AVI->track[AVI->aptr].audio_superindex) {#ifdef DEBUG_ODML GF_LOG(GF_LOG_DEBUG, GF_LOG_CONTAINER, ("[avilib] ODML: fcc = %s\n", fcc));#endif if (avi_init_super_index(AVI, (unsigned char *)fcc, &AVI->track[AVI->aptr].audio_superindex) < 0) return -1; AVI->track[AVI->aptr].audio_superindex->nEntriesInUse++; sprintf(fcc, "ix%02d", AVI->aptr+1); if (avi_add_std_index (AVI, (unsigned char *)fcc, tag, AVI->track[AVI->aptr].audio_superindex->stdindex[ AVI->track[AVI->aptr].audio_superindex->nEntriesInUse - 1 ]) < 0 ) return -1; } // init } towrite = 0; if (AVI->video_superindex) { cur_std_idx = AVI->video_superindex->nEntriesInUse-1; towrite += AVI->video_superindex->stdindex[cur_std_idx]->nEntriesInUse*8 + 4+4+2+1+1+4+4+8+4; if (cur_std_idx == 0) { towrite += AVI->n_idx*16 + 8; towrite += HEADERBYTES; } } for (audtr=0; audtr<AVI->anum; audtr++) { if (AVI->track[audtr].audio_superindex) { cur_std_idx = AVI->track[audtr].audio_superindex->nEntriesInUse-1; towrite += AVI->track[audtr].audio_superindex->stdindex[cur_std_idx]->nEntriesInUse*8
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -