Tag Parser  8.2.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 ChronoUtilities;
13 
14 namespace TagParser {
15 
25 void WaveFormatHeader::parse(IoUtilities::BinaryReader &reader)
26 {
27  Diagnostics diag;
28  parseExt(reader, 16, diag);
29 }
30 
39 pair<MediaFormat, uint64> WaveFormatHeader::parseExt(IoUtilities::BinaryReader &reader, uint64 maxSize, Diagnostics &diag)
40 {
41  auto result = make_pair<MediaFormat, uint64>(GeneralMediaFormat::Unknown, 0);
42  if (maxSize < 16) {
43  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated.", "parsing WAVE format header");
44  return result;
45  }
46 
47  formatTag = reader.readUInt16LE();
48  result.first = format();
49  channelCount = reader.readUInt16LE();
50  sampleRate = reader.readUInt32LE();
51  bytesPerSecond = reader.readUInt32LE();
52  chunkSize = reader.readUInt16LE();
53  bitsPerSample = reader.readUInt16LE();
54  result.second = 16;
55 
56  // read extended header unless format is PCM
57  if (result.first.general == GeneralMediaFormat::Pcm) {
58  return result;
59  }
60  if ((maxSize -= 16) < 2) {
61  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated (extended header missing).", "parsing WAVE format header");
62  return result;
63  }
64  const auto extensionSize = reader.readUInt16LE();
65  result.second += 2;
66  if ((maxSize -= 2) < 2) {
67  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated (extended header truncated).", "parsing WAVE format header");
68  return result;
69  }
70 
71  // skip extended header unless format is "WAVE_FORMAT_EXTENSIBLE"
72  if (formatTag != 65534) {
73  reader.stream()->seekg(extensionSize, ios_base::cur);
74  result.second += extensionSize;
75  return result;
76  }
77 
78  // read extended header for "WAVE_FORMAT_EXTENSIBLE"
79  if (extensionSize != 22) {
80  diag.emplace_back(DiagLevel::Warning, "\"fmt \" extended header has unexptected size.", "parsing WAVE format header");
81  return result;
82  }
83  bitsPerSample = reader.readUInt16LE();
84  reader.stream()->seekg(4, ios_base::cur); // skip channel mask
85  const auto guid1 = reader.readUInt64BE();
86  const auto guid2 = reader.readUInt64BE();
87  result.second += 22;
88  switch (guid2) {
89  case 0x000800000aa00389b71:
90  switch (guid1) {
91  case 0x0100000000001000ul:
92  result.first = MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
93  break;
94  case 0x0300000000001000ul:
95  result.first = MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
96  break;
97  }
98  break;
99  }
100  return result;
101 }
102 
106 MediaFormat WaveFormatHeader::format() const
107 {
108  switch (formatTag) {
109  case 0x0001u:
110  return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmIntLe);
111  case 0x0003u:
112  return MediaFormat(GeneralMediaFormat::Pcm, SubFormats::PcmFloatIeee);
113  case 0x0050u:
115  case 0x0055u:
117  default:
118  return GeneralMediaFormat::Unknown;
119  }
120 }
121 
131 WaveAudioStream::WaveAudioStream(iostream &stream, uint64 startOffset)
132  : AbstractTrack(stream, startOffset)
133  , m_dataOffset(0)
134 {
136 }
137 
142 {
143 }
144 
146 {
148 }
149 
154 {
155  track.m_formatId = ConversionUtilities::numberToString(waveHeader.formatTag);
156  track.m_channelCount = waveHeader.channelCount;
157  track.m_samplingFrequency = waveHeader.sampleRate;
158  track.m_bytesPerSecond = waveHeader.bytesPerSecond;
159  track.m_chunkSize = waveHeader.chunkSize;
160  track.m_bitsPerSample = waveHeader.bitsPerSample;
161  track.m_bitrate = waveHeader.bitrate();
162 }
163 
165 {
166  const string context("parsing RIFF/WAVE header");
167  if (!m_istream) {
168  throw NoDataFoundException();
169  }
170  if (m_reader.readUInt32BE() != 0x52494646u) {
171  throw NoDataFoundException();
172  }
173  m_istream->seekg(static_cast<streamoff>(m_startOffset + 8));
174  if (m_reader.readUInt32BE() != 0x57415645u) {
175  throw NoDataFoundException();
176  }
177  while (!m_dataOffset) {
178  const auto segmentId = m_reader.readUInt32BE();
179  auto restHeaderLen = m_reader.readUInt32LE();
180  switch (segmentId) {
181  case 0x666D7420u: { // format segment
182  WaveFormatHeader waveHeader;
183  uint64 bytesRead;
184  tie(m_format, bytesRead) = waveHeader.parseExt(m_reader, restHeaderLen, diag);
185  addInfo(waveHeader, *this);
186  restHeaderLen -= bytesRead;
187  } break;
188  case 0x64617461u: // data segment
189  m_dataOffset = static_cast<uint64>(m_istream->tellg());
190  m_size = restHeaderLen;
192  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_samplingFrequency));
193  break;
194  default:;
195  }
196  m_istream->seekg(restHeaderLen, ios_base::cur);
197  }
198  if (m_format.general != GeneralMediaFormat::Mpeg1Audio || !m_dataOffset) {
199  return;
200  }
201  m_istream->seekg(static_cast<streamoff>(m_dataOffset));
202  MpegAudioFrame frame;
203  frame.parseHeader(m_reader, diag);
204  MpegAudioFrameStream::addInfo(frame, *this);
206  ? ((static_cast<double>(m_size) * 8.0)
207  / (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
208  : frame.bitrate();
209  m_bytesPerSecond = static_cast<uint32>(m_bitrate * 125);
210  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 128.0));
211 }
212 
213 } // namespace TagParser
TAG_PARSER_EXPORT byte channelCount(byte config)
Returns the channel count for the specified MPEG-4 channel config.
Definition: mp4ids.cpp:452
uint32 sampleCount() const
Returns the sample count if known; otherwise returns 0.
IoUtilities::BinaryReader m_reader
~WaveAudioStream() override
Destroys the track.
The MpegAudioFrame class is used to parse MPEG audio frames.
The MediaFormat class specifies the format of media data.
Definition: mediaformat.h:244
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
The WaveFormatHeader class parses the WAVEFORMATEX structure defined by MS.
GeneralMediaFormat general
Definition: mediaformat.h:257
constexpr bool isXingFramefieldPresent() const
Returns an indication whether the Xing frame field is present.
std::pair< MediaFormat, uint64 > parseExt(IoUtilities::BinaryReader &reader, uint64 maxSize, Diagnostics &diag)
Parses the WAVE "fmt " header segment using the specified reader.
ChronoUtilities::TimeSpan m_duration
TrackType type() const override
Returns the type of the track if known; otherwise returns TrackType::Unspecified.
The exception that is thrown when the data to be parsed holds no parsable information (e....
Definition: exceptions.h:18
void parseHeader(IoUtilities::BinaryReader &reader, Diagnostics &diag)
Parses the header read using the specified reader.
uint16 bitrate() const
Returns the bitrate of the frame if known; otherwise returns 0.
std::istream * m_istream
static void addInfo(const MpegAudioFrame &frame, AbstractTrack &track)
Adds the information from the specified frame to the specified track.
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
Definition: abstracttrack.h:40
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:9
constexpr uint32 xingFrameCount() const
Returns an indication whether the Xing frame count is present.
TrackType
Specifies the track type.
Definition: abstracttrack.h:28
constexpr uint32 bitrate() const
Calculates the bitrate from the header data.
uint32 samplingFrequency() const
Returns the sampeling frequency of the frame if known; otherwise returns 0.
void internalParseHeader(Diagnostics &diag) override
This method is internally called to parse header information.
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156