Skip to content

Commit 8eba386

Browse files
committed
wip
1 parent 5c003c1 commit 8eba386

File tree

6 files changed

+241
-9
lines changed

6 files changed

+241
-9
lines changed

src/Session.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,8 @@ void SESSION::CSession::UpdateStream(CStream& stream)
577577
stream.m_info.SetCodecName(CODEC::NAME_DTS);
578578
else if (CODEC::Contains(codecs, CODEC::FOURCC_AC_3, codecStr))
579579
stream.m_info.SetCodecName(CODEC::NAME_AC3);
580+
else if (CODEC::Contains(codecs, CODEC::FOURCC_AC_4, codecStr))
581+
stream.m_info.SetCodecName(CODEC::NAME_AC4);
580582
else if (CODEC::Contains(codecs, CODEC::FOURCC_EC_3, codecStr))
581583
{
582584
stream.m_info.SetCodecName(CODEC::NAME_EAC3);

src/demuxers/ADTSReader.cpp

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,12 @@ ADTSFrame::ADTSFrameInfo ADTSFrame::GetFrameInfo(AP4_ByteStream* stream)
137137
case AdtsType::AC3:
138138
ParseAc3Header(stream, frameInfo);
139139
break;
140+
case AdtsType::AC4:
141+
ParseAc4Header(stream, frameInfo);
142+
break;
140143
case AdtsType::EAC3:
141144
ParseEc3Header(stream, frameInfo);
142145
break;
143-
case AdtsType::AC4:
144-
break;
145146
default:
146147
break;
147148
}
@@ -157,10 +158,10 @@ bool ADTSFrame::parse(AP4_ByteStream* stream)
157158
return ParseAac(stream);
158159
case AdtsType::AC3:
159160
return ParseAc3(stream);
161+
case AdtsType::AC4:
162+
return ParseAc4(stream);
160163
case AdtsType::EAC3:
161164
return ParseEc3(stream);
162-
case AdtsType::AC4:
163-
return false;
164165
default:
165166
return false;
166167
}
@@ -255,6 +256,50 @@ bool ADTSFrame::ParseAc3Header(AP4_ByteStream* stream, ADTSFrameInfo& frameInfo)
255256
return true;
256257
}
257258

259+
bool ADTSFrame::ParseAc4(AP4_ByteStream* stream)
260+
{
261+
if (!ParseAc4Header(stream, m_frameInfo))
262+
return false;
263+
264+
m_summedFrameCount += m_frameInfo.m_frameCount;
265+
266+
// rewind stream to beginning of syncframe
267+
AP4_Position currentPos;
268+
stream->Tell(currentPos);
269+
stream->Seek(currentPos - (AP4_AC4_HEADER_SIZE));
270+
271+
m_dataBuffer.SetDataSize(m_frameInfo.m_frameSize);
272+
if (!AP4_SUCCEEDED(stream->Read(m_dataBuffer.UseData(), m_dataBuffer.GetDataSize())))
273+
return false;
274+
275+
AdjustStreamForPadding(stream);
276+
return true;
277+
}
278+
279+
bool ADTSFrame::ParseAc4Header(AP4_ByteStream* stream, ADTSFrameInfo& frameInfo)
280+
{
281+
AP4_DataBuffer buffer;
282+
buffer.SetDataSize(AP4_AC3_HEADER_SIZE);
283+
284+
if (!AP4_SUCCEEDED(stream->Read(buffer.UseData(), AP4_AC3_HEADER_SIZE)))
285+
return false;
286+
287+
CAdaptiveAc3Parser parser;
288+
AP4_Size sz = buffer.GetDataSize();
289+
parser.Feed(buffer.GetData(), &sz);
290+
291+
AP4_Ac3Frame frame;
292+
AP4_Result result = parser.FindFrameHeader(frame);
293+
if (!AP4_SUCCEEDED(result))
294+
return false;
295+
296+
frameInfo.m_frameSize = frame.m_Info.m_FrameSize;
297+
frameInfo.m_frameCount = 256u * frame.m_Info.m_ChannelCount;
298+
frameInfo.m_sampleRate = frame.m_Info.m_SampleRate;
299+
frameInfo.m_channels = frame.m_Info.m_ChannelCount;
300+
return true;
301+
}
302+
258303
bool ADTSFrame::ParseEc3(AP4_ByteStream* stream)
259304
{
260305
if (!ParseEc3Header(stream, m_frameInfo))
@@ -379,6 +424,10 @@ bool ADTSReader::GetInformation(kodi::addon::InputstreamInfo& info)
379424
{
380425
codecName = CODEC::NAME_AC3;
381426
}
427+
else if (frameInfo.m_codecType == AdtsType::AC4)
428+
{
429+
codecName = CODEC::NAME_AC4;
430+
}
382431
else if (frameInfo.m_codecType == AdtsType::EAC3)
383432
{
384433
codecName = CODEC::NAME_EAC3;

src/demuxers/ADTSReader.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class ATTR_DLL_LOCAL ADTSFrame
8080
bool ParseAacHeader(AP4_ByteStream* stream, ADTSFrameInfo& frameInfo);
8181
bool ParseAc3(AP4_ByteStream* stream);
8282
bool ParseAc3Header(AP4_ByteStream* stream, ADTSFrameInfo& frameInfo);
83+
bool ParseAc4(AP4_ByteStream* stream);
84+
bool ParseAc4Header(AP4_ByteStream* stream, ADTSFrameInfo& frameInfo);
8385
bool ParseEc3(AP4_ByteStream* stream);
8486
bool ParseEc3Header(AP4_ByteStream* stream, ADTSFrameInfo& frameInfo);
8587
void reset();

src/parser/CodecParser.cpp

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,175 @@ AP4_Result CAdaptiveAc3Parser::FindFrameHeader(AP4_Ac3Frame& frame)
157157
return AP4_SUCCESS;
158158
}
159159

160+
AP4_Result CAdaptiveAc4Parser::FindFrameHeader(AP4_Ac4Frame& frame)
161+
{
162+
unsigned int available;
163+
unsigned char raw_header[AP4_AC4_HEADER_SIZE];
164+
AP4_Result result;
165+
166+
/* align to the start of the next byte */
167+
m_Bits.ByteAlign();
168+
169+
/* find a frame header */
170+
result = FindHeader(raw_header);
171+
if (AP4_FAILED(result))
172+
return result;
173+
174+
// duplicated work, just to get the frame size
175+
AP4_BitReader tmp_bits(raw_header, AP4_AC4_HEADER_SIZE);
176+
unsigned int sync_frame_size = GetSyncFrameSize(tmp_bits);
177+
if (sync_frame_size > (AP4_BITSTREAM_BUFFER_SIZE - 1))
178+
{
179+
return AP4_ERROR_NOT_ENOUGH_DATA;
180+
}
181+
182+
/*
183+
* Error handling to skip the 'fake' sync word.
184+
* - the maximum sync frame size is about (AP4_BITSTREAM_BUFFER_SIZE - 1) bytes.
185+
*/
186+
if (m_Bits.GetBytesAvailable() < sync_frame_size)
187+
{
188+
if (m_Bits.GetBytesAvailable() == (AP4_BITSTREAM_BUFFER_SIZE - 1))
189+
{
190+
// skip the sync word, assume it's 'fake' sync word
191+
m_Bits.SkipBytes(2);
192+
}
193+
return AP4_ERROR_NOT_ENOUGH_DATA;
194+
}
195+
196+
unsigned char* rawframe = new unsigned char[sync_frame_size];
197+
198+
// copy the whole frame becasue toc size is unknown
199+
m_Bits.PeekBytes(rawframe, sync_frame_size);
200+
/* parse the header */
201+
AP4_Ac4Header ac4_header(rawframe, sync_frame_size);
202+
203+
delete[] rawframe;
204+
205+
// Place before goto statement to resolve Xcode compiler issue
206+
unsigned int bit_rate_mode = 0;
207+
208+
/* check the header */
209+
result = ac4_header.Check();
210+
if (AP4_FAILED(result))
211+
{
212+
m_Bits.SkipBytes(sync_frame_size);
213+
goto fail;
214+
}
215+
216+
/* check if we have enough data to peek at the next header */
217+
available = m_Bits.GetBytesAvailable();
218+
// TODO: find the proper AP4_AC4_MAX_TOC_SIZE or just parse what this step need ?
219+
if (available >= ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize +
220+
AP4_AC4_HEADER_SIZE + AP4_AC4_MAX_TOC_SIZE)
221+
{
222+
// enough to peek at the header of the next frame
223+
224+
m_Bits.SkipBytes(ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize);
225+
m_Bits.PeekBytes(raw_header, AP4_AC4_HEADER_SIZE);
226+
227+
// duplicated work, just to get the frame size
228+
AP4_BitReader peak_tmp_bits(raw_header, AP4_AC4_HEADER_SIZE);
229+
unsigned int next_sync_frame_size = GetSyncFrameSize(peak_tmp_bits);
230+
231+
unsigned char* next_rawframe = new unsigned char[next_sync_frame_size];
232+
233+
// copy the whole frame becasue toc size is unknown
234+
if (m_Bits.GetBytesAvailable() < (next_sync_frame_size))
235+
{
236+
next_sync_frame_size = m_Bits.GetBytesAvailable();
237+
}
238+
m_Bits.PeekBytes(next_rawframe, next_sync_frame_size);
239+
240+
m_Bits.SkipBytes(
241+
-((int)(ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize)));
242+
243+
/* check the header */
244+
AP4_Ac4Header peek_ac4_header(next_rawframe, next_sync_frame_size);
245+
246+
delete[] next_rawframe;
247+
248+
result = peek_ac4_header.Check();
249+
if (AP4_FAILED(result))
250+
{
251+
// TODO: need to reserve current sync frame ?
252+
m_Bits.SkipBytes(sync_frame_size + next_sync_frame_size);
253+
goto fail;
254+
}
255+
256+
/* check that the fixed part of this header is the same as the */
257+
/* fixed part of the previous header */
258+
if (!AP4_Ac4Header::MatchFixed(ac4_header, peek_ac4_header))
259+
{
260+
// TODO: need to reserve current sync frame ?
261+
m_Bits.SkipBytes(sync_frame_size + next_sync_frame_size);
262+
goto fail;
263+
}
264+
}
265+
else if (available < (ac4_header.m_FrameSize + ac4_header.m_HeaderSize + ac4_header.m_CrcSize) ||
266+
(m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) == 0)
267+
{
268+
// not enough for a frame, or not at the end (in which case we'll want to peek at the next header)
269+
return AP4_ERROR_NOT_ENOUGH_DATA;
270+
}
271+
272+
m_Bits.SkipBytes(ac4_header.m_HeaderSize);
273+
274+
/* fill in the frame info */
275+
frame.m_Info.m_HeaderSize = ac4_header.m_HeaderSize;
276+
frame.m_Info.m_FrameSize = ac4_header.m_FrameSize;
277+
frame.m_Info.m_CRCSize = ac4_header.m_CrcSize;
278+
frame.m_Info.m_ChannelCount = ac4_header.m_ChannelCount;
279+
frame.m_Info.m_SampleDuration =
280+
(ac4_header.m_FsIndex == 0) ? 2048 : AP4_Ac4SampleDeltaTable[ac4_header.m_FrameRateIndex];
281+
frame.m_Info.m_MediaTimeScale =
282+
(ac4_header.m_FsIndex == 0) ? 44100 : AP4_Ac4MediaTimeScaleTable[ac4_header.m_FrameRateIndex];
283+
frame.m_Info.m_Iframe = ac4_header.m_BIframeGlobal;
284+
285+
/* fill the AC4 DSI info */
286+
frame.m_Info.m_Ac4Dsi.ac4_dsi_version = 1;
287+
frame.m_Info.m_Ac4Dsi.d.v1.bitstream_version = ac4_header.m_BitstreamVersion;
288+
frame.m_Info.m_Ac4Dsi.d.v1.fs_index = ac4_header.m_FsIndex;
289+
frame.m_Info.m_Ac4Dsi.d.v1.fs =
290+
AP4_Ac4SamplingFrequencyTable[frame.m_Info.m_Ac4Dsi.d.v1.fs_index];
291+
frame.m_Info.m_Ac4Dsi.d.v1.frame_rate_index = ac4_header.m_FrameRateIndex;
292+
frame.m_Info.m_Ac4Dsi.d.v1.b_program_id = ac4_header.m_BProgramId;
293+
frame.m_Info.m_Ac4Dsi.d.v1.short_program_id = ac4_header.m_ShortProgramId;
294+
frame.m_Info.m_Ac4Dsi.d.v1.b_uuid = ac4_header.m_BProgramUuidPresent;
295+
AP4_CopyMemory(frame.m_Info.m_Ac4Dsi.d.v1.program_uuid, ac4_header.m_ProgramUuid, 16);
296+
297+
// Calcuate the bit rate mode according to ETSI TS 103 190-2 V1.2.1 Annex B
298+
if (ac4_header.m_WaitFrames == 0)
299+
{
300+
bit_rate_mode = 1;
301+
}
302+
else if (ac4_header.m_WaitFrames >= 1 && ac4_header.m_WaitFrames <= 6)
303+
{
304+
bit_rate_mode = 2;
305+
}
306+
else if (ac4_header.m_WaitFrames > 6)
307+
{
308+
bit_rate_mode = 3;
309+
}
310+
311+
frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate_mode = bit_rate_mode;
312+
frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate = 0; // unknown, fixed value now
313+
frame.m_Info.m_Ac4Dsi.d.v1.ac4_bitrate_dsi.bit_rate_precision =
314+
0xffffffff; // unknown, fixed value now
315+
frame.m_Info.m_Ac4Dsi.d.v1.n_presentations = ac4_header.m_NPresentations;
316+
frame.m_Info.m_Ac4Dsi.d.v1.presentations = ac4_header.m_PresentationV1;
317+
318+
/* set the frame source */
319+
frame.m_Source = &m_Bits;
320+
321+
return AP4_SUCCESS;
322+
323+
fail:
324+
/* skip the header and return (only skip the first byte in */
325+
/* case this was a false header that hides one just after) */
326+
return AP4_ERROR_CORRUPTED_BITSTREAM;
327+
}
328+
160329
AP4_Result CAdaptiveEac3Parser::FindFrameHeader(AP4_Eac3Frame& frame)
161330
{
162331
bool dependent_stream_exist = false;

src/parser/CodecParser.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
#include <bento4/Ap4Ac3Parser.h>
10+
#include <bento4/Ap4Ac4Parser.h>
1011
#include <bento4/Ap4AdtsParser.h>
1112
#include <bento4/Ap4Eac3Parser.h>
1213
#include <kodi/addon-instance/Inputstream.h>
@@ -44,6 +45,13 @@ class ATTR_DLL_LOCAL CAdaptiveAc3Parser : public AP4_Ac3Parser
4445
AP4_Result FindFrameHeader(AP4_Ac3Frame& frame);
4546
};
4647

48+
class ATTR_DLL_LOCAL CAdaptiveAc4Parser : public AP4_Ac4Parser
49+
{
50+
public:
51+
CAdaptiveAc4Parser() {}
52+
AP4_Result FindFrameHeader(AP4_Ac4Frame& frame);
53+
};
54+
4755
class ATTR_DLL_LOCAL CAdaptiveEac3Parser : public AP4_Eac3Parser
4856
{
4957
public:

src/utils/Utils.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,12 @@ constexpr std::array VIDEO_NAME_LIST = {NAME_MPEG1, NAME_MPEG2, NAME_MPEG4, NAME
9393
constexpr const char* NAME_AAC = "aac";
9494
constexpr const char* NAME_DTS = "dca";
9595
constexpr const char* NAME_AC3 = "ac3";
96+
constexpr const char* NAME_AC4 = "ac4";
9697
constexpr const char* NAME_EAC3 = "eac3"; // Enhanced AC-3
9798
constexpr const char* NAME_OPUS = "opus";
9899
constexpr const char* NAME_VORBIS = "vorbis";
99100

100-
constexpr std::array AUDIO_NAME_LIST = {NAME_AAC, NAME_DTS, NAME_AC3,
101+
constexpr std::array AUDIO_NAME_LIST = {NAME_AAC, NAME_DTS, NAME_AC3, NAME_AC4,
101102
NAME_EAC3, NAME_OPUS, NAME_VORBIS};
102103

103104
// Subtitles definitions
@@ -132,6 +133,7 @@ constexpr const char* FOURCC_MP4A = "mp4a";
132133
constexpr const char* FOURCC_AAC_ = "aac"; // Generic prefix for all aac* fourcc, e.g. aac, aacl...
133134
constexpr const char* FOURCC_AACL = "aacl";
134135
constexpr const char* FOURCC_AC_3 = "ac-3";
136+
constexpr const char* FOURCC_AC_4 = "ac-4";
135137
constexpr const char* FOURCC_EC_3 = "ec-3"; // Enhanced AC-3
136138
constexpr const char* FOURCC_OPUS = "opus";
137139
constexpr const char* FOURCC_VORB = "vorb"; // Vorbis
@@ -143,10 +145,10 @@ constexpr const char* FOURCC_VORB3 = "vor3"; // Vorbis 3
143145
constexpr const char* FOURCC_VORB3P = "vo3+"; // Vorbis 3+
144146
constexpr const char* FOURCC_DTS_ = "dts"; // Generic prefix for all dts* fourcc, e.g. dtsx
145147

146-
constexpr std::array AUDIO_FOURCC_LIST = {FOURCC_MP4A, FOURCC_AAC_, FOURCC_AACL,
147-
FOURCC_AC_3, FOURCC_EC_3, FOURCC_OPUS, FOURCC_VORB, FOURCC_VORB1,
148-
FOURCC_VORB1P, FOURCC_VORB2, FOURCC_VORB2P, FOURCC_VORB3,
149-
FOURCC_VORB3P, FOURCC_DTS_};
148+
constexpr std::array AUDIO_FOURCC_LIST = {FOURCC_MP4A, FOURCC_AAC_, FOURCC_AACL, FOURCC_AC_3,
149+
FOURCC_AC_4, FOURCC_EC_3, FOURCC_OPUS, FOURCC_VORB,
150+
FOURCC_VORB1, FOURCC_VORB1P, FOURCC_VORB2, FOURCC_VORB2P,
151+
FOURCC_VORB3, FOURCC_VORB3P, FOURCC_DTS_};
150152

151153
// Fourcc subtitles definitions
152154

0 commit comments

Comments
 (0)