Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support Dolby Vision profile 8.x (HEVC) and 10.x (AV1) in HLS and DASH #1396

Merged
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
42 changes: 41 additions & 1 deletion packager/app/test/packager_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,8 @@ def _GetFlags(self,
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:
Expand Down Expand Up @@ -544,6 +545,9 @@ def _GetFlags(self,
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:
Expand Down Expand Up @@ -1456,6 +1460,42 @@ def testDolbyVisionProfile8WithEncryption(self):
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',
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?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="scte214" 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: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>
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?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="scte214" 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: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>
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 9 additions & 0 deletions packager/hls/base/master_playlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
22 changes: 21 additions & 1 deletion packager/hls/base/media_playlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions packager/hls/base/media_playlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion packager/hls/base/media_playlist_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions packager/media/base/fourccs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions packager/media/base/video_stream_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,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_; }
Expand All @@ -71,6 +73,14 @@ class VideoStreamInfo : public StreamInfo {
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;
}
Expand Down Expand Up @@ -98,6 +108,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_;
Expand Down
23 changes: 22 additions & 1 deletion packager/media/codecs/dovi_decoder_configuration_record.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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
5 changes: 5 additions & 0 deletions packager/media/codecs/dovi_decoder_configuration_record.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ 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;
DOVIDecoderConfigurationRecord& operator=(
const DOVIDecoderConfigurationRecord&) = delete;

uint8_t profile_ = 0;
uint8_t bl_signal_compatibility_id_ = 0;
uint8_t level_ = 0;
};

Expand Down
10 changes: 10 additions & 0 deletions packager/media/event/mpd_notify_muxer_listener_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down Expand Up @@ -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"
Expand Down