📄 pwavfile.cxx
字号:
if (autoConverter == NULL) {
PTRACE(1, "PWAVFile\tNo format converter for type " << (int)wavFmtChunk.format);
return FALSE;
}
}
return (TRUE);
}
// Update the WAV header according to the file length
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:
virtual ~PWAVFileFormatPCM() {}
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)
#endif
struct 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()
#endif
class PWAVFileFormatG7231 : public PWAVFileFormat
{
public:
PWAVFileFormatG7231(unsigned short _g7231)
: g7231(_g7231) { }
virtual ~PWAVFileFormatG7231() {}
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) { }
virtual ~PWAVFileFormatG7231_vivo() {}
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) { }
virtual ~PWAVFileFormatG7231_ms() {}
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:
virtual ~PWAVFileConverterPCM() {}
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 + -