OLD | NEW |
---|---|
(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 "base/bind.h" | |
8 #include "base/location.h" | |
9 #include "base/logging.h" | |
10 #include "base/memory/scoped_vector.h" | |
11 #include "base/message_loop/message_loop_proxy.h" | |
12 #include "base/synchronization/waitable_event.h" | |
13 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h" | |
14 #include "media/base/bitstream_buffer.h" | |
15 #include "media/base/video_frame.h" | |
16 #include "media/filters/gpu_video_accelerator_factories.h" | |
17 #include "media/video/video_encode_accelerator.h" | |
18 | |
19 #define NOTIFY_ERROR(x) \ | |
20 do { \ | |
21 DLOG(ERROR) << "calling NotifyError(): " << x; \ | |
22 NotifyError(x); \ | |
23 } while (0) | |
24 | |
25 namespace content { | |
26 | |
27 // This private class of RTCVideoEncoder does the actual work of communicating | |
28 // with a media::VideoEncodeAccelerator for handling video encoding. It can | |
29 // be created on any thread, but should subsequently be posted to (and Destroy() | |
30 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the | |
31 // thread on which the instance was constructed. | |
32 // | |
33 // This class separates state related to the thread that RTCVideoEncoder | |
34 // operates on (presently the libjingle worker thread) from the thread that | |
35 // |gpu_factories_| provides for accelerator operations (presently the media | |
36 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while | |
37 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA. | |
38 class RTCVideoEncoder::Impl | |
39 : public media::VideoEncodeAccelerator::Client, | |
40 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> { | |
41 public: | |
42 explicit Impl( | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
explicit no longer necessary
sheu
2013/08/07 09:25:03
Done.
| |
43 const base::WeakPtr<RTCVideoEncoder>& weak_encoder, | |
44 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories); | |
45 | |
46 // Create the VEA and call Initialize() on it. Called once per instantiation, | |
47 // and then the instance is then bound forevermore to whichever thread made | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
s/is then/is/
sheu
2013/08/07 09:25:03
Done.
| |
48 // the call. | |
49 // WebRTC expects this call to be synchronous. | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
This sentence is out of place here considering thi
sheu
2013/08/07 09:25:03
Done.
| |
50 void CreateAndInitializeVEA(const gfx::Size& input_visible_size, | |
51 int32 bitrate, | |
52 media::VideoCodecProfile profile, | |
53 base::WaitableEvent* async_waiter, | |
54 int32_t* async_retval); | |
55 // Enqueue a frame from WebRTC for encoding. WebRTC expects this call to be | |
56 // synchronous. | |
57 void Enqueue(const webrtc::I420VideoFrame* input_frame, | |
58 bool force_keyframe, | |
59 base::WaitableEvent* async_waiter, | |
60 int32_t* async_retval); | |
61 // These can be asynchronous to WebRTC. | |
62 void UseOutputBitstreamBufferId(int32 bitstream_buffer_id); | |
63 void RequestEncodingParameterChange(int32 bitrate); | |
64 void Destroy(); | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
No you didn't.
sheu
2013/08/07 09:25:03
I added one more. I suppose you want more than th
Ami GONE FROM CHROMIUM
2013/08/07 21:07:15
I wanted the doco to talk about how it deletes thi
| |
65 | |
66 // media::VideoEncodeAccelerator::Client implementation. | |
67 virtual void NotifyInitializeDone() OVERRIDE; | |
68 virtual void RequireBitstreamBuffers(int input_count, | |
69 const gfx::Size& input_coded_size, | |
70 size_t output_buffer_size) OVERRIDE; | |
71 virtual void BitstreamBufferReady(int32 bitstream_buffer_id, | |
72 size_t payload_size, | |
73 bool key_frame) OVERRIDE; | |
74 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE; | |
75 | |
76 private: | |
77 friend class base::RefCountedThreadSafe<Impl>; | |
78 | |
79 enum { | |
80 kInputBufferExtraCount = 1, // The number of input buffers allocated, more | |
81 // than what is requested by | |
82 // VEA::RequireBitstreamBuffers(). | |
83 kOutputBufferCount = 3, | |
84 }; | |
85 | |
86 virtual ~Impl(); | |
87 | |
88 // Perform encoding on an input frame from the input queue. | |
89 void EncodeOneFrame(); | |
90 | |
91 // Notify that an input frame is finished for encoding. |index| is the index | |
92 // of the completed frame in |input_buffers_|. | |
93 void EncodeFrameFinished(int index); | |
94 | |
95 // Set up/signal |async_waiter_| and |async_retval_|; see declarations below. | |
96 void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval); | |
97 void SignalAsyncWaiter(int32_t retval); | |
98 | |
99 base::ThreadChecker thread_checker_; | |
100 | |
101 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client | |
102 // notifications. | |
103 const base::WeakPtr<RTCVideoEncoder> weak_encoder_; | |
104 | |
105 // The message loop on which to post callbacks to |weak_encoder_|. | |
106 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_; | |
107 | |
108 // Factory for creating VEAs, shared memory buffers, etc. | |
109 const scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_; | |
110 | |
111 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous. | |
112 // Do this by waiting on the |async_waiter_| and returning the return value in | |
113 // |async_retval_| when initialization completes, encoding completes, or | |
114 // an error occurs. | |
115 base::WaitableEvent* async_waiter_; | |
116 int32_t* async_retval_; | |
117 | |
118 // The underlying VEA to perform encoding on. | |
119 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_; | |
120 | |
121 // Next input frame. Since there is at most one next frame, a single-element | |
122 // queue is sufficient. | |
123 const webrtc::I420VideoFrame* input_next_frame_; | |
124 | |
125 // Whether to encode a keyframe next. | |
126 bool input_next_frame_keyframe_; | |
127 | |
128 // Frame sizes. | |
129 gfx::Size input_frame_coded_size_; | |
130 gfx::Size input_visible_size_; | |
131 | |
132 // Shared memory buffers for input/output with the VEA. | |
133 ScopedVector<base::SharedMemory> input_buffers_; | |
134 ScopedVector<base::SharedMemory> output_buffers_; | |
135 | |
136 // Input buffers ready to be filled with input from Encode(). As a LIFO since | |
137 // we don't care about ordering. | |
138 std::vector<int> input_buffers_free_; | |
139 | |
140 DISALLOW_COPY_AND_ASSIGN(Impl); | |
141 }; | |
142 | |
143 RTCVideoEncoder::Impl::Impl( | |
144 const base::WeakPtr<RTCVideoEncoder>& weak_encoder, | |
145 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) | |
146 : weak_encoder_(weak_encoder), | |
147 encoder_message_loop_proxy_(base::MessageLoopProxy::current()), | |
148 gpu_factories_(gpu_factories), | |
149 async_waiter_(NULL), | |
150 async_retval_(NULL), | |
151 input_next_frame_(NULL), | |
152 input_next_frame_keyframe_(false) { | |
153 thread_checker_.DetachFromThread(); | |
154 } | |
155 | |
156 void RTCVideoEncoder::Impl::CreateAndInitializeVEA( | |
157 const gfx::Size& input_visible_size, | |
158 int32 bitrate, | |
159 media::VideoCodecProfile profile, | |
160 base::WaitableEvent* async_waiter, | |
161 int32_t* async_retval) { | |
162 DVLOG(3) << "Impl::CreateAndInitializeVEA()"; | |
163 DCHECK(thread_checker_.CalledOnValidThread()); | |
164 | |
165 RegisterAsyncWaiter(async_waiter, async_retval); | |
166 | |
167 // Check for overflow converting codecSettings.startBitrate (kilobits/sec) to | |
168 // bits/sec. | |
169 if (bitrate > kint32max / 1000) { | |
170 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError); | |
171 return; | |
172 } | |
173 | |
174 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass(); | |
175 if (!video_encoder_) { | |
176 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
177 return; | |
178 } | |
179 input_visible_size_ = input_visible_size; | |
180 video_encoder_->Initialize(media::VideoFrame::I420, | |
181 input_visible_size_, | |
182 profile, | |
183 bitrate * 1000); | |
184 } | |
185 | |
186 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame, | |
187 bool force_keyframe, | |
188 base::WaitableEvent* async_waiter, | |
189 int32_t* async_retval) { | |
190 DVLOG(3) << "Impl::Enqueue()"; | |
191 DCHECK(thread_checker_.CalledOnValidThread()); | |
192 DCHECK(!input_next_frame_); | |
193 | |
194 RegisterAsyncWaiter(async_waiter, async_retval); | |
195 input_next_frame_ = input_frame; | |
196 input_next_frame_keyframe_ = force_keyframe; | |
197 | |
198 if (!input_buffers_free_.empty()) | |
199 EncodeOneFrame(); | |
200 } | |
201 | |
202 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId( | |
203 int32 bitstream_buffer_id) { | |
204 DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): " | |
205 "bitstream_buffer_id=" << bitstream_buffer_id; | |
206 DCHECK(thread_checker_.CalledOnValidThread()); | |
207 if (video_encoder_) { | |
208 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
209 bitstream_buffer_id, | |
210 output_buffers_[bitstream_buffer_id]->handle(), | |
211 output_buffers_[bitstream_buffer_id]->mapped_size())); | |
212 } | |
213 } | |
214 | |
215 void RTCVideoEncoder::Impl::RequestEncodingParameterChange(int32 bitrate) { | |
216 DVLOG(3) << "Impl::RequestEncodingParameterChange(): bitrate=" << bitrate; | |
217 DCHECK(thread_checker_.CalledOnValidThread()); | |
218 if (video_encoder_) | |
219 video_encoder_->RequestEncodingParameterChange(bitrate); | |
220 } | |
221 | |
222 void RTCVideoEncoder::Impl::Destroy() { | |
223 DVLOG(3) << "Impl::Destroy()"; | |
224 DCHECK(thread_checker_.CalledOnValidThread()); | |
225 if (video_encoder_) | |
226 video_encoder_.release()->Destroy(); | |
227 } | |
228 | |
229 void RTCVideoEncoder::Impl::NotifyInitializeDone() { | |
230 DVLOG(3) << "Impl::NotifyInitializeDone()"; | |
231 DCHECK(thread_checker_.CalledOnValidThread()); | |
232 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); | |
233 } | |
234 | |
235 void RTCVideoEncoder::Impl::RequireBitstreamBuffers( | |
236 int input_count, | |
237 const gfx::Size& input_coded_size, | |
238 size_t output_buffer_size) { | |
239 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count | |
240 << ", input_coded_size=" << input_coded_size.ToString() | |
241 << ", output_buffer_size=" << output_buffer_size; | |
242 DCHECK(thread_checker_.CalledOnValidThread()); | |
243 | |
244 if (!video_encoder_) | |
245 return; | |
246 | |
247 input_frame_coded_size_ = input_coded_size; | |
248 | |
249 for (int i = 0; i < input_count + kInputBufferExtraCount; ++i) { | |
250 base::SharedMemory* shm = | |
251 gpu_factories_->CreateSharedMemory(input_coded_size.GetArea() * 3 / 2); | |
252 if (!shm) { | |
253 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " | |
254 "failed to create input buffer " << i; | |
255 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
256 return; | |
257 } | |
258 input_buffers_.push_back(shm); | |
259 input_buffers_free_.push_back(i); | |
260 } | |
261 | |
262 for (int i = 0; i < kOutputBufferCount; ++i) { | |
263 base::SharedMemory* shm = | |
264 gpu_factories_->CreateSharedMemory(output_buffer_size); | |
265 if (!shm) { | |
266 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " | |
267 "failed to create output buffer " << i; | |
268 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
269 return; | |
270 } | |
271 output_buffers_.push_back(shm); | |
272 } | |
273 | |
274 // Immediately provide all output buffers to the VEA. | |
275 for (size_t i = 0; i < output_buffers_.size(); ++i) { | |
276 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
277 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size())); | |
278 } | |
279 } | |
280 | |
281 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id, | |
282 size_t payload_size, | |
283 bool key_frame) { | |
284 DVLOG(3) << "Impl::BitstreamBufferReady(): " | |
285 "bitstream_buffer_id=" << bitstream_buffer_id | |
286 << ", payload_size=" << payload_size | |
287 << ", key_frame=" << key_frame; | |
288 DCHECK(thread_checker_.CalledOnValidThread()); | |
289 | |
290 if (bitstream_buffer_id < 0 || | |
291 bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) { | |
292 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id=" | |
293 << bitstream_buffer_id; | |
294 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError); | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
No, it's an invalid argument coming from the VEA i
sheu
2013/08/07 09:25:03
BitstreamBufferReady is part of the VEA::Client in
| |
295 return; | |
296 } | |
297 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; | |
298 if (payload_size > output_buffer->mapped_size()) { | |
299 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size=" | |
300 << payload_size; | |
301 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError); | |
302 return; | |
303 } | |
304 | |
305 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage( | |
306 reinterpret_cast<uint8_t*>(output_buffer->memory()), | |
307 payload_size, | |
308 output_buffer->mapped_size())); | |
309 image->_encodedWidth = input_visible_size_.width(); | |
310 image->_encodedHeight = input_visible_size_.height(); | |
311 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame); | |
312 image->_completeFrame = true; | |
313 | |
314 encoder_message_loop_proxy_->PostTask( | |
315 FROM_HERE, | |
316 base::Bind(&RTCVideoEncoder::ReturnEncodedImage, | |
317 weak_encoder_, | |
318 make_scoped_refptr(this), | |
319 base::Passed(&image), | |
320 bitstream_buffer_id)); | |
321 } | |
322 | |
323 void RTCVideoEncoder::Impl::NotifyError( | |
324 media::VideoEncodeAccelerator::Error error) { | |
325 DVLOG(3) << "Impl::NotifyError(): error=" << error; | |
326 DCHECK(thread_checker_.CalledOnValidThread()); | |
327 int32_t retval; | |
328 switch (error) { | |
329 case media::VideoEncodeAccelerator::kInvalidArgumentError: | |
330 retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
331 break; | |
332 case media::VideoEncodeAccelerator::kPlatformFailureError: | |
333 retval = WEBRTC_VIDEO_CODEC_MEMORY; | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
I guess s/MEMORY/ERROR/ (better to be vague than
sheu
2013/08/07 09:25:03
Most kPlatformFailureErrors are memory-related I t
Ami GONE FROM CHROMIUM
2013/08/07 21:07:15
I worry that MEMORY is specific enough that it'll
| |
334 break; | |
335 default: | |
336 retval = WEBRTC_VIDEO_CODEC_ERROR; | |
337 } | |
338 | |
339 if (video_encoder_) | |
340 video_encoder_.release()->Destroy(); | |
341 | |
342 if (async_waiter_) { | |
343 SignalAsyncWaiter(retval); | |
344 } else { | |
345 encoder_message_loop_proxy_->PostTask( | |
346 FROM_HERE, | |
347 base::Bind(&RTCVideoEncoder::NotifyError, | |
348 weak_encoder_, | |
349 make_scoped_refptr(this), | |
350 retval)); | |
351 } | |
352 } | |
353 | |
354 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); } | |
355 | |
356 void RTCVideoEncoder::Impl::EncodeOneFrame() { | |
357 DVLOG(3) << "Impl::EncodeOneFrame()"; | |
358 DCHECK(thread_checker_.CalledOnValidThread()); | |
359 DCHECK(input_next_frame_); | |
360 DCHECK(!input_buffers_free_.empty()); | |
361 | |
362 const int index = input_buffers_free_.back(); | |
363 base::SharedMemory* input_buffer = input_buffers_[index]; | |
sheu
2013/08/07 09:25:03
Actually now that I think of it, I should move the
| |
364 | |
365 if (video_encoder_) { | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
Isn't the negation an error condition?
sheu
2013/08/07 09:25:03
It is, but I'd still like to leave the Impl in a s
| |
366 // Do a strided copy of the input frame to match the input requirements for | |
367 // the encoder. | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
Please add a TODO pointing to a crbug for the rema
sheu
2013/08/07 09:25:03
Done.
| |
368 const uint8_t* src = input_next_frame_->buffer(webrtc::kYPlane); | |
369 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory()); | |
370 uint8* const y_dst = dst; | |
371 int width = input_frame_coded_size_.width(); | |
372 int stride = input_next_frame_->stride(webrtc::kYPlane); | |
373 for (int i = 0; i < input_next_frame_->height(); ++i) { | |
374 memcpy(dst, src, width); | |
375 src += stride; | |
376 dst += width; | |
sheu
2013/08/06 06:16:36
Teehee
The benefits of not testing
| |
377 } | |
378 src = input_next_frame_->buffer(webrtc::kUPlane); | |
379 width = input_frame_coded_size_.width() / 2; | |
380 stride = input_next_frame_->stride(webrtc::kUPlane); | |
381 uint8* const u_dst = dst; | |
382 for (int i = 0; i < input_next_frame_->height() / 2; ++i) { | |
383 memcpy(dst, src, width); | |
384 src += stride; | |
385 dst += width; | |
386 } | |
387 src = input_next_frame_->buffer(webrtc::kVPlane); | |
388 width = input_frame_coded_size_.width() / 2; | |
389 stride = input_next_frame_->stride(webrtc::kVPlane); | |
390 uint8* const v_dst = dst; | |
391 for (int i = 0; i < input_next_frame_->height() / 2; ++i) { | |
392 memcpy(dst, src, width); | |
393 src += stride; | |
394 dst += width; | |
395 } | |
396 | |
397 scoped_refptr<media::VideoFrame> frame = | |
398 media::VideoFrame::WrapExternalYuvData( | |
399 media::VideoFrame::I420, | |
400 input_frame_coded_size_, | |
401 gfx::Rect(input_visible_size_), | |
402 input_visible_size_, | |
403 input_frame_coded_size_.width(), | |
404 input_frame_coded_size_.width() / 2, | |
405 input_frame_coded_size_.width() / 2, | |
406 y_dst, | |
407 u_dst, | |
408 v_dst, | |
409 base::TimeDelta(), | |
410 input_buffer->handle(), | |
411 base::Bind( | |
412 &RTCVideoEncoder::Impl::EncodeFrameFinished, this, index)); | |
413 video_encoder_->Encode(frame, input_next_frame_keyframe_); | |
414 } | |
415 | |
416 input_next_frame_ = NULL; | |
417 input_next_frame_keyframe_ = false; | |
418 input_buffers_free_.pop_back(); | |
419 | |
420 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); | |
421 } | |
422 | |
423 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) { | |
424 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index; | |
425 DCHECK(thread_checker_.CalledOnValidThread()); | |
426 DCHECK_GE(index, 0); | |
427 DCHECK_LT(index, static_cast<int>(input_buffers_.size())); | |
428 input_buffers_free_.push_back(index); | |
429 if (input_next_frame_) | |
430 EncodeOneFrame(); | |
431 } | |
432 | |
433 void RTCVideoEncoder::Impl::RegisterAsyncWaiter(base::WaitableEvent* waiter, | |
434 int32_t* retval) { | |
435 DCHECK(thread_checker_.CalledOnValidThread()); | |
436 DCHECK(!async_waiter_); | |
437 DCHECK(!async_retval_); | |
438 async_waiter_ = waiter; | |
439 async_retval_ = retval; | |
440 } | |
441 | |
442 void RTCVideoEncoder::Impl::SignalAsyncWaiter(int32_t retval) { | |
443 DCHECK(thread_checker_.CalledOnValidThread()); | |
444 *async_retval_ = retval; | |
445 async_waiter_->Signal(); | |
446 async_retval_ = NULL; | |
447 async_waiter_ = NULL; | |
448 } | |
449 | |
450 //////////////////////////////////////////////////////////////////////////////// | |
451 // | |
452 // RTCVideoEncoder | |
453 // | |
454 //////////////////////////////////////////////////////////////////////////////// | |
455 | |
456 #undef NOTIFY_ERROR | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
go above separator
sheu
2013/08/07 09:25:03
Done.
| |
457 | |
458 RTCVideoEncoder::RTCVideoEncoder( | |
459 media::VideoCodecProfile profile, | |
460 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) | |
461 : video_codec_profile_(profile), | |
462 gpu_factories_(gpu_factories), | |
463 weak_this_factory_(this), | |
464 weak_this_(weak_this_factory_.GetWeakPtr()), | |
465 encoded_image_callback_(NULL), | |
466 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) { | |
467 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile; | |
468 } | |
469 | |
470 RTCVideoEncoder::~RTCVideoEncoder() { | |
471 DCHECK(thread_checker_.CalledOnValidThread()); | |
472 Release(); | |
473 DCHECK(!impl_); | |
474 } | |
475 | |
476 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, | |
477 int32_t number_of_cores, | |
478 uint32_t max_payload_size) { | |
479 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType | |
480 << ", width=" << codec_settings->width | |
481 << ", height=" << codec_settings->height | |
482 << ", startBitrate=" << codec_settings->startBitrate; | |
483 DCHECK(thread_checker_.CalledOnValidThread()); | |
484 DCHECK(!impl_); | |
485 | |
486 impl_ = new Impl(weak_this_, gpu_factories_); | |
487 base::WaitableEvent initialization_waiter(true, false); | |
488 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
What does that mean?
sheu
2013/08/07 09:25:03
Yeah ok that made no sense.
Anyways I was thinkin
| |
489 gpu_factories_->GetMessageLoop()->PostTask( | |
490 FROM_HERE, | |
491 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, | |
492 impl_, | |
493 gfx::Size(codec_settings->width, codec_settings->height), | |
494 codec_settings->startBitrate, | |
495 video_codec_profile_, | |
496 &initialization_waiter, | |
497 &initialization_retval)); | |
498 | |
499 // webrtc::VideoEncoder expects this call to be synchronous. | |
500 initialization_waiter.Wait(); | |
501 return initialization_retval; | |
502 } | |
503 | |
504 int32_t RTCVideoEncoder::Encode( | |
505 const webrtc::I420VideoFrame& input_image, | |
506 const webrtc::CodecSpecificInfo* codec_specific_info, | |
507 const std::vector<webrtc::VideoFrameType>* frame_types) { | |
508 DVLOG(3) << "Encode()"; | |
509 // DCHECK(thread_checker_.CalledOnValidThread()); | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
Big-ass TODO please, then.
sheu
2013/08/07 09:25:03
Done.
| |
510 if (!impl_) { | |
511 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_; | |
512 return impl_status_; | |
513 } | |
514 | |
515 base::WaitableEvent encode_waiter(true, false); | |
516 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
517 gpu_factories_->GetMessageLoop()->PostTask( | |
518 FROM_HERE, | |
519 base::Bind(&RTCVideoEncoder::Impl::Enqueue, | |
520 impl_, | |
521 &input_image, | |
522 (frame_types->front() == webrtc::kKeyFrame), | |
523 &encode_waiter, | |
524 &encode_retval)); | |
525 | |
526 // webrtc::VideoEncoder expects this call to be synchronous. | |
527 encode_waiter.Wait(); | |
528 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval; | |
529 return encode_retval; | |
530 } | |
531 | |
532 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback( | |
533 webrtc::EncodedImageCallback* callback) { | |
534 DVLOG(3) << "RegisterEncodeCompleteCallback()"; | |
535 DCHECK(thread_checker_.CalledOnValidThread()); | |
536 if (!impl_) { | |
537 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_; | |
538 return impl_status_; | |
539 } | |
540 | |
541 encoded_image_callback_ = callback; | |
542 return WEBRTC_VIDEO_CODEC_OK; | |
543 } | |
544 | |
545 int32_t RTCVideoEncoder::Release() { | |
546 DVLOG(3) << "Release()"; | |
547 DCHECK(thread_checker_.CalledOnValidThread()); | |
548 | |
549 // Reset the gpu_factory_, in case we reuse this encoder. | |
550 gpu_factories_->Abort(); | |
551 gpu_factories_ = gpu_factories_->Clone(); | |
552 if (impl_) { | |
553 gpu_factories_->GetMessageLoop()->PostTask( | |
554 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); | |
555 impl_ = NULL; | |
556 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
557 } | |
558 return WEBRTC_VIDEO_CODEC_OK; | |
559 } | |
560 | |
561 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) { | |
562 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss | |
563 << ", rtt=" << rtt; | |
564 DCHECK(thread_checker_.CalledOnValidThread()); | |
565 // Ignored. | |
566 return WEBRTC_VIDEO_CODEC_OK; | |
567 } | |
568 | |
569 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, | |
570 uint32_t /* ignored_frame_rate */) { | |
571 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate; | |
572 DCHECK(thread_checker_.CalledOnValidThread()); | |
573 if (!impl_) { | |
574 DVLOG(3) << "SetRates(): returning " << impl_status_; | |
575 return impl_status_; | |
576 } | |
577 | |
578 gpu_factories_->GetMessageLoop()->PostTask( | |
579 FROM_HERE, | |
580 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParameterChange, | |
581 impl_, | |
582 new_bit_rate)); | |
583 return WEBRTC_VIDEO_CODEC_OK; | |
584 } | |
585 | |
586 void RTCVideoEncoder::ReturnEncodedImage(const scoped_refptr<Impl>& impl, | |
587 scoped_ptr<webrtc::EncodedImage> image, | |
588 int32 bitstream_buffer_id) { | |
589 DCHECK(thread_checker_.CalledOnValidThread()); | |
590 | |
591 if (impl != impl_) | |
592 return; | |
593 | |
594 DVLOG(3) << "ReturnEncodedImage(): " | |
595 "bitstream_buffer_id=" << bitstream_buffer_id; | |
596 | |
597 if (!encoded_image_callback_) | |
598 return; | |
599 | |
600 int32_t retval = encoded_image_callback_->Encoded(*image, NULL, NULL); | |
601 if (retval < 0) { | |
602 DLOG(ERROR) << "ReturnEncodedImage(): encoded_image_callback_ returned " | |
603 << retval; | |
604 NotifyError(impl_, retval); | |
605 return; | |
606 } | |
607 | |
608 // The call through webrtc::EncodedImageCallback is synchronous, so we can | |
609 // immediately recycle the output buffer back to the Impl. | |
610 gpu_factories_->GetMessageLoop()->PostTask( | |
611 FROM_HERE, | |
612 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId, | |
613 impl_, | |
614 bitstream_buffer_id)); | |
615 } | |
616 | |
617 void RTCVideoEncoder::NotifyError(const scoped_refptr<Impl>& impl, | |
618 int32_t error) { | |
619 DCHECK(thread_checker_.CalledOnValidThread()); | |
620 | |
621 if (!impl_) | |
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
impossible given l.623 (and the fact that the only
sheu
2013/08/07 09:25:03
Done.
| |
622 return; | |
623 if (impl != impl_) | |
624 return; | |
625 | |
626 DVLOG(1) << "NotifyError(): error=" << error; | |
627 | |
628 impl_status_ = error; | |
629 gpu_factories_->GetMessageLoop()->PostTask( | |
630 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); | |
631 impl_ = NULL; | |
632 } | |
633 | |
634 } // namespace content | |
OLD | NEW |