MPD signaling for Dolby Enhanced AC3 audio.
Parse channel layout value from dec3 box. Pass it through audio stream info. MPD builder forms audio channel configuration to signal ec-3 codec. Specs: 1) ETSI TS 102 366 V1.3.1 Digital Audio Compression (AC-3, Enhanced AC-3) Standard E.1.3.1.8. 2) DASH-IF Interoperability Points v3.0 9.2.1.2. Issue #64 Change-Id: Ia2c22dd3d82e757ba5a88ba1de35c5d593f5005e
This commit is contained in:
parent
38c30bd7a1
commit
9ddf9276ce
|
@ -27,6 +27,7 @@
|
||||||
'../../third_party/protobuf/protobuf.gyp:protobuf_full_do_not_use',
|
'../../third_party/protobuf/protobuf.gyp:protobuf_full_do_not_use',
|
||||||
'../base/media_base.gyp:media_base',
|
'../base/media_base.gyp:media_base',
|
||||||
'../file/file.gyp:file',
|
'../file/file.gyp:file',
|
||||||
|
'../filters/filters.gyp:filters',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "packager/media/base/audio_stream_info.h"
|
#include "packager/media/base/audio_stream_info.h"
|
||||||
#include "packager/media/base/muxer_options.h"
|
#include "packager/media/base/muxer_options.h"
|
||||||
#include "packager/media/base/video_stream_info.h"
|
#include "packager/media/base/video_stream_info.h"
|
||||||
|
#include "packager/media/filters/ec3_audio_util.h"
|
||||||
#include "packager/mpd/base/media_info.pb.h"
|
#include "packager/mpd/base/media_info.pb.h"
|
||||||
|
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
@ -118,6 +119,16 @@ void AddAudioInfo(const AudioStreamInfo* audio_stream_info,
|
||||||
if (!extra_data.empty()) {
|
if (!extra_data.empty()) {
|
||||||
audio_info->set_decoder_config(&extra_data[0], extra_data.size());
|
audio_info->set_decoder_config(&extra_data[0], extra_data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (audio_stream_info->codec_string() == "ec-3") {
|
||||||
|
uint32_t ec3_channel_map;
|
||||||
|
if (!CalculateEC3ChannelMap(extra_data, &ec3_channel_map)) {
|
||||||
|
LOG(ERROR) << "Failed to calculate EC3 channel map.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
audio_info->mutable_codec_specific_data()->set_ec3_channel_map(
|
||||||
|
ec3_channel_map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
|
void SetMediaInfoStreamInfo(const StreamInfo& stream_info,
|
||||||
|
|
|
@ -0,0 +1,155 @@
|
||||||
|
// 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/filters/ec3_audio_util.h"
|
||||||
|
#include "packager/media/formats/mp4/rcheck.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
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<uint8_t>& 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<uint8_t>& 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 edash_packager
|
|
@ -0,0 +1,27 @@
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Enhanced AC3 audio utility functions.
|
||||||
|
|
||||||
|
#ifndef MEDIA_FILTERS_EC3_AUDIO_UTIL_H_
|
||||||
|
#define MEDIA_FILTERS_EC3_AUDIO_UTIL_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
/// Parse data from EC3Specific box and calculate EC3 channel map value based on
|
||||||
|
/// ETSI TS 102 366 V1.3.1 Digital Audio Compression (AC-3, Enhanced AC-3)
|
||||||
|
/// Standard E.1.3.1.8.
|
||||||
|
bool CalculateEC3ChannelMap(const std::vector<uint8_t>& ec3_data,
|
||||||
|
uint32_t* channel_map);
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace edash_packager
|
||||||
|
|
||||||
|
#endif // MEDIA_FILTERS_EC3_AUDIO_UTIL_H_
|
|
@ -0,0 +1,43 @@
|
||||||
|
// 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 <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "packager/media/filters/ec3_audio_util.h"
|
||||||
|
|
||||||
|
namespace edash_packager {
|
||||||
|
namespace media {
|
||||||
|
|
||||||
|
TEST(EC3AudioUtilTest, CalculateEC3ChannelMapTest1) {
|
||||||
|
// audio_coding_mode is 7, which is Left, Center, Right, Left surround, Right
|
||||||
|
// surround. No dependent substreams. LFE channel on.
|
||||||
|
const std::vector<uint8_t> ec3_data = {0, 0, 0, 0x0f, 0};
|
||||||
|
uint32_t channel_map;
|
||||||
|
EXPECT_TRUE(CalculateEC3ChannelMap(ec3_data, &channel_map));
|
||||||
|
EXPECT_EQ(0xF801u, channel_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EC3AudioUtilTest, CalculateEC3ChannelMapTest2) {
|
||||||
|
// audio_coding_mode is 2, which is Left and Right. No dependent substreams.
|
||||||
|
// LFE channel off.
|
||||||
|
const std::vector<uint8_t> ec3_data = {0, 0, 0, 0x04, 0};
|
||||||
|
uint32_t channel_map;
|
||||||
|
EXPECT_TRUE(CalculateEC3ChannelMap(ec3_data, &channel_map));
|
||||||
|
EXPECT_EQ(0xA000u, channel_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(EC3AudioUtilTest, CalculateEC3ChannelMapTest3) {
|
||||||
|
// audio_coding_mode is 3, which is Left, Center, and Right. Dependent
|
||||||
|
// substreams layout is 0b100000011, which is Left center/ Right center pair,
|
||||||
|
// Left rear surround/ Right rear surround pair, LFE2 on. LFE channel on.
|
||||||
|
const std::vector<uint8_t> ec3_data = {0, 0, 0, 0x07, 0x07, 0x03};
|
||||||
|
uint32_t channel_map;
|
||||||
|
EXPECT_TRUE(CalculateEC3ChannelMap(ec3_data, &channel_map));
|
||||||
|
EXPECT_EQ(0xE603u, channel_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace media
|
||||||
|
} // namespace edash_packager
|
|
@ -15,6 +15,8 @@
|
||||||
'sources': [
|
'sources': [
|
||||||
'avc_decoder_configuration.cc',
|
'avc_decoder_configuration.cc',
|
||||||
'avc_decoder_configuration.h',
|
'avc_decoder_configuration.h',
|
||||||
|
'ec3_audio_util.cc',
|
||||||
|
'ec3_audio_util.h',
|
||||||
'hevc_decoder_configuration.cc',
|
'hevc_decoder_configuration.cc',
|
||||||
'hevc_decoder_configuration.h',
|
'hevc_decoder_configuration.h',
|
||||||
'h264_bit_reader.cc',
|
'h264_bit_reader.cc',
|
||||||
|
@ -40,6 +42,7 @@
|
||||||
'type': '<(gtest_target_type)',
|
'type': '<(gtest_target_type)',
|
||||||
'sources': [
|
'sources': [
|
||||||
'avc_decoder_configuration_unittest.cc',
|
'avc_decoder_configuration_unittest.cc',
|
||||||
|
'ec3_audio_util_unittest.cc',
|
||||||
'h264_bit_reader_unittest.cc',
|
'h264_bit_reader_unittest.cc',
|
||||||
'h264_byte_to_unit_stream_converter_unittest.cc',
|
'h264_byte_to_unit_stream_converter_unittest.cc',
|
||||||
'h264_parser_unittest.cc',
|
'h264_parser_unittest.cc',
|
||||||
|
|
|
@ -1439,7 +1439,7 @@ uint32_t AC3Specific::ComputeSizeInternal() {
|
||||||
return HeaderSize() + data.size();
|
return HeaderSize() + data.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
EC3Specific::EC3Specific() : number_independent_substreams(0) {}
|
EC3Specific::EC3Specific() {}
|
||||||
EC3Specific::~EC3Specific() {}
|
EC3Specific::~EC3Specific() {}
|
||||||
|
|
||||||
FourCC EC3Specific::BoxType() const { return FOURCC_DEC3; }
|
FourCC EC3Specific::BoxType() const { return FOURCC_DEC3; }
|
||||||
|
@ -1448,35 +1448,6 @@ bool EC3Specific::ReadWriteInternal(BoxBuffer* buffer) {
|
||||||
RCHECK(ReadWriteHeaderInternal(buffer));
|
RCHECK(ReadWriteHeaderInternal(buffer));
|
||||||
uint32_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
|
uint32_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
|
||||||
RCHECK(buffer->ReadWriteVector(&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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -315,32 +315,10 @@ struct AC3Specific : Box {
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> 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 {
|
struct EC3Specific : Box {
|
||||||
DECLARE_BOX_METHODS(EC3Specific);
|
DECLARE_BOX_METHODS(EC3Specific);
|
||||||
|
|
||||||
// Before we know the number of independent substreams, data in EC3Specific
|
|
||||||
// box is store for parsing later.
|
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
size_t number_independent_substreams; // num_id_sub: 3 bits.
|
|
||||||
std::vector<IndependentSubstream> independent_substreams;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AudioSampleEntry : Box {
|
struct AudioSampleEntry : Box {
|
||||||
|
|
|
@ -49,6 +49,13 @@ message MediaInfo {
|
||||||
optional uint32 num_channels = 4;
|
optional uint32 num_channels = 4;
|
||||||
optional string language = 5;
|
optional string language = 5;
|
||||||
optional bytes decoder_config = 6;
|
optional bytes decoder_config = 6;
|
||||||
|
optional AudioCodecSpecificData codec_specific_data = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AudioCodecSpecificData {
|
||||||
|
// EC3 Channel map bit fields, encoded based on ETSI TS 102 366 V1.3.1
|
||||||
|
// Digital Audio Compression (AC-3, Enhanced AC-3) Standard E.1.3.1.8.
|
||||||
|
optional uint32 ec3_channel_map = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message TextInfo {
|
message TextInfo {
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include "packager/base/logging.h"
|
#include "packager/base/logging.h"
|
||||||
#include "packager/base/macros.h"
|
#include "packager/base/macros.h"
|
||||||
#include "packager/base/stl_util.h"
|
#include "packager/base/stl_util.h"
|
||||||
|
#include "packager/base/sys_byteorder.h"
|
||||||
#include "packager/base/strings/string_number_conversions.h"
|
#include "packager/base/strings/string_number_conversions.h"
|
||||||
#include "packager/mpd/base/media_info.pb.h"
|
#include "packager/mpd/base/media_info.pb.h"
|
||||||
#include "packager/mpd/base/segment_info.h"
|
#include "packager/mpd/base/segment_info.h"
|
||||||
|
@ -27,6 +28,7 @@ typedef ContentProtectionXml::AttributeNameValuePair AttributeNameValuePair;
|
||||||
namespace edash_packager {
|
namespace edash_packager {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
const char kEC3Codec[] = "ec-3";
|
||||||
|
|
||||||
std::string RangeToString(const Range& range) {
|
std::string RangeToString(const Range& range) {
|
||||||
return base::Uint64ToString(range.begin()) + "-" +
|
return base::Uint64ToString(range.begin()) + "-" +
|
||||||
|
@ -343,13 +345,28 @@ bool RepresentationXmlNode::AddLiveOnlyInfo(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RepresentationXmlNode::AddAudioChannelInfo(const AudioInfo& audio_info) {
|
bool RepresentationXmlNode::AddAudioChannelInfo(const AudioInfo& audio_info) {
|
||||||
const uint32_t num_channels = audio_info.num_channels();
|
std::string audio_channel_config_scheme;
|
||||||
|
std::string audio_channel_config_value;
|
||||||
|
|
||||||
|
if (audio_info.codec() == kEC3Codec) {
|
||||||
|
// Convert EC3 channel map into string of hexadecimal digits. Spec: DASH-IF
|
||||||
|
// Interoperability Points v3.0 9.2.1.2.
|
||||||
|
const uint16_t ec3_channel_map =
|
||||||
|
base::HostToNet16(audio_info.codec_specific_data().ec3_channel_map());
|
||||||
|
audio_channel_config_value =
|
||||||
|
base::HexEncode(&ec3_channel_map, sizeof(ec3_channel_map));
|
||||||
|
audio_channel_config_scheme =
|
||||||
|
"tag:dolby.com,2014:dash:audio_channel_configuration:2011";
|
||||||
|
} else {
|
||||||
|
audio_channel_config_value = base::UintToString(audio_info.num_channels());
|
||||||
|
audio_channel_config_scheme =
|
||||||
|
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
|
||||||
|
}
|
||||||
|
|
||||||
XmlNode audio_channel_config("AudioChannelConfiguration");
|
XmlNode audio_channel_config("AudioChannelConfiguration");
|
||||||
const char kAudioChannelConfigScheme[] =
|
|
||||||
"urn:mpeg:dash:23003:3:audio_channel_configuration:2011";
|
|
||||||
audio_channel_config.SetStringAttribute("schemeIdUri",
|
audio_channel_config.SetStringAttribute("schemeIdUri",
|
||||||
kAudioChannelConfigScheme);
|
audio_channel_config_scheme);
|
||||||
audio_channel_config.SetIntegerAttribute("value", num_channels);
|
audio_channel_config.SetStringAttribute("value", audio_channel_config_value);
|
||||||
|
|
||||||
return AddChild(audio_channel_config.PassScopedPtr());
|
return AddChild(audio_channel_config.PassScopedPtr());
|
||||||
}
|
}
|
||||||
|
|
|
@ -217,6 +217,24 @@ TEST_F(RepresentationTest, AddContentProtectionElements) {
|
||||||
doc.get()));
|
doc.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(RepresentationTest, AddEC3AudioInfo) {
|
||||||
|
MediaInfo::AudioInfo audio_info;
|
||||||
|
audio_info.set_codec("ec-3");
|
||||||
|
audio_info.set_sampling_frequency(44100);
|
||||||
|
audio_info.mutable_codec_specific_data()->set_ec3_channel_map(0xF801);
|
||||||
|
representation_.AddAudioInfo(audio_info);
|
||||||
|
scoped_xml_ptr<xmlDoc> doc(MakeDoc(representation_.PassScopedPtr()));
|
||||||
|
|
||||||
|
ASSERT_TRUE(XmlEqual(
|
||||||
|
"<Representation audioSamplingRate=\"44100\">\n"
|
||||||
|
" <AudioChannelConfiguration\n"
|
||||||
|
" schemeIdUri=\n"
|
||||||
|
" \"tag:dolby.com,2014:dash:audio_channel_configuration:2011\"\n"
|
||||||
|
" value=\"F801\"/>\n"
|
||||||
|
"</Representation>\n",
|
||||||
|
doc.get()));
|
||||||
|
}
|
||||||
|
|
||||||
// Some template names cannot be used for init segment name.
|
// Some template names cannot be used for init segment name.
|
||||||
TEST_F(RepresentationTest, InvalidLiveInitSegmentName) {
|
TEST_F(RepresentationTest, InvalidLiveInitSegmentName) {
|
||||||
MediaInfo media_info;
|
MediaInfo media_info;
|
||||||
|
|
Loading…
Reference in New Issue