| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082 |
- /*
- * Xing VBR tagging for LAME.
- *
- * Copyright (c) 1999 A.L. Faber
- * Copyright (c) 2001 Jonathan Dee
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library 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
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
- /* $Id$ */
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- #include "lame.h"
- #include "machine.h"
- #include "encoder.h"
- #include "util.h"
- #include "bitstream.h"
- #include "VbrTag.h"
- #include "lame_global_flags.h"
- #include "tables.h"
- #ifdef __sun__
- /* woraround for SunOS 4.x, it has SEEK_* defined here */
- #include <unistd.h>
- #endif
- #ifdef _DEBUG
- /* #define DEBUG_VBRTAG */
- #endif
- /*
- * 4 bytes for Header Tag
- * 4 bytes for Header Flags
- * 100 bytes for entry (NUMTOCENTRIES)
- * 4 bytes for FRAME SIZE
- * 4 bytes for STREAM_SIZE
- * 4 bytes for VBR SCALE. a VBR quality indicator: 0=best 100=worst
- * 20 bytes for LAME tag. for example, "LAME3.12 (beta 6)"
- * ___________
- * 140 bytes
- */
- #define VBRHEADERSIZE (NUMTOCENTRIES+4+4+4+4+4)
- #define LAMEHEADERSIZE (VBRHEADERSIZE + 9 + 1 + 1 + 8 + 1 + 1 + 3 + 1 + 1 + 2 + 4 + 2 + 2)
- /* the size of the Xing header (MPEG1 and MPEG2) in kbps */
- #define XING_BITRATE1 128
- #define XING_BITRATE2 64
- #define XING_BITRATE25 32
- extern const char* get_lame_tag_encoder_short_version(void);
- static const char VBRTag0[] = { "Xing" };
- static const char VBRTag1[] = { "Info" };
- /* Lookup table for fast CRC computation
- * See 'CRC_update_lookup'
- * Uses the polynomial x^16+x^15+x^2+1 */
- static const unsigned int crc16_lookup[256] = {
- 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
- 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
- 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
- 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
- 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
- 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
- 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
- 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
- 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
- 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
- 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
- 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
- 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
- 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
- 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
- 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
- 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
- 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
- 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
- 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
- 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
- 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
- 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
- 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
- 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
- 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
- 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
- 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
- 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
- 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
- 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
- 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
- };
- /***********************************************************************
- * Robert Hegemann 2001-01-17
- ***********************************************************************/
- static void
- addVbr(VBR_seek_info_t * v, int bitrate)
- {
- int i;
- v->nVbrNumFrames++;
- v->sum += bitrate;
- v->seen++;
- if (v->seen < v->want) {
- return;
- }
- if (v->pos < v->size) {
- v->bag[v->pos] = v->sum;
- v->pos++;
- v->seen = 0;
- }
- if (v->pos == v->size) {
- for (i = 1; i < v->size; i += 2) {
- v->bag[i / 2] = v->bag[i];
- }
- v->want *= 2;
- v->pos /= 2;
- }
- }
- static void
- Xing_seek_table(VBR_seek_info_t const* v, unsigned char *t)
- {
- int i, indx;
- int seek_point;
- if (v->pos <= 0)
- return;
- for (i = 1; i < NUMTOCENTRIES; ++i) {
- float j = i / (float) NUMTOCENTRIES, act, sum;
- indx = (int) (floor(j * v->pos));
- if (indx > v->pos - 1)
- indx = v->pos - 1;
- act = v->bag[indx];
- sum = v->sum;
- seek_point = (int) (256. * act / sum);
- if (seek_point > 255)
- seek_point = 255;
- t[i] = seek_point;
- }
- }
- #ifdef DEBUG_VBR_SEEKING_TABLE
- static void
- print_seeking(unsigned char *t)
- {
- int i;
- printf("seeking table ");
- for (i = 0; i < NUMTOCENTRIES; ++i) {
- printf(" %d ", t[i]);
- }
- printf("\n");
- }
- #endif
- /****************************************************************************
- * AddVbrFrame: Add VBR entry, used to fill the VBR the TOC entries
- * Paramters:
- * nStreamPos: how many bytes did we write to the bitstream so far
- * (in Bytes NOT Bits)
- ****************************************************************************
- */
- void
- AddVbrFrame(lame_internal_flags * gfc)
- {
- int kbps = bitrate_table[gfc->cfg.version][gfc->ov_enc.bitrate_index];
- assert(gfc->VBR_seek_table.bag);
- addVbr(&gfc->VBR_seek_table, kbps);
- }
- /*-------------------------------------------------------------*/
- static int
- ExtractI4(const unsigned char *buf)
- {
- int x;
- /* big endian extract */
- x = buf[0];
- x <<= 8;
- x |= buf[1];
- x <<= 8;
- x |= buf[2];
- x <<= 8;
- x |= buf[3];
- return x;
- }
- static void
- CreateI4(unsigned char *buf, uint32_t nValue)
- {
- /* big endian create */
- buf[0] = (nValue >> 24) & 0xff;
- buf[1] = (nValue >> 16) & 0xff;
- buf[2] = (nValue >> 8) & 0xff;
- buf[3] = (nValue) & 0xff;
- }
- static void
- CreateI2(unsigned char *buf, int nValue)
- {
- /* big endian create */
- buf[0] = (nValue >> 8) & 0xff;
- buf[1] = (nValue) & 0xff;
- }
- /* check for magic strings*/
- static int
- IsVbrTag(const unsigned char *buf)
- {
- int isTag0, isTag1;
- isTag0 = ((buf[0] == VBRTag0[0]) && (buf[1] == VBRTag0[1]) && (buf[2] == VBRTag0[2])
- && (buf[3] == VBRTag0[3]));
- isTag1 = ((buf[0] == VBRTag1[0]) && (buf[1] == VBRTag1[1]) && (buf[2] == VBRTag1[2])
- && (buf[3] == VBRTag1[3]));
- return (isTag0 || isTag1);
- }
- #define SHIFT_IN_BITS_VALUE(x,n,v) ( x = (x << (n)) | ( (v) & ~(-1 << (n)) ) )
- static void
- setLameTagFrameHeader(lame_internal_flags const *gfc, unsigned char *buffer)
- {
- SessionConfig_t const *const cfg = &gfc->cfg;
- EncResult_t const *const eov = &gfc->ov_enc;
- char abyte, bbyte;
- SHIFT_IN_BITS_VALUE(buffer[0], 8u, 0xffu);
- SHIFT_IN_BITS_VALUE(buffer[1], 3u, 7);
- SHIFT_IN_BITS_VALUE(buffer[1], 1u, (cfg->samplerate_out < 16000) ? 0 : 1);
- SHIFT_IN_BITS_VALUE(buffer[1], 1u, cfg->version);
- SHIFT_IN_BITS_VALUE(buffer[1], 2u, 4 - 3);
- SHIFT_IN_BITS_VALUE(buffer[1], 1u, (!cfg->error_protection) ? 1 : 0);
- SHIFT_IN_BITS_VALUE(buffer[2], 4u, eov->bitrate_index);
- SHIFT_IN_BITS_VALUE(buffer[2], 2u, cfg->samplerate_index);
- SHIFT_IN_BITS_VALUE(buffer[2], 1u, 0);
- SHIFT_IN_BITS_VALUE(buffer[2], 1u, cfg->extension);
- SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->mode);
- SHIFT_IN_BITS_VALUE(buffer[3], 2u, eov->mode_ext);
- SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->copyright);
- SHIFT_IN_BITS_VALUE(buffer[3], 1u, cfg->original);
- SHIFT_IN_BITS_VALUE(buffer[3], 2u, cfg->emphasis);
- /* the default VBR header. 48 kbps layer III, no padding, no crc */
- /* but sampling freq, mode andy copyright/copy protection taken */
- /* from first valid frame */
- buffer[0] = (uint8_t) 0xff;
- abyte = (buffer[1] & (unsigned char) 0xf1);
- {
- int bitrate;
- if (1 == cfg->version) {
- bitrate = XING_BITRATE1;
- }
- else {
- if (cfg->samplerate_out < 16000)
- bitrate = XING_BITRATE25;
- else
- bitrate = XING_BITRATE2;
- }
- if (cfg->vbr == vbr_off)
- bitrate = cfg->avg_bitrate;
- if (cfg->free_format)
- bbyte = 0x00;
- else
- bbyte = 16 * BitrateIndex(bitrate, cfg->version, cfg->samplerate_out);
- }
- /* Use as much of the info from the real frames in the
- * Xing header: samplerate, channels, crc, etc...
- */
- if (cfg->version == 1) {
- /* MPEG1 */
- buffer[1] = abyte | (char) 0x0a; /* was 0x0b; */
- abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */
- buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG1 frame */
- }
- else {
- /* MPEG2 */
- buffer[1] = abyte | (char) 0x02; /* was 0x03; */
- abyte = buffer[2] & (char) 0x0d; /* AF keep also private bit */
- buffer[2] = (char) bbyte | abyte; /* 64kbs MPEG2 frame */
- }
- }
- #if 0
- static int CheckVbrTag(unsigned char *buf);
- /*-------------------------------------------------------------*/
- /* Same as GetVbrTag below, but only checks for the Xing tag.
- requires buf to contain only 40 bytes */
- /*-------------------------------------------------------------*/
- int
- CheckVbrTag(unsigned char *buf)
- {
- int h_id, h_mode;
- /* get selected MPEG header data */
- h_id = (buf[1] >> 3) & 1;
- h_mode = (buf[3] >> 6) & 3;
- /* determine offset of header */
- if (h_id) {
- /* mpeg1 */
- if (h_mode != 3)
- buf += (32 + 4);
- else
- buf += (17 + 4);
- }
- else {
- /* mpeg2 */
- if (h_mode != 3)
- buf += (17 + 4);
- else
- buf += (9 + 4);
- }
- return IsVbrTag(buf);
- }
- #endif
- int
- GetVbrTag(VBRTAGDATA * pTagData, const unsigned char *buf)
- {
- int i, head_flags;
- int h_bitrate, h_id, h_mode, h_sr_index, h_layer;
- int enc_delay, enc_padding;
- /* get Vbr header data */
- pTagData->flags = 0;
- /* get selected MPEG header data */
- h_layer = (buf[1] >> 1) & 3;
- if ( h_layer != 0x01 ) {
- /* the following code assumes Layer-3, so give up here */
- return 0;
- }
- h_id = (buf[1] >> 3) & 1;
- h_sr_index = (buf[2] >> 2) & 3;
- h_mode = (buf[3] >> 6) & 3;
- h_bitrate = ((buf[2] >> 4) & 0xf);
- h_bitrate = bitrate_table[h_id][h_bitrate];
- /* check for FFE syncword */
- if ((buf[1] >> 4) == 0xE)
- pTagData->samprate = samplerate_table[2][h_sr_index];
- else
- pTagData->samprate = samplerate_table[h_id][h_sr_index];
- /* if( h_id == 0 ) */
- /* pTagData->samprate >>= 1; */
- /* determine offset of header */
- if (h_id) {
- /* mpeg1 */
- if (h_mode != 3)
- buf += (32 + 4);
- else
- buf += (17 + 4);
- }
- else {
- /* mpeg2 */
- if (h_mode != 3)
- buf += (17 + 4);
- else
- buf += (9 + 4);
- }
- if (!IsVbrTag(buf))
- return 0;
- buf += 4;
- pTagData->h_id = h_id;
- head_flags = pTagData->flags = ExtractI4(buf);
- buf += 4; /* get flags */
- if (head_flags & FRAMES_FLAG) {
- pTagData->frames = ExtractI4(buf);
- buf += 4;
- }
- if (head_flags & BYTES_FLAG) {
- pTagData->bytes = ExtractI4(buf);
- buf += 4;
- }
- if (head_flags & TOC_FLAG) {
- if (pTagData->toc != NULL) {
- for (i = 0; i < NUMTOCENTRIES; i++)
- pTagData->toc[i] = buf[i];
- }
- buf += NUMTOCENTRIES;
- }
- pTagData->vbr_scale = -1;
- if (head_flags & VBR_SCALE_FLAG) {
- pTagData->vbr_scale = ExtractI4(buf);
- buf += 4;
- }
- pTagData->headersize = ((h_id + 1) * 72000 * h_bitrate) / pTagData->samprate;
- buf += 21;
- enc_delay = buf[0] << 4;
- enc_delay += buf[1] >> 4;
- enc_padding = (buf[1] & 0x0F) << 8;
- enc_padding += buf[2];
- /* check for reasonable values (this may be an old Xing header, */
- /* not a INFO tag) */
- if (enc_delay < 0 || enc_delay > 3000)
- enc_delay = -1;
- if (enc_padding < 0 || enc_padding > 3000)
- enc_padding = -1;
- pTagData->enc_delay = enc_delay;
- pTagData->enc_padding = enc_padding;
- #ifdef DEBUG_VBRTAG
- fprintf(stderr, "\n\n********************* VBR TAG INFO *****************\n");
- fprintf(stderr, "tag :%s\n", VBRTag);
- fprintf(stderr, "head_flags :%d\n", head_flags);
- fprintf(stderr, "bytes :%d\n", pTagData->bytes);
- fprintf(stderr, "frames :%d\n", pTagData->frames);
- fprintf(stderr, "VBR Scale :%d\n", pTagData->vbr_scale);
- fprintf(stderr, "enc_delay = %i \n", enc_delay);
- fprintf(stderr, "enc_padding= %i \n", enc_padding);
- fprintf(stderr, "toc:\n");
- if (pTagData->toc != NULL) {
- for (i = 0; i < NUMTOCENTRIES; i++) {
- if ((i % 10) == 0)
- fprintf(stderr, "\n");
- fprintf(stderr, " %3d", (int) (pTagData->toc[i]));
- }
- }
- fprintf(stderr, "\n***************** END OF VBR TAG INFO ***************\n");
- #endif
- return 1; /* success */
- }
- /****************************************************************************
- * InitVbrTag: Initializes the header, and write empty frame to stream
- * Paramters:
- * fpStream: pointer to output file stream
- * nMode : Channel Mode: 0=STEREO 1=JS 2=DS 3=MONO
- ****************************************************************************
- */
- int
- InitVbrTag(lame_global_flags * gfp)
- {
- lame_internal_flags *gfc = gfp->internal_flags;
- SessionConfig_t const *const cfg = &gfc->cfg;
- int kbps_header;
- #define MAXFRAMESIZE 2880 /* or 0xB40, the max freeformat 640 32kHz framesize */
- /*
- * Xing VBR pretends to be a 48kbs layer III frame. (at 44.1kHz).
- * (at 48kHz they use 56kbs since 48kbs frame not big enough for
- * table of contents)
- * let's always embed Xing header inside a 64kbs layer III frame.
- * this gives us enough room for a LAME version string too.
- * size determined by sampling frequency (MPEG1)
- * 32kHz: 216 bytes@48kbs 288bytes@ 64kbs
- * 44.1kHz: 156 bytes 208bytes@64kbs (+1 if padding = 1)
- * 48kHz: 144 bytes 192
- *
- * MPEG 2 values are the same since the framesize and samplerate
- * are each reduced by a factor of 2.
- */
- if (1 == cfg->version) {
- kbps_header = XING_BITRATE1;
- }
- else {
- if (cfg->samplerate_out < 16000)
- kbps_header = XING_BITRATE25;
- else
- kbps_header = XING_BITRATE2;
- }
- if (cfg->vbr == vbr_off)
- kbps_header = cfg->avg_bitrate;
- /** make sure LAME Header fits into Frame
- */
- {
- int total_frame_size = ((cfg->version + 1) * 72000 * kbps_header) / cfg->samplerate_out;
- int header_size = (cfg->sideinfo_len + LAMEHEADERSIZE);
- gfc->VBR_seek_table.TotalFrameSize = total_frame_size;
- if (total_frame_size < header_size || total_frame_size > MAXFRAMESIZE) {
- /* disable tag, it wont fit */
- gfc->cfg.write_lame_tag = 0;
- return 0;
- }
- }
- gfc->VBR_seek_table.nVbrNumFrames = 0;
- gfc->VBR_seek_table.nBytesWritten = 0;
- gfc->VBR_seek_table.sum = 0;
- gfc->VBR_seek_table.seen = 0;
- gfc->VBR_seek_table.want = 1;
- gfc->VBR_seek_table.pos = 0;
- if (gfc->VBR_seek_table.bag == NULL) {
- gfc->VBR_seek_table.bag = lame_calloc(int, 400);
- if (gfc->VBR_seek_table.bag != NULL) {
- gfc->VBR_seek_table.size = 400;
- }
- else {
- gfc->VBR_seek_table.size = 0;
- ERRORF(gfc, "Error: can't allocate VbrFrames buffer\n");
- gfc->cfg.write_lame_tag = 0;
- return -1;
- }
- }
- /* write dummy VBR tag of all 0's into bitstream */
- {
- uint8_t buffer[MAXFRAMESIZE];
- size_t i, n;
- memset(buffer, 0, sizeof(buffer));
- setLameTagFrameHeader(gfc, buffer);
- n = gfc->VBR_seek_table.TotalFrameSize;
- for (i = 0; i < n; ++i) {
- add_dummy_byte(gfc, buffer[i], 1);
- }
- }
- /* Success */
- return 0;
- }
- /* fast CRC-16 computation - uses table crc16_lookup 8*/
- static uint16_t
- CRC_update_lookup(uint16_t value, uint16_t crc)
- {
- uint16_t tmp;
- tmp = crc ^ value;
- crc = (crc >> 8) ^ crc16_lookup[tmp & 0xff];
- return crc;
- }
- void
- UpdateMusicCRC(uint16_t * crc, unsigned char const *buffer, int size)
- {
- int i;
- for (i = 0; i < size; ++i)
- *crc = CRC_update_lookup(buffer[i], *crc);
- }
- /****************************************************************************
- * Jonathan Dee 2001/08/31
- *
- * PutLameVBR: Write LAME info: mini version + info on various switches used
- * Paramters:
- * pbtStreamBuffer : pointer to output buffer
- * id3v2size : size of id3v2 tag in bytes
- * crc : computation of crc-16 of Lame Tag so far (starting at frame sync)
- *
- ****************************************************************************
- */
- static int
- PutLameVBR(lame_global_flags const *gfp, size_t nMusicLength, uint8_t * pbtStreamBuffer, uint16_t crc)
- {
- lame_internal_flags const *gfc = gfp->internal_flags;
- SessionConfig_t const *const cfg = &gfc->cfg;
- int nBytesWritten = 0;
- int i;
- int enc_delay = gfc->ov_enc.encoder_delay; /* encoder delay */
- int enc_padding = gfc->ov_enc.encoder_padding; /* encoder padding */
- /*recall: cfg->vbr_q is for example set by the switch -V */
- /* gfp->quality by -q, -h, -f, etc */
- int nQuality = (100 - 10 * gfp->VBR_q - gfp->quality);
- /*
- NOTE:
- Even though the specification for the LAME VBR tag
- did explicitly mention other encoders than LAME,
- many SW/HW decoder seem to be able to make use of
- this tag only, if the encoder version starts with LAME.
- To be compatible with such decoders, ANY encoder will
- be forced to write a fake LAME version string!
- As a result, the encoder version info becomes worthless.
- */
- const char *szVersion = get_lame_tag_encoder_short_version();
- uint8_t nVBR;
- uint8_t nRevision = 0x00;
- uint8_t nRevMethod;
- uint8_t vbr_type_translator[] = { 1, 5, 3, 2, 4, 0, 3 }; /*numbering different in vbr_mode vs. Lame tag */
- uint8_t nLowpass =
- (((cfg->lowpassfreq / 100.0) + .5) > 255 ? 255 : (cfg->lowpassfreq / 100.0) + .5);
- uint32_t nPeakSignalAmplitude = 0;
- uint16_t nRadioReplayGain = 0;
- uint16_t nAudiophileReplayGain = 0;
- uint8_t nNoiseShaping = cfg->noise_shaping;
- uint8_t nStereoMode = 0;
- int bNonOptimal = 0;
- uint8_t nSourceFreq = 0;
- uint8_t nMisc = 0;
- uint16_t nMusicCRC = 0;
- /*psy model type: Gpsycho or NsPsytune */
- unsigned char bExpNPsyTune = 1; /* only NsPsytune */
- unsigned char bSafeJoint = (cfg->use_safe_joint_stereo) != 0;
- unsigned char bNoGapMore = 0;
- unsigned char bNoGapPrevious = 0;
- int nNoGapCount = gfp->nogap_total;
- int nNoGapCurr = gfp->nogap_current;
- uint8_t nAthType = cfg->ATHtype; /*4 bits. */
- uint8_t nFlags = 0;
- /* if ABR, {store bitrate <=255} else { store "-b"} */
- int nABRBitrate;
- switch (cfg->vbr) {
- case vbr_abr:{
- nABRBitrate = cfg->vbr_avg_bitrate_kbps;
- break;
- }
- case vbr_off:{
- nABRBitrate = cfg->avg_bitrate;
- break;
- }
- default:{ /*vbr modes */
- nABRBitrate = bitrate_table[cfg->version][cfg->vbr_min_bitrate_index];;
- }
- }
- /*revision and vbr method */
- if (cfg->vbr < sizeof(vbr_type_translator))
- nVBR = vbr_type_translator[cfg->vbr];
- else
- nVBR = 0x00; /*unknown. */
- nRevMethod = 0x10 * nRevision + nVBR;
- /* ReplayGain */
- if (cfg->findReplayGain) {
- int RadioGain = gfc->ov_rpg.RadioGain;
- if (RadioGain > 0x1FE)
- RadioGain = 0x1FE;
- if (RadioGain < -0x1FE)
- RadioGain = -0x1FE;
- nRadioReplayGain = 0x2000; /* set name code */
- nRadioReplayGain |= 0xC00; /* set originator code to `determined automatically' */
- if (RadioGain >= 0)
- nRadioReplayGain |= RadioGain; /* set gain adjustment */
- else {
- nRadioReplayGain |= 0x200; /* set the sign bit */
- nRadioReplayGain |= -RadioGain; /* set gain adjustment */
- }
- }
- /* peak sample */
- if (cfg->findPeakSample)
- nPeakSignalAmplitude =
- abs((int) ((((FLOAT) gfc->ov_rpg.PeakSample) / 32767.0) * pow(2, 23) + .5));
- /*nogap */
- if (nNoGapCount != -1) {
- if (nNoGapCurr > 0)
- bNoGapPrevious = 1;
- if (nNoGapCurr < nNoGapCount - 1)
- bNoGapMore = 1;
- }
- /*flags */
- nFlags = nAthType + (bExpNPsyTune << 4)
- + (bSafeJoint << 5)
- + (bNoGapMore << 6)
- + (bNoGapPrevious << 7);
- if (nQuality < 0)
- nQuality = 0;
- /*stereo mode field... a bit ugly. */
- switch (cfg->mode) {
- case MONO:
- nStereoMode = 0;
- break;
- case STEREO:
- nStereoMode = 1;
- break;
- case DUAL_CHANNEL:
- nStereoMode = 2;
- break;
- case JOINT_STEREO:
- if (cfg->force_ms)
- nStereoMode = 4;
- else
- nStereoMode = 3;
- break;
- case NOT_SET:
- /* FALLTHROUGH */
- default:
- nStereoMode = 7;
- break;
- }
- /*Intensity stereo : nStereoMode = 6. IS is not implemented */
- if (cfg->samplerate_in <= 32000)
- nSourceFreq = 0x00;
- else if (cfg->samplerate_in == 48000)
- nSourceFreq = 0x02;
- else if (cfg->samplerate_in > 48000)
- nSourceFreq = 0x03;
- else
- nSourceFreq = 0x01; /*default is 44100Hz. */
- /*Check if the user overrided the default LAME behaviour with some nasty options */
- if (cfg->short_blocks == short_block_forced || cfg->short_blocks == short_block_dispensed || ((cfg->lowpassfreq == -1) && (cfg->highpassfreq == -1)) || /* "-k" */
- (cfg->disable_reservoir && cfg->avg_bitrate < 320) ||
- cfg->noATH || cfg->ATHonly || (nAthType == 0) || cfg->samplerate_in <= 32000)
- bNonOptimal = 1;
- nMisc = nNoiseShaping + (nStereoMode << 2)
- + (bNonOptimal << 5)
- + (nSourceFreq << 6);
- nMusicCRC = gfc->nMusicCRC;
- /*Write all this information into the stream */
- CreateI4(&pbtStreamBuffer[nBytesWritten], nQuality);
- nBytesWritten += 4;
- strncpy((char *) &pbtStreamBuffer[nBytesWritten], szVersion, 9);
- nBytesWritten += 9;
- pbtStreamBuffer[nBytesWritten] = nRevMethod;
- nBytesWritten++;
- pbtStreamBuffer[nBytesWritten] = nLowpass;
- nBytesWritten++;
- CreateI4(&pbtStreamBuffer[nBytesWritten], nPeakSignalAmplitude);
- nBytesWritten += 4;
- CreateI2(&pbtStreamBuffer[nBytesWritten], nRadioReplayGain);
- nBytesWritten += 2;
- CreateI2(&pbtStreamBuffer[nBytesWritten], nAudiophileReplayGain);
- nBytesWritten += 2;
- pbtStreamBuffer[nBytesWritten] = nFlags;
- nBytesWritten++;
- if (nABRBitrate >= 255)
- pbtStreamBuffer[nBytesWritten] = 0xFF;
- else
- pbtStreamBuffer[nBytesWritten] = nABRBitrate;
- nBytesWritten++;
- pbtStreamBuffer[nBytesWritten] = enc_delay >> 4; /* works for win32, does it for unix? */
- pbtStreamBuffer[nBytesWritten + 1] = (enc_delay << 4) + (enc_padding >> 8);
- pbtStreamBuffer[nBytesWritten + 2] = enc_padding;
- nBytesWritten += 3;
- pbtStreamBuffer[nBytesWritten] = nMisc;
- nBytesWritten++;
- pbtStreamBuffer[nBytesWritten++] = 0; /*unused in rev0 */
- CreateI2(&pbtStreamBuffer[nBytesWritten], cfg->preset);
- nBytesWritten += 2;
- CreateI4(&pbtStreamBuffer[nBytesWritten], (int) nMusicLength);
- nBytesWritten += 4;
- CreateI2(&pbtStreamBuffer[nBytesWritten], nMusicCRC);
- nBytesWritten += 2;
- /*Calculate tag CRC.... must be done here, since it includes
- *previous information*/
- for (i = 0; i < nBytesWritten; i++)
- crc = CRC_update_lookup(pbtStreamBuffer[i], crc);
- CreateI2(&pbtStreamBuffer[nBytesWritten], crc);
- nBytesWritten += 2;
- return nBytesWritten;
- }
- static long
- skipId3v2(FILE * fpStream)
- {
- size_t nbytes;
- long id3v2TagSize;
- unsigned char id3v2Header[10];
- /* seek to the beginning of the stream */
- if (fseek(fpStream, 0, SEEK_SET) != 0) {
- return -2; /* not seekable, abort */
- }
- /* read 10 bytes in case there's an ID3 version 2 header here */
- nbytes = fread(id3v2Header, 1, sizeof(id3v2Header), fpStream);
- if (nbytes != sizeof(id3v2Header)) {
- return -3; /* not readable, maybe opened Write-Only */
- }
- /* does the stream begin with the ID3 version 2 file identifier? */
- if (!strncmp((char *) id3v2Header, "ID3", 3)) {
- /* the tag size (minus the 10-byte header) is encoded into four
- * bytes where the most significant bit is clear in each byte */
- id3v2TagSize = (((id3v2Header[6] & 0x7f) << 21)
- | ((id3v2Header[7] & 0x7f) << 14)
- | ((id3v2Header[8] & 0x7f) << 7)
- | (id3v2Header[9] & 0x7f))
- + sizeof id3v2Header;
- }
- else {
- /* no ID3 version 2 tag in this stream */
- id3v2TagSize = 0;
- }
- return id3v2TagSize;
- }
- size_t
- lame_get_lametag_frame(lame_global_flags const *gfp, unsigned char *buffer, size_t size)
- {
- lame_internal_flags *gfc;
- SessionConfig_t const *cfg;
- unsigned long stream_size;
- unsigned int nStreamIndex;
- uint8_t btToc[NUMTOCENTRIES];
- if (gfp == 0) {
- return 0;
- }
- gfc = gfp->internal_flags;
- if (gfc == 0) {
- return 0;
- }
- if (!is_lame_internal_flags_valid(gfc)) {
- return 0;
- }
- cfg = &gfc->cfg;
- if (cfg->write_lame_tag == 0) {
- return 0;
- }
- if (gfc->VBR_seek_table.pos <= 0) {
- return 0;
- }
- if (size < gfc->VBR_seek_table.TotalFrameSize) {
- return gfc->VBR_seek_table.TotalFrameSize;
- }
- if (buffer == 0) {
- return 0;
- }
- memset(buffer, 0, gfc->VBR_seek_table.TotalFrameSize);
- /* 4 bytes frame header */
- setLameTagFrameHeader(gfc, buffer);
- /* Clear all TOC entries */
- memset(btToc, 0, sizeof(btToc));
- if (cfg->free_format) {
- int i;
- for (i = 1; i < NUMTOCENTRIES; ++i)
- btToc[i] = 255 * i / 100;
- }
- else {
- Xing_seek_table(&gfc->VBR_seek_table, btToc);
- }
- #ifdef DEBUG_VBR_SEEKING_TABLE
- print_seeking(btToc);
- #endif
- /* Start writing the tag after the zero frame */
- nStreamIndex = cfg->sideinfo_len;
- /* note! Xing header specifies that Xing data goes in the
- * ancillary data with NO ERROR PROTECTION. If error protecton
- * in enabled, the Xing data still starts at the same offset,
- * and now it is in sideinfo data block, and thus will not
- * decode correctly by non-Xing tag aware players */
- if (cfg->error_protection)
- nStreamIndex -= 2;
- /* Put Vbr tag */
- if (cfg->vbr == vbr_off) {
- buffer[nStreamIndex++] = VBRTag1[0];
- buffer[nStreamIndex++] = VBRTag1[1];
- buffer[nStreamIndex++] = VBRTag1[2];
- buffer[nStreamIndex++] = VBRTag1[3];
- }
- else {
- buffer[nStreamIndex++] = VBRTag0[0];
- buffer[nStreamIndex++] = VBRTag0[1];
- buffer[nStreamIndex++] = VBRTag0[2];
- buffer[nStreamIndex++] = VBRTag0[3];
- }
- /* Put header flags */
- CreateI4(&buffer[nStreamIndex], FRAMES_FLAG + BYTES_FLAG + TOC_FLAG + VBR_SCALE_FLAG);
- nStreamIndex += 4;
- /* Put Total Number of frames */
- CreateI4(&buffer[nStreamIndex], gfc->VBR_seek_table.nVbrNumFrames);
- nStreamIndex += 4;
- /* Put total audio stream size, including Xing/LAME Header */
- stream_size = gfc->VBR_seek_table.nBytesWritten + gfc->VBR_seek_table.TotalFrameSize;
- CreateI4(&buffer[nStreamIndex], stream_size);
- nStreamIndex += 4;
- /* Put TOC */
- memcpy(&buffer[nStreamIndex], btToc, sizeof(btToc));
- nStreamIndex += sizeof(btToc);
- if (cfg->error_protection) {
- /* (jo) error_protection: add crc16 information to header */
- CRC_writeheader(gfc, (char *) buffer);
- }
- {
- /*work out CRC so far: initially crc = 0 */
- uint16_t crc = 0x00;
- unsigned int i;
- for (i = 0; i < nStreamIndex; i++)
- crc = CRC_update_lookup(buffer[i], crc);
- /*Put LAME VBR info */
- nStreamIndex += PutLameVBR(gfp, stream_size, buffer + nStreamIndex, crc);
- }
- #ifdef DEBUG_VBRTAG
- {
- VBRTAGDATA TestHeader;
- GetVbrTag(&TestHeader, buffer);
- }
- #endif
- return gfc->VBR_seek_table.TotalFrameSize;
- }
- /***********************************************************************
- *
- * PutVbrTag: Write final VBR tag to the file
- * Paramters:
- * lpszFileName: filename of MP3 bit stream
- * nVbrScale : encoder quality indicator (0..100)
- ****************************************************************************
- */
- int
- PutVbrTag(lame_global_flags const *gfp, FILE * fpStream)
- {
- lame_internal_flags *gfc = gfp->internal_flags;
- long lFileSize;
- long id3v2TagSize;
- size_t nbytes;
- uint8_t buffer[MAXFRAMESIZE];
- if (gfc->VBR_seek_table.pos <= 0)
- return -1;
- /* Seek to end of file */
- fseek(fpStream, 0, SEEK_END);
- /* Get file size */
- lFileSize = ftell(fpStream);
- /* Abort if file has zero length. Yes, it can happen :) */
- if (lFileSize == 0)
- return -1;
- /*
- * The VBR tag may NOT be located at the beginning of the stream.
- * If an ID3 version 2 tag was added, then it must be skipped to write
- * the VBR tag data.
- */
- id3v2TagSize = skipId3v2(fpStream);
- if (id3v2TagSize < 0) {
- return id3v2TagSize;
- }
- /*Seek to the beginning of the stream */
- fseek(fpStream, id3v2TagSize, SEEK_SET);
- nbytes = lame_get_lametag_frame(gfp, buffer, sizeof(buffer));
- if (nbytes > sizeof(buffer)) {
- return -1;
- }
- if (nbytes < 1) {
- return 0;
- }
- /* Put it all to disk again */
- if (fwrite(buffer, nbytes, 1, fpStream) != 1) {
- return -1;
- }
- return 0; /* success */
- }
|