| 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 |
| 37 namespace content { | 42 namespace content { |
| 38 | 43 |
| 44 namespace { |
| 45 |
| 46 const int kVEAEncoderMinResolutionWidth = 640; |
| 47 const int kVEAEncoderMinResolutionHeight = 480; |
| 48 const int kVEAEncoderOutputBufferCount = 4; |
| 49 |
| 50 static struct { |
| 51 VideoTrackRecorder::CodecId codec_id; |
| 52 media::VideoCodecProfile min_profile; |
| 53 media::VideoCodecProfile max_profile; |
| 54 } const kSupportedVideoCodecIdToProfile[] = { |
| 55 {VideoTrackRecorder::CodecId::VP8, |
| 56 media::VP8PROFILE_MIN, |
| 57 media::VP8PROFILE_MAX}, |
| 58 {VideoTrackRecorder::CodecId::VP9, |
| 59 media::VP9PROFILE_MIN, |
| 60 media::VP9PROFILE_MAX}, |
| 61 {VideoTrackRecorder::CodecId::H264, |
| 62 media::H264PROFILE_MIN, |
| 63 media::H264PROFILE_MAX}}; |
| 64 |
| 65 // Returns the corresponding codec profile from VEA supported codecs. If no |
| 66 // profile is found, returns VIDEO_CODEC_PROFILE_UNKNOWN. |
| 67 media::VideoCodecProfile CodecIdToVEAProfile( |
| 68 content::VideoTrackRecorder::CodecId codec) { |
| 69 content::RenderThreadImpl* render_thread_impl = |
| 70 content::RenderThreadImpl::current(); |
| 71 if (!render_thread_impl) |
| 72 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 73 |
| 74 media::GpuVideoAcceleratorFactories* gpu_factories = |
| 75 content::RenderThreadImpl::current()->GetGpuFactories(); |
| 76 if (!gpu_factories || !gpu_factories->IsGpuVideoAcceleratorEnabled()) { |
| 77 DVLOG(3) << "Couldn't initialize GpuVideoAcceleratorFactories"; |
| 78 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 79 } |
| 80 |
| 81 const media::VideoEncodeAccelerator::SupportedProfiles& vea_profiles = |
| 82 gpu_factories->GetVideoEncodeAcceleratorSupportedProfiles(); |
| 83 for (const auto& vea_profile : vea_profiles) { |
| 84 for (const auto& supported_profile : kSupportedVideoCodecIdToProfile) { |
| 85 if (codec == supported_profile.codec_id && |
| 86 vea_profile.profile >= supported_profile.min_profile && |
| 87 vea_profile.profile <= supported_profile.max_profile) |
| 88 return vea_profile.profile; |
| 89 } |
| 90 } |
| 91 return media::VIDEO_CODEC_PROFILE_UNKNOWN; |
| 92 } |
| 93 |
| 94 } // anonymous namespace |
| 95 |
| 39 // Base class to describe a generic Encoder, encapsulating all actual encoder | 96 // Base class to describe a generic Encoder, encapsulating all actual encoder |
| 40 // (re)configurations, encoding and delivery of received frames. This class is | 97 // (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 | 98 // 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 | 99 // the callback that MediaStreamVideoSink passes along) and to jump back and |
| 43 // forth to an internal encoder thread. Moreover, this class: | 100 // forth to an internal encoder thread. Moreover, this class: |
| 44 // - is created and destroyed on its parent's thread (usually the main Render | 101 // - is created and destroyed on its parent's thread (usually the main Render |
| 45 // thread), |main_task_runner_|. | 102 // thread), |main_task_runner_|. |
| 46 // - receives VideoFrames on |origin_task_runner_| and runs OnEncodedVideoCB on | 103 // - 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 | 104 // 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); | 105 // is supposed to be the render IO thread (but this is not enforced); |
| 49 // - uses an internal |encoding_task_runner_| for actual encoder interactions, | 106 // - uses an internal |encoding_task_runner_| for actual encoder interactions, |
| 50 // namely configuration, encoding (which might take some time) and destruction. | 107 // 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 | 108 // This task runner can be passed on the creation. If nothing is passed, a new |
| 52 // encoding thread is created and used. | 109 // encoding thread is created and used. |
| 53 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { | 110 class VideoTrackRecorder::Encoder : public base::RefCountedThreadSafe<Encoder> { |
| 54 public: | 111 public: |
| 55 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, | 112 Encoder(const OnEncodedVideoCB& on_encoded_video_callback, |
| 56 int32_t bits_per_second, | 113 int32_t bits_per_second, |
| 57 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = | 114 scoped_refptr<base::SingleThreadTaskRunner> encoding_task_runner = |
| 58 nullptr) | 115 nullptr) |
| 59 : main_task_runner_(base::MessageLoop::current()->task_runner()), | 116 : main_task_runner_(base::MessageLoop::current()->task_runner()), |
| 60 encoding_task_runner_(encoding_task_runner), | 117 encoding_task_runner_(encoding_task_runner), |
| 61 paused_(false), | 118 paused_(false), |
| 62 on_encoded_video_callback_(on_encoded_video_callback), | 119 on_encoded_video_callback_(on_encoded_video_callback), |
| 63 bits_per_second_(bits_per_second) { | 120 bits_per_second_(bits_per_second) { |
| 64 DCHECK(!on_encoded_video_callback_.is_null()); | 121 DCHECK(!on_encoded_video_callback_.is_null()); |
| 65 if (encoding_thread_) | 122 if (encoding_task_runner_) |
| 66 return; | 123 return; |
| 67 encoding_thread_.reset(new base::Thread("EncodingThread")); | 124 encoding_thread_.reset(new base::Thread("EncodingThread")); |
| 68 encoding_thread_->Start(); | 125 encoding_thread_->Start(); |
| 69 encoding_task_runner_ = encoding_thread_->task_runner(); | 126 encoding_task_runner_ = encoding_thread_->task_runner(); |
| 70 } | 127 } |
| 71 | 128 |
| 72 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This | 129 // Start encoding |frame|, returning via |on_encoded_video_callback_|. This |
| 73 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first | 130 // call will also trigger a ConfigureEncoderOnEncodingTaskRunner() upon first |
| 74 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to | 131 // frame arrival or parameter change, and an EncodeOnEncodingTaskRunner() to |
| 75 // actually encode the frame. | 132 // 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); | 229 on_encoded_video_cb.Run(frame, std::move(data), capture_timestamp, keyframe); |
| 173 } | 230 } |
| 174 | 231 |
| 175 static int GetNumberOfThreadsForEncoding() { | 232 static int GetNumberOfThreadsForEncoding() { |
| 176 // Do not saturate CPU utilization just for encoding. On a lower-end system | 233 // 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 | 234 // 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. | 235 // more cores, allow half of the cores to be used for encoding. |
| 179 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); | 236 return std::min(8, (base::SysInfo::NumberOfProcessors() + 1) / 2); |
| 180 } | 237 } |
| 181 | 238 |
| 239 // Class encapsulating VideoEncodeAccelerator interactions. |
| 240 // This class is created and destroyed in its owner thread. All other methods |
| 241 // operate on the task runner pointed by GpuFactories. |
| 242 class VEAEncoder final : public VideoTrackRecorder::Encoder, |
| 243 public media::VideoEncodeAccelerator::Client { |
| 244 public: |
| 245 VEAEncoder( |
| 246 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 247 int32_t bits_per_second, |
| 248 media::VideoCodecProfile codec); |
| 249 |
| 250 // media::VideoEncodeAccelerator::Client implementation. |
| 251 void RequireBitstreamBuffers(unsigned int input_count, |
| 252 const gfx::Size& input_coded_size, |
| 253 size_t output_buffer_size) override; |
| 254 void BitstreamBufferReady(int32_t bitstream_buffer_id, |
| 255 size_t payload_size, |
| 256 bool key_frame) override; |
| 257 void NotifyError(media::VideoEncodeAccelerator::Error error) override; |
| 258 |
| 259 private: |
| 260 using VideoFrameAndTimestamp = |
| 261 std::pair<scoped_refptr<VideoFrame>, base::TimeTicks>; |
| 262 |
| 263 void UseOutputBitstreamBufferId(int32_t bitstream_buffer_id); |
| 264 void FrameFinished(std::unique_ptr<base::SharedMemory> shm); |
| 265 |
| 266 // VideoTrackRecorder::Encoder implementation. |
| 267 ~VEAEncoder() override; |
| 268 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, |
| 269 base::TimeTicks capture_timestamp) override; |
| 270 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; |
| 271 |
| 272 media::GpuVideoAcceleratorFactories* const gpu_factories_; |
| 273 |
| 274 const media::VideoCodecProfile codec_; |
| 275 |
| 276 // The underlying VEA to perform encoding on. |
| 277 std::unique_ptr<media::VideoEncodeAccelerator> video_encoder_; |
| 278 |
| 279 // Shared memory buffers for output with the VEA. |
| 280 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; |
| 281 |
| 282 // Shared memory buffers for output with the VEA as FIFO. |
| 283 std::queue<std::unique_ptr<base::SharedMemory>> input_buffers_; |
| 284 |
| 285 // Tracks error status. |
| 286 bool error_notified_; |
| 287 |
| 288 // Tracks the first frame to encode. |
| 289 std::unique_ptr<VideoFrameAndTimestamp> first_frame_; |
| 290 |
| 291 // Size used to initialize encoder. |
| 292 gfx::Size input_size_; |
| 293 |
| 294 // Coded size that encoder requests as input. |
| 295 gfx::Size vea_requested_input_size_; |
| 296 |
| 297 // Frames and corresponding timestamps in encode as FIFO. |
| 298 std::queue<VideoFrameAndTimestamp> frames_in_encode_; |
| 299 }; |
| 300 |
| 182 // Class encapsulating all libvpx interactions for VP8/VP9 encoding. | 301 // Class encapsulating all libvpx interactions for VP8/VP9 encoding. |
| 183 class VpxEncoder final : public VideoTrackRecorder::Encoder { | 302 class VpxEncoder final : public VideoTrackRecorder::Encoder { |
| 184 public: | 303 public: |
| 185 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, | 304 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, |
| 186 ScopedVpxCodecCtxPtr encoder); | 305 ScopedVpxCodecCtxPtr encoder); |
| 187 | 306 |
| 188 VpxEncoder( | 307 VpxEncoder( |
| 189 bool use_vp9, | 308 bool use_vp9, |
| 190 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 309 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 191 int32_t bits_per_second); | 310 int32_t bits_per_second); |
| 192 | 311 |
| 193 private: | 312 private: |
| 194 // VideoTrackRecorder::Encoder | 313 // VideoTrackRecorder::Encoder implementation. |
| 195 ~VpxEncoder() override; | 314 ~VpxEncoder() override; |
| 196 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, | 315 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, |
| 197 base::TimeTicks capture_timestamp) override; | 316 base::TimeTicks capture_timestamp) override; |
| 198 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; | 317 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; |
| 199 | 318 |
| 200 // Returns true if |codec_config_| has been filled in at least once. | 319 // Returns true if |codec_config_| has been filled in at least once. |
| 201 bool IsInitialized() const; | 320 bool IsInitialized() const; |
| 202 | 321 |
| 203 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. | 322 // Estimate the frame duration from |frame| and |last_frame_timestamp_|. |
| 204 base::TimeDelta EstimateFrameDuration(const scoped_refptr<VideoFrame>& frame); | 323 base::TimeDelta EstimateFrameDuration(const scoped_refptr<VideoFrame>& frame); |
| 205 | 324 |
| 206 // Force usage of VP9 for encoding, instead of VP8 which is the default. | 325 // Force usage of VP9 for encoding, instead of VP8 which is the default. |
| 207 const bool use_vp9_; | 326 const bool use_vp9_; |
| (...skipping 28 matching lines...) Expand all Loading... |
| 236 class H264Encoder final : public VideoTrackRecorder::Encoder { | 355 class H264Encoder final : public VideoTrackRecorder::Encoder { |
| 237 public: | 356 public: |
| 238 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, | 357 static void ShutdownEncoder(std::unique_ptr<base::Thread> encoding_thread, |
| 239 ScopedISVCEncoderPtr encoder); | 358 ScopedISVCEncoderPtr encoder); |
| 240 | 359 |
| 241 H264Encoder( | 360 H264Encoder( |
| 242 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, | 361 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 243 int32_t bits_per_second); | 362 int32_t bits_per_second); |
| 244 | 363 |
| 245 private: | 364 private: |
| 246 // VideoTrackRecorder::Encoder | 365 // VideoTrackRecorder::Encoder implementation. |
| 247 ~H264Encoder() override; | 366 ~H264Encoder() override; |
| 248 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, | 367 void EncodeOnEncodingTaskRunner(const scoped_refptr<VideoFrame>& frame, |
| 249 base::TimeTicks capture_timestamp) override; | 368 base::TimeTicks capture_timestamp) override; |
| 250 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; | 369 void ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) override; |
| 251 | 370 |
| 252 // |openh264_encoder_| is a special scoped pointer to guarantee proper | 371 // |openh264_encoder_| is a special scoped pointer to guarantee proper |
| 253 // destruction, also when reconfiguring due to parameters change. Only used on | 372 // destruction, also when reconfiguring due to parameters change. Only used on |
| 254 // |encoding_thread_|. | 373 // |encoding_thread_|. |
| 255 gfx::Size configured_size_; | 374 gfx::Size configured_size_; |
| 256 ScopedISVCEncoderPtr openh264_encoder_; | 375 ScopedISVCEncoderPtr openh264_encoder_; |
| 257 | 376 |
| 258 // The |VideoFrame::timestamp()| of the first received frame. Only used on | 377 // The |VideoFrame::timestamp()| of the first received frame. Only used on |
| 259 // |encoding_thread_|. | 378 // |encoding_thread_|. |
| 260 base::TimeTicks first_frame_timestamp_; | 379 base::TimeTicks first_frame_timestamp_; |
| 261 | 380 |
| 262 DISALLOW_COPY_AND_ASSIGN(H264Encoder); | 381 DISALLOW_COPY_AND_ASSIGN(H264Encoder); |
| 263 }; | 382 }; |
| 264 | 383 |
| 265 #endif // #if BUILDFLAG(RTC_USE_H264) | 384 #endif // #if BUILDFLAG(RTC_USE_H264) |
| 266 | 385 |
| 386 VEAEncoder::VEAEncoder( |
| 387 const VideoTrackRecorder::OnEncodedVideoCB& on_encoded_video_callback, |
| 388 int32_t bits_per_second, |
| 389 media::VideoCodecProfile codec) |
| 390 : Encoder(on_encoded_video_callback, |
| 391 bits_per_second, |
| 392 RenderThreadImpl::current()->GetGpuFactories()->GetTaskRunner()), |
| 393 gpu_factories_(RenderThreadImpl::current()->GetGpuFactories()), |
| 394 codec_(codec), |
| 395 error_notified_(false) { |
| 396 DCHECK(gpu_factories_); |
| 397 } |
| 398 |
| 399 VEAEncoder::~VEAEncoder() { |
| 400 encoding_task_runner_->PostTask( |
| 401 FROM_HERE, base::Bind(&media::VideoEncodeAccelerator::Destroy, |
| 402 base::Unretained(video_encoder_.release()))); |
| 403 } |
| 404 |
| 405 void VEAEncoder::RequireBitstreamBuffers(unsigned int /*input_count*/, |
| 406 const gfx::Size& input_coded_size, |
| 407 size_t output_buffer_size) { |
| 408 DVLOG(3) << __FUNCTION__; |
| 409 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 410 |
| 411 vea_requested_input_size_ = input_coded_size; |
| 412 output_buffers_.clear(); |
| 413 std::queue<std::unique_ptr<base::SharedMemory>>().swap(input_buffers_); |
| 414 |
| 415 for (int i = 0; i < kVEAEncoderOutputBufferCount; ++i) { |
| 416 std::unique_ptr<base::SharedMemory> shm = |
| 417 gpu_factories_->CreateSharedMemory(output_buffer_size); |
| 418 if (shm) |
| 419 output_buffers_.push_back(base::WrapUnique(shm.release())); |
| 420 } |
| 421 |
| 422 for (size_t i = 0; i < output_buffers_.size(); ++i) |
| 423 UseOutputBitstreamBufferId(i); |
| 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 base::SharedMemory* output_buffer = |
| 433 output_buffers_[bitstream_buffer_id].get(); |
| 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 // TODO(emircan): Notify the owner via a callback. |
| 452 error_notified_ = true; |
| 453 } |
| 454 |
| 455 void VEAEncoder::UseOutputBitstreamBufferId(int32_t bitstream_buffer_id) { |
| 456 DVLOG(3) << __FUNCTION__; |
| 457 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 458 |
| 459 video_encoder_->UseOutputBitstreamBuffer(media::BitstreamBuffer( |
| 460 bitstream_buffer_id, output_buffers_[bitstream_buffer_id]->handle(), |
| 461 output_buffers_[bitstream_buffer_id]->mapped_size())); |
| 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( |
| 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"; |
| 490 return; |
| 491 } |
| 492 |
| 493 // Drop frames if there is no output buffers available. |
| 494 if (output_buffers_.empty()) { |
| 495 // TODO(emircan): Investigate if resetting encoder would help. |
| 496 DVLOG(3) << "Dropped frame."; |
| 497 return; |
| 498 } |
| 499 |
| 500 // If first frame hasn't been encoded, do it first. |
| 501 if (first_frame_) { |
| 502 std::unique_ptr<VideoFrameAndTimestamp> first_frame(first_frame_.release()); |
| 503 EncodeOnEncodingTaskRunner(first_frame->first, first_frame->second); |
| 504 } |
| 505 |
| 506 // Lower resolutions may fall back to SW encoder in some platforms, i.e. Mac. |
| 507 // In that case, the encoder expects more frames before returning result. |
| 508 // Therefore, a copy is necessary to release the current frame. |
| 509 scoped_refptr<media::VideoFrame> video_frame = frame; |
| 510 if (vea_requested_input_size_ != input_size_ || |
| 511 input_size_.width() < kVEAEncoderMinResolutionWidth || |
| 512 input_size_.height() < kVEAEncoderMinResolutionHeight) { |
| 513 // Create SharedMemory backed input buffers as necessary. These SharedMemory |
| 514 // instances will be shared with GPU process. |
| 515 std::unique_ptr<base::SharedMemory> input_buffer; |
| 516 const size_t desired_mapped_size = media::VideoFrame::AllocationSize( |
| 517 media::PIXEL_FORMAT_I420, vea_requested_input_size_); |
| 518 if (input_buffers_.empty()) { |
| 519 input_buffer = gpu_factories_->CreateSharedMemory(desired_mapped_size); |
| 520 } else { |
| 521 do { |
| 522 input_buffer = std::move(input_buffers_.front()); |
| 523 input_buffers_.pop(); |
| 524 } while (!input_buffers_.empty() && |
| 525 input_buffer->mapped_size() < desired_mapped_size); |
| 526 if (!input_buffer || input_buffer->mapped_size() < desired_mapped_size) |
| 527 return; |
| 528 } |
| 529 |
| 530 video_frame = media::VideoFrame::WrapExternalSharedMemory( |
| 531 media::PIXEL_FORMAT_I420, vea_requested_input_size_, |
| 532 gfx::Rect(input_size_), input_size_, |
| 533 reinterpret_cast<uint8_t*>(input_buffer->memory()), |
| 534 input_buffer->mapped_size(), input_buffer->handle(), 0, |
| 535 frame->timestamp()); |
| 536 video_frame->AddDestructionObserver(media::BindToCurrentLoop( |
| 537 base::Bind(&VEAEncoder::FrameFinished, this, |
| 538 base::Passed(std::move(input_buffer))))); |
| 539 libyuv::I420Copy(frame->visible_data(media::VideoFrame::kYPlane), |
| 540 frame->stride(media::VideoFrame::kYPlane), |
| 541 frame->visible_data(media::VideoFrame::kUPlane), |
| 542 frame->stride(media::VideoFrame::kUPlane), |
| 543 frame->visible_data(media::VideoFrame::kVPlane), |
| 544 frame->stride(media::VideoFrame::kVPlane), |
| 545 video_frame->visible_data(media::VideoFrame::kYPlane), |
| 546 video_frame->stride(media::VideoFrame::kYPlane), |
| 547 video_frame->visible_data(media::VideoFrame::kUPlane), |
| 548 video_frame->stride(media::VideoFrame::kUPlane), |
| 549 video_frame->visible_data(media::VideoFrame::kVPlane), |
| 550 video_frame->stride(media::VideoFrame::kVPlane), |
| 551 input_size_.width(), input_size_.height()); |
| 552 } |
| 553 frames_in_encode_.push(std::make_pair(video_frame, capture_timestamp)); |
| 554 |
| 555 encoding_task_runner_->PostTask( |
| 556 FROM_HERE, |
| 557 base::Bind(&media::VideoEncodeAccelerator::Encode, |
| 558 base::Unretained(video_encoder_.get()), video_frame, false)); |
| 559 } |
| 560 |
| 561 void VEAEncoder::ConfigureEncoderOnEncodingTaskRunner(const gfx::Size& size) { |
| 562 DVLOG(3) << __FUNCTION__; |
| 563 DCHECK(encoding_task_runner_->BelongsToCurrentThread()); |
| 564 DCHECK(gpu_factories_->GetTaskRunner()->BelongsToCurrentThread()); |
| 565 |
| 566 input_size_ = size; |
| 567 video_encoder_ = gpu_factories_->CreateVideoEncodeAccelerator(); |
| 568 if (!video_encoder_ || |
| 569 !video_encoder_->Initialize(media::PIXEL_FORMAT_I420, input_size_, codec_, |
| 570 bits_per_second_, this)) { |
| 571 NotifyError(media::VideoEncodeAccelerator::kPlatformFailureError); |
| 572 } |
| 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 = CodecIdToVEAProfile(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 { |
| 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 |