Tag Parser  10.0.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  CPP_UTILITIES_UNUSED(progress)
150 
151  const string context("parsing RIFF/WAVE header");
152  if (!m_istream) {
153  throw NoDataFoundException();
154  }
155  if (m_reader.readUInt32BE() != 0x52494646u) {
156  throw NoDataFoundException();
157  }
158  m_istream->seekg(static_cast<streamoff>(m_startOffset + 8));
159  if (m_reader.readUInt32BE() != 0x57415645u) {
160  throw NoDataFoundException();
161  }
162  while (!m_dataOffset) {
163  const auto segmentId = m_reader.readUInt32BE();
164  auto restHeaderLen = static_cast<std::uint64_t>(m_reader.readUInt32LE());
165  switch (segmentId) {
166  case 0x666D7420u: { // format segment
167  WaveFormatHeader waveHeader;
168  const auto bytesRead = waveHeader.parse(m_reader, restHeaderLen, diag);
169  addInfo(waveHeader, *this);
170  restHeaderLen -= bytesRead;
171  } break;
172  case 0x64617461u: // data segment
173  m_dataOffset = static_cast<std::uint64_t>(m_istream->tellg());
174  m_size = restHeaderLen;
176  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_samplingFrequency));
177  break;
178  default:;
179  }
180  m_istream->seekg(static_cast<std::streamoff>(restHeaderLen), ios_base::cur);
181  }
182  if (m_format.general != GeneralMediaFormat::Mpeg1Audio || !m_dataOffset) {
183  return;
184  }
185  m_istream->seekg(static_cast<streamoff>(m_dataOffset));
186  MpegAudioFrame frame;
187  frame.parseHeader(m_reader, diag);
188  MpegAudioFrameStream::addInfo(frame, *this);
189  m_bitrate = frame.isXingFramefieldPresent() ? ((static_cast<double>(m_size) * 8.0)
190  / (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
191  : frame.bitrate();
192  m_bytesPerSecond = static_cast<std::uint32_t>(m_bitrate * 125);
193  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 128.0));
194 }
195 
196 } // namespace TagParser
The AbortableProgressFeedback class provides feedback about an ongoing operation via callbacks.
The AbstractTrack class parses and stores technical information about video, audio and other kinds of...
Definition: abstracttrack.h:65
std::uint64_t m_sampleCount
std::uint32_t m_bytesPerSecond
std::uint16_t m_bitsPerSample
std::uint16_t m_channelCount
CppUtilities::TimeSpan m_duration
CppUtilities::BinaryReader m_reader
std::uint64_t m_startOffset
std::istream * m_istream
std::uint32_t m_samplingFrequency
The Diagnostics class is a container for DiagMessage.
Definition: diagnostics.h:156
The MediaFormat class specifies the format of media data.
Definition: mediaformat.h:246
GeneralMediaFormat general
Definition: mediaformat.h:259
static void addInfo(const MpegAudioFrame &frame, AbstractTrack &track)
Adds the information from the specified frame to the specified track.
The MpegAudioFrame class is used to parse MPEG audio frames.
std::uint32_t samplingFrequency() const
Returns the sampeling frequency of the frame if known; otherwise returns 0.
std::uint32_t sampleCount() const
Returns the sample count if known; otherwise returns 0.
std::uint16_t bitrate() const
Returns the bitrate of the frame if known; otherwise returns 0.
constexpr std::uint32_t xingFrameCount() const
Returns an indication whether the Xing frame count is present.
void parseHeader(CppUtilities::BinaryReader &reader, Diagnostics &diag)
Parses the header read using the specified reader.
constexpr bool isXingFramefieldPresent() const
Returns an indication whether the Xing frame field is present.
The exception that is thrown when the data to be parsed holds no parsable information (e....
Definition: exceptions.h:18
TrackType type() const override
Returns the type of the track if known; otherwise returns TrackType::Unspecified.
static void addInfo(const WaveFormatHeader &waveHeader, AbstractTrack &track)
Adds the information from the specified waveHeader to the specified track.
~WaveAudioStream() override
Destroys the track.
void internalParseHeader(Diagnostics &diag, AbortableProgressFeedback &progress) override
This method is internally called to parse header information.
The WaveFormatHeader class parses the WAVEFORMATEX structure defined by MS.
MediaFormat format() const
Returns the media format denoted by the format tag.
constexpr std::uint32_t bitrate() const
Calculates the bitrate from the header data.
std::uint64_t parse(CppUtilities::BinaryReader &reader, std::uint64_t maxSize, Diagnostics &diag)
Parses the WAVE "fmt " header segment using the specified reader.
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
Contains all classes and functions of the TagInfo library.
Definition: aaccodebook.h:10
TrackType
The TrackType enum specifies the underlying file type of a track and the concrete class of the track ...
Definition: abstracttrack.h:31