Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: content/renderer/media/rtc_video_encoder.cc

Issue 20632002: Add media::VideoEncodeAccelerator with WebRTC integration (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@git-svn
Patch Set: 7fd9dbd5 More debugging statements, some fixes Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/renderer/media/rtc_video_encoder.h"
6
7 #include <vector>
8
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "base/message_loop/message_loop_proxy.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "media/base/bitstream_buffer.h"
15 #include "media/filters/gpu_video_accelerator_factories.h"
16 #include "media/video/video_encode_accelerator.h"
17
18 namespace content {
19
20 // This private class of RTCVideoEncoder does the actual work of communicating
21 // with a media::VideoEncodeAccelerator for handling video encoding. It can
22 // be created on any thread, but should subsequently be posted to (and
23 // destroyed) on the thread that calls CreateAndInitializeVEA(). Notifications
24 // returned by the encoder are posted to the thread on which the instance was
25 // constructed.
26 //
27 // This class is separated from the RTCVideoEncoder class to allow
28 // RTCVideoEncoder to be deleted directly by WebRTC, while RTCVideoEncoder::Impl
29 // stays long enough to properly shut down the VEA.
30 class RTCVideoEncoder::Impl : public media::VideoEncodeAccelerator::Client {
31 public:
32 Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder);
Ami GONE FROM CHROMIUM 2013/07/31 23:01:12 single-arg ctors need to be marked explicit.
sheu 2013/08/02 01:27:49 Done.
33 virtual ~Impl();
34
35 // Create the VEA and call Initialize() on it. This instance of Impl is bound
36 // to whichever thread makes this call.
37 void CreateAndInitializeVEA(
38 const webrtc::VideoCodec& codecSettings,
39 media::VideoCodecProfile profile,
40 base::WaitableEvent* initialization_waiter,
41 int32_t* initialization_retval,
42 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
43 void Encode(const media::BitstreamBuffer& buffer, bool force_keyframe);
44 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer);
45 void RequestEncodingParameterChange(int32 bitrate);
46 static void Destroy(scoped_ptr<Impl> self);
47
48 // media::VideoEncodeAccelerator::Client implementation.
49 virtual void NotifyInitializeDone() OVERRIDE;
50 virtual void RequireBitstreamBuffers(int input_count,
51 const gfx::Size& input_dimensions,
52 size_t output_size) OVERRIDE;
53 virtual void NotifyInputDone(int32 bitstream_buffer_id) OVERRIDE;
54 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
55 size_t payload_size,
56 bool key_frame) OVERRIDE;
57 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
58
59 private:
60 base::ThreadChecker thread_checker_;
61
62 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
63 // notifications.
64 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
65
66 // The message loop on which to post notifications.
67 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
68
69 // webrtc::VideoEncoder expects initialization to be synchronous. Do this by
70 // waiting on the |initialization_waiter_| in InitEncode(). The event is
71 // signalled when initialization completes, or an error ooccurs, and the
72 // return value is retuned in |initialization_retval_|.
73 base::WaitableEvent* initialization_waiter_;
74 int32_t* initialization_retval_;
75
76 // The underling VEA to perform encoding on.
77 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
78
79 DISALLOW_COPY_AND_ASSIGN(Impl);
80 };
81
82 RTCVideoEncoder::Impl::Impl(
83 const base::WeakPtr<RTCVideoEncoder>& weak_encoder)
84 : weak_encoder_(weak_encoder),
85 encoder_message_loop_proxy_(base::MessageLoopProxy::current()),
86 initialization_waiter_(NULL),
87 initialization_retval_(NULL) {
88 thread_checker_.DetachFromThread();
89 }
90
91 RTCVideoEncoder::Impl::~Impl() {
92 DCHECK(thread_checker_.CalledOnValidThread());
93 DCHECK(!video_encoder_);
94 }
95
96 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
97 const webrtc::VideoCodec& codecSettings,
98 media::VideoCodecProfile profile,
99 base::WaitableEvent* initialization_waiter,
100 int32_t* initialization_retval,
101 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories) {
102 DCHECK(thread_checker_.CalledOnValidThread());
103
104 initialization_waiter_ = initialization_waiter;
105 initialization_retval_ = initialization_retval;
106 video_encoder_ = gpu_factories->CreateVideoEncodeAccelerator(this).Pass();
107 if (!video_encoder_) {
108 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
109 return;
110 }
111 gfx::Size dimensions(codecSettings.width, codecSettings.height);
112 video_encoder_->Initialize(
113 media::VideoFrame::I420,
114 dimensions,
115 profile,
116 codecSettings.startBitrate * 1000); // startBitrate is in kbits/sec.
117 }
118
119 void RTCVideoEncoder::Impl::Encode(const media::BitstreamBuffer& buffer,
120 bool force_keyframe) {
121 DCHECK(thread_checker_.CalledOnValidThread());
122 if (video_encoder_)
123 video_encoder_->Encode(buffer, force_keyframe);
124 }
125
126 void RTCVideoEncoder::Impl::UseOutputBitstreamBuffer(
127 const media::BitstreamBuffer& buffer) {
128 DCHECK(thread_checker_.CalledOnValidThread());
129 if (video_encoder_)
130 video_encoder_->UseOutputBitstreamBuffer(buffer);
131 }
132
133 void RTCVideoEncoder::Impl::RequestEncodingParameterChange(int32 bitrate) {
134 DCHECK(thread_checker_.CalledOnValidThread());
135 if (video_encoder_)
136 video_encoder_->RequestEncodingParameterChange(bitrate);
137 }
138
139 // static
140 void RTCVideoEncoder::Impl::Destroy(scoped_ptr<Impl> self) {
141 DCHECK(self->thread_checker_.CalledOnValidThread());
142 if (self->video_encoder_)
143 self->video_encoder_.release()->Destroy();
144 }
145
146 void RTCVideoEncoder::Impl::NotifyInitializeDone() {
147 DCHECK(thread_checker_.CalledOnValidThread());
148 *initialization_retval_ = WEBRTC_VIDEO_CODEC_OK;
149 initialization_waiter_->Signal();
150 initialization_retval_ = NULL;
151 initialization_waiter_ = NULL;
152 }
153
154 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
155 int input_count,
156 const gfx::Size& input_dimensions,
157 size_t output_size) {
158 DCHECK(thread_checker_.CalledOnValidThread());
159 encoder_message_loop_proxy_->PostTask(
160 FROM_HERE,
161 base::Bind(&RTCVideoEncoder::RequireBitstreamBuffers,
162 weak_encoder_,
163 input_count,
164 input_dimensions,
165 output_size));
166 }
167
168 void RTCVideoEncoder::Impl::NotifyInputDone(int32 bitstream_buffer_id) {
169 DCHECK(thread_checker_.CalledOnValidThread());
170 encoder_message_loop_proxy_->PostTask(
171 FROM_HERE,
172 base::Bind(&RTCVideoEncoder::NotifyInputDone,
173 weak_encoder_,
174 bitstream_buffer_id));
175 }
176
177 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
178 size_t payload_size,
179 bool key_frame) {
180 DCHECK(thread_checker_.CalledOnValidThread());
181 encoder_message_loop_proxy_->PostTask(
182 FROM_HERE,
183 base::Bind(&RTCVideoEncoder::BitstreamBufferReady,
184 weak_encoder_,
185 bitstream_buffer_id,
186 payload_size,
187 key_frame));
188 }
189
190 void RTCVideoEncoder::Impl::NotifyError(
191 media::VideoEncodeAccelerator::Error error) {
192 DCHECK(thread_checker_.CalledOnValidThread());
193 int32_t retval;
194 switch (error) {
195 default:
196 retval = WEBRTC_VIDEO_CODEC_ERROR;
197 }
198
199 if (video_encoder_)
200 video_encoder_.release()->Destroy();
201
202 if (initialization_waiter_) {
203 *initialization_retval_ = retval;
204 initialization_waiter_->Signal();
205 initialization_retval_ = NULL;
206 initialization_waiter_ = NULL;
207 } else {
208 encoder_message_loop_proxy_->PostTask(
209 FROM_HERE,
210 base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
211 }
212 }
213
214 RTCVideoEncoder::RTCVideoEncoder(
215 media::VideoCodecProfile profile,
216 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
217 : video_codec_profile_(profile),
218 gpu_factories_(gpu_factories),
219 impl_message_loop_proxy_(gpu_factories_->GetMessageLoop()),
220 weak_this_factory_(this),
221 weak_this_(weak_this_factory_.GetWeakPtr()),
222 encoded_image_callback_(NULL),
223 impl_status_(WEBRTC_VIDEO_CODEC_OK) {
224 DVLOG(1) << "RTCVideoEncoder::RTCVideoEncoder(): profile=" << profile;
225 }
226
227 RTCVideoEncoder::~RTCVideoEncoder() {
228 DCHECK(thread_checker_.CalledOnValidThread());
229 Release();
230 DCHECK(!impl_);
231 }
232
233 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
234 int32_t number_of_cores,
235 uint32_t max_payload_size) {
236 DCHECK(thread_checker_.CalledOnValidThread());
237 DCHECK(!impl_);
238 DVLOG(1) << "RTCVideoEncoder::InitEncode(): "
239 "codecType=" << codec_settings->codecType
240 << ", width=" << codec_settings->width
241 << ", height=" << codec_settings->height
242 << ", startBitrate=" << codec_settings->startBitrate;
243
244 impl_.reset(new Impl(weak_this_));
245 base::WaitableEvent initialization_waiter(true, false);
246 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
247 impl_message_loop_proxy_->PostTask(
248 FROM_HERE,
249 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
250 base::Unretained(impl_.get()),
251 *codec_settings,
252 video_codec_profile_,
253 &initialization_waiter,
254 &initialization_retval,
255 gpu_factories_));
256
257 // webrtc::VideoEncoder expects this call to be synchronous.
258 initialization_waiter.Wait();
259 return initialization_retval;
260 }
261
262 int32_t RTCVideoEncoder::Encode(
263 const webrtc::I420VideoFrame& input_image,
264 const webrtc::CodecSpecificInfo* codec_specific_info,
265 const std::vector<webrtc::VideoFrameType>* frame_types) {
266 DCHECK(thread_checker_.CalledOnValidThread());
267 if (!impl_)
268 return impl_status_;
269
270 if (input_buffers_free_.empty())
271 return WEBRTC_VIDEO_CODEC_OK;
272 int index = input_buffers_free_.back();
273 input_buffers_free_.pop_back();
274 base::SharedMemory* input_buffer = input_buffers_[index];
275
276 // Do a strided copy of the input frame to match the input requirements for
277 // the encoder.
278 const uint8_t* src = input_image.buffer(webrtc::kYPlane);
279 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory());
280 int width = input_frame_dimensions_.width();
281 int stride = input_image.stride(webrtc::kYPlane);
282 for (int i = 0; i < input_image.height(); ++i) {
283 memcpy(dst, src, width);
284 dst += stride;
285 src += width;
286 }
287 src = input_image.buffer(webrtc::kUPlane);
288 width = input_frame_dimensions_.width() / 2;
289 stride = input_image.stride(webrtc::kUPlane);
290 for (int i = 0; i < input_image.height() / 2; ++i) {
291 memcpy(dst, src, width);
292 dst += stride;
293 src += width;
294 }
295 src = input_image.buffer(webrtc::kVPlane);
296 width = input_frame_dimensions_.width() / 2;
297 stride = input_image.stride(webrtc::kVPlane);
298 for (int i = 0; i < input_image.height() / 2; ++i) {
299 memcpy(dst, src, width);
300 dst += stride;
301 src += width;
302 }
303
304 const webrtc::VideoFrameType type = frame_types->front();
305 DVLOG(3) << "RTCVideoEncoder::Encode() buffer.id()=" << index;
306 impl_message_loop_proxy_->PostTask(
307 FROM_HERE,
308 base::Bind(
309 &RTCVideoEncoder::Impl::Encode,
310 base::Unretained(impl_.get()),
311 media::BitstreamBuffer(index,
312 input_buffer->handle(),
313 input_frame_dimensions_.GetArea() * 3 / 2),
314 (type == webrtc::kKeyFrame)));
315 return WEBRTC_VIDEO_CODEC_OK;
316 }
317
318 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
319 webrtc::EncodedImageCallback* callback) {
320 DCHECK(thread_checker_.CalledOnValidThread());
321 if (!impl_)
322 return impl_status_;
323
324 encoded_image_callback_ = callback;
325 return WEBRTC_VIDEO_CODEC_OK;
326 }
327
328 int32_t RTCVideoEncoder::Release() {
329 DCHECK(thread_checker_.CalledOnValidThread());
330 if (!impl_)
331 return impl_status_;
332
333 impl_message_loop_proxy_->PostTask(
334 FROM_HERE,
335 base::Bind(&RTCVideoEncoder::Impl::Destroy, base::Passed(&impl_)));
336 return WEBRTC_VIDEO_CODEC_OK;
337 }
338
339 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
340 DCHECK(thread_checker_.CalledOnValidThread());
341 // Ignored.
342 return WEBRTC_VIDEO_CODEC_OK;
343 }
344
345 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
346 DCHECK(thread_checker_.CalledOnValidThread());
347 if (!impl_)
348 return impl_status_;
349
350 impl_message_loop_proxy_->PostTask(
351 FROM_HERE,
352 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParameterChange,
353 base::Unretained(impl_.get()),
354 new_bit_rate));
355 return WEBRTC_VIDEO_CODEC_OK;
356 }
357
358 void RTCVideoEncoder::RequireBitstreamBuffers(int input_count,
359 const gfx::Size& input_dimensions,
360 size_t output_size) {
361 DCHECK(thread_checker_.CalledOnValidThread());
362 DCHECK_EQ(input_buffers_.size(), 0U);
363 DCHECK_EQ(output_buffers_.size(), 0U);
364 input_frame_dimensions_ = input_dimensions;
365 output_buffer_size_ = output_size;
366
367 for (int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
368 scoped_ptr<base::SharedMemory> shm(gpu_factories_->CreateSharedMemory(
369 input_frame_dimensions_.GetArea() * 3 / 2));
370 if (shm)
371 input_buffers_.push_back(shm.release());
372 }
373 for (size_t i = 0; i < input_buffers_.size(); ++i)
374 input_buffers_free_.push_back(i);
375
376 for (int i = 0; i < kOutputBufferCount; ++i) {
377 scoped_ptr<base::SharedMemory> shm(
378 gpu_factories_->CreateSharedMemory(output_buffer_size_));
379 if (shm)
380 output_buffers_.push_back(shm.release());
381 }
382
383 // Immediately provide all output buffers to the VEA.
384 for (size_t i = 0; i < output_buffers_.size(); ++i) {
385 impl_message_loop_proxy_->PostTask(
386 FROM_HERE,
387 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBuffer,
388 base::Unretained(impl_.get()),
389 media::BitstreamBuffer(i,
390 output_buffers_[i]->handle(),
391 output_buffers_[i]->mapped_size())));
392 }
393 }
394
395 void RTCVideoEncoder::NotifyInputDone(int32 bitstream_buffer_id) {
396 DCHECK(thread_checker_.CalledOnValidThread());
397
398 if (!impl_)
399 return;
400 if (bitstream_buffer_id < 0 ||
401 bitstream_buffer_id >= (int32)input_buffers_.size())
402 return;
403 input_buffers_free_.push_back(bitstream_buffer_id);
404 }
405
406 void RTCVideoEncoder::BitstreamBufferReady(int32 bitstream_buffer_id,
407 size_t payload_size,
408 bool key_frame) {
409 DCHECK(thread_checker_.CalledOnValidThread());
410
411 if (!impl_)
412 return;
413 if (!encoded_image_callback_)
414 return;
415 if (bitstream_buffer_id < 0 ||
416 bitstream_buffer_id >= (int32)output_buffers_.size())
417 return;
418 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
419 if (payload_size > output_buffer->mapped_size())
420 return;
421
422 webrtc::EncodedImage image(
423 reinterpret_cast<uint8_t*>(output_buffer->memory()),
424 payload_size,
425 output_buffer->mapped_size());
426 image._encodedWidth = output_frame_dimensions_.width();
427 image._encodedHeight = output_frame_dimensions_.height();
428 image._frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
429 image._completeFrame = true;
430 DVLOG(3) << "RTCVideoEncoder::BitstreamBufferReady() buffer.id()="
431 << bitstream_buffer_id;
432 int32_t retval = encoded_image_callback_->Encoded(image, NULL, NULL);
433 if (retval < 0) {
434 NotifyError(retval);
435 return;
436 }
437
438 // The call through webrtc::EncodedImageCallback is synchronous, so we can
439 // immediately recycle the output buffer back to the VEA.
440 impl_message_loop_proxy_->PostTask(
441 FROM_HERE,
442 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBuffer,
443 base::Unretained(impl_.get()),
444 media::BitstreamBuffer(bitstream_buffer_id,
445 output_buffer->handle(),
446 output_buffer->mapped_size())));
447 }
448
449 void RTCVideoEncoder::NotifyError(int32_t error) {
450 DCHECK(thread_checker_.CalledOnValidThread());
451 impl_status_ = error;
452 impl_message_loop_proxy_->PostTask(
453 FROM_HERE,
454 base::Bind(&RTCVideoEncoder::Impl::Destroy, base::Passed(&impl_)));
455 }
456
457 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698