Tag Parser 12.1.0
C++ library for reading and writing MP4 (iTunes), ID3, Vorbis, Opus, FLAC and Matroska tags
Loading...
Searching...
No Matches
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
11using namespace std;
12using namespace CppUtilities;
13
14namespace TagParser {
15
25std::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
79{
80 switch (formatTag) {
81 case 0x0001u:
83 case 0x0003u:
85 case 0x0050u:
87 case 0x0055u:
89 default:
90 switch (guid2) {
91 case 0x000800000aa00389b71:
92 switch (guid1) {
93 case 0x0100000000001000ul:
95 case 0x0300000000001000ul:
97 }
98 break;
99 }
101 }
102}
103
113WaveAudioStream::WaveAudioStream(iostream &stream, std::uint64_t startOffset)
114 : AbstractTrack(stream, startOffset)
115 , m_dataOffset(0)
116{
118}
119
126
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...
std::uint32_t m_bytesPerSecond
std::uint16_t m_bitsPerSample
CppUtilities::TimeSpan m_duration
CppUtilities::BinaryReader m_reader
std::uint32_t m_samplingFrequency
The Diagnostics class is a container for DiagMessage.
The MediaFormat class specifies the format of media data.
GeneralMediaFormat general
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.
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 ...