| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "media/gpu/vt_video_encode_accelerator_mac.h" | 5 #include "media/gpu/vt_video_encode_accelerator_mac.h" |
| 6 | 6 |
| 7 #include <memory> | 7 #include <memory> |
| 8 | 8 |
| 9 #include "base/mac/mac_util.h" | 9 #include "base/mac/mac_util.h" |
| 10 #include "base/threading/thread_task_runner_handle.h" | 10 #include "base/threading/thread_task_runner_handle.h" |
| 11 #include "media/base/mac/coremedia_glue.h" | 11 #include "media/base/mac/coremedia_glue.h" |
| 12 #include "media/base/mac/corevideo_glue.h" | 12 #include "media/base/mac/corevideo_glue.h" |
| 13 #include "media/base/mac/video_frame_mac.h" | 13 #include "media/base/mac/video_frame_mac.h" |
| 14 #include "third_party/webrtc/system_wrappers/include/clock.h" |
| 14 | 15 |
| 15 namespace media { | 16 namespace media { |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 | 19 |
| 19 // TODO(emircan): Check if we can find the actual system capabilities via | 20 // TODO(emircan): Check if we can find the actual system capabilities via |
| 20 // creating VTCompressionSessions with varying requirements. | 21 // creating VTCompressionSessions with varying requirements. |
| 21 // See crbug.com/584784. | 22 // See crbug.com/584784. |
| 22 const size_t kBitsPerByte = 8; | 23 const size_t kBitsPerByte = 8; |
| 23 const size_t kDefaultResolutionWidth = 640; | 24 const size_t kDefaultResolutionWidth = 640; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 size_t size) | 57 size_t size) |
| 57 : id(id), shm(std::move(shm)), size(size) {} | 58 : id(id), shm(std::move(shm)), size(size) {} |
| 58 const int32_t id; | 59 const int32_t id; |
| 59 const std::unique_ptr<base::SharedMemory> shm; | 60 const std::unique_ptr<base::SharedMemory> shm; |
| 60 const size_t size; | 61 const size_t size; |
| 61 | 62 |
| 62 private: | 63 private: |
| 63 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); | 64 DISALLOW_IMPLICIT_CONSTRUCTORS(BitstreamBufferRef); |
| 64 }; | 65 }; |
| 65 | 66 |
| 67 // .5 is set as a minimum to prevent overcompensating for large temporary |
| 68 // overshoots. We don't want to degrade video quality too badly. |
| 69 // .95 is set to prevent oscillations. When a lower bitrate is set on the |
| 70 // encoder than previously set, its output seems to have a brief period of |
| 71 // drastically reduced bitrate, so we want to avoid that. In steady state |
| 72 // conditions, 0.95 seems to give us better overall bitrate over long periods |
| 73 // of time. |
| 66 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() | 74 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() |
| 67 : client_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 75 : bitrate_adjuster_(webrtc::Clock::GetRealTimeClock(), .5, .95), |
| 76 client_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 68 encoder_thread_("VTEncoderThread"), | 77 encoder_thread_("VTEncoderThread"), |
| 69 encoder_task_weak_factory_(this) { | 78 encoder_task_weak_factory_(this) { |
| 70 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); | 79 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); |
| 71 } | 80 } |
| 72 | 81 |
| 73 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { | 82 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { |
| 74 DVLOG(3) << __FUNCTION__; | 83 DVLOG(3) << __FUNCTION__; |
| 75 DCHECK(thread_checker_.CalledOnValidThread()); | 84 DCHECK(thread_checker_.CalledOnValidThread()); |
| 76 | 85 |
| 77 Destroy(); | 86 Destroy(); |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) { | 275 media::VideoFrameMetadata::REFERENCE_TIME, &ref_time)) { |
| 267 ref_time = base::TimeTicks::Now(); | 276 ref_time = base::TimeTicks::Now(); |
| 268 } | 277 } |
| 269 auto timestamp_cm = CoreMediaGlue::CMTimeMake( | 278 auto timestamp_cm = CoreMediaGlue::CMTimeMake( |
| 270 frame->timestamp().InMicroseconds(), USEC_PER_SEC); | 279 frame->timestamp().InMicroseconds(), USEC_PER_SEC); |
| 271 // Wrap information we'll need after the frame is encoded in a heap object. | 280 // Wrap information we'll need after the frame is encoded in a heap object. |
| 272 // We'll get the pointer back from the VideoToolbox completion callback. | 281 // We'll get the pointer back from the VideoToolbox completion callback. |
| 273 std::unique_ptr<InProgressFrameEncode> request( | 282 std::unique_ptr<InProgressFrameEncode> request( |
| 274 new InProgressFrameEncode(frame->timestamp(), ref_time)); | 283 new InProgressFrameEncode(frame->timestamp(), ref_time)); |
| 275 | 284 |
| 285 // Update the bitrate if needed. |
| 286 RequestEncodingParametersChangeTask(bitrate_adjuster_.GetAdjustedBitrateBps(), |
| 287 frame_rate_); |
| 288 |
| 276 // We can pass the ownership of |request| to the encode callback if | 289 // We can pass the ownership of |request| to the encode callback if |
| 277 // successful. Otherwise let it fall out of scope. | 290 // successful. Otherwise let it fall out of scope. |
| 278 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( | 291 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( |
| 279 compression_session_, pixel_buffer, timestamp_cm, | 292 compression_session_, pixel_buffer, timestamp_cm, |
| 280 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, | 293 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, |
| 281 reinterpret_cast<void*>(request.get()), nullptr); | 294 reinterpret_cast<void*>(request.get()), nullptr); |
| 282 if (status != noErr) { | 295 if (status != noErr) { |
| 283 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; | 296 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; |
| 284 NotifyError(kPlatformFailureError); | 297 NotifyError(kPlatformFailureError); |
| 285 } else { | 298 } else { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 301 } | 314 } |
| 302 | 315 |
| 303 bitstream_buffer_queue_.push_back(std::move(buffer_ref)); | 316 bitstream_buffer_queue_.push_back(std::move(buffer_ref)); |
| 304 } | 317 } |
| 305 | 318 |
| 306 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 319 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
| 307 uint32_t bitrate, | 320 uint32_t bitrate, |
| 308 uint32_t framerate) { | 321 uint32_t framerate) { |
| 309 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 322 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 310 | 323 |
| 311 frame_rate_ = framerate > 1 ? framerate : 1; | |
| 312 target_bitrate_ = bitrate > 1 ? bitrate : 1; | |
| 313 | |
| 314 if (!compression_session_) { | 324 if (!compression_session_) { |
| 315 NotifyError(kPlatformFailureError); | 325 NotifyError(kPlatformFailureError); |
| 316 return; | 326 return; |
| 317 } | 327 } |
| 318 | 328 |
| 319 media::video_toolbox::SessionPropertySetter session_property_setter( | 329 bool rv; |
| 320 compression_session_, videotoolbox_glue_); | 330 if (framerate != static_cast<uint32_t>(frame_rate_)) { |
| 321 // TODO(emircan): See crbug.com/425352. | 331 frame_rate_ = framerate > 1 ? framerate : 1; |
| 322 bool rv = session_property_setter.Set( | 332 media::video_toolbox::SessionPropertySetter session_property_setter( |
| 323 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), | 333 compression_session_, videotoolbox_glue_); |
| 324 target_bitrate_); | 334 rv = session_property_setter.Set( |
| 325 rv &= session_property_setter.Set( | 335 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), |
| 326 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), | 336 frame_rate_); |
| 327 frame_rate_); | 337 DLOG_IF(ERROR, !rv) |
| 328 rv &= session_property_setter.Set( | 338 << "Couldn't change frame rate parameters of encode session."; |
| 329 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), | 339 } |
| 330 media::video_toolbox::ArrayWithIntegerAndFloat( | 340 |
| 331 target_bitrate_ / kBitsPerByte, 1.0f)); | 341 if (bitrate != static_cast<uint32_t>(adjusted_bitrate_)) { |
| 332 DLOG_IF(ERROR, !rv) << "Couldn't change session encoding parameters."; | 342 target_bitrate_ = bitrate > 1 ? bitrate : 1; |
| 343 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_); |
| 344 adjusted_bitrate_ = bitrate_adjuster_.GetAdjustedBitrateBps(); |
| 345 media::video_toolbox::SessionPropertySetter session_property_setter( |
| 346 compression_session_, videotoolbox_glue_); |
| 347 rv = session_property_setter.Set( |
| 348 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), |
| 349 adjusted_bitrate_); |
| 350 rv &= session_property_setter.Set( |
| 351 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), |
| 352 media::video_toolbox::ArrayWithIntegerAndFloat( |
| 353 adjusted_bitrate_ / kBitsPerByte, 1.0f)); |
| 354 DLOG_IF(ERROR, !rv) |
| 355 << "Couldn't change bitrate parameters of encode session."; |
| 356 } |
| 333 } | 357 } |
| 334 | 358 |
| 335 void VTVideoEncodeAccelerator::DestroyTask() { | 359 void VTVideoEncodeAccelerator::DestroyTask() { |
| 336 DCHECK(thread_checker_.CalledOnValidThread() || | 360 DCHECK(thread_checker_.CalledOnValidThread() || |
| 337 (encoder_thread_.IsRunning() && | 361 (encoder_thread_.IsRunning() && |
| 338 encoder_thread_task_runner_->BelongsToCurrentThread())); | 362 encoder_thread_task_runner_->BelongsToCurrentThread())); |
| 339 | 363 |
| 340 // Cancel all encoder thread callbacks. | 364 // Cancel all encoder thread callbacks. |
| 341 encoder_task_weak_factory_.InvalidateWeakPtrs(); | 365 encoder_task_weak_factory_.InvalidateWeakPtrs(); |
| 342 | 366 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 sample_attachments, CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); | 452 sample_attachments, CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); |
| 429 | 453 |
| 430 size_t used_buffer_size = 0; | 454 size_t used_buffer_size = 0; |
| 431 const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer( | 455 const bool copy_rv = media::video_toolbox::CopySampleBufferToAnnexBBuffer( |
| 432 encode_output->sample_buffer.get(), keyframe, buffer_ref->size, | 456 encode_output->sample_buffer.get(), keyframe, buffer_ref->size, |
| 433 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); | 457 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); |
| 434 if (!copy_rv) { | 458 if (!copy_rv) { |
| 435 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; | 459 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; |
| 436 used_buffer_size = 0; | 460 used_buffer_size = 0; |
| 437 } | 461 } |
| 462 bitrate_adjuster_.Update(used_buffer_size); |
| 438 | 463 |
| 439 client_task_runner_->PostTask( | 464 client_task_runner_->PostTask( |
| 440 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, | 465 FROM_HERE, base::Bind(&Client::BitstreamBufferReady, client_, |
| 441 buffer_ref->id, used_buffer_size, keyframe)); | 466 buffer_ref->id, used_buffer_size, keyframe)); |
| 442 } | 467 } |
| 443 | 468 |
| 444 bool VTVideoEncodeAccelerator::ResetCompressionSession() { | 469 bool VTVideoEncodeAccelerator::ResetCompressionSession() { |
| 445 DCHECK(thread_checker_.CalledOnValidThread()); | 470 DCHECK(thread_checker_.CalledOnValidThread()); |
| 446 | 471 |
| 447 DestroyCompressionSession(); | 472 DestroyCompressionSession(); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 (encoder_thread_.IsRunning() && | 572 (encoder_thread_.IsRunning() && |
| 548 encoder_thread_task_runner_->BelongsToCurrentThread())); | 573 encoder_thread_task_runner_->BelongsToCurrentThread())); |
| 549 | 574 |
| 550 if (compression_session_) { | 575 if (compression_session_) { |
| 551 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); | 576 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); |
| 552 compression_session_.reset(); | 577 compression_session_.reset(); |
| 553 } | 578 } |
| 554 } | 579 } |
| 555 | 580 |
| 556 } // namespace media | 581 } // namespace media |
| OLD | NEW |