📄 pwavfile.cxx
字号:
BOOL PWAVFile::UpdateHeader(){ // Check file is still open if (!IsOpen()) { PTRACE(1,"WAV\tUpdateHeader: Not Open"); return (FALSE); } // Check there is already a valid header if (!isValidWAV) { PTRACE(1,"WAV\tUpdateHeader: File not valid"); return (FALSE); } // Find out the length of the audio data lenData = PFile::GetLength() - lenHeader; // rewrite the length in the RIFF chunk PInt32l riffChunkLen = (lenHeader - 8) + lenData; // size does not include first 8 bytes PFile::SetPosition(4); if (!WriteAndCheck(*this, &riffChunkLen, sizeof(riffChunkLen))) return FALSE; // rewrite the data length field in the data chunk PInt32l dataChunkLen; dataChunkLen = lenData; PFile::SetPosition(lenHeader - 4); if (!WriteAndCheck(*this, &dataChunkLen, sizeof(dataChunkLen))) return FALSE; header_needs_updating = FALSE; return TRUE;}//////////////////////////////////////////////////////////////////BOOL PWAVFileFormat::Read(PWAVFile & file, void * buf, PINDEX & len){ if (!file.RawRead(buf, len)) return FALSE; len = file.GetLastReadCount(); return TRUE;}BOOL PWAVFileFormat::Write(PWAVFile & file, const void * buf, PINDEX & len){ if (!file.RawWrite(buf, len)) return FALSE; len = file.GetLastWriteCount(); return TRUE;}//////////////////////////////////////////////////////////////////class PWAVFileFormatPCM : public PWAVFileFormat{ public: void CreateHeader(PWAV::FMTChunk & wavFmtChunk, PBYTEArray & extendedHeader); PString GetDescription() const; unsigned GetFormat() const; PString GetFormatString() const; BOOL Read(PWAVFile & file, void * buf, PINDEX & len); BOOL Write(PWAVFile & file, const void * buf, PINDEX & len);};PWAVFileFormatByIDFactory::Worker<PWAVFileFormatPCM> pcmIDWAVFormat(PWAVFile::fmt_PCM);PWAVFileFormatByFormatFactory::Worker<PWAVFileFormatPCM> pcmFormatWAVFormat("PCM-16");unsigned PWAVFileFormatPCM::GetFormat() const{ return PWAVFile::fmt_PCM;}PString PWAVFileFormatPCM::GetDescription() const{ return "PCM";}PString PWAVFileFormatPCM::GetFormatString() const{ return "PCM-16";}void PWAVFileFormatPCM::CreateHeader(PWAV::FMTChunk & wavFmtChunk, PBYTEArray & /*extendedHeader*/){ wavFmtChunk.hdr.len = sizeof(wavFmtChunk) - sizeof(wavFmtChunk.hdr); // no extended information wavFmtChunk.format = PWAVFile::fmt_PCM; wavFmtChunk.numChannels = 1; wavFmtChunk.sampleRate = 8000; wavFmtChunk.bytesPerSample = 2; wavFmtChunk.bitsPerSample = 16; wavFmtChunk.bytesPerSec = wavFmtChunk.sampleRate * wavFmtChunk.bytesPerSample;}BOOL PWAVFileFormatPCM::Read(PWAVFile & file, void * buf, PINDEX & len){ if (!file.FileRead(buf, len)) return FALSE; len = file.GetLastReadCount(); // WAV files are little-endian. So swap the bytes if this is // a big endian machine and we have 16 bit samples // Note: swab only works on even length buffers. if (file.wavFmtChunk.bitsPerSample == 16) { SWAB(buf, buf, len); } return TRUE;}BOOL PWAVFileFormatPCM::Write(PWAVFile & file, const void * buf, PINDEX & len){ // WAV files are little-endian. So swap the bytes if this is // a big endian machine and we have 16 bit samples // Note: swab only works on even length buffers. if (file.wavFmtChunk.bitsPerSample == 16) { SWAB(buf, (void *)buf, len); } if (!file.FileWrite(buf, len)) return FALSE; len = file.GetLastWriteCount(); return TRUE;}//////////////////////////////////////////////////////////////////#ifdef __GNUC__#define P_PACKED __attribute__ ((packed));#else#define P_PACKED#pragma pack(1)#endifstruct G7231ExtendedInfo { PInt16l data1 P_PACKED; // 1 PInt16l data2 P_PACKED; // 480};struct G7231FACTChunk { PWAV::ChunkHeader hdr; PInt32l data1 P_PACKED; // 0 Should be number of samples.};#ifdef __GNUC__#undef P_PACKED#else#pragma pack()#endifclass PWAVFileFormatG7231 : public PWAVFileFormat{ public: PWAVFileFormatG7231(unsigned short _g7231) : g7231(_g7231) { } void CreateHeader(PWAV::FMTChunk & wavFmtChunk, PBYTEArray & extendedHeader); BOOL WriteExtraChunks(PWAVFile & file); PString GetFormatString() const { return "G.723.1"; } // must match string in mediafmt.h void OnStart(); BOOL Read(PWAVFile & file, void * buf, PINDEX & len); BOOL Write(PWAVFile & file, const void * buf, PINDEX & len); protected: unsigned short g7231; BYTE cacheBuffer[24]; PINDEX cacheLen; PINDEX cachePos;};void PWAVFileFormatG7231::CreateHeader(PWAV::FMTChunk & wavFmtChunk, PBYTEArray & extendedHeader){ wavFmtChunk.hdr.len = sizeof(wavFmtChunk) - sizeof(wavFmtChunk.hdr) + sizeof(sizeof(G7231ExtendedInfo)); wavFmtChunk.format = g7231; wavFmtChunk.numChannels = 1; wavFmtChunk.sampleRate = 8000; wavFmtChunk.bytesPerSample = 24; wavFmtChunk.bitsPerSample = 0; wavFmtChunk.bytesPerSec = 800; extendedHeader.SetSize(sizeof(G7231ExtendedInfo)); G7231ExtendedInfo * g7231Info = (G7231ExtendedInfo *)extendedHeader.GetPointer(sizeof(G7231ExtendedInfo)); g7231Info->data1 = 1; g7231Info->data2 = 480;}BOOL PWAVFileFormatG7231::WriteExtraChunks(PWAVFile & file){ // write the fact chunk G7231FACTChunk factChunk; memcpy(factChunk.hdr.tag, "FACT", 4); factChunk.hdr.len = sizeof(factChunk) - sizeof(factChunk.hdr); factChunk.data1 = 0; return file.FileWrite(&factChunk, sizeof(factChunk));}static PINDEX G7231FrameSizes[4] = { 24, 20, 4, 1 };void PWAVFileFormatG7231::OnStart(){ cacheLen = cachePos = 0;}BOOL PWAVFileFormatG7231::Read(PWAVFile & file, void * origData, PINDEX & origLen){ // Note that Microsoft && VivoActive G.2723.1 codec cannot do SID frames, so // we must parse the data and remove SID frames // also note that frames are always written as 24 byte frames, so each frame must be unpadded PINDEX bytesRead = 0; while (bytesRead < origLen) { // keep reading until we find a 20 or 24 byte frame while (cachePos == cacheLen) { if (!file.FileRead(cacheBuffer, 24)) return FALSE; // calculate actual length of frame PINDEX frameLen = G7231FrameSizes[cacheBuffer[0] & 3]; if (frameLen == 20 || frameLen == 24) { cacheLen = frameLen; cachePos = 0; } } // copy data to requested buffer PINDEX copyLen = PMIN(origLen-bytesRead, cacheLen-cachePos); memcpy(origData, cacheBuffer+cachePos, copyLen); origData = copyLen + (char *)origData; cachePos += copyLen; bytesRead += copyLen; } origLen = bytesRead; return TRUE;}BOOL PWAVFileFormatG7231::Write(PWAVFile & file, const void * origData, PINDEX & len){ // Note that Microsoft && VivoActive G.2723.1 codec cannot do SID frames, so // we must parse the data and remove SID frames // also note that frames are always written as 24 byte frames, so each frame must be padded PINDEX written = 0; BYTE frameBuffer[24]; while (len > 0) { // calculate actual length of frame PINDEX frameLen = G7231FrameSizes[(*(char *)origData) & 3]; if (len < frameLen) return FALSE; // we can write 24 byte frame straight out, // 20 byte frames need to be reblocked // we ignore any other frames const void * buf = NULL; switch (frameLen) { case 24: buf = origData; break; case 20: memcpy(frameBuffer, origData, 20); buf = frameBuffer; break; default: break; } if (buf != NULL && !file.FileWrite(buf, 24)) return FALSE; else written += 24; origData = (char *)origData + frameLen; len -= frameLen; } len = written; return TRUE;}class PWAVFileFormatG7231_vivo : public PWAVFileFormatG7231{ public: PWAVFileFormatG7231_vivo() : PWAVFileFormatG7231(PWAVFile::fmt_VivoG7231) { } unsigned GetFormat() const { return PWAVFile::fmt_VivoG7231; } PString GetDescription() const { return GetFormatString() & "Vivo"; }};PWAVFileFormatByIDFactory::Worker<PWAVFileFormatG7231_vivo> g7231VivoWAVFormat(PWAVFile::fmt_VivoG7231);PWAVFileFormatByFormatFactory::Worker<PWAVFileFormatG7231_vivo> g7231FormatWAVFormat("G.723.1");class PWAVFileFormatG7231_ms : public PWAVFileFormatG7231{ public: PWAVFileFormatG7231_ms() : PWAVFileFormatG7231(PWAVFile::fmt_MSG7231) { } unsigned GetFormat() const { return PWAVFile::fmt_MSG7231; } PString GetDescription() const { return GetFormatString() & "MS"; }};PWAVFileFormatByIDFactory::Worker<PWAVFileFormatG7231_ms> g7231MSWAVFormat(PWAVFile::fmt_MSG7231);//////////////////////////////////////////////////////////////////class PWAVFileConverterPCM : public PWAVFileConverter{ public: unsigned GetFormat (const PWAVFile & file) const; off_t GetPosition (const PWAVFile & file) const; BOOL SetPosition (PWAVFile & file, off_t pos, PFile::FilePositionOrigin origin); unsigned GetSampleSize(const PWAVFile & file) const; off_t GetDataLength (PWAVFile & file); BOOL Read (PWAVFile & file, void * buf, PINDEX len); BOOL Write (PWAVFile & file, const void * buf, PINDEX len);};unsigned PWAVFileConverterPCM::GetFormat(const PWAVFile &) const{ return PWAVFile::fmt_PCM;}off_t PWAVFileConverterPCM::GetPosition(const PWAVFile & file) const{ off_t pos = file.RawGetPosition(); return pos * 2;}BOOL PWAVFileConverterPCM::SetPosition(PWAVFile & file, off_t pos, PFile::FilePositionOrigin origin){ pos /= 2; return file.SetPosition(pos, origin);}unsigned PWAVFileConverterPCM::GetSampleSize(const PWAVFile &) const{ return 16;}off_t PWAVFileConverterPCM::GetDataLength(PWAVFile & file){ return file.RawGetDataLength() * 2;}BOOL PWAVFileConverterPCM::Read(PWAVFile & file, void * buf, PINDEX len){ if (file.wavFmtChunk.bitsPerSample == 16) return file.PWAVFile::RawRead(buf, len); if (file.wavFmtChunk.bitsPerSample != 8) { PTRACE(1, "PWAVFile\tAttempt to read autoconvert PCM data with unsupported number of bits per sample " << (int)file.wavFmtChunk.bitsPerSample); return FALSE; } // read the PCM data with 8 bits per sample PINDEX samples = (len / 2); PBYTEArray pcm8; if (!file.PWAVFile::RawRead(pcm8.GetPointer(samples), samples)) return FALSE; // convert to PCM-16 PINDEX i; short * pcmPtr = (short *)buf; for (i = 0; i < samples; i++) *pcmPtr++ = (unsigned short)((pcm8[i] << 8) - 0x8000); // fake the lastReadCount file.SetLastReadCount(len); return TRUE;}BOOL PWAVFileConverterPCM::Write(PWAVFile & file, const void * buf, PINDEX len){ if (file.wavFmtChunk.bitsPerSample == 16) return file.PWAVFile::RawWrite(buf, len); PTRACE(1, "PWAVFile\tAttempt to write autoconvert PCM data with unsupported number of bits per sample " << (int)file.wavFmtChunk.bitsPerSample); return FALSE;}PWAVFileConverterFactory::Worker<PWAVFileConverterPCM> pcmConverter(PWAVFile::fmt_PCM, true);//////////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -