Improve reading MPEG audio info
* Skip empty frames * Improve error messages
This commit is contained in:
parent
32e3cd9593
commit
9569065fb4
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include "../exceptions.h"
|
||||
|
||||
#include <c++utilities/conversion/stringbuilder.h>
|
||||
#include <c++utilities/conversion/stringconversion.h>
|
||||
#include <c++utilities/io/binaryreader.h>
|
||||
|
||||
using namespace std;
|
||||
|
@ -46,15 +48,23 @@ const std::uint16_t MpegAudioFrame::s_bitrateTable[0x2][0x3][0xF] = { { { 0, 32,
|
|||
*/
|
||||
void MpegAudioFrame::parseHeader(BinaryReader &reader, Diagnostics &diag)
|
||||
{
|
||||
// read MPEG audio frame header
|
||||
m_header = reader.readUInt32BE();
|
||||
if (!isValid()) {
|
||||
diag.emplace_back(DiagLevel::Critical, "Header is invalid.", "parsing MPEG audio frame header");
|
||||
diag.emplace_back(DiagLevel::Critical,
|
||||
"Frame 0x" % numberToString(m_header, 16) % " at 0x" % numberToString<std::int64_t>(reader.stream()->tellg() - 4l, 16) + " is invalid.",
|
||||
"parsing MPEG audio frame header");
|
||||
throw InvalidDataException();
|
||||
}
|
||||
|
||||
// read XING header (see https://www.codeproject.com/Articles/8295/MPEG-Audio-Frame-Header#XINGHeader)
|
||||
if (size() < s_xingHeaderOffset - 4 + 8) {
|
||||
return;
|
||||
}
|
||||
reader.stream()->seekg(s_xingHeaderOffset - 4, ios_base::cur);
|
||||
m_xingHeader = reader.readUInt64BE();
|
||||
m_xingHeaderFlags = static_cast<XingHeaderFlags>(m_xingHeader & 0xffffffffuL);
|
||||
if (isXingHeaderAvailable()) {
|
||||
m_xingHeaderFlags = static_cast<XingHeaderFlags>(m_xingHeader & 0xffffffffuL);
|
||||
if (isXingFramefieldPresent()) {
|
||||
m_xingFramefield = reader.readUInt32BE();
|
||||
}
|
||||
|
|
|
@ -41,16 +41,24 @@ void MpegAudioFrameStream::internalParseHeader(Diagnostics &diag)
|
|||
m_size = static_cast<std::uint64_t>(m_istream->tellg()) + 125u - m_startOffset;
|
||||
}
|
||||
m_istream->seekg(static_cast<streamoff>(m_startOffset), ios_base::beg);
|
||||
// parse frame header
|
||||
m_frames.emplace_back();
|
||||
MpegAudioFrame &frame = m_frames.back();
|
||||
frame.parseHeader(m_reader, diag);
|
||||
// parse frames until the first non-empty frame is reached
|
||||
auto isFrameEmpty = false;
|
||||
while (!isFrameEmpty && m_frames.size() < 200) {
|
||||
MpegAudioFrame &frame = m_frames.emplace_back();
|
||||
frame.parseHeader(m_reader, diag);
|
||||
isFrameEmpty = frame.size();
|
||||
if (frame.isProtectedByCrc()) {
|
||||
m_istream->seekg(2, ios_base::cur);
|
||||
}
|
||||
}
|
||||
const MpegAudioFrame &frame = m_frames.back();
|
||||
addInfo(frame, *this);
|
||||
if (frame.isXingBytesfieldPresent()) {
|
||||
std::uint32_t xingSize = frame.xingBytesfield();
|
||||
if (m_size && xingSize != m_size) {
|
||||
diag.emplace_back(DiagLevel::Warning,
|
||||
"Real length of MPEG audio frames is not equal with value provided by Xing header. The Xing header value will be used.", context);
|
||||
"Real length of MPEG audio frames is not in accordance with value provided by Xing header. The Xing header value will be used.",
|
||||
context);
|
||||
m_size = xingSize;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue