-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMPAFrame.cpp
More file actions
144 lines (117 loc) · 4.45 KB
/
MPAFrame.cpp
File metadata and controls
144 lines (117 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// GNU LESSER GENERAL PUBLIC LICENSE
// Version 3, 29 June 2007
//
// Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
//
// Everyone is permitted to copy and distribute verbatim copies of this license
// document, but changing it is not allowed.
//
// This version of the GNU Lesser General Public License incorporates the terms
// and conditions of version 3 of the GNU General Public License, supplemented
// by the additional permissions listed below.
#include "stdafx.h"
#include "MPAFrame.h"
#include <cmath> // for std::ceil
#include "MPAEndOfFileException.h"
#include "Platform.h"
namespace {
// CRC16 check
static unsigned short CalcCRC16(unsigned char* buffer, unsigned bit_size) {
assert(buffer);
unsigned short tmp_char{0}, crc_mask{0};
unsigned short crc{0xFFFFU}; // start with inverted value of 0
// start with byte 2 of header
for (unsigned n = 16U; n < bit_size; n++) {
// skip the 2 bytes of the crc itself
if (n < 32U || n >= 48U) {
if (n % 8U == 0) {
crc_mask = 1U << 8U;
tmp_char = buffer[n / 8U];
}
crc_mask >>= 1;
unsigned short tmpi = static_cast<unsigned short>(crc & 0x8000U);
crc <<= 1;
if (!tmpi ^ !(tmp_char & crc_mask)) crc ^= 0x8005U;
}
}
crc &= 0xFFFFU; // invert the result
return crc;
}
} // namespace
// number of bits that are used for CRC check in MPEG 1 Layer 2
// (this table is invalid for Joint Stereo/Intensity Stereo)
// 1. index = allocation table index, 2. index = mono
constexpr unsigned CMPAFrame::m_dwProtectedBitsLayer2[5][2] = {
{284, 142}, // table a
{308, 154}, // table b
{42, 84}, // table c
{62, 114}, // table d
{270, 135} // table for MPEG 2/2.5
};
CMPAFrame::CMPAFrame(CMPAStream* stream, unsigned& offset,
bool should_find_next_frame, bool is_exact_offset,
bool should_reverse, CMPAHeader* compare_header)
// decode header of frame at position offset
: m_pHeader{new CMPAHeader{stream, offset, is_exact_offset, should_reverse,
compare_header}},
m_pStream{stream},
m_dwOffset{offset},
m_dwFrameSize{m_pHeader->CalcFrameSize()},
m_bIsLast{false} {
// do extended check?
if (should_find_next_frame) {
// calc offset for next frame header
unsigned new_offset{GetSubsequentHeaderOffset()};
// If no next frame found
// - end of file reached (last frame)
// - corruption in file
// - next frame is at incorrect position (out of detection range)
// - frame was incorrectly detected (very improbable)
try {
const CMPAFrame next_frame{stream, new_offset, false,
true, false, m_pHeader};
} catch (CMPAEndOfFileException&) {
m_bIsLast = true;
}
}
}
CVBRHeader* CMPAFrame::FindVBRHeader() const {
// read out VBR header (if available), must be freed with delete
return CVBRHeader::FindHeader(this);
}
CMPAFrame::~CMPAFrame() { delete m_pHeader; }
// returns true if CRC is correct otherwise false
// do only call this function, if header contains a CRC checksum
bool CMPAFrame::CheckCRC() const {
if (!m_pHeader->m_bCRC) return false;
unsigned protected_bits;
// which bits should be considered for CRC calculation
switch (m_pHeader->m_Layer) {
case CMPAHeader::MPALayer::Layer1:
protected_bits = 4U * (m_pHeader->GetNumChannels() * m_pHeader->m_wBound +
(32U - m_pHeader->m_wBound));
break;
case CMPAHeader::MPALayer::Layer2:
// no check for Layer II files (not easy to compute number protected bits,
// need to get allocation bits first)
return true;
break;
// for Layer III the protected bits are the side information
case CMPAHeader::MPALayer::Layer3:
protected_bits = m_pHeader->GetSideInfoSize() * 8U;
break;
default:
return true;
}
// CRC is also calculated from the last 2 bytes of the header
protected_bits += MPA_HEADER_SIZE * 8U + 16U; // +16bit for CRC itself
const unsigned byte_size{
static_cast<unsigned>(std::ceil(protected_bits / 8.0f))};
// the first 2 bytes and the CRC itself are automatically skipped
unsigned offset{m_dwOffset};
const unsigned short crc16{CalcCRC16(
m_pStream->ReadBytes(byte_size, offset, false), protected_bits)};
// read out crc from frame (it follows frame header)
offset += MPA_HEADER_SIZE;
return crc16 == m_pStream->ReadBEValue(2, offset, false);
}