diff --git a/packager/media/base/audio_stream_info.cc b/packager/media/base/audio_stream_info.cc index 39adcad273..a651ff61c2 100644 --- a/packager/media/base/audio_stream_info.cc +++ b/packager/media/base/audio_stream_info.cc @@ -33,6 +33,8 @@ std::string AudioCodecToString(AudioCodec audio_codec) { return "DTS-"; case kCodecDTSP: return "DTS+"; + case kCodecEAC3: + return "EAC3"; case kCodecOpus: return "Opus"; case kCodecVorbis: @@ -115,6 +117,8 @@ std::string AudioStreamInfo::GetCodecString(AudioCodec codec, return "dts-"; case kCodecAC3: return "ac-3"; + case kCodecEAC3: + return "ec-3"; default: NOTIMPLEMENTED() << "Codec: " << codec; return "unknown"; diff --git a/packager/media/base/audio_stream_info.h b/packager/media/base/audio_stream_info.h index dd11c7d342..6fb9e01b0a 100644 --- a/packager/media/base/audio_stream_info.h +++ b/packager/media/base/audio_stream_info.h @@ -24,6 +24,7 @@ enum AudioCodec { kCodecDTSL, kCodecDTSM, kCodecDTSP, + kCodecEAC3, kCodecOpus, kCodecVorbis, diff --git a/packager/media/formats/mp4/box_definitions.cc b/packager/media/formats/mp4/box_definitions.cc index 062117ffd6..e9304b03f2 100644 --- a/packager/media/formats/mp4/box_definitions.cc +++ b/packager/media/formats/mp4/box_definitions.cc @@ -8,6 +8,7 @@ #include "packager/base/logging.h" #include "packager/media/base/bit_reader.h" +#include "packager/media/base/macros.h" #include "packager/media/formats/mp4/box_buffer.h" #include "packager/media/formats/mp4/rcheck.h" @@ -1435,6 +1436,54 @@ uint32_t AC3Specific::ComputeSizeInternal() { return HeaderSize() + data.size(); } +EC3Specific::EC3Specific() : number_independent_substreams(0) {} +EC3Specific::~EC3Specific() {} + +FourCC EC3Specific::BoxType() const { return FOURCC_DEC3; } + +bool EC3Specific::ReadWriteInternal(BoxBuffer* buffer) { + RCHECK(ReadWriteHeaderInternal(buffer)); + uint32_t size = buffer->Reading() ? buffer->BytesLeft() : data.size(); + RCHECK(buffer->ReadWriteVector(&data, size)); + + // Skip data rate, read number of independent substreams and parse the + // independent substreams. + BitReader bit_reader(&data[0], size); + RCHECK(bit_reader.SkipBits(13) && + bit_reader.ReadBits(3, &number_independent_substreams)); + + // The value of this field is one less than the number of independent + // substreams present. + ++number_independent_substreams; + IndependentSubstream substream; + for (size_t i = 0; i < number_independent_substreams; ++i) { + RCHECK(bit_reader.ReadBits(2, &substream.sample_rate_code)); + RCHECK(bit_reader.ReadBits(5, &substream.bit_stream_identification)); + RCHECK(bit_reader.SkipBits(1)); + RCHECK(bit_reader.ReadBits(1, &substream.audio_service)); + RCHECK(bit_reader.ReadBits(3, &substream.bit_stream_mode)); + RCHECK(bit_reader.ReadBits(3, &substream.audio_coding_mode)); + RCHECK(bit_reader.ReadBits(1, &substream.lfe_channel_on)); + RCHECK(bit_reader.SkipBits(3)); + RCHECK(bit_reader.ReadBits(4, &substream.number_dependent_substreams)); + if (substream.number_dependent_substreams > 0) { + RCHECK(bit_reader.ReadBits(9, &substream.channel_location)); + } else { + RCHECK(bit_reader.SkipBits(1)); + } + independent_substreams.push_back(substream); + } + + return true; +} + +uint32_t EC3Specific::ComputeSizeInternal() { + // This box is optional. Skip it if not initialized. + if (data.empty()) + return 0; + return HeaderSize() + data.size(); +} + AudioSampleEntry::AudioSampleEntry() : format(FOURCC_NULL), data_reference_index(1), @@ -1489,6 +1538,7 @@ bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) { RCHECK(buffer->TryReadWriteChild(&esds)); RCHECK(buffer->TryReadWriteChild(&ddts)); RCHECK(buffer->TryReadWriteChild(&dac3)); + RCHECK(buffer->TryReadWriteChild(&dec3)); return true; } @@ -1496,6 +1546,7 @@ uint32_t AudioSampleEntry::ComputeSizeInternal() { return HeaderSize() + sizeof(data_reference_index) + sizeof(channelcount) + sizeof(samplesize) + sizeof(samplerate) + sinf.ComputeSize() + esds.ComputeSize() + ddts.ComputeSize() + dac3.ComputeSize() + + dec3.ComputeSize() + 6 + 8 + // 6 + 8 bytes reserved. 4; // 4 bytes predefined. } diff --git a/packager/media/formats/mp4/box_definitions.h b/packager/media/formats/mp4/box_definitions.h index 12ff1f5a7d..026ea162a8 100644 --- a/packager/media/formats/mp4/box_definitions.h +++ b/packager/media/formats/mp4/box_definitions.h @@ -315,6 +315,34 @@ struct AC3Specific : Box { std::vector data; }; +// Independent substream in EC3Specific box. +struct IndependentSubstream { + uint8_t sample_rate_code; // fscod: 2 bits + uint8_t bit_stream_identification; // bsid: 5 bits + // reserved_1: 1 bit + uint8_t audio_service; // asvc: 1 bit + uint8_t bit_stream_mode; // bsmod: 3 bits + uint8_t audio_coding_mode; // acmod: 3 bits + uint8_t lfe_channel_on; // lfeon: 1 bit + // reserved_2: 3 bit + uint8_t number_dependent_substreams; // num_dep_sub: 4 bits. + // If num_dep_sub > 0, chan_loc is present and the size is 9 bits. + // Otherwise, reserved_3 is present and the size is 1 bit. + uint16_t channel_location; // chan_loc: 9 bits. + // reserved_3: 1 bit +}; + +struct EC3Specific : Box { + DECLARE_BOX_METHODS(EC3Specific); + + // Before we know the number of independent substreams, data in EC3Specific + // box is store for parsing later. + std::vector data; + + size_t number_independent_substreams; // num_id_sub: 3 bits. + std::vector independent_substreams; +}; + struct AudioSampleEntry : Box { DECLARE_BOX_METHODS(AudioSampleEntry); // Returns actual format of this sample entry. @@ -329,9 +357,11 @@ struct AudioSampleEntry : Box { uint32_t samplerate; ProtectionSchemeInfo sinf; + ElementaryStreamDescriptor esds; DTSSpecific ddts; AC3Specific dac3; + EC3Specific dec3; }; struct WebVTTConfigurationBox : Box { diff --git a/packager/media/formats/mp4/box_definitions_comparison.h b/packager/media/formats/mp4/box_definitions_comparison.h index 896ad2b9e4..6f98ce4b5d 100644 --- a/packager/media/formats/mp4/box_definitions_comparison.h +++ b/packager/media/formats/mp4/box_definitions_comparison.h @@ -245,6 +245,11 @@ inline bool operator==(const AC3Specific& lhs, return lhs.data == rhs.data; } +inline bool operator==(const EC3Specific& lhs, + const EC3Specific& rhs) { + return lhs.data == rhs.data; +} + inline bool operator==(const AudioSampleEntry& lhs, const AudioSampleEntry& rhs) { return lhs.format == rhs.format && @@ -252,7 +257,7 @@ inline bool operator==(const AudioSampleEntry& lhs, lhs.channelcount == rhs.channelcount && lhs.samplesize == rhs.samplesize && lhs.samplerate == rhs.samplerate && lhs.sinf == rhs.sinf && lhs.esds == rhs.esds && lhs.ddts == rhs.ddts && - lhs.dac3 == rhs.dac3; + lhs.dac3 == rhs.dac3 && lhs.dec3 == rhs.dec3; } inline bool operator==(const WebVTTConfigurationBox& lhs, diff --git a/packager/media/formats/mp4/box_definitions_unittest.cc b/packager/media/formats/mp4/box_definitions_unittest.cc index 7d83ba4e3c..fb9bf615e7 100644 --- a/packager/media/formats/mp4/box_definitions_unittest.cc +++ b/packager/media/formats/mp4/box_definitions_unittest.cc @@ -390,6 +390,16 @@ class BoxDefinitionsTestGeneral : public testing::Test { dac3->data.assign(kAc3Data, kAc3Data + arraysize(kAc3Data)); } + void Fill(EC3Specific* dec3) { + const uint8_t kEc3Data[] = {0x08, 0x00, 0x20, 0x0f, 0x00}; + dec3->data.assign(kEc3Data, kEc3Data + arraysize(kEc3Data)); + } + + void Modify(EC3Specific* dec3) { + const uint8_t kEc3Data[] = {0x07, 0x00, 0x60, 0x04, 0x00}; + dec3->data.assign(kEc3Data, kEc3Data + arraysize(kEc3Data)); + } + void Fill(AudioSampleEntry* enca) { enca->format = FOURCC_ENCA; enca->data_reference_index = 2; @@ -895,6 +905,7 @@ class BoxDefinitionsTestGeneral : public testing::Test { bool IsOptional(const PixelAspectRatio* box) { return true; } bool IsOptional(const ElementaryStreamDescriptor* box) { return true; } bool IsOptional(const AC3Specific* box) { return true; } + bool IsOptional(const EC3Specific* box) { return true; } // Recommended, but optional. bool IsOptional(const WebVTTSourceLabelBox* box) { return true; } bool IsOptional(const CompositionTimeToSample* box) { return true; } @@ -938,6 +949,7 @@ typedef testing::Typesbuffer_.get()); - AudioSampleEntry entry_readback; ASSERT_TRUE(ReadBack(&entry_readback)); ASSERT_EQ(entry, entry_readback); @@ -1099,6 +1110,21 @@ TEST_F(BoxDefinitionsTest, AC3SampleEntry) { ASSERT_EQ(entry, entry_readback); } +TEST_F(BoxDefinitionsTest, EC3SampleEntry) { + AudioSampleEntry entry; + entry.format = FOURCC_EAC3; + entry.data_reference_index = 2; + entry.channelcount = 5; + entry.samplesize = 16; + entry.samplerate = 44100; + Fill(&entry.dec3); + entry.Write(this->buffer_.get()); + + AudioSampleEntry entry_readback; + ASSERT_TRUE(ReadBack(&entry_readback)); + ASSERT_EQ(entry, entry_readback); +} + TEST_F(BoxDefinitionsTest, ProtectionSystemSpecificHeader) { ProtectionSystemSpecificHeader pssh; Fill(&pssh); diff --git a/packager/media/formats/mp4/fourccs.h b/packager/media/formats/mp4/fourccs.h index 19bfaf2532..8c92b8f59b 100644 --- a/packager/media/formats/mp4/fourccs.h +++ b/packager/media/formats/mp4/fourccs.h @@ -26,6 +26,7 @@ enum FourCC { FOURCC_DAC3 = 0x64616333, FOURCC_DASH = 0x64617368, FOURCC_DDTS = 0x64647473, + FOURCC_DEC3 = 0x64656333, FOURCC_DINF = 0x64696e66, FOURCC_DREF = 0x64726566, FOURCC_DTSC = 0x64747363, @@ -34,6 +35,7 @@ enum FourCC { FOURCC_DTSL = 0x6474736c, FOURCC_DTSM = 0x6474732d, FOURCC_DTSP = 0x6474732b, + FOURCC_EAC3 = 0x65632d33, // This fourcc is "ec-3". FOURCC_EDTS = 0x65647473, FOURCC_ELST = 0x656c7374, FOURCC_ENCA = 0x656e6361, diff --git a/packager/media/formats/mp4/mp4_media_parser.cc b/packager/media/formats/mp4/mp4_media_parser.cc index 19e508c3f7..38c5022dce 100644 --- a/packager/media/formats/mp4/mp4_media_parser.cc +++ b/packager/media/formats/mp4/mp4_media_parser.cc @@ -76,6 +76,8 @@ AudioCodec FourCCToAudioCodec(FourCC fourcc) { return kCodecDTSM; case FOURCC_AC3: return kCodecAC3; + case FOURCC_EAC3: + return kCodecEAC3; default: return kUnknownAudioCodec; } @@ -415,6 +417,11 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { num_channels = entry.channelcount; sampling_frequency = entry.samplerate; break; + case FOURCC_EAC3: + extra_data = entry.dec3.data; + num_channels = entry.channelcount; + sampling_frequency = entry.samplerate; + break; default: LOG(ERROR) << "Unsupported audio format 0x" << std::hex << actual_format << " in stsd box."; diff --git a/packager/media/formats/mp4/mp4_muxer.cc b/packager/media/formats/mp4/mp4_muxer.cc index e07ddd03b0..a6a6fcb976 100644 --- a/packager/media/formats/mp4/mp4_muxer.cc +++ b/packager/media/formats/mp4/mp4_muxer.cc @@ -75,6 +75,8 @@ FourCC AudioCodecToFourCC(AudioCodec codec) { return FOURCC_DTSE; case kCodecDTSM: return FOURCC_DTSM; + case kCodecEAC3: + return FOURCC_EAC3; default: return FOURCC_NULL; } @@ -266,6 +268,9 @@ void MP4Muxer::GenerateAudioTrak(const AudioStreamInfo* audio_info, case kCodecAC3: audio.dac3.data = audio_info->extra_data(); break; + case kCodecEAC3: + audio.dec3.data = audio_info->extra_data(); + break; default: NOTIMPLEMENTED(); break;