From 3e7dda485e432a27c5fff5ac3dbfd850bc9d0680 Mon Sep 17 00:00:00 2001 From: Cosmin Stejerean Date: Thu, 9 May 2024 13:50:20 -0700 Subject: [PATCH] parse primaries and matrix coefficients and include them in the MPD for DASH --- .../output.mpd | 2 ++ .../output.mpd | 2 ++ .../output.mpd | 2 ++ .../output.mpd | 4 +++ .../testdata/hdr10-with-encryption/output.mpd | 2 ++ .../media/base/media_handler_test_base.cc | 8 ++++-- packager/media/base/video_stream_info.cc | 4 +++ packager/media/base/video_stream_info.h | 12 +++++++++ .../codecs/decoder_configuration_record.h | 18 +++++++++++++ packager/media/codecs/h264_parser.cc | 4 +-- packager/media/codecs/h264_parser.h | 2 ++ packager/media/codecs/h265_parser.cc | 6 +++-- packager/media/codecs/h265_parser.h | 2 ++ .../hevc_decoder_configuration_record.cc | 4 +++ .../crypto/subsample_generator_unittest.cc | 7 +++-- .../media/event/muxer_listener_internal.cc | 7 +++++ .../media/event/muxer_listener_test_helper.cc | 2 ++ packager/media/formats/mp2t/es_parser_h264.cc | 3 ++- packager/media/formats/mp2t/es_parser_h265.cc | 6 +++-- .../mp2t/pes_packet_generator_unittest.cc | 10 ++++--- .../formats/mp2t/ts_segmenter_unittest.cc | 26 ++++++++++--------- .../media/formats/mp4/mp4_media_parser.cc | 15 ++++++++--- .../media/formats/webm/segmenter_test_base.cc | 7 +++-- .../webm/webm_cluster_parser_unittest.cc | 4 +++ .../media/formats/webm/webm_video_client.cc | 4 +-- .../media/formats/wvm/wvm_media_parser.cc | 7 ++--- packager/mpd/base/adaptation_set.cc | 16 ++++++++++++ packager/mpd/base/adaptation_set.h | 23 ++++++++++++++++ packager/mpd/base/media_info.proto | 6 +++-- packager/mpd/base/mpd_utils.h | 1 + packager/mpd/base/period.cc | 5 ++++ 31 files changed, 181 insertions(+), 40 deletions(-) diff --git a/packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.mpd b/packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.mpd index 1e37b7b1450..2a43ee4e413 100644 --- a/packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.mpd +++ b/packager/app/test/testdata/dolby-vision-profile-10-supplemental-codecs/output.mpd @@ -3,6 +3,8 @@ + + sparks_dovi_10-video.mp4 diff --git a/packager/app/test/testdata/dolby-vision-profile-5-with-encryption/output.mpd b/packager/app/test/testdata/dolby-vision-profile-5-with-encryption/output.mpd index 300d51637a4..da522e3591e 100644 --- a/packager/app/test/testdata/dolby-vision-profile-5-with-encryption/output.mpd +++ b/packager/app/test/testdata/dolby-vision-profile-5-with-encryption/output.mpd @@ -3,6 +3,8 @@ + + diff --git a/packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.mpd b/packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.mpd index ed9040f2bef..5d06e41c784 100644 --- a/packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.mpd +++ b/packager/app/test/testdata/dolby-vision-profile-8-supplemental-codecs/output.mpd @@ -3,6 +3,8 @@ + + sparks_dovi_8-video.mp4 diff --git a/packager/app/test/testdata/dolby-vision-profile-8-with-encryption/output.mpd b/packager/app/test/testdata/dolby-vision-profile-8-with-encryption/output.mpd index 0acbe5ca43c..7f5da8fad93 100644 --- a/packager/app/test/testdata/dolby-vision-profile-8-with-encryption/output.mpd +++ b/packager/app/test/testdata/dolby-vision-profile-8-with-encryption/output.mpd @@ -3,6 +3,8 @@ + + @@ -16,6 +18,8 @@ + + diff --git a/packager/app/test/testdata/hdr10-with-encryption/output.mpd b/packager/app/test/testdata/hdr10-with-encryption/output.mpd index af2733fe848..3eaf56c203d 100644 --- a/packager/app/test/testdata/hdr10-with-encryption/output.mpd +++ b/packager/app/test/testdata/hdr10-with-encryption/output.mpd @@ -3,6 +3,8 @@ + + diff --git a/packager/media/base/media_handler_test_base.cc b/packager/media/base/media_handler_test_base.cc index 8a5a7d1e033..a9c78f91009 100644 --- a/packager/media/base/media_handler_test_base.cc +++ b/packager/media/base/media_handler_test_base.cc @@ -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 MediaHandlerTestBase::GetVideoStreamInfo( return std::unique_ptr(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 MediaHandlerTestBase::GetAudioStreamInfo( diff --git a/packager/media/base/video_stream_info.cc b/packager/media/base/video_stream_info.cc index 1512ce83c2d..b557482bf2e 100644 --- a/packager/media/base/video_stream_info.cc +++ b/packager/media/base/video_stream_info.cc @@ -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) {} diff --git a/packager/media/base/video_stream_info.h b/packager/media/base/video_stream_info.h index 533a204d297..8f5e705ee4f 100644 --- a/packager/media/base/video_stream_info.h +++ b/packager/media/base/video_stream_info.h @@ -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, @@ -67,6 +69,8 @@ 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_; } @@ -91,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; } @@ -120,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 diff --git a/packager/media/codecs/decoder_configuration_record.h b/packager/media/codecs/decoder_configuration_record.h index b826484e719..45221cf5281 100644 --- a/packager/media/codecs/decoder_configuration_record.h +++ b/packager/media/codecs/decoder_configuration_record.h @@ -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); }; diff --git a/packager/media/codecs/h264_parser.cc b/packager/media/codecs/h264_parser.cc index 8b86133b1de..c25dcbb0c9d 100644 --- a/packager/media/codecs/h264_parser.cc +++ b/packager/media/codecs/h264_parser.cc @@ -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 } } diff --git a/packager/media/codecs/h264_parser.h b/packager/media/codecs/h264_parser.h index 423fe5a40d4..2752e31a388 100644 --- a/packager/media/codecs/h264_parser.h +++ b/packager/media/codecs/h264_parser.h @@ -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; diff --git a/packager/media/codecs/h265_parser.cc b/packager/media/codecs/h265_parser.cc index bd7f2a411ce..7c3cab7bf51 100644 --- a/packager/media/codecs/h265_parser.cc +++ b/packager/media/codecs/h265_parser.cc @@ -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 } } diff --git a/packager/media/codecs/h265_parser.h b/packager/media/codecs/h265_parser.h index a36f82e8abc..febb2e0731d 100644 --- a/packager/media/codecs/h265_parser.h +++ b/packager/media/codecs/h265_parser.h @@ -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; diff --git a/packager/media/codecs/hevc_decoder_configuration_record.cc b/packager/media/codecs/hevc_decoder_configuration_record.cc index 9fef0fe06e1..f171fa56fce 100644 --- a/packager/media/codecs/hevc_decoder_configuration_record.cc +++ b/packager/media/codecs/hevc_decoder_configuration_record.cc @@ -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); } } } diff --git a/packager/media/crypto/subsample_generator_unittest.cc b/packager/media/crypto/subsample_generator_unittest.cc index c384f45adf6..e12dc721166 100644 --- a/packager/media/crypto/subsample_generator_unittest.cc +++ b/packager/media/crypto/subsample_generator_unittest.cc @@ -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) { diff --git a/packager/media/event/muxer_listener_internal.cc b/packager/media/event/muxer_listener_internal.cc index 7f343f23347..0bc150fd0cf 100644 --- a/packager/media/event/muxer_listener_internal.cc +++ b/packager/media/event/muxer_listener_internal.cc @@ -98,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, diff --git a/packager/media/event/muxer_listener_test_helper.cc b/packager/media/event/muxer_listener_test_helper.cc index 9225f71e880..f8029763446 100644 --- a/packager/media/event/muxer_listener_test_helper.cc +++ b/packager/media/event/muxer_listener_test_helper.cc @@ -23,6 +23,8 @@ std::shared_ptr 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); diff --git a/packager/media/formats/mp2t/es_parser_h264.cc b/packager/media/formats/mp2t/es_parser_h264.cc index e450c81202c..eb4eec2d1e8 100644 --- a/packager/media/formats/mp2t/es_parser_h264.cc +++ b/packager/media/formats/mp2t/es_parser_h264.cc @@ -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; diff --git a/packager/media/formats/mp2t/es_parser_h265.cc b/packager/media/formats/mp2t/es_parser_h265.cc index 319ce47bcff..b89dd3f3f4b 100644 --- a/packager/media/formats/mp2t/es_parser_h265.cc +++ b/packager/media/formats/mp2t/es_parser_h265.cc @@ -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_); diff --git a/packager/media/formats/mp2t/pes_packet_generator_unittest.cc b/packager/media/formats/mp2t/pes_packet_generator_unittest.cc index c47e8aa53f8..c3cb0021e08 100644 --- a/packager/media/formats/mp2t/pes_packet_generator_unittest.cc +++ b/packager/media/formats/mp2t/pes_packet_generator_unittest.cc @@ -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 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()); diff --git a/packager/media/formats/mp2t/ts_segmenter_unittest.cc b/packager/media/formats/mp2t/ts_segmenter_unittest.cc index 7751e1a5619..3f34856e226 100644 --- a/packager/media/formats/mp2t/ts_segmenter_unittest.cc +++ b/packager/media/formats/mp2t/ts_segmenter_unittest.cc @@ -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"; diff --git a/packager/media/formats/mp4/mp4_media_parser.cc b/packager/media/formats/mp4/mp4_media_parser.cc index 3b072dc434c..7aac01590f3 100644 --- a/packager/media/formats/mp4/mp4_media_parser.cc +++ b/packager/media/formats/mp4/mp4_media_parser.cc @@ -664,6 +664,8 @@ bool MP4MediaParser::ParseMoov(BoxReader* reader) { 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); @@ -677,9 +679,10 @@ 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(); @@ -715,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) { @@ -763,6 +768,8 @@ 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. @@ -822,8 +829,8 @@ 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)); diff --git a/packager/media/formats/webm/segmenter_test_base.cc b/packager/media/formats/webm/segmenter_test_base.cc index 9e2ef8d5118..c965e269157 100644 --- a/packager/media/formats/webm/segmenter_test_base.cc +++ b/packager/media/formats/webm/segmenter_test_base.cc @@ -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 { diff --git a/packager/media/formats/webm/webm_cluster_parser_unittest.cc b/packager/media/formats/webm/webm_cluster_parser_unittest.cc index a287932dfd6..9a3f353d9df 100644 --- a/packager/media/formats/webm/webm_cluster_parser_unittest.cc +++ b/packager/media/formats/webm/webm_cluster_parser_unittest.cc @@ -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, diff --git a/packager/media/formats/webm/webm_video_client.cc b/packager/media/formats/webm/webm_video_client.cc index fb8dc13142e..be83cee922c 100644 --- a/packager/media/formats/webm/webm_video_client.cc +++ b/packager/media/formats/webm/webm_video_client.cc @@ -125,8 +125,8 @@ std::shared_ptr WebMVideoClient::GetVideoStreamInfo( return std::make_shared( 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( diff --git a/packager/media/formats/wvm/wvm_media_parser.cc b/packager/media/formats/wvm/wvm_media_parser.cc index c66e921b090..41d98cb1290 100644 --- a/packager/media/formats/wvm/wvm_media_parser.cc +++ b/packager/media/formats/wvm/wvm_media_parser.cc @@ -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)] = diff --git a/packager/mpd/base/adaptation_set.cc b/packager/mpd/base/adaptation_set.cc index 52ef7f55690..5ad8e33fa05 100644 --- a/packager/mpd/base/adaptation_set.cc +++ b/packager/mpd/base/adaptation_set.cc @@ -384,6 +384,22 @@ std::optional 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( diff --git a/packager/mpd/base/adaptation_set.h b/packager/mpd/base/adaptation_set.h index d2bf228a0af..c49cd247944 100644 --- a/packager/mpd/base/adaptation_set.h +++ b/packager/mpd/base/adaptation_set.h @@ -198,6 +198,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_; @@ -373,6 +391,11 @@ class AdaptationSet { // stream. std::vector trick_play_references_; + // Matrix Coefficients. + uint32_t matrix_coefficients_ = 0; + // Colour Primaries. + uint32_t color_primaries_ = 0; + // Transfer characteristics. uint32_t transfer_characteristics_ = 0; diff --git a/packager/mpd/base/media_info.proto b/packager/mpd/base/media_info.proto index 79c91f8684c..61afe6a18de 100644 --- a/packager/mpd/base/media_info.proto +++ b/packager/mpd/base/media_info.proto @@ -49,10 +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 = 11; - optional uint32 compatible_brand = 12; + optional string supplemental_codec = 13; + optional uint32 compatible_brand = 14; } message AudioInfo { diff --git a/packager/mpd/base/mpd_utils.h b/packager/mpd/base/mpd_utils.h index 7c687dde750..4e944b0d27c 100644 --- a/packager/mpd/base/mpd_utils.h +++ b/packager/mpd/base/mpd_utils.h @@ -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); diff --git a/packager/mpd/base/period.cc b/packager/mpd/base/period.cc index 249bbdb9611..9faafccc787 100644 --- a/packager/mpd/base/period.cc +++ b/packager/mpd/base/period.cc @@ -269,6 +269,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") {