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 |