#include "Ap4BitStream.h"
#include "Ap4Eac3Parser.h"
#include "Ap4Utils.h"
AP4_Eac3Header::AP4_Eac3Header(const AP4_UI08* bytes)
{
AP4_BitReader bits(bytes, AP4_EAC3_HEADER_SIZE);
bits.SkipBits(16);
m_Strmtyp = bits.ReadBits(2);
m_Substreamid = bits.ReadBits(3);
m_Frmsiz = bits.ReadBits(11);
m_FrameSize = (m_Frmsiz + 1) * 2;
m_Fscod = bits.ReadBits(2);
unsigned char numblkscod = 0;
unsigned int blks_per_frm = 0;
if (m_Fscod == 0x3){
fprintf(stderr, "ERROR: Half sample rate unsupported\n");
return;
}else{
numblkscod = bits.ReadBits(2);
if (numblkscod == 0x3){
blks_per_frm = 6;
}else {
blks_per_frm = numblkscod + 1;
}
}
m_Acmod = bits.ReadBits(3);
m_Lfeon = bits.ReadBits(1);
m_ChannelCount = GLOBAL_CHANNEL_ARY[m_Acmod] + m_Lfeon;
m_Bsid = bits.ReadBits(5);
if (!((m_Bsid > 10) && (m_Bsid <=16))){
fprintf(stderr, "ERROR: Unsupported bitstream id\n");
return;
}
bits.ReadBits(5); if (bits.ReadBit()) { bits.ReadBits(8);
}
if (m_Acmod == 0x0){ bits.SkipBits(5); if (bits.ReadBit()) { bits.SkipBits(8); }
}
if (m_Strmtyp == 0x1) { m_Chanmape = bits.ReadBit();
if (m_Chanmape) {
m_Chanmap = bits.ReadBits(16);
}else {
m_Chanmap = 0;
}
}else {
m_Chanmape = 0;
m_Chanmap = 0;
}
if (bits.ReadBit()){ if (m_Acmod > 0x2) {
bits.ReadBits(2);
}
if ((m_Acmod & 0x1) && (m_Acmod > 0x2)) {
bits.ReadBits(3);
bits.ReadBits(3);
}
if (m_Acmod & 0x4) {
bits.ReadBits(3);
bits.ReadBits(3);
}
if (m_Lfeon) {
if (bits.ReadBit()) { bits.ReadBits(5);
}
}
if (m_Strmtyp == 0x0) { if (bits.ReadBit()) { bits.ReadBits(6);
}
if (m_Acmod == 0x0){ if(bits.ReadBit()) { bits.SkipBits(6); }
}
if(bits.ReadBit()) { bits.ReadBits(6);
}
char mixdef = bits.ReadBits(2);
if(mixdef == 0x1) { bits.SkipBits(5) ;} else if (mixdef == 0x2) { bits.SkipBits(12);} else if (mixdef == 0x3) {
char mixdeflen = bits.ReadBits(5);
unsigned int mixdefbits = 1; if(bits.ReadBit()){ bits.SkipBits(5); mixdefbits += 5;
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1; if(bits.ReadBit()) {
bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1;
if(bits.ReadBit()){ mixdefbits += 1;
if(bits.ReadBit()) { bits.SkipBits(4); mixdefbits += 4;
}
mixdefbits += 1;
if(bits.ReadBit()) { bits.SkipBits(4); mixdefbits += 4;
}
}
}
mixdefbits += 1;
if(bits.ReadBit()){ bits.SkipBits(5); mixdefbits += 5;
mixdefbits += 1;
if(bits.ReadBit()){ bits.SkipBits(7); mixdefbits += 7;
mixdefbits += 1;
if(bits.ReadBit()){ bits.SkipBits(8); mixdefbits += 8;
}
}
}
bits.SkipBits(8 * (mixdeflen + 2) - mixdefbits); }
if (m_Acmod < 0x2) { if(bits.ReadBit()){ bits.SkipBits(8 + 6); }
if (m_Acmod == 0x0) { if(bits.ReadBit()){ bits.SkipBits(8 + 6); }
}
}
if (bits.ReadBit()){ if (blks_per_frm == 1) {
bits.SkipBits(5); }else{
for (unsigned int idx = 0; idx < blks_per_frm; idx++){
if(bits.ReadBit()){ bits.SkipBits(5); }
}
}
}
} }
m_Infomdate = bits.ReadBit();
if (m_Infomdate){
m_Bsmod = bits.ReadBits(3);
bits.ReadBits(1);
bits.ReadBits(1);
if (m_Acmod == 0x2) { bits.SkipBits(4); }
if (m_Acmod >= 0x6) { bits.ReadBits(2);
}
if(bits.ReadBit()){ bits.SkipBits(8); }
if (m_Acmod == 0x0) { if(bits.ReadBit()){ bits.SkipBits(8); }
}
if (m_Fscod < 0x3) { bits.SkipBits(1); }
} else { m_Bsmod = 0;
}
m_Convsync = 1;
if ((m_Strmtyp == 0x0) && (numblkscod != 0x3)){
m_Convsync = bits.ReadBits(1);
}
if (m_Strmtyp == 0x2) { unsigned char blkid = 0;
if (numblkscod == 0x3) {
blkid = 1;
}else {
blkid = bits.ReadBits(1);
}
if (blkid) {bits.SkipBits(6); } }
m_Addbsie = bits.ReadBit();
if (m_Addbsie){
m_Addbsil = bits.ReadBits(6);
for (unsigned int idx = 0 ; idx < (m_Addbsil + 1); idx ++){
m_Addbsi[idx] = bits.ReadBits(8);
}
} else {
m_Addbsil = 0;
AP4_SetMemory(m_Addbsi, 0, sizeof (m_Addbsi));
}
m_HeadSize = (bits.GetBitsRead() / 8) + ((bits.GetBitsRead() % 8 == 0) ? 0: 1);
}
bool
AP4_Eac3Header::MatchFixed(AP4_Eac3Header& frame, AP4_Eac3Header& next_frame)
{
if (frame.m_Acmod == next_frame.m_Acmod &&
frame.m_Bsid == next_frame.m_Bsid &&
frame.m_Bsmod == next_frame.m_Bsmod &&
frame.m_Lfeon == next_frame.m_Lfeon &&
frame.m_Fscod == next_frame.m_Fscod ) {
return true;
} else {
return false;
}
}
AP4_Result
AP4_Eac3Header::Check()
{
if (m_Fscod == 1 || m_Fscod == 2) {
fprintf(stderr, "WARN: The sample rate is NOT 48 kHz\n");
} else if (m_Fscod == 3) {
return AP4_FAILURE;
}
if (m_Bsid < 10 || m_Bsid > 16) {
return AP4_FAILURE;
}
if (m_Substreamid != 0) {
fprintf(stderr, "ERROR: Only single independent substream (I0) or single depenpent substream (D0) is allowed in a DD+ stream\n");
return AP4_FAILURE;
}
return AP4_SUCCESS;
}
AP4_Eac3Parser::AP4_Eac3Parser() :
m_FrameCount(0)
{
}
AP4_Eac3Parser::~AP4_Eac3Parser()
{
}
AP4_Result
AP4_Eac3Parser::Reset()
{
m_FrameCount = 0;
return AP4_SUCCESS;
}
AP4_Result
AP4_Eac3Parser::Feed(const AP4_UI08* buffer,
AP4_Size* buffer_size,
AP4_Flags flags)
{
AP4_Size free_space;
m_Bits.m_Flags = flags;
if (buffer == NULL ||
buffer_size == NULL ||
*buffer_size == 0) {
return AP4_SUCCESS;
}
free_space = m_Bits.GetBytesFree();
if (*buffer_size > free_space) *buffer_size = free_space;
if (*buffer_size == 0) return AP4_SUCCESS;
return m_Bits.WriteBytes(buffer, *buffer_size);
}
AP4_Result
AP4_Eac3Parser::FindHeader(AP4_UI08* header, AP4_Size& skip_size)
{
AP4_Size available = m_Bits.GetBytesAvailable();
while (available-- >= AP4_EAC3_HEADER_SIZE) {
m_Bits.PeekBytes(header, 2);
if( (((header[0] << 8) | header[1]) == AP4_EAC3_SYNC_WORD_BIG_ENDIAN) ||
(((header[0] << 8) | header[1]) == AP4_EAC3_SYNC_WORD_LITTLE_ENDIAN) ){
if (((header[0] << 8) | header[1]) == AP4_EAC3_SYNC_WORD_LITTLE_ENDIAN) {
m_LittleEndian = true;
} else {
m_LittleEndian = false;
}
m_Bits.PeekBytes(header, AP4_EAC3_HEADER_SIZE);
return AP4_SUCCESS;
} else {
m_Bits.SkipBytes(1); skip_size++;
}
}
return AP4_ERROR_NOT_ENOUGH_DATA;
}
AP4_Result
AP4_Eac3Parser::FindFrame(AP4_Eac3Frame& frame)
{
bool dependent_stream_exist = false;
unsigned int dependent_stream_chan_loc = 0;
unsigned int dependent_stream_length = 0;
unsigned int skip_size = 0;
unsigned int available;
unsigned char raw_header[AP4_EAC3_HEADER_SIZE];
AP4_Result result;
m_Bits.ByteAlign();
result = FindHeader(raw_header, skip_size);
if (AP4_FAILED(result)) return result;
if (m_LittleEndian) {
AP4_ByteSwap16(raw_header, AP4_EAC3_HEADER_SIZE);
}
AP4_Eac3Header eac3_header(raw_header);
result = eac3_header.Check();
if (AP4_FAILED(result)) {
goto fail;
}
available = m_Bits.GetBytesAvailable();
if (available >= eac3_header.m_FrameSize + AP4_EAC3_HEADER_SIZE) {
unsigned char peek_raw_header[AP4_EAC3_HEADER_SIZE];
m_Bits.SkipBytes(eac3_header.m_FrameSize);
skip_size = 0;
result = FindHeader(peek_raw_header, skip_size);
if (AP4_FAILED(result)) return result;
m_Bits.SkipBytes(-((int)(eac3_header.m_FrameSize + skip_size)));
if (m_LittleEndian) {
AP4_ByteSwap16(peek_raw_header, AP4_EAC3_HEADER_SIZE);
}
AP4_Eac3Header peek_eac3_header(peek_raw_header);
result = peek_eac3_header.Check();
if (AP4_FAILED(result)) {
goto fail;
}
if (peek_eac3_header.m_Strmtyp == 1) {
dependent_stream_exist = true;
if (peek_eac3_header.m_Chanmape == 0){
goto fail;
}else {
if (peek_eac3_header.m_Chanmap & 0x200) {
dependent_stream_chan_loc |= 0x2;
dependent_stream_length = peek_eac3_header.m_FrameSize;
eac3_header.m_ChannelCount += 2;
} else {
fprintf(stderr, "ERROR: Only support 7.1-channel (I0 + D0). For other D0, the tool doesn't support yet.\n");
goto fail;
}
}
}
else if (!AP4_Eac3Header::MatchFixed(eac3_header, peek_eac3_header)) {
goto fail;
}
} else if (available < eac3_header.m_FrameSize || (m_Bits.m_Flags & AP4_BITSTREAM_FLAG_EOS) == 0) {
return AP4_ERROR_NOT_ENOUGH_DATA;
}
frame.m_Info.m_ChannelCount = eac3_header.m_ChannelCount;
if (dependent_stream_exist) {
frame.m_Info.m_FrameSize = eac3_header.m_FrameSize + dependent_stream_length;
}else {
frame.m_Info.m_FrameSize = eac3_header.m_FrameSize;
}
frame.m_Info.m_SampleRate = EAC3_SAMPLE_RATE_ARY[eac3_header.m_Fscod];
frame.m_Info.m_Eac3SubStream.fscod = eac3_header.m_Fscod;
frame.m_Info.m_Eac3SubStream.bsid = eac3_header.m_Bsid;
frame.m_Info.m_Eac3SubStream.bsmod = eac3_header.m_Bsmod;
frame.m_Info.m_Eac3SubStream.acmod = eac3_header.m_Acmod;
frame.m_Info.m_Eac3SubStream.lfeon = eac3_header.m_Lfeon;
if (dependent_stream_exist) {
frame.m_Info.m_Eac3SubStream.num_dep_sub = 1;
frame.m_Info.m_Eac3SubStream.chan_loc = dependent_stream_chan_loc;
}else {
frame.m_Info.m_Eac3SubStream.num_dep_sub = 0;
frame.m_Info.m_Eac3SubStream.chan_loc = 0;
}
frame.m_Info.complexity_index_type_a = 0;
if (eac3_header.m_Addbsie && (eac3_header.m_Addbsil == 1) && (eac3_header.m_Addbsi[0] == 0x1)){
frame.m_Info.complexity_index_type_a = eac3_header.m_Addbsi[1];
}
frame.m_LittleEndian = m_LittleEndian;
frame.m_Source = &m_Bits;
return AP4_SUCCESS;
fail:
return AP4_ERROR_CORRUPTED_BITSTREAM;
}
AP4_Size
AP4_Eac3Parser::GetBytesFree()
{
return (m_Bits.GetBytesFree());
}
AP4_Size
AP4_Eac3Parser::GetBytesAvailable()
{
return (m_Bits.GetBytesAvailable());
}