Tag Parser  8.0.1
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  formatTag = reader.readUInt16LE();
28  channelCount = reader.readUInt16LE();
29  sampleRate = reader.readUInt32LE();
30  bytesPerSecond = reader.readUInt32LE();
31  chunkSize = reader.readUInt16LE();
32  bitsPerSample = reader.readUInt16LE();
33 }
34 
38 MediaFormat WaveFormatHeader::format() const
39 {
40  switch (formatTag) {
41  case 0x0001u:
42  return GeneralMediaFormat::Pcm;
43  case 0x0050u:
45  case 0x0055u:
47  default:
48  return GeneralMediaFormat::Unknown;
49  }
50 }
51 
61 WaveAudioStream::WaveAudioStream(iostream &stream, uint64 startOffset)
62  : AbstractTrack(stream, startOffset)
63  , m_dataOffset(0)
64 {
66 }
67 
72 {
73 }
74 
76 {
78 }
79 
84 {
85  track.m_format = waveHeader.format();
86  track.m_formatId = ConversionUtilities::numberToString(waveHeader.formatTag);
87  track.m_channelCount = waveHeader.channelCount;
88  track.m_samplingFrequency = waveHeader.sampleRate;
89  track.m_bytesPerSecond = waveHeader.bytesPerSecond;
90  track.m_chunkSize = waveHeader.chunkSize;
91  track.m_bitsPerSample = waveHeader.bitsPerSample;
92  track.m_bitrate = waveHeader.bitrate();
93 }
94 
96 {
97  const string context("parsing RIFF/WAVE header");
98  if (!m_istream) {
99  throw NoDataFoundException();
100  }
101  if (m_reader.readUInt32BE() != 0x52494646u) {
102  throw NoDataFoundException();
103  }
104  m_istream->seekg(static_cast<streamoff>(m_startOffset + 8));
105  if (m_reader.readUInt32BE() != 0x57415645u) {
106  throw NoDataFoundException();
107  }
108  while (!m_dataOffset) {
109  uint32 segmentId = m_reader.readUInt32BE();
110  uint32 restHeaderLen = m_reader.readUInt32LE();
111  switch (segmentId) {
112  case 0x666D7420u:
113  if (restHeaderLen >= 16u) {
114  WaveFormatHeader waveHeader;
115  waveHeader.parse(m_reader);
116  addInfo(waveHeader, *this);
117  restHeaderLen -= 16u;
118  } else {
119  diag.emplace_back(DiagLevel::Warning, "\"fmt \" segment is truncated.", context);
120  }
121  break;
122  case 0x64617461u:
123  m_dataOffset = static_cast<uint64>(m_istream->tellg());
124  m_size = restHeaderLen;
126  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_sampleCount) / static_cast<double>(m_samplingFrequency));
127  break;
128  default:;
129  }
130  m_istream->seekg(restHeaderLen, ios_base::cur);
131  }
132  if (m_format.general != GeneralMediaFormat::Mpeg1Audio || !m_dataOffset) {
133  return;
134  }
135  m_istream->seekg(static_cast<streamoff>(m_dataOffset));
136  MpegAudioFrame frame;
137  frame.parseHeader(m_reader, diag);
138  MpegAudioFrameStream::addInfo(frame, *this);
140  ? ((static_cast<double>(m_size) * 8.0)
141  / (static_cast<double>(frame.xingFrameCount() * frame.sampleCount()) / static_cast<double>(frame.samplingFrequency())) / 1024.0)
142  : frame.bitrate();
143  m_bytesPerSecond = static_cast<uint32>(m_bitrate * 125);
144  m_duration = TimeSpan::fromSeconds(static_cast<double>(m_size) / (m_bitrate * 128.0));
145 }
146 
147 } // 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.
STL namespace.
MediaFormat format() const
Returns the media format denoted by the format tag.
GeneralMediaFormat general
Definition: mediaformat.h:257
void parse(IoUtilities::BinaryReader &reader)
Parses the WAVE "fmt " header segment using the specified reader.
constexpr bool isXingFramefieldPresent() const
Returns an indication whether the Xing frame field is present.
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.
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