blob: fdad4caa55e14a67bf0a60a7f55f0523e15d322d [file] [log] [blame]
stefan@webrtc.org360e3762013-08-22 09:29:56 +00001/*
2 * Copyright (c) 2013 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
pbos@webrtc.org16e03b72013-10-28 16:32:01 +000011#include "webrtc/test/fake_encoder.h"
stefan@webrtc.org360e3762013-08-22 09:29:56 +000012
brandtre78d2662017-01-16 05:57:16 -080013#include <string.h>
14
palmkviste75f2042016-09-28 06:19:48 -070015#include <algorithm>
brandtre78d2662017-01-16 05:57:16 -080016#include <memory>
palmkviste75f2042016-09-28 06:19:48 -070017
perkj26091b12016-09-01 01:17:40 -070018#include "webrtc/base/checks.h"
brandtre78d2662017-01-16 05:57:16 -080019#include "webrtc/common_types.h"
Henrik Kjellander2557b862015-11-18 22:00:21 +010020#include "webrtc/modules/video_coding/include/video_codec_interface.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/sleep.h"
kwibergac9f8762016-09-30 22:29:43 -070022#include "webrtc/test/gtest.h"
pbos@webrtc.orgab990ae2014-09-17 09:02:25 +000023
stefan@webrtc.org360e3762013-08-22 09:29:56 +000024namespace webrtc {
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +000025namespace test {
stefan@webrtc.org360e3762013-08-22 09:29:56 +000026
sprangcdafeda2017-06-08 06:12:05 -070027const int kKeyframeSizeFactor = 10;
28
stefan@webrtc.org360e3762013-08-22 09:29:56 +000029FakeEncoder::FakeEncoder(Clock* clock)
30 : clock_(clock),
brandtre78d2662017-01-16 05:57:16 -080031 callback_(nullptr),
sprangcdafeda2017-06-08 06:12:05 -070032 configured_input_framerate_(-1),
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000033 max_target_bitrate_kbps_(-1),
sprangcdafeda2017-06-08 06:12:05 -070034 pending_keyframe_(true),
35 debt_bytes_(0) {
sprang@webrtc.org40709352013-11-26 11:41:59 +000036 // Generate some arbitrary not-all-zero data
37 for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
38 encoded_buffer_[i] = static_cast<uint8_t>(i);
39 }
stefan@webrtc.org360e3762013-08-22 09:29:56 +000040}
41
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000042void FakeEncoder::SetMaxBitrate(int max_kbps) {
perkj26091b12016-09-01 01:17:40 -070043 RTC_DCHECK_GE(max_kbps, -1); // max_kbps == -1 disables it.
brandtre78d2662017-01-16 05:57:16 -080044 rtc::CritScope cs(&crit_sect_);
pbos@webrtc.org3349ae02014-03-13 12:52:27 +000045 max_target_bitrate_kbps_ = max_kbps;
46}
47
stefan@webrtc.org360e3762013-08-22 09:29:56 +000048int32_t FakeEncoder::InitEncode(const VideoCodec* config,
49 int32_t number_of_cores,
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000050 size_t max_payload_size) {
brandtre78d2662017-01-16 05:57:16 -080051 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +000052 config_ = *config;
Erik Språng08127a92016-11-16 16:41:30 +010053 target_bitrate_.SetBitrate(0, 0, config_.startBitrate * 1000);
sprangcdafeda2017-06-08 06:12:05 -070054 configured_input_framerate_ = config_.maxFramerate;
55 pending_keyframe_ = true;
stefan@webrtc.org360e3762013-08-22 09:29:56 +000056 return 0;
57}
58
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -070059int32_t FakeEncoder::Encode(const VideoFrame& input_image,
60 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -070061 const std::vector<FrameType>* frame_types) {
brandtre78d2662017-01-16 05:57:16 -080062 unsigned char max_framerate;
63 unsigned char num_simulcast_streams;
64 SimulcastStream simulcast_streams[kMaxSimulcastStreams];
65 EncodedImageCallback* callback;
66 uint32_t target_bitrate_sum_kbps;
67 int max_target_bitrate_kbps;
brandtre78d2662017-01-16 05:57:16 -080068 size_t num_encoded_bytes;
sprangcdafeda2017-06-08 06:12:05 -070069 int framerate;
ilnik00d802b2017-04-11 10:34:31 -070070 VideoCodecMode mode;
sprangcdafeda2017-06-08 06:12:05 -070071 bool keyframe;
brandtre78d2662017-01-16 05:57:16 -080072 {
73 rtc::CritScope cs(&crit_sect_);
74 max_framerate = config_.maxFramerate;
75 num_simulcast_streams = config_.numberOfSimulcastStreams;
76 for (int i = 0; i < num_simulcast_streams; ++i) {
77 simulcast_streams[i] = config_.simulcastStream[i];
78 }
79 callback = callback_;
80 target_bitrate_sum_kbps = target_bitrate_.get_sum_kbps();
81 max_target_bitrate_kbps = max_target_bitrate_kbps_;
brandtre78d2662017-01-16 05:57:16 -080082 num_encoded_bytes = sizeof(encoded_buffer_);
ilnik00d802b2017-04-11 10:34:31 -070083 mode = config_.mode;
sprangcdafeda2017-06-08 06:12:05 -070084 if (configured_input_framerate_ > 0) {
85 framerate = configured_input_framerate_;
86 } else {
87 framerate = max_framerate;
88 }
89 keyframe = pending_keyframe_;
90 pending_keyframe_ = false;
brandtre78d2662017-01-16 05:57:16 -080091 }
92
sprangcdafeda2017-06-08 06:12:05 -070093 for (FrameType frame_type : *frame_types) {
94 if (frame_type == kVideoFrameKey) {
95 keyframe = true;
96 break;
97 }
98 }
99
brandtre78d2662017-01-16 05:57:16 -0800100 RTC_DCHECK_GT(max_framerate, 0);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000101
sprangcdafeda2017-06-08 06:12:05 -0700102 size_t bitrate =
103 std::max(target_bitrate_sum_kbps, simulcast_streams[0].minBitrate);
104 if (max_target_bitrate_kbps > 0)
105 bitrate = std::min(bitrate, static_cast<size_t>(max_target_bitrate_kbps));
brandtre78d2662017-01-16 05:57:16 -0800106
sprangcdafeda2017-06-08 06:12:05 -0700107 size_t bits_available = bitrate * 1000 / framerate;
brandtre78d2662017-01-16 05:57:16 -0800108
109 RTC_DCHECK_GT(num_simulcast_streams, 0);
110 for (unsigned char i = 0; i < num_simulcast_streams; ++i) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000111 CodecSpecificInfo specifics;
112 memset(&specifics, 0, sizeof(specifics));
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000113 specifics.codecType = kVideoCodecGeneric;
114 specifics.codecSpecific.generic.simulcast_idx = i;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000115 size_t min_stream_bits = static_cast<size_t>(
sprangcdafeda2017-06-08 06:12:05 -0700116 (simulcast_streams[i].minBitrate * 1000) / framerate);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000117 size_t max_stream_bits = static_cast<size_t>(
sprangcdafeda2017-06-08 06:12:05 -0700118 (simulcast_streams[i].maxBitrate * 1000) / framerate);
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000119 size_t stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000120 bits_available;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000121 size_t stream_bytes = (stream_bits + 7) / 8;
sprangcdafeda2017-06-08 06:12:05 -0700122 if (keyframe) {
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000123 // The first frame is a key frame and should be larger.
sprangcdafeda2017-06-08 06:12:05 -0700124 // Store the overshoot bytes and distribute them over the coming frames,
125 // so that we on average meet the bitrate target.
126 debt_bytes_ += (kKeyframeSizeFactor - 1) * stream_bytes;
127 stream_bytes *= kKeyframeSizeFactor;
128 } else {
129 if (debt_bytes_ > 0) {
130 // Pay at most half of the frame size for old debts.
131 size_t payment_size = std::min(stream_bytes / 2, debt_bytes_);
132 debt_bytes_ -= payment_size;
133 stream_bytes -= payment_size;
134 }
stefan@webrtc.org0bae1fa2014-11-05 14:05:29 +0000135 }
sprangcdafeda2017-06-08 06:12:05 -0700136
brandtre78d2662017-01-16 05:57:16 -0800137 if (stream_bytes > num_encoded_bytes)
138 stream_bytes = num_encoded_bytes;
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000139
perkj26091b12016-09-01 01:17:40 -0700140 // Always encode something on the first frame.
141 if (min_stream_bits > bits_available && i > 0)
142 continue;
brandtre78d2662017-01-16 05:57:16 -0800143
144 std::unique_ptr<uint8_t[]> encoded_buffer(new uint8_t[num_encoded_bytes]);
145 memcpy(encoded_buffer.get(), encoded_buffer_, num_encoded_bytes);
146 EncodedImage encoded(encoded_buffer.get(), stream_bytes, num_encoded_bytes);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000147 encoded._timeStamp = input_image.timestamp();
148 encoded.capture_time_ms_ = input_image.render_time_ms();
pbos@webrtc.org0181b5f2013-09-09 08:26:30 +0000149 encoded._frameType = (*frame_types)[i];
brandtre78d2662017-01-16 05:57:16 -0800150 encoded._encodedWidth = simulcast_streams[i].width;
151 encoded._encodedHeight = simulcast_streams[i].height;
perkj803d97f2016-11-01 11:45:46 -0700152 encoded.rotation_ = input_image.rotation();
ilnik00d802b2017-04-11 10:34:31 -0700153 encoded.content_type_ = (mode == kScreensharing)
154 ? VideoContentType::SCREENSHARE
155 : VideoContentType::UNSPECIFIED;
perkj275afc52016-09-01 00:21:16 -0700156 specifics.codec_name = ImplementationName();
brandtre78d2662017-01-16 05:57:16 -0800157 RTC_DCHECK(callback);
158 if (callback->OnEncodedImage(encoded, &specifics, nullptr).error !=
sergeyu2cb155a2016-11-04 11:39:29 -0700159 EncodedImageCallback::Result::OK) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000160 return -1;
sergeyu2cb155a2016-11-04 11:39:29 -0700161 }
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +0000162 bits_available -= std::min(encoded._length * 8, bits_available);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000163 }
164 return 0;
165}
166
167int32_t FakeEncoder::RegisterEncodeCompleteCallback(
168 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800169 rtc::CritScope cs(&crit_sect_);
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000170 callback_ = callback;
171 return 0;
172}
173
174int32_t FakeEncoder::Release() { return 0; }
175
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000176int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int64_t rtt) {
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000177 return 0;
178}
179
Erik Språng08127a92016-11-16 16:41:30 +0100180int32_t FakeEncoder::SetRateAllocation(const BitrateAllocation& rate_allocation,
181 uint32_t framerate) {
brandtre78d2662017-01-16 05:57:16 -0800182 rtc::CritScope cs(&crit_sect_);
Erik Språng08127a92016-11-16 16:41:30 +0100183 target_bitrate_ = rate_allocation;
sprangcdafeda2017-06-08 06:12:05 -0700184 configured_input_framerate_ = framerate;
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000185 return 0;
186}
pbos@webrtc.org3349ae02014-03-13 12:52:27 +0000187
Peter Boströmb7d9a972015-12-18 16:01:11 +0100188const char* FakeEncoder::kImplementationName = "fake_encoder";
189const char* FakeEncoder::ImplementationName() const {
190 return kImplementationName;
191}
192
sprangcdafeda2017-06-08 06:12:05 -0700193int FakeEncoder::GetConfiguredInputFramerate() const {
194 rtc::CritScope cs(&crit_sect_);
195 return configured_input_framerate_;
196}
197
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000198FakeH264Encoder::FakeH264Encoder(Clock* clock)
brandtre78d2662017-01-16 05:57:16 -0800199 : FakeEncoder(clock), callback_(nullptr), idr_counter_(0) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000200 FakeEncoder::RegisterEncodeCompleteCallback(this);
201}
202
203int32_t FakeH264Encoder::RegisterEncodeCompleteCallback(
204 EncodedImageCallback* callback) {
brandtre78d2662017-01-16 05:57:16 -0800205 rtc::CritScope cs(&local_crit_sect_);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000206 callback_ = callback;
207 return 0;
208}
209
Sergey Ulanov525df3f2016-08-02 17:46:41 -0700210EncodedImageCallback::Result FakeH264Encoder::OnEncodedImage(
211 const EncodedImage& encoded_image,
212 const CodecSpecificInfo* codec_specific_info,
213 const RTPFragmentationHeader* fragments) {
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000214 const size_t kSpsSize = 8;
215 const size_t kPpsSize = 11;
216 const int kIdrFrequency = 10;
brandtre78d2662017-01-16 05:57:16 -0800217 EncodedImageCallback* callback;
218 int current_idr_counter;
219 {
220 rtc::CritScope cs(&local_crit_sect_);
221 callback = callback_;
222 current_idr_counter = idr_counter_;
223 ++idr_counter_;
224 }
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000225 RTPFragmentationHeader fragmentation;
brandtre78d2662017-01-16 05:57:16 -0800226 if (current_idr_counter % kIdrFrequency == 0 &&
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000227 encoded_image._length > kSpsSize + kPpsSize + 1) {
228 const size_t kNumSlices = 3;
229 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
230 fragmentation.fragmentationOffset[0] = 0;
231 fragmentation.fragmentationLength[0] = kSpsSize;
232 fragmentation.fragmentationOffset[1] = kSpsSize;
233 fragmentation.fragmentationLength[1] = kPpsSize;
234 fragmentation.fragmentationOffset[2] = kSpsSize + kPpsSize;
235 fragmentation.fragmentationLength[2] =
236 encoded_image._length - (kSpsSize + kPpsSize);
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000237 const size_t kSpsNalHeader = 0x67;
238 const size_t kPpsNalHeader = 0x68;
239 const size_t kIdrNalHeader = 0x65;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000240 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kSpsNalHeader;
241 encoded_image._buffer[fragmentation.fragmentationOffset[1]] = kPpsNalHeader;
242 encoded_image._buffer[fragmentation.fragmentationOffset[2]] = kIdrNalHeader;
243 } else {
244 const size_t kNumSlices = 1;
245 fragmentation.VerifyAndAllocateFragmentationHeader(kNumSlices);
246 fragmentation.fragmentationOffset[0] = 0;
247 fragmentation.fragmentationLength[0] = encoded_image._length;
glaznev@webrtc.orge69220c2015-02-05 17:56:15 +0000248 const size_t kNalHeader = 0x41;
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000249 encoded_image._buffer[fragmentation.fragmentationOffset[0]] = kNalHeader;
250 }
251 uint8_t value = 0;
252 int fragment_counter = 0;
253 for (size_t i = 0; i < encoded_image._length; ++i) {
254 if (fragment_counter == fragmentation.fragmentationVectorSize ||
255 i != fragmentation.fragmentationOffset[fragment_counter]) {
256 encoded_image._buffer[i] = value++;
257 } else {
258 ++fragment_counter;
259 }
260 }
palmkviste75f2042016-09-28 06:19:48 -0700261 CodecSpecificInfo specifics;
262 memset(&specifics, 0, sizeof(specifics));
263 specifics.codecType = kVideoCodecH264;
hta9aa96882016-12-06 05:36:03 -0800264 specifics.codecSpecific.H264.packetization_mode =
265 H264PacketizationMode::NonInterleaved;
brandtre78d2662017-01-16 05:57:16 -0800266 RTC_DCHECK(callback);
267 return callback->OnEncodedImage(encoded_image, &specifics, &fragmentation);
stefan@webrtc.org79c33592014-08-06 09:24:53 +0000268}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000269
270DelayedEncoder::DelayedEncoder(Clock* clock, int delay_ms)
brandtr49ce67c2017-02-11 00:25:18 -0800271 : test::FakeEncoder(clock), delay_ms_(delay_ms) {
272 // The encoder could be created on a different thread than
273 // it is being used on.
274 sequence_checker_.Detach();
275}
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000276
perkj803d97f2016-11-01 11:45:46 -0700277void DelayedEncoder::SetDelay(int delay_ms) {
brandtr49ce67c2017-02-11 00:25:18 -0800278 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
perkj803d97f2016-11-01 11:45:46 -0700279 delay_ms_ = delay_ms;
280}
281
Miguel Casas-Sanchez47650702015-05-29 17:21:40 -0700282int32_t DelayedEncoder::Encode(const VideoFrame& input_image,
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000283 const CodecSpecificInfo* codec_specific_info,
pbos22993e12015-10-19 02:39:06 -0700284 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800285 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
286
287 SleepMs(delay_ms_);
288
asapersson@webrtc.org049e4ec2014-11-20 10:19:46 +0000289 return FakeEncoder::Encode(input_image, codec_specific_info, frame_types);
290}
brandtr696c9c62016-12-19 05:47:28 -0800291
brandtre78d2662017-01-16 05:57:16 -0800292MultithreadedFakeH264Encoder::MultithreadedFakeH264Encoder(Clock* clock)
brandtr696c9c62016-12-19 05:47:28 -0800293 : test::FakeH264Encoder(clock),
294 current_queue_(0),
brandtr49ce67c2017-02-11 00:25:18 -0800295 queue1_(nullptr),
296 queue2_(nullptr) {
297 // The encoder could be created on a different thread than
298 // it is being used on.
299 sequence_checker_.Detach();
300}
brandtr696c9c62016-12-19 05:47:28 -0800301
brandtr49ce67c2017-02-11 00:25:18 -0800302int32_t MultithreadedFakeH264Encoder::InitEncode(const VideoCodec* config,
303 int32_t number_of_cores,
304 size_t max_payload_size) {
305 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
306
307 queue1_.reset(new rtc::TaskQueue("Queue 1"));
308 queue2_.reset(new rtc::TaskQueue("Queue 2"));
309
310 return FakeH264Encoder::InitEncode(config, number_of_cores, max_payload_size);
311}
brandtr696c9c62016-12-19 05:47:28 -0800312
brandtre78d2662017-01-16 05:57:16 -0800313class MultithreadedFakeH264Encoder::EncodeTask : public rtc::QueuedTask {
brandtr696c9c62016-12-19 05:47:28 -0800314 public:
brandtre78d2662017-01-16 05:57:16 -0800315 EncodeTask(MultithreadedFakeH264Encoder* encoder,
brandtr696c9c62016-12-19 05:47:28 -0800316 const VideoFrame& input_image,
317 const CodecSpecificInfo* codec_specific_info,
318 const std::vector<FrameType>* frame_types)
319 : encoder_(encoder),
320 input_image_(input_image),
321 codec_specific_info_(),
322 frame_types_(*frame_types) {
323 if (codec_specific_info)
324 codec_specific_info_ = *codec_specific_info;
325 }
326
327 private:
328 bool Run() override {
329 encoder_->EncodeCallback(input_image_, &codec_specific_info_,
330 &frame_types_);
331 return true;
332 }
333
brandtre78d2662017-01-16 05:57:16 -0800334 MultithreadedFakeH264Encoder* const encoder_;
brandtr696c9c62016-12-19 05:47:28 -0800335 VideoFrame input_image_;
336 CodecSpecificInfo codec_specific_info_;
337 std::vector<FrameType> frame_types_;
338};
339
brandtre78d2662017-01-16 05:57:16 -0800340int32_t MultithreadedFakeH264Encoder::Encode(
brandtr696c9c62016-12-19 05:47:28 -0800341 const VideoFrame& input_image,
342 const CodecSpecificInfo* codec_specific_info,
343 const std::vector<FrameType>* frame_types) {
brandtr49ce67c2017-02-11 00:25:18 -0800344 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtr696c9c62016-12-19 05:47:28 -0800345
brandtr49ce67c2017-02-11 00:25:18 -0800346 std::unique_ptr<rtc::TaskQueue>& queue =
347 (current_queue_++ % 2 == 0) ? queue1_ : queue2_;
348
349 if (!queue) {
350 return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
351 }
352
353 queue->PostTask(std::unique_ptr<rtc::QueuedTask>(
brandtr696c9c62016-12-19 05:47:28 -0800354 new EncodeTask(this, input_image, codec_specific_info, frame_types)));
355
brandtr49ce67c2017-02-11 00:25:18 -0800356 return WEBRTC_VIDEO_CODEC_OK;
brandtr696c9c62016-12-19 05:47:28 -0800357}
358
brandtre78d2662017-01-16 05:57:16 -0800359int32_t MultithreadedFakeH264Encoder::EncodeCallback(
brandtr696c9c62016-12-19 05:47:28 -0800360 const VideoFrame& input_image,
361 const CodecSpecificInfo* codec_specific_info,
362 const std::vector<FrameType>* frame_types) {
363 return FakeH264Encoder::Encode(input_image, codec_specific_info, frame_types);
364}
365
brandtr49ce67c2017-02-11 00:25:18 -0800366int32_t MultithreadedFakeH264Encoder::Release() {
367 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
368
369 queue1_.reset();
370 queue2_.reset();
371
372 return FakeH264Encoder::Release();
373}
374
pbos@webrtc.orgcb5118c2013-09-03 09:10:37 +0000375} // namespace test
stefan@webrtc.org360e3762013-08-22 09:29:56 +0000376} // namespace webrtc