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

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

Issue 1845563006: Make RTCVideoEncoder usable from non-postable thread. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 4 years, 8 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
« no previous file with comments | « content/renderer/media/rtc_video_encoder.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/renderer/media/rtc_video_encoder.h" 5 #include "content/renderer/media/rtc_video_encoder.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 } 85 }
86 return true; 86 return true;
87 } 87 }
88 88
89 } // namespace 89 } // namespace
90 90
91 // This private class of RTCVideoEncoder does the actual work of communicating 91 // This private class of RTCVideoEncoder does the actual work of communicating
92 // with a media::VideoEncodeAccelerator for handling video encoding. It can 92 // with a media::VideoEncodeAccelerator for handling video encoding. It can
93 // be created on any thread, but should subsequently be posted to (and Destroy() 93 // be created on any thread, but should subsequently be posted to (and Destroy()
94 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the 94 // called on) a single thread. Callbacks to RTCVideoEncoder are posted to the
95 // thread on which the instance was constructed. 95 // thread on which the instance was constructed.
emircan 2016/04/12 20:15:02 "Callbacks to RTCVideoEncoder are ... constructed"
wuchengli 2016/04/13 15:26:26 Yes. Removed. Also updated other comments here.
96 // 96 //
97 // This class separates state related to the thread that RTCVideoEncoder 97 // This class separates state related to the thread that RTCVideoEncoder
98 // operates on (presently the libjingle worker thread) from the thread that 98 // operates on (presently the libjingle worker thread) from the thread that
99 // |gpu_factories_| provides for accelerator operations (presently the media 99 // |gpu_factories_| provides for accelerator operations (presently the media
100 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while 100 // thread). The RTCVideoEncoder class can be deleted directly by WebRTC, while
101 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA. 101 // RTCVideoEncoder::Impl stays around long enough to properly shut down the VEA.
102 class RTCVideoEncoder::Impl 102 class RTCVideoEncoder::Impl
103 : public media::VideoEncodeAccelerator::Client, 103 : public media::VideoEncodeAccelerator::Client,
104 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> { 104 public base::RefCountedThreadSafe<RTCVideoEncoder::Impl> {
105 public: 105 public:
106 Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder, 106 Impl(media::GpuVideoAcceleratorFactories* gpu_factories,
107 media::GpuVideoAcceleratorFactories* gpu_factories); 107 webrtc::VideoCodecType video_codec_type);
108 108
109 // Create the VEA and call Initialize() on it. Called once per instantiation, 109 // Create the VEA and call Initialize() on it. Called once per instantiation,
110 // and then the instance is bound forevermore to whichever thread made the 110 // and then the instance is bound forevermore to whichever thread made the
111 // call. 111 // call.
112 // RTCVideoEncoder expects to be able to call this function synchronously from 112 // RTCVideoEncoder expects to be able to call this function synchronously from
113 // its own thread, hence the |async_waiter| and |async_retval| arguments. 113 // its own thread, hence the |async_waiter| and |async_retval| arguments.
114 void CreateAndInitializeVEA(const gfx::Size& input_visible_size, 114 void CreateAndInitializeVEA(const gfx::Size& input_visible_size,
115 uint32_t bitrate, 115 uint32_t bitrate,
116 media::VideoCodecProfile profile, 116 media::VideoCodecProfile profile,
117 base::WaitableEvent* async_waiter, 117 base::WaitableEvent* async_waiter,
118 int32_t* async_retval); 118 int32_t* async_retval);
119 // Enqueue a frame from WebRTC for encoding. 119 // Enqueue a frame from WebRTC for encoding.
120 // RTCVideoEncoder expects to be able to call this function synchronously from 120 // RTCVideoEncoder expects to be able to call this function synchronously from
121 // its own thread, hence the |async_waiter| and |async_retval| arguments. 121 // its own thread, hence the |async_waiter| and |async_retval| arguments.
122 void Enqueue(const webrtc::VideoFrame* input_frame, 122 void Enqueue(const webrtc::VideoFrame* input_frame,
123 bool force_keyframe, 123 bool force_keyframe,
124 base::WaitableEvent* async_waiter, 124 base::WaitableEvent* async_waiter,
125 int32_t* async_retval); 125 int32_t* async_retval);
126 126
127 // RTCVideoEncoder is given a buffer to be passed to WebRTC through the 127 // RTCVideoEncoder is given a buffer to be passed to WebRTC through the
128 // RTCVideoEncoder::ReturnEncodedImage() function. When that is complete, 128 // RTCVideoEncoder::ReturnEncodedImage() function. When that is complete,
129 // the buffer is returned to Impl by its index using this function. 129 // the buffer is returned to Impl by its index using this function.
130 void UseOutputBitstreamBufferId(int32_t bitstream_buffer_id); 130 void UseOutputBitstreamBufferId(int32_t bitstream_buffer_id);
131 131
132 // Request encoding parameter change for the underlying encoder. 132 // Request encoding parameter change for the underlying encoder.
133 void RequestEncodingParametersChange(uint32_t bitrate, uint32_t framerate); 133 void RequestEncodingParametersChange(uint32_t bitrate, uint32_t framerate);
134 134
135 void RegisterEncodeCompleteCallback(base::WaitableEvent* async_waiter,
136 int32_t* async_retval,
137 webrtc::EncodedImageCallback* callback);
138
135 // Destroy this Impl's encoder. The destructor is not explicitly called, as 139 // Destroy this Impl's encoder. The destructor is not explicitly called, as
136 // Impl is a base::RefCountedThreadSafe. 140 // Impl is a base::RefCountedThreadSafe.
137 void Destroy(); 141 void Destroy(base::WaitableEvent* async_waiter);
142
143 // Return the status of Impl. One of WEBRTC_VIDEO_CODEC_XXX value.
144 int32_t GetStatus();
emircan 2016/04/12 20:15:02 Mark method as const.
wuchengli 2016/04/13 15:26:26 Done.
145
146 webrtc::VideoCodecType video_codec_type() { return video_codec_type_; }
138 147
139 // media::VideoEncodeAccelerator::Client implementation. 148 // media::VideoEncodeAccelerator::Client implementation.
140 void RequireBitstreamBuffers(unsigned int input_count, 149 void RequireBitstreamBuffers(unsigned int input_count,
141 const gfx::Size& input_coded_size, 150 const gfx::Size& input_coded_size,
142 size_t output_buffer_size) override; 151 size_t output_buffer_size) override;
143 void BitstreamBufferReady(int32_t bitstream_buffer_id, 152 void BitstreamBufferReady(int32_t bitstream_buffer_id,
144 size_t payload_size, 153 size_t payload_size,
145 bool key_frame) override; 154 bool key_frame) override;
146 void NotifyError(media::VideoEncodeAccelerator::Error error) override; 155 void NotifyError(media::VideoEncodeAccelerator::Error error) override;
147 156
(...skipping 25 matching lines...) Expand all
173 void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval); 182 void RegisterAsyncWaiter(base::WaitableEvent* waiter, int32_t* retval);
174 void SignalAsyncWaiter(int32_t retval); 183 void SignalAsyncWaiter(int32_t retval);
175 184
176 // Checks if the bitrate would overflow when passing from kbps to bps. 185 // Checks if the bitrate would overflow when passing from kbps to bps.
177 bool IsBitrateTooHigh(uint32_t bitrate); 186 bool IsBitrateTooHigh(uint32_t bitrate);
178 187
179 // Checks if the frame size is different than hardware accelerator 188 // Checks if the frame size is different than hardware accelerator
180 // requirements. 189 // requirements.
181 bool RequiresSizeChange(const scoped_refptr<media::VideoFrame>& frame) const; 190 bool RequiresSizeChange(const scoped_refptr<media::VideoFrame>& frame) const;
182 191
192 // Return an encoded output buffer to WebRTC.
193 void ReturnEncodedImage(const webrtc::EncodedImage& image,
194 int32_t bitstream_buffer_id,
195 uint16_t picture_id);
196
emircan 2016/04/12 20:15:02 Can we add a comment about this being attached to
wuchengli 2016/04/13 15:26:26 Done.
183 base::ThreadChecker thread_checker_; 197 base::ThreadChecker thread_checker_;
184 198
185 // Weak pointer to the parent RTCVideoEncoder, for posting back VEA::Client
186 // notifications.
187 const base::WeakPtr<RTCVideoEncoder> weak_encoder_;
188
189 // The message loop on which to post callbacks to |weak_encoder_|.
190 const scoped_refptr<base::SingleThreadTaskRunner> encoder_task_runner_;
191
192 // Factory for creating VEAs, shared memory buffers, etc. 199 // Factory for creating VEAs, shared memory buffers, etc.
193 media::GpuVideoAcceleratorFactories* gpu_factories_; 200 media::GpuVideoAcceleratorFactories* gpu_factories_;
194 201
195 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous. 202 // webrtc::VideoEncoder expects InitEncode() and Encode() to be synchronous.
196 // Do this by waiting on the |async_waiter_| and returning the return value in 203 // Do this by waiting on the |async_waiter_| and returning the return value in
197 // |async_retval_| when initialization completes, encoding completes, or 204 // |async_retval_| when initialization completes, encoding completes, or
198 // an error occurs. 205 // an error occurs.
199 base::WaitableEvent* async_waiter_; 206 base::WaitableEvent* async_waiter_;
200 int32_t* async_retval_; 207 int32_t* async_retval_;
201 208
(...skipping 19 matching lines...) Expand all
221 // we don't care about ordering. 228 // we don't care about ordering.
222 std::vector<int> input_buffers_free_; 229 std::vector<int> input_buffers_free_;
223 230
224 // The number of output buffers ready to be filled with output from the 231 // The number of output buffers ready to be filled with output from the
225 // encoder. 232 // encoder.
226 int output_buffers_free_count_; 233 int output_buffers_free_count_;
227 234
228 // 15 bits running index of the VP8 frames. See VP8 RTP spec for details. 235 // 15 bits running index of the VP8 frames. See VP8 RTP spec for details.
229 uint16_t picture_id_; 236 uint16_t picture_id_;
230 237
238 // webrtc::VideoEncoder encode complete callback.
239 webrtc::EncodedImageCallback* encoded_image_callback_;
240
241 // The video codec type, as reported to WebRTC.
242 const webrtc::VideoCodecType video_codec_type_;
243
244 // We cannot immediately return error conditions to the WebRTC user of this
245 // class, as there is no error callback in the webrtc::VideoEncoder interface.
246 // Instead, we cache an error status here and return it the next time an
247 // interface entry point is called. |status_| is read or written on
248 // |gpu_task_runner_| in Impl. It can be read in RTCVideoEncoder on other
249 // threads, hence atomic.
250 std::atomic<int32_t> status_;
pbos 2016/04/12 11:25:59 std::atomic looks banned for now, I think you have
wuchengli 2016/04/13 15:26:26 Thanks. The comments in base/atomicops.h do not en
251
231 DISALLOW_COPY_AND_ASSIGN(Impl); 252 DISALLOW_COPY_AND_ASSIGN(Impl);
232 }; 253 };
233 254
234 RTCVideoEncoder::Impl::Impl(const base::WeakPtr<RTCVideoEncoder>& weak_encoder, 255 RTCVideoEncoder::Impl::Impl(media::GpuVideoAcceleratorFactories* gpu_factories,
235 media::GpuVideoAcceleratorFactories* gpu_factories) 256 webrtc::VideoCodecType video_codec_type)
236 : weak_encoder_(weak_encoder), 257 : gpu_factories_(gpu_factories),
237 encoder_task_runner_(base::ThreadTaskRunnerHandle::Get()),
238 gpu_factories_(gpu_factories),
239 async_waiter_(NULL), 258 async_waiter_(NULL),
240 async_retval_(NULL), 259 async_retval_(NULL),
241 input_next_frame_(NULL), 260 input_next_frame_(NULL),
242 input_next_frame_keyframe_(false), 261 input_next_frame_keyframe_(false),
243 output_buffers_free_count_(0) { 262 output_buffers_free_count_(0),
263 encoded_image_callback_(nullptr),
264 video_codec_type_(video_codec_type),
265 status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED) {
244 thread_checker_.DetachFromThread(); 266 thread_checker_.DetachFromThread();
245 // Picture ID should start on a random number. 267 // Picture ID should start on a random number.
246 picture_id_ = static_cast<uint16_t>(base::RandInt(0, 0x7FFF)); 268 picture_id_ = static_cast<uint16_t>(base::RandInt(0, 0x7FFF));
247 } 269 }
248 270
249 void RTCVideoEncoder::Impl::CreateAndInitializeVEA( 271 void RTCVideoEncoder::Impl::CreateAndInitializeVEA(
250 const gfx::Size& input_visible_size, 272 const gfx::Size& input_visible_size,
251 uint32_t bitrate, 273 uint32_t bitrate,
252 media::VideoCodecProfile profile, 274 media::VideoCodecProfile profile,
253 base::WaitableEvent* async_waiter, 275 base::WaitableEvent* async_waiter,
254 int32_t* async_retval) { 276 int32_t* async_retval) {
255 DVLOG(3) << "Impl::CreateAndInitializeVEA()"; 277 DVLOG(3) << "Impl::CreateAndInitializeVEA()";
256 DCHECK(thread_checker_.CalledOnValidThread()); 278 DCHECK(thread_checker_.CalledOnValidThread());
257 279
280 status_.store(WEBRTC_VIDEO_CODEC_UNINITIALIZED);
258 RegisterAsyncWaiter(async_waiter, async_retval); 281 RegisterAsyncWaiter(async_waiter, async_retval);
259 282
260 // Check for overflow converting bitrate (kilobits/sec) to bits/sec. 283 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
261 if (IsBitrateTooHigh(bitrate)) 284 if (IsBitrateTooHigh(bitrate))
262 return; 285 return;
263 286
264 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(); 287 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator();
265 if (!video_encoder_) { 288 if (!video_encoder_) {
266 LogAndNotifyError(FROM_HERE, "Error creating VideoEncodeAccelerator", 289 LogAndNotifyError(FROM_HERE, "Error creating VideoEncodeAccelerator",
267 media::VideoEncodeAccelerator::kPlatformFailureError); 290 media::VideoEncodeAccelerator::kPlatformFailureError);
268 return; 291 return;
269 } 292 }
270 input_visible_size_ = input_visible_size; 293 input_visible_size_ = input_visible_size;
271 if (!video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_visible_size_, 294 if (!video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_visible_size_,
272 profile, bitrate * 1000, this)) { 295 profile, bitrate * 1000, this)) {
273 LogAndNotifyError(FROM_HERE, "Error initializing video_encoder", 296 LogAndNotifyError(FROM_HERE, "Error initializing video_encoder",
274 media::VideoEncodeAccelerator::kInvalidArgumentError); 297 media::VideoEncodeAccelerator::kInvalidArgumentError);
275 return; 298 return;
276 } 299 }
300 // RequireBitstreamBuffers or NotifyError will be called and the waiter will
301 // be signaled.
277 } 302 }
278 303
279 void RTCVideoEncoder::Impl::Enqueue(const webrtc::VideoFrame* input_frame, 304 void RTCVideoEncoder::Impl::Enqueue(const webrtc::VideoFrame* input_frame,
280 bool force_keyframe, 305 bool force_keyframe,
281 base::WaitableEvent* async_waiter, 306 base::WaitableEvent* async_waiter,
282 int32_t* async_retval) { 307 int32_t* async_retval) {
283 DVLOG(3) << "Impl::Enqueue()"; 308 DVLOG(3) << "Impl::Enqueue()";
284 DCHECK(thread_checker_.CalledOnValidThread()); 309 DCHECK(thread_checker_.CalledOnValidThread());
285 DCHECK(!input_next_frame_); 310 DCHECK(!input_next_frame_);
286 311
287 RegisterAsyncWaiter(async_waiter, async_retval); 312 RegisterAsyncWaiter(async_waiter, async_retval);
313 int32_t retval = status_.load();
314 if (retval != WEBRTC_VIDEO_CODEC_OK) {
315 SignalAsyncWaiter(retval);
316 return;
317 }
318
288 // If there are no free input and output buffers, drop the frame to avoid a 319 // If there are no free input and output buffers, drop the frame to avoid a
289 // deadlock. If there is a free input buffer, EncodeOneFrame will run and 320 // deadlock. If there is a free input buffer, EncodeOneFrame will run and
290 // unblock Encode(). If there are no free input buffers but there is a free 321 // unblock Encode(). If there are no free input buffers but there is a free
291 // output buffer, EncodeFrameFinished will be called later to unblock 322 // output buffer, EncodeFrameFinished will be called later to unblock
292 // Encode(). 323 // Encode().
293 // 324 //
294 // The caller of Encode() holds a webrtc lock. The deadlock happens when: 325 // The caller of Encode() holds a webrtc lock. The deadlock happens when:
295 // (1) Encode() is waiting for the frame to be encoded in EncodeOneFrame(). 326 // (1) Encode() is waiting for the frame to be encoded in EncodeOneFrame().
296 // (2) There are no free input buffers and they cannot be freed because 327 // (2) There are no free input buffers and they cannot be freed because
297 // the encoder has no output buffers. 328 // the encoder has no output buffers.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
337 DCHECK(thread_checker_.CalledOnValidThread()); 368 DCHECK(thread_checker_.CalledOnValidThread());
338 369
339 // Check for overflow converting bitrate (kilobits/sec) to bits/sec. 370 // Check for overflow converting bitrate (kilobits/sec) to bits/sec.
340 if (IsBitrateTooHigh(bitrate)) 371 if (IsBitrateTooHigh(bitrate))
341 return; 372 return;
342 373
343 if (video_encoder_) 374 if (video_encoder_)
344 video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate); 375 video_encoder_->RequestEncodingParametersChange(bitrate * 1000, framerate);
345 } 376 }
346 377
347 void RTCVideoEncoder::Impl::Destroy() { 378 void RTCVideoEncoder::Impl::Destroy(base::WaitableEvent* async_waiter) {
348 DVLOG(3) << "Impl::Destroy()"; 379 DVLOG(3) << "Impl::Destroy()";
349 DCHECK(thread_checker_.CalledOnValidThread()); 380 DCHECK(thread_checker_.CalledOnValidThread());
350 video_encoder_.reset(); 381 if (video_encoder_) {
382 video_encoder_.reset();
383 status_.store(WEBRTC_VIDEO_CODEC_UNINITIALIZED);
384 }
385 async_waiter->Signal();
386 }
387
388 int32_t RTCVideoEncoder::Impl::GetStatus() {
389 return status_.load();
351 } 390 }
352 391
353 void RTCVideoEncoder::Impl::RequireBitstreamBuffers( 392 void RTCVideoEncoder::Impl::RequireBitstreamBuffers(
354 unsigned int input_count, 393 unsigned int input_count,
355 const gfx::Size& input_coded_size, 394 const gfx::Size& input_coded_size,
356 size_t output_buffer_size) { 395 size_t output_buffer_size) {
357 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count 396 DVLOG(3) << "Impl::RequireBitstreamBuffers(): input_count=" << input_count
358 << ", input_coded_size=" << input_coded_size.ToString() 397 << ", input_coded_size=" << input_coded_size.ToString()
359 << ", output_buffer_size=" << output_buffer_size; 398 << ", output_buffer_size=" << output_buffer_size;
360 DCHECK(thread_checker_.CalledOnValidThread()); 399 DCHECK(thread_checker_.CalledOnValidThread());
(...skipping 26 matching lines...) Expand all
387 } 426 }
388 output_buffers_.push_back(shm.release()); 427 output_buffers_.push_back(shm.release());
389 } 428 }
390 429
391 // Immediately provide all output buffers to the VEA. 430 // Immediately provide all output buffers to the VEA.
392 for (size_t i = 0; i < output_buffers_.size(); ++i) { 431 for (size_t i = 0; i < output_buffers_.size(); ++i) {
393 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( 432 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
394 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size())); 433 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
395 output_buffers_free_count_++; 434 output_buffers_free_count_++;
396 } 435 }
436 DCHECK_EQ(status_.load(), WEBRTC_VIDEO_CODEC_UNINITIALIZED);
437 status_.store(WEBRTC_VIDEO_CODEC_OK);
397 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK); 438 SignalAsyncWaiter(WEBRTC_VIDEO_CODEC_OK);
398 } 439 }
399 440
400 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32_t bitstream_buffer_id, 441 void RTCVideoEncoder::Impl::BitstreamBufferReady(int32_t bitstream_buffer_id,
401 size_t payload_size, 442 size_t payload_size,
402 bool key_frame) { 443 bool key_frame) {
403 DVLOG(3) << "Impl::BitstreamBufferReady(): " 444 DVLOG(3) << "Impl::BitstreamBufferReady(): "
404 "bitstream_buffer_id=" << bitstream_buffer_id 445 "bitstream_buffer_id=" << bitstream_buffer_id
405 << ", payload_size=" << payload_size 446 << ", payload_size=" << payload_size
406 << ", key_frame=" << key_frame; 447 << ", key_frame=" << key_frame;
(...skipping 15 matching lines...) Expand all
422 463
423 // Use webrtc timestamps to ensure correct RTP sender behavior. 464 // Use webrtc timestamps to ensure correct RTP sender behavior.
424 // TODO(hshi): obtain timestamp from the capturer, see crbug.com/350106. 465 // TODO(hshi): obtain timestamp from the capturer, see crbug.com/350106.
425 const int64_t capture_time_us = webrtc::TickTime::MicrosecondTimestamp(); 466 const int64_t capture_time_us = webrtc::TickTime::MicrosecondTimestamp();
426 467
427 // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks). 468 // Derive the capture time (in ms) and RTP timestamp (in 90KHz ticks).
428 const int64_t capture_time_ms = capture_time_us / 1000; 469 const int64_t capture_time_ms = capture_time_us / 1000;
429 const uint32_t rtp_timestamp = 470 const uint32_t rtp_timestamp =
430 static_cast<uint32_t>(capture_time_us * 90 / 1000); 471 static_cast<uint32_t>(capture_time_us * 90 / 1000);
431 472
432 std::unique_ptr<webrtc::EncodedImage> image(new webrtc::EncodedImage( 473 webrtc::EncodedImage image(
433 reinterpret_cast<uint8_t*>(output_buffer->memory()), payload_size, 474 reinterpret_cast<uint8_t*>(output_buffer->memory()), payload_size,
434 output_buffer->mapped_size())); 475 output_buffer->mapped_size());
435 image->_encodedWidth = input_visible_size_.width(); 476 image._encodedWidth = input_visible_size_.width();
436 image->_encodedHeight = input_visible_size_.height(); 477 image._encodedHeight = input_visible_size_.height();
437 image->_timeStamp = rtp_timestamp; 478 image._timeStamp = rtp_timestamp;
438 image->capture_time_ms_ = capture_time_ms; 479 image.capture_time_ms_ = capture_time_ms;
439 image->_frameType = 480 image._frameType =
440 (key_frame ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta); 481 (key_frame ? webrtc::kVideoFrameKey : webrtc::kVideoFrameDelta);
441 image->_completeFrame = true; 482 image._completeFrame = true;
442 483
443 encoder_task_runner_->PostTask( 484 ReturnEncodedImage(image, bitstream_buffer_id, picture_id_);
444 FROM_HERE,
445 base::Bind(&RTCVideoEncoder::ReturnEncodedImage, weak_encoder_,
446 base::Passed(&image), bitstream_buffer_id, picture_id_));
447 // Picture ID must wrap after reaching the maximum. 485 // Picture ID must wrap after reaching the maximum.
448 picture_id_ = (picture_id_ + 1) & 0x7FFF; 486 picture_id_ = (picture_id_ + 1) & 0x7FFF;
449 } 487 }
450 488
451 void RTCVideoEncoder::Impl::NotifyError( 489 void RTCVideoEncoder::Impl::NotifyError(
452 media::VideoEncodeAccelerator::Error error) { 490 media::VideoEncodeAccelerator::Error error) {
453 DCHECK(thread_checker_.CalledOnValidThread()); 491 DCHECK(thread_checker_.CalledOnValidThread());
454 int32_t retval; 492 int32_t retval;
455 switch (error) { 493 switch (error) {
456 case media::VideoEncodeAccelerator::kInvalidArgumentError: 494 case media::VideoEncodeAccelerator::kInvalidArgumentError:
457 retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER; 495 retval = WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
458 break; 496 break;
459 default: 497 default:
460 retval = WEBRTC_VIDEO_CODEC_ERROR; 498 retval = WEBRTC_VIDEO_CODEC_ERROR;
461 } 499 }
462 500
463 video_encoder_.reset(); 501 video_encoder_.reset();
464 502
465 if (async_waiter_) { 503 status_.store(retval);
504 if (async_waiter_)
466 SignalAsyncWaiter(retval); 505 SignalAsyncWaiter(retval);
467 } else {
468 encoder_task_runner_->PostTask(
469 FROM_HERE,
470 base::Bind(&RTCVideoEncoder::NotifyError, weak_encoder_, retval));
471 }
472 } 506 }
473 507
474 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); } 508 RTCVideoEncoder::Impl::~Impl() { DCHECK(!video_encoder_); }
475 509
476 void RTCVideoEncoder::Impl::LogAndNotifyError( 510 void RTCVideoEncoder::Impl::LogAndNotifyError(
477 const tracked_objects::Location& location, 511 const tracked_objects::Location& location,
478 const std::string& str, 512 const std::string& str,
479 media::VideoEncodeAccelerator::Error error) { 513 media::VideoEncodeAccelerator::Error error) {
480 static const char* kErrorNames[] = { 514 static const char* kErrorNames[] = {
481 "kIllegalStateError", "kInvalidArgumentError", "kPlatformFailureError"}; 515 "kIllegalStateError", "kInvalidArgumentError", "kPlatformFailureError"};
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 media::VideoEncodeAccelerator::kInvalidArgumentError); 625 media::VideoEncodeAccelerator::kInvalidArgumentError);
592 return true; 626 return true;
593 } 627 }
594 628
595 bool RTCVideoEncoder::Impl::RequiresSizeChange( 629 bool RTCVideoEncoder::Impl::RequiresSizeChange(
596 const scoped_refptr<media::VideoFrame>& frame) const { 630 const scoped_refptr<media::VideoFrame>& frame) const {
597 return (frame->coded_size() != input_frame_coded_size_ || 631 return (frame->coded_size() != input_frame_coded_size_ ||
598 frame->visible_rect() != gfx::Rect(input_visible_size_)); 632 frame->visible_rect() != gfx::Rect(input_visible_size_));
599 } 633 }
600 634
635 void RTCVideoEncoder::Impl::RegisterEncodeCompleteCallback(
636 base::WaitableEvent* async_waiter,
637 int32_t* async_retval,
638 webrtc::EncodedImageCallback* callback) {
639 DCHECK(thread_checker_.CalledOnValidThread());
640 DVLOG(3) << "RegisterEncodeCompleteCallback()";
641 RegisterAsyncWaiter(async_waiter, async_retval);
642 if (status_.load() == WEBRTC_VIDEO_CODEC_OK) {
emircan 2016/04/12 20:15:03 Remove { } since it is a one-liner.
wuchengli 2016/04/13 15:26:26 Done.
643 encoded_image_callback_ = callback;
644 }
645 SignalAsyncWaiter(status_.load());
646 }
647
648 void RTCVideoEncoder::Impl::ReturnEncodedImage(
649 const webrtc::EncodedImage& image,
650 int32_t bitstream_buffer_id,
651 uint16_t picture_id) {
652 DCHECK(thread_checker_.CalledOnValidThread());
653 DVLOG(3) << "ReturnEncodedImage(): "
654 << "bitstream_buffer_id=" << bitstream_buffer_id
655 << ", picture_id=" << picture_id;
656
657 if (!encoded_image_callback_)
658 return;
659
660 webrtc::RTPFragmentationHeader header;
661 memset(&header, 0, sizeof(header));
662 switch (video_codec_type_) {
663 case webrtc::kVideoCodecVP8:
664 // Generate a header describing a single fragment.
665 header.VerifyAndAllocateFragmentationHeader(1);
666 header.fragmentationOffset[0] = 0;
667 header.fragmentationLength[0] = image._length;
668 header.fragmentationPlType[0] = 0;
669 header.fragmentationTimeDiff[0] = 0;
670 break;
671 case webrtc::kVideoCodecH264:
672 if (!GetRTPFragmentationHeaderH264(&header, image._buffer,
673 image._length)) {
674 DLOG(ERROR) << "Failed to get RTP fragmentation header for H264";
675 NotifyError(
676 (media::VideoEncodeAccelerator::Error)WEBRTC_VIDEO_CODEC_ERROR);
677 return;
678 }
679 break;
680 default:
681 NOTREACHED() << "Invalid video codec type";
682 return;
683 }
684
685 webrtc::CodecSpecificInfo info;
686 memset(&info, 0, sizeof(info));
687 info.codecType = video_codec_type_;
688 if (video_codec_type_ == webrtc::kVideoCodecVP8) {
689 info.codecSpecific.VP8.pictureId = picture_id;
690 info.codecSpecific.VP8.tl0PicIdx = -1;
691 info.codecSpecific.VP8.keyIdx = -1;
692 }
693
694 int32_t retval = encoded_image_callback_->Encoded(image, &info, &header);
emircan 2016/04/12 20:15:02 const
wuchengli 2016/04/13 15:26:26 Done.
695 if (retval < 0) {
696 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
697 << retval;
698 }
699
700 UseOutputBitstreamBufferId(bitstream_buffer_id);
701 }
702
601 RTCVideoEncoder::RTCVideoEncoder( 703 RTCVideoEncoder::RTCVideoEncoder(
602 webrtc::VideoCodecType type, 704 webrtc::VideoCodecType type,
603 media::GpuVideoAcceleratorFactories* gpu_factories) 705 media::GpuVideoAcceleratorFactories* gpu_factories)
604 : video_codec_type_(type), 706 : gpu_factories_(gpu_factories),
605 gpu_factories_(gpu_factories),
606 gpu_task_runner_(gpu_factories->GetTaskRunner()), 707 gpu_task_runner_(gpu_factories->GetTaskRunner()),
607 encoded_image_callback_(NULL), 708 impl_(new Impl(gpu_factories_, type)) {
608 impl_status_(WEBRTC_VIDEO_CODEC_UNINITIALIZED),
609 weak_factory_(this) {
610 DVLOG(1) << "RTCVideoEncoder(): codec type=" << type; 709 DVLOG(1) << "RTCVideoEncoder(): codec type=" << type;
611 } 710 }
612 711
613 RTCVideoEncoder::~RTCVideoEncoder() { 712 RTCVideoEncoder::~RTCVideoEncoder() {
614 DVLOG(3) << "~RTCVideoEncoder"; 713 DVLOG(3) << "~RTCVideoEncoder";
615 DCHECK(thread_checker_.CalledOnValidThread());
616 Release(); 714 Release();
617 DCHECK(!impl_.get());
618 } 715 }
619 716
620 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings, 717 int32_t RTCVideoEncoder::InitEncode(const webrtc::VideoCodec* codec_settings,
621 int32_t number_of_cores, 718 int32_t number_of_cores,
622 size_t max_payload_size) { 719 size_t max_payload_size) {
623 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType 720 DVLOG(1) << "InitEncode(): codecType=" << codec_settings->codecType
624 << ", width=" << codec_settings->width 721 << ", width=" << codec_settings->width
625 << ", height=" << codec_settings->height 722 << ", height=" << codec_settings->height
626 << ", startBitrate=" << codec_settings->startBitrate; 723 << ", startBitrate=" << codec_settings->startBitrate;
627 DCHECK(thread_checker_.CalledOnValidThread());
628 DCHECK(!impl_.get());
629 724
630 const media::VideoCodecProfile profile = 725 const media::VideoCodecProfile profile = WebRTCVideoCodecToVideoCodecProfile(
631 WebRTCVideoCodecToVideoCodecProfile(video_codec_type_, codec_settings); 726 impl_->video_codec_type(), codec_settings);
632 727
633 weak_factory_.InvalidateWeakPtrs();
634 impl_ = new Impl(weak_factory_.GetWeakPtr(), gpu_factories_);
635 base::WaitableEvent initialization_waiter(true, false); 728 base::WaitableEvent initialization_waiter(true, false);
636 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; 729 int32_t initialization_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
637 gpu_task_runner_->PostTask( 730 gpu_task_runner_->PostTask(
638 FROM_HERE, 731 FROM_HERE,
639 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA, 732 base::Bind(&RTCVideoEncoder::Impl::CreateAndInitializeVEA,
640 impl_, 733 impl_,
641 gfx::Size(codec_settings->width, codec_settings->height), 734 gfx::Size(codec_settings->width, codec_settings->height),
642 codec_settings->startBitrate, 735 codec_settings->startBitrate,
643 profile, 736 profile,
644 &initialization_waiter, 737 &initialization_waiter,
645 &initialization_retval)); 738 &initialization_retval));
646 739
647 // webrtc::VideoEncoder expects this call to be synchronous. 740 // webrtc::VideoEncoder expects this call to be synchronous.
648 initialization_waiter.Wait(); 741 initialization_waiter.Wait();
649 RecordInitEncodeUMA(initialization_retval, profile); 742 RecordInitEncodeUMA(initialization_retval, profile);
650 return initialization_retval; 743 return initialization_retval;
651 } 744 }
652 745
653 int32_t RTCVideoEncoder::Encode( 746 int32_t RTCVideoEncoder::Encode(
654 const webrtc::VideoFrame& input_image, 747 const webrtc::VideoFrame& input_image,
655 const webrtc::CodecSpecificInfo* codec_specific_info, 748 const webrtc::CodecSpecificInfo* codec_specific_info,
656 const std::vector<webrtc::FrameType>* frame_types) { 749 const std::vector<webrtc::FrameType>* frame_types) {
657 DVLOG(3) << "Encode()"; 750 DVLOG(3) << "Encode()";
658 if (!impl_.get()) {
659 DVLOG(3) << "Encode(): returning impl_status_=" << impl_status_;
660 return impl_status_;
661 }
662 751
663 const bool want_key_frame = frame_types && frame_types->size() && 752 const bool want_key_frame = frame_types && frame_types->size() &&
664 frame_types->front() == webrtc::kVideoFrameKey; 753 frame_types->front() == webrtc::kVideoFrameKey;
665 base::WaitableEvent encode_waiter(true, false); 754 base::WaitableEvent encode_waiter(true, false);
666 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED; 755 int32_t encode_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
667 gpu_task_runner_->PostTask( 756 gpu_task_runner_->PostTask(
668 FROM_HERE, 757 FROM_HERE,
669 base::Bind(&RTCVideoEncoder::Impl::Enqueue, 758 base::Bind(&RTCVideoEncoder::Impl::Enqueue,
670 impl_, 759 impl_,
671 &input_image, 760 &input_image,
672 want_key_frame, 761 want_key_frame,
673 &encode_waiter, 762 &encode_waiter,
674 &encode_retval)); 763 &encode_retval));
675 764
676 // webrtc::VideoEncoder expects this call to be synchronous. 765 // webrtc::VideoEncoder expects this call to be synchronous.
677 encode_waiter.Wait(); 766 encode_waiter.Wait();
678 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval; 767 DVLOG(3) << "Encode(): returning encode_retval=" << encode_retval;
679 return encode_retval; 768 return encode_retval;
680 } 769 }
681 770
682 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback( 771 int32_t RTCVideoEncoder::RegisterEncodeCompleteCallback(
683 webrtc::EncodedImageCallback* callback) { 772 webrtc::EncodedImageCallback* callback) {
684 DVLOG(3) << "RegisterEncodeCompleteCallback()"; 773 DVLOG(3) << "RegisterEncodeCompleteCallback()";
685 DCHECK(thread_checker_.CalledOnValidThread()); 774 base::WaitableEvent register_waiter(true, false);
686 if (!impl_.get()) { 775 int32_t register_retval = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
687 DVLOG(3) << "RegisterEncodeCompleteCallback(): returning " << impl_status_; 776 gpu_task_runner_->PostTask(
688 return impl_status_; 777 FROM_HERE,
689 } 778 base::Bind(&RTCVideoEncoder::Impl::RegisterEncodeCompleteCallback, impl_,
690 779 &register_waiter, &register_retval, callback));
691 encoded_image_callback_ = callback; 780 register_waiter.Wait();
692 return WEBRTC_VIDEO_CODEC_OK; 781 return register_retval;
693 } 782 }
694 783
695 int32_t RTCVideoEncoder::Release() { 784 int32_t RTCVideoEncoder::Release() {
696 DVLOG(3) << "Release()"; 785 DVLOG(3) << "Release()";
697 DCHECK(thread_checker_.CalledOnValidThread());
698 786
699 if (impl_.get()) { 787 base::WaitableEvent release_waiter(true, false);
700 gpu_task_runner_->PostTask(FROM_HERE, 788 gpu_task_runner_->PostTask(
701 base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_)); 789 FROM_HERE,
702 impl_ = NULL; 790 base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_, &release_waiter));
703 weak_factory_.InvalidateWeakPtrs(); 791 release_waiter.Wait();
704 impl_status_ = WEBRTC_VIDEO_CODEC_UNINITIALIZED;
705 }
706 return WEBRTC_VIDEO_CODEC_OK; 792 return WEBRTC_VIDEO_CODEC_OK;
707 } 793 }
708 794
709 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss, 795 int32_t RTCVideoEncoder::SetChannelParameters(uint32_t packet_loss,
710 int64_t rtt) { 796 int64_t rtt) {
711 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss 797 DVLOG(3) << "SetChannelParameters(): packet_loss=" << packet_loss
712 << ", rtt=" << rtt; 798 << ", rtt=" << rtt;
713 // Ignored. 799 // Ignored.
714 return WEBRTC_VIDEO_CODEC_OK; 800 return WEBRTC_VIDEO_CODEC_OK;
715 } 801 }
716 802
717 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) { 803 int32_t RTCVideoEncoder::SetRates(uint32_t new_bit_rate, uint32_t frame_rate) {
718 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate 804 DVLOG(3) << "SetRates(): new_bit_rate=" << new_bit_rate
719 << ", frame_rate=" << frame_rate; 805 << ", frame_rate=" << frame_rate;
720 if (!impl_.get()) { 806 int32_t retval = impl_->GetStatus();
emircan 2016/04/12 20:15:03 const
wuchengli 2016/04/13 15:26:26 Done.
721 DVLOG(3) << "SetRates(): returning " << impl_status_; 807 if (retval != WEBRTC_VIDEO_CODEC_OK) {
722 return impl_status_; 808 DVLOG(3) << "SetRates(): returning " << retval;
809 return retval;
723 } 810 }
724 811
emircan 2016/04/12 20:15:02 A question: Should l.371 return WEBRTC_VIDEO_CODEC
wuchengli 2016/04/13 15:26:26 After l.371 (IsBitrateTooHigh) returns false, |sta
725 gpu_task_runner_->PostTask( 812 gpu_task_runner_->PostTask(
726 FROM_HERE, 813 FROM_HERE,
727 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange, 814 base::Bind(&RTCVideoEncoder::Impl::RequestEncodingParametersChange,
728 impl_, 815 impl_,
729 new_bit_rate, 816 new_bit_rate,
730 frame_rate)); 817 frame_rate));
731 return WEBRTC_VIDEO_CODEC_OK; 818 return WEBRTC_VIDEO_CODEC_OK;
732 } 819 }
733 820
734 void RTCVideoEncoder::ReturnEncodedImage(
735 std::unique_ptr<webrtc::EncodedImage> image,
736 int32_t bitstream_buffer_id,
737 uint16_t picture_id) {
738 DCHECK(thread_checker_.CalledOnValidThread());
739 DVLOG(3) << "ReturnEncodedImage(): "
740 << "bitstream_buffer_id=" << bitstream_buffer_id
741 << ", picture_id=" << picture_id;
742
743 if (!encoded_image_callback_)
744 return;
745
746 webrtc::RTPFragmentationHeader header;
747 memset(&header, 0, sizeof(header));
748 switch (video_codec_type_) {
749 case webrtc::kVideoCodecVP8:
750 // Generate a header describing a single fragment.
751 header.VerifyAndAllocateFragmentationHeader(1);
752 header.fragmentationOffset[0] = 0;
753 header.fragmentationLength[0] = image->_length;
754 header.fragmentationPlType[0] = 0;
755 header.fragmentationTimeDiff[0] = 0;
756 break;
757 case webrtc::kVideoCodecH264:
758 if (!GetRTPFragmentationHeaderH264(
759 &header, image->_buffer, image->_length)) {
760 DLOG(ERROR) << "Failed to get RTP fragmentation header for H264";
761 NotifyError(WEBRTC_VIDEO_CODEC_ERROR);
762 return;
763 }
764 break;
765 default:
766 NOTREACHED() << "Invalid video codec type";
767 return;
768 }
769
770 webrtc::CodecSpecificInfo info;
771 memset(&info, 0, sizeof(info));
772 info.codecType = video_codec_type_;
773 if (video_codec_type_ == webrtc::kVideoCodecVP8) {
774 info.codecSpecific.VP8.pictureId = picture_id;
775 info.codecSpecific.VP8.tl0PicIdx = -1;
776 info.codecSpecific.VP8.keyIdx = -1;
777 }
778
779 int32_t retval = encoded_image_callback_->Encoded(*image, &info, &header);
780 if (retval < 0) {
781 DVLOG(2) << "ReturnEncodedImage(): encoded_image_callback_ returned "
782 << retval;
783 }
784
785 // The call through webrtc::EncodedImageCallback is synchronous, so we can
786 // immediately recycle the output buffer back to the Impl.
787 gpu_task_runner_->PostTask(
788 FROM_HERE,
789 base::Bind(&RTCVideoEncoder::Impl::UseOutputBitstreamBufferId,
790 impl_,
791 bitstream_buffer_id));
792 }
793
794 void RTCVideoEncoder::NotifyError(int32_t error) {
795 DCHECK(thread_checker_.CalledOnValidThread());
796 DVLOG(1) << "NotifyError(): error=" << error;
797
798 impl_status_ = error;
799 gpu_task_runner_->PostTask(FROM_HERE,
800 base::Bind(&RTCVideoEncoder::Impl::Destroy, impl_));
801 impl_ = NULL;
802 }
803
804 void RTCVideoEncoder::RecordInitEncodeUMA( 821 void RTCVideoEncoder::RecordInitEncodeUMA(
805 int32_t init_retval, media::VideoCodecProfile profile) { 822 int32_t init_retval, media::VideoCodecProfile profile) {
806 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess", 823 UMA_HISTOGRAM_BOOLEAN("Media.RTCVideoEncoderInitEncodeSuccess",
807 init_retval == WEBRTC_VIDEO_CODEC_OK); 824 init_retval == WEBRTC_VIDEO_CODEC_OK);
808 if (init_retval == WEBRTC_VIDEO_CODEC_OK) { 825 if (init_retval == WEBRTC_VIDEO_CODEC_OK) {
809 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile", 826 UMA_HISTOGRAM_ENUMERATION("Media.RTCVideoEncoderProfile",
810 profile, 827 profile,
811 media::VIDEO_CODEC_PROFILE_MAX + 1); 828 media::VIDEO_CODEC_PROFILE_MAX + 1);
812 } 829 }
813 } 830 }
814 831
815 } // namespace content 832 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/rtc_video_encoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698