Detect float PCM in WAVE container

This commit is contained in:
Martchus 2019-01-01 23:39:40 +01:00
parent 6afcd0f8d3
commit 3c06590085
2 changed files with 82 additions and 15 deletions

View File

@ -24,12 +24,80 @@ namespace TagParser {
*/
void WaveFormatHeader::parse(IoUtilities::BinaryReader &reader)
{
Diagnostics diag;
parseExt(reader, 16, diag);
}
/*!
* \brief Parses the WAVE "fmt " header segment using the specified \a reader.
* \returns Returns the detected media format and the number of bytes read.
* \todo
* - Make sampleRate and bytesPerSecond 32-bit in v9.
* - Make GUID a field of WaveFormatHeader instead of returning the MediaFormat in v9.
* - Replace parse() function with this.
*/
pair<MediaFormat, uint64> WaveFormatHeader::parseExt(IoUtilities::BinaryReader &reader, uint64 maxSize, Diagnostics &diag)
{
auto result = make_pair<MediaFormat, uint64>(GeneralMediaFormat::Unknown, 0);
if (maxSize < 16) {
diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated.", "parsing WAVE format header");
return result;
}
formatTag = reader.readUInt16LE();
result.first = format();
channelCount = reader.readUInt16LE();
sampleRate = reader.readUInt32LE();
bytesPerSecond = reader.readUInt32LE();
chunkSize = reader.readUInt16LE();
bitsPerSample = reader.readUInt16LE();
result.second = 16;
// read extended header unless format is PCM
if (result.first.general == GeneralMediaFormat::Pcm) {
return result;
}
if ((maxSize -= 16) < 2) {
diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated (extended header missing).", "parsing WAVE format header");
return result;
}
const auto extensionSize = reader.readUInt16LE();
result.second += 2;
if ((maxSize -= 2) < 2) {
diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated (extended header truncated).", "parsing WAVE format header");
return result;
}
// skip extended header unless format is "WAVE_FORMAT_EXTENSIBLE"
if (formatTag != 65534) {
reader.stream()->seekg(extensionSize, ios_base::cur);
result.second += extensionSize;
return result;
}
// read extended header for "WAVE_FORMAT_EXTENSIBLE"
if (extensionSize != 22) {
diag.emplace_back(DiagLevel::Warning, "\"fmt \" extended header has unexptected size.", "parsing WAVE format header");
return result;
}
bitsPerSample = reader.readUInt16LE();
reader.stream()->seekg(4, ios_base::cur); // skip channel mask
const auto guid1 = reader.readUInt64BE();
const auto guid2 = reader.readUInt64BE();
result.second += 22;
switch (guid2) {
case 0x000800000aa00389b71:
switch (guid1) {
case 0x0100000000001000ul:
result.first = MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
break;
case 0x0300000000001000ul:
result.first = MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
break;
}
break;
}
return result;
}
/*!
@ -39,7 +107,9 @@ MediaFormat WaveFormatHeader::format() const
{
switch (formatTag) {
case 0x0001u:
return GeneralMediaFormat::Pcm;
return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
case 0x0003u:
return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
case 0x0050u:
return MediaFormat(GeneralMediaFormat::Mpeg1Audio, SubFormats::Mpeg1Layer2);
case 0x0055u:
@ -82,7 +152,6 @@ TrackType WaveAudioStream::type() const
*/
void WaveAudioStream::addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
{
track.m_format = waveHeader.format();
track.m_formatId = ConversionUtilities::numberToString(waveHeader.formatTag);
track.m_channelCount = waveHeader.channelCount;
track.m_samplingFrequency = waveHeader.sampleRate;
@ -106,20 +175,17 @@ void WaveAudioStream::internalParseHeader(Diagnostics &diag)
throw NoDataFoundException();
}
while (!m_dataOffset) {
uint32 segmentId = m_reader.readUInt32BE();
uint32 restHeaderLen = m_reader.readUInt32LE();
const auto segmentId = m_reader.readUInt32BE();
auto restHeaderLen = m_reader.readUInt32LE();
switch (segmentId) {
case 0x666D7420u:
if (restHeaderLen >= 16u) {
WaveFormatHeader waveHeader;
waveHeader.parse(m_reader);
addInfo(waveHeader, *this);
restHeaderLen -= 16u;
} else {
diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated.", context);
}
break;
case 0x64617461u:
case 0x666D7420u: { // format segment
WaveFormatHeader waveHeader;
uint64 bytesRead;
tie(m_format, bytesRead) = waveHeader.parseExt(m_reader, restHeaderLen, diag);
addInfo(waveHeader, *this);
restHeaderLen -= bytesRead;
} break;
case 0x64617461u: // data segment
m_dataOffset = static_cast<uint64>(m_istream->tellg());
m_size = restHeaderLen;
m_sampleCount = m_size / m_chunkSize;

View File

@ -10,6 +10,7 @@ public:
constexpr WaveFormatHeader();
void parse(IoUtilities::BinaryReader &reader);
std::pair<MediaFormat, uint64> parseExt(IoUtilities::BinaryReader &reader, uint64 maxSize, Diagnostics &diag);
MediaFormat format() const;
constexpr uint32 bitrate() const;