Add end-to-end test for ColorSpace information
Bug: webrtc:8651 Change-Id: Ib7f6162c8dd41868b7d7acca8a6292b2d911c520 Reviewed-on: https://webrtc-review.googlesource.com/c/113941 Commit-Queue: Johannes Kron <kron@webrtc.org> Reviewed-by: Niels Moller <nisse@webrtc.org> Reviewed-by: Sebastian Jansson <srte@webrtc.org> Reviewed-by: Erik Språng <sprang@webrtc.org> Cr-Commit-Position: refs/heads/master@{#25992}
This commit is contained in:

committed by
Commit Bot

parent
3d5df13f52
commit
f7f13e0742
@ -118,6 +118,10 @@ class RTC_EXPORT VideoFrame {
|
||||
const ColorSpace* color_space() const {
|
||||
return color_space_ ? &*color_space_ : nullptr;
|
||||
}
|
||||
void set_color_space(ColorSpace* color_space) {
|
||||
color_space_ =
|
||||
color_space ? absl::make_optional(*color_space) : absl::nullopt;
|
||||
}
|
||||
|
||||
// Get render time in milliseconds.
|
||||
// TODO(nisse): Deprecated. Migrate all users to timestamp_us().
|
||||
|
@ -31,10 +31,6 @@
|
||||
namespace webrtc {
|
||||
namespace test {
|
||||
|
||||
namespace {
|
||||
const int kVideoRotationRtpExtensionId = 4;
|
||||
}
|
||||
|
||||
CallTest::CallTest()
|
||||
: clock_(Clock::GetRealTimeClock()),
|
||||
send_event_log_(RtcEventLog::CreateNull()),
|
||||
@ -240,6 +236,7 @@ void CallTest::CreateVideoSendConfig(VideoSendStream::Config* video_config,
|
||||
bitrate_allocator_factory_.get();
|
||||
video_config->rtp.payload_name = "FAKE";
|
||||
video_config->rtp.payload_type = kFakeVideoSendPayloadType;
|
||||
video_config->rtp.extmap_allow_mixed = true;
|
||||
video_config->rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kTransportSequenceNumberUri,
|
||||
kTransportSequenceNumberExtensionId));
|
||||
@ -255,8 +252,10 @@ void CallTest::CreateVideoSendConfig(VideoSendStream::Config* video_config,
|
||||
|
||||
for (size_t i = 0; i < num_video_streams; ++i)
|
||||
video_config->rtp.ssrcs.push_back(kVideoSendSsrcs[num_used_ssrcs + i]);
|
||||
video_config->rtp.extensions.push_back(RtpExtension(
|
||||
RtpExtension::kVideoRotationUri, kVideoRotationRtpExtensionId));
|
||||
video_config->rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kVideoRotationUri, kVideoRotationExtensionId));
|
||||
video_config->rtp.extensions.push_back(
|
||||
RtpExtension(RtpExtension::kColorSpaceUri, kColorSpaceExtensionId));
|
||||
}
|
||||
|
||||
void CallTest::CreateAudioAndFecSendConfigs(size_t num_audio_streams,
|
||||
|
@ -21,6 +21,7 @@ const int kVideoRotationExtensionId = 9;
|
||||
const int kVideoContentTypeExtensionId = 10;
|
||||
const int kVideoTimingExtensionId = 11;
|
||||
const int kGenericDescriptorExtensionId = 12;
|
||||
const int kColorSpaceExtensionId = 13;
|
||||
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
@ -19,5 +19,6 @@ extern const int kVideoRotationExtensionId;
|
||||
extern const int kVideoContentTypeExtensionId;
|
||||
extern const int kVideoTimingExtensionId;
|
||||
extern const int kGenericDescriptorExtensionId;
|
||||
extern const int kColorSpaceExtensionId;
|
||||
} // namespace test
|
||||
} // namespace webrtc
|
||||
|
@ -50,6 +50,9 @@ class FrameGenerator {
|
||||
virtual ~FrameGenerator() = default;
|
||||
|
||||
// Returns video frame that remains valid until next call.
|
||||
// TODO(kron): Return rtc::scoped_refptr<VideoFrameBuffer> instead of
|
||||
// VideoFrame* and populate the VideoFrame struct in FrameGeneratorCapturer
|
||||
// using VideoFrame::Builder.
|
||||
virtual VideoFrame* NextFrame() = 0;
|
||||
|
||||
// Change the capture resolution.
|
||||
|
@ -147,6 +147,12 @@ void FrameGeneratorCapturer::SetFakeRotation(VideoRotation rotation) {
|
||||
fake_rotation_ = rotation;
|
||||
}
|
||||
|
||||
void FrameGeneratorCapturer::SetFakeColorSpace(
|
||||
absl::optional<ColorSpace> color_space) {
|
||||
rtc::CritScope cs(&lock_);
|
||||
fake_color_space_ = color_space;
|
||||
}
|
||||
|
||||
bool FrameGeneratorCapturer::Init() {
|
||||
// This check is added because frame_generator_ might be file based and should
|
||||
// not crash because a file moved.
|
||||
@ -173,6 +179,9 @@ void FrameGeneratorCapturer::InsertFrame() {
|
||||
frame->set_timestamp_us(clock_->TimeInMicroseconds());
|
||||
frame->set_ntp_time_ms(clock_->CurrentNtpInMilliseconds());
|
||||
frame->set_rotation(fake_rotation_);
|
||||
if (fake_color_space_) {
|
||||
frame->set_color_space(&fake_color_space_.value());
|
||||
}
|
||||
if (first_frame_capture_time_ == -1) {
|
||||
first_frame_capture_time_ = frame->ntp_time_ms();
|
||||
}
|
||||
|
@ -74,6 +74,7 @@ class FrameGeneratorCapturer : public TestVideoCapturer {
|
||||
|
||||
void ForceFrame();
|
||||
void SetFakeRotation(VideoRotation rotation);
|
||||
void SetFakeColorSpace(absl::optional<ColorSpace> color_space);
|
||||
|
||||
int64_t first_frame_capture_time() const { return first_frame_capture_time_; }
|
||||
|
||||
@ -101,6 +102,7 @@ class FrameGeneratorCapturer : public TestVideoCapturer {
|
||||
int target_capture_fps_ RTC_GUARDED_BY(&lock_);
|
||||
absl::optional<int> wanted_fps_ RTC_GUARDED_BY(&lock_);
|
||||
VideoRotation fake_rotation_ = kVideoRotation_0;
|
||||
absl::optional<ColorSpace> fake_color_space_ RTC_GUARDED_BY(&lock_);
|
||||
|
||||
int64_t first_frame_capture_time_;
|
||||
// Must be the last field, so it will be deconstructed first as tasks
|
||||
|
@ -8,7 +8,10 @@
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
#include "absl/types/optional.h"
|
||||
#include "api/test/video/function_video_encoder_factory.h"
|
||||
#include "api/video/color_space.h"
|
||||
#include "api/video/video_rotation.h"
|
||||
#include "media/engine/internaldecoderfactory.h"
|
||||
#include "media/engine/internalencoderfactory.h"
|
||||
#include "modules/video_coding/codecs/h264/include/h264.h"
|
||||
@ -22,6 +25,35 @@
|
||||
#include "test/gtest.h"
|
||||
|
||||
namespace webrtc {
|
||||
namespace {
|
||||
HdrMetadata CreateTestHdrMetadata() {
|
||||
// Random but reasonable HDR metadata.
|
||||
HdrMetadata hdr_metadata;
|
||||
hdr_metadata.mastering_metadata.luminance_max = 2000.0;
|
||||
hdr_metadata.mastering_metadata.luminance_min = 2.0001;
|
||||
hdr_metadata.mastering_metadata.primary_r.x = 0.3003;
|
||||
hdr_metadata.mastering_metadata.primary_r.y = 0.4004;
|
||||
hdr_metadata.mastering_metadata.primary_g.x = 0.3201;
|
||||
hdr_metadata.mastering_metadata.primary_g.y = 0.4604;
|
||||
hdr_metadata.mastering_metadata.primary_b.x = 0.3409;
|
||||
hdr_metadata.mastering_metadata.primary_b.y = 0.4907;
|
||||
hdr_metadata.mastering_metadata.white_point.x = 0.4103;
|
||||
hdr_metadata.mastering_metadata.white_point.y = 0.4806;
|
||||
hdr_metadata.max_content_light_level = 2345;
|
||||
hdr_metadata.max_frame_average_light_level = 1789;
|
||||
return hdr_metadata;
|
||||
}
|
||||
|
||||
ColorSpace CreateTestColorSpace(bool with_hdr_metadata) {
|
||||
HdrMetadata hdr_metadata = CreateTestHdrMetadata();
|
||||
return ColorSpace(
|
||||
ColorSpace::PrimaryID::kBT709, ColorSpace::TransferID::kGAMMA22,
|
||||
ColorSpace::MatrixID::kSMPTE2085, ColorSpace::RangeID::kFull,
|
||||
ColorSpace::ChromaSiting::kCollocated,
|
||||
ColorSpace::ChromaSiting::kCollocated,
|
||||
with_hdr_metadata ? &hdr_metadata : nullptr);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class CodecEndToEndTest : public test::CallTest,
|
||||
public testing::WithParamInterface<std::string> {
|
||||
@ -37,6 +69,7 @@ class CodecObserver : public test::EndToEndTest,
|
||||
public:
|
||||
CodecObserver(int no_frames_to_wait_for,
|
||||
VideoRotation rotation_to_test,
|
||||
absl::optional<ColorSpace> color_space_to_test,
|
||||
const std::string& payload_name,
|
||||
VideoEncoderFactory* encoder_factory,
|
||||
VideoDecoderFactory* decoder_factory)
|
||||
@ -45,6 +78,7 @@ class CodecObserver : public test::EndToEndTest,
|
||||
// https://bugs.webrtc.org/6830
|
||||
no_frames_to_wait_for_(no_frames_to_wait_for),
|
||||
expected_rotation_(rotation_to_test),
|
||||
expected_color_space_(color_space_to_test),
|
||||
payload_name_(payload_name),
|
||||
encoder_factory_(encoder_factory),
|
||||
decoder_factory_(decoder_factory),
|
||||
@ -75,6 +109,14 @@ class CodecObserver : public test::EndToEndTest,
|
||||
|
||||
void OnFrame(const VideoFrame& video_frame) override {
|
||||
EXPECT_EQ(expected_rotation_, video_frame.rotation());
|
||||
// Test only if explicit color space has been specified since otherwise the
|
||||
// color space is codec dependent.
|
||||
if (expected_color_space_) {
|
||||
EXPECT_EQ(expected_color_space_,
|
||||
video_frame.color_space()
|
||||
? absl::make_optional(*video_frame.color_space())
|
||||
: absl::nullopt);
|
||||
}
|
||||
if (++frame_counter_ == no_frames_to_wait_for_)
|
||||
observation_complete_.Set();
|
||||
}
|
||||
@ -82,11 +124,13 @@ class CodecObserver : public test::EndToEndTest,
|
||||
void OnFrameGeneratorCapturerCreated(
|
||||
test::FrameGeneratorCapturer* frame_generator_capturer) override {
|
||||
frame_generator_capturer->SetFakeRotation(expected_rotation_);
|
||||
frame_generator_capturer->SetFakeColorSpace(expected_color_space_);
|
||||
}
|
||||
|
||||
private:
|
||||
int no_frames_to_wait_for_;
|
||||
VideoRotation expected_rotation_;
|
||||
absl::optional<ColorSpace> expected_color_space_;
|
||||
std::string payload_name_;
|
||||
VideoEncoderFactory* encoder_factory_;
|
||||
VideoDecoderFactory* decoder_factory_;
|
||||
@ -103,8 +147,8 @@ TEST_P(CodecEndToEndTest, SendsAndReceivesVP8) {
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return VP8Decoder::Create(); });
|
||||
CodecObserver test(5, kVideoRotation_0, "VP8", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(5, kVideoRotation_0, absl::nullopt, "VP8",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -113,8 +157,8 @@ TEST_P(CodecEndToEndTest, SendsAndReceivesVP8Rotation90) {
|
||||
[]() { return VP8Encoder::Create(); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return VP8Decoder::Create(); });
|
||||
CodecObserver test(5, kVideoRotation_90, "VP8", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "VP8",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -124,8 +168,8 @@ TEST_P(CodecEndToEndTest, SendsAndReceivesVP9) {
|
||||
[]() { return VP9Encoder::Create(); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return VP9Decoder::Create(); });
|
||||
CodecObserver test(500, kVideoRotation_0, "VP9", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "VP9",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -134,8 +178,31 @@ TEST_P(CodecEndToEndTest, SendsAndReceivesVP9VideoRotation90) {
|
||||
[]() { return VP9Encoder::Create(); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return VP9Decoder::Create(); });
|
||||
CodecObserver test(5, kVideoRotation_90, "VP9", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "VP9",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
TEST_P(CodecEndToEndTest, SendsAndReceivesVP9ExplicitColorSpace) {
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP9Encoder::Create(); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return VP9Decoder::Create(); });
|
||||
CodecObserver test(5, kVideoRotation_90,
|
||||
CreateTestColorSpace(/*with_hdr_metadata=*/false), "VP9",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
TEST_P(CodecEndToEndTest,
|
||||
SendsAndReceivesVP9ExplicitColorSpaceWithHdrMetadata) {
|
||||
test::FunctionVideoEncoderFactory encoder_factory(
|
||||
[]() { return VP9Encoder::Create(); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return VP9Decoder::Create(); });
|
||||
CodecObserver test(5, kVideoRotation_90,
|
||||
CreateTestColorSpace(/*with_hdr_metadata=*/true), "VP9",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -154,8 +221,8 @@ TEST_P(CodecEndToEndTest, SendsAndReceivesMultiplex) {
|
||||
&internal_decoder_factory, SdpVideoFormat(cricket::kVp9CodecName));
|
||||
});
|
||||
|
||||
CodecObserver test(5, kVideoRotation_0, "multiplex", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(5, kVideoRotation_0, absl::nullopt, "multiplex",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -172,8 +239,8 @@ TEST_P(CodecEndToEndTest, SendsAndReceivesMultiplexVideoRotation90) {
|
||||
return absl::make_unique<MultiplexDecoderAdapter>(
|
||||
&internal_decoder_factory, SdpVideoFormat(cricket::kVp9CodecName));
|
||||
});
|
||||
CodecObserver test(5, kVideoRotation_90, "multiplex", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "multiplex",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -200,8 +267,8 @@ TEST_P(EndToEndTestH264, SendsAndReceivesH264) {
|
||||
[]() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return H264Decoder::Create(); });
|
||||
CodecObserver test(500, kVideoRotation_0, "H264", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "H264",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -210,8 +277,8 @@ TEST_P(EndToEndTestH264, SendsAndReceivesH264VideoRotation90) {
|
||||
[]() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return H264Decoder::Create(); });
|
||||
CodecObserver test(5, kVideoRotation_90, "H264", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "H264",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -222,8 +289,8 @@ TEST_P(EndToEndTestH264, SendsAndReceivesH264PacketizationMode0) {
|
||||
[codec]() { return H264Encoder::Create(codec); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return H264Decoder::Create(); });
|
||||
CodecObserver test(500, kVideoRotation_0, "H264", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "H264",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
|
||||
@ -234,8 +301,8 @@ TEST_P(EndToEndTestH264, SendsAndReceivesH264PacketizationMode1) {
|
||||
[codec]() { return H264Encoder::Create(codec); });
|
||||
test::FunctionVideoDecoderFactory decoder_factory(
|
||||
[]() { return H264Decoder::Create(); });
|
||||
CodecObserver test(500, kVideoRotation_0, "H264", &encoder_factory,
|
||||
&decoder_factory);
|
||||
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "H264",
|
||||
&encoder_factory, &decoder_factory);
|
||||
RunBaseTest(&test);
|
||||
}
|
||||
#endif // defined(WEBRTC_USE_H264)
|
||||
|
Reference in New Issue
Block a user