Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 { | |
| 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( | |
| 51 content::VideoTrackRecorder::CodecId codec) { | |
| 52 media::GpuVideoAcceleratorFactories* gpu_factories = | |
| 53 content::RenderThreadImpl::current()->GetGpuFactories(); | |
| 54 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { | |
| 55 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; | |
| 56 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | |
| 57 } | |
| 58 | |
| 59 const media::VideoEncodeAccelerator::SupportedProfiles& profiles = | |
| 60 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); | |
| 61 for (const auto& profile : profiles) { | |
| 62 if ((codec == content::VideoTrackRecorder::CodecId::VP8 && | |
| 63 profile.profile >= media::VP8PROFILE_MIN && | |
| 64 profile.profile <= media::VP8PROFILE_MAX) || | |
| 65 (codec == content::VideoTrackRecorder::CodecId::VP9 && | |
| 66 profile.profile >= media::VP9PROFILE_MIN && | |
| 67 profile.profile <= media::VP9PROFILE_MAX) || | |
| 68 (codec == content::VideoTrackRecorder::CodecId::H264 && | |
| 69 profile.profile >= media::H264PROFILE_MIN && | |
| 70 profile.profile <= media::H264PROFILE_MAX)) | |
| 71 return profile.profile; | |
| 72 } | |
| 73 return media::VIDEO_CODEC_PROFILE_UNKNOWN; | |
| 74 } | |
| 75 | |
| 76 } // anonymous namespace | |
| 77 | |
| 37 namespace content { | 78 namespace content { |
| 38 | 79 |
| 39 // Base class to describe a generic Encoder, encapsulating all actual encoder | 80 // Base class to describe a generic Encoder, encapsulating all actual encoder |
| 40 // (re)configurations, encoding and delivery of received frames. This class is | 81 // (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 | 82 // 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 | 83 // the callback that MediaStreamVideoSink passes along) and to jump back and |
| 43 // forth to an internal encoder thread. Moreover, this class: | 84 // forth to an internal encoder thread. Moreover, this class: |
| 44 // - is created and destroyed on its parent's thread (usually the main Render | 85 // - is created and destroyed on its parent's thread (usually the main Render |
| 45 // thread), |main_task_runner_|. | 86 // thread), |main_task_runner_|. |
| 46 // - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on | 87 // - 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 | 88 // 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); | 89 // is supposed to be the render IO thread (but this is not enforced); |
| 49 // - uses an internal |encoding_task_runner_| for actual encoder interactions, | 90 // - uses an internal |encoding_task_runner_| for actual encoder interactions, |
| 50 // namely configuration, encoding (which might take some time) and destruction. | 91 // 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 | 92 // This task runner can be passed on the creation. If nothing is passed, a new |
| 52 // encoding thread is created and used. | 93 // encoding thread is created and used. |
| 53 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { | 94 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { |
| 54 public: | 95 public: |
| 55 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, | 96 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, |
| 56 int32_t bits_per_second, | 97 int32_t bits_per_second, |
| 57 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = | 98 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = |
| 58 nullptr) | 99 nullptr) |
| 59 : main_task_runner_(base::MessageLoop::current()->task_runner()), | 100 : main_task_runner_(base::MessageLoop::current()->task_runner()), |
| 60 encoding_task_runner_(encoding_task_runner), | 101 encoding_task_runner_(encoding_task_runner), |
| 61 paused_(false), | 102 paused_(false), |
| 62 on_encoded_video_callback_(on_encoded_video_callback), | 103 on_encoded_video_callback_(on_encoded_video_callback), |
| 63 bits_per_second_(bits_per_second) { | 104 bits_per_second_(bits_per_second) { |
| 64 DCHECK(!on_encoded_video_callback_.is_null()); | 105 DCHECK(!on_encoded_video_callback_.is_null()); |
| 65 if (encoding_thread_) | 106 if (encoding_task_runner_) |
| 66 return; | 107 return; |
| 67 encoding_thread_.reset(new base::Thread("EncodingThread")); | 108 encoding_thread_.reset(new base::Thread("EncodingThread")); |
| 68 encoding_thread_->Start(); | 109 encoding_thread_->Start(); |
| 69 encoding_task_runner_ = encoding_thread_->task_runner(); | 110 encoding_task_runner_ = encoding_thread_->task_runner(); |
| 70 } | 111 } |
| 71 | 112 |
| 72 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This | 113 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This |
| 73 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first | 114 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first |
| 74 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to | 115 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to |
| 75 // actually encode the frame. | 116 // actually encode the frame. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe); | 213 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe); |
| 173 } | 214 } |
| 174 | 215 |
| 175 static int GetNumberOfThreadsForEncoding() { | 216 static int GetNumberOfThreadsForEncoding() { |
| 176 // Do not saturate CPU utilization just for encoding. On a lower-end system | 217 // 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 | 218 // 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. | 219 // more cores, allow half of the cores to be used for encoding. |
| 179 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); | 220 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); |
| 180 } | 221 } |
| 181 | 222 |
| 223 // Class encapsulating VideoEncodeAccelerator interactions. | |
| 224 class VEAEncoder final : public VideoTrackRecorder::Encoder, | |
| 225 public media::VideoEncodeAccelerator::Client { | |
| 226 public: | |
| 227 VEAEncoder( | |
| 228 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | |
| 229 int32_t bits_per_second, | |
| 230 media::VideoCodecProfile codec); | |
| 231 | |
| 232 // media::VideoEncodeAccelerator::Client implementation. | |
| 233 void RequireBitstreamBuffers(unsigned int input_count, | |
| 234 const gfx::Size& input_coded_size, | |
| 235 size_t output_buffer_size) override; | |
| 236 void BitstreamBufferReady(int32_t bitstream_buffer_id, | |
| 237 size_t payload_size, | |
| 238 bool key_frame) override; | |
| 239 void NotifyError(media::VideoEncodeAccelerator::Error error) override; | |
| 240 | |
| 241 private: | |
| 242 void UseOutputBitstreamBufferId(int32_t bitstream_buffer_id); | |
| 243 void FrameFinished(std::unique_ptr<base::SharedMemory> shm); | |
| 244 | |
| 245 // VideoTrackRecorder::Encoder | |
| 246 ~VEAEncoder() override; | |
| 247 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, | |
| 248 base::TimeTicks capture_timestamp) override; | |
| 249 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; | |
| 250 | |
| 251 media::GpuVideoAcceleratorFactories* const gpu_factories_; | |
| 252 | |
| 253 media::VideoCodecProfile codec_; | |
| 254 | |
| 255 // The underlying VEA to perform encoding on. | |
| 256 std::unique_ptr<media::VideoEncodeAccelerator> video_encoder_; | |
| 257 | |
| 258 // Shared memory buffers for output with the VEA. | |
| 259 ScopedVector<base::SharedMemory> output_buffers_; | |
| 260 | |
| 261 // Shared memory buffers for output with the VEA as FIFO. | |
| 262 std::queue<std::unique_ptr<base::SharedMemory>> input_buffers_; | |
| 263 | |
| 264 // The number of output buffers ready to be filled. | |
| 265 int output_buffers_free_count_; | |
| 266 | |
| 267 // Tracks error status. | |
| 268 bool error_notified_; | |
| 269 | |
| 270 // Tracks first encode frame and its usage. | |
| 271 std::unique_ptr<std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>> | |
| 272 first_frame_; | |
| 273 bool first_frame_encoded_; | |
| 274 | |
| 275 // Size used to initialize encoder. | |
| 276 gfx::Size input_size_; | |
| 277 | |
| 278 // Coded size that encoder requests as input. | |
| 279 gfx::Size vea_requested_input_size_; | |
| 280 | |
| 281 // Frames and corresponding timestamps in encode as FIFO. | |
| 282 std::queue<std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>> | |
| 283 frames_in_encode_; | |
| 284 }; | |
| 285 | |
| 182 // Class encapsulating all libvpx interactions for VP8/VP9 encoding. | 286 // Class encapsulating all libvpx interactions for VP8/VP9 encoding. |
| 183 class VpxEncoder final : public VideoTrackRecorder::Encoder { | 287 class VpxEncoder final : public VideoTrackRecorder::Encoder { |
| 184 public: | 288 public: |
| 185 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, | 289 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, |
| 186 ScopedVpxCodecCtxPtr encoder); | 290 ScopedVpxCodecCtxPtr encoder); |
| 187 | 291 |
| 188 VpxEncoder( | 292 VpxEncoder( |
| 189 bool use_vp9, | 293 bool use_vp9, |
| 190 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 294 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 191 int32_t bits_per_second); | 295 int32_t bits_per_second); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 257 | 361 |
| 258 // The |VideoFrame::timestamp()| of the first received frame. Only used on | 362 // The |VideoFrame::timestamp()| of the first received frame. Only used on |
| 259 // |encoding_thread_|. | 363 // |encoding_thread_|. |
| 260 base::TimeTicks first_frame_timestamp_; | 364 base::TimeTicks first_frame_timestamp_; |
| 261 | 365 |
| 262 DISALLOW_COPY_AND_ASSIGN(H264Encoder); | 366 DISALLOW_COPY_AND_ASSIGN(H264Encoder); |
| 263 }; | 367 }; |
| 264 | 368 |
| 265 #endif // #if BUILDFLAG(RTC_USE_H264) | 369 #endif // #if BUILDFLAG(RTC_USE_H264) |
| 266 | 370 |
| 371 VEAEncoder::VEAEncoder( | |
| 372 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | |
| 373 int32_t bits_per_second, | |
| 374 media::VideoCodecProfile codec) | |
| 375 : Encoder(on_encoded_video_callback, | |
| 376 bits_per_second, | |
| 377 RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()), | |
| 378 gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()), | |
| 379 codec_(codec), | |
| 380 output_buffers_free_count_(0), | |
| 381 error_notified_(false), | |
| 382 first_frame_encoded_(false) { | |
| 383 DCHECK(gpu_factories_); | |
| 384 } | |
| 385 | |
| 386 VEAEncoder::~VEAEncoder() { | |
| 387 encoding_task_runner_->PostTask( | |
| 388 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy, | |
| 389 base::Unretained(video_encoder_.release()))); | |
| 390 } | |
| 391 | |
| 392 void VEAEncoder::RequireBitstreamBuffers(unsigned int input_count, | |
| 393 const gfx::Size& input_coded_size, | |
| 394 size_t output_buffer_size) { | |
| 395 DVLOG(3) << __FUNCTION__; | |
| 396 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 397 | |
| 398 vea_requested_input_size_ = input_coded_size; | |
| 399 output_buffers_.clear(); | |
| 400 output_buffers_free_count_ = 0; | |
| 401 std::queue<std::unique_ptr<base::SharedMemory>>().swap(input_buffers_); | |
| 402 | |
| 403 for (int i = 0; i < kVEAEncoderOutputBufferCount; ++i) { | |
| 404 DCHECK(gpu_factories_); | |
| 405 std::unique_ptr<base::SharedMemory> shm = | |
| 406 gpu_factories_->CreateSharedMemory(output_buffer_size); | |
| 407 if (!shm) { | |
| 408 NOTREACHED(); | |
| 409 return; | |
| 410 } | |
| 411 output_buffers_.push_back(shm.release()); | |
| 412 } | |
| 413 | |
| 414 for (size_t i = 0; i < output_buffers_.size(); ++i) { | |
| 415 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
| 416 i, output_buffers_[i]->handle(), output_buffers_[i]->mapped_size())); | |
| 417 output_buffers_free_count_++; | |
| 418 } | |
| 419 } | |
| 420 | |
| 421 void VEAEncoder::BitstreamBufferReady(int32_t bitstream_buffer_id, | |
| 422 size_t payload_size, | |
| 423 bool keyframe) { | |
| 424 DVLOG(3) << __FUNCTION__; | |
| 425 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 426 | |
| 427 output_buffers_free_count_--; | |
| 428 base::SharedMemory* output_buffer = output_buffers_[bitstream_buffer_id]; | |
| 429 | |
| 430 std::unique_ptr<std::string> data(new std::string); | |
| 431 data->append(reinterpret_cast<char*>(output_buffer->memory()), payload_size); | |
| 432 | |
| 433 const auto front_frame = frames_in_encode_.front(); | |
| 434 frames_in_encode_.pop(); | |
| 435 origin_task_runner_->PostTask( | |
| 436 FROM_HERE, base::Bind(OnFrameEncodeCompleted, on_encoded_video_callback_, | |
| 437 front_frame.first, base::Passed(&data), | |
| 438 front_frame.second, keyframe)); | |
| 439 UseOutputBitstreamBufferId(bitstream_buffer_id); | |
| 440 } | |
| 441 | |
| 442 void VEAEncoder::NotifyError(media::VideoEncodeAccelerator::Error error) { | |
| 443 DVLOG(3) << __FUNCTION__; | |
| 444 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 445 | |
| 446 error_notified_ = true; | |
| 447 } | |
| 448 | |
| 449 void VEAEncoder::UseOutputBitstreamBufferId(int32_t bitstream_buffer_id) { | |
| 450 DVLOG(3) << __FUNCTION__; | |
| 451 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 452 | |
| 453 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( | |
| 454 bitstream_buffer_id, output_buffers_[bitstream_buffer_id]->handle(), | |
| 455 output_buffers_[bitstream_buffer_id]->mapped_size())); | |
| 456 output_buffers_free_count_++; | |
| 457 } | |
| 458 | |
| 459 void VEAEncoder::FrameFinished(std::unique_ptr<base::SharedMemory> shm) { | |
| 460 DVLOG(3) << __FUNCTION__; | |
| 461 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 462 input_buffers_.push(std::move(shm)); | |
| 463 } | |
| 464 | |
| 465 void VEAEncoder::EncodeOnEncodingTaskRunner( | |
| 466 const scoped_refptr<VideoFrame>& frame, | |
| 467 base::TimeTicks capture_timestamp) { | |
| 468 DVLOG(3) << __FUNCTION__; | |
| 469 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 470 | |
| 471 if (input_size_ != frame->visible_rect().size() && video_encoder_) { | |
| 472 video_encoder_->Destroy(); | |
| 473 video_encoder_.reset(); | |
| 474 } | |
| 475 | |
| 476 if (!video_encoder_) { | |
| 477 ConfigureEncoderOnEncodingTaskRunner(frame->visible_rect().size()); | |
| 478 first_frame_.reset( | |
| 479 new std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>( | |
| 480 frame, capture_timestamp)); | |
| 481 } | |
| 482 | |
| 483 if (error_notified_) { | |
| 484 DVLOG(3) << "An error occurred in VEA encoder"; | |
| 485 return; | |
| 486 } | |
| 487 | |
| 488 // Drop frames if there is no output buffers available. | |
| 489 if (output_buffers_free_count_ == 0) { | |
| 490 DVLOG(3) << "Dropped frame."; | |
| 491 return; | |
| 492 } | |
| 493 | |
| 494 // If first frame hasn't been encoded, do it first. | |
| 495 if (!first_frame_encoded_ && first_frame_) { | |
| 496 std::unique_ptr<std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>> | |
| 497 first_frame(first_frame_.release()); | |
| 498 EncodeOnEncodingTaskRunner(first_frame->first, first_frame->second); | |
| 499 first_frame_encoded_ = true; | |
| 500 } | |
| 501 | |
| 502 // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac. | |
| 503 // In that case, the encoder expects more frames before returning result. | |
| 504 // Therefore, a copy is necessary to release the current frame. | |
| 505 scoped_refptr<media::VideoFrame> video_frame = frame; | |
| 506 if (vea_requested_input_size_ != input_size_ || | |
| 507 input_size_.width() < kVEAEncoderMinResolutionWidth || | |
| 508 input_size_.height() < kVEAEncoderMinResolutionHeight) { | |
| 509 // Create SharedMemory backed input buffers as necessary. These SharedMemory | |
| 510 // instances will be shared with GPU process. | |
| 511 if (input_buffers_.empty()) { | |
| 512 std::unique_ptr<base::SharedMemory> shm = | |
| 513 gpu_factories_->CreateSharedMemory(media::VideoFrame::AllocationSize( | |
| 514 media::PIXEL_FORMAT_I420, vea_requested_input_size_)); | |
| 515 input_buffers_.push(std::move(shm)); | |
| 516 } | |
| 517 std::unique_ptr<base::SharedMemory> input_buffer = | |
| 518 std::move(input_buffers_.front()); | |
| 519 input_buffers_.pop(); | |
| 520 while (input_buffer->mapped_size() < | |
| 521 media::VideoFrame::AllocationSize(media::PIXEL_FORMAT_I420, | |
| 522 vea_requested_input_size_)) { | |
| 523 input_buffer.reset(input_buffers_.front().release()); | |
| 524 input_buffers_.pop(); | |
| 525 } | |
| 526 video_frame = media::VideoFrame::WrapExternalSharedMemory( | |
| 527 media::PIXEL_FORMAT_I420, vea_requested_input_size_, | |
| 528 gfx::Rect(input_size_), input_size_, | |
| 529 reinterpret_cast<uint8_t*>(input_buffer->memory()), | |
| 530 input_buffer->mapped_size(), input_buffer->handle(), 0, | |
| 531 frame->timestamp()); | |
| 532 video_frame->AddDestructionObserver(media::BindToCurrentLoop( | |
| 533 base::Bind(&VEAEncoder::FrameFinished, this, | |
| 534 base::Passed(std::move(input_buffer))))); | |
| 535 libyuv::I420Copy(frame->visible_data(media::VideoFrame::kYPlane), | |
| 536 frame->stride(media::VideoFrame::kYPlane), | |
| 537 frame->visible_data(media::VideoFrame::kUPlane), | |
| 538 frame->stride(media::VideoFrame::kUPlane), | |
| 539 frame->visible_data(media::VideoFrame::kVPlane), | |
| 540 frame->stride(media::VideoFrame::kVPlane), | |
| 541 video_frame->visible_data(media::VideoFrame::kYPlane), | |
| 542 video_frame->stride(media::VideoFrame::kYPlane), | |
| 543 video_frame->visible_data(media::VideoFrame::kUPlane), | |
| 544 video_frame->stride(media::VideoFrame::kUPlane), | |
| 545 video_frame->visible_data(media::VideoFrame::kVPlane), | |
| 546 video_frame->stride(media::VideoFrame::kVPlane), | |
| 547 input_size_.width(), input_size_.height()); | |
| 548 } | |
| 549 frames_in_encode_.push(std::make_pair(video_frame, capture_timestamp)); | |
| 550 | |
| 551 encoding_task_runner_->PostTask( | |
| 552 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Encode, | |
| 553 base::Unretained(video_encoder_.get()), video_frame, | |
| 554 first_frame_encoded_ ? false : true)); | |
| 555 } | |
| 556 | |
| 557 void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) { | |
| 558 DVLOG(3) << __FUNCTION__; | |
| 559 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); | |
| 560 DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread()); | |
| 561 | |
| 562 input_size_ = size; | |
| 563 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(); | |
| 564 if (!video_encoder_) { | |
| 565 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
| 566 return; | |
| 567 } | |
| 568 if (!video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_size_, | |
| 569 codec_, bits_per_second_, this)) { | |
| 570 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); | |
| 571 } | |
| 572 first_frame_encoded_ = false; | |
| 573 } | |
| 574 | |
| 267 // static | 575 // static |
| 268 void VpxEncoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, | 576 void VpxEncoder::ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, |
| 269 ScopedVpxCodecCtxPtr encoder) { | 577 ScopedVpxCodecCtxPtr encoder) { |
| 270 DCHECK(encoding_thread->IsRunning()); | 578 DCHECK(encoding_thread->IsRunning()); |
| 271 encoding_thread->Stop(); | 579 encoding_thread->Stop(); |
| 272 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. | 580 // Both |encoding_thread| and |encoder| will be destroyed at end-of-scope. |
| 273 } | 581 } |
| 274 | 582 |
| 275 VpxEncoder::VpxEncoder( | 583 VpxEncoder::VpxEncoder( |
| 276 bool use_vp9, | 584 bool use_vp9, |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 619 VideoTrackRecorder::VideoTrackRecorder( | 927 VideoTrackRecorder::VideoTrackRecorder( |
| 620 CodecId codec, | 928 CodecId codec, |
| 621 const blink::WebMediaStreamTrack& track, | 929 const blink::WebMediaStreamTrack& track, |
| 622 const OnEncodedVideoCB& on_encoded_video_callback, | 930 const OnEncodedVideoCB& on_encoded_video_callback, |
| 623 int32_t bits_per_second) | 931 int32_t bits_per_second) |
| 624 : track_(track) { | 932 : track_(track) { |
| 625 DCHECK(main_render_thread_checker_.CalledOnValidThread()); | 933 DCHECK(main_render_thread_checker_.CalledOnValidThread()); |
| 626 DCHECK(!track_.isNull()); | 934 DCHECK(!track_.isNull()); |
| 627 DCHECK(track_.getExtraData()); | 935 DCHECK(track_.getExtraData()); |
| 628 | 936 |
| 629 switch (codec) { | 937 const auto& vea_supported_profile = GetVEASupportedProfile(codec); |
| 938 // TODO(emircan): Prioritize software based encoders in lower resolutions. | |
| 939 if (vea_supported_profile != media::VIDEO_CODEC_PROFILE_UNKNOWN) { | |
| 940 encoder_ = new VEAEncoder(on_encoded_video_callback, bits_per_second, | |
| 941 vea_supported_profile); | |
| 942 } else { | |
|
mcasas
2016/05/18 21:36:09
Maybe we can still change this |else| to
if (!enco
emircan
2016/05/18 21:50:14
In PS#2, when RenderThreadImpl::current() is not d
| |
| 943 switch (codec) { | |
| 630 #if BUILDFLAG(RTC_USE_H264) | 944 #if BUILDFLAG(RTC_USE_H264) |
| 631 case CodecId::H264: | 945 case CodecId::H264: |
| 632 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); | 946 encoder_ = new H264Encoder(on_encoded_video_callback, bits_per_second); |
| 633 break; | 947 break; |
| 634 #endif | 948 #endif |
| 635 case CodecId::VP8: | 949 case CodecId::VP8: |
| 636 case CodecId::VP9: | 950 case CodecId::VP9: |
| 637 encoder_ = new VpxEncoder(codec == CodecId::VP9, | 951 encoder_ = new VpxEncoder(codec == CodecId::VP9, |
| 638 on_encoded_video_callback, bits_per_second); | 952 on_encoded_video_callback, bits_per_second); |
| 639 break; | 953 break; |
| 640 default: | 954 default: |
| 641 NOTREACHED() << "Unsupported codec"; | 955 NOTREACHED() << "Unsupported codec"; |
| 956 } | |
| 642 } | 957 } |
| 643 | 958 |
| 644 // StartFrameEncode() will be called on Render IO thread. | 959 // StartFrameEncode() will be called on Render IO thread. |
| 645 MediaStreamVideoSink::ConnectToTrack( | 960 MediaStreamVideoSink::ConnectToTrack( |
| 646 track_, | 961 track_, |
| 647 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), | 962 base::Bind(&VideoTrackRecorder::Encoder::StartFrameEncode, encoder_), |
| 648 false); | 963 false); |
| 649 } | 964 } |
| 650 | 965 |
| 651 VideoTrackRecorder::~VideoTrackRecorder() { | 966 VideoTrackRecorder::~VideoTrackRecorder() { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 666 encoder_->SetPaused(false); | 981 encoder_->SetPaused(false); |
| 667 } | 982 } |
| 668 | 983 |
| 669 void VideoTrackRecorder::OnVideoFrameForTesting( | 984 void VideoTrackRecorder::OnVideoFrameForTesting( |
| 670 const scoped_refptr<media::VideoFrame>& frame, | 985 const scoped_refptr<media::VideoFrame>& frame, |
| 671 base::TimeTicks timestamp) { | 986 base::TimeTicks timestamp) { |
| 672 encoder_->StartFrameEncode(frame, timestamp); | 987 encoder_->StartFrameEncode(frame, timestamp); |
| 673 } | 988 } |
| 674 | 989 |
| 675 } // namespace content | 990 } // namespace content |
| OLD | NEW |