| 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" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 }; | 65 }; |
| 66 | 66 |
| 67 // .5 is set as a minimum to prevent overcompensating for large temporary | 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. | 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 | 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 | 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 | 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 | 72 // conditions, 0.95 seems to give us better overall bitrate over long periods |
| 73 // of time. | 73 // of time. |
| 74 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() | 74 VTVideoEncodeAccelerator::VTVideoEncodeAccelerator() |
| 75 : bitrate_adjuster_(webrtc::Clock::GetRealTimeClock(), .5, .95), | 75 : target_bitrate_(0), |
| 76 bitrate_adjuster_(webrtc::Clock::GetRealTimeClock(), .5, .95), |
| 76 client_task_runner_(base::ThreadTaskRunnerHandle::Get()), | 77 client_task_runner_(base::ThreadTaskRunnerHandle::Get()), |
| 77 encoder_thread_("VTEncoderThread"), | 78 encoder_thread_("VTEncoderThread"), |
| 78 encoder_task_weak_factory_(this) { | 79 encoder_task_weak_factory_(this) { |
| 79 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); | 80 encoder_weak_ptr_ = encoder_task_weak_factory_.GetWeakPtr(); |
| 80 } | 81 } |
| 81 | 82 |
| 82 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { | 83 VTVideoEncodeAccelerator::~VTVideoEncodeAccelerator() { |
| 83 DVLOG(3) << __FUNCTION__; | 84 DVLOG(3) << __FUNCTION__; |
| 84 DCHECK(thread_checker_.CalledOnValidThread()); | 85 DCHECK(thread_checker_.CalledOnValidThread()); |
| 85 | 86 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 156 if (!base::mac::IsOSMavericksOrLater()) { | 157 if (!base::mac::IsOSMavericksOrLater()) { |
| 157 DLOG(ERROR) << "VideoToolbox hardware encoder is supported on Mac OS 10.9 " | 158 DLOG(ERROR) << "VideoToolbox hardware encoder is supported on Mac OS 10.9 " |
| 158 "and later."; | 159 "and later."; |
| 159 return false; | 160 return false; |
| 160 } | 161 } |
| 161 | 162 |
| 162 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 163 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
| 163 client_ = client_ptr_factory_->GetWeakPtr(); | 164 client_ = client_ptr_factory_->GetWeakPtr(); |
| 164 input_visible_size_ = input_visible_size; | 165 input_visible_size_ = input_visible_size; |
| 165 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; | 166 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; |
| 166 target_bitrate_ = initial_bitrate; | 167 initial_bitrate_ = initial_bitrate; |
| 167 bitstream_buffer_size_ = input_visible_size.GetArea(); | 168 bitstream_buffer_size_ = input_visible_size.GetArea(); |
| 168 | 169 |
| 169 if (!encoder_thread_.Start()) { | 170 if (!encoder_thread_.Start()) { |
| 170 DLOG(ERROR) << "Failed spawning encoder thread."; | 171 DLOG(ERROR) << "Failed spawning encoder thread."; |
| 171 return false; | 172 return false; |
| 172 } | 173 } |
| 173 encoder_thread_task_runner_ = encoder_thread_.task_runner(); | 174 encoder_thread_task_runner_ = encoder_thread_.task_runner(); |
| 174 | 175 |
| 175 if (!ResetCompressionSession()) { | 176 if (!ResetCompressionSession()) { |
| 176 DLOG(ERROR) << "Failed creating compression session."; | 177 DLOG(ERROR) << "Failed creating compression session."; |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 ref_time = base::TimeTicks::Now(); | 277 ref_time = base::TimeTicks::Now(); |
| 277 } | 278 } |
| 278 auto timestamp_cm = CoreMediaGlue::CMTimeMake( | 279 auto timestamp_cm = CoreMediaGlue::CMTimeMake( |
| 279 frame->timestamp().InMicroseconds(), USEC_PER_SEC); | 280 frame->timestamp().InMicroseconds(), USEC_PER_SEC); |
| 280 // Wrap information we'll need after the frame is encoded in a heap object. | 281 // Wrap information we'll need after the frame is encoded in a heap object. |
| 281 // We'll get the pointer back from the VideoToolbox completion callback. | 282 // We'll get the pointer back from the VideoToolbox completion callback. |
| 282 std::unique_ptr<InProgressFrameEncode> request( | 283 std::unique_ptr<InProgressFrameEncode> request( |
| 283 new InProgressFrameEncode(frame->timestamp(), ref_time)); | 284 new InProgressFrameEncode(frame->timestamp(), ref_time)); |
| 284 | 285 |
| 285 // Update the bitrate if needed. | 286 // Update the bitrate if needed. |
| 286 RequestEncodingParametersChangeTask(bitrate_adjuster_.GetAdjustedBitrateBps(), | 287 SetAdjustedBitrate(bitrate_adjuster_.GetAdjustedBitrateBps()); |
| 287 frame_rate_); | |
| 288 | 288 |
| 289 // 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 |
| 290 // successful. Otherwise let it fall out of scope. | 290 // successful. Otherwise let it fall out of scope. |
| 291 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( | 291 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( |
| 292 compression_session_, pixel_buffer, timestamp_cm, | 292 compression_session_, pixel_buffer, timestamp_cm, |
| 293 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, | 293 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, |
| 294 reinterpret_cast<void*>(request.get()), nullptr); | 294 reinterpret_cast<void*>(request.get()), nullptr); |
| 295 if (status != noErr) { | 295 if (status != noErr) { |
| 296 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; | 296 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; |
| 297 NotifyError(kPlatformFailureError); | 297 NotifyError(kPlatformFailureError); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 319 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( | 319 void VTVideoEncodeAccelerator::RequestEncodingParametersChangeTask( |
| 320 uint32_t bitrate, | 320 uint32_t bitrate, |
| 321 uint32_t framerate) { | 321 uint32_t framerate) { |
| 322 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 322 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 323 | 323 |
| 324 if (!compression_session_) { | 324 if (!compression_session_) { |
| 325 NotifyError(kPlatformFailureError); | 325 NotifyError(kPlatformFailureError); |
| 326 return; | 326 return; |
| 327 } | 327 } |
| 328 | 328 |
| 329 bool rv; | |
| 330 if (framerate != static_cast<uint32_t>(frame_rate_)) { | 329 if (framerate != static_cast<uint32_t>(frame_rate_)) { |
| 331 frame_rate_ = framerate > 1 ? framerate : 1; | |
| 332 media::video_toolbox::SessionPropertySetter session_property_setter( | 330 media::video_toolbox::SessionPropertySetter session_property_setter( |
| 333 compression_session_, videotoolbox_glue_); | 331 compression_session_, videotoolbox_glue_); |
| 334 rv = session_property_setter.Set( | 332 session_property_setter.Set( |
| 335 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), | 333 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), |
| 336 frame_rate_); | 334 frame_rate_); |
| 337 DLOG_IF(ERROR, !rv) | |
| 338 << "Couldn't change frame rate parameters of encode session."; | |
| 339 } | 335 } |
| 340 | 336 |
| 341 if (bitrate != static_cast<uint32_t>(adjusted_bitrate_)) { | 337 if (bitrate != static_cast<uint32_t>(target_bitrate_) && bitrate > 0) { |
| 342 target_bitrate_ = bitrate > 1 ? bitrate : 1; | 338 target_bitrate_ = bitrate; |
| 343 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_); | 339 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_); |
| 344 adjusted_bitrate_ = bitrate_adjuster_.GetAdjustedBitrateBps(); | 340 SetAdjustedBitrate(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 } | 341 } |
| 357 } | 342 } |
| 358 | 343 |
| 344 void VTVideoEncodeAccelerator::SetAdjustedBitrate(int32_t bitrate) { |
| 345 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
| 346 |
| 347 if (bitrate == encoder_set_bitrate_) |
| 348 return; |
| 349 |
| 350 encoder_set_bitrate_ = bitrate; |
| 351 media::video_toolbox::SessionPropertySetter session_property_setter( |
| 352 compression_session_, videotoolbox_glue_); |
| 353 bool rv = session_property_setter.Set( |
| 354 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), |
| 355 encoder_set_bitrate_); |
| 356 rv &= session_property_setter.Set( |
| 357 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), |
| 358 media::video_toolbox::ArrayWithIntegerAndFloat( |
| 359 encoder_set_bitrate_ / kBitsPerByte, 1.0f)); |
| 360 DLOG_IF(ERROR, !rv) |
| 361 << "Couldn't change bitrate parameters of encode session."; |
| 362 } |
| 363 |
| 359 void VTVideoEncodeAccelerator::DestroyTask() { | 364 void VTVideoEncodeAccelerator::DestroyTask() { |
| 360 DCHECK(thread_checker_.CalledOnValidThread() || | 365 DCHECK(thread_checker_.CalledOnValidThread() || |
| 361 (encoder_thread_.IsRunning() && | 366 (encoder_thread_.IsRunning() && |
| 362 encoder_thread_task_runner_->BelongsToCurrentThread())); | 367 encoder_thread_task_runner_->BelongsToCurrentThread())); |
| 363 | 368 |
| 364 // Cancel all encoder thread callbacks. | 369 // Cancel all encoder thread callbacks. |
| 365 encoder_task_weak_factory_.InvalidateWeakPtrs(); | 370 encoder_task_weak_factory_.InvalidateWeakPtrs(); |
| 366 | 371 |
| 367 // This call blocks until all pending frames are flushed out. | 372 // This call blocks until all pending frames are flushed out. |
| 368 DestroyCompressionSession(); | 373 DestroyCompressionSession(); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 490 | 495 |
| 491 bool session_rv = | 496 bool session_rv = |
| 492 CreateCompressionSession(attributes, input_visible_size_, false); | 497 CreateCompressionSession(attributes, input_visible_size_, false); |
| 493 if (!session_rv) { | 498 if (!session_rv) { |
| 494 DestroyCompressionSession(); | 499 DestroyCompressionSession(); |
| 495 return false; | 500 return false; |
| 496 } | 501 } |
| 497 | 502 |
| 498 const bool configure_rv = ConfigureCompressionSession(); | 503 const bool configure_rv = ConfigureCompressionSession(); |
| 499 if (configure_rv) | 504 if (configure_rv) |
| 500 RequestEncodingParametersChange(target_bitrate_, frame_rate_); | 505 RequestEncodingParametersChange(initial_bitrate_, frame_rate_); |
| 501 return configure_rv; | 506 return configure_rv; |
| 502 } | 507 } |
| 503 | 508 |
| 504 bool VTVideoEncodeAccelerator::CreateCompressionSession( | 509 bool VTVideoEncodeAccelerator::CreateCompressionSession( |
| 505 base::ScopedCFTypeRef<CFDictionaryRef> attributes, | 510 base::ScopedCFTypeRef<CFDictionaryRef> attributes, |
| 506 const gfx::Size& input_size, | 511 const gfx::Size& input_size, |
| 507 bool require_hw_encoding) { | 512 bool require_hw_encoding) { |
| 508 DCHECK(thread_checker_.CalledOnValidThread()); | 513 DCHECK(thread_checker_.CalledOnValidThread()); |
| 509 | 514 |
| 510 std::vector<CFTypeRef> encoder_keys; | 515 std::vector<CFTypeRef> encoder_keys; |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 572 (encoder_thread_.IsRunning() && | 577 (encoder_thread_.IsRunning() && |
| 573 encoder_thread_task_runner_->BelongsToCurrentThread())); | 578 encoder_thread_task_runner_->BelongsToCurrentThread())); |
| 574 | 579 |
| 575 if (compression_session_) { | 580 if (compression_session_) { |
| 576 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); | 581 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); |
| 577 compression_session_.reset(); | 582 compression_session_.reset(); |
| 578 } | 583 } |
| 579 } | 584 } |
| 580 | 585 |
| 581 } // namespace media | 586 } // namespace media |
| OLD | NEW |