Tag Parser  9.3.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
waveaudiostream.cpp
Go to the documentation of this file.
1 #include "./waveaudiostream.h"
2 
3 #include "../mpegaudio/mpegaudioframestream.h"
4 
5 #include "../exceptions.h"
6 #include "../mediaformat.h"
7 
8 #include <c++utilities/conversion/stringconversion.h>
9 #include <c++utilities/io/binaryreader.h>
10 
11 using namespace std;
12 using namespace CppUtilities;
13 
14 namespace TagParser {
15 
25 std::uint64_t WaveFormatHeader::parse(CppUtilities::BinaryReader &reader, std::uint64_t maxSize, Diagnostics &diag)
26 {
27  uint64_t bytesRead = 0;
28  if (maxSize < 16) {
29  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated.", "parsing WAVE format header");
30  return bytesRead;
31  }
32 
33  formatTag = reader.readUInt16LE();
34  channelCount = reader.readUInt16LE();
35  sampleRate = reader.readUInt32LE();
36  bytesPerSecond = reader.readUInt32LE();
37  chunkSize = reader.readUInt16LE();
38  bitsPerSample = reader.readUInt16LE();
39  bytesRead = 16;
40 
41  // read extended header unless format is PCM
42  if (formatTag == 0x0001u || formatTag == 0x0003u) {
43  return bytesRead;
44  }
45  if ((maxSize -= 16) < 2) {
46  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated (extended header missing).", "parsing WAVE format header");
47  return bytesRead;
48  }
49  const auto extensionSize = reader.readUInt16LE();
50  bytesRead += 2;
51  if ((maxSize -= 2) < 2) {
52  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated (extended header truncated).", "parsing WAVE format header");
53  return bytesRead;
54  }
55 
56  // skip extended header unless format is "WAVE_FORMAT_EXTENSIBLE"
57  if (formatTag != 65534) {
58  reader.stream()->seekg(extensionSize, ios_base::cur);
59  bytesRead += extensionSize;
60  return bytesRead;
61  }
62 
63  // read extended header for "WAVE_FORMAT_EXTENSIBLE"
64  if (extensionSize != 22) {
65  diag.emplace_back(DiagLevel::Warning, "\"fmt \" extended header has unexptected size.", "parsing WAVE format header");
66  return bytesRead;
67  }
68  bitsPerSample = reader.readUInt16LE();
69  channelMask = reader.readUInt32LE();
70  guid1 = reader.readUInt64BE();
71  guid2 = reader.readUInt64BE();
72  return bytesRead += 22;
73 }
74 
78 MediaFormat WaveFormatHeader::format() const
79 {
80  switch (formatTag) {
81  case 0x0001u:
82  return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
83  case 0x0003u:
84  return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
85  case 0x0050u:
87  case 0x0055u:
89  default:
90  switch (guid2) {
91  case 0x000800000aa00389b71:
92  switch (guid1) {
93  case 0x0100000000001000ul:
94  return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
95  case 0x0300000000001000ul:
96  return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
97  }
98  break;
99  }
100  return GeneralMediaFormat::Unknown;
101  }
102 }
103 
113 WaveAudioStream::WaveAudioStream(iostream &stream, std::uint64_t startOffset)
114  : AbstractTrack(stream, startOffset)
115  , m_dataOffset(0)
116 {
118 }
119 
124 {
125 }
126 
128 {
130 }
131 
136 {
137  track.m_format += waveHeader.format();
138  track.m_formatId = numberToString(waveHeader.formatTag);
139  track.m_channelCount = waveHeader.channelCount;
140  track.m_samplingFrequency = waveHeader.sampleRate;
141  track.m_bytesPerSecond = waveHeader.bytesPerSecond;
142  track.m_chunkSize = waveHeader.chunkSize;
143  track.m_bitsPerSample = waveHeader.bitsPerSample;
144  track.m_bitrate = waveHeader.bitrate();
145 }
146 
148 {
149  const string context("parsing RIFF/WAVE header");
150  if (!m_istream) {
151  throw NoDataFoundException();
152  }
153  if (m_reader.readUInt32BE() != 0x52494646u) {
154  throw NoDataFoundException();
155  }
156  m_istream->seekg(static_cast<streamoff>(m_startOffset + 8));
157  if (m_reader.readUInt32BE() != 0x57415645u) {
158  throw NoDataFoundException();
159  }
160  while (!m_dataOffset) {
161  const auto segmentId = m_reader.readUInt32BE();
162  auto restHeaderLen = m_reader.readUInt32LE();
163  switch (segmentId) {
164  case 0x666D7420u: { // format segment
165  WaveFormatHeader waveHeader;
166  const auto bytesRead = waveHeader.parse(m_reader, restHeaderLen, diag);
167  addInfo(waveHeader, *this);
168  restHeaderLen -= bytesRead;
169  } break;
170  case 0x64617461u: // data segment
171  m_dataOffset = static_cast<std::uint64_t>(m_istream->tellg());
172  m_size = restHeaderLen;
174  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_samplingFrequency));
175  break;
176  default:;
177  }
178  m_istream->seekg(restHeaderLen, ios_base::cur);
179  }
180  if (m_format.general != GeneralMediaFormat::Mpeg1Audio || !m_dataOffset) {
181  return;
182  }
183  m_istream->seekg(static_cast<streamoff>(m_dataOffset));
184  MpegAudioFrame frame;
185  frame.parseHeader(m_reader, diag);
186  MpegAudioFrameStream::addInfo(frame, *this);
187  m_bitrate = frame.isXingFramefieldPresent() ? ((static_cast<double>(m_size) * 8.0)
188  / (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
189  : frame.bitrate();
190  m_bytesPerSecond = static_cast<std::uint32_t>(m_bitrate * 125);
191  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 128.0));
192 }
193 
194 } // namespace TagParser
TagParser::WaveFormatHeader::formatTag
std::uint16_t formatTag
Definition: waveaudiostream.h:18
TagParser::AbstractTrack::m_samplingFrequency
std::uint32_t m_samplingFrequency
Definition: abstracttrack.h:140
TagParser::MpegAudioFrame::samplingFrequency
std::uint32_t samplingFrequency() const
Returns the sampeling frequency of the frame if known; otherwise returns 0.
Definition: mpegaudioframe.cpp:110
TagParser::MpegAudioFrame::parseHeader
void parseHeader(CppUtilities::BinaryReader &reader, Diagnostics &diag)
Parses the header read using the specified reader.
Definition: mpegaudioframe.cpp:47
TagParser::AbstractTrack::m_bitrate
double m_bitrate
Definition: abstracttrack.h:135
TagParser::WaveAudioStream::addInfo
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
Definition: waveaudiostream.cpp:135
TagParser::WaveFormatHeader
The WaveFormatHeader class parses the WAVEFORMATEX structure defined by MS.
Definition: waveaudiostream.h:8
waveaudiostream.h
TagParser::SubFormats::PcmFloatIeee
@ PcmFloatIeee
Definition: mediaformat.h:224
TagParser::SubFormats::Mpeg1Layer3
@ Mpeg1Layer3
Definition: mediaformat.h:112
TagParser::MpegAudioFrame
The MpegAudioFrame class is used to parse MPEG audio frames.
Definition: mpegaudioframe.h:36
TagParser::TrackType::WaveAudioStream
@ WaveAudioStream
TagParser::Diagnostics
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
TagParser::WaveFormatHeader::parse
std::uint64_t parse(CppUtilities::BinaryReader &reader, std::uint64_t maxSize, Diagnostics &diag)
Parses the WAVE "fmt " header segment using the specified reader.
Definition: waveaudiostream.cpp:25
TagParser
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TagParser::AbstractTrack::m_formatId
std::string m_formatId
Definition: abstracttrack.h:126
TagParser::AbstractTrack::m_sampleCount
std::uint64_t m_sampleCount
Definition: abstracttrack.h:148
TagParser::AbstractTrack::m_reader
CppUtilities::BinaryReader m_reader
Definition: abstracttrack.h:121
TagParser::AbstractTrack::m_chunkSize
std::uint16_t m_chunkSize
Definition: abstracttrack.h:147
TagParser::WaveFormatHeader::sampleRate
std::uint32_t sampleRate
Definition: waveaudiostream.h:20
TagParser::Mpeg4ElementaryStreamObjectIds::Mpeg1Audio
@ Mpeg1Audio
Definition: mp4ids.h:467
TagParser::MpegAudioFrame::bitrate
std::uint16_t bitrate() const
Returns the bitrate of the frame if known; otherwise returns 0.
Definition: mpegaudioframe.h:108
TagParser::MpegAudioFrame::sampleCount
std::uint32_t sampleCount() const
Returns the sample count if known; otherwise returns 0.
Definition: mpegaudioframe.cpp:173
TagParser::AbstractTrack::m_duration
CppUtilities::TimeSpan m_duration
Definition: abstracttrack.h:134
TagParser::TrackType
TrackType
Specifies the track type.
Definition: abstracttrack.h:27
TagParser::Mpeg4ChannelConfigs::channelCount
TAG_PARSER_EXPORT std::uint8_t channelCount(std::uint8_t config)
Returns the channel count for the specified MPEG-4 channel config.
Definition: mp4ids.cpp:460
TagParser::WaveAudioStream::internalParseHeader
void internalParseHeader(Diagnostics &diag) override
This method is internally called to parse header information.
Definition: waveaudiostream.cpp:147
TagParser::AbstractTrack::m_size
std::uint64_t m_size
Definition: abstracttrack.h:130
TagParser::MpegAudioFrameStream::addInfo
static void addInfo(const MpegAudioFrame &frame, AbstractTrack &track)
Adds the information from the specified frame to the specified track.
Definition: mpegaudioframestream.cpp:21
TagParser::WaveFormatHeader::bitsPerSample
std::uint16_t bitsPerSample
Definition: waveaudiostream.h:23
CppUtilities
Definition: abstractcontainer.h:15
TagParser::AbstractTrack
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
Definition: abstracttrack.h:39
TagParser::AbstractTrack::m_channelCount
std::uint16_t m_channelCount
Definition: abstracttrack.h:144
TagParser::WaveFormatHeader::channelCount
std::uint16_t channelCount
Definition: waveaudiostream.h:19
TagParser::AbstractTrack::m_mediaType
MediaType m_mediaType
Definition: abstracttrack.h:128
TagParser::SubFormats::Mpeg1Layer2
@ Mpeg1Layer2
Definition: mediaformat.h:112
TagParser::WaveFormatHeader::chunkSize
std::uint16_t chunkSize
Definition: waveaudiostream.h:22
TagParser::MediaFormat::general
GeneralMediaFormat general
Definition: mediaformat.h:258
TagParser::MpegAudioFrame::xingFrameCount
constexpr std::uint32_t xingFrameCount() const
Returns an indication whether the Xing frame count is present.
Definition: mpegaudioframe.h:206
TagParser::AbstractTrack::m_bytesPerSecond
std::uint32_t m_bytesPerSecond
Definition: abstracttrack.h:143
TagParser::MpegAudioFrame::isXingFramefieldPresent
constexpr bool isXingFramefieldPresent() const
Returns an indication whether the Xing frame field is present.
Definition: mpegaudioframe.h:174
TagParser::AbstractTrack::m_bitsPerSample
std::uint16_t m_bitsPerSample
Definition: abstracttrack.h:142
TagParser::NoDataFoundException
The exception that is thrown when the data to be parsed holds no parsable information (e....
Definition: exceptions.h:18
TagParser::AbstractTrack::m_startOffset
std::uint64_t m_startOffset
Definition: abstracttrack.h:123
TagParser::AbstractTrack::m_format
MediaFormat m_format
Definition: abstracttrack.h:125
TagParser::WaveFormatHeader::bitrate
constexpr std::uint32_t bitrate() const
Calculates the bitrate from the header data.
Definition: waveaudiostream.h:46
TagParser::WaveAudioStream::type
TrackType type() const override
Returns the type of the track if known; otherwise returns TrackType::Unspecified.
Definition: waveaudiostream.cpp:127
TagParser::WaveFormatHeader::bytesPerSecond
std::uint32_t bytesPerSecond
Definition: waveaudiostream.h:21
TagParser::WaveAudioStream::~WaveAudioStream
~WaveAudioStream() override
Destroys the track.
Definition: waveaudiostream.cpp:123
TagParser::SubFormats::PcmIntLe
@ PcmIntLe
Definition: mediaformat.h:224
TagParser::MediaFormat
The MediaFormat class specifies the format of media data.
Definition: mediaformat.h:245
TagParser::AbstractTrack::m_istream
std::istream * m_istream
Definition: abstracttrack.h:119
TagParser::MatroskaTrackType::Audio
@ Audio
Definition: matroskaid.h:403
TagParser::WaveFormatHeader::format
MediaFormat format() const
Returns the media format denoted by the format tag.
Definition: waveaudiostream.cpp:78