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

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

Issue 1990643002: Add VEAEncoder to VideoTrackRecorder (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix unittests. Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/video_track_recorder.h" 5 #include "content/renderer/media/video_track_recorder.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/macros.h" 11 #include "base/macros.h"
12 #include "base/sys_info.h" 12 #include "base/sys_info.h"
13 #include "base/task_runner_util.h"
13 #include "base/threading/thread.h" 14 #include "base/threading/thread.h"
14 #include "base/time/time.h" 15 #include "base/time/time.h"
15 #include "base/trace_event/trace_event.h" 16 #include "base/trace_event/trace_event.h"
17 #include "content/renderer/media/renderer_gpu_video_accelerator_factories.h"
18 #include "content/renderer/render_thread_impl.h"
19 #include "media/base/bind_to_current_loop.h"
16 #include "media/base/video_frame.h" 20 #include "media/base/video_frame.h"
17 #include "media/base/video_util.h" 21 #include "media/base/video_util.h"
22 #include "third_party/libyuv/include/libyuv/convert.h"
18 #include "ui/gfx/geometry/size.h" 23 #include "ui/gfx/geometry/size.h"
19 24
20 #if BUILDFLAG(RTC_USE_H264) 25 #if BUILDFLAG(RTC_USE_H264)
21 #include "third_party/openh264/src/codec/api/svc/codec_api.h" 26 #include "third_party/openh264/src/codec/api/svc/codec_api.h"
22 #include "third_party/openh264/src/codec/api/svc/codec_app_def.h" 27 #include "third_party/openh264/src/codec/api/svc/codec_app_def.h"
23 #include "third_party/openh264/src/codec/api/svc/codec_def.h" 28 #include "third_party/openh264/src/codec/api/svc/codec_def.h"
24 #endif // #if BUILDFLAG(RTC_USE_H264) 29 #endif // #if BUILDFLAG(RTC_USE_H264)
25 30
26 extern "C" { 31 extern "C" {
27 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide 32 // VPX_CODEC_DISABLE_COMPAT excludes parts of the libvpx API that provide
28 // backwards compatibility for legacy applications using the library. 33 // backwards compatibility for legacy applications using the library.
29 #define VPX_CODEC_DISABLE_COMPAT 1 34 #define VPX_CODEC_DISABLE_COMPAT 1
30 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" 35 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
31 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" 36 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
32 } 37 }
33 38
34 using media::VideoFrame; 39 using media::VideoFrame;
35 using media::VideoFrameMetadata; 40 using media::VideoFrameMetadata;
36 41
42 namespace {
mcasas 2016/05/18 22:22:58 IIRC, you can move this anonymous namespace inside
emircan 2016/05/21 00:01:17 Done.
43
44 const int kVEAEncoderMinResolutionWidth = 640;
45 const int kVEAEncoderMinResolutionHeight = 480;
46 const int kVEAEncoderOutputBufferCount = 4;
47
48 // Returns the preferred codec profile from VEA supported profiles. If no
49 // profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN.
50 media::VideoCodecProfile GetVEASupportedProfile(
mcasas 2016/05/18 22:22:58 nit: s/GetVEASupportedProfile/CodecIdToVEAProfile/
emircan 2016/05/21 00:01:17 Done.
51 content::VideoTrackRecorder::CodecId codec) {
52 content::RenderThreadImpl* render_thread_impl =
53 content::RenderThreadImpl::current();
54 if (!render_thread_impl)
55 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
56
57 media::GpuVideoAcceleratorFactories* gpu_factories =
58 content::RenderThreadImpl::current()->GetGpuFactories();
59 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) {
60 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories";
61 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
62 }
63
64 const media::VideoEncodeAccelerator::SupportedProfiles& profiles =
65 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles();
66 for (const auto& profile : profiles) {
67 if ((codec == content::VideoTrackRecorder::CodecId::VP8 &&
68 profile.profile >= media::VP8PROFILE_MIN &&
69 profile.profile <= media::VP8PROFILE_MAX) ||
70 (codec == content::VideoTrackRecorder::CodecId::VP9 &&
71 profile.profile >= media::VP9PROFILE_MIN &&
72 profile.profile <= media::VP9PROFILE_MAX) ||
73 (codec == content::VideoTrackRecorder::CodecId::H264 &&
74 profile.profile >= media::H264PROFILE_MIN &&
75 profile.profile <= media::H264PROFILE_MAX))
76 return profile.profile;
77 }
78 return media::VIDEO_CODEC_PROFILE_UNKNOWN;
mcasas 2016/05/18 22:22:58 Just some side nit, if you could refactor this blo
emircan 2016/05/21 00:01:17 Done.
79 }
80
81 } // anonymous namespace
82
37 namespace content { 83 namespace content {
38 84
39 // Base class to describe a generic Encoder, encapsulating all actual encoder 85 // Base class to describe a generic Encoder, encapsulating all actual encoder
40 // (re)configurations, encoding and delivery of received frames. This class is 86 // (re)configurations, encoding and delivery of received frames. This class is
41 // ref-counted to allow the MediaStreamVideoTrack to hold a reference to it (via 87 // ref-counted to allow the MediaStreamVideoTrack to hold a reference to it (via
42 // the callback that MediaStreamVideoSink passes along) and to jump back and 88 // the callback that MediaStreamVideoSink passes along) and to jump back and
43 // forth to an internal encoder thread. Moreover, this class: 89 // forth to an internal encoder thread. Moreover, this class:
44 // - is created and destroyed on its parent's thread (usually the main Render 90 // - is created and destroyed on its parent's thread (usually the main Render
45 // thread), |main_task_runner_|. 91 // thread), |main_task_runner_|.
46 // - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on 92 // - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on
47 // that thread as well. This task runner is cached on first frame arrival, and 93 // that thread as well. This task runner is cached on first frame arrival, and
48 // is supposed to be the render IO thread (but this is not enforced); 94 // is supposed to be the render IO thread (but this is not enforced);
49 // - uses an internal |encoding_task_runner_| for actual encoder interactions, 95 // - uses an internal |encoding_task_runner_| for actual encoder interactions,
50 // namely configuration, encoding (which might take some time) and destruction. 96 // namely configuration, encoding (which might take some time) and destruction.
51 // This task runner can be passed on the creation. If nothing is passed, a new 97 // This task runner can be passed on the creation. If nothing is passed, a new
52 // encoding thread is created and used. 98 // encoding thread is created and used.
53 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { 99 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> {
54 public: 100 public:
55 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, 101 Encoder(const OnEncodedVideoCB& on_encoded_video_callback,
56 int32_t bits_per_second, 102 int32_t bits_per_second,
57 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = 103 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner =
58 nullptr) 104 nullptr)
59 : main_task_runner_(base::MessageLoop::current()->task_runner()), 105 : main_task_runner_(base::MessageLoop::current()->task_runner()),
60 encoding_task_runner_(encoding_task_runner), 106 encoding_task_runner_(encoding_task_runner),
61 paused_(false), 107 paused_(false),
62 on_encoded_video_callback_(on_encoded_video_callback), 108 on_encoded_video_callback_(on_encoded_video_callback),
63 bits_per_second_(bits_per_second) { 109 bits_per_second_(bits_per_second) {
64 DCHECK(!on_encoded_video_callback_.is_null()); 110 DCHECK(!on_encoded_video_callback_.is_null());
65 if (encoding_thread_) 111 if (encoding_task_runner_)
66 return; 112 return;
67 encoding_thread_.reset(new base::Thread("EncodingThread")); 113 encoding_thread_.reset(new base::Thread("EncodingThread"));
68 encoding_thread_->Start(); 114 encoding_thread_->Start();
69 encoding_task_runner_ = encoding_thread_->task_runner(); 115 encoding_task_runner_ = encoding_thread_->task_runner();
70 } 116 }
71 117
72 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This 118 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This
73 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first 119 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first
74 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to 120 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to
75 // actually encode the frame. 121 // actually encode the frame.
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
172 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe); 218 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe);
173 } 219 }
174 220
175 static int GetNumberOfThreadsForEncoding() { 221 static int GetNumberOfThreadsForEncoding() {
176 // Do not saturate CPU utilization just for encoding. On a lower-end system 222 // Do not saturate CPU utilization just for encoding. On a lower-end system
177 // with only 1 or 2 cores, use only one thread for encoding. On systems with 223 // with only 1 or 2 cores, use only one thread for encoding. On systems with
178 // more cores, allow half of the cores to be used for encoding. 224 // more cores, allow half of the cores to be used for encoding.
179 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); 225 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2);
180 } 226 }
181 227
228 // Class encapsulating VideoEncodeAccelerator interactions.
229 class VEAEncoder final : public VideoTrackRecorder::Encoder,
mcasas 2016/05/18 22:22:58 Could you comment on the threading here plz? I se
emircan 2016/05/21 00:01:17 Done.
230 public media::VideoEncodeAccelerator::Client {
231 public:
232 VEAEncoder(
233 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
234 int32_t bits_per_second,
235 media::VideoCodecProfile codec);
236
237 // media::VideoEncodeAccelerator::Client implementation.
238 void RequireBitstreamBuffers(unsigned int input_count,
239 const gfx::Size& input_coded_size,
240 size_t output_buffer_size) override;
241 void BitstreamBufferReady(int32_t bitstream_buffer_id,
242 size_t payload_size,
243 bool key_frame) override;
244 void NotifyError(media::VideoEncodeAccelerator::Error error) override;
245
246 private:
247 void UseOutputBitstreamBufferId(int32_t bitstream_buffer_id);
248 void FrameFinished(std::unique_ptr<base::SharedMemory> shm);
249
250 // VideoTrackRecorder::Encoder
mcasas 2016/05/18 22:22:58 ... implementation and that should only apply to t
emircan 2016/05/21 00:01:17 See l.303 and 355. I think it should apply to dtor
251 ~VEAEncoder() override;
252 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame,
253 base::TimeTicks capture_timestamp) override;
254 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override;
255
256 media::GpuVideoAcceleratorFactories* const gpu_factories_;
257
258 media::VideoCodecProfile codec_;
mcasas 2016/05/18 22:22:58 const?
emircan 2016/05/21 00:01:17 Done.
259
260 // The underlying VEA to perform encoding on.
261 std::unique_ptr<media::VideoEncodeAccelerator> video_encoder_;
262
263 // Shared memory buffers for output with the VEA.
264 ScopedVector<base::SharedMemory> output_buffers_;
mcasas 2016/05/18 22:22:58 ScopedVector is deprecated [1], instead, use std::
emircan 2016/05/21 00:01:17 Done.
265
266 // Shared memory buffers for output with the VEA as FIFO.
267 std::queue<std::unique_ptr<base::SharedMemory>> input_buffers_;
268
269 // The number of output buffers ready to be filled.
270 int output_buffers_free_count_;
271
272 // Tracks error status.
273 bool error_notified_;
274
275 // Tracks first encode frame and its usage.
276 std::unique_ptr<std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>>
mcasas 2016/05/18 22:22:58 I suggest using VideoFrameAndTimestamp = st
emircan 2016/05/21 00:01:18 Done.
277 first_frame_;
278 bool first_frame_encoded_;
279
280 // Size used to initialize encoder.
281 gfx::Size input_size_;
282
283 // Coded size that encoder requests as input.
284 gfx::Size vea_requested_input_size_;
285
286 // Frames and corresponding timestamps in encode as FIFO.
287 std::queue<std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>>
288 frames_in_encode_;
289 };
290
182 // Class encapsulating all libvpx interactions for VP8/VP9 encoding. 291 // Class encapsulating all libvpx interactions for VP8/VP9 encoding.
183 class VpxEncoder final : public VideoTrackRecorder::Encoder { 292 class VpxEncoder final : public VideoTrackRecorder::Encoder {
184 public: 293 public:
185 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, 294 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread,
186 ScopedVpxCodecCtxPtr encoder); 295 ScopedVpxCodecCtxPtr encoder);
187 296
188 VpxEncoder( 297 VpxEncoder(
189 bool use_vp9, 298 bool use_vp9,
190 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, 299 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
191 int32_t bits_per_second); 300 int32_t bits_per_second);
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 366
258 // The |VideoFrame::timestamp()| of the first received frame. Only used on 367 // The |VideoFrame::timestamp()| of the first received frame. Only used on
259 // |encoding_thread_|. 368 // |encoding_thread_|.
260 base::TimeTicks first_frame_timestamp_; 369 base::TimeTicks first_frame_timestamp_;
261 370
262 DISALLOW_COPY_AND_ASSIGN(H264Encoder); 371 DISALLOW_COPY_AND_ASSIGN(H264Encoder);
263 }; 372 };
264 373
265 #endif // #if BUILDFLAG(RTC_USE_H264) 374 #endif // #if BUILDFLAG(RTC_USE_H264)
266 375
376 VEAEncoder::VEAEncoder(
377 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback,
378 int32_t bits_per_second,
379 media::VideoCodecProfile codec)
380 : Encoder(on_encoded_video_callback,
381 bits_per_second,
382 RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()),
383 gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()),
384 codec_(codec),
385 output_buffers_free_count_(0),
386 error_notified_(false),
387 first_frame_encoded_(false) {
388 DCHECK(gpu_factories_);
389 }
390
391 VEAEncoder::~VEAEncoder() {
392 encoding_task_runner_->PostTask(
393 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy,
394 base::Unretained(video_encoder_.release())));
395 }
396
397 void VEAEncoder::RequireBitstreamBuffers(unsigned int input_count,
mcasas 2016/05/18 22:22:58 Shouldn't we at least DCHECK_GE(kVEAEncoderOutputB
emircan 2016/05/21 00:01:17 Not really as those two aren't related. I am comme
398 const gfx::Size& input_coded_size,
399 size_t output_buffer_size) {
400 DVLOG(3) << __FUNCTION__;
401 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
402
403 vea_requested_input_size_ = input_coded_size;
404 output_buffers_.clear();
405 output_buffers_free_count_ = 0;
406 std::queue<std::unique_ptr<base::SharedMemory>>().swap(input_buffers_);
407
408 for (int i = 0; i < kVEAEncoderOutputBufferCount; ++i) {
409 DCHECK(gpu_factories_);
mcasas 2016/05/18 22:22:58 Needed? It's already checked in ctor l.388?
emircan 2016/05/21 00:01:18 Done.
410 std::unique_ptr<base::SharedMemory> shm =
411 gpu_factories_->CreateSharedMemory(output_buffer_size);
412 if (!shm) {
413 NOTREACHED();
414 return;
415 }
416 output_buffers_.push_back(shm.release());
417 }
418
419 for (size_t i = 0; i < output_buffers_.size(); ++i) {
420 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
421 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size()));
422 output_buffers_free_count_++;
423 }
424 }
425
426 void VEAEncoder::BitstreamBufferReady(int32_t bitstream_buffer_id,
427 size_t payload_size,
428 bool keyframe) {
429 DVLOG(3) << __FUNCTION__;
430 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
431
432 output_buffers_free_count_--;
433 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id];
434
435 std::unique_ptr<std::string> data(new std::string);
436 data->append(reinterpret_cast<char*>(output_buffer->memory()), payload_size);
437
438 const auto front_frame = frames_in_encode_.front();
439 frames_in_encode_.pop();
440 origin_task_runner_->PostTask(
441 FROM_HERE, base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_,
442 front_frame.first, base::Passed(&data),
443 front_frame.second, keyframe));
444 UseOutputBitstreamBufferId(bitstream_buffer_id);
445 }
446
447 void VEAEncoder::NotifyError(media::VideoEncodeAccelerator::Error error) {
448 DVLOG(3) << __FUNCTION__;
449 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
450
451 error_notified_ = true;
mcasas 2016/05/18 22:22:58 It's unfortunate we don't have a callback of sorts
emircan 2016/05/21 00:01:18 Done.
452 }
453
454 void VEAEncoder::UseOutputBitstreamBufferId(int32_t bitstream_buffer_id) {
455 DVLOG(3) << __FUNCTION__;
456 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
457
458 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer(
459 bitstream_buffer_id, output_buffers_[bitstream_buffer_id]->handle(),
460 output_buffers_[bitstream_buffer_id]->mapped_size()));
461 output_buffers_free_count_++;
462 }
463
464 void VEAEncoder::FrameFinished(std::unique_ptr<base::SharedMemory> shm) {
465 DVLOG(3) << __FUNCTION__;
466 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
467 input_buffers_.push(std::move(shm));
468 }
469
470 void VEAEncoder::EncodeOnEncodingTaskRunner(
471 const scoped_refptr<VideoFrame>& frame,
472 base::TimeTicks capture_timestamp) {
473 DVLOG(3) << __FUNCTION__;
474 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
475
476 if (input_size_ != frame->visible_rect().size() && video_encoder_) {
477 video_encoder_->Destroy();
478 video_encoder_.reset();
479 }
480
481 if (!video_encoder_) {
482 ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size());
483 first_frame_.reset(
mcasas 2016/05/18 22:22:58 So, if we hypothetically were to receive a few |fr
emircan 2016/05/21 00:01:18 Done.
484 new std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>(
485 frame, capture_timestamp));
486 }
487
488 if (error_notified_) {
489 DVLOG(3) << "An error occurred in VEA encoder";
mcasas 2016/05/18 22:22:58 Would it be a good idea to destroy the |video_enco
emircan 2016/05/21 00:01:18 We had that logic in place for decoder. I will lea
490 return;
491 }
492
493 // Drop frames if there is no output buffers available.
494 if (output_buffers_free_count_ == 0) {
495 DVLOG(3) << "Dropped frame.";
496 return;
497 }
498
499 // If first frame hasn't been encoded, do it first.
500 if (!first_frame_encoded_ && first_frame_) {
501 std::unique_ptr<std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>>
502 first_frame(first_frame_.release());
503 EncodeOnEncodingTaskRunner(first_frame->first, first_frame->second);
mcasas 2016/05/18 22:22:58 I don't understand, we recursively call ourselves
emircan 2016/05/21 00:01:17 Second time around it wouldn't fall here since |fi
504 first_frame_encoded_ = true;
mcasas 2016/05/18 22:22:58 Couldn't we drop |first_frame_encoded_| and instea
emircan 2016/05/21 00:01:17 Done.
505 }
506
507 // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac.
508 // In that case, the encoder expects more frames before returning result.
509 // Therefore, a copy is necessary to release the current frame.
510 scoped_refptr<media::VideoFrame> video_frame = frame;
511 if (vea_requested_input_size_ != input_size_ ||
512 input_size_.width() < kVEAEncoderMinResolutionWidth ||
513 input_size_.height() < kVEAEncoderMinResolutionHeight) {
514 // Create SharedMemory backed input buffers as necessary. These SharedMemory
515 // instances will be shared with GPU process.
516 if (input_buffers_.empty()) {
517 std::unique_ptr<base::SharedMemory> shm =
518 gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize(
519 media::PIXEL_FORMAT_I420, vea_requested_input_size_));
520 input_buffers_.push(std::move(shm));
521 }
522 std::unique_ptr<base::SharedMemory> input_buffer =
523 std::move(input_buffers_.front());
524 input_buffers_.pop();
mcasas 2016/05/18 22:22:58 Suggestion of alternative for l.516-524 ? st
emircan 2016/05/21 00:01:17 Done.
525 while (input_buffer->mapped_size() <
526 media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420,
527 vea_requested_input_size_)) {
528 input_buffer.reset(input_buffers_.front().release());
529 input_buffers_.pop();
530 }
531 video_frame = media::VideoFrame::WrapExternalSharedMemory(
532 media::PIXEL_FORMAT_I420, vea_requested_input_size_,
533 gfx::Rect(input_size_), input_size_,
534 reinterpret_cast<uint8_t*>(input_buffer->memory()),
535 input_buffer->mapped_size(), input_buffer->handle(), 0,
536 frame->timestamp());
537 video_frame->AddDestructionObserver(media::BindToCurrentLoop(
538 base::Bind(&VEAEncoder::FrameFinished, this,
539 base::Passed(std::move(input_buffer)))));
540 libyuv::I420Copy(frame->visible_data(media::VideoFrame::kYPlane),
541 frame->stride(media::VideoFrame::kYPlane),
542 frame->visible_data(media::VideoFrame::kUPlane),
543 frame->stride(media::VideoFrame::kUPlane),
544 frame->visible_data(media::VideoFrame::kVPlane),
545 frame->stride(media::VideoFrame::kVPlane),
546 video_frame->visible_data(media::VideoFrame::kYPlane),
547 video_frame->stride(media::VideoFrame::kYPlane),
548 video_frame->visible_data(media::VideoFrame::kUPlane),
549 video_frame->stride(media::VideoFrame::kUPlane),
550 video_frame->visible_data(media::VideoFrame::kVPlane),
551 video_frame->stride(media::VideoFrame::kVPlane),
552 input_size_.width(), input_size_.height());
553 }
554 frames_in_encode_.push(std::make_pair(video_frame, capture_timestamp));
555
556 encoding_task_runner_->PostTask(
557 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Encode,
558 base::Unretained(video_encoder_.get()), video_frame,
559 first_frame_encoded_ ? false : true));
560 }
561
562 void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) {
563 DVLOG(3) << __FUNCTION__;
564 DCHECK(encoding_task_runner_->BelongsToCurrentThread());
565 DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread());
566
567 input_size_ = size;
568 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator();
569 if (!video_encoder_) {
570 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
571 return;
572 }
573 if (!video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_size_,
mcasas 2016/05/18 22:22:58 Bundle these two if()s ?
emircan 2016/05/21 00:01:17 Done.
574 codec_, bits_per_second_, this)) {
575 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError);
576 }
577 first_frame_encoded_ = false;
578 }
579
267 // static 580 // static
268 void VpxEncoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, 581 void VpxEncoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread,
269 ScopedVpxCodecCtxPtr encoder) { 582 ScopedVpxCodecCtxPtr encoder) {
270 DCHECK(encoding_thread->IsRunning()); 583 DCHECK(encoding_thread->IsRunning());
271 encoding_thread->Stop(); 584 encoding_thread->Stop();
272 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. 585 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope.
273 } 586 }
274 587
275 VpxEncoder::VpxEncoder( 588 VpxEncoder::VpxEncoder(
276 bool use_vp9, 589 bool use_vp9,
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 VideoTrackRecorder::VideoTrackRecorder( 932 VideoTrackRecorder::VideoTrackRecorder(
620 CodecId codec, 933 CodecId codec,
621 const blink::WebMediaStreamTrack& track, 934 const blink::WebMediaStreamTrack& track,
622 const OnEncodedVideoCB& on_encoded_video_callback, 935 const OnEncodedVideoCB& on_encoded_video_callback,
623 int32_t bits_per_second) 936 int32_t bits_per_second)
624 : track_(track) { 937 : track_(track) {
625 DCHECK(main_render_thread_checker_.CalledOnValidThread()); 938 DCHECK(main_render_thread_checker_.CalledOnValidThread());
626 DCHECK(!track_.isNull()); 939 DCHECK(!track_.isNull());
627 DCHECK(track_.getExtraData()); 940 DCHECK(track_.getExtraData());
628 941
629 switch (codec) { 942 const auto& vea_supported_profile = GetVEASupportedProfile(codec);
943 // TODO(emircan): Prioritize software based encoders in lower resolutions.
944 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) {
945 encoder_ = new VEAEncoder(on_encoded_video_callback, bits_per_second,
946 vea_supported_profile);
947 } else {
948 switch (codec) {
630 #if BUILDFLAG(RTC_USE_H264) 949 #if BUILDFLAG(RTC_USE_H264)
631 case CodecId::H264: 950 case CodecId::H264:
632 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); 951 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second);
633 break; 952 break;
634 #endif 953 #endif
635 case CodecId::VP8: 954 case CodecId::VP8:
636 case CodecId::VP9: 955 case CodecId::VP9:
637 encoder_ = new VpxEncoder(codec == CodecId::VP9, 956 encoder_ = new VpxEncoder(codec == CodecId::VP9,
638 on_encoded_video_callback, bits_per_second); 957 on_encoded_video_callback, bits_per_second);
639 break; 958 break;
640 default: 959 default:
641 NOTREACHED() << "Unsupported codec"; 960 NOTREACHED() << "Unsupported codec";
961 }
642 } 962 }
643 963
644 // StartFrameEncode() will be called on Render IO thread. 964 // StartFrameEncode() will be called on Render IO thread.
645 MediaStreamVideoSink::ConnectToTrack( 965 MediaStreamVideoSink::ConnectToTrack(
646 track_, 966 track_,
647 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), 967 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_),
648 false); 968 false);
649 } 969 }
650 970
651 VideoTrackRecorder::~VideoTrackRecorder() { 971 VideoTrackRecorder::~VideoTrackRecorder() {
(...skipping 14 matching lines...) Expand all
666 encoder_->SetPaused(false); 986 encoder_->SetPaused(false);
667 } 987 }
668 988
669 void VideoTrackRecorder::OnVideoFrameForTesting( 989 void VideoTrackRecorder::OnVideoFrameForTesting(
670 const scoped_refptr<media::VideoFrame>& frame, 990 const scoped_refptr<media::VideoFrame>& frame,
671 base::TimeTicks timestamp) { 991 base::TimeTicks timestamp) {
672 encoder_->StartFrameEncode(frame, timestamp); 992 encoder_->StartFrameEncode(frame, timestamp);
673 } 993 }
674 994
675 } // namespace content 995 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/media/video_track_recorder.h ('k') | media/gpu/vt_video_encode_accelerator_mac.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698