feat: support Dolby Vision profile 8.x (HEVC) and 10.x (AV1) in HLS and DASH (#1396)
Support Dolby Vision profile 8.1, 8.2, 8.4, 10.1, 10.4 signaling in HLS and DASH. Adds new option `--use_dovi_supplemental_codecs` (off by default) to use SUPPLEMENTAL-CODECS in HLS and `scte214:supplementalCodecs` and `scte214:supplementalProfiles` for DASH. To maintain compatibility with existing players the current behavior of using two entries in the manifest remains the default. This will be changed in a future version where `use_dovi_supplemental_codecs` will become on by default. Adds Dolby Vision compatible brands, 'db1p', 'db2g', 'db4g', 'db4h', 'dby1' based on https://mp4ra.org/#/brands --------- Co-authored-by: Xingzhao Yun <xyun@dolby.com>
This commit is contained in:
parent
f6f60e5fff
commit
a99cfe036f
|
@ -486,7 +486,8 @@ class PackagerAppTest(unittest.TestCase):
|
|||
allow_codec_switching=False,
|
||||
dash_force_segment_list=False,
|
||||
force_cl_index=None,
|
||||
start_segment_number=None):
|
||||
start_segment_number=None,
|
||||
use_dovi_supplemental_codecs=None):
|
||||
flags = ['--single_threaded']
|
||||
|
||||
if not strip_parameter_set_nalus:
|
||||
|
@ -544,6 +545,9 @@ class PackagerAppTest(unittest.TestCase):
|
|||
if not dash_if_iop:
|
||||
flags.append('--generate_dash_if_iop_compliant_mpd=false')
|
||||
|
||||
if use_dovi_supplemental_codecs:
|
||||
flags.append('--use_dovi_supplemental_codecs')
|
||||
|
||||
if output_media_info:
|
||||
flags.append('--output_media_info')
|
||||
if output_dash:
|
||||
|
@ -1456,6 +1460,42 @@ class PackagerFunctionalTest(PackagerAppTest):
|
|||
self.assertPackageSuccess(streams, flags)
|
||||
self._CheckTestResults('dolby-vision-profile-8-with-encryption')
|
||||
|
||||
# TODO(cosmin): shared_library build does not support
|
||||
# use_dovi_supplemental_codecs
|
||||
@unittest.skipIf(
|
||||
test_env.BUILD_TYPE == 'shared',
|
||||
'libpackager shared_library does not support '
|
||||
'--use_dovi_supplemental_codecs flag.'
|
||||
)
|
||||
def testDolbyVisionProfile8UsingSupplementalCodecs(self):
|
||||
streams = [
|
||||
self._GetStream('video', test_file='sparks_dovi_8.mp4')
|
||||
]
|
||||
flags = self._GetFlags(output_dash=True,
|
||||
output_hls=True,
|
||||
use_dovi_supplemental_codecs=True)
|
||||
|
||||
self.assertPackageSuccess(streams, flags)
|
||||
self._CheckTestResults('dolby-vision-profile-8-supplemental-codecs')
|
||||
|
||||
# TODO(cosmin): shared_library build does not support
|
||||
# use_dovi_supplemental_codecs
|
||||
@unittest.skipIf(
|
||||
test_env.BUILD_TYPE == 'shared',
|
||||
'libpackager shared_library does not support '
|
||||
'--use_dovi_supplemental_codecs flag.'
|
||||
)
|
||||
def testDolbyVisionProfile10UsingSupplementalCodecs(self):
|
||||
streams = [
|
||||
self._GetStream('video', test_file='sparks_dovi_10.mp4')
|
||||
]
|
||||
flags = self._GetFlags(output_dash=True,
|
||||
output_hls=True,
|
||||
use_dovi_supplemental_codecs=True)
|
||||
|
||||
self.assertPackageSuccess(streams, flags)
|
||||
self._CheckTestResults('dolby-vision-profile-10-supplemental-codecs')
|
||||
|
||||
def testVp8Mp4WithEncryption(self):
|
||||
streams = [
|
||||
self._GetStream('video',
|
||||
|
|
7
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.m3u8
vendored
Normal file
7
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.m3u8
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
#EXTM3U
|
||||
## Generated with https://github.com/shaka-project/shaka-packager version <tag>-<hash>-<test>
|
||||
|
||||
#EXT-X-INDEPENDENT-SEGMENTS
|
||||
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=550702,AVERAGE-BANDWIDTH=577484,CODECS="av01.0.04M.10.0.111.09.16.09.0",SUPPLEMENTAL-CODECS="dav1.10.01/db1p",RESOLUTION=640x360,FRAME-RATE=59.940,VIDEO-RANGE=PQ,CLOSED-CAPTIONS=NONE
|
||||
stream_0.m3u8
|
17
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.mpd
vendored
Normal file
17
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.mpd
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/shaka-project/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:scte214="urn:scte:dash:scte214-extensions" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT6.022683S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="60000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"/>
|
||||
<Representation id="0" bandwidth="550702" codecs="av01.0.04M.10.0.111.09.16.09.0" mimeType="video/mp4" scte214:supplementalCodecs="dav1.10.01" scte214:supplementalProfiles="db1p" sar="1:1">
|
||||
<BaseURL>sparks_dovi_10-video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="871-926" timescale="60000">
|
||||
<Initialization range="0-870"/>
|
||||
</SegmentBase>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
BIN
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/sparks_dovi_10-video.mp4
vendored
Normal file
BIN
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/sparks_dovi_10-video.mp4
vendored
Normal file
Binary file not shown.
13
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/stream_0.m3u8
vendored
Normal file
13
packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/stream_0.m3u8
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
#EXTM3U
|
||||
#EXT-X-VERSION:6
|
||||
## Generated with https://github.com/shaka-project/shaka-packager version <tag>-<hash>-<test>
|
||||
#EXT-X-TARGETDURATION:6
|
||||
#EXT-X-PLAYLIST-TYPE:VOD
|
||||
#EXT-X-MAP:URI="sparks_dovi_10-video.mp4",BYTERANGE="871@0"
|
||||
#EXTINF:5.355,
|
||||
#EXT-X-BYTERANGE:368650@927
|
||||
sparks_dovi_10-video.mp4
|
||||
#EXTINF:0.667,
|
||||
#EXT-X-BYTERANGE:66100
|
||||
sparks_dovi_10-video.mp4
|
||||
#EXT-X-ENDLIST
|
|
@ -3,6 +3,8 @@
|
|||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT6.022683S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="60000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="2"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="2"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"/>
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
|
|
7
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.m3u8
vendored
Normal file
7
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.m3u8
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
#EXTM3U
|
||||
## Generated with https://github.com/shaka-project/shaka-packager version <tag>-<hash>-<test>
|
||||
|
||||
#EXT-X-INDEPENDENT-SEGMENTS
|
||||
|
||||
#EXT-X-STREAM-INF:BANDWIDTH=807837,AVERAGE-BANDWIDTH=748074,CODECS="hvc1.2.4.L90.90",SUPPLEMENTAL-CODECS="dvh1.08.01/db2g",RESOLUTION=640x360,FRAME-RATE=59.940,VIDEO-RANGE=PQ,CLOSED-CAPTIONS=NONE
|
||||
stream_0.m3u8
|
17
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.mpd
vendored
Normal file
17
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.mpd
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--Generated with https://github.com/shaka-project/shaka-packager version <tag>-<hash>-<test>-->
|
||||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:scte214="urn:scte:dash:scte214-extensions" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT6.022683S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="60000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"/>
|
||||
<Representation id="0" bandwidth="807837" codecs="hvc1.2.4.L90.90" mimeType="video/mp4" scte214:supplementalCodecs="dvh1.08.01" scte214:supplementalProfiles="db2g" sar="1:1">
|
||||
<BaseURL>sparks_dovi_8-video.mp4</BaseURL>
|
||||
<SegmentBase indexRange="992-1071" timescale="60000">
|
||||
<Initialization range="0-991"/>
|
||||
</SegmentBase>
|
||||
</Representation>
|
||||
</AdaptationSet>
|
||||
</Period>
|
||||
</MPD>
|
BIN
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/sparks_dovi_8-video.mp4
vendored
Normal file
BIN
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/sparks_dovi_8-video.mp4
vendored
Normal file
Binary file not shown.
19
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/stream_0.m3u8
vendored
Normal file
19
packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/stream_0.m3u8
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
#EXTM3U
|
||||
#EXT-X-VERSION:6
|
||||
## Generated with https://github.com/shaka-project/shaka-packager version <tag>-<hash>-<test>
|
||||
#EXT-X-TARGETDURATION:3
|
||||
#EXT-X-PLAYLIST-TYPE:VOD
|
||||
#EXT-X-MAP:URI="sparks_dovi_8-video.mp4",BYTERANGE="992@0"
|
||||
#EXTINF:2.002,
|
||||
#EXT-X-BYTERANGE:172013@1072
|
||||
sparks_dovi_8-video.mp4
|
||||
#EXTINF:2.002,
|
||||
#EXT-X-BYTERANGE:186781
|
||||
sparks_dovi_8-video.mp4
|
||||
#EXTINF:2.002,
|
||||
#EXT-X-BYTERANGE:202161
|
||||
sparks_dovi_8-video.mp4
|
||||
#EXTINF:0.017,
|
||||
#EXT-X-BYTERANGE:2221
|
||||
sparks_dovi_8-video.mp4
|
||||
#EXT-X-ENDLIST
|
|
@ -3,6 +3,8 @@
|
|||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT6.022683S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="60000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"/>
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
|
@ -16,6 +18,8 @@
|
|||
</Representation>
|
||||
</AdaptationSet>
|
||||
<AdaptationSet id="1" contentType="video" width="640" height="360" frameRate="60000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"/>
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
|
|
|
@ -8,6 +8,8 @@ video_info {
|
|||
decoder_config: "\001d\000\036\377\341\000\031gd\000\036\254\331@\240/\371p\021\000\000\003\003\351\000\000\352`\017\026-\226\001\000\006h\353\343\313\"\300"
|
||||
pixel_width: 1
|
||||
pixel_height: 1
|
||||
supplemental_codec: ""
|
||||
compatible_brand: 0
|
||||
}
|
||||
init_range {
|
||||
begin: 0
|
||||
|
|
|
@ -8,6 +8,8 @@ video_info {
|
|||
decoder_config: "\001d\000\036\377\341\000\031gd\000\036\254\331@\240/\371p\021\000\000\003\003\351\000\000\352`\017\026-\226\001\000\006h\353\343\313\"\300"
|
||||
pixel_width: 1
|
||||
pixel_height: 1
|
||||
supplemental_codec: ""
|
||||
compatible_brand: 0
|
||||
}
|
||||
init_range {
|
||||
begin: 0
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
<MPD xmlns="urn:mpeg:dash:schema:mpd:2011" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:mpeg:dash:schema:mpd:2011 DASH-MPD.xsd" xmlns:cenc="urn:mpeg:cenc:2013" profiles="urn:mpeg:dash:profile:isoff-on-demand:2011" minBufferTime="PT2S" type="static" mediaPresentationDuration="PT2.8028S">
|
||||
<Period id="0">
|
||||
<AdaptationSet id="0" contentType="video" width="640" height="360" frameRate="30000/1001" subsegmentAlignment="true" par="16:9">
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:MatrixCoefficients" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:ColourPrimaries" value="9"/>
|
||||
<SupplementalProperty schemeIdUri="urn:mpeg:mpegB:cicp:TransferCharacteristics" value="16"/>
|
||||
<ContentProtection value="cenc" schemeIdUri="urn:mpeg:dash:mp4protection:2011" cenc:default_KID="31323334-3536-3738-3930-313233343536"/>
|
||||
<ContentProtection schemeIdUri="urn:uuid:1077efec-c0b2-4d02-ace3-3c1e52e2fb4b">
|
||||
|
|
|
@ -228,6 +228,15 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
|
|||
variant.text_codecs.end());
|
||||
tag.AddQuotedString("CODECS", absl::StrJoin(all_codecs, ","));
|
||||
|
||||
if (playlist.supplemental_codec() != "" &&
|
||||
playlist.compatible_brand() != media::FOURCC_NULL) {
|
||||
std::vector<std::string> supplemental_codecs;
|
||||
supplemental_codecs.push_back(playlist.supplemental_codec());
|
||||
supplemental_codecs.push_back(FourCCToString(playlist.compatible_brand()));
|
||||
tag.AddQuotedString("SUPPLEMENTAL-CODECS",
|
||||
absl::StrJoin(supplemental_codecs, "/"));
|
||||
}
|
||||
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
if (playlist.GetDisplayResolution(&width, &height)) {
|
||||
|
|
|
@ -393,6 +393,13 @@ bool MediaPlaylist::SetMediaInfo(const MediaInfo& media_info) {
|
|||
if (media_info.has_video_info()) {
|
||||
stream_type_ = MediaPlaylistStreamType::kVideo;
|
||||
codec_ = AdjustVideoCodec(media_info.video_info().codec());
|
||||
if (media_info.video_info().has_supplemental_codec() &&
|
||||
media_info.video_info().has_compatible_brand()) {
|
||||
supplemental_codec_ =
|
||||
AdjustVideoCodec(media_info.video_info().supplemental_codec());
|
||||
compatible_brand_ = static_cast<media::FourCC>(
|
||||
media_info.video_info().compatible_brand());
|
||||
}
|
||||
} else if (media_info.has_audio_info()) {
|
||||
stream_type_ = MediaPlaylistStreamType::kAudio;
|
||||
codec_ = media_info.audio_info().codec();
|
||||
|
@ -576,10 +583,23 @@ std::string MediaPlaylist::GetVideoRange() const {
|
|||
// https://tools.ietf.org/html/draft-pantos-hls-rfc8216bis-02#section-4.4.4.2
|
||||
switch (media_info_.video_info().transfer_characteristics()) {
|
||||
case 1:
|
||||
case 6:
|
||||
case 13:
|
||||
case 14:
|
||||
// Dolby Vision profile 8.4 may have a transfer_characteristics 14, the
|
||||
// actual value refers to preferred_transfer_characteristic value in SEI
|
||||
// message, using compatible brand as a workaround
|
||||
if (!supplemental_codec_.empty() &&
|
||||
compatible_brand_ == media::FOURCC_db4g)
|
||||
return "HLG";
|
||||
else
|
||||
return "SDR";
|
||||
case 15:
|
||||
return "SDR";
|
||||
case 16:
|
||||
case 18:
|
||||
return "PQ";
|
||||
case 18:
|
||||
return "HLG";
|
||||
default:
|
||||
// Leave it empty if we do not have the transfer characteristics
|
||||
// information.
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <packager/macros/classes.h>
|
||||
#include <packager/mpd/base/bandwidth_estimator.h>
|
||||
#include <packager/mpd/base/media_info.pb.h>
|
||||
#include "packager/media/base/fourccs.h"
|
||||
|
||||
namespace shaka {
|
||||
|
||||
|
@ -80,6 +81,8 @@ class MediaPlaylist {
|
|||
const std::string& group_id() const { return group_id_; }
|
||||
MediaPlaylistStreamType stream_type() const { return stream_type_; }
|
||||
const std::string& codec() const { return codec_; }
|
||||
const std::string& supplemental_codec() const { return supplemental_codec_; }
|
||||
const media::FourCC& compatible_brand() const { return compatible_brand_; }
|
||||
|
||||
/// For testing only.
|
||||
void SetStreamTypeForTesting(MediaPlaylistStreamType stream_type);
|
||||
|
@ -265,6 +268,8 @@ class MediaPlaylist {
|
|||
// Whether to use byte range for SegmentInfoEntry.
|
||||
bool use_byte_range_ = false;
|
||||
std::string codec_;
|
||||
std::string supplemental_codec_;
|
||||
media::FourCC compatible_brand_;
|
||||
std::string language_;
|
||||
std::vector<std::string> characteristics_;
|
||||
bool forced_subtitle_ = false;
|
||||
|
|
|
@ -1227,7 +1227,7 @@ INSTANTIATE_TEST_CASE_P(VideoRanges,
|
|||
Values(VideoRangeTestData{"hvc1.2.4.L63.90", 0, ""},
|
||||
VideoRangeTestData{"hvc1.2.4.L63.90", 1, "SDR"},
|
||||
VideoRangeTestData{"hvc1.2.4.L63.90", 16, "PQ"},
|
||||
VideoRangeTestData{"hvc1.2.4.L63.90", 18, "PQ"},
|
||||
VideoRangeTestData{"hvc1.2.4.L63.90", 18, "HLG"},
|
||||
VideoRangeTestData{"dvh1.05.08", 0, "PQ"}));
|
||||
|
||||
} // namespace hls
|
||||
|
|
|
@ -47,6 +47,11 @@ enum FourCC : uint32_t {
|
|||
FOURCC_dac3 = 0x64616333,
|
||||
FOURCC_dac4 = 0x64616334,
|
||||
FOURCC_dash = 0x64617368,
|
||||
FOURCC_dav1 = 0x64617631,
|
||||
FOURCC_db1p = 0x64623170,
|
||||
FOURCC_db2g = 0x64623267,
|
||||
FOURCC_db4g = 0x64623467,
|
||||
FOURCC_db4h = 0x64623468,
|
||||
FOURCC_dby1 = 0x64627931,
|
||||
FOURCC_ddts = 0x64647473,
|
||||
FOURCC_dec3 = 0x64656333,
|
||||
|
|
|
@ -31,7 +31,10 @@ const uint32_t kWidth = 10u;
|
|||
const uint32_t kHeight = 20u;
|
||||
const uint32_t kPixelWidth = 2u;
|
||||
const uint32_t kPixelHeight = 3u;
|
||||
const uint8_t kColorPrimaries = 0;
|
||||
const uint8_t kMatrixCoefficients = 0;
|
||||
const uint8_t kTransferCharacteristics = 0;
|
||||
|
||||
const int16_t kTrickPlayFactor = 0;
|
||||
const uint8_t kNaluLengthSize = 1u;
|
||||
const bool kEncrypted = true;
|
||||
|
@ -207,8 +210,9 @@ std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetVideoStreamInfo(
|
|||
return std::unique_ptr<VideoStreamInfo>(new VideoStreamInfo(
|
||||
kTrackId, time_scale, kDuration, codec, H26xStreamFormat::kUnSpecified,
|
||||
kCodecString, kCodecConfig, sizeof(kCodecConfig), width, height,
|
||||
kPixelWidth, kPixelHeight, kTransferCharacteristics, kTrickPlayFactor,
|
||||
kNaluLengthSize, kLanguage, !kEncrypted));
|
||||
kPixelWidth, kPixelHeight, kColorPrimaries, kMatrixCoefficients,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
!kEncrypted));
|
||||
}
|
||||
|
||||
std::unique_ptr<StreamInfo> MediaHandlerTestBase::GetAudioStreamInfo(
|
||||
|
|
|
@ -50,6 +50,8 @@ VideoStreamInfo::VideoStreamInfo(int track_id,
|
|||
uint32_t height,
|
||||
uint32_t pixel_width,
|
||||
uint32_t pixel_height,
|
||||
uint8_t color_primaries,
|
||||
uint8_t matrix_coefficients,
|
||||
uint8_t transfer_characteristics,
|
||||
uint32_t trick_play_factor,
|
||||
uint8_t nalu_length_size,
|
||||
|
@ -71,6 +73,8 @@ VideoStreamInfo::VideoStreamInfo(int track_id,
|
|||
pixel_width_(pixel_width),
|
||||
pixel_height_(pixel_height),
|
||||
transfer_characteristics_(transfer_characteristics),
|
||||
color_primaries_(color_primaries),
|
||||
matrix_coefficients_(matrix_coefficients),
|
||||
trick_play_factor_(trick_play_factor),
|
||||
nalu_length_size_(nalu_length_size) {}
|
||||
|
||||
|
|
|
@ -39,6 +39,8 @@ class VideoStreamInfo : public StreamInfo {
|
|||
uint32_t height,
|
||||
uint32_t pixel_width,
|
||||
uint32_t pixel_height,
|
||||
uint8_t color_primaries,
|
||||
uint8_t matrix_coefficients,
|
||||
uint8_t transfer_characteristics,
|
||||
uint32_t trick_play_factor,
|
||||
uint8_t nalu_length_size,
|
||||
|
@ -54,6 +56,8 @@ class VideoStreamInfo : public StreamInfo {
|
|||
std::unique_ptr<StreamInfo> Clone() const override;
|
||||
/// @}
|
||||
|
||||
const std::string supplemental_codec() const { return supplemental_codec_; }
|
||||
FourCC compatible_brand() const { return compatible_brand_; }
|
||||
const std::vector<uint8_t>& extra_config() const { return extra_config_; }
|
||||
H26xStreamFormat h26x_stream_format() const { return h26x_stream_format_; }
|
||||
uint32_t width() const { return width_; }
|
||||
|
@ -65,12 +69,22 @@ class VideoStreamInfo : public StreamInfo {
|
|||
/// @return 0 if unknown.
|
||||
uint32_t pixel_height() const { return pixel_height_; }
|
||||
uint8_t transfer_characteristics() const { return transfer_characteristics_; }
|
||||
uint8_t color_primaries() const { return color_primaries_; }
|
||||
uint8_t matrix_coefficients() const { return matrix_coefficients_; }
|
||||
uint8_t nalu_length_size() const { return nalu_length_size_; }
|
||||
uint32_t trick_play_factor() const { return trick_play_factor_; }
|
||||
uint32_t playback_rate() const { return playback_rate_; }
|
||||
const std::vector<uint8_t>& eme_init_data() const { return eme_init_data_; }
|
||||
const std::vector<uint8_t>& colr_data() const { return colr_data_; }
|
||||
|
||||
void set_supplemental_codec(const std::string supplemental_codec) {
|
||||
supplemental_codec_ = supplemental_codec;
|
||||
}
|
||||
|
||||
void set_compatible_brand(const FourCC compatible_brand) {
|
||||
compatible_brand_ = compatible_brand;
|
||||
}
|
||||
|
||||
void set_extra_config(const std::vector<uint8_t>& extra_config) {
|
||||
extra_config_ = extra_config;
|
||||
}
|
||||
|
@ -81,6 +95,12 @@ class VideoStreamInfo : public StreamInfo {
|
|||
void set_transfer_characteristics(uint8_t transfer_characteristics) {
|
||||
transfer_characteristics_ = transfer_characteristics;
|
||||
}
|
||||
void set_color_primaries(uint8_t color_primaries) {
|
||||
color_primaries_ = color_primaries;
|
||||
}
|
||||
void set_matrix_coefficients(uint8_t matrix_coefficients) {
|
||||
matrix_coefficients_ = matrix_coefficients;
|
||||
}
|
||||
void set_trick_play_factor(uint32_t trick_play_factor) {
|
||||
trick_play_factor_ = trick_play_factor;
|
||||
}
|
||||
|
@ -98,6 +118,8 @@ class VideoStreamInfo : public StreamInfo {
|
|||
private:
|
||||
// Extra codec configuration in a stream of mp4 boxes. It is only applicable
|
||||
// to mp4 container only. It is needed by some codecs, e.g. Dolby Vision.
|
||||
std::string supplemental_codec_ = "";
|
||||
FourCC compatible_brand_ = FOURCC_NULL;
|
||||
std::vector<uint8_t> extra_config_;
|
||||
H26xStreamFormat h26x_stream_format_;
|
||||
uint32_t width_;
|
||||
|
@ -108,6 +130,8 @@ class VideoStreamInfo : public StreamInfo {
|
|||
uint32_t pixel_width_;
|
||||
uint32_t pixel_height_;
|
||||
uint8_t transfer_characteristics_ = 0;
|
||||
uint8_t color_primaries_ = 0;
|
||||
uint8_t matrix_coefficients_ = 0;
|
||||
uint32_t trick_play_factor_ = 0; // Non-zero for trick-play streams.
|
||||
|
||||
// Playback rate is the attribute for trick play stream, which signals the
|
||||
|
|
|
@ -48,6 +48,12 @@ class DecoderConfigurationRecord {
|
|||
/// @return Transfer characteristics of the config.
|
||||
uint8_t transfer_characteristics() const { return transfer_characteristics_; }
|
||||
|
||||
/// @return Colour Primaries of the config.
|
||||
uint8_t color_primaries() const { return color_primaries_; }
|
||||
|
||||
/// @return Matrix Coeffs of the config.
|
||||
uint8_t matrix_coefficients() const { return matrix_coefficients_; }
|
||||
|
||||
protected:
|
||||
DecoderConfigurationRecord();
|
||||
|
||||
|
@ -71,6 +77,15 @@ class DecoderConfigurationRecord {
|
|||
transfer_characteristics_ = transfer_characteristics;
|
||||
}
|
||||
|
||||
/// Sets the colour primaries.
|
||||
void set_color_primaries(uint8_t color_primaries) {
|
||||
color_primaries_ = color_primaries;
|
||||
}
|
||||
/// Sets the matrix coeffs.
|
||||
void set_matrix_coefficients(uint8_t matrix_coefficients) {
|
||||
matrix_coefficients_ = matrix_coefficients;
|
||||
}
|
||||
|
||||
private:
|
||||
// Performs the actual parsing of the data.
|
||||
virtual bool ParseInternal() = 0;
|
||||
|
@ -86,6 +101,9 @@ class DecoderConfigurationRecord {
|
|||
// The parameter is extracted from SPS.
|
||||
uint8_t transfer_characteristics_ = 0;
|
||||
|
||||
uint8_t color_primaries_ = 0;
|
||||
uint8_t matrix_coefficients_ = 0;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DecoderConfigurationRecord);
|
||||
};
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@ bool DOVIDecoderConfigurationRecord::Parse(const std::vector<uint8_t>& data) {
|
|||
uint8_t minor_version = 0;
|
||||
RCHECK(reader.ReadBits(8, &major_version) && major_version == 1 &&
|
||||
reader.ReadBits(8, &minor_version) && minor_version == 0 &&
|
||||
reader.ReadBits(7, &profile_) && reader.ReadBits(6, &level_));
|
||||
reader.ReadBits(7, &profile_) && reader.ReadBits(6, &level_) &&
|
||||
reader.SkipBits(3) &&
|
||||
reader.ReadBits(4, &bl_signal_compatibility_id_));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -35,5 +37,24 @@ std::string DOVIDecoderConfigurationRecord::GetCodecString(
|
|||
profile_, level_);
|
||||
}
|
||||
|
||||
FourCC DOVIDecoderConfigurationRecord::GetDoViCompatibleBrand(
|
||||
const uint8_t transfer_characteristics) const {
|
||||
// Dolby Vision Streams within the ISO Base Media File Format Version 2.4:
|
||||
switch (bl_signal_compatibility_id_) {
|
||||
case 1:
|
||||
return FOURCC_db1p;
|
||||
case 2:
|
||||
return FOURCC_db2g;
|
||||
case 4:
|
||||
if (transfer_characteristics == 14) {
|
||||
return FOURCC_db4g;
|
||||
}
|
||||
// transfer_characteristics == 18
|
||||
return FOURCC_db4h;
|
||||
default:
|
||||
return FOURCC_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace media
|
||||
} // namespace shaka
|
||||
|
|
|
@ -35,6 +35,10 @@ class DOVIDecoderConfigurationRecord {
|
|||
/// DASH and HLS manifests.
|
||||
std::string GetCodecString(FourCC codec_fourcc) const;
|
||||
|
||||
/// @return The compatiable brand in the format defined by
|
||||
/// https://mp4ra.org/#/brands.
|
||||
FourCC GetDoViCompatibleBrand(const uint8_t transfer_characteristics) const;
|
||||
|
||||
private:
|
||||
DOVIDecoderConfigurationRecord(const DOVIDecoderConfigurationRecord&) =
|
||||
delete;
|
||||
|
@ -42,6 +46,7 @@ class DOVIDecoderConfigurationRecord {
|
|||
const DOVIDecoderConfigurationRecord&) = delete;
|
||||
|
||||
uint8_t profile_ = 0;
|
||||
uint8_t bl_signal_compatibility_id_ = 0;
|
||||
uint8_t level_ = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -519,9 +519,9 @@ H264Parser::Result H264Parser::ParseVUIParameters(H26xBitReader* br,
|
|||
READ_BOOL_OR_RETURN(&data); // video_full_range_flag
|
||||
READ_BOOL_OR_RETURN(&data); // colour_description_present_flag
|
||||
if (data) {
|
||||
READ_BITS_OR_RETURN(8, &data); // colour primaries
|
||||
READ_BITS_OR_RETURN(8, &sps->color_primaries); // colour primaries
|
||||
READ_BITS_OR_RETURN(8, &sps->transfer_characteristics);
|
||||
READ_BITS_OR_RETURN(8, &data); // matrix coeffs
|
||||
READ_BITS_OR_RETURN(8, &sps->matrix_coefficients); // matrix coeffs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -81,6 +81,8 @@ struct H264Sps {
|
|||
int sar_width; // Set to 0 when not specified.
|
||||
int sar_height; // Set to 0 when not specified.
|
||||
int transfer_characteristics;
|
||||
int color_primaries;
|
||||
int matrix_coefficients;
|
||||
|
||||
bool timing_info_present_flag;
|
||||
long num_units_in_tick;
|
||||
|
|
|
@ -680,9 +680,11 @@ H265Parser::Result H265Parser::ParseVuiParameters(int max_num_sub_layers_minus1,
|
|||
bool colour_description_present_flag;
|
||||
TRUE_OR_RETURN(br->ReadBool(&colour_description_present_flag));
|
||||
if (colour_description_present_flag) {
|
||||
TRUE_OR_RETURN(br->SkipBits(8)); // colour_primaries
|
||||
TRUE_OR_RETURN(
|
||||
br->ReadBits(8, &vui->color_primaries)); // color_primaries
|
||||
TRUE_OR_RETURN(br->ReadBits(8, &vui->transfer_characteristics));
|
||||
TRUE_OR_RETURN(br->SkipBits(8)); // matrix_coeffs
|
||||
TRUE_OR_RETURN(
|
||||
br->ReadBits(8, &vui->matrix_coefficients)); // matrix_coeffs
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ struct H265VuiParameters {
|
|||
int sar_width = 0;
|
||||
int sar_height = 0;
|
||||
int transfer_characteristics = 0;
|
||||
int color_primaries = 0;
|
||||
int matrix_coefficients = 0;
|
||||
|
||||
bool vui_timing_info_present_flag = false;
|
||||
long vui_num_units_in_tick = 0;
|
||||
|
|
|
@ -120,6 +120,10 @@ bool HEVCDecoderConfigurationRecord::ParseInternal() {
|
|||
RCHECK(parser.ParseSps(nalu, &sps_id) == H265Parser::kOk);
|
||||
set_transfer_characteristics(
|
||||
parser.GetSps(sps_id)->vui_parameters.transfer_characteristics);
|
||||
set_color_primaries(
|
||||
parser.GetSps(sps_id)->vui_parameters.color_primaries);
|
||||
set_matrix_coefficients(
|
||||
parser.GetSps(sps_id)->vui_parameters.matrix_coefficients);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,6 +63,8 @@ VideoStreamInfo GetVideoStreamInfo(Codec codec) {
|
|||
const uint16_t kHeight = 20u;
|
||||
const uint32_t kPixelWidth = 2u;
|
||||
const uint32_t kPixelHeight = 3u;
|
||||
const uint8_t kColorPrimaries = 0;
|
||||
const uint8_t kMatrixCoefficients = 0;
|
||||
const uint8_t kTransferCharacteristics = 0;
|
||||
const int16_t kTrickPlayFactor = 0;
|
||||
const uint8_t kNaluLengthSize = 1u;
|
||||
|
@ -85,8 +87,9 @@ VideoStreamInfo GetVideoStreamInfo(Codec codec) {
|
|||
return VideoStreamInfo(
|
||||
kTrackId, kTimeScale, kDuration, codec, H26xStreamFormat::kUnSpecified,
|
||||
kCodecString, codec_config, codec_config_size, kWidth, kHeight,
|
||||
kPixelWidth, kPixelHeight, kTransferCharacteristics, kTrickPlayFactor,
|
||||
kNaluLengthSize, kLanguage, !kEncrypted);
|
||||
kPixelWidth, kPixelHeight, kColorPrimaries, kMatrixCoefficients,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
!kEncrypted);
|
||||
}
|
||||
|
||||
AudioStreamInfo GetAudioStreamInfo(Codec codec) {
|
||||
|
|
|
@ -301,6 +301,8 @@ TEST_F(MpdNotifyMuxerListenerTest, VodOnSampleDurationReady) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
@ -349,6 +351,8 @@ TEST_F(MpdNotifyMuxerListenerTest, VodOnSampleDurationReadySegmentList) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
@ -616,6 +620,8 @@ TEST_F(MpdNotifyMuxerListenerTest, LowLatencyDash) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"media_duration_seconds: 20.0\n"
|
||||
"index: 0\n"
|
||||
|
@ -682,6 +688,8 @@ TEST_P(MpdNotifyMuxerListenerTest, LiveNoKeyRotation) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"media_duration_seconds: 20.0\n"
|
||||
"index: 0\n"
|
||||
|
@ -767,6 +775,8 @@ TEST_P(MpdNotifyMuxerListenerTest, LiveWithKeyRotation) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"media_duration_seconds: 20.0\n"
|
||||
"index: 0\n"
|
||||
|
|
|
@ -73,6 +73,8 @@ void AddVideoInfo(const VideoStreamInfo* video_stream_info,
|
|||
DCHECK(video_stream_info);
|
||||
DCHECK(media_info);
|
||||
MediaInfo_VideoInfo* video_info = media_info->mutable_video_info();
|
||||
video_info->set_supplemental_codec(video_stream_info->supplemental_codec());
|
||||
video_info->set_compatible_brand(video_stream_info->compatible_brand());
|
||||
video_info->set_codec(video_stream_info->codec_string());
|
||||
video_info->set_width(video_stream_info->width());
|
||||
video_info->set_height(video_stream_info->height());
|
||||
|
@ -96,6 +98,13 @@ void AddVideoInfo(const VideoStreamInfo* video_stream_info,
|
|||
video_info->set_transfer_characteristics(
|
||||
video_stream_info->transfer_characteristics());
|
||||
}
|
||||
if (video_stream_info->color_primaries() > 0) {
|
||||
video_info->set_color_primaries(video_stream_info->color_primaries());
|
||||
}
|
||||
if (video_stream_info->matrix_coefficients() > 0) {
|
||||
video_info->set_matrix_coefficients(
|
||||
video_stream_info->matrix_coefficients());
|
||||
}
|
||||
}
|
||||
|
||||
void AddAudioInfo(const AudioStreamInfo* audio_stream_info,
|
||||
|
|
|
@ -23,6 +23,8 @@ std::shared_ptr<VideoStreamInfo> CreateVideoStreamInfo(
|
|||
H26xStreamFormat::kUnSpecified, param.codec_string,
|
||||
param.codec_config.data(), param.codec_config.size(), param.width,
|
||||
param.height, param.pixel_width, param.pixel_height,
|
||||
0, // color_primaries
|
||||
0, // matrix_coefficients
|
||||
0, // transfer_characteristics
|
||||
0, // trick_play_factor
|
||||
param.nalu_length_size, param.language, param.is_encrypted);
|
||||
|
|
|
@ -26,6 +26,8 @@ const char kExpectedDefaultPsshBox[] = "expected_pssh_box";
|
|||
const char kExpectedDefaultMediaInfo[] =
|
||||
"video_info {\n"
|
||||
" codec: 'avc1.010101'\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
" width: 720\n"
|
||||
" height: 480\n"
|
||||
" time_scale: 10\n"
|
||||
|
@ -54,6 +56,8 @@ const char kExpectedDefaultMediaInfoSubsegmentRange[] =
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
|
|
@ -138,6 +138,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
@ -170,6 +172,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, EncryptedStream_Normal) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
@ -218,6 +222,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, CheckPixelWidthAndHeightSet) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 8\n"
|
||||
" pixel_height: 9\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
@ -260,6 +266,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, CheckBandwidth) {
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
@ -297,6 +305,8 @@ TEST_F(VodMediaInfoDumpMuxerListenerTest, UnencryptedStream_Normal_SegmentList)
|
|||
" time_scale: 10\n"
|
||||
" pixel_width: 1\n"
|
||||
" pixel_height: 1\n"
|
||||
" supplemental_codec: ''\n"
|
||||
" compatible_brand: 0\n"
|
||||
"}\n"
|
||||
"init_range {\n"
|
||||
" begin: 0\n"
|
||||
|
|
|
@ -174,7 +174,8 @@ bool EsParserH264::UpdateVideoDecoderConfig(int pps_id) {
|
|||
codec_fourcc, decoder_config_record[1], decoder_config_record[2],
|
||||
decoder_config_record[3]),
|
||||
decoder_config_record.data(), decoder_config_record.size(), coded_width,
|
||||
coded_height, pixel_width, pixel_height, sps->transfer_characteristics, 0,
|
||||
coded_height, pixel_width, pixel_height, sps->color_primaries,
|
||||
sps->matrix_coefficients, sps->transfer_characteristics, 0,
|
||||
nalu_length_size, std::string(), false);
|
||||
DVLOG(1) << "Profile IDC: " << sps->profile_idc;
|
||||
DVLOG(1) << "Level IDC: " << sps->level_idc;
|
||||
|
|
|
@ -177,8 +177,10 @@ bool EsParserH265::UpdateVideoDecoderConfig(int pps_id) {
|
|||
pid(), kMpeg2Timescale, kInfiniteDuration, kCodecH265, stream_format,
|
||||
decoder_config.GetCodecString(codec_fourcc), decoder_config_record.data(),
|
||||
decoder_config_record.size(), coded_width, coded_height, pixel_width,
|
||||
pixel_height, sps->vui_parameters.transfer_characteristics, 0,
|
||||
nalu_length_size, std::string(), false);
|
||||
pixel_height, sps->vui_parameters.color_primaries,
|
||||
sps->vui_parameters.matrix_coefficients,
|
||||
sps->vui_parameters.transfer_characteristics, 0, nalu_length_size,
|
||||
std::string(), false);
|
||||
|
||||
// Video config notification.
|
||||
new_stream_info_cb_(last_video_decoder_config_);
|
||||
|
|
|
@ -84,6 +84,8 @@ const uint32_t kWidth = 1280;
|
|||
const uint32_t kHeight = 720;
|
||||
const uint32_t kPixelWidth = 1;
|
||||
const uint32_t kPixelHeight = 1;
|
||||
const uint8_t kColorPrimaries = 0;
|
||||
const uint8_t kMatrixCoefficients = 0;
|
||||
const uint8_t kTransferCharacteristics = 0;
|
||||
const uint16_t kTrickPlayFactor = 1;
|
||||
const uint8_t kNaluLengthSize = 1;
|
||||
|
@ -125,8 +127,8 @@ std::shared_ptr<VideoStreamInfo> CreateVideoStreamInfo(Codec codec) {
|
|||
kTrackId, kTimeScale, kDuration, codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kVideoExtraData,
|
||||
std::size(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
return stream_info;
|
||||
}
|
||||
|
||||
|
@ -358,8 +360,8 @@ TEST_F(PesPacketGeneratorTest, TimeStampScaling) {
|
|||
kTrackId, kTestTimescale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kVideoExtraData,
|
||||
std::size(kVideoExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
EXPECT_TRUE(generator_.Initialize(*stream_info));
|
||||
|
||||
EXPECT_EQ(0u, generator_.NumberOfReadyPesPackets());
|
||||
|
|
|
@ -45,6 +45,8 @@ const uint32_t kWidth = 1280;
|
|||
const uint32_t kHeight = 720;
|
||||
const uint32_t kPixelWidth = 1;
|
||||
const uint32_t kPixelHeight = 1;
|
||||
const uint8_t kColorPrimaries = 0;
|
||||
const uint8_t kMatrixCoefficients = 0;
|
||||
const uint8_t kTransferCharacteristics = 0;
|
||||
const uint16_t kTrickPlayFactor = 1;
|
||||
const uint8_t kNaluLengthSize = 1;
|
||||
|
@ -115,8 +117,8 @@ TEST_F(TsSegmenterTest, Initialize) {
|
|||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
std::size(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
options.segment_template = "file$Number$.ts";
|
||||
TsSegmenter segmenter(options, nullptr);
|
||||
|
@ -135,8 +137,8 @@ TEST_F(TsSegmenterTest, AddSample) {
|
|||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
std::size(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
options.segment_template = "file$Number$.ts";
|
||||
TsSegmenter segmenter(options, nullptr);
|
||||
|
@ -187,8 +189,8 @@ TEST_F(TsSegmenterTest, PassedSegmentDuration) {
|
|||
kTrackId, kInputTimescale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
std::size(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
options.segment_template = "memory://file$Number$.ts";
|
||||
|
||||
|
@ -269,8 +271,8 @@ TEST_F(TsSegmenterTest, InitializeThenFinalize) {
|
|||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
std::size(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
options.segment_template = "file$Number$.ts";
|
||||
TsSegmenter segmenter(options, nullptr);
|
||||
|
@ -297,8 +299,8 @@ TEST_F(TsSegmenterTest, FinalizeSegment) {
|
|||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
std::size(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
options.segment_template = "file$Number$.ts";
|
||||
TsSegmenter segmenter(options, nullptr);
|
||||
|
@ -324,8 +326,8 @@ TEST_F(TsSegmenterTest, EncryptedSample) {
|
|||
kTrackId, kTimeScale, kDuration, kH264Codec,
|
||||
H26xStreamFormat::kAnnexbByteStream, kCodecString, kExtraData,
|
||||
std::size(kExtraData), kWidth, kHeight, kPixelWidth, kPixelHeight,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
kIsEncrypted));
|
||||
kColorPrimaries, kMatrixCoefficients, kTransferCharacteristics,
|
||||
kTrickPlayFactor, kNaluLengthSize, kLanguage, kIsEncrypted));
|
||||
MuxerOptions options;
|
||||
|
||||
options.segment_template = "memory://file$Number$.ts";
|
||||
|
|
|
@ -1633,6 +1633,16 @@ bool VideoSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
|
|||
extra_codec_configs.push_back(std::move(dv_box));
|
||||
}
|
||||
}
|
||||
const bool is_av1 = actual_format == FOURCC_av01;
|
||||
if (is_av1) {
|
||||
for (FourCC fourcc : {FOURCC_dvvC}) {
|
||||
CodecConfiguration dv_box;
|
||||
dv_box.box_type = fourcc;
|
||||
RCHECK(buffer->TryReadWriteChild(&dv_box));
|
||||
if (!dv_box.data.empty())
|
||||
extra_codec_configs.push_back(std::move(dv_box));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (CodecConfiguration& extra_codec_config : extra_codec_configs)
|
||||
RCHECK(buffer->ReadWriteChild(&extra_codec_config));
|
||||
|
|
|
@ -37,6 +37,13 @@
|
|||
#include <packager/media/formats/mp4/box_reader.h>
|
||||
#include <packager/media/formats/mp4/track_run_iterator.h>
|
||||
|
||||
ABSL_FLAG(bool,
|
||||
use_dovi_supplemental_codecs,
|
||||
false,
|
||||
"Set to true to signal DolbyVision using the modern supplemental "
|
||||
"codecs approach instead of the legacy "
|
||||
"duplicate representations approach");
|
||||
|
||||
namespace shaka {
|
||||
namespace media {
|
||||
namespace mp4 {
|
||||
|
@ -156,6 +163,7 @@ bool UpdateCodecStringForDolbyVision(
|
|||
switch (actual_format) {
|
||||
case FOURCC_dvh1:
|
||||
case FOURCC_dvhe:
|
||||
case FOURCC_dav1:
|
||||
// Non-Backward compatibility mode. Replace the code string with
|
||||
// Dolby Vision only.
|
||||
*codec_string = dovi_config.GetCodecString(actual_format);
|
||||
|
@ -169,6 +177,9 @@ bool UpdateCodecStringForDolbyVision(
|
|||
// See above.
|
||||
*codec_string += ";" + dovi_config.GetCodecString(FOURCC_dvh1);
|
||||
break;
|
||||
case FOURCC_av01:
|
||||
*codec_string += ";" + dovi_config.GetCodecString(FOURCC_dav1);
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unsupported format with extra codec "
|
||||
<< FourCCToString(actual_format);
|
||||
|
@ -177,6 +188,48 @@ bool UpdateCodecStringForDolbyVision(
|
|||
return true;
|
||||
}
|
||||
|
||||
bool UpdateDolbyVisionInfo(FourCC actual_format,
|
||||
const std::vector<CodecConfiguration>& configs,
|
||||
uint8_t transfer_characteristics,
|
||||
std::string* codec_string,
|
||||
std::string* dovi_supplemental_codec_string,
|
||||
FourCC* dovi_compatible_brand) {
|
||||
DOVIDecoderConfigurationRecord dovi_config;
|
||||
if (!dovi_config.Parse(GetDOVIDecoderConfig(configs))) {
|
||||
LOG(ERROR) << "Failed to parse Dolby Vision decoder "
|
||||
"configuration record.";
|
||||
return false;
|
||||
}
|
||||
switch (actual_format) {
|
||||
case FOURCC_dvh1:
|
||||
case FOURCC_dvhe:
|
||||
case FOURCC_dav1:
|
||||
// Non-Backward compatibility mode. Replace the code string with
|
||||
// Dolby Vision only.
|
||||
*codec_string = dovi_config.GetCodecString(actual_format);
|
||||
break;
|
||||
case FOURCC_hev1:
|
||||
// Backward compatibility mode. Use supplemental codec indicating Dolby
|
||||
// Dolby Vision content.
|
||||
*dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dvhe);
|
||||
break;
|
||||
case FOURCC_hvc1:
|
||||
// See above.
|
||||
*dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dvh1);
|
||||
break;
|
||||
case FOURCC_av01:
|
||||
*dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dav1);
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR) << "Unsupported format with extra codec "
|
||||
<< FourCCToString(actual_format);
|
||||
return false;
|
||||
}
|
||||
*dovi_compatible_brand =
|
||||
dovi_config.GetDoViCompatibleBrand(transfer_characteristics);
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint64_t kNanosecondsPerSecond = 1000000000ull;
|
||||
|
||||
} // namespace
|
||||
|
@ -391,6 +444,9 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
|
||||
std::vector<std::shared_ptr<StreamInfo>> streams;
|
||||
|
||||
bool use_dovi_supplemental =
|
||||
absl::GetFlag(FLAGS_use_dovi_supplemental_codecs);
|
||||
|
||||
for (std::vector<Track>::const_iterator track = moov_->tracks.begin();
|
||||
track != moov_->tracks.end(); ++track) {
|
||||
const int32_t timescale = track->media.header.timescale;
|
||||
|
@ -604,8 +660,12 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
&pixel_height);
|
||||
}
|
||||
std::string codec_string;
|
||||
std::string dovi_supplemental_codec_string("");
|
||||
FourCC dovi_compatible_brand = FOURCC_NULL;
|
||||
uint8_t nalu_length_size = 0;
|
||||
uint8_t transfer_characteristics = 0;
|
||||
uint8_t color_primaries = 0;
|
||||
uint8_t matrix_coefficients = 0;
|
||||
|
||||
const FourCC actual_format = entry.GetActualFormat();
|
||||
const Codec video_codec = FourCCToCodec(actual_format);
|
||||
|
@ -618,13 +678,34 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
}
|
||||
// Generate the full codec string if the colr atom is present.
|
||||
if (entry.colr.color_parameter_type != FOURCC_NULL) {
|
||||
transfer_characteristics = entry.colr.transfer_characteristics;
|
||||
color_primaries = entry.colr.color_primaries;
|
||||
matrix_coefficients = entry.colr.matrix_coefficients;
|
||||
codec_string = av1_config.GetCodecString(
|
||||
entry.colr.color_primaries, entry.colr.transfer_characteristics,
|
||||
entry.colr.matrix_coefficients,
|
||||
color_primaries, transfer_characteristics, matrix_coefficients,
|
||||
entry.colr.video_full_range_flag);
|
||||
} else {
|
||||
codec_string = av1_config.GetCodecString();
|
||||
}
|
||||
|
||||
if (!entry.extra_codec_configs.empty()) {
|
||||
// |extra_codec_configs| is present only for Dolby Vision.
|
||||
if (use_dovi_supplemental) {
|
||||
if (!UpdateDolbyVisionInfo(
|
||||
actual_format, entry.extra_codec_configs,
|
||||
transfer_characteristics, &codec_string,
|
||||
&dovi_supplemental_codec_string,
|
||||
&dovi_compatible_brand)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!UpdateCodecStringForDolbyVision(actual_format,
|
||||
entry.extra_codec_configs,
|
||||
&codec_string)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FOURCC_avc1:
|
||||
|
@ -637,6 +718,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
codec_string = avc_config.GetCodecString(actual_format);
|
||||
nalu_length_size = avc_config.nalu_length_size();
|
||||
transfer_characteristics = avc_config.transfer_characteristics();
|
||||
color_primaries = avc_config.color_primaries();
|
||||
matrix_coefficients = avc_config.matrix_coefficients();
|
||||
|
||||
// Use configurations from |avc_config| if it is valid.
|
||||
if (avc_config.coded_width() != 0) {
|
||||
|
@ -685,13 +768,26 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
codec_string = hevc_config.GetCodecString(actual_format);
|
||||
nalu_length_size = hevc_config.nalu_length_size();
|
||||
transfer_characteristics = hevc_config.transfer_characteristics();
|
||||
color_primaries = hevc_config.color_primaries();
|
||||
matrix_coefficients = hevc_config.matrix_coefficients();
|
||||
|
||||
if (!entry.extra_codec_configs.empty()) {
|
||||
// |extra_codec_configs| is present only for Dolby Vision.
|
||||
if (!UpdateCodecStringForDolbyVision(
|
||||
actual_format, entry.extra_codec_configs, &codec_string)) {
|
||||
if (use_dovi_supplemental) {
|
||||
if (!UpdateDolbyVisionInfo(
|
||||
actual_format, entry.extra_codec_configs,
|
||||
transfer_characteristics, &codec_string,
|
||||
&dovi_supplemental_codec_string,
|
||||
&dovi_compatible_brand)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!UpdateCodecStringForDolbyVision(actual_format,
|
||||
entry.extra_codec_configs,
|
||||
&codec_string)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -733,10 +829,16 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
|
|||
track->header.track_id, timescale, duration, video_codec,
|
||||
GetH26xStreamFormat(actual_format), codec_string,
|
||||
codec_configuration_data.data(), codec_configuration_data.size(),
|
||||
coded_width, coded_height, pixel_width, pixel_height,
|
||||
transfer_characteristics,
|
||||
coded_width, coded_height, pixel_width, pixel_height, color_primaries,
|
||||
matrix_coefficients, transfer_characteristics,
|
||||
0, // trick_play_factor
|
||||
nalu_length_size, track->media.header.language.code, is_encrypted));
|
||||
|
||||
if (use_dovi_supplemental) {
|
||||
video_stream_info->set_supplemental_codec(
|
||||
dovi_supplemental_codec_string);
|
||||
video_stream_info->set_compatible_brand(dovi_compatible_brand);
|
||||
}
|
||||
video_stream_info->set_extra_config(entry.ExtraCodecConfigsAsVector());
|
||||
video_stream_info->set_colr_data((entry.colr.raw_box).data(),
|
||||
(entry.colr.raw_box).size());
|
||||
|
|
|
@ -12,11 +12,16 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <absl/flags/declare.h>
|
||||
#include <absl/flags/flag.h>
|
||||
|
||||
#include <packager/macros/classes.h>
|
||||
#include <packager/media/base/decryptor_source.h>
|
||||
#include <packager/media/base/media_parser.h>
|
||||
#include <packager/media/base/offset_byte_queue.h>
|
||||
|
||||
ABSL_DECLARE_FLAG(bool, use_dovi_supplemental_codecs);
|
||||
|
||||
namespace shaka {
|
||||
namespace media {
|
||||
namespace mp4 {
|
||||
|
|
|
@ -237,8 +237,22 @@ Status MP4Muxer::DelayInitializeMuxer() {
|
|||
ftyp->compatible_brands.push_back(codec_fourcc);
|
||||
|
||||
// https://professional.dolby.com/siteassets/content-creation/dolby-vision-for-content-creators/dolby_vision_bitstreams_within_the_iso_base_media_file_format_dec2017.pdf
|
||||
if (streams()[0].get()->codec_string().find("dvh") != std::string::npos)
|
||||
std::string codec_string =
|
||||
static_cast<const VideoStreamInfo*>(streams()[0].get())
|
||||
->codec_string();
|
||||
std::string supplemental_codec_string =
|
||||
static_cast<const VideoStreamInfo*>(streams()[0].get())
|
||||
->supplemental_codec();
|
||||
if (codec_string.find("dvh") != std::string::npos ||
|
||||
supplemental_codec_string.find("dvh") != std::string::npos ||
|
||||
codec_string.find("dav1") != std::string::npos ||
|
||||
supplemental_codec_string.find("dav1") != std::string::npos)
|
||||
ftyp->compatible_brands.push_back(FOURCC_dby1);
|
||||
FourCC extra_brand =
|
||||
static_cast<const VideoStreamInfo*>(streams()[0].get())
|
||||
->compatible_brand();
|
||||
if (extra_brand != FOURCC_NULL)
|
||||
ftyp->compatible_brands.push_back(extra_brand);
|
||||
}
|
||||
|
||||
// CMAF allows only one track/stream per file.
|
||||
|
|
|
@ -32,6 +32,8 @@ const uint16_t kWidth = 100;
|
|||
const uint16_t kHeight = 100;
|
||||
const uint16_t kPixelWidth = 100;
|
||||
const uint16_t kPixelHeight = 100;
|
||||
const uint8_t kColorPrimaries = 0;
|
||||
const uint8_t kMatrixCoefficients = 0;
|
||||
const uint8_t kTransferCharacteristics = 0;
|
||||
const int16_t kTrickPlayFactor = 1;
|
||||
const uint8_t kNaluLengthSize = 0;
|
||||
|
@ -88,8 +90,9 @@ VideoStreamInfo* SegmentTestBase::CreateVideoStreamInfo(
|
|||
return new VideoStreamInfo(
|
||||
kTrackId, time_scale, kDurationInSeconds * time_scale, kCodec,
|
||||
H26xStreamFormat::kUnSpecified, kCodecString, NULL, 0, kWidth, kHeight,
|
||||
kPixelWidth, kPixelHeight, kTransferCharacteristics, kTrickPlayFactor,
|
||||
kNaluLengthSize, kLanguage, false);
|
||||
kPixelWidth, kPixelHeight, kColorPrimaries, kMatrixCoefficients,
|
||||
kTransferCharacteristics, kTrickPlayFactor, kNaluLengthSize, kLanguage,
|
||||
false);
|
||||
}
|
||||
|
||||
std::string SegmentTestBase::OutputFileName() const {
|
||||
|
|
|
@ -94,6 +94,8 @@ const uint16_t kWidth = 320u;
|
|||
const uint16_t kHeight = 180u;
|
||||
const uint32_t kPixelWidth = 1u;
|
||||
const uint32_t kPixelHeight = 1u;
|
||||
const uint8_t kColorPrimaries = 0;
|
||||
const uint8_t kMatrixCoefficients = 0;
|
||||
const uint8_t kTransferCharacteristics = 0;
|
||||
const int16_t kTrickPlayFactor = 0;
|
||||
const uint8_t kNaluLengthSize = 0u;
|
||||
|
@ -354,6 +356,8 @@ class WebMClusterParserTest : public testing::Test {
|
|||
kHeight,
|
||||
kPixelWidth,
|
||||
kPixelHeight,
|
||||
kColorPrimaries,
|
||||
kMatrixCoefficients,
|
||||
kTransferCharacteristics,
|
||||
kTrickPlayFactor,
|
||||
kNaluLengthSize,
|
||||
|
|
|
@ -125,8 +125,8 @@ std::shared_ptr<VideoStreamInfo> WebMVideoClient::GetVideoStreamInfo(
|
|||
return std::make_shared<VideoStreamInfo>(
|
||||
track_num, kWebMTimeScale, 0, video_codec, H26xStreamFormat::kUnSpecified,
|
||||
codec_string, codec_private.data(), codec_private.size(),
|
||||
width_after_crop, height_after_crop, pixel_width, pixel_height, 0, 0,
|
||||
0 /* transfer_characteristics */, std::string(), is_encrypted);
|
||||
width_after_crop, height_after_crop, pixel_width, pixel_height, 0, 0, 0,
|
||||
0, 0, std::string(), is_encrypted);
|
||||
}
|
||||
|
||||
VPCodecConfigurationRecord WebMVideoClient::GetVpCodecConfig(
|
||||
|
|
|
@ -744,9 +744,10 @@ bool WvmMediaParser::ParseIndexEntry() {
|
|||
stream_id_count_, time_scale, track_duration, kCodecH264,
|
||||
byte_to_unit_stream_converter_.stream_format(), std::string(),
|
||||
video_codec_config.data(), video_codec_config.size(), video_width,
|
||||
video_height, pixel_width, pixel_height,
|
||||
0 /* transfer_characteristics */, trick_play_factor, nalu_length_size,
|
||||
std::string(), decryption_key_source_ ? false : true));
|
||||
video_height, pixel_width, pixel_height, 0 /* color_primaries */,
|
||||
0 /*matrix_coefficients */, 0 /* transfer_characteristics */,
|
||||
trick_play_factor, nalu_length_size, std::string(),
|
||||
decryption_key_source_ ? false : true));
|
||||
program_demux_stream_map_[absl::StrFormat(
|
||||
"%u:%u", index_program_id_,
|
||||
video_pes_stream_id ? video_pes_stream_id : kDefaultVideoStreamId)] =
|
||||
|
|
Binary file not shown.
|
@ -382,6 +382,22 @@ std::optional<xml::XmlNode> AdaptationSet::GetXml() {
|
|||
}
|
||||
}
|
||||
|
||||
// https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf - 4.2.5.1
|
||||
if (IsVideo() && matrix_coefficients_ > 0 &&
|
||||
!adaptation_set.AddSupplementalProperty(
|
||||
"urn:mpeg:mpegB:cicp:MatrixCoefficients",
|
||||
std::to_string(matrix_coefficients_))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf - 4.2.5.1
|
||||
if (IsVideo() && color_primaries_ > 0 &&
|
||||
!adaptation_set.AddSupplementalProperty(
|
||||
"urn:mpeg:mpegB:cicp:ColourPrimaries",
|
||||
std::to_string(color_primaries_))) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// https://dashif.org/docs/DASH-IF-IOP-v4.3.pdf - 4.2.5.1
|
||||
if (IsVideo() && transfer_characteristics_ > 0 &&
|
||||
!adaptation_set.AddSupplementalProperty(
|
||||
|
|
|
@ -203,6 +203,24 @@ class AdaptationSet {
|
|||
/// @param codec is the new codec to be set.
|
||||
void set_codec(const std::string& codec) { codec_ = codec; };
|
||||
|
||||
/// @return matrix_coefficients.
|
||||
uint32_t matrix_coefficients() const { return matrix_coefficients_; }
|
||||
|
||||
/// Set AdaptationSet's video matrix coefficients.
|
||||
/// @param matrix_coefficients is the video matrix coefficients.
|
||||
void set_matrix_coefficients(const uint32_t& matrix_coefficients) {
|
||||
matrix_coefficients_ = matrix_coefficients;
|
||||
};
|
||||
|
||||
/// @return color_primaries.
|
||||
uint32_t color_primaries() const { return color_primaries_; }
|
||||
|
||||
/// Set AdaptationSet's video colour primaries.
|
||||
/// @param color_primaries is the video colour primaries.
|
||||
void set_color_primaries(const uint32_t& color_primaries) {
|
||||
color_primaries_ = color_primaries;
|
||||
};
|
||||
|
||||
/// @return transfer_characteristics.
|
||||
uint32_t transfer_characteristics() const {
|
||||
return transfer_characteristics_;
|
||||
|
@ -378,6 +396,11 @@ class AdaptationSet {
|
|||
// stream.
|
||||
std::vector<const AdaptationSet*> trick_play_references_;
|
||||
|
||||
// Matrix Coefficients.
|
||||
uint32_t matrix_coefficients_ = 0;
|
||||
// Colour Primaries.
|
||||
uint32_t color_primaries_ = 0;
|
||||
|
||||
// Transfer characteristics.
|
||||
uint32_t transfer_characteristics_ = 0;
|
||||
|
||||
|
|
|
@ -49,6 +49,12 @@ message MediaInfo {
|
|||
// Transfer characteristics. Useful to determine the VIDEO-RANGE for HLS,
|
||||
// i.e. whether it is SDR or HDR.
|
||||
optional uint32 transfer_characteristics = 10;
|
||||
optional uint32 color_primaries = 11;
|
||||
optional uint32 matrix_coefficients = 12;
|
||||
|
||||
// Fro Dolby Vision back compatiable content.
|
||||
optional string supplemental_codec = 13;
|
||||
optional uint32 compatible_brand = 14;
|
||||
}
|
||||
|
||||
message AudioInfo {
|
||||
|
|
|
@ -53,12 +53,12 @@ bool AddMpdNameSpaceInfo(XmlNode* mpd) {
|
|||
"urn:marlin:mas:1-0:services:schemas:mpd";
|
||||
static const char kXmlNamespaceXlink[] = "http://www.w3.org/1999/xlink";
|
||||
static const char kMsprNamespace[] = "urn:microsoft:playready";
|
||||
static const char kScte214Namespace[] = "urn:scte:dash:scte214-extensions";
|
||||
|
||||
const std::map<std::string, std::string> uris = {
|
||||
{"cenc", kCencNamespace},
|
||||
{"mas", kMarlinNamespace},
|
||||
{"xlink", kXmlNamespaceXlink},
|
||||
{"mspr", kMsprNamespace},
|
||||
{"cenc", kCencNamespace}, {"mas", kMarlinNamespace},
|
||||
{"xlink", kXmlNamespaceXlink}, {"mspr", kMsprNamespace},
|
||||
{"scte214", kScte214Namespace},
|
||||
};
|
||||
|
||||
for (const std::string& namespace_name : namespaces) {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <libxml/tree.h>
|
||||
|
||||
#include <packager/macros/logging.h>
|
||||
#include <packager/media/base/fourccs.h>
|
||||
#include <packager/media/base/language_utils.h>
|
||||
#include <packager/media/base/protection_system_specific_info.h>
|
||||
#include <packager/mpd/base/adaptation_set.h>
|
||||
|
@ -128,6 +129,29 @@ std::string GetCodecs(const MediaInfo& media_info) {
|
|||
return "";
|
||||
}
|
||||
|
||||
std::string GetSupplementalCodecs(const MediaInfo& media_info) {
|
||||
CHECK(OnlyOneTrue(media_info.has_video_info(), media_info.has_audio_info(),
|
||||
media_info.has_text_info()));
|
||||
|
||||
if (media_info.has_video_info() &&
|
||||
media_info.video_info().has_supplemental_codec()) {
|
||||
return media_info.video_info().supplemental_codec();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string GetSupplementalProfiles(const MediaInfo& media_info) {
|
||||
CHECK(OnlyOneTrue(media_info.has_video_info(), media_info.has_audio_info(),
|
||||
media_info.has_text_info()));
|
||||
|
||||
if (media_info.has_video_info() &&
|
||||
media_info.video_info().has_compatible_brand()) {
|
||||
return FourCCToString(
|
||||
static_cast<media::FourCC>(media_info.video_info().compatible_brand()));
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string GetBaseCodec(const MediaInfo& media_info) {
|
||||
std::string codec;
|
||||
if (media_info.has_video_info()) {
|
||||
|
|
|
@ -27,6 +27,7 @@ const char kEncryptedMp4Scheme[] = "urn:mpeg:dash:mp4protection:2011";
|
|||
const char kPsshElementName[] = "cenc:pssh";
|
||||
const char kMsproElementName[] = "mspr:pro";
|
||||
const uint32_t kTransferFunctionPQ = 16;
|
||||
const uint32_t kTransferFunctionHLG = 18;
|
||||
|
||||
bool HasVODOnlyFields(const MediaInfo& media_info);
|
||||
|
||||
|
@ -45,6 +46,10 @@ std::string GetLanguage(const MediaInfo& media_info);
|
|||
// comma.
|
||||
std::string GetCodecs(const MediaInfo& media_info);
|
||||
|
||||
std::string GetSupplementalCodecs(const MediaInfo& media_info);
|
||||
|
||||
std::string GetSupplementalProfiles(const MediaInfo& media_info);
|
||||
|
||||
// Returns a codec string without variants. For example, "mp4a" instead of
|
||||
// "mp4a.40.2". May return a format for text streams.
|
||||
std::string GetBaseCodec(const MediaInfo& media_info);
|
||||
|
|
|
@ -272,6 +272,11 @@ bool Period::SetNewAdaptationSetAttributes(
|
|||
new_adaptation_set->set_transfer_characteristics(
|
||||
media_info.video_info().transfer_characteristics());
|
||||
}
|
||||
|
||||
new_adaptation_set->set_matrix_coefficients(
|
||||
media_info.video_info().matrix_coefficients());
|
||||
new_adaptation_set->set_color_primaries(
|
||||
media_info.video_info().color_primaries());
|
||||
} else if (media_info.has_audio_info()) {
|
||||
if (codec == "mp4a" || codec == "ac-3" || codec == "ec-3" ||
|
||||
codec == "ac-4") {
|
||||
|
|
|
@ -151,6 +151,8 @@ bool Representation::Init() {
|
|||
return false;
|
||||
|
||||
codecs_ = GetCodecs(media_info_);
|
||||
supplemental_codecs_ = GetSupplementalCodecs(media_info_);
|
||||
supplemental_profiles_ = GetSupplementalProfiles(media_info_);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -270,6 +272,16 @@ std::optional<xml::XmlNode> Representation::GetXml() {
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!supplemental_codecs_.empty() && !supplemental_profiles_.empty()) {
|
||||
if (!representation.SetStringAttribute("scte214:supplementalCodecs",
|
||||
supplemental_codecs_) ||
|
||||
!representation.SetStringAttribute("scte214:supplementalProfiles",
|
||||
supplemental_profiles_)) {
|
||||
LOG(ERROR) << "Failed to add supplemental codecs/profiles to "
|
||||
"Representation XML.";
|
||||
}
|
||||
}
|
||||
|
||||
const bool has_video_info = media_info_.has_video_info();
|
||||
const bool has_audio_info = media_info_.has_audio_info();
|
||||
|
||||
|
|
|
@ -249,6 +249,8 @@ class Representation {
|
|||
const uint32_t id_;
|
||||
std::string mime_type_;
|
||||
std::string codecs_;
|
||||
std::string supplemental_codecs_;
|
||||
std::string supplemental_profiles_;
|
||||
BandwidthEstimator bandwidth_estimator_;
|
||||
const MpdOptions& mpd_options_;
|
||||
|
||||
|
|
Loading…
Reference in New Issue