diff --git a/modules/video_coding/codecs/h264/h264_decoder_impl.cc b/modules/video_coding/codecs/h264/h264_decoder_impl.cc index fa0d925e65..ea74cc4177 100644 --- a/modules/video_coding/codecs/h264/h264_decoder_impl.cc +++ b/modules/video_coding/codecs/h264/h264_decoder_impl.cc @@ -300,7 +300,10 @@ int32_t H264DecoderImpl::Decode(const EncodedImage& input_image, RTC_CHECK_EQ(av_frame_->data[kUPlaneIndex], i420_buffer->DataU()); RTC_CHECK_EQ(av_frame_->data[kVPlaneIndex], i420_buffer->DataV()); - const ColorSpace& color_space = ExtractH264ColorSpace(av_context_.get()); + // Pass on color space from input frame if explicitly specified. + const ColorSpace& color_space = + input_frame->color_space() ? *input_frame->color_space() + : ExtractH264ColorSpace(av_context_.get()); VideoFrame decoded_frame = VideoFrame::Builder() .set_video_frame_buffer(input_frame->video_frame_buffer()) diff --git a/modules/video_coding/codecs/h264/h264_encoder_impl.cc b/modules/video_coding/codecs/h264/h264_encoder_impl.cc index c33e45123b..3a49ac0a6f 100644 --- a/modules/video_coding/codecs/h264/h264_encoder_impl.cc +++ b/modules/video_coding/codecs/h264/h264_encoder_impl.cc @@ -502,6 +502,7 @@ int32_t H264EncoderImpl::Encode(const VideoFrame& input_frame, encoded_images_[i].ntp_time_ms_ = input_frame.ntp_time_ms(); encoded_images_[i].capture_time_ms_ = input_frame.render_time_ms(); encoded_images_[i].rotation_ = input_frame.rotation(); + encoded_images_[i].SetColorSpace(input_frame.color_space()); encoded_images_[i].content_type_ = (codec_.mode == VideoCodecMode::kScreensharing) ? VideoContentType::SCREENSHARE diff --git a/modules/video_coding/codecs/h264/test/h264_impl_unittest.cc b/modules/video_coding/codecs/h264/test/h264_impl_unittest.cc index 70326d3fae..384ea70011 100644 --- a/modules/video_coding/codecs/h264/test/h264_impl_unittest.cc +++ b/modules/video_coding/codecs/h264/test/h264_impl_unittest.cc @@ -20,6 +20,7 @@ #include "api/video_codecs/video_encoder.h" #include "common_types.h" // NOLINT(build/include) #include "common_video/libyuv/include/webrtc_libyuv.h" +#include "common_video/test/utilities.h" #include "media/base/codec.h" #include "media/base/mediaconstants.h" #include "modules/video_coding/codecs/h264/include/h264.h" @@ -49,9 +50,17 @@ class TestH264Impl : public VideoCodecUnitTest { #ifdef WEBRTC_USE_H264 #define MAYBE_EncodeDecode EncodeDecode #define MAYBE_DecodedQpEqualsEncodedQp DecodedQpEqualsEncodedQp +#define MAYBE_EncodedColorSpaceEqualsInputColorSpace \ + EncodedColorSpaceEqualsInputColorSpace +#define MAYBE_DecodedColorSpaceEqualsEncodedColorSpace \ + DecodedColorSpaceEqualsEncodedColorSpace #else #define MAYBE_EncodeDecode DISABLED_EncodeDecode #define MAYBE_DecodedQpEqualsEncodedQp DISABLED_DecodedQpEqualsEncodedQp +#define MAYBE_EncodedColorSpaceEqualsInputColorSpace \ + DISABLED_EncodedColorSpaceEqualsInputColorSpace +#define MAYBE_DecodedColorSpaceEqualsEncodedColorSpace \ + DISABLED_DecodedColorSpaceEqualsEncodedColorSpace #endif TEST_F(TestH264Impl, MAYBE_EncodeDecode) { @@ -100,4 +109,47 @@ TEST_F(TestH264Impl, MAYBE_DecodedQpEqualsEncodedQp) { EXPECT_EQ(encoded_frame.qp_, *decoded_qp); } +TEST_F(TestH264Impl, MAYBE_EncodedColorSpaceEqualsInputColorSpace) { + VideoFrame* input_frame = NextInputFrame(); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(*input_frame, nullptr, nullptr)); + EncodedImage encoded_frame; + CodecSpecificInfo codec_specific_info; + ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info)); + EXPECT_FALSE(encoded_frame.ColorSpace()); + + // Video frame with explicit color space information. + ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false); + VideoFrame input_frame_w_color_space = + VideoFrame::Builder() + .set_video_frame_buffer(input_frame->video_frame_buffer()) + .set_color_space(&color_space) + .build(); + + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(input_frame_w_color_space, nullptr, nullptr)); + ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info)); + ASSERT_TRUE(encoded_frame.ColorSpace()); + EXPECT_EQ(*encoded_frame.ColorSpace(), color_space); +} + +TEST_F(TestH264Impl, MAYBE_DecodedColorSpaceEqualsEncodedColorSpace) { + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + encoder_->Encode(*NextInputFrame(), nullptr, nullptr)); + EncodedImage encoded_frame; + CodecSpecificInfo codec_specific_info; + ASSERT_TRUE(WaitForEncodedFrame(&encoded_frame, &codec_specific_info)); + // Add color space to encoded frame. + ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false); + encoded_frame.SetColorSpace(&color_space); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + decoder_->Decode(encoded_frame, false, nullptr, 0)); + std::unique_ptr decoded_frame; + absl::optional decoded_qp; + ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp)); + ASSERT_TRUE(decoded_frame); + ASSERT_TRUE(decoded_frame->color_space()); + EXPECT_EQ(color_space, *decoded_frame->color_space()); +} + } // namespace webrtc diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc index 0c27a6714f..b0d5e1da1e 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.cc @@ -266,7 +266,8 @@ int LibvpxVp8Decoder::Decode(const EncodedImage& input_image, vpx_codec_err_t vpx_ret = vpx_codec_control(decoder_, VPXD_GET_LAST_QUANTIZER, &qp); RTC_DCHECK_EQ(vpx_ret, VPX_CODEC_OK); - ret = ReturnFrame(img, input_image.Timestamp(), input_image.ntp_time_ms_, qp); + ret = ReturnFrame(img, input_image.Timestamp(), input_image.ntp_time_ms_, qp, + input_image.ColorSpace()); if (ret != 0) { // Reset to avoid requesting key frames too often. if (ret < 0 && propagation_cnt_ > 0) @@ -285,7 +286,8 @@ int LibvpxVp8Decoder::Decode(const EncodedImage& input_image, int LibvpxVp8Decoder::ReturnFrame(const vpx_image_t* img, uint32_t timestamp, int64_t ntp_time_ms, - int qp) { + int qp, + const ColorSpace* explicit_color_space) { if (img == NULL) { // Decoder OK and NULL image => No show frame return WEBRTC_VIDEO_CODEC_NO_OUTPUT; @@ -317,8 +319,12 @@ int LibvpxVp8Decoder::ReturnFrame(const vpx_image_t* img, buffer->MutableDataV(), buffer->StrideV(), img->d_w, img->d_h); - VideoFrame decoded_image(buffer, timestamp, 0, kVideoRotation_0); - decoded_image.set_ntp_time_ms(ntp_time_ms); + VideoFrame decoded_image = VideoFrame::Builder() + .set_video_frame_buffer(buffer) + .set_timestamp_rtp(timestamp) + .set_ntp_time_ms(ntp_time_ms) + .set_color_space(explicit_color_space) + .build(); decode_complete_callback_->Decoded(decoded_image, absl::nullopt, qp); return WEBRTC_VIDEO_CODEC_OK; diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.h b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.h index cff9e89988..0db4c3b221 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.h +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_decoder.h @@ -53,8 +53,8 @@ class LibvpxVp8Decoder : public VideoDecoder { int ReturnFrame(const vpx_image_t* img, uint32_t timeStamp, int64_t ntp_time_ms, - int qp); - + int qp, + const ColorSpace* explicit_color_space); const bool use_postproc_arm_; I420BufferPool buffer_pool_; diff --git a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc index 808bfaa199..9f2cb8ef99 100644 --- a/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc +++ b/modules/video_coding/codecs/vp8/libvpx_vp8_encoder.cc @@ -918,6 +918,7 @@ int LibvpxVp8Encoder::GetEncodedPartitions(const VideoFrame& input_image) { ? VideoContentType::SCREENSHARE : VideoContentType::UNSPECIFIED; encoded_images_[encoder_idx].timing_.flags = VideoSendTiming::kInvalid; + encoded_images_[encoder_idx].SetColorSpace(input_image.color_space()); if (send_stream_[stream_idx]) { if (encoded_images_[encoder_idx]._length > 0) { diff --git a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc index 11ac5b543f..40e01bdd13 100644 --- a/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc +++ b/modules/video_coding/codecs/vp8/test/vp8_impl_unittest.cc @@ -16,6 +16,7 @@ #include "api/test/mock_video_encoder.h" #include "api/video_codecs/vp8_temporal_layers.h" #include "common_video/libyuv/include/webrtc_libyuv.h" +#include "common_video/test/utilities.h" #include "modules/video_coding/codecs/test/video_codec_unittest.h" #include "modules/video_coding/codecs/vp8/include/vp8.h" #include "modules/video_coding/codecs/vp8/libvpx_vp8_encoder.h" @@ -173,6 +174,28 @@ TEST_F(TestVp8Impl, EncodedRotationEqualsInputRotation) { EXPECT_EQ(kVideoRotation_90, encoded_frame.rotation_); } +TEST_F(TestVp8Impl, EncodedColorSpaceEqualsInputColorSpace) { + // Video frame without explicit color space information. + VideoFrame* input_frame = NextInputFrame(); + EncodedImage encoded_frame; + CodecSpecificInfo codec_specific_info; + EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info); + EXPECT_FALSE(encoded_frame.ColorSpace()); + + // Video frame with explicit color space information. + ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false); + VideoFrame input_frame_w_color_space = + VideoFrame::Builder() + .set_video_frame_buffer(input_frame->video_frame_buffer()) + .set_color_space(&color_space) + .build(); + + EncodeAndWaitForFrame(input_frame_w_color_space, &encoded_frame, + &codec_specific_info); + ASSERT_TRUE(encoded_frame.ColorSpace()); + EXPECT_EQ(*encoded_frame.ColorSpace(), color_space); +} + TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) { VideoFrame* input_frame = NextInputFrame(); EncodedImage encoded_frame; @@ -192,6 +215,25 @@ TEST_F(TestVp8Impl, DecodedQpEqualsEncodedQp) { EXPECT_EQ(encoded_frame.qp_, *decoded_qp); } +TEST_F(TestVp8Impl, DecodedColorSpaceEqualsEncodedColorSpace) { + VideoFrame* input_frame = NextInputFrame(); + EncodedImage encoded_frame; + CodecSpecificInfo codec_specific_info; + EncodeAndWaitForFrame(*input_frame, &encoded_frame, &codec_specific_info); + + // Encoded frame with explicit color space information. + ColorSpace color_space = CreateTestColorSpace(/*with_hdr_metadata=*/false); + encoded_frame.SetColorSpace(&color_space); + EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, + decoder_->Decode(encoded_frame, false, nullptr, -1)); + std::unique_ptr decoded_frame; + absl::optional decoded_qp; + ASSERT_TRUE(WaitForDecodedFrame(&decoded_frame, &decoded_qp)); + ASSERT_TRUE(decoded_frame); + ASSERT_TRUE(decoded_frame->color_space()); + EXPECT_EQ(color_space, *decoded_frame->color_space()); +} + TEST_F(TestVp8Impl, ChecksSimulcastSettings) { codec_settings_.numberOfSimulcastStreams = 2; // Reslutions are not scaled by 2, temporal layers do not match. diff --git a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc index 62cf6afcf0..085af97eff 100644 --- a/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc +++ b/modules/video_coding/codecs/vp9/test/vp9_impl_unittest.cc @@ -187,7 +187,7 @@ TEST_F(TestVp9Impl, EncodedColorSpaceEqualsInputColorSpace) { EXPECT_EQ(*encoded_frame.ColorSpace(), color_space); } -TEST_F(TestVp9Impl, DecodedHdrMetadataEqualsEncodedHdrMetadata) { +TEST_F(TestVp9Impl, DecodedColorSpaceEqualsEncodedColorSpace) { EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, encoder_->Encode(*NextInputFrame(), nullptr, nullptr)); EncodedImage encoded_frame;