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

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: 4cd5068c WIP - almost done, just comments (and debugging prints) left Created 7 years, 5 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/message_loop/message_loop_proxy.h"
12 #include "base/synchronization/waitable_event.h"
13 #include "media/base/bitstream_buffer.h"
14 #include "media/filters/gpu_video_accelerator_factories.h"
15 #include "media/video/video_encode_accelerator.h"
16
17 namespace content {
18
19 // This private class of RTCVideEncoder does the actual work of communicating
20 // with a media::VideoEncodeAccelerator for handling video encoding. It can
21 // be created on any thread, but should subsequently be posted to (and
22 // destroyed) on the thread that calls CreateAndInitializeVEA(). The
23 // constructor is provided with |encoder_message_loop_proxy| for posting
24 // returning notifications.
25 //
26 // This class is separated from the RTCVideoEncoder class to allow
27 // RTCVideoEncoder to be deleted directly by WebRTC, while RTCVideoEncoder::Impl
28 // handles properly shutting down the VEA.
29 class RTCVideoEncoder::Impl : public media::VideoEncodeAccelerator::Client {
30 public:
31 Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
32 const scoped_refptr<base::MessageLoopProxy>& encoder_message_loop_proxy);
33 virtual ~Impl();
34
35 void CreateAndInitializeVEA(
36 const webrtc::VideoCodec& codecSettings,
37 media::VideoCodecProfile profile,
38 base::WaitableEvent* initialization_waiter,
39 int32_t* initialization_retval,
40 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories);
41 void Encode(const media::BitstreamBuffer& buffer, bool force_keyframe);
42 void UseOutputBitstreamBuffer(const media::BitstreamBuffer& buffer);
43 void RequestEncodingParameterChange(int32 bitrate);
44 static void Destroy(scoped_ptr<Impl> self);
45
46 // media::VideoEncodeAccelerator::Client implementation.
47 virtual void NotifyInitializeDone() OVERRIDE;
48 virtual void RequireBitstreamBuffers(int input_count,
49 const gfx::Size& input_dimensions,
50 size_t output_size) OVERRIDE;
51 virtual void NotifyInputDone(int32 bitstream_buffer_id) OVERRIDE;
52 virtual void BitstreamBufferReady(int32 bitstream_buffer_id,
53 size_t size,
54 bool key_frame) OVERRIDE;
55 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE;
56
57 private:
58 base::ThreadChecker thread_checker_;
59 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
60 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_;
61 base::WaitableEvent* initialization_waiter_;
62 int32_t* initialization_retval_;
63 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_;
64
65 DISALLOW_COPY_AND_ASSIGN(Impl);
66 };
67
68 RTCVideoEncoder::Impl::Impl(
69 const base::WeakPtr<RTCVideoEncoder>& weak_encoder,
70 const scoped_refptr<base::MessageLoopProxy>& encoder_message_loop_proxy)
71 : weak_encoder_(weak_encoder),
72 encoder_message_loop_proxy_(encoder_message_loop_proxy),
73 initialization_waiter_(NULL),
74 initialization_retval_(NULL) {
75 thread_checker_.DetachFromThread();
76 }
77
78 RTCVideoEncoder::Impl::~Impl() {
79 DCHECK(thread_checker_.CalledOnValidThread());
80 DCHECK(!video_encoder_);
81 }
82
83 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
84 const webrtc::VideoCodec& codecSettings,
85 media::VideoCodecProfile profile,
86 base::WaitableEvent* initialization_waiter,
87 int32_t* initialization_retval,
88 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories) {
89 DCHECK(thread_checker_.CalledOnValidThread());
90
91 initialization_waiter_ = initialization_waiter;
92 initialization_retval_ = initialization_retval;
93 video_encoder_ = gpu_factories->CreateVideoEncodeAccelerator(this).Pass();
94 if (!video_encoder_) {
95 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
96 return;
97 }
98 gfx::Size dimensions(codecSettings.width, codecSettings.height);
99 video_encoder_->Initialize(
100 media::VideoFrame::I420, dimensions, profile, codecSettings.startBitrate);
101 }
102
103 void RTCVideoEncoder::Impl::Encode(const media::BitstreamBuffer& buffer,
104 bool force_keyframe) {
105 DCHECK(thread_checker_.CalledOnValidThread());
106 if (video_encoder_)
107 video_encoder_->Encode(buffer, force_keyframe);
108 }
109
110 void RTCVideoEncoder::Impl::UseOutputBitstreamBuffer(
111 const media::BitstreamBuffer& buffer) {
112 DCHECK(thread_checker_.CalledOnValidThread());
113 if (video_encoder_)
114 video_encoder_->UseOutputBitstreamBuffer(buffer);
115 }
116
117 void RTCVideoEncoder::Impl::RequestEncodingParameterChange(int32 bitrate) {
118 DCHECK(thread_checker_.CalledOnValidThread());
119 if (video_encoder_)
120 video_encoder_->RequestEncodingParameterChange(bitrate);
121 }
122
123 // static
124 void RTCVideoEncoder::Impl::Destroy(scoped_ptr<Impl> self) {
125 DCHECK(self->thread_checker_.CalledOnValidThread());
126 if (self->video_encoder_)
127 self->video_encoder_.release()->Destroy();
128 }
129
130 void RTCVideoEncoder::Impl::NotifyInitializeDone() {
131 DCHECK(thread_checker_.CalledOnValidThread());
132 *initialization_retval_ = WEBRTC_VIDEO_CODEC_OK;
133 initialization_waiter_->Signal();
134 }
135
136 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
137 int input_count,
138 const gfx::Size& input_dimensions,
139 size_t output_size) {
140 DCHECK(thread_checker_.CalledOnValidThread());
141 encoder_message_loop_proxy_->PostTask(
142 FROM_HERE,
143 base::Bind(&RTCVideoEncoder::RequireBitstreamBuffers,
144 weak_encoder_,
145 input_count,
146 input_dimensions,
147 output_size));
148 }
149
150 void RTCVideoEncoder::Impl::NotifyInputDone(int32 bitstream_buffer_id) {
151 DCHECK(thread_checker_.CalledOnValidThread());
152 encoder_message_loop_proxy_->PostTask(
153 FROM_HERE,
154 base::Bind(&RTCVideoEncoder::NotifyInputDone,
155 weak_encoder_,
156 bitstream_buffer_id));
157 }
158
159 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id,
160 size_t size,
161 bool key_frame) {
162 DCHECK(thread_checker_.CalledOnValidThread());
163 encoder_message_loop_proxy_->PostTask(
164 FROM_HERE,
165 base::Bind(&RTCVideoEncoder::BitstreamBufferReady,
166 weak_encoder_,
167 bitstream_buffer_id,
168 size,
169 key_frame));
170 }
171
172 void RTCVideoEncoder::Impl::NotifyError(
173 media::VideoEncodeAccelerator::Error error) {
174 DCHECK(thread_checker_.CalledOnValidThread());
175 int32_t retval;
176 switch (error) {
177 default:
178 retval = WEBRTC_VIDEO_CODEC_ERROR;
179 }
180
181 if (video_encoder_)
182 video_encoder_.release()->Destroy();
183
184 if (initialization_waiter_) {
185 *initialization_retval_ = retval;
186 initialization_waiter_->Signal();
187 } else {
188 encoder_message_loop_proxy_->PostTask(
189 FROM_HERE,
190 base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
191 }
192 }
193
194 RTCVideoEncoder::RTCVideoEncoder(
195 media::VideoCodecProfile profile,
196 const scoped_refptr<media::GpuVideoAcceleratorFactories>& gpu_factories)
197 : video_codec_profile_(profile),
198 gpu_factories_(gpu_factories),
199 impl_message_loop_proxy_(gpu_factories_->GetMessageLoop()),
200 weak_this_factory_(this),
201 weak_this_(weak_this_factory_.GetWeakPtr()),
202 encoded_image_callback_(NULL),
203 impl_status_(WEBRTC_VIDEO_CODEC_OK) {}
204
205 RTCVideoEncoder::~RTCVideoEncoder() {
206 DCHECK(thread_checker_.CalledOnValidThread());
207 Release();
208 DCHECK(!impl_);
209 }
210
211 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
212 int32_t number_of_cores,
213 uint32_t max_payload_size) {
214 DCHECK(thread_checker_.CalledOnValidThread());
215 DCHECK(!impl_);
216 impl_.reset(new Impl(weak_this_, impl_message_loop_proxy_));
217 base::WaitableEvent initialization_waiter(true, false);
218 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
219 impl_message_loop_proxy_->PostTask(
220 FROM_HERE,
221 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
222 base::Unretained(impl_.get()),
223 *codec_settings,
224 video_codec_profile_,
225 &initialization_waiter,
226 &initialization_retval,
227 gpu_factories_));
228 initialization_waiter.Wait();
229 return initialization_retval;
230 }
231
232 int32_t RTCVideoEncoder::Encode(
233 const webrtc::I420VideoFrame& input_image,
234 const webrtc::CodecSpecificInfo* codec_specific_info,
235 const std::vector<webrtc::VideoFrameType>* frame_types) {
236 DCHECK(thread_checker_.CalledOnValidThread());
237 if (!impl_)
238 return impl_status_;
239
240 if (input_buffers_free_.empty())
241 return WEBRTC_VIDEO_CODEC_OK;
242 int index = input_buffers_free_.back();
243 input_buffers_free_.pop_back();
244 base::SharedMemory* input_buffer = input_buffers_[index];
245
246 const uint8_t* src = input_image.buffer(webrtc::kYPlane);
247 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory());
248 int width = input_frame_dimensions_.width();
249 int stride = input_image.stride(webrtc::kYPlane);
250 for (int i = 0; i < input_image.height(); ++i) {
251 memcpy(dst, src, width);
252 dst += stride;
253 src += width;
254 }
255 src = input_image.buffer(webrtc::kUPlane);
256 width = input_frame_dimensions_.width() / 2;
257 stride = input_image.stride(webrtc::kUPlane);
258 for (int i = 0; i < input_image.height() / 2; ++i) {
259 memcpy(dst, src, width);
260 dst += stride;
261 src += width;
262 }
263 src = input_image.buffer(webrtc::kVPlane);
264 width = input_frame_dimensions_.width() / 2;
265 stride = input_image.stride(webrtc::kVPlane);
266 for (int i = 0; i < input_image.height() / 2; ++i) {
267 memcpy(dst, src, width);
268 dst += stride;
269 src += width;
270 }
271
272 webrtc::VideoFrameType type = frame_types->front();
273 impl_message_loop_proxy_->PostTask(
274 FROM_HERE,
275 base::Bind(
276 &RTCVideoEncoder::Impl::Encode,
277 base::Unretained(impl_.get()),
278 media::BitstreamBuffer(index,
279 input_buffer->handle(),
280 input_frame_dimensions_.GetArea() * 3 / 2),
281 (type == webrtc::kKeyFrame)));
282 return WEBRTC_VIDEO_CODEC_OK;
283 }
284
285 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
286 webrtc::EncodedImageCallback* callback) {
287 DCHECK(thread_checker_.CalledOnValidThread());
288 if (!impl_)
289 return impl_status_;
290
291 encoded_image_callback_ = callback;
292 return WEBRTC_VIDEO_CODEC_OK;
293 }
294
295 int32_t RTCVideoEncoder::Release() {
296 DCHECK(thread_checker_.CalledOnValidThread());
297 if (!impl_)
298 return impl_status_;
299
300 impl_message_loop_proxy_->PostTask(
301 FROM_HERE,
302 base::Bind(&RTCVideoEncoder::Impl::Destroy, base::Passed(&impl_)));
303 return WEBRTC_VIDEO_CODEC_OK;
304 }
305
306 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
307 DCHECK(thread_checker_.CalledOnValidThread());
308 // Ignored.
309 return WEBRTC_VIDEO_CODEC_OK;
310 }
311
312 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
313 DCHECK(thread_checker_.CalledOnValidThread());
314 if (!impl_)
315 return impl_status_;
316
317 impl_message_loop_proxy_->PostTask(
318 FROM_HERE,
319 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParameterChange,
320 base::Unretained(impl_.get()),
321 new_bit_rate));
322 return WEBRTC_VIDEO_CODEC_OK;
323 }
324
325 void RTCVideoEncoder::RequireBitstreamBuffers(int input_count,
326 const gfx::Size& input_dimensions,
327 size_t output_size) {
328 DCHECK(thread_checker_.CalledOnValidThread());
329 DCHECK_EQ(input_buffers_.size(), 0U);
330 DCHECK_EQ(output_buffers_.size(), 0U);
331 input_frame_dimensions_ = input_dimensions;
332 output_buffer_size_ = output_size;
333
334 for (int i = 0; i < input_count + kInputBufferExtraCount; ++i) {
335 scoped_ptr<base::SharedMemory> shm(gpu_factories_->CreateSharedMemory(
336 input_frame_dimensions_.GetArea() * 3 / 2));
337 if (shm)
338 input_buffers_.push_back(shm.release());
339 }
340 for (size_t i = 0; i < input_buffers_.size(); ++i)
341 input_buffers_free_.push_back(i);
342
343 for (int i = 0; i < kOutputBufferCount; ++i) {
344 scoped_ptr<base::SharedMemory> shm(
345 gpu_factories_->CreateSharedMemory(output_buffer_size_));
346 if (shm)
347 output_buffers_.push_back(shm.release());
348 }
349
350 for (size_t i = 0; i < output_buffers_.size(); ++i) {
351 impl_message_loop_proxy_->PostTask(
352 FROM_HERE,
353 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBuffer,
354 base::Unretained(impl_.get()),
355 media::BitstreamBuffer(i,
356 output_buffers_[i]->handle(),
357 output_buffers_[i]->mapped_size())));
358 }
359 }
360
361 void RTCVideoEncoder::NotifyInputDone(int32 bitstream_buffer_id) {
362 DCHECK(thread_checker_.CalledOnValidThread());
363
364 if (!impl_)
365 return;
366 if (bitstream_buffer_id < 0 ||
367 bitstream_buffer_id >= (int32)input_buffers_.size())
368 return;
369 input_buffers_free_.push_back(bitstream_buffer_id);
370 }
371
372 void RTCVideoEncoder::BitstreamBufferReady(int32 bitstream_buffer_id,
373 size_t size,
374 bool key_frame) {
375 DCHECK(thread_checker_.CalledOnValidThread());
376
377 if (!impl_)
378 return;
379 if (!encoded_image_callback_)
380 return;
381 if (bitstream_buffer_id < 0 ||
382 bitstream_buffer_id >= (int32)output_buffers_.size())
383 return;
384 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
385 if (size > output_buffer->mapped_size())
386 return;
387
388 webrtc::EncodedImage image(
389 reinterpret_cast<uint8_t*>(output_buffer->memory()),
390 size,
391 output_buffer->mapped_size());
392 image._encodedWidth = output_frame_dimensions_.width();
393 image._encodedHeight = output_frame_dimensions_.height();
394 image._frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame);
395 image._completeFrame = true;
396 int32_t retval = encoded_image_callback_->Encoded(image, NULL, NULL);
397 if (retval < 0) {
398 NotifyError(retval);
399 return;
400 }
401
402 impl_message_loop_proxy_->PostTask(
403 FROM_HERE,
404 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBuffer,
405 base::Unretained(impl_.get()),
406 media::BitstreamBuffer(bitstream_buffer_id,
407 output_buffer->handle(),
408 output_buffer->mapped_size())));
409 }
410
411 void RTCVideoEncoder::NotifyError(int32_t error) {
412 DCHECK(thread_checker_.CalledOnValidThread());
413 impl_status_ = error;
414 impl_message_loop_proxy_->PostTask(
415 FROM_HERE,
416 base::Bind(&RTCVideoEncoder::Impl::Destroy, base::Passed(&impl_)));
417 }
418
419 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698