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() | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Since CreateAndInitializeVEA is one of the methods
sheu
2013/08/06 06:16:36
Done.
| |
30 // called on) the thread that calls CreateAndInitializeVEA(). Notifications | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/Notifications returned by the encoder/Callbacks
sheu
2013/08/06 06:16:36
Done.
| |
31 // returned by the encoder are posted to the thread on which the instance was | |
32 // constructed. | |
33 // | |
34 // This class is separated from the RTCVideoEncoder class to allow | |
35 // RTCVideoEncoder to be deleted directly by WebRTC, while RTCVideoEncoder::Impl | |
36 // stays long enough to properly shut down the VEA. | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
I would emph the thread-separation more.
sheu
2013/08/06 06:16:36
Done.
| |
37 class RTCVideoEncoder::Impl | |
38 : public media::VideoEncodeAccelerator::Client, | |
39 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> { | |
40 public: | |
41 explicit Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder); | |
42 | |
43 // Create the VEA and call Initialize() on it. This instance of Impl is bound | |
44 // to whichever thread makes this call. | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Comment should explain it's only legal to call thi
sheu
2013/08/06 06:16:36
Done.
| |
45 void CreateAndInitializeVEA( | |
46 const webrtc::VideoCodec& codecSettings, | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/codecSettings/codec_settings/
but I think it's a
sheu
2013/08/06 06:16:36
Sure, makes sense.
| |
47 media::VideoCodecProfile profile, | |
48 base::WaitableEvent* async_waiter, | |
49 int32_t* async_retval, | |
50 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
This is known at ctor time so why not pass it in t
sheu
2013/08/06 06:16:36
Done.
| |
51 void Enqueue(const webrtc::I420VideoFrame* input_frame, | |
52 bool force_keyframe, | |
53 base::WaitableEvent* async_waiter, | |
54 int32_t* async_retval); | |
55 void UseOutputBitstreamBufferId(int32 bitstream_buffer_id); | |
56 void RequestEncodingParameterChange(int32 bitrate); | |
57 void Destroy(); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
doco
sheu
2013/08/06 06:16:36
Done.
| |
58 | |
59 // media::VideoEncodeAccelerator::Client implementation. | |
60 virtual void NotifyInitializeDone() OVERRIDE; | |
61 virtual void RequireBitstreamBuffers(int input_count, | |
62 const gfx::Size& input_input_coded_size, | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
input_input
sheu
2013/08/06 06:16:36
Done.
| |
63 size_t output_buffer_size) OVERRIDE; | |
64 virtual void BitstreamBufferReady(int32 bitstream_buffer_id, | |
65 size_t payload_size, | |
66 bool key_frame) OVERRIDE; | |
67 virtual void NotifyError(media::VideoEncodeAccelerator::Error error) OVERRIDE; | |
68 | |
69 private: | |
70 friend class base::RefCountedThreadSafe<Impl>; | |
71 | |
72 enum { | |
73 kInputBufferExtraCount = 1, // The number of input buffers allocated, more | |
74 // than what is requested by | |
75 // VEA::RequireBitstreamBuffers(). | |
76 kOutputBufferCount = 3, | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
per comment on VEA.h this seems like it should be
sheu
2013/08/06 06:16:36
(see VEA)
| |
77 }; | |
78 | |
79 virtual ~Impl(); | |
80 | |
81 // Perform encoding on an input frame from the input queue. | |
82 void EncodeOneFrame(); | |
83 | |
84 // Notify that an input frame is finished for encoding. | |
85 void EncodeFrameFinished(int index); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Doco what |index| is an index into.
sheu
2013/08/06 06:16:36
Done.
| |
86 | |
87 base::ThreadChecker thread_checker_; | |
88 | |
89 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client | |
90 // notifications. | |
91 const base::WeakPtr<RTCVideoEncoder> weak_encoder_; | |
92 | |
93 // Factory for creating VEAs, shared memory buffers, etc. | |
94 scoped_refptr<RendererGpuVideoAcceleratorFactories> gpu_factories_; | |
95 | |
96 // The message loop on which to post notifications. | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/notifications/callbacks to weak_encoder_/
sheu
2013/08/06 06:16:36
Done.
| |
97 const scoped_refptr<base::MessageLoopProxy> encoder_message_loop_proxy_; | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Put this right above or below weak_encoder_?
sheu
2013/08/06 06:16:36
Done.
| |
98 | |
99 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous. | |
100 // Do this by waiting on the |async_waiter_| and returning the return value in | |
101 // |async_retval_| when we initialization completes, encoding completes, or | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/we//
sheu
2013/08/06 06:16:36
Done.
| |
102 // an error occurs. | |
103 base::WaitableEvent* async_waiter_; | |
104 int32_t* async_retval_; | |
105 | |
106 // The underling VEA to perform encoding on. | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/underling/underlying/ unless you've got your opp
sheu
2013/08/06 06:16:36
we don't recognize an oppressor, we're an anarcho-
| |
107 scoped_ptr<media::VideoEncodeAccelerator> video_encoder_; | |
108 | |
109 // Next input frame. Since there is at most one next frame, a single-element | |
110 // queue is sufficient. | |
111 const webrtc::I420VideoFrame* input_next_frame_; | |
112 | |
113 // Whether to encode a keyframe next. | |
114 bool input_next_frame_keyframe_; | |
115 | |
116 // Frame sizes. | |
117 gfx::Size input_frame_coded_size_; | |
118 gfx::Size output_frame_dimensions_; | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Isn't this input_frame_visible_size_?
sheu
2013/08/06 06:16:36
Yeah, I was on the fence about renaming this. If
| |
119 | |
120 // Shared memory buffers for input/output with the VEA. | |
121 ScopedVector<base::SharedMemory> input_buffers_; | |
122 ScopedVector<base::SharedMemory> output_buffers_; | |
123 | |
124 // Input buffers ready to be filled with input from Encode(). As a LIFO since | |
125 // we don't care about ordering. | |
126 std::vector<int> input_buffers_free_; | |
127 | |
128 DISALLOW_COPY_AND_ASSIGN(Impl); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/COPY_AND_ASSIGN/IMPLICIT_CONSTRUCTORS/?
sheu
2013/08/06 06:16:36
DISALLOW_COPY_AND_ASSIGN is my reflexive weapon of
| |
129 }; | |
130 | |
131 RTCVideoEncoder::Impl::Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder) | |
132 : weak_encoder_(weak_encoder), | |
133 encoder_message_loop_proxy_(base::MessageLoopProxy::current()), | |
134 async_waiter_(NULL), | |
135 async_retval_(NULL), | |
136 input_next_frame_(NULL), | |
137 input_next_frame_keyframe_(false) { | |
138 thread_checker_.DetachFromThread(); | |
139 } | |
140 | |
141 void RTCVideoEncoder::Impl::CreateAndInitializeVEA( | |
142 const webrtc::VideoCodec& codecSettings, | |
143 media::VideoCodecProfile profile, | |
144 base::WaitableEvent* async_waiter, | |
145 int32_t* async_retval, | |
146 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) { | |
147 DVLOG(3) << "Impl::CreateAndInitializeVEA()"; | |
148 DCHECK(thread_checker_.CalledOnValidThread()); | |
149 | |
150 async_waiter_ = async_waiter; | |
151 async_retval_ = async_retval; | |
152 | |
153 // Check for overflow converting codecSettings.startBitrate (kilobits/sec) to | |
154 // bits/sec. | |
155 const int32 bitrate = codecSettings.startBitrate * 1000; | |
156 if (bitrate <= 0) { | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Signed integer overflow is undefined behavior.
Bet
sheu
2013/08/06 06:16:36
I was hoping to get something more generic with sa
| |
157 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError); | |
158 return; | |
159 } | |
160 | |
161 gpu_factories_ = gpu_factories; | |
162 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(this).Pass(); | |
163 if (!video_encoder_) { | |
164 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
165 return; | |
166 } | |
167 output_frame_dimensions_.SetSize(codecSettings.width, codecSettings.height); | |
168 video_encoder_->Initialize( | |
169 media::VideoFrame::I420, output_frame_dimensions_, profile, bitrate); | |
170 } | |
171 | |
172 void RTCVideoEncoder::Impl::Enqueue(const webrtc::I420VideoFrame* input_frame, | |
173 bool force_keyframe, | |
174 base::WaitableEvent* async_waiter, | |
175 int32_t* async_retval) { | |
176 DVLOG(3) << "Impl::Enqueue()"; | |
177 DCHECK(thread_checker_.CalledOnValidThread()); | |
178 DCHECK(!input_next_frame_); | |
179 | |
180 async_waiter_ = async_waiter; | |
181 async_retval_ = async_retval; | |
182 input_next_frame_ = input_frame; | |
183 input_next_frame_keyframe_ = force_keyframe; | |
184 | |
185 if (!input_buffers_free_.empty()) | |
186 EncodeOneFrame(); | |
187 } | |
188 | |
189 void RTCVideoEncoder::Impl::UseOutputBitstreamBufferId( | |
190 int32 bitstream_buffer_id) { | |
191 DVLOG(3) << "Impl::UseOutputBitstreamBufferIndex(): " | |
192 "bitstream_buffer_id=" << bitstream_buffer_id; | |
193 DCHECK(thread_checker_.CalledOnValidThread()); | |
194 if (video_encoder_) { | |
195 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
196 bitstream_buffer_id, | |
197 output_buffers_[bitstream_buffer_id]->handle(), | |
198 output_buffers_[bitstream_buffer_id]->mapped_size())); | |
199 } | |
200 } | |
201 | |
202 void RTCVideoEncoder::Impl::RequestEncodingParameterChange(int32 bitrate) { | |
203 DVLOG(3) << "Impl::RequestEncodingParameterChange(): bitrate=" << bitrate; | |
204 DCHECK(thread_checker_.CalledOnValidThread()); | |
205 if (video_encoder_) | |
206 video_encoder_->RequestEncodingParameterChange(bitrate); | |
207 } | |
208 | |
209 void RTCVideoEncoder::Impl::Destroy() { | |
210 DVLOG(3) << "Impl::Destroy()"; | |
211 DCHECK(thread_checker_.CalledOnValidThread()); | |
212 if (video_encoder_) | |
213 video_encoder_.release()->Destroy(); | |
214 } | |
215 | |
216 void RTCVideoEncoder::Impl::NotifyInitializeDone() { | |
217 DVLOG(3) << "Impl::NotifyInitializeDone()"; | |
218 DCHECK(thread_checker_.CalledOnValidThread()); | |
219 *async_retval_ = WEBRTC_VIDEO_CODEC_OK; | |
220 async_waiter_->Signal(); | |
221 async_retval_ = NULL; | |
222 async_waiter_ = NULL; | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
This stanza is repeated frequently. Extract to he
sheu
2013/08/06 06:16:36
Done.
| |
223 } | |
224 | |
225 void RTCVideoEncoder::Impl::RequireBitstreamBuffers( | |
226 int input_count, | |
227 const gfx::Size& input_coded_size, | |
228 size_t output_buffer_size) { | |
229 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count | |
230 << ", input_coded_size=" << input_coded_size.ToString() | |
231 << ", output_buffer_size=" << output_buffer_size; | |
232 DCHECK(thread_checker_.CalledOnValidThread()); | |
233 | |
234 if (!video_encoder_) | |
235 return; | |
236 | |
237 input_frame_coded_size_ = input_coded_size; | |
238 | |
239 for (int i = 0; i < input_count + kInputBufferExtraCount; ++i) { | |
240 base::SharedMemory* shm = | |
241 gpu_factories_->CreateSharedMemory(input_coded_size.GetArea() * 3 / 2); | |
242 if (!shm) { | |
243 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " | |
244 "failed to create input buffer " << i; | |
245 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
I thought the point of using a macro for NOTIFY_ER
sheu
2013/08/06 06:16:36
I'd like to see exactly what the parameters were t
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
Then you might enjoy putting them in the NOTIFY_ER
| |
246 return; | |
247 } | |
248 input_buffers_.push_back(shm); | |
249 } | |
250 for (size_t i = 0; i < input_buffers_.size(); ++i) | |
251 input_buffers_free_.push_back(i); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
could do this at l.248, fwiw.
sheu
2013/08/06 06:16:36
Done.
| |
252 | |
253 for (int i = 0; i < kOutputBufferCount; ++i) { | |
254 base::SharedMemory* shm = | |
255 gpu_factories_->CreateSharedMemory(output_buffer_size); | |
256 if (!shm) { | |
257 DLOG(ERROR) << "Impl::RequireBitstreamBuffers(): " | |
258 "failed to create output buffer " << i; | |
259 NOTIFY_ERROR(media::VideoEncodeAccelerator::kPlatformFailureError); | |
260 return; | |
261 } | |
262 output_buffers_.push_back(shm); | |
263 } | |
264 | |
265 // Immediately provide all output buffers to the VEA. | |
266 for (size_t i = 0; i < output_buffers_.size(); ++i) { | |
267 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
268 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size())); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Oh, wow, I didn't realize
https://chromiumcoderevi
sheu
2013/08/06 06:16:36
Don't think so. BitstreamBuffer comes across as a
| |
269 } | |
270 } | |
271 | |
272 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32 bitstream_buffer_id, | |
273 size_t payload_size, | |
274 bool key_frame) { | |
275 DVLOG(3) << "Impl::BitstreamBufferReady(): " | |
276 "bitstream_buffer_id=" << bitstream_buffer_id | |
277 << ", payload_size=" << payload_size | |
278 << ", key_frame=" << key_frame; | |
279 DCHECK(thread_checker_.CalledOnValidThread()); | |
280 | |
281 if (bitstream_buffer_id < 0 || | |
282 bitstream_buffer_id >= static_cast<int>(output_buffers_.size())) { | |
283 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid bitstream_buffer_id=" | |
284 << bitstream_buffer_id; | |
285 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
This is a platform error.
sheu
2013/08/06 06:16:36
Is it? It's an invalid argument coming back over
| |
286 return; | |
287 } | |
288 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; | |
289 if (payload_size > output_buffer->mapped_size()) { | |
290 DLOG(ERROR) << "Impl::BitstreamBufferReady(): invalid payload_size=" | |
291 << payload_size; | |
292 NOTIFY_ERROR(media::VideoEncodeAccelerator::kInvalidArgumentError); | |
293 return; | |
294 } | |
295 | |
296 scoped_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage( | |
297 reinterpret_cast<uint8_t*>(output_buffer->memory()), | |
298 payload_size, | |
299 output_buffer->mapped_size())); | |
300 image->_encodedWidth = output_frame_dimensions_.width(); | |
301 image->_encodedHeight = output_frame_dimensions_.height(); | |
302 image->_frameType = (key_frame ? webrtc::kKeyFrame : webrtc::kDeltaFrame); | |
303 image->_completeFrame = true; | |
304 | |
305 encoder_message_loop_proxy_->PostTask( | |
306 FROM_HERE, | |
307 base::Bind(&RTCVideoEncoder::ReturnEncodedImage, | |
308 weak_encoder_, | |
309 make_scoped_refptr(this), | |
310 base::Passed(&image), | |
311 bitstream_buffer_id)); | |
312 } | |
313 | |
314 void RTCVideoEncoder::Impl::NotifyError( | |
315 media::VideoEncodeAccelerator::Error error) { | |
316 DVLOG(3) << "Impl::NotifyError(): error=" << error; | |
317 DCHECK(thread_checker_.CalledOnValidThread()); | |
318 int32_t retval; | |
319 switch (error) { | |
320 default: | |
321 retval = WEBRTC_VIDEO_CODEC_ERROR; | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
You could do a more specific job of mapping VEA's
sheu
2013/08/06 06:16:36
Gave it a shot. Tell me what you think.
| |
322 } | |
323 | |
324 if (video_encoder_) | |
325 video_encoder_.release()->Destroy(); | |
326 | |
327 if (async_waiter_) { | |
328 *async_retval_ = retval; | |
329 async_waiter_->Signal(); | |
330 async_retval_ = NULL; | |
331 async_waiter_ = NULL; | |
332 } else { | |
333 encoder_message_loop_proxy_->PostTask( | |
334 FROM_HERE, | |
335 base::Bind(&RTCVideoEncoder::NotifyError, | |
336 weak_encoder_, | |
337 make_scoped_refptr(this), | |
338 retval)); | |
339 } | |
340 } | |
341 | |
342 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); } | |
343 | |
344 void RTCVideoEncoder::Impl::EncodeOneFrame() { | |
345 DVLOG(3) << "Impl::EncodeOneFrame()"; | |
346 DCHECK(thread_checker_.CalledOnValidThread()); | |
347 DCHECK(input_next_frame_); | |
348 DCHECK(!input_buffers_free_.empty()); | |
349 DCHECK(async_waiter_); | |
350 DCHECK(async_retval_); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
drop these in favor of DCHECKs in the proposed Sig
sheu
2013/08/06 06:16:36
Done.
| |
351 | |
352 const int index = input_buffers_free_.back(); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
why not pop_back right here?
sheu
2013/08/06 06:16:36
I tend to get in the habit of only destructively p
Ami GONE FROM CHROMIUM
2013/08/06 20:41:13
FWIW I consider that a dangerous habit and would e
| |
353 base::SharedMemory* input_buffer = input_buffers_[index]; | |
354 | |
355 if (video_encoder_) { | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
why not reverse the test and early-return at the t
sheu
2013/08/06 06:16:36
We'd still like to consume the buffers and signal
| |
356 // Do a strided copy of the input frame to match the input requirements for | |
357 // the encoder. | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Can you avoid the copy in the case where the requi
sheu
2013/08/06 06:16:36
That will require support for passing SharedMemory
| |
358 const uint8_t* src = input_next_frame_->buffer(webrtc::kYPlane); | |
359 uint8* dst = reinterpret_cast<uint8*>(input_buffer->memory()); | |
360 uint8* const y_dst = dst; | |
361 int width = input_frame_coded_size_.width(); | |
362 int stride = input_next_frame_->stride(webrtc::kYPlane); | |
363 for (int i = 0; i < input_next_frame_->height(); ++i) { | |
364 memcpy(dst, src, width); | |
365 dst += stride; | |
366 src += width; | |
367 } | |
368 src = input_next_frame_->buffer(webrtc::kUPlane); | |
369 width = input_frame_coded_size_.width() / 2; | |
370 stride = input_next_frame_->stride(webrtc::kUPlane); | |
371 uint8* const u_dst = dst; | |
372 for (int i = 0; i < input_next_frame_->height() / 2; ++i) { | |
373 memcpy(dst, src, width); | |
374 dst += stride; | |
375 src += width; | |
376 } | |
377 src = input_next_frame_->buffer(webrtc::kVPlane); | |
378 width = input_frame_coded_size_.width() / 2; | |
379 stride = input_next_frame_->stride(webrtc::kVPlane); | |
380 uint8* const v_dst = dst; | |
381 for (int i = 0; i < input_next_frame_->height() / 2; ++i) { | |
382 memcpy(dst, src, width); | |
383 dst += stride; | |
384 src += width; | |
385 } | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Extract CopyPlaneWithStride() helper to avoid the
sheu
2013/08/06 06:16:36
Tried it. The copypasta just gets a little more c
| |
386 | |
387 scoped_refptr<media::VideoFrame> frame = | |
388 media::VideoFrame::WrapExternalYuvData( | |
389 media::VideoFrame::I420, | |
390 input_frame_coded_size_, | |
391 gfx::Rect(output_frame_dimensions_), | |
392 output_frame_dimensions_, | |
393 input_frame_coded_size_.width(), | |
394 input_frame_coded_size_.width() / 2, | |
395 input_frame_coded_size_.width() / 2, | |
396 y_dst, | |
397 u_dst, | |
398 v_dst, | |
399 base::TimeDelta(), | |
400 input_buffer->handle(), | |
401 base::Bind( | |
402 &RTCVideoEncoder::Impl::EncodeFrameFinished, this, index)); | |
403 video_encoder_->Encode(frame, input_next_frame_keyframe_); | |
404 } | |
405 | |
406 input_next_frame_ = NULL; | |
407 input_next_frame_keyframe_ = false; | |
408 input_buffers_free_.pop_back(); | |
409 | |
410 *async_retval_ = WEBRTC_VIDEO_CODEC_OK; | |
411 async_waiter_->Signal(); | |
412 async_retval_ = NULL; | |
413 async_waiter_ = NULL; | |
414 } | |
415 | |
416 void RTCVideoEncoder::Impl::EncodeFrameFinished(int index) { | |
417 DVLOG(3) << "Impl::EncodeFrameFinished(): index=" << index; | |
418 DCHECK(thread_checker_.CalledOnValidThread()); | |
419 DCHECK_GE(index, 0); | |
420 DCHECK_LT(index, static_cast<int>(input_buffers_.size())); | |
421 input_buffers_free_.push_back(index); | |
422 if (input_next_frame_) | |
423 EncodeOneFrame(); | |
424 } | |
425 | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
This might be a good place for a
///////////////
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
#undef NOTIFY_ERROR
(I care because N_E has threa
sheu
2013/08/06 06:16:36
Done.
sheu
2013/08/06 06:16:36
Done.
| |
426 RTCVideoEncoder::RTCVideoEncoder( | |
427 media::VideoCodecProfile profile, | |
428 const scoped_refptr<RendererGpuVideoAcceleratorFactories>& gpu_factories) | |
429 : video_codec_profile_(profile), | |
430 gpu_factories_(gpu_factories), | |
431 impl_message_loop_proxy_(gpu_factories_->GetMessageLoop()), | |
432 weak_this_factory_(this), | |
433 weak_this_(weak_this_factory_.GetWeakPtr()), | |
434 encoded_image_callback_(NULL), | |
435 impl_status_(WEBRTC_VIDEO_CODEC_OK) { | |
436 DVLOG(1) << "RTCVideoEncoder(): profile=" << profile; | |
437 } | |
438 | |
439 RTCVideoEncoder::~RTCVideoEncoder() { | |
440 DCHECK(thread_checker_.CalledOnValidThread()); | |
441 Release(); | |
442 DCHECK(!impl_); | |
443 } | |
444 | |
445 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, | |
446 int32_t number_of_cores, | |
447 uint32_t max_payload_size) { | |
448 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType | |
449 << ", width=" << codec_settings->width | |
450 << ", height=" << codec_settings->height | |
451 << ", startBitrate=" << codec_settings->startBitrate; | |
452 DCHECK(thread_checker_.CalledOnValidThread()); | |
453 DCHECK(!impl_); | |
454 | |
455 impl_ = new Impl(weak_this_); | |
456 base::WaitableEvent initialization_waiter(true, false); | |
457 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
any reason not to use impl_status_ for this?
(he
sheu
2013/08/06 06:16:36
impl_status_ belongs on another thread.
| |
458 impl_message_loop_proxy_->PostTask( | |
459 FROM_HERE, | |
460 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, | |
461 impl_, | |
462 *codec_settings, | |
463 video_codec_profile_, | |
464 &initialization_waiter, | |
465 &initialization_retval, | |
466 gpu_factories_)); | |
467 | |
468 // webrtc::VideoEncoder expects this call to be synchronous. | |
469 initialization_waiter.Wait(); | |
470 return initialization_retval; | |
471 } | |
472 | |
473 int32_t RTCVideoEncoder::Encode( | |
474 const webrtc::I420VideoFrame& input_image, | |
475 const webrtc::CodecSpecificInfo* codec_specific_info, | |
476 const std::vector<webrtc::VideoFrameType>* frame_types) { | |
477 DVLOG(3) << "Encode()"; | |
478 // DCHECK(thread_checker_.CalledOnValidThread()); | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
uncomment
sheu
2013/08/06 06:16:36
This fails presently for reasons unknown that I st
| |
479 if (!impl_) { | |
480 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_; | |
481 return impl_status_; | |
482 } | |
483 | |
484 base::WaitableEvent encode_waiter(true, false); | |
485 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; | |
486 impl_message_loop_proxy_->PostTask( | |
487 FROM_HERE, | |
488 base::Bind(&RTCVideoEncoder::Impl::Enqueue, | |
489 impl_, | |
490 &input_image, | |
491 (frame_types->front() == webrtc::kKeyFrame), | |
492 &encode_waiter, | |
493 &encode_retval)); | |
494 | |
495 // webrtc::VideoEncoder expects this call to be synchronous. | |
496 encode_waiter.Wait(); | |
497 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval; | |
498 return encode_retval; | |
499 } | |
500 | |
501 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback( | |
502 webrtc::EncodedImageCallback* callback) { | |
503 DVLOG(3) << "RegisterEncodeCompleteCallback()"; | |
504 DCHECK(thread_checker_.CalledOnValidThread()); | |
505 if (!impl_) { | |
506 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_; | |
507 return impl_status_; | |
508 } | |
509 | |
510 encoded_image_callback_ = callback; | |
511 return WEBRTC_VIDEO_CODEC_OK; | |
512 } | |
513 | |
514 int32_t RTCVideoEncoder::Release() { | |
515 DVLOG(3) << "Release()"; | |
516 DCHECK(thread_checker_.CalledOnValidThread()); | |
517 | |
518 // Reset the gpu_factory_, in case we reuse this encoder. | |
519 gpu_factories_->Abort(); | |
520 gpu_factories_ = gpu_factories_->Clone(); | |
521 impl_message_loop_proxy_->PostTask( | |
522 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); | |
523 impl_ = NULL; | |
524 impl_status_ = WEBRTC_VIDEO_CODEC_OK; | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
s/OK/UNINITIALIZED?
sheu
2013/08/06 06:16:36
Done.
| |
525 return WEBRTC_VIDEO_CODEC_OK; | |
526 } | |
527 | |
528 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) { | |
529 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss | |
530 << ", rtt=" << rtt; | |
531 DCHECK(thread_checker_.CalledOnValidThread()); | |
532 // Ignored. | |
533 return WEBRTC_VIDEO_CODEC_OK; | |
534 } | |
535 | |
536 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) { | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
frame_rate is ignored; should that be noted someho
sheu
2013/08/06 06:16:36
Done.
| |
537 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate | |
538 << ", frame_rate=" << frame_rate; | |
539 DCHECK(thread_checker_.CalledOnValidThread()); | |
540 if (!impl_) { | |
541 DVLOG(3) << "SetRates(): returning " << impl_status_; | |
542 return impl_status_; | |
543 } | |
544 | |
545 impl_message_loop_proxy_->PostTask( | |
546 FROM_HERE, | |
547 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParameterChange, | |
548 impl_, | |
549 new_bit_rate)); | |
550 return WEBRTC_VIDEO_CODEC_OK; | |
551 } | |
552 | |
553 void RTCVideoEncoder::ReturnEncodedImage(const scoped_refptr<Impl>& impl, | |
554 scoped_ptr<webrtc::EncodedImage> image, | |
555 int32 bitstream_buffer_id) { | |
556 DCHECK(thread_checker_.CalledOnValidThread()); | |
557 | |
558 if (impl != impl_) | |
559 return; | |
560 | |
561 DVLOG(3) << "ReturnEncodedImage(): " | |
562 "bitstream_buffer_id=" << bitstream_buffer_id; | |
563 | |
564 if (!impl_) | |
Ami GONE FROM CHROMIUM
2013/08/05 18:44:38
Impossible given l.558.
sheu
2013/08/06 06:16:36
Done.
| |
565 return; | |
566 if (!encoded_image_callback_) | |
567 return; | |
568 | |
569 int32_t retval = encoded_image_callback_->Encoded(*image, NULL, NULL); | |
570 if (retval < 0) { | |
571 NotifyError(impl_, retval); | |
572 return; | |
573 } | |
574 | |
575 // The call through webrtc::EncodedImageCallback is synchronous, so we can | |
576 // immediately recycle the output buffer back to the Impl. | |
577 impl_message_loop_proxy_->PostTask( | |
578 FROM_HERE, | |
579 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId, | |
580 impl_, | |
581 bitstream_buffer_id)); | |
582 } | |
583 | |
584 void RTCVideoEncoder::NotifyError(const scoped_refptr<Impl>& impl, | |
585 int32_t error) { | |
586 DCHECK(thread_checker_.CalledOnValidThread()); | |
587 | |
588 if (impl != impl_) | |
589 return; | |
590 | |
591 DVLOG(1) << "NotifyError(): error=" << error; | |
592 | |
593 impl_status_ = error; | |
594 impl_message_loop_proxy_->PostTask( | |
595 FROM_HERE, base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); | |
596 impl_ = NULL; | |
597 } | |
598 | |
599 } // namespace content | |
OLD | NEW |