// Copyright 2016 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd #include "packager/media/base/bit_reader.h" #include "packager/media/base/rcheck.h" #include "packager/media/codecs/ec3_audio_util.h" namespace shaka { namespace media { namespace { // Channels bit map. 16 bits. // Bit, Location // 0(MSB), Left // 1, Center // 2, Right // 3, Left Surround // 4, Right Surround // 5, Left center/Right center pair // 6, Left rear surround/Right rear surround pair // 7, Center surround // 8, Top center surround // 9, Left surround direct/Right surround direct pair // 10, Left wide/Right wide pair // 11, Lvertical height/Right vertical height pair // 12, Center vertical height // 13, Lts/Rts pair // 14, LFE2 // 15, LFE enum kEC3AudioChannelMap { kLeft = 0x8000, kCenter = 0x4000, kRight = 0x2000, kLeftSurround = 0x1000, kRightSurround = 0x800, kLcRcPair = 0x400, kLrsRrsPair = 0x200, kCenterSurround = 0x100, kTopCenterSurround = 0x80, kLsdRsdPair = 0x40, kLwRwPair = 0x20, kLvhRvhPair = 0x10, kCenterVerticalHeight = 0x8, kLtsRtsPair = 0x4, kLFE2 = 0x2, kLFEScreen = 0x1 }; // EC3 Audio coding mode map (acmod) to determine EC3 audio channel layout. The // value stands for the existence of Left, Center, Right, Left surround, and // Right surround. const uint16_t kEC3AudioCodingModeMap[] = { kLeft | kRight, kCenter, kLeft | kRight, kLeft | kCenter | kRight, kLeft | kRight | kLeftSurround | kRightSurround, kLeft | kCenter | kRight | kLeftSurround | kRightSurround, kLeft | kRight | kLeftSurround | kRightSurround, kLeft | kCenter | kRight | kLeftSurround | kRightSurround, }; // Reverse bit order. uint8_t ReverseBits8(uint8_t n) { n = ((n >> 1) & 0x55) | ((n & 0x55) << 1); n = ((n >> 2) & 0x33) | ((n & 0x33) << 2); return ((n >> 4) & 0x0f) | ((n & 0x0f) << 4); } bool ExtractEc3Data(const std::vector& ec3_data, uint8_t* audio_coding_mode, bool* lfe_channel_on, uint16_t* dependent_substreams_layout) { BitReader bit_reader(ec3_data.data(), ec3_data.size()); // Read number of independent substreams and parse the independent substreams. uint8_t number_independent_substreams; 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; // Parse audio_coding_mode, dependent_substreams_layout and lfe_channel_on // from the first independent substream. // Independent substream in EC3Specific box: // fscod: 2 bits // bsid: 5 bits // reserved_1: 1 bit // asvc: 1 bit // bsmod: 3 bits // acmod: 3 bits // lfeon: 1 bit // reserved_2: 3 bits // 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. // chan_loc: 9 bits // reserved_3: 1 bit RCHECK(bit_reader.SkipBits(12)); RCHECK(bit_reader.ReadBits(3, audio_coding_mode)); RCHECK(bit_reader.ReadBits(1, lfe_channel_on)); uint8_t number_dependent_substreams = 0; RCHECK(bit_reader.SkipBits(3)); RCHECK(bit_reader.ReadBits(4, &number_dependent_substreams)); *dependent_substreams_layout = 0; if (number_dependent_substreams > 0) { RCHECK(bit_reader.ReadBits(9, dependent_substreams_layout)); } return true; } } // namespace bool CalculateEC3ChannelMap(const std::vector& ec3_data, uint32_t* channel_map) { uint8_t audio_coding_mode; bool lfe_channel_on; uint16_t dependent_substreams_layout; if (!ExtractEc3Data(ec3_data, &audio_coding_mode, &lfe_channel_on, &dependent_substreams_layout)) return false; // Dependent substreams layout bit map: // Bit, Location // 0, Lc/Rc pair // 1, Lrs/Rrs pair // 2, Cs // 3, Ts // 4, Lsd/Rsd pair // 5, Lw/Rw pair // 6, Lvh/Rvh pair // 7, Cvh // 8(MSB), LFE2 // Reverse bit order of dependent substreams channel layout (LFE2 not // included) to apply on channel_map bit 5 - 12. const uint8_t reversed_dependent_substreams_layout = ReverseBits8(dependent_substreams_layout & 0xFF); *channel_map = kEC3AudioCodingModeMap[audio_coding_mode] | (reversed_dependent_substreams_layout << 3); if (dependent_substreams_layout & 0x100) *channel_map |= kLFE2; if (lfe_channel_on) *channel_map |= kLFEScreen; return true; } } // namespace media } // namespace shaka