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 signaling for HLS #1255

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packager/hls/base/master_playlist.cc
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,16 @@ void BuildStreamInfTag(const MediaPlaylist& playlist,
variant.text_codecs.end());
tag.AddQuotedString("CODECS", base::JoinString(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",
base::JoinString(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 @@ -380,6 +380,14 @@ 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 @@ -560,10 +568,22 @@ 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 15:
return "SDR";
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 temp solution.
if (!supplemental_codec_.empty() && compatible_brand_ == media::FOURCC_db4g)
return "HLG";
else
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 @@ -16,6 +16,7 @@
#include "packager/hls/public/hls_params.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 @@ -79,6 +80,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 @@ -258,6 +261,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_;
uint32_t media_sequence_number_ = 0;
Expand Down
6 changes: 5 additions & 1 deletion packager/media/base/fourccs.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ enum FourCC : uint32_t {
FOURCC_dac3 = 0x64616333,
FOURCC_dac4 = 0x64616334,
FOURCC_dash = 0x64617368,
FOURCC_dby1 = 0x64627931,
FOURCC_db1p = 0x64623170, // "db1p"
FOURCC_db2g = 0x64623267, // "db2g"
FOURCC_db4g = 0x64623467, // "db4g"
FOURCC_db4h = 0x64623468, // "db4h"
FOURCC_dby1 = 0x64627931, // "dby1"
FOURCC_ddts = 0x64647473,
FOURCC_dec3 = 0x64656333,
FOURCC_dfLa = 0x64664c61,
Expand Down
10 changes: 10 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_; }
uint16_t width() const { return width_; }
Expand All @@ -70,6 +72,12 @@ class VideoStreamInfo : public StreamInfo {
uint32_t playback_rate() const { return playback_rate_; }
const std::vector<uint8_t>& eme_init_data() const { return eme_init_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 All @@ -94,6 +102,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_;
std::vector<uint8_t> extra_config_;
H26xStreamFormat h26x_stream_format_;
uint16_t width_;
Expand Down
24 changes: 23 additions & 1 deletion packager/media/codecs/dovi_decoder_configuration_record.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ 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 @@ -34,5 +35,26 @@ std::string DOVIDecoderConfigurationRecord::GetCodecString(
"%s.%02d.%02d", FourCCToString(codec_fourcc).c_str(), 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;
}
else if (transfer_characteristics == 18) {
return FOURCC_db4h;
}
default:
return FOURCC_NULL;
}
return FOURCC_NULL;
}

} // namespace media
} // namespace shaka
4 changes: 4 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,17 @@ 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
2 changes: 2 additions & 0 deletions packager/media/event/muxer_listener_internal.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,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());
Expand Down
27 changes: 19 additions & 8 deletions packager/media/formats/mp4/mp4_media_parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,13 @@ std::vector<uint8_t> GetDOVIDecoderConfig(
return std::vector<uint8_t>();
}

bool UpdateCodecStringForDolbyVision(
bool UpdateDolbyVisionInfo(
FourCC actual_format,
const std::vector<CodecConfiguration>& configs,
std::string* codec_string) {
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 "
Expand All @@ -155,19 +158,21 @@ bool UpdateCodecStringForDolbyVision(
*codec_string = dovi_config.GetCodecString(actual_format);
break;
case FOURCC_hev1:
// Backward compatibility mode. Two codecs are signalled: base codec
// without Dolby Vision and HDR with Dolby Vision.
*codec_string += ";" + dovi_config.GetCodecString(FOURCC_dvhe);
// 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.
*codec_string += ";" + dovi_config.GetCodecString(FOURCC_dvh1);
*dovi_supplemental_codec_string = dovi_config.GetCodecString(FOURCC_dvh1);
break;
default:
LOG(ERROR) << "Unsupported format with extra codec "
<< FourCCToString(actual_format);
return false;
}
*dovi_compatible_brand =
dovi_config.GetDoViCompatibleBrand(transfer_characteristics);
return true;
}

Expand Down Expand Up @@ -592,6 +597,8 @@ 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;

Expand Down Expand Up @@ -676,8 +683,10 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {

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 (!UpdateDolbyVisionInfo(actual_format, entry.extra_codec_configs,
transfer_characteristics, &codec_string,
&dovi_supplemental_codec_string,
&dovi_compatible_brand)) {
return false;
}
}
Expand Down Expand Up @@ -725,6 +734,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) {
transfer_characteristics,
0, // trick_play_factor
nalu_length_size, track->media.header.language.code, is_encrypted));
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());

// Set pssh raw data if it has.
Expand Down
12 changes: 11 additions & 1 deletion packager/media/formats/mp4/mp4_muxer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,18 @@ 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)
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.
Expand Down
5 changes: 5 additions & 0 deletions packager/mpd/base/media_info.proto
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ 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;

// supplemental_codec/compatible_brand is used for SUPPLEMENTAL-CODECS for
// HLS. It's useful for Dolby Vision back compatiable content.
optional string supplemental_codec = 11;
optional uint32 compatible_brand = 12;
}

message AudioInfo {
Expand Down
Loading