diff --git a/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd b/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd index 95bb75d440..7d3209934b 100644 --- a/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-320x240-opus-vp9-cenc-golden.mpd @@ -20,10 +20,10 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_video.mp4 - - + + diff --git a/packager/app/test/testdata/bear-320x240-vp9-cenc-golden.mp4 b/packager/app/test/testdata/bear-320x240-vp9-cenc-golden.mp4 index 32e9992269..3b3ccc2494 100644 Binary files a/packager/app/test/testdata/bear-320x240-vp9-cenc-golden.mp4 and b/packager/app/test/testdata/bear-320x240-vp9-cenc-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-320x240-vp9-golden.mp4 b/packager/app/test/testdata/bear-320x240-vp9-golden.mp4 index 9c5af5948a..eb37055756 100644 Binary files a/packager/app/test/testdata/bear-320x240-vp9-golden.mp4 and b/packager/app/test/testdata/bear-320x240-vp9-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-320x240-vp9-golden.webm b/packager/app/test/testdata/bear-320x240-vp9-golden.webm index 0618a8009c..bf9c2ee34c 100644 Binary files a/packager/app/test/testdata/bear-320x240-vp9-golden.webm and b/packager/app/test/testdata/bear-320x240-vp9-golden.webm differ diff --git a/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd b/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd index d6994a1f04..e3b2257434 100644 --- a/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd +++ b/packager/app/test/testdata/bear-320x240-vp9-opus-webm-golden.mpd @@ -12,10 +12,10 @@ - + output_video.webm - - + + diff --git a/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mp4 b/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mp4 index 81c04f212c..6608e03f64 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mp4 and b/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mpd b/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mpd index 893418c5f6..108e3c3a47 100644 --- a/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mpd +++ b/packager/app/test/testdata/bear-640x360-vp8-cenc-golden.mpd @@ -7,10 +7,10 @@ AAAANHBzc2gBAAAAEHfv7MCyTQKs4zweUuL7SwAAAAExMjM0NTY3ODkwMTIzNDU2AAAAAA== - + output_video.mp4 - - + + diff --git a/packager/app/test/testdata/bear-640x360-vp8-golden.mp4 b/packager/app/test/testdata/bear-640x360-vp8-golden.mp4 index 3c7843fb39..8c51125bac 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp8-golden.mp4 and b/packager/app/test/testdata/bear-640x360-vp8-golden.mp4 differ diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm index ae1c97b480..ef57017720 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm and b/packager/app/test/testdata/bear-640x360-vp9-altref-dec-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm index 6493afa80c..997c263a72 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm and b/packager/app/test/testdata/bear-640x360-vp9-altref-enc-golden.webm differ diff --git a/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm b/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm index b08ea493af..83046b2036 100644 Binary files a/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm and b/packager/app/test/testdata/bear-640x360-vp9-fullsample-enc-golden.webm differ diff --git a/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm b/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm index aeda2e9b36..d9a6961ca6 100644 Binary files a/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm and b/packager/app/test/testdata/bear-vp9-blockgroup-golden.webm differ diff --git a/packager/media/codecs/vp8_parser.cc b/packager/media/codecs/vp8_parser.cc index b925e54c2d..6a7b0f4c8b 100644 --- a/packager/media/codecs/vp8_parser.cc +++ b/packager/media/codecs/vp8_parser.cc @@ -154,10 +154,6 @@ bool VP8Parser::Parse(const uint8_t* data, writable_codec_config()->set_bit_depth(8); writable_codec_config()->set_chroma_subsampling( VPCodecConfigurationRecord::CHROMA_420_COLLOCATED_WITH_LUMA); - // VP8 uses YCrCb color space defined in ITU-R_BT.601. - // http://tools.ietf.org/html/rfc6386 Section 9.2. - writable_codec_config()->set_color_space( - VPCodecConfigurationRecord::COLOR_SPACE_BT_601); VPxFrameInfo vpx_frame; vpx_frame.frame_size = data_size; diff --git a/packager/media/codecs/vp8_parser_unittest.cc b/packager/media/codecs/vp8_parser_unittest.cc index 357000fda8..c96b2051c4 100644 --- a/packager/media/codecs/vp8_parser_unittest.cc +++ b/packager/media/codecs/vp8_parser_unittest.cc @@ -43,7 +43,7 @@ TEST(VP8ParserTest, Keyframe) { VP8Parser parser; std::vector frames; ASSERT_TRUE(parser.Parse(kData, arraysize(kData), &frames)); - EXPECT_EQ("vp08.02.00.08.01.01.00.00", + EXPECT_EQ("vp08.02.10.08.01.02.02.02.00", parser.codec_config().GetCodecString(kCodecVP8)); EXPECT_THAT(frames, ElementsAre(EqualVPxFrame(arraysize(kData), 22u, true, 320u, 240u))); diff --git a/packager/media/codecs/vp9_parser.cc b/packager/media/codecs/vp9_parser.cc index 1ab53811fe..cacf6d6232 100644 --- a/packager/media/codecs/vp9_parser.cc +++ b/packager/media/codecs/vp9_parser.cc @@ -160,30 +160,66 @@ bool ReadSyncCode(BitReader* reader) { return sync_code == VP9_SYNC_CODE; } -VPCodecConfigurationRecord::ColorSpace GetColorSpace(uint8_t color_space) { +void SetColorAttributes(uint8_t bit_depth, + uint8_t color_space, + VPCodecConfigurationRecord* codec_config) { switch (color_space) { case VPX_COLOR_SPACE_UNKNOWN: - return VPCodecConfigurationRecord::COLOR_SPACE_UNSPECIFIED; + codec_config->set_color_primaries(AVCOL_PRI_UNSPECIFIED); + codec_config->set_matrix_coefficients(AVCOL_SPC_UNSPECIFIED); + codec_config->set_transfer_characteristics(AVCOL_TRC_UNSPECIFIED); + break; case VPX_COLOR_SPACE_BT_601: - return VPCodecConfigurationRecord::COLOR_SPACE_BT_601; + // Don't know if it is 525 line or 625 line. + codec_config->set_color_primaries(AVCOL_PRI_UNSPECIFIED); + codec_config->set_matrix_coefficients(AVCOL_SPC_UNSPECIFIED); + codec_config->set_transfer_characteristics(AVCOL_TRC_SMPTE170M); + break; case VPX_COLOR_SPACE_BT_709: - return VPCodecConfigurationRecord::COLOR_SPACE_BT_709; + codec_config->set_color_primaries(AVCOL_PRI_BT709); + codec_config->set_matrix_coefficients(AVCOL_SPC_BT709); + codec_config->set_transfer_characteristics(AVCOL_TRC_BT709); + break; case VPX_COLOR_SPACE_SMPTE_170: - return VPCodecConfigurationRecord::COLOR_SPACE_SMPTE_170; + codec_config->set_color_primaries(AVCOL_PRI_SMPTE170M); + codec_config->set_matrix_coefficients(AVCOL_SPC_SMPTE170M); + codec_config->set_transfer_characteristics(AVCOL_TRC_SMPTE170M); + break; case VPX_COLOR_SPACE_SMPTE_240: - return VPCodecConfigurationRecord::COLOR_SPACE_SMPTE_240; + codec_config->set_color_primaries(AVCOL_PRI_SMPTE240M); + codec_config->set_matrix_coefficients(AVCOL_SPC_SMPTE240M); + codec_config->set_transfer_characteristics(AVCOL_TRC_SMPTE240M); + break; case VPX_COLOR_SPACE_BT_2020: + codec_config->set_color_primaries(AVCOL_PRI_BT2020); // VP9 does not specify if it is in the form of “constant luminance” or // “non-constant luminance”. As such, application should rely on the // signaling outside of VP9 bitstream. If there is no such signaling, // application may assume non-constant luminance for BT.2020. - return VPCodecConfigurationRecord:: - COLOR_SPACE_BT_2020_NON_CONSTANT_LUMINANCE; + codec_config->set_matrix_coefficients(AVCOL_SPC_BT2020_NCL); + switch (bit_depth) { + case 10: + codec_config->set_transfer_characteristics(AVCOL_TRC_BT2020_10); + break; + case 12: + codec_config->set_transfer_characteristics(AVCOL_TRC_BT2020_12); + break; + default: + codec_config->set_transfer_characteristics(AVCOL_TRC_UNSPECIFIED); + break; + } + break; case VPX_COLOR_SPACE_SRGB: - return VPCodecConfigurationRecord::COLOR_SPACE_SRGB; + codec_config->set_color_primaries(AVCOL_PRI_UNSPECIFIED); + codec_config->set_matrix_coefficients(AVCOL_SPC_RGB); + codec_config->set_transfer_characteristics(AVCOL_TRC_UNSPECIFIED); + break; default: LOG(WARNING) << "Unknown color space: " << static_cast(color_space); - return VPCodecConfigurationRecord::COLOR_SPACE_UNSPECIFIED; + codec_config->set_color_primaries(AVCOL_PRI_UNSPECIFIED); + codec_config->set_matrix_coefficients(AVCOL_SPC_UNSPECIFIED); + codec_config->set_transfer_characteristics(AVCOL_TRC_UNSPECIFIED); + break; } } @@ -219,7 +255,7 @@ bool ReadBitDepthAndColorSpace(BitReader* reader, uint8_t color_space; RCHECK(reader->ReadBits(3, &color_space)); - codec_config->set_color_space(GetColorSpace(color_space)); + SetColorAttributes(bit_depth, color_space, codec_config); bool yuv_full_range = false; auto chroma_subsampling = VPCodecConfigurationRecord::CHROMA_444; @@ -261,7 +297,8 @@ bool ReadBitDepthAndColorSpace(BitReader* reader, VLOG(3) << "\n profile " << static_cast(codec_config->profile()) << "\n bit depth " << static_cast(codec_config->bit_depth()) - << "\n color space " << static_cast(codec_config->color_space()) + << "\n matrix coefficients " + << static_cast(codec_config->matrix_coefficients()) << "\n full_range " << static_cast(codec_config->video_full_range_flag()) << "\n chroma subsampling " diff --git a/packager/media/codecs/vp9_parser_unittest.cc b/packager/media/codecs/vp9_parser_unittest.cc index f7d3517525..c1358d6d7f 100644 --- a/packager/media/codecs/vp9_parser_unittest.cc +++ b/packager/media/codecs/vp9_parser_unittest.cc @@ -76,7 +76,7 @@ TEST(VP9ParserTest, KeyframeChroma420) { VP9Parser parser; std::vector frames; ASSERT_TRUE(parser.Parse(kData, arraysize(kData), &frames)); - EXPECT_EQ("vp09.00.00.08.00.01.00.00", + EXPECT_EQ("vp09.00.10.08.01.02.02.02.00", parser.codec_config().GetCodecString(kCodecVP9)); EXPECT_THAT(frames, ElementsAre(EqualVPxFrame(arraysize(kData), 18u, true, 32u, 8u))); @@ -98,7 +98,7 @@ TEST(VP9ParserTest, KeyframeProfile1Chroma422) { VP9Parser parser; std::vector frames; ASSERT_TRUE(parser.Parse(kData, arraysize(kData), &frames)); - EXPECT_EQ("vp09.01.00.08.00.02.00.00", + EXPECT_EQ("vp09.01.10.08.02.02.02.02.00", parser.codec_config().GetCodecString(kCodecVP9)); EXPECT_THAT(frames, ElementsAre(EqualVPxFrame(arraysize(kData), 18u, true, 160u, 90u))); @@ -120,7 +120,7 @@ TEST(VP9ParserTest, KeyframeProfile2Chroma420) { VP9Parser parser; std::vector frames; ASSERT_TRUE(parser.Parse(kData, arraysize(kData), &frames)); - EXPECT_EQ("vp09.02.00.10.00.01.00.00", + EXPECT_EQ("vp09.02.10.10.01.02.02.02.00", parser.codec_config().GetCodecString(kCodecVP9)); EXPECT_THAT(frames, ElementsAre(EqualVPxFrame(arraysize(kData), 18u, true, 160u, 90u))); @@ -142,7 +142,7 @@ TEST(VP9ParserTest, KeyframeProfile3Chroma444) { VP9Parser parser; std::vector frames; ASSERT_TRUE(parser.Parse(kData, arraysize(kData), &frames)); - EXPECT_EQ("vp09.03.00.12.00.03.00.00", + EXPECT_EQ("vp09.03.10.12.03.02.02.02.00", parser.codec_config().GetCodecString(kCodecVP9)); EXPECT_THAT(frames, ElementsAre(EqualVPxFrame(arraysize(kData), 19u, true, 160u, 90u))); } @@ -164,7 +164,7 @@ TEST(VP9ParserTest, Intra) { VP9Parser parser; std::vector frames; ASSERT_TRUE(parser.Parse(kData, arraysize(kData), &frames)); - EXPECT_EQ("vp09.00.00.08.00.01.00.00", + EXPECT_EQ("vp09.00.10.08.01.02.02.02.00", parser.codec_config().GetCodecString(kCodecVP9)); EXPECT_THAT(frames, ElementsAre(EqualVPxFrame(arraysize(kData), 19u, false, 352u, 288u))); diff --git a/packager/media/codecs/vp_codec_configuration_record.cc b/packager/media/codecs/vp_codec_configuration_record.cc index 2709c5054e..f4803c4294 100644 --- a/packager/media/codecs/vp_codec_configuration_record.cc +++ b/packager/media/codecs/vp_codec_configuration_record.cc @@ -40,18 +40,17 @@ std::string VPCodecAsString(Codec codec) { template void MergeField(const std::string& name, - T source_value, - bool source_is_set, - T* dest_value, - bool* dest_is_set) { - if (!*dest_is_set || source_is_set) { - if (*dest_is_set && source_value != *dest_value) { + const base::Optional& source_value, + base::Optional* dest_value) { + if (*dest_value) { + if (source_value && *source_value != **dest_value) { LOG(WARNING) << "VPx " << name << " is inconsistent, " - << static_cast(*dest_value) << " vs " - << static_cast(source_value); + << static_cast(**dest_value) << " vs " + << static_cast(*source_value); } + } else { + // Only set dest_value if it is not set. *dest_value = source_value; - *dest_is_set = true; } } @@ -63,45 +62,46 @@ VPCodecConfigurationRecord::VPCodecConfigurationRecord( uint8_t profile, uint8_t level, uint8_t bit_depth, - uint8_t color_space, uint8_t chroma_subsampling, - uint8_t transfer_function, bool video_full_range_flag, + uint8_t color_primaries, + uint8_t transfer_characteristics, + uint8_t matrix_coefficients, const std::vector& codec_initialization_data) : profile_(profile), level_(level), bit_depth_(bit_depth), - color_space_(color_space), chroma_subsampling_(chroma_subsampling), - transfer_function_(transfer_function), video_full_range_flag_(video_full_range_flag), - profile_is_set_(true), - level_is_set_(true), - bit_depth_is_set_(true), - color_space_is_set_(true), - chroma_subsampling_is_set_(true), - transfer_function_is_set_(true), - video_full_range_flag_is_set_(true), + color_primaries_(color_primaries), + transfer_characteristics_(transfer_characteristics), + matrix_coefficients_(matrix_coefficients), codec_initialization_data_(codec_initialization_data) {} VPCodecConfigurationRecord::~VPCodecConfigurationRecord(){}; +// https://www.webmproject.org/vp9/mp4/ bool VPCodecConfigurationRecord::ParseMP4(const std::vector& data) { BitReader reader(data.data(), data.size()); - profile_is_set_ = true; - level_is_set_ = true; - bit_depth_is_set_ = true; - color_space_is_set_ = true; - chroma_subsampling_is_set_ = true; - transfer_function_is_set_ = true; - video_full_range_flag_is_set_ = true; - RCHECK(reader.ReadBits(8, &profile_)); - RCHECK(reader.ReadBits(8, &level_)); - RCHECK(reader.ReadBits(4, &bit_depth_)); - RCHECK(reader.ReadBits(4, &color_space_)); - RCHECK(reader.ReadBits(4, &chroma_subsampling_)); - RCHECK(reader.ReadBits(3, &transfer_function_)); - RCHECK(reader.ReadBits(1, &video_full_range_flag_)); + uint8_t value; + RCHECK(reader.ReadBits(8, &value)); + profile_ = value; + RCHECK(reader.ReadBits(8, &value)); + level_ = value; + RCHECK(reader.ReadBits(4, &value)); + bit_depth_ = value; + RCHECK(reader.ReadBits(3, &value)); + chroma_subsampling_ = value; + bool bool_value; + RCHECK(reader.ReadBits(1, &bool_value)); + video_full_range_flag_ = bool_value; + RCHECK(reader.ReadBits(8, &value)); + color_primaries_ = value; + RCHECK(reader.ReadBits(8, &value)); + transfer_characteristics_ = value; + RCHECK(reader.ReadBits(8, &value)); + matrix_coefficients_ = value; + uint16_t codec_initialization_data_size = 0; RCHECK(reader.ReadBits(16, &codec_initialization_data_size)); RCHECK(reader.bits_available() >= codec_initialization_data_size * 8u); @@ -121,26 +121,27 @@ bool VPCodecConfigurationRecord::ParseWebM(const std::vector& data) { RCHECK(reader.Read1(&id)); RCHECK(reader.Read1(&size)); + uint8_t value = 0; switch (id) { case kFeatureProfile: RCHECK(size == 1); - RCHECK(reader.Read1(&profile_)); - profile_is_set_ = true; + RCHECK(reader.Read1(&value)); + profile_ = value; break; case kFeatureLevel: RCHECK(size == 1); - RCHECK(reader.Read1(&level_)); - level_is_set_ = true; + RCHECK(reader.Read1(&value)); + level_ = value; break; case kFeatureBitDepth: RCHECK(size == 1); - RCHECK(reader.Read1(&bit_depth_)); - bit_depth_is_set_ = true; + RCHECK(reader.Read1(&value)); + bit_depth_ = value; break; case kFeatureChromaSubsampling: RCHECK(size == 1); - RCHECK(reader.Read1(&chroma_subsampling_)); - chroma_subsampling_is_set_ = true; + RCHECK(reader.Read1(&value)); + chroma_subsampling_ = value; break; default: { LOG(WARNING) << "Skipping unknown VP9 codec feature " << id; @@ -154,13 +155,14 @@ bool VPCodecConfigurationRecord::ParseWebM(const std::vector& data) { void VPCodecConfigurationRecord::WriteMP4(std::vector* data) const { BufferWriter writer; - writer.AppendInt(profile_); - writer.AppendInt(level_); - uint8_t bit_depth_color_space = (bit_depth_ << 4) | color_space_; - writer.AppendInt(bit_depth_color_space); - uint8_t chroma = (chroma_subsampling_ << 4) | (transfer_function_ << 1) | - (video_full_range_flag_ ? 1 : 0); - writer.AppendInt(chroma); + writer.AppendInt(profile()); + writer.AppendInt(level()); + uint8_t bit_depth_chroma = (bit_depth() << 4) | (chroma_subsampling() << 1) | + (video_full_range_flag() ? 1 : 0); + writer.AppendInt(bit_depth_chroma); + writer.AppendInt(color_primaries()); + writer.AppendInt(transfer_characteristics()); + writer.AppendInt(matrix_coefficients()); uint16_t codec_initialization_data_size = static_cast(codec_initialization_data_.size()); writer.AppendInt(codec_initialization_data_size); @@ -171,35 +173,29 @@ void VPCodecConfigurationRecord::WriteMP4(std::vector* data) const { void VPCodecConfigurationRecord::WriteWebM(std::vector* data) const { BufferWriter writer; - if (profile_is_set_) { + if (profile_) { writer.AppendInt(static_cast(kFeatureProfile)); // ID = 1 writer.AppendInt(static_cast(1)); // Length = 1 - writer.AppendInt(static_cast(profile_)); + writer.AppendInt(*profile_); } - if (level_is_set_ && level_ != 0) { + if (level_) { writer.AppendInt(static_cast(kFeatureLevel)); // ID = 2 writer.AppendInt(static_cast(1)); // Length = 1 - writer.AppendInt(static_cast(level_)); + writer.AppendInt(*level_); } - if (bit_depth_is_set_) { + if (bit_depth_) { writer.AppendInt(static_cast(kFeatureBitDepth)); // ID = 3 writer.AppendInt(static_cast(1)); // Length = 1 - writer.AppendInt(static_cast(bit_depth_)); + writer.AppendInt(*bit_depth_); } - if (chroma_subsampling_is_set_) { - // WebM doesn't differentiate whether it is vertical or collocated with luma - // for 4:2:0. - const uint8_t subsampling = - chroma_subsampling_ == CHROMA_420_COLLOCATED_WITH_LUMA - ? CHROMA_420_VERTICAL - : chroma_subsampling_; + if (chroma_subsampling_) { // ID = 4, Length = 1 writer.AppendInt(static_cast(kFeatureChromaSubsampling)); writer.AppendInt(static_cast(1)); - writer.AppendInt(subsampling); + writer.AppendInt(*chroma_subsampling_); } writer.SwapBuffer(data); @@ -207,13 +203,14 @@ void VPCodecConfigurationRecord::WriteWebM(std::vector* data) const { std::string VPCodecConfigurationRecord::GetCodecString(Codec codec) const { const std::string fields[] = { - base::IntToString(profile_), - base::IntToString(level_), - base::IntToString(bit_depth_), - base::IntToString(color_space_), - base::IntToString(chroma_subsampling_), - base::IntToString(transfer_function_), - (video_full_range_flag_ ? "01" : "00"), + base::IntToString(profile()), + base::IntToString(level()), + base::IntToString(bit_depth()), + base::IntToString(chroma_subsampling()), + base::IntToString(color_primaries()), + base::IntToString(transfer_characteristics()), + base::IntToString(matrix_coefficients()), + (video_full_range_flag_ && *video_full_range_flag_) ? "01" : "00", }; std::string codec_string = VPCodecAsString(codec); @@ -228,23 +225,18 @@ std::string VPCodecConfigurationRecord::GetCodecString(Codec codec) const { void VPCodecConfigurationRecord::MergeFrom( const VPCodecConfigurationRecord& other) { - MergeField("profile", other.profile_, other.profile_is_set_, &profile_, - &profile_is_set_); - MergeField("level", other.level_, other.level_is_set_, &level_, - &level_is_set_); - MergeField("bit depth", other.bit_depth_, other.bit_depth_is_set_, - &bit_depth_, &bit_depth_is_set_); - MergeField("color space", other.color_space_, other.color_space_is_set_, - &color_space_, &color_space_is_set_); + MergeField("profile", other.profile_, &profile_); + MergeField("level", other.level_, &level_); + MergeField("bit depth", other.bit_depth_, &bit_depth_); MergeField("chroma subsampling", other.chroma_subsampling_, - other.chroma_subsampling_is_set_, &chroma_subsampling_, - &chroma_subsampling_is_set_); - MergeField("transfer function", other.transfer_function_, - other.transfer_function_is_set_, &transfer_function_, - &transfer_function_is_set_); + &chroma_subsampling_); MergeField("video full range flag", other.video_full_range_flag_, - other.video_full_range_flag_is_set_, &video_full_range_flag_, - &video_full_range_flag_is_set_); + &video_full_range_flag_); + MergeField("color primaries", other.color_primaries_, &color_primaries_); + MergeField("transfer characteristics", other.transfer_characteristics_, + &transfer_characteristics_); + MergeField("matrix coefficients", other.matrix_coefficients_, + &matrix_coefficients_); if (codec_initialization_data_.empty() || !other.codec_initialization_data_.empty()) { diff --git a/packager/media/codecs/vp_codec_configuration_record.h b/packager/media/codecs/vp_codec_configuration_record.h index 8b07b48d1b..91aa7075be 100644 --- a/packager/media/codecs/vp_codec_configuration_record.h +++ b/packager/media/codecs/vp_codec_configuration_record.h @@ -12,25 +12,118 @@ #include #include "packager/base/macros.h" +#include "packager/base/optional.h" #include "packager/media/base/video_stream_info.h" namespace shaka { namespace media { +/// The below enums are from ffmpeg/libavutil/pixfmt.h. +/// Chromaticity coordinates of the source primaries. +enum AVColorPrimaries { + AVCOL_PRI_RESERVED0 = 0, + /// Also ITU-R BT1361 / IEC 61966-2-4 / SMPTE RP177 Annex B + AVCOL_PRI_BT709 = 1, + AVCOL_PRI_UNSPECIFIED = 2, + AVCOL_PRI_RESERVED = 3, + /// Also FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_PRI_BT470M = 4, + /// Also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM + AVCOL_PRI_BT470BG = 5, + /// Also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_PRI_SMPTE170M = 6, + /// Functionally identical to above + AVCOL_PRI_SMPTE240M = 7, + /// Colour filters using Illuminant C + AVCOL_PRI_FILM = 8, + /// ITU-R BT2020 + AVCOL_PRI_BT2020 = 9, + /// SMPTE ST 428-1 (CIE 1931 XYZ) + AVCOL_PRI_SMPTE428 = 10, + AVCOL_PRI_SMPTEST428_1 = AVCOL_PRI_SMPTE428, + /// SMPTE ST 431-2 (2011) + AVCOL_PRI_SMPTE431 = 11, + /// SMPTE ST 432-1 D65 (2010) + AVCOL_PRI_SMPTE432 = 12, + ///< Not part of ABI + AVCOL_PRI_NB +}; + +/// Color Transfer Characteristic. +enum AVColorTransferCharacteristic { + AVCOL_TRC_RESERVED0 = 0, + /// Also ITU-R BT1361 + AVCOL_TRC_BT709 = 1, + AVCOL_TRC_UNSPECIFIED = 2, + AVCOL_TRC_RESERVED = 3, + /// Also ITU-R BT470M / ITU-R BT1700 625 PAL & SECAM + AVCOL_TRC_GAMMA22 = 4, + /// Also ITU-R BT470BG + AVCOL_TRC_GAMMA28 = 5, + /// Also ITU-R BT601-6 525 or 625 / ITU-R BT1358 525 or 625 / ITU-R BT1700 + /// NTSC + AVCOL_TRC_SMPTE170M = 6, + AVCOL_TRC_SMPTE240M = 7, + /// "Linear transfer characteristics" + AVCOL_TRC_LINEAR = 8, + /// "Logarithmic transfer characteristic (100:1 range)" + AVCOL_TRC_LOG = 9, + /// "Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range)" + AVCOL_TRC_LOG_SQRT = 10, + /// IEC 61966-2-4 + AVCOL_TRC_IEC61966_2_4 = 11, + /// ITU-R BT1361 Extended Colour Gamut + AVCOL_TRC_BT1361_ECG = 12, + /// IEC 61966-2-1 (sRGB or sYCC) + AVCOL_TRC_IEC61966_2_1 = 13, + /// ITU-R BT2020 for 10-bit system + AVCOL_TRC_BT2020_10 = 14, + /// ITU-R BT2020 for 12-bit system + AVCOL_TRC_BT2020_12 = 15, + /// SMPTE ST 2084 for 10-, 12-, 14- and 16-bit systems + AVCOL_TRC_SMPTE2084 = 16, + AVCOL_TRC_SMPTEST2084 = AVCOL_TRC_SMPTE2084, + /// SMPTE ST 428-1 + AVCOL_TRC_SMPTE428 = 17, + AVCOL_TRC_SMPTEST428_1 = AVCOL_TRC_SMPTE428, + /// ARIB STD-B67, known as "Hybrid log-gamma" + AVCOL_TRC_ARIB_STD_B67 = 18, + /// Not part of ABI + AVCOL_TRC_NB +}; + +/// YUV colorspace type (a.c.a matrix coefficients in 23001-8:2016). +enum AVColorSpace { + /// Order of coefficients is actually GBR, also IEC 61966-2-1 (sRGB) + AVCOL_SPC_RGB = 0, + /// Also ITU-R BT1361 / IEC 61966-2-4 xvYCC709 / SMPTE RP177 Annex B + AVCOL_SPC_BT709 = 1, + AVCOL_SPC_UNSPECIFIED = 2, + AVCOL_SPC_RESERVED = 3, + /// FCC Title 47 Code of Federal Regulations 73.682 (a)(20) + AVCOL_SPC_FCC = 4, + /// Also ITU-R BT601-6 625 / ITU-R BT1358 625 / ITU-R BT1700 625 PAL & SECAM / + /// IEC 61966-2-4 xvYCC601 + AVCOL_SPC_BT470BG = 5, + /// Also ITU-R BT601-6 525 / ITU-R BT1358 525 / ITU-R BT1700 NTSC + AVCOL_SPC_SMPTE170M = 6, + /// Functionally identical to above + AVCOL_SPC_SMPTE240M = 7, + /// Used by Dirac / VC-2 and H.264 FRext, see ITU-T SG16 + AVCOL_SPC_YCOCG = 8, + /// ITU-R BT2020 non-constant luminance system + AVCOL_SPC_BT2020_NCL = 9, + /// ITU-R BT2020 constant luminance system + AVCOL_SPC_BT2020_CL = 10, + /// SMPTE 2085, Y'D'zD'x + AVCOL_SPC_SMPTE2085 = 11, + /// Not part of ABI + AVCOL_SPC_NB +}; + /// Class for parsing or writing VP codec configuration record. class VPCodecConfigurationRecord { public: - enum ColorSpace { - COLOR_SPACE_UNSPECIFIED = 0, - COLOR_SPACE_BT_601 = 1, - COLOR_SPACE_BT_709 = 2, - COLOR_SPACE_SMPTE_170 = 3, - COLOR_SPACE_SMPTE_240 = 4, - COLOR_SPACE_BT_2020_NON_CONSTANT_LUMINANCE = 5, - COLOR_SPACE_BT_2020_CONSTANT_LUMINANCE = 6, - COLOR_SPACE_SRGB = 7, - }; - enum ChromaSubsampling { CHROMA_420_VERTICAL = 0, CHROMA_420_COLLOCATED_WITH_LUMA = 1, @@ -44,10 +137,11 @@ class VPCodecConfigurationRecord { uint8_t profile, uint8_t level, uint8_t bit_depth, - uint8_t color_space, uint8_t chroma_subsampling, - uint8_t transfer_function, bool video_full_range_flag, + uint8_t color_primaries, + uint8_t transfer_characteristics, + uint8_t matrix_coefficients, const std::vector& codec_initialization_data); ~VPCodecConfigurationRecord(); @@ -74,57 +168,53 @@ class VPCodecConfigurationRecord { // both |*this| and |other|, the values in |other| take precedence. void MergeFrom(const VPCodecConfigurationRecord& other); - void set_profile(uint8_t profile) { - profile_ = profile; - profile_is_set_ = true; - } - void set_level(uint8_t level) { - level_ = level; - level_is_set_ = true; - } - void set_bit_depth(uint8_t bit_depth) { - bit_depth_ = bit_depth; - bit_depth_is_set_ = true; - } - void set_color_space(uint8_t color_space) { - color_space_ = color_space; - color_space_is_set_ = true; - } + void set_profile(uint8_t profile) { profile_ = profile; } + void set_level(uint8_t level) { level_ = level; } + void set_bit_depth(uint8_t bit_depth) { bit_depth_ = bit_depth; } void set_chroma_subsampling(uint8_t chroma_subsampling) { chroma_subsampling_ = chroma_subsampling; - chroma_subsampling_is_set_ = true; - } - void set_transfer_function(uint8_t transfer_function) { - transfer_function_ = transfer_function; - transfer_function_is_set_ = true; } void set_video_full_range_flag(bool video_full_range_flag) { video_full_range_flag_ = video_full_range_flag; } + void set_color_primaries(uint8_t color_primaries) { + color_primaries_ = color_primaries; + } + void set_transfer_characteristics(uint8_t transfer_characteristics) { + transfer_characteristics_ = transfer_characteristics; + } + void set_matrix_coefficients(uint8_t matrix_coefficients) { + matrix_coefficients_ = matrix_coefficients; + } - uint8_t profile() const { return profile_; } - uint8_t level() const { return level_; } - uint8_t bit_depth() const { return bit_depth_; } - uint8_t color_space() const { return color_space_; } - uint8_t chroma_subsampling() const { return chroma_subsampling_; } - uint8_t transfer_function() const { return transfer_function_; } - bool video_full_range_flag() const { return video_full_range_flag_; } + uint8_t profile() const { return profile_.value_or(0); } + uint8_t level() const { return level_.value_or(10); } + uint8_t bit_depth() const { return bit_depth_.value_or(8); } + uint8_t chroma_subsampling() const { + return chroma_subsampling_.value_or(CHROMA_420_COLLOCATED_WITH_LUMA); + } + bool video_full_range_flag() const { + return video_full_range_flag_.value_or(false); + } + uint8_t color_primaries() const { + return color_primaries_.value_or(AVCOL_PRI_UNSPECIFIED); + } + uint8_t transfer_characteristics() const { + return transfer_characteristics_.value_or(AVCOL_TRC_UNSPECIFIED); + } + uint8_t matrix_coefficients() const { + return matrix_coefficients_.value_or(AVCOL_SPC_UNSPECIFIED); + } private: - uint8_t profile_ = 0; - uint8_t level_ = 0; - uint8_t bit_depth_ = 0; - uint8_t color_space_ = 0; - uint8_t chroma_subsampling_ = 0; - uint8_t transfer_function_ = 0; - bool video_full_range_flag_ = false; - bool profile_is_set_ = false; - bool level_is_set_ = false; - bool bit_depth_is_set_ = false; - bool color_space_is_set_ = false; - bool chroma_subsampling_is_set_ = false; - bool transfer_function_is_set_ = false; - bool video_full_range_flag_is_set_ = false; + base::Optional profile_; + base::Optional level_; + base::Optional bit_depth_; + base::Optional chroma_subsampling_; + base::Optional video_full_range_flag_; + base::Optional color_primaries_; + base::Optional transfer_characteristics_; + base::Optional matrix_coefficients_; std::vector codec_initialization_data_; // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler diff --git a/packager/media/codecs/vp_codec_configuration_record_unittest.cc b/packager/media/codecs/vp_codec_configuration_record_unittest.cc index 2dac9227d9..dea8998052 100644 --- a/packager/media/codecs/vp_codec_configuration_record_unittest.cc +++ b/packager/media/codecs/vp_codec_configuration_record_unittest.cc @@ -13,50 +13,50 @@ namespace media { TEST(VPCodecConfigurationRecordTest, Parse) { const uint8_t kVpCodecConfigurationData[] = { - 0x01, 0x00, 0xA2, 0x14, 0x00, 0x01, 0x00, + 0x01, 0x14, 0xA2, 0x02, 0x03, 0x04, 0x00, 0x00, }; VPCodecConfigurationRecord vp_config; - ASSERT_TRUE(vp_config.ParseMP4(std::vector( - kVpCodecConfigurationData, - kVpCodecConfigurationData + arraysize(kVpCodecConfigurationData)))); + ASSERT_TRUE(vp_config.ParseMP4( + std::vector(std::begin(kVpCodecConfigurationData), + std::end(kVpCodecConfigurationData)))); EXPECT_EQ(1u, vp_config.profile()); - EXPECT_EQ(0u, vp_config.level()); + EXPECT_EQ(20u, vp_config.level()); EXPECT_EQ(10u, vp_config.bit_depth()); - EXPECT_EQ(2u, vp_config.color_space()); EXPECT_EQ(1u, vp_config.chroma_subsampling()); - EXPECT_EQ(2u, vp_config.transfer_function()); EXPECT_FALSE(vp_config.video_full_range_flag()); + EXPECT_EQ(2u, vp_config.color_primaries()); + EXPECT_EQ(3u, vp_config.transfer_characteristics()); + EXPECT_EQ(4u, vp_config.matrix_coefficients()); - EXPECT_EQ("vp09.01.00.10.02.01.02.00", vp_config.GetCodecString(kCodecVP9)); + EXPECT_EQ("vp09.01.20.10.01.02.03.04.00", + vp_config.GetCodecString(kCodecVP9)); } TEST(VPCodecConfigurationRecordTest, ParseWithInsufficientData) { const uint8_t kVpCodecConfigurationData[] = { - 0x01, 0x00, 0xA2, 0x14, + 0x01, 0x14, 0xA2, 0x02, }; VPCodecConfigurationRecord vp_config; - ASSERT_FALSE(vp_config.ParseMP4(std::vector( - kVpCodecConfigurationData, - kVpCodecConfigurationData + arraysize(kVpCodecConfigurationData)))); + ASSERT_FALSE(vp_config.ParseMP4( + std::vector(std::begin(kVpCodecConfigurationData), + std::end(kVpCodecConfigurationData)))); } TEST(VPCodecConfigurationRecordTest, WriteMP4) { const uint8_t kExpectedVpCodecConfigurationData[] = { - 0x02, 0x01, 0x80, 0x21, 0x00, 0x00, + 0x02, 0x01, 0x85, 0x03, 0x04, 0x05, 0x00, 0x00, }; - VPCodecConfigurationRecord vp_config(0x02, 0x01, 0x08, 0x00, 0x02, 0x00, true, - std::vector()); + VPCodecConfigurationRecord vp_config(0x02, 0x01, 0x08, 0x02, true, 0x03, 0x04, + 0x05, std::vector()); std::vector data; vp_config.WriteMP4(&data); - EXPECT_EQ( - std::vector(kExpectedVpCodecConfigurationData, - kExpectedVpCodecConfigurationData + - arraysize(kExpectedVpCodecConfigurationData)), - data); + EXPECT_EQ(std::vector(std::begin(kExpectedVpCodecConfigurationData), + std::end(kExpectedVpCodecConfigurationData)), + data); } TEST(VPCodecConfigurationRecordTest, WriteWebM) { @@ -64,18 +64,16 @@ TEST(VPCodecConfigurationRecordTest, WriteWebM) { 0x01, 0x01, 0x02, 0x02, 0x01, 0x01, 0x03, 0x01, 0x08, - 0x04, 0x01, 0x03 + 0x04, 0x01, 0x02, }; - VPCodecConfigurationRecord vp_config(0x02, 0x01, 0x08, 0x00, 0x03, 0x00, true, - std::vector()); + VPCodecConfigurationRecord vp_config(0x02, 0x01, 0x08, 0x02, true, 0x03, 0x04, + 0x05, std::vector()); std::vector data; vp_config.WriteWebM(&data); - EXPECT_EQ( - std::vector(kExpectedVpCodecConfigurationData, - kExpectedVpCodecConfigurationData + - arraysize(kExpectedVpCodecConfigurationData)), - data); + EXPECT_EQ(std::vector(std::begin(kExpectedVpCodecConfigurationData), + std::end(kExpectedVpCodecConfigurationData)), + data); } } // namespace media diff --git a/packager/media/formats/mp4/box_definitions.cc b/packager/media/formats/mp4/box_definitions.cc index 95ff6e2e34..bf94410b8b 100644 --- a/packager/media/formats/mp4/box_definitions.cc +++ b/packager/media/formats/mp4/box_definitions.cc @@ -1446,9 +1446,12 @@ bool CodecConfiguration::ReadWriteInternal(BoxBuffer* buffer) { // VPCodecConfiguration box inherits from FullBox instead of Box. The extra 4 // bytes are handled here. if (box_type == FOURCC_vpcC) { - uint32_t version_flags = 0; + // Only version 1 box is supported. + uint8_t vpcc_version = 1; + uint32_t version_flags = vpcc_version << 24; RCHECK(buffer->ReadWriteUInt32(&version_flags)); - RCHECK(version_flags == 0); + vpcc_version = version_flags >> 24; + RCHECK(vpcc_version == 1); } if (buffer->Reading()) { diff --git a/packager/media/formats/webm/webm_cluster_parser_unittest.cc b/packager/media/formats/webm/webm_cluster_parser_unittest.cc index 800e34a9ec..249d2953d1 100644 --- a/packager/media/formats/webm/webm_cluster_parser_unittest.cc +++ b/packager/media/formats/webm/webm_cluster_parser_unittest.cc @@ -821,7 +821,7 @@ TEST_F(WebMClusterParserTest, ParseVP8) { ASSERT_EQ(2u, streams_from_init_event_.size()); EXPECT_EQ(kStreamAudio, streams_from_init_event_[0]->stream_type()); EXPECT_EQ(kStreamVideo, streams_from_init_event_[1]->stream_type()); - EXPECT_EQ("vp08.01.00.08.01.01.00.00", + EXPECT_EQ("vp08.01.10.08.01.02.02.02.00", streams_from_init_event_[1]->codec_string()); } @@ -835,7 +835,7 @@ TEST_F(WebMClusterParserTest, ParseVP9) { ASSERT_EQ(2u, streams_from_init_event_.size()); EXPECT_EQ(kStreamAudio, streams_from_init_event_[0]->stream_type()); EXPECT_EQ(kStreamVideo, streams_from_init_event_[1]->stream_type()); - EXPECT_EQ("vp09.03.00.12.00.03.00.00", + EXPECT_EQ("vp09.03.10.12.03.02.02.02.00", streams_from_init_event_[1]->codec_string()); }