home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 13 / AACD13.ISO / AACD / Sound / LAME / src / VbrTag.c < prev    next >
C/C++ Source or Header  |  2000-07-21  |  13KB  |  488 lines

  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.  
  22. #include "machine.h"
  23. #if defined(__riscos__) && defined(FPA10)
  24. #include    "ymath.h"
  25. #else
  26. #include    <math.h>
  27. #endif
  28. #include "VbrTag.h"
  29. #include "version.h"
  30. #include "bitstream.h"
  31.  
  32. #ifdef _DEBUG
  33. /*  #define DEBUG_VBRTAG */
  34. #endif
  35.  
  36.  
  37. const static char    VBRTag[]={"Xing"};
  38. const int SizeOfEmptyFrame[2][2]=
  39. {
  40.     {17,9},
  41.     {32,17},
  42. };
  43.  
  44.  
  45.  
  46. /****************************************************************************
  47.  * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries
  48.  * Paramters:
  49.  *    nStreamPos: how many bytes did we write to the bitstream so far
  50.  *                (in Bytes NOT Bits)
  51.  ****************************************************************************
  52. */
  53. void AddVbrFrame(lame_global_flags *gfp)
  54. {
  55.   int nStreamPos;
  56.   lame_internal_flags *gfc=gfp->internal_flags;
  57.   nStreamPos = (gfc->bs.totbit/8);
  58.  
  59.         /* Simple exponential growing buffer */
  60.     if (gfp->pVbrFrames==NULL || gfp->nVbrFrameBufferSize==0)
  61.     {
  62.                 /* Start with 100 frames */
  63.         gfp->nVbrFrameBufferSize=100;
  64.  
  65.         /* Allocate them */
  66.         gfp->pVbrFrames=(int*)malloc((size_t)(gfp->nVbrFrameBufferSize*sizeof(int)));
  67.     }
  68.  
  69.     /* Is buffer big enough to store this new frame */
  70.     if (gfp->nVbrNumFrames==gfp->nVbrFrameBufferSize)
  71.     {
  72.                 /* Guess not, double th e buffer size */
  73.         gfp->nVbrFrameBufferSize*=2;
  74.  
  75.         /* Allocate new buffer */
  76.         gfp->pVbrFrames=(int*)realloc(gfp->pVbrFrames,(size_t)(gfp->nVbrFrameBufferSize*sizeof(int)));
  77.     }
  78.  
  79.     /* Store values */
  80.     gfp->pVbrFrames[gfp->nVbrNumFrames++]=nStreamPos;
  81. }
  82.  
  83.  
  84. /*-------------------------------------------------------------*/
  85. static int ExtractI4(unsigned char *buf)
  86. {
  87.     int x;
  88.     /* big endian extract */
  89.     x = buf[0];
  90.     x <<= 8;
  91.     x |= buf[1];
  92.     x <<= 8;
  93.     x |= buf[2];
  94.     x <<= 8;
  95.     x |= buf[3];
  96.     return x;
  97. }
  98.  
  99. void CreateI4(unsigned char *buf, int nValue)
  100. {
  101.         /* big endian create */
  102.     buf[0]=(nValue>>24)&0xff;
  103.     buf[1]=(nValue>>16)&0xff;
  104.     buf[2]=(nValue>> 8)&0xff;
  105.     buf[3]=(nValue    )&0xff;
  106. }
  107.  
  108.  
  109. /*-------------------------------------------------------------*/
  110. /* Same as GetVbrTag below, but only checks for the Xing tag.
  111.    requires buf to contain only 40 bytes */
  112. /*-------------------------------------------------------------*/
  113. int CheckVbrTag(unsigned char *buf)
  114. {
  115.     int            h_id, h_mode, h_sr_index;
  116.  
  117.     /* get selected MPEG header data */
  118.     h_id       = (buf[1] >> 3) & 1;
  119.     h_sr_index = (buf[2] >> 2) & 3;
  120.     h_mode     = (buf[3] >> 6) & 3;
  121.  
  122.     /*  determine offset of header */
  123.     if( h_id )
  124.     {
  125.                 /* mpeg1 */
  126.         if( h_mode != 3 )    buf+=(32+4);
  127.         else                buf+=(17+4);
  128.     }
  129.     else
  130.     {
  131.                 /* mpeg2 */
  132.         if( h_mode != 3 ) buf+=(17+4);
  133.         else              buf+=(9+4);
  134.     }
  135.  
  136.     if( buf[0] != VBRTag[0] ) return 0;    /* fail */
  137.     if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
  138.     if( buf[2] != VBRTag[2] ) return 0;
  139.     if( buf[3] != VBRTag[3] ) return 0;
  140.     return 1;
  141. }
  142.  
  143. int GetVbrTag(VBRTAGDATA *pTagData,  unsigned char *buf)
  144. {
  145.     int            i, head_flags;
  146.     int            h_id, h_mode, h_sr_index;
  147.     static int    sr_table[4] = { 44100, 48000, 32000, 99999 };
  148.  
  149.     /* get Vbr header data */
  150.     pTagData->flags = 0;
  151.  
  152.     /* get selected MPEG header data */
  153.     h_id       = (buf[1] >> 3) & 1;
  154.     h_sr_index = (buf[2] >> 2) & 3;
  155.     h_mode     = (buf[3] >> 6) & 3;
  156.  
  157.     /*  determine offset of header */
  158.     if( h_id )
  159.     {
  160.                 /* mpeg1 */
  161.         if( h_mode != 3 )    buf+=(32+4);
  162.         else                buf+=(17+4);
  163.     }
  164.     else
  165.     {
  166.                 /* mpeg2 */
  167.         if( h_mode != 3 ) buf+=(17+4);
  168.         else              buf+=(9+4);
  169.     }
  170.  
  171.     if( buf[0] != VBRTag[0] ) return 0;    /* fail */
  172.     if( buf[1] != VBRTag[1] ) return 0;    /* header not found*/
  173.     if( buf[2] != VBRTag[2] ) return 0;
  174.     if( buf[3] != VBRTag[3] ) return 0;
  175.  
  176.     buf+=4;
  177.  
  178.     pTagData->h_id = h_id;
  179.  
  180.     pTagData->samprate = sr_table[h_sr_index];
  181.  
  182.     if( h_id == 0 )
  183.         pTagData->samprate >>= 1;
  184.  
  185.     head_flags = pTagData->flags = ExtractI4(buf); buf+=4;      /* get flags */
  186.  
  187.     if( head_flags & FRAMES_FLAG )
  188.     {
  189.         pTagData->frames   = ExtractI4(buf); buf+=4;
  190.     }
  191.  
  192.     if( head_flags & BYTES_FLAG )
  193.     {
  194.         pTagData->bytes = ExtractI4(buf); buf+=4;
  195.     }
  196.  
  197.     if( head_flags & TOC_FLAG )
  198.     {
  199.         if( pTagData->toc != NULL )
  200.         {
  201.             for(i=0;i<NUMTOCENTRIES;i++)
  202.                 pTagData->toc[i] = buf[i];
  203.         }
  204.         buf+=NUMTOCENTRIES;
  205.     }
  206.  
  207.     pTagData->vbr_scale = -1;
  208.  
  209.     if( head_flags & VBR_SCALE_FLAG )
  210.     {
  211.         pTagData->vbr_scale = ExtractI4(buf); buf+=4;
  212.     }
  213.  
  214. #ifdef DEBUG_VBRTAG
  215.     DEBUGF("\n\n********************* VBR TAG INFO *****************\n");
  216.     DEBUGF("tag         :%s\n",VBRTag);
  217.     DEBUGF("head_flags  :%d\n",head_flags);
  218.     DEBUGF("bytes       :%d\n",pTagData->bytes);
  219.     DEBUGF("frames      :%d\n",pTagData->frames);
  220.     DEBUGF("VBR Scale   :%d\n",pTagData->vbr_scale);
  221.     DEBUGF("toc:\n");
  222.     if( pTagData->toc != NULL )
  223.     {
  224.         for(i=0;i<NUMTOCENTRIES;i++)
  225.         {
  226.             if( (i%10) == 0 ) DEBUGF("\n");
  227.             DEBUGF(" %3d", (int)(pTagData->toc[i]));
  228.         }
  229.     }
  230.     DEBUGF("\n***************** END OF VBR TAG INFO ***************\n");
  231. #endif
  232.     return 1;       /* success */
  233. }
  234.  
  235.  
  236. /****************************************************************************
  237.  * InitVbrTag: Initializes the header, and write empty frame to stream
  238.  * Paramters:
  239.  *                fpStream: pointer to output file stream
  240.  *                nMode    : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO
  241.  ****************************************************************************
  242. */
  243. int InitVbrTag(lame_global_flags *gfp)
  244. {
  245.     int nMode,SampIndex;
  246.     lame_internal_flags *gfc = gfp->internal_flags;
  247.     u_char pbtStreamBuffer[216];
  248.     nMode = gfp->mode;
  249.     SampIndex = gfc->samplerate_index;
  250.  
  251.  
  252.     /* Clear Frame position array variables */
  253.     gfp->pVbrFrames=NULL;
  254.     gfp->nVbrNumFrames=0;
  255.     gfp->nVbrFrameBufferSize=0;
  256.  
  257.  
  258.     /* Clear stream buffer */
  259.     memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
  260.  
  261.  
  262.  
  263.     /* Reserve the proper amount of bytes */
  264.     if (nMode==3)
  265.     {
  266.         gfp->nZeroStreamSize=SizeOfEmptyFrame[gfp->version][1]+4;
  267.     }
  268.     else
  269.     {
  270.         gfp->nZeroStreamSize=SizeOfEmptyFrame[gfp->version][0]+4;
  271.     }
  272.  
  273.     /*
  274.     // Xing VBR pretends to be a 48kbs layer III frame.  (at 44.1kHz).
  275.         // (at 48kHz they use 56kbs since 48kbs frame not big enough for
  276.         // table of contents)
  277.     // let's always embed Xing header inside a 64kbs layer III frame.
  278.     // this gives us enough room for a LAME version string too.
  279.     // size determined by sampling frequency (MPEG1)
  280.     // 32kHz:    216 bytes@48kbs    288bytes@ 64kbs
  281.     // 44.1kHz:  156 bytes          208bytes@64kbs     (+1 if padding = 1)
  282.     // 48kHz:    144 bytes          192
  283.     //
  284.     // MPEG 2 values are the since the framesize and samplerate
  285.         // are each reduced by a factor of 2.
  286.     */
  287.     {
  288.     int tot;
  289.     static const int framesize[3]={208,192,288};  /* 64kbs MPEG1 or MPEG2  framesize */
  290.     /* static int framesize[3]={156,144,216}; */ /* 48kbs framesize */
  291.  
  292.     if (SampIndex>2) {
  293.       ERRORF("illegal sampling frequency index\n");
  294.       LAME_ERROR_EXIT();
  295.     }
  296.     gfp->TotalFrameSize= framesize[SampIndex];
  297.     tot = (gfp->nZeroStreamSize+VBRHEADERSIZE);
  298.     tot += 20;  /* extra 20 bytes for LAME & version string */
  299.  
  300.     if (gfp->TotalFrameSize < tot ) {
  301.       ERRORF("Xing VBR header problem...use -t\n");
  302.       LAME_ERROR_EXIT();
  303.     }
  304.     }
  305.  
  306.     add_dummy_vbrframe(gfp,8*gfp->TotalFrameSize);
  307.  
  308.     /* Success */
  309.     return 0;
  310. }
  311.  
  312.  
  313.  
  314. /****************************************************************************
  315.  * PutVbrTag: Write final VBR tag to the file
  316.  * Paramters:
  317.  *                lpszFileName: filename of MP3 bit stream
  318.  *                nVbrScale    : encoder quality indicator (0..100)
  319.  ****************************************************************************
  320. */
  321. int PutVbrTag(lame_global_flags *gfp,char* lpszFileName,int nVbrScale)
  322. {
  323.     int            i;
  324.     long lFileSize;
  325.     int nStreamIndex;
  326.     char abyte;
  327.     u_char        btToc[NUMTOCENTRIES];
  328.     FILE *fpStream;
  329.         u_char pbtStreamBuffer[216];
  330.     char str1[80];
  331.         unsigned char id3v2Header[10];
  332.         size_t id3v2TagSize;
  333.  
  334.     if (gfp->nVbrNumFrames==0 || gfp->pVbrFrames==NULL)
  335.         return -1;
  336.  
  337.     /* Open the bitstream again */
  338.     fpStream=fopen(lpszFileName,"rb+");
  339.  
  340.     /* Assert stream is valid */
  341.     if (fpStream==NULL)
  342.         return -1;
  343.  
  344.     /* Clear stream buffer */
  345.     memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer));
  346.  
  347.     /* Seek to end of file*/
  348.     fseek(fpStream,0,SEEK_END);
  349.  
  350.     /* Get file size */
  351.     lFileSize=ftell(fpStream);
  352.  
  353.     /* Abort if file has zero length. Yes, it can happen :) */
  354.     if (lFileSize==0)
  355.         return -1;
  356.  
  357.         /*
  358.          * The VBR tag may NOT be located at the beginning of the stream.
  359.          * If an ID3 version 2 tag was added, then it must be skipped to write
  360.          * the VBR tag data.
  361.          */
  362.  
  363.         /* seek to the beginning of the stream */
  364.     fseek(fpStream,0,SEEK_SET);
  365.         /* read 10 bytes in case there's an ID3 version 2 header here */
  366.         fread(id3v2Header,1,sizeof id3v2Header,fpStream);
  367.         /* does the stream begin with the ID3 version 2 file identifier? */
  368.         if (!strncmp((char *)id3v2Header,"ID3",3)) {
  369.           /* the tag size (minus the 10-byte header) is encoded into four
  370.            * bytes where the most significant bit is clear in each byte */
  371.           id3v2TagSize=(((id3v2Header[6] & 0x7f)<<21)
  372.             | ((id3v2Header[7] & 0x7f)<<14)
  373.             | ((id3v2Header[8] & 0x7f)<<7)
  374.             | (id3v2Header[9] & 0x7f))
  375.             + sizeof id3v2Header;
  376.         } else {
  377.           /* no ID3 version 2 tag in this stream */
  378.           id3v2TagSize=0;
  379.         }
  380.  
  381.     /* Seek to first real frame */
  382.     fseek(fpStream,id3v2TagSize+(long)gfp->TotalFrameSize,SEEK_SET);
  383.  
  384.     /* Read the header (first valid frame) */
  385.     fread(pbtStreamBuffer,4,1,fpStream);
  386.  
  387.     /* the default VBR header.  48kbs layer III, no padding, no crc */
  388.     /* but sampling freq, mode andy copyright/copy protection taken */
  389.     /* from first valid frame */
  390.     pbtStreamBuffer[0]=(u_char) 0xff;
  391.     abyte = (pbtStreamBuffer[1] & (char) 0xf1);
  392.     if (gfp->version==1) {
  393.           /* changed behaviour as suggested by Mathew Hendry:
  394.            * The Xing VBR header is a valid mpeg.  But because some
  395.        * decoders require CRC on for all frames, or off for all frames,
  396.            * keep crc from the first valid frame without calculating it
  397.            * for this additional Xing frame
  398.            */ 
  399.       pbtStreamBuffer[1]=abyte | (char) 0x0a;     /* was 0x0b; */
  400.       abyte = pbtStreamBuffer[2] & (char) 0x0d;   /* AF keep also private bit */
  401.       pbtStreamBuffer[2]=(char) 0x50 | abyte;     /* 64kbs MPEG1 frame */
  402.     }else{
  403.       pbtStreamBuffer[1]=abyte | (char) 0x02;     /* was 0x03; */
  404.       abyte = pbtStreamBuffer[2] & (char) 0x0d;   /* AF keep also private bit */
  405.       pbtStreamBuffer[2]=(char) 0x80 | abyte;     /* 64kbs MPEG2 frame */
  406.     }
  407.  
  408.  
  409.     /*Seek to the beginning of the stream */
  410.     fseek(fpStream,id3v2TagSize,SEEK_SET);
  411.  
  412.     /* Clear all TOC entries */
  413.     memset(btToc,0,sizeof(btToc));
  414.  
  415.         for (i=1;i<NUMTOCENTRIES;i++) /* Don't touch zero point... */
  416.         {
  417.                 /* Calculate frame from given percentage */
  418.                 int frameNum=(int)(floor(0.01*i*gfp->nVbrNumFrames));
  419.  
  420.                 /*  Calculate relative file postion, normalized to 0..256!(?) */
  421.                 float fRelStreamPos=(float)256.0*(float)gfp->pVbrFrames[frameNum]/(float)lFileSize;
  422.  
  423.                 /* Just to be safe */
  424.                 if (fRelStreamPos>255) fRelStreamPos=255;
  425.  
  426.                 /* Assign toc entry value */
  427.                 btToc[i]=(u_char) fRelStreamPos;
  428.         }
  429.  
  430.  
  431.  
  432.     /* Start writing the tag after the zero frame */
  433.     nStreamIndex=gfp->nZeroStreamSize;
  434.  
  435.     /* Put Vbr tag */
  436.     pbtStreamBuffer[nStreamIndex++]=VBRTag[0];
  437.     pbtStreamBuffer[nStreamIndex++]=VBRTag[1];
  438.     pbtStreamBuffer[nStreamIndex++]=VBRTag[2];
  439.     pbtStreamBuffer[nStreamIndex++]=VBRTag[3];
  440.  
  441.     /* Put header flags */
  442.     CreateI4(&pbtStreamBuffer[nStreamIndex],FRAMES_FLAG+BYTES_FLAG+TOC_FLAG+VBR_SCALE_FLAG);
  443.     nStreamIndex+=4;
  444.  
  445.     /* Put Total Number of frames */
  446.     CreateI4(&pbtStreamBuffer[nStreamIndex],gfp->nVbrNumFrames);
  447.     nStreamIndex+=4;
  448.  
  449.     /* Put Total file size */
  450.     CreateI4(&pbtStreamBuffer[nStreamIndex],(int)lFileSize);
  451.     nStreamIndex+=4;
  452.  
  453.     /* Put TOC */
  454.     memcpy(&pbtStreamBuffer[nStreamIndex],btToc,sizeof(btToc));
  455.     nStreamIndex+=sizeof(btToc);
  456.  
  457.     /* Put VBR SCALE */
  458.     CreateI4(&pbtStreamBuffer[nStreamIndex],nVbrScale);
  459.     nStreamIndex+=4;
  460.  
  461.     /* Put LAME id */
  462.     sprintf(str1,"LAME%s",get_lame_version());
  463.     strncpy((char *)&pbtStreamBuffer[nStreamIndex],str1,(size_t) 20);
  464.     nStreamIndex+=20;
  465.  
  466.  
  467. #ifdef DEBUG_VBRTAG
  468. {
  469.     VBRTAGDATA TestHeader;
  470.     GetVbrTag(&TestHeader,pbtStreamBuffer);
  471. }
  472. #endif
  473.  
  474.         /* Put it all to disk again */
  475.     if (fwrite(pbtStreamBuffer,(unsigned int)gfp->TotalFrameSize,1,fpStream)!=1)
  476.     {
  477.         return -1;
  478.     }
  479.     fclose(fpStream);
  480.  
  481.     /* Save to delete the frame buffer */
  482.     free(gfp->pVbrFrames);
  483.     gfp->pVbrFrames=NULL;
  484.  
  485.     return 0;       /* success */
  486. }
  487.  
  488.