You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
289 lines
11 KiB
289 lines
11 KiB
/*
|
|
* Copyright 2018 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include <memory>
|
|
#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 "common_video/test/utilities.h"
|
|
#include "media/engine/internal_decoder_factory.h"
|
|
#include "media/engine/internal_encoder_factory.h"
|
|
#include "modules/video_coding/codecs/h264/include/h264.h"
|
|
#include "modules/video_coding/codecs/multiplex/include/multiplex_decoder_adapter.h"
|
|
#include "modules/video_coding/codecs/multiplex/include/multiplex_encoder_adapter.h"
|
|
#include "modules/video_coding/codecs/vp8/include/vp8.h"
|
|
#include "modules/video_coding/codecs/vp9/include/vp9.h"
|
|
#include "test/call_test.h"
|
|
#include "test/encoder_settings.h"
|
|
#include "test/field_trial.h"
|
|
#include "test/gtest.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
enum : int { // The first valid value is 1.
|
|
kColorSpaceExtensionId = 1,
|
|
kVideoRotationExtensionId,
|
|
};
|
|
} // namespace
|
|
|
|
class CodecEndToEndTest : public test::CallTest {
|
|
public:
|
|
CodecEndToEndTest() {
|
|
RegisterRtpExtension(
|
|
RtpExtension(RtpExtension::kColorSpaceUri, kColorSpaceExtensionId));
|
|
RegisterRtpExtension(RtpExtension(RtpExtension::kVideoRotationUri,
|
|
kVideoRotationExtensionId));
|
|
}
|
|
};
|
|
|
|
class CodecObserver : public test::EndToEndTest,
|
|
public rtc::VideoSinkInterface<VideoFrame> {
|
|
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)
|
|
: EndToEndTest(4 * CodecEndToEndTest::kDefaultTimeoutMs),
|
|
// TODO(hta): This timeout (120 seconds) is excessive.
|
|
// 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),
|
|
frame_counter_(0) {}
|
|
|
|
void PerformTest() override {
|
|
EXPECT_TRUE(Wait())
|
|
<< "Timed out while waiting for enough frames to be decoded.";
|
|
}
|
|
|
|
void ModifyVideoConfigs(
|
|
VideoSendStream::Config* send_config,
|
|
std::vector<VideoReceiveStream::Config>* receive_configs,
|
|
VideoEncoderConfig* encoder_config) override {
|
|
encoder_config->codec_type = PayloadStringToCodecType(payload_name_);
|
|
send_config->encoder_settings.encoder_factory = encoder_factory_;
|
|
send_config->rtp.payload_name = payload_name_;
|
|
send_config->rtp.payload_type = test::CallTest::kVideoSendPayloadType;
|
|
|
|
(*receive_configs)[0].renderer = this;
|
|
(*receive_configs)[0].decoders.resize(1);
|
|
(*receive_configs)[0].decoders[0].payload_type =
|
|
send_config->rtp.payload_type;
|
|
(*receive_configs)[0].decoders[0].video_format =
|
|
SdpVideoFormat(send_config->rtp.payload_name);
|
|
(*receive_configs)[0].decoders[0].decoder_factory = decoder_factory_;
|
|
}
|
|
|
|
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();
|
|
}
|
|
|
|
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_;
|
|
int frame_counter_;
|
|
};
|
|
|
|
TEST_F(CodecEndToEndTest, SendsAndReceivesVP8) {
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return VP8Encoder::Create(); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return VP8Decoder::Create(); });
|
|
CodecObserver test(5, kVideoRotation_0, absl::nullopt, "VP8",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(CodecEndToEndTest, SendsAndReceivesVP8Rotation90) {
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return VP8Encoder::Create(); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return VP8Decoder::Create(); });
|
|
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "VP8",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
#if defined(RTC_ENABLE_VP9)
|
|
TEST_F(CodecEndToEndTest, SendsAndReceivesVP9) {
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return VP9Encoder::Create(); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return VP9Decoder::Create(); });
|
|
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "VP9",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(CodecEndToEndTest, SendsAndReceivesVP9VideoRotation90) {
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return VP9Encoder::Create(); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return VP9Decoder::Create(); });
|
|
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "VP9",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(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_F(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);
|
|
}
|
|
|
|
// Mutiplex tests are using VP9 as the underlying implementation.
|
|
TEST_F(CodecEndToEndTest, SendsAndReceivesMultiplex) {
|
|
InternalEncoderFactory internal_encoder_factory;
|
|
InternalDecoderFactory internal_decoder_factory;
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[&internal_encoder_factory]() {
|
|
return std::make_unique<MultiplexEncoderAdapter>(
|
|
&internal_encoder_factory, SdpVideoFormat(cricket::kVp9CodecName));
|
|
});
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[&internal_decoder_factory]() {
|
|
return std::make_unique<MultiplexDecoderAdapter>(
|
|
&internal_decoder_factory, SdpVideoFormat(cricket::kVp9CodecName));
|
|
});
|
|
|
|
CodecObserver test(5, kVideoRotation_0, absl::nullopt, "multiplex",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_F(CodecEndToEndTest, SendsAndReceivesMultiplexVideoRotation90) {
|
|
InternalEncoderFactory internal_encoder_factory;
|
|
InternalDecoderFactory internal_decoder_factory;
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[&internal_encoder_factory]() {
|
|
return std::make_unique<MultiplexEncoderAdapter>(
|
|
&internal_encoder_factory, SdpVideoFormat(cricket::kVp9CodecName));
|
|
});
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[&internal_decoder_factory]() {
|
|
return std::make_unique<MultiplexDecoderAdapter>(
|
|
&internal_decoder_factory, SdpVideoFormat(cricket::kVp9CodecName));
|
|
});
|
|
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "multiplex",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
#endif // defined(RTC_ENABLE_VP9)
|
|
|
|
#if defined(WEBRTC_USE_H264)
|
|
class EndToEndTestH264 : public test::CallTest,
|
|
public ::testing::WithParamInterface<std::string> {
|
|
public:
|
|
EndToEndTestH264() : field_trial_(GetParam()) {
|
|
RegisterRtpExtension(RtpExtension(RtpExtension::kVideoRotationUri,
|
|
kVideoRotationExtensionId));
|
|
}
|
|
|
|
private:
|
|
test::ScopedFieldTrials field_trial_;
|
|
};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
SpsPpsIdrIsKeyframe,
|
|
EndToEndTestH264,
|
|
::testing::Values("WebRTC-SpsPpsIdrIsH264Keyframe/Disabled/",
|
|
"WebRTC-SpsPpsIdrIsH264Keyframe/Enabled/"));
|
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264) {
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return H264Decoder::Create(); });
|
|
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "H264",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264VideoRotation90) {
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[]() { return H264Encoder::Create(cricket::VideoCodec("H264")); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return H264Decoder::Create(); });
|
|
CodecObserver test(5, kVideoRotation_90, absl::nullopt, "H264",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264PacketizationMode0) {
|
|
cricket::VideoCodec codec = cricket::VideoCodec("H264");
|
|
codec.SetParam(cricket::kH264FmtpPacketizationMode, "0");
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[codec]() { return H264Encoder::Create(codec); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return H264Decoder::Create(); });
|
|
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "H264",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
|
|
TEST_P(EndToEndTestH264, SendsAndReceivesH264PacketizationMode1) {
|
|
cricket::VideoCodec codec = cricket::VideoCodec("H264");
|
|
codec.SetParam(cricket::kH264FmtpPacketizationMode, "1");
|
|
test::FunctionVideoEncoderFactory encoder_factory(
|
|
[codec]() { return H264Encoder::Create(codec); });
|
|
test::FunctionVideoDecoderFactory decoder_factory(
|
|
[]() { return H264Decoder::Create(); });
|
|
CodecObserver test(500, kVideoRotation_0, absl::nullopt, "H264",
|
|
&encoder_factory, &decoder_factory);
|
|
RunBaseTest(&test);
|
|
}
|
|
#endif // defined(WEBRTC_USE_H264)
|
|
|
|
} // namespace webrtc
|