blob: 9ef7b1c7b15c403955bb24741ab61ab8a4d8499f [file] [log] [blame]
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +02001/*
2 * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "test/fake_vp8_encoder.h"
12
Erik Språng4529fbc2018-10-12 10:30:31 +020013#include "api/video_codecs/create_vp8_temporal_layers.h"
14#include "api/video_codecs/vp8_temporal_layers.h"
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020015#include "common_types.h" // NOLINT(build/include)
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020016#include "modules/video_coding/include/video_codec_interface.h"
17#include "modules/video_coding/include/video_error_codes.h"
18#include "modules/video_coding/utility/simulcast_utility.h"
19#include "rtc_base/checks.h"
20#include "rtc_base/logging.h"
21#include "rtc_base/random.h"
22#include "rtc_base/timeutils.h"
23
Per Kjellander841c9122018-10-04 18:40:28 +020024namespace {
25
26// Write width and height to the payload the same way as the real encoder does.
27// It requires that |payload| has a size of at least kMinPayLoadHeaderLength.
28void WriteFakeVp8(unsigned char* payload,
29 int width,
30 int height,
31 bool key_frame) {
32 payload[0] = key_frame ? 0 : 0x01;
33
34 if (key_frame) {
35 payload[9] = (height & 0x3F00) >> 8;
36 payload[8] = (height & 0x00FF);
37
38 payload[7] = (width & 0x3F00) >> 8;
39 payload[6] = (width & 0x00FF);
40 }
41}
42} // namespace
43
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020044namespace webrtc {
45
46namespace test {
47
48FakeVP8Encoder::FakeVP8Encoder(Clock* clock)
49 : FakeEncoder(clock), callback_(nullptr) {
50 FakeEncoder::RegisterEncodeCompleteCallback(this);
51 sequence_checker_.Detach();
52}
53
54int32_t FakeVP8Encoder::RegisterEncodeCompleteCallback(
55 EncodedImageCallback* callback) {
56 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
57 callback_ = callback;
58 return 0;
59}
60
61int32_t FakeVP8Encoder::InitEncode(const VideoCodec* config,
62 int32_t number_of_cores,
63 size_t max_payload_size) {
64 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
65 auto result =
66 FakeEncoder::InitEncode(config, number_of_cores, max_payload_size);
67 if (result != WEBRTC_VIDEO_CODEC_OK) {
68 return result;
69 }
70
Erik Språng8abd56c2018-10-01 18:47:03 +020071 SetupTemporalLayers(*config);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020072
73 return WEBRTC_VIDEO_CODEC_OK;
74}
75
76int32_t FakeVP8Encoder::Release() {
77 auto result = FakeEncoder::Release();
78 sequence_checker_.Detach();
79 return result;
80}
81
Erik Språng8abd56c2018-10-01 18:47:03 +020082void FakeVP8Encoder::SetupTemporalLayers(const VideoCodec& codec) {
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020083 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
84
Erik Språng8abd56c2018-10-01 18:47:03 +020085 int num_streams = SimulcastUtility::NumberOfSimulcastStreams(codec);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020086 for (int i = 0; i < num_streams; ++i) {
Erik Språng4529fbc2018-10-12 10:30:31 +020087 Vp8TemporalLayersType type;
Erik Språng8abd56c2018-10-01 18:47:03 +020088 int num_temporal_layers =
89 SimulcastUtility::NumberOfTemporalLayers(codec, i);
90 if (SimulcastUtility::IsConferenceModeScreenshare(codec) && i == 0) {
Erik Språng4529fbc2018-10-12 10:30:31 +020091 type = Vp8TemporalLayersType::kBitrateDynamic;
Erik Språng8abd56c2018-10-01 18:47:03 +020092 // Legacy screenshare layers supports max 2 layers.
93 num_temporal_layers = std::max<int>(2, num_temporal_layers);
94 } else {
Erik Språng4529fbc2018-10-12 10:30:31 +020095 type = Vp8TemporalLayersType::kFixedPattern;
Erik Språng8abd56c2018-10-01 18:47:03 +020096 }
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020097 temporal_layers_.emplace_back(
Erik Språng4529fbc2018-10-12 10:30:31 +020098 CreateVp8TemporalLayers(type, num_temporal_layers));
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +020099 }
100}
101
Erik Språng59021ba2018-10-03 11:05:16 +0200102void FakeVP8Encoder::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
103 size_t size_bytes,
104 FrameType frame_type,
105 int stream_idx,
106 uint32_t timestamp) {
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200107 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
108 codec_specific->codecType = kVideoCodecVP8;
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200109 CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200110 vp8Info->keyIdx = kNoKeyIdx;
111 vp8Info->nonReference = false;
Erik Språng59021ba2018-10-03 11:05:16 +0200112 temporal_layers_[stream_idx]->OnEncodeDone(
113 timestamp, size_bytes, frame_type == kVideoFrameKey, -1, vp8Info);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200114}
115
116EncodedImageCallback::Result FakeVP8Encoder::OnEncodedImage(
117 const EncodedImage& encoded_image,
118 const CodecSpecificInfo* codec_specific_info,
119 const RTPFragmentationHeader* fragments) {
120 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
Niels Möllerd3b8c632018-08-27 15:33:42 +0200121 uint8_t stream_idx = encoded_image.SpatialIndex().value_or(0);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200122 CodecSpecificInfo overrided_specific_info;
Erik Språng59021ba2018-10-03 11:05:16 +0200123 temporal_layers_[stream_idx]->UpdateLayerConfig(encoded_image.Timestamp());
124 PopulateCodecSpecific(&overrided_specific_info, encoded_image._length,
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200125 encoded_image._frameType, stream_idx,
Niels Möller72bc8d62018-09-12 10:03:51 +0200126 encoded_image.Timestamp());
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200127
Per Kjellander841c9122018-10-04 18:40:28 +0200128 // Write width and height to the payload the same way as the real encoder
129 // does.
130 WriteFakeVp8(encoded_image._buffer, encoded_image._encodedWidth,
131 encoded_image._encodedHeight,
132 encoded_image._frameType == kVideoFrameKey);
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200133 return callback_->OnEncodedImage(encoded_image, &overrided_specific_info,
134 fragments);
135}
136
Erik Språng86336a52018-11-15 15:38:05 +0100137VideoEncoder::EncoderInfo FakeVP8Encoder::GetEncoderInfo() const {
138 EncoderInfo info;
139 info.implementation_name = "FakeVp8Encoder";
140 return info;
141}
142
Ilya Nikolaevskiyb0588e62018-08-27 14:12:27 +0200143} // namespace test
144} // namespace webrtc