blob: f2c3ea61c46636af85979e7b94945f4aca5e5656 [file] [log] [blame]
/*
* Copyright (c) 2015 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 "webrtc/video_encoder.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/video_coding/include/video_error_codes.h"
namespace webrtc {
const int kWidth = 320;
const int kHeight = 240;
const size_t kMaxPayloadSize = 800;
class VideoEncoderSoftwareFallbackWrapperTest : public ::testing::Test {
protected:
VideoEncoderSoftwareFallbackWrapperTest()
: fallback_wrapper_(kVideoCodecVP8, &fake_encoder_) {}
class CountingFakeEncoder : public VideoEncoder {
public:
int32_t InitEncode(const VideoCodec* codec_settings,
int32_t number_of_cores,
size_t max_payload_size) override {
++init_encode_count_;
return init_encode_return_code_;
}
int32_t Encode(const VideoFrame& frame,
const CodecSpecificInfo* codec_specific_info,
const std::vector<FrameType>* frame_types) override {
++encode_count_;
return encode_return_code_;
}
int32_t RegisterEncodeCompleteCallback(
EncodedImageCallback* callback) override {
encode_complete_callback_ = callback;
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t Release() override {
++release_count_;
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t SetChannelParameters(uint32_t packet_loss, int64_t rtt) override {
++set_channel_parameters_count_;
return WEBRTC_VIDEO_CODEC_OK;
}
int32_t SetRates(uint32_t bitrate, uint32_t framerate) override {
++set_rates_count_;
return WEBRTC_VIDEO_CODEC_OK;
}
void OnDroppedFrame() override { ++on_dropped_frame_count_; }
bool SupportsNativeHandle() const override {
++supports_native_handle_count_;
return false;
}
const char* ImplementationName() const override {
return "fake-encoder";
}
int init_encode_count_ = 0;
int32_t init_encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
int32_t encode_return_code_ = WEBRTC_VIDEO_CODEC_OK;
int encode_count_ = 0;
EncodedImageCallback* encode_complete_callback_ = nullptr;
int release_count_ = 0;
int set_channel_parameters_count_ = 0;
int set_rates_count_ = 0;
int on_dropped_frame_count_ = 0;
mutable int supports_native_handle_count_ = 0;
};
class FakeEncodedImageCallback : public EncodedImageCallback {
public:
int32_t Encoded(const EncodedImage& encoded_image,
const CodecSpecificInfo* codec_specific_info,
const RTPFragmentationHeader* fragmentation) override {
return ++callback_count_;
}
int callback_count_ = 0;
};
void UtilizeFallbackEncoder();
void FallbackFromEncodeRequest();
void EncodeFrame();
FakeEncodedImageCallback callback_;
CountingFakeEncoder fake_encoder_;
VideoEncoderSoftwareFallbackWrapper fallback_wrapper_;
VideoCodec codec_ = {};
VideoFrame frame_;
};
void VideoEncoderSoftwareFallbackWrapperTest::EncodeFrame() {
frame_.CreateEmptyFrame(kWidth, kHeight, kWidth, (kWidth + 1) / 2,
(kWidth + 1) / 2);
memset(frame_.video_frame_buffer()->MutableDataY(), 16,
frame_.allocated_size(webrtc::kYPlane));
memset(frame_.video_frame_buffer()->MutableDataU(), 128,
frame_.allocated_size(webrtc::kUPlane));
memset(frame_.video_frame_buffer()->MutableDataV(), 128,
frame_.allocated_size(webrtc::kVPlane));
std::vector<FrameType> types(1, kVideoFrameKey);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
fallback_wrapper_.Encode(frame_, nullptr, &types));
}
void VideoEncoderSoftwareFallbackWrapperTest::UtilizeFallbackEncoder() {
fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
EXPECT_EQ(&callback_, fake_encoder_.encode_complete_callback_);
// Register with failing fake encoder. Should succeed with VP8 fallback.
codec_.codecType = kVideoCodecVP8;
codec_.maxFramerate = 30;
codec_.width = kWidth;
codec_.height = kHeight;
fake_encoder_.init_encode_return_code_ = WEBRTC_VIDEO_CODEC_ERROR;
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRates(300, 30));
int callback_count = callback_.callback_count_;
int encode_count = fake_encoder_.encode_count_;
EncodeFrame();
EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
EXPECT_EQ(callback_count + 1, callback_.callback_count_);
}
void VideoEncoderSoftwareFallbackWrapperTest::FallbackFromEncodeRequest() {
fallback_wrapper_.RegisterEncodeCompleteCallback(&callback_);
codec_.codecType = kVideoCodecVP8;
codec_.maxFramerate = 30;
codec_.width = kWidth;
codec_.height = kHeight;
fallback_wrapper_.InitEncode(&codec_, 2, kMaxPayloadSize);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.SetRates(300, 30));
EXPECT_EQ(1, fake_encoder_.init_encode_count_);
// Have the non-fallback encoder request a software fallback.
fake_encoder_.encode_return_code_ = WEBRTC_VIDEO_CODEC_FALLBACK_SOFTWARE;
int callback_count = callback_.callback_count_;
int encode_count = fake_encoder_.encode_count_;
EncodeFrame();
// Single encode request, which returned failure.
EXPECT_EQ(encode_count + 1, fake_encoder_.encode_count_);
EXPECT_EQ(callback_count + 1, callback_.callback_count_);
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest, InitializesEncoder) {
VideoCodec codec = {};
fallback_wrapper_.InitEncode(&codec, 2, kMaxPayloadSize);
EXPECT_EQ(1, fake_encoder_.init_encode_count_);
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest, EncodeRequestsFallback) {
FallbackFromEncodeRequest();
// After fallback, further encodes shouldn't hit the fake encoder.
int encode_count = fake_encoder_.encode_count_;
EncodeFrame();
EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest, CanUtilizeFallbackEncoder) {
UtilizeFallbackEncoder();
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
InternalEncoderReleasedDuringFallback) {
EXPECT_EQ(0, fake_encoder_.release_count_);
UtilizeFallbackEncoder();
EXPECT_EQ(1, fake_encoder_.release_count_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
// No extra release when the fallback is released.
EXPECT_EQ(1, fake_encoder_.release_count_);
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
InternalEncoderNotEncodingDuringFallback) {
UtilizeFallbackEncoder();
int encode_count = fake_encoder_.encode_count_;
EncodeFrame();
EXPECT_EQ(encode_count, fake_encoder_.encode_count_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
CanRegisterCallbackWhileUsingFallbackEncoder) {
UtilizeFallbackEncoder();
// Registering an encode-complete callback should still work when fallback
// encoder is being used.
FakeEncodedImageCallback callback2;
fallback_wrapper_.RegisterEncodeCompleteCallback(&callback2);
EXPECT_EQ(&callback2, fake_encoder_.encode_complete_callback_);
// Encoding a frame using the fallback should arrive at the new callback.
std::vector<FrameType> types(1, kVideoFrameKey);
frame_.set_timestamp(frame_.timestamp() + 1000);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK,
fallback_wrapper_.Encode(frame_, nullptr, &types));
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
SetChannelParametersForwardedDuringFallback) {
UtilizeFallbackEncoder();
EXPECT_EQ(0, fake_encoder_.set_channel_parameters_count_);
fallback_wrapper_.SetChannelParameters(1, 1);
EXPECT_EQ(1, fake_encoder_.set_channel_parameters_count_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
SetRatesForwardedDuringFallback) {
UtilizeFallbackEncoder();
EXPECT_EQ(1, fake_encoder_.set_rates_count_);
fallback_wrapper_.SetRates(1, 1);
EXPECT_EQ(2, fake_encoder_.set_rates_count_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
OnDroppedFrameForwardedWithoutFallback) {
fallback_wrapper_.OnDroppedFrame();
EXPECT_EQ(1, fake_encoder_.on_dropped_frame_count_);
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
OnDroppedFrameNotForwardedDuringFallback) {
UtilizeFallbackEncoder();
fallback_wrapper_.OnDroppedFrame();
EXPECT_EQ(0, fake_encoder_.on_dropped_frame_count_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
SupportsNativeHandleForwardedWithoutFallback) {
fallback_wrapper_.SupportsNativeHandle();
EXPECT_EQ(1, fake_encoder_.supports_native_handle_count_);
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
SupportsNativeHandleNotForwardedDuringFallback) {
UtilizeFallbackEncoder();
fallback_wrapper_.SupportsNativeHandle();
EXPECT_EQ(0, fake_encoder_.supports_native_handle_count_);
EXPECT_EQ(WEBRTC_VIDEO_CODEC_OK, fallback_wrapper_.Release());
}
TEST_F(VideoEncoderSoftwareFallbackWrapperTest,
ReportsFallbackImplementationName) {
UtilizeFallbackEncoder();
// Hard coded expected value since libvpx is the software implementation name
// for VP8. Change accordingly if the underlying implementation does.
EXPECT_STREQ("libvpx (fallback from: fake-encoder)",
fallback_wrapper_.ImplementationName());
}
} // namespace webrtc