VbrTag.c
上传用户:sun1608
上传日期:2007-02-02
资源大小:6116k
文件大小:13k
源码类别:

流媒体/Mpeg4/MP4

开发平台:

Visual C++

  1. /*
  2.  * Xing VBR tagging for LAME.
  3.  *
  4.  * Copyright (c) 1999 A.L. Faber
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Library General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14.  * Library General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Library General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21. #include "machine.h"
  22. #include <math.h>
  23. #include "VbrTag.h"
  24. #include "version.h"
  25. #ifdef _DEBUG
  26. /*  #define DEBUG_VBRTAG */
  27. #endif
  28. int SizeOfEmptyFrame[2][2]=
  29. {
  30. {32,17},
  31. {17,9},
  32. };
  33. static u_char pbtStreamBuffer[216];   
  34. static long g_Position[NUMTOCENTRIES];
  35. static int nZeroStreamSize=0;
  36. static int TotalFrameSize=0;
  37. static char VBRTag[]={"Xing"};
  38. int* pVbrFrames=NULL;
  39. int nVbrNumFrames=0;
  40. int nVbrFrameBufferSize=0;
  41. /****************************************************************************
  42.  * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries
  43.  * Paramters:
  44.  * nStreamPos: how many bytes did we write to the bitstream so far
  45.  * (in Bytes NOT Bits)
  46.  ****************************************************************************
  47. */
  48. void AddVbrFrame(int nStreamPos)
  49. {
  50.         /* Simple exponential growing buffer */
  51. if (pVbrFrames==NULL || nVbrFrameBufferSize==0)
  52. {
  53.                 /* Start with 100 frames */
  54. nVbrFrameBufferSize=100;
  55. /* Allocate them */
  56. pVbrFrames=(int*)malloc((size_t)(nVbrFrameBufferSize*sizeof(int)));
  57. }
  58. /* Is buffer big enough to store this new frame */
  59. if (nVbrNumFrames==nVbrFrameBufferSize)
  60. {
  61.                 /* Guess not, double th e buffer size */
  62. nVbrFrameBufferSize*=2;
  63. /* Allocate new buffer */
  64. pVbrFrames=(int*)realloc(pVbrFrames,(size_t)(nVbrFrameBufferSize*sizeof(int)));
  65. }
  66. /* Store values */
  67. pVbrFrames[nVbrNumFrames++]=nStreamPos;
  68. }
  69. /*-------------------------------------------------------------*/
  70. static int ExtractI4(unsigned char *buf)
  71. {
  72. int x;
  73. /* big endian extract */
  74. x = buf[0];
  75. x <<= 8;
  76. x |= buf[1];
  77. x <<= 8;
  78. x |= buf[2];
  79. x <<= 8;
  80. x |= buf[3];
  81. return x;
  82. }
  83. void CreateI4(unsigned char *buf, int nValue)
  84. {
  85.         /* big endian create */
  86. buf[0]=(nValue>>24)&0xff;
  87. buf[1]=(nValue>>16)&0xff;
  88. buf[2]=(nValue>> 8)&0xff;
  89. buf[3]=(nValue    )&0xff;
  90. }
  91. /*-------------------------------------------------------------*/
  92. /* Same as GetVbrTag below, but only checks for the Xing tag.
  93.    requires buf to contain only 40 bytes */
  94. /*-------------------------------------------------------------*/
  95. int CheckVbrTag(unsigned char *buf)
  96. {
  97. int h_id, h_mode, h_sr_index;
  98. /* get selected MPEG header data */
  99. h_id       = (buf[1] >> 3) & 1;
  100. h_sr_index = (buf[2] >> 2) & 3;
  101. h_mode     = (buf[3] >> 6) & 3;
  102. /*  determine offset of header */
  103. if( h_id ) 
  104. {
  105.                 /* mpeg1 */
  106. if( h_mode != 3 ) buf+=(32+4);
  107. else buf+=(17+4);
  108. }
  109. else
  110. {
  111.                 /* mpeg2 */
  112. if( h_mode != 3 ) buf+=(17+4);
  113. else              buf+=(9+4);
  114. }
  115. if( buf[0] != VBRTag[0] ) return 0;    /* fail */
  116. if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
  117. if( buf[2] != VBRTag[2] ) return 0;
  118. if( buf[3] != VBRTag[3] ) return 0;
  119. return 1;
  120. }
  121. int GetVbrTag(VBRTAGDATA *pTagData,  unsigned char *buf)
  122. {
  123. int i, head_flags;
  124. int h_id, h_mode, h_sr_index;
  125. static int sr_table[4] = { 44100, 48000, 32000, 99999 };
  126. /* get Vbr header data */
  127. pTagData->flags = 0;     
  128. /* get selected MPEG header data */
  129. h_id       = (buf[1] >> 3) & 1;
  130. h_sr_index = (buf[2] >> 2) & 3;
  131. h_mode     = (buf[3] >> 6) & 3;
  132. /*  determine offset of header */
  133. if( h_id ) 
  134. {
  135.                 /* mpeg1 */
  136. if( h_mode != 3 ) buf+=(32+4);
  137. else buf+=(17+4);
  138. }
  139. else
  140. {
  141.                 /* mpeg2 */
  142. if( h_mode != 3 ) buf+=(17+4);
  143. else              buf+=(9+4);
  144. }
  145. if( buf[0] != VBRTag[0] ) return 0;    /* fail */
  146. if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
  147. if( buf[2] != VBRTag[2] ) return 0;
  148. if( buf[3] != VBRTag[3] ) return 0;
  149. buf+=4;
  150. pTagData->h_id = h_id;
  151. pTagData->samprate = sr_table[h_sr_index];
  152. if( h_id == 0 )
  153. pTagData->samprate >>= 1;
  154. head_flags = pTagData->flags = ExtractI4(buf); buf+=4;      /* get flags */
  155. if( head_flags & FRAMES_FLAG )
  156. {
  157. pTagData->frames   = ExtractI4(buf); buf+=4;
  158. }
  159. if( head_flags & BYTES_FLAG )
  160. {
  161. pTagData->bytes = ExtractI4(buf); buf+=4;
  162. }
  163. if( head_flags & TOC_FLAG )
  164. {
  165. if( pTagData->toc != NULL )
  166. {
  167. for(i=0;i<NUMTOCENTRIES;i++)
  168. pTagData->toc[i] = buf[i];
  169. }
  170. buf+=NUMTOCENTRIES;
  171. }
  172. pTagData->vbr_scale = -1;
  173. if( head_flags & VBR_SCALE_FLAG )
  174. {
  175. pTagData->vbr_scale = ExtractI4(buf); buf+=4;
  176. }
  177. #ifdef DEBUG_VBRTAG
  178. printf("nn********************* VBR TAG INFO *****************n");
  179. printf("tag         :%sn",VBRTag);
  180. printf("head_flags  :%dn",head_flags);
  181. printf("bytes       :%dn",pTagData->bytes);
  182. printf("frames      :%dn",pTagData->frames);
  183. printf("VBR Scale   :%dn",pTagData->vbr_scale);
  184. printf("toc:n");
  185. if( pTagData->toc != NULL )
  186. {
  187. for(i=0;i<NUMTOCENTRIES;i++)
  188. {
  189. if( (i%10) == 0 ) printf("n");
  190. printf(" %3d", (int)(pTagData->toc[i]));
  191. }
  192. }
  193. printf("n***************** END OF VBR TAG INFO ***************n");
  194. #endif
  195. return 1;       /* success */
  196. }
  197. /****************************************************************************
  198.  * InitVbrTag: Initializes the header, and write empty frame to stream
  199.  * Paramters:
  200.  * fpStream: pointer to output file stream
  201.  * nVersion: 0= MPEG1 1=MPEG2
  202.  * nMode : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO
  203.  ****************************************************************************
  204. */
  205. int InitVbrTag(Bit_stream_struc* pBs,int nVersion, int nMode, int SampIndex)
  206. {
  207. int i;
  208. /* Clear Frame position array variables */
  209. pVbrFrames=NULL;
  210. nVbrNumFrames=0;
  211. nVbrFrameBufferSize=0;
  212. /* Clear struct */
  213. memset(g_Position,0x00,sizeof(g_Position));
  214. /* Clear stream buffer */
  215. memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
  216. /* Set TOC values to 255 */
  217. for (i=0;i<NUMTOCENTRIES;i++)
  218. {
  219. g_Position[i]=-1;
  220. }
  221. /* Reserve the proper amount of bytes */
  222. if (nMode==3)
  223. {
  224. nZeroStreamSize=SizeOfEmptyFrame[nVersion][1]+4;
  225. }
  226. else
  227. {
  228. nZeroStreamSize=SizeOfEmptyFrame[nVersion][0]+4;
  229. }
  230. /*
  231. // Xing VBR pretends to be a 48kbs layer III frame.  (at 44.1kHz).
  232.         // (at 48kHz they use 56kbs since 48kbs frame not big enough for 
  233.         // table of contents)
  234. // let's always embed Xing header inside a 64kbs layer III frame.  
  235. // this gives us enough room for a LAME version string too.
  236. // size determined by sampling frequency (MPEG1)
  237. // 32kHz:    216 bytes@48kbs    288bytes@ 64kbs    
  238. // 44.1kHz:  156 bytes          208bytes@64kbs     (+1 if padding = 1)
  239. // 48kHz:    144 bytes          192
  240. // 
  241. // MPEG 2 values are the since the framesize and samplerate
  242.         // are each reduced by a factor of 2.
  243. */
  244. {
  245. int tot;
  246. static const int framesize[3]={208,192,288};  /* 64kbs MPEG1 or MPEG2  framesize */
  247. /* static int framesize[3]={156,144,216}; */ /* 48kbs framesize */
  248. if (SampIndex>2) {
  249.   fprintf(stderr,"illegal sampling frequency indexn");
  250.   exit(-1);
  251. }
  252. TotalFrameSize= framesize[SampIndex];
  253. tot = (nZeroStreamSize+VBRHEADERSIZE);
  254. tot += 20;  /* extra 20 bytes for LAME & version string */
  255. if (TotalFrameSize < tot ) {
  256.   fprintf(stderr,"Xing VBR header problem...use -tn");
  257.   exit(-1);
  258. }
  259. }
  260. /* Put empty bytes into the bitstream */
  261. for (i=0;i<TotalFrameSize;i++)
  262. {
  263.                 /* Write a byte to the bitstream */
  264. putbits(pBs,0,8);
  265. }
  266. /* Success */
  267. return 0;
  268. }
  269. /****************************************************************************
  270.  * PutVbrTag: Write final VBR tag to the file
  271.  * Paramters:
  272.  * lpszFileName: filename of MP3 bit stream
  273.  * nVersion: 0= MPEG1 1=MPEG2
  274.  * nVbrScale : encoder quality indicator (0..100)
  275.  ****************************************************************************
  276. */
  277. int PutVbrTag(char* lpszFileName,int nVbrScale,int nVersion)
  278. {
  279. int i;
  280. long lFileSize;
  281. int nStreamIndex;
  282. char abyte;
  283. u_char btToc[NUMTOCENTRIES];
  284. FILE *fpStream;
  285. char str1[80];
  286. if (nVbrNumFrames==0 || pVbrFrames==NULL)
  287. return -1;
  288. /* Open the bitstream again */
  289. fpStream=fopen(lpszFileName,"rb+");
  290. /* Assert stream is valid */
  291. if (fpStream==NULL)
  292. return -1;
  293. /* Clear stream buffer */
  294. memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
  295. /* Seek to end of file*/
  296. fseek(fpStream,0,SEEK_END);
  297. /* Get file size */
  298. lFileSize=ftell(fpStream);
  299. /* Abort if file has zero length. Yes, it can happen :) */
  300. if (lFileSize==0)
  301. return -1;
  302. /* Seek to first real frame */
  303. fseek(fpStream,(long)TotalFrameSize,SEEK_SET);
  304. /* Read the header (first valid frame) */
  305. fread(pbtStreamBuffer,4,1,fpStream);
  306. /* the default VBR header.  48kbs layer III, no padding, no crc */
  307. /* but sampling freq, mode andy copyright/copy protection taken */
  308. /* from first valid frame */
  309. pbtStreamBuffer[0]=(u_char) 0xff;    
  310. if (nVersion==0) {
  311.   pbtStreamBuffer[1]=(u_char) 0xfb;    
  312.   abyte = pbtStreamBuffer[2] & (char) 0x0c;   
  313.   pbtStreamBuffer[2]=(char) 0x50 | abyte;     /* 64kbs MPEG1 frame */
  314. }else{
  315.   pbtStreamBuffer[1]=(u_char) 0xf3;    
  316.   abyte = pbtStreamBuffer[2] & (char) 0x0c;   
  317.   pbtStreamBuffer[2]=(char) 0x80 | abyte;     /* 64kbs MPEG2 frame */
  318. }
  319. /*Seek to the beginning of the stream */
  320. fseek(fpStream,0,SEEK_SET);
  321. /* Clear all TOC entries */
  322. memset(btToc,0,sizeof(btToc));
  323.         for (i=1;i<NUMTOCENTRIES;i++) /* Don't touch zero point... */
  324.         {
  325.                 /* Calculate frame from given percentage */
  326.                 int frameNum=(int)(floor(0.01*i*nVbrNumFrames));
  327.                 /*  Calculate relative file postion, normalized to 0..256!(?) */
  328.                 float fRelStreamPos=(float)256.0*(float)pVbrFrames[frameNum]/(float)lFileSize;
  329.                 /* Just to be safe */
  330.                 if (fRelStreamPos>255) fRelStreamPos=255;
  331.                 /* Assign toc entry value */
  332.                 btToc[i]=(u_char) fRelStreamPos;
  333.         }
  334. /* Start writing the tag after the zero frame */
  335. nStreamIndex=nZeroStreamSize;
  336. /* Put Vbr tag */
  337. pbtStreamBuffer[nStreamIndex++]=VBRTag[0];
  338. pbtStreamBuffer[nStreamIndex++]=VBRTag[1];
  339. pbtStreamBuffer[nStreamIndex++]=VBRTag[2];
  340. pbtStreamBuffer[nStreamIndex++]=VBRTag[3];
  341. /* Put header flags */
  342. CreateI4(&pbtStreamBuffer[nStreamIndex],FRAMES_FLAG+BYTES_FLAG+TOC_FLAG+VBR_SCALE_FLAG);
  343. nStreamIndex+=4;
  344. /* Put Total Number of frames */
  345. CreateI4(&pbtStreamBuffer[nStreamIndex],nVbrNumFrames);
  346. nStreamIndex+=4;
  347. /* Put Total file size */
  348. CreateI4(&pbtStreamBuffer[nStreamIndex],(int)lFileSize);
  349. nStreamIndex+=4;
  350. /* Put TOC */
  351. memcpy(&pbtStreamBuffer[nStreamIndex],btToc,sizeof(btToc));
  352. nStreamIndex+=sizeof(btToc);
  353. /* Put VBR SCALE */
  354. CreateI4(&pbtStreamBuffer[nStreamIndex],nVbrScale);
  355. nStreamIndex+=4;
  356. /* Put LAME id */
  357. sprintf(str1,"LAME%s",get_lame_version());
  358. strncpy((char *)&pbtStreamBuffer[nStreamIndex],str1,(size_t) 20);
  359. nStreamIndex+=20;
  360. #ifdef DEBUG_VBRTAG
  361. {
  362. VBRTAGDATA TestHeader;
  363. GetVbrTag(&TestHeader,pbtStreamBuffer);
  364. }
  365. #endif
  366.         /* Put it all to disk again */
  367. if (fwrite(pbtStreamBuffer,TotalFrameSize,1,fpStream)!=1)
  368. {
  369. return -1;
  370. }
  371. fclose(fpStream);
  372. /* Save to delete the frame buffer */
  373. free(pVbrFrames);
  374. pVbrFrames=NULL;
  375. return 0;       /* success */
  376. }
  377. /*-------------------------------------------------------------*/
  378. int SeekPoint(unsigned char TOC[NUMTOCENTRIES], int file_bytes, float percent)
  379. {
  380. /* interpolate in TOC to get file seek point in bytes */
  381. int a, seekpoint;
  382. float fa, fb, fx;
  383. if( percent < (float)0.0 )   percent = (float)0.0;
  384. if( percent > (float)100.0 ) percent = (float)100.0;
  385. a = (int)percent;
  386. if( a > 99 ) a = 99;
  387. fa = TOC[a];
  388. if( a < 99 ) {
  389.     fb = TOC[a+1];
  390. }
  391. else {
  392.     fb = (float)256.0;
  393. }
  394. fx = fa + (fb-fa)*(percent-a);
  395. seekpoint = (int)(((float)(1.0/256.0))*fx*file_bytes); 
  396. return seekpoint;
  397. }
  398. /*-------------------------------------------------------------*/