📄 vbrtag.c
字号:
/* fast CRC-16 computation - uses table crc16_lookup 8*/int CRC_update_lookup(int value, int crc){ int tmp; tmp=crc^value; crc=(crc>>8)^crc16_lookup[tmp & 0xff]; return crc;}void UpdateMusicCRC(uint16_t *crc,unsigned char *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) * *****************************************************************************/int PutLameVBR(lame_global_flags *gfp, FILE *fpStream, uint8_t *pbtStreamBuffer, uint32_t id3v2size, uint16_t crc){ lame_internal_flags *gfc = gfp->internal_flags;/* FLOAT fVersion = LAME_MAJOR_VERSION + 0.01 * LAME_MINOR_VERSION; */ int nBytesWritten = 0; int nFilesize = 0; /*size of fpStream. Will be equal to size after process finishes. */ int i; int enc_delay=lame_get_encoder_delay(gfp); /* encoder delay */ int enc_padding=lame_get_encoder_padding(gfp); /* encoder padding */ /*recall: gfp->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); const char *szVersion = get_lame_very_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 = ( ((gfp->lowpassfreq / 100.0)+.5) > 255 ? 255 : (gfp->lowpassfreq / 100.0)+.5 ); uint32_t nPeakSignalAmplitude = 0; uint16_t nRadioReplayGain = 0; uint16_t nAudiophileReplayGain = 0; uint8_t nNoiseShaping = gfp->internal_flags->noise_shaping; uint8_t nStereoMode = 0; int bNonOptimal = 0; uint8_t nSourceFreq = 0; uint8_t nMisc = 0; uint32_t nMusicLength = 0; int bId3v1Present = ((gfp->internal_flags->tag_spec.flags & CHANGED_FLAG) && !(gfp->internal_flags->tag_spec.flags & V2_ONLY_FLAG)); uint16_t nMusicCRC = 0; /*psy model type: Gpsycho or NsPsytune */ unsigned char bExpNPsyTune = gfp->exp_nspsytune & 1; unsigned char bSafeJoint = (gfp->exp_nspsytune & 2)!=0; unsigned char bNoGapMore = 0; unsigned char bNoGapPrevious = 0; int nNoGapCount = gfp->internal_flags->nogap_total; int nNoGapCurr = gfp->internal_flags->nogap_current; uint8_t nAthType = gfp->ATHtype; /*4 bits. */ uint8_t nFlags = 0; /* if ABR, {store bitrate <=255} else { store "-b"} */ int nABRBitrate; switch (gfp->VBR) { case vbr_abr:{ nABRBitrate = gfp->VBR_mean_bitrate_kbps; break; } case vbr_off:{ nABRBitrate = gfp->brate; break; } default:{ /*vbr modes*/ nABRBitrate = gfp->VBR_min_bitrate_kbps; } } /*revision and vbr method */ if (gfp->VBR>=0 && gfp->VBR < sizeof(vbr_type_translator)) nVBR = vbr_type_translator[gfp->VBR]; else nVBR = 0x00; /*unknown. */ nRevMethod = 0x10 * nRevision + nVBR; /* ReplayGain */ if (gfc->findReplayGain) { if (gfc->RadioGain > 0x1FE) gfc->RadioGain = 0x1FE; if (gfc->RadioGain < -0x1FE) gfc->RadioGain = -0x1FE; nRadioReplayGain = 0x2000; /* set name code */ nRadioReplayGain |= 0xC00; /* set originator code to `determined automatically' */ if (gfc->RadioGain >= 0) nRadioReplayGain |= gfc->RadioGain; /* set gain adjustment */ else { nRadioReplayGain |= 0x200; /* set the sign bit */ nRadioReplayGain |= -gfc->RadioGain; /* set gain adjustment */ } } /* peak sample */ if(gfc->findPeakSample) nPeakSignalAmplitude = abs((int)((((FLOAT)gfc->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(gfp->mode) { case MONO: nStereoMode = 0; break; case STEREO: nStereoMode = 1; break; case DUAL_CHANNEL: nStereoMode = 2; break; case JOINT_STEREO: if (gfp->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 (gfp->in_samplerate <= 32000) nSourceFreq = 0x00; else if (gfp->in_samplerate ==48000) nSourceFreq = 0x02; else if (gfp->in_samplerate > 48000) nSourceFreq = 0x03; else nSourceFreq = 0x01; /*default is 44100Hz. */ /*Check if the user overrided the default LAME behaviour with some nasty options */ if (gfp->short_blocks == short_block_forced || gfp->short_blocks == short_block_dispensed || ((gfp->lowpassfreq == -1) && (gfp->highpassfreq == -1)) || /* "-k" */ (gfp->scale_left != gfp->scale_right) || (gfp->disable_reservoir && gfp->brate < 320) || gfp->noATH || gfp->ATHonly || (nAthType == 0) || gfp->in_samplerate <= 32000) bNonOptimal = 1; nMisc = nNoiseShaping + (nStereoMode << 2) + (bNonOptimal << 5) + (nSourceFreq << 6); /*get filesize */ fseek(fpStream, 0, SEEK_END); nFilesize = ftell(fpStream); nMusicLength = nFilesize - id3v2size; /*omit current frame */ if (bId3v1Present) nMusicLength-=128; /*id3v1 present. */ nMusicCRC = gfc->nMusicCRC; /*Write all this information into the stream*/ CreateI4(&pbtStreamBuffer[nBytesWritten], nQuality); nBytesWritten+=4; strncpy(&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], gfp->preset); nBytesWritten+=2; CreateI4(&pbtStreamBuffer[nBytesWritten], 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;}/*********************************************************************** * * 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 *gfp,FILE *fpStream,int nVbrScale){ lame_internal_flags * gfc = gfp->internal_flags; long lFileSize; int nStreamIndex; char abyte,bbyte; uint8_t btToc[NUMTOCENTRIES]; uint8_t pbtStreamBuffer[MAXFRAMESIZE]; int i; uint16_t crc = 0x00; unsigned char id3v2Header[10]; size_t id3v2TagSize; if (gfc->VBR_seek_table.pos <= 0) return -1; /* Clear stream buffer */ memset(pbtStreamBuffer,0x00,sizeof(pbtStreamBuffer)); /* 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. */ /* seek to the beginning of the stream */ fseek(fpStream,0,SEEK_SET); /* read 10 bytes in case there's an ID3 version 2 header here */ fread(id3v2Header,1,sizeof id3v2Header,fpStream); /* 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; } /* Seek to first real frame */ fseek(fpStream,id3v2TagSize+gfp->TotalFrameSize,SEEK_SET); /* Read the header (first valid frame) */ fread(pbtStreamBuffer,4,1,fpStream); /* 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 */ pbtStreamBuffer[0]=(uint8_t) 0xff; abyte = (pbtStreamBuffer[1] & (char) 0xf1); { int bitrate; if (1==gfp->version) { bitrate = XING_BITRATE1; } else { if (gfp->out_samplerate < 16000 ) bitrate = XING_BITRATE25; else bitrate = XING_BITRATE2; } if (gfp->VBR==vbr_off) bitrate = gfp->brate; if (gfp->free_format) bbyte = 0x00; else bbyte = 16*BitrateIndex(bitrate,gfp->version,gfp->out_samplerate); } /* Use as much of the info from the real frames in the * Xing header: samplerate, channels, crc, etc... */ if (gfp->version==1) { /* MPEG1 */ pbtStreamBuffer[1]=abyte | (char) 0x0a; /* was 0x0b; */ abyte = pbtStreamBuffer[2] & (char) 0x0d; /* AF keep also private bit */ pbtStreamBuffer[2]=(char) bbyte | abyte; /* 64kbs MPEG1 frame */ }else{ /* MPEG2 */ pbtStreamBuffer[1]=abyte | (char) 0x02; /* was 0x03; */ abyte = pbtStreamBuffer[2] & (char) 0x0d; /* AF keep also private bit */ pbtStreamBuffer[2]=(char) bbyte | abyte; /* 64kbs MPEG2 frame */ } /* Clear all TOC entries */ memset(btToc,0,sizeof(btToc)); if (gfp->free_format) { int i; for (i = 1; i < NUMTOCENTRIES; ++i) btToc[i] = 255*i/100; } else { Xing_seek_table(&gfc->VBR_seek_table, btToc); } /*print_seeking (btToc);*/ /* Start writing the tag after the zero frame */ nStreamIndex=gfc->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 (gfp->error_protection) nStreamIndex -= 2; /* Put Vbr tag */ if (gfp->VBR == vbr_off) { pbtStreamBuffer[nStreamIndex++]=VBRTag1[0]; pbtStreamBuffer[nStreamIndex++]=VBRTag1[1]; pbtStreamBuffer[nStreamIndex++]=VBRTag1[2]; pbtStreamBuffer[nStreamIndex++]=VBRTag1[3]; } else { pbtStreamBuffer[nStreamIndex++]=VBRTag0[0]; pbtStreamBuffer[nStreamIndex++]=VBRTag0[1]; pbtStreamBuffer[nStreamIndex++]=VBRTag0[2]; pbtStreamBuffer[nStreamIndex++]=VBRTag0[3]; } /* Put header flags */ CreateI4(&pbtStreamBuffer[nStreamIndex],FRAMES_FLAG+BYTES_FLAG+TOC_FLAG+VBR_SCALE_FLAG); nStreamIndex+=4; /* Put Total Number of frames */ CreateI4(&pbtStreamBuffer[nStreamIndex],gfp->nVbrNumFrames); nStreamIndex+=4; /* Put Total file size */ CreateI4(&pbtStreamBuffer[nStreamIndex],(int)lFileSize); nStreamIndex+=4; /* Put TOC */ memcpy(&pbtStreamBuffer[nStreamIndex],btToc,sizeof(btToc)); nStreamIndex+=sizeof(btToc); if (gfp->error_protection) { /* (jo) error_protection: add crc16 information to header */ CRC_writeheader(gfc, (char*)pbtStreamBuffer); } /*work out CRC so far: initially crc = 0 */ for (i = 0;i< nStreamIndex ;i++) crc = CRC_update_lookup(pbtStreamBuffer[i], crc); /*Put LAME VBR info*/ nStreamIndex+=PutLameVBR(gfp, fpStream, pbtStreamBuffer + nStreamIndex, id3v2TagSize,crc);#ifdef DEBUG_VBRTAG { VBRTAGDATA TestHeader; GetVbrTag(&TestHeader,pbtStreamBuffer); }#endif /*Seek to the beginning of the stream */ fseek(fpStream,id3v2TagSize,SEEK_SET); /* Put it all to disk again */ if (fwrite(pbtStreamBuffer,(unsigned int)gfp->TotalFrameSize,1,fpStream)!=1) { return -1; } return 0; /* success */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -