| 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/threading/thread_task_runner_handle.h" | 9 #include "base/threading/thread_task_runner_handle.h" |
| 10 #include "media/base/mac/video_frame_mac.h" | 10 #include "media/base/mac/video_frame_mac.h" |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); | 90 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); |
| 91 } | 91 } |
| 92 | 92 |
| 93 VideoEncodeAccelerator::SupportedProfiles | 93 VideoEncodeAccelerator::SupportedProfiles |
| 94 VTVideoEncodeAccelerator::GetSupportedProfiles() { | 94 VTVideoEncodeAccelerator::GetSupportedProfiles() { |
| 95 DVLOG(3) << __func__; | 95 DVLOG(3) << __func__; |
| 96 DCHECK(thread_checker_.CalledOnValidThread()); | 96 DCHECK(thread_checker_.CalledOnValidThread()); |
| 97 | 97 |
| 98 SupportedProfiles profiles; | 98 SupportedProfiles profiles; |
| 99 const bool rv = CreateCompressionSession( | 99 const bool rv = CreateCompressionSession( |
| 100 gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight)); | 100 video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0), |
| 101 gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight), true); |
| 101 DestroyCompressionSession(); | 102 DestroyCompressionSession(); |
| 102 if (!rv) { | 103 if (!rv) { |
| 103 VLOG(1) | 104 VLOG(1) |
| 104 << "Hardware encode acceleration is not available on this platform."; | 105 << "Hardware encode acceleration is not available on this platform."; |
| 105 return profiles; | 106 return profiles; |
| 106 } | 107 } |
| 107 | 108 |
| 108 SupportedProfile profile; | 109 SupportedProfile profile; |
| 109 profile.profile = H264PROFILE_BASELINE; | 110 profile.profile = H264PROFILE_BASELINE; |
| 110 profile.max_framerate_numerator = kMaxFrameRateNumerator; | 111 profile.max_framerate_numerator = kMaxFrameRateNumerator; |
| (...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 445 FROM_HERE, | 446 FROM_HERE, |
| 446 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, | 447 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, |
| 447 used_buffer_size, keyframe, encode_output->capture_timestamp)); | 448 used_buffer_size, keyframe, encode_output->capture_timestamp)); |
| 448 } | 449 } |
| 449 | 450 |
| 450 bool VTVideoEncodeAccelerator::ResetCompressionSession() { | 451 bool VTVideoEncodeAccelerator::ResetCompressionSession() { |
| 451 DCHECK(thread_checker_.CalledOnValidThread()); | 452 DCHECK(thread_checker_.CalledOnValidThread()); |
| 452 | 453 |
| 453 DestroyCompressionSession(); | 454 DestroyCompressionSession(); |
| 454 | 455 |
| 455 bool session_rv = CreateCompressionSession(input_visible_size_); | 456 CFTypeRef attributes_keys[] = {kCVPixelBufferOpenGLCompatibilityKey, |
| 457 kCVPixelBufferIOSurfacePropertiesKey, |
| 458 kCVPixelBufferPixelFormatTypeKey}; |
| 459 const int format[] = {kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; |
| 460 CFTypeRef attributes_values[] = { |
| 461 kCFBooleanTrue, |
| 462 video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0).release(), |
| 463 video_toolbox::ArrayWithIntegers(format, arraysize(format)).release()}; |
| 464 const base::ScopedCFTypeRef<CFDictionaryRef> attributes = |
| 465 video_toolbox::DictionaryWithKeysAndValues( |
| 466 attributes_keys, attributes_values, arraysize(attributes_keys)); |
| 467 for (auto* v : attributes_values) |
| 468 CFRelease(v); |
| 469 |
| 470 bool session_rv = |
| 471 CreateCompressionSession(attributes, input_visible_size_, false); |
| 456 if (!session_rv) { | 472 if (!session_rv) { |
| 457 DestroyCompressionSession(); | 473 DestroyCompressionSession(); |
| 458 return false; | 474 return false; |
| 459 } | 475 } |
| 460 | 476 |
| 461 const bool configure_rv = ConfigureCompressionSession(); | 477 const bool configure_rv = ConfigureCompressionSession(); |
| 462 if (configure_rv) | 478 if (configure_rv) |
| 463 RequestEncodingParametersChange(initial_bitrate_, frame_rate_); | 479 RequestEncodingParametersChange(initial_bitrate_, frame_rate_); |
| 464 return configure_rv; | 480 return configure_rv; |
| 465 } | 481 } |
| 466 | 482 |
| 467 bool VTVideoEncodeAccelerator::CreateCompressionSession( | 483 bool VTVideoEncodeAccelerator::CreateCompressionSession( |
| 468 const gfx::Size& input_size) { | 484 base::ScopedCFTypeRef<CFDictionaryRef> attributes, |
| 485 const gfx::Size& input_size, |
| 486 bool require_hw_encoding) { |
| 469 DCHECK(thread_checker_.CalledOnValidThread()); | 487 DCHECK(thread_checker_.CalledOnValidThread()); |
| 470 | 488 |
| 471 std::vector<CFTypeRef> encoder_keys( | 489 std::vector<CFTypeRef> encoder_keys; |
| 472 1, kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder); | 490 std::vector<CFTypeRef> encoder_values; |
| 473 std::vector<CFTypeRef> encoder_values(1, kCFBooleanTrue); | 491 if (require_hw_encoding) { |
| 492 encoder_keys.push_back( |
| 493 kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder); |
| 494 encoder_values.push_back(kCFBooleanTrue); |
| 495 } else { |
| 496 encoder_keys.push_back( |
| 497 kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder); |
| 498 encoder_values.push_back(kCFBooleanTrue); |
| 499 } |
| 474 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec = | 500 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec = |
| 475 video_toolbox::DictionaryWithKeysAndValues( | 501 video_toolbox::DictionaryWithKeysAndValues( |
| 476 encoder_keys.data(), encoder_values.data(), encoder_keys.size()); | 502 encoder_keys.data(), encoder_values.data(), encoder_keys.size()); |
| 477 | 503 |
| 478 // Create the compression session. | 504 // Create the compression session. |
| 479 // Note that the encoder object is given to the compression session as the | 505 // Note that the encoder object is given to the compression session as the |
| 480 // callback context using a raw pointer. The C API does not allow us to use a | 506 // callback context using a raw pointer. The C API does not allow us to use a |
| 481 // smart pointer, nor is this encoder ref counted. However, this is still | 507 // smart pointer, nor is this encoder ref counted. However, this is still |
| 482 // safe, because we 1) we own the compression session and 2) we tear it down | 508 // safe, because we 1) we own the compression session and 2) we tear it down |
| 483 // safely. When destructing the encoder, the compression session is flushed | 509 // safely. When destructing the encoder, the compression session is flushed |
| 484 // and invalidated. Internally, VideoToolbox will join all of its threads | 510 // and invalidated. Internally, VideoToolbox will join all of its threads |
| 485 // before returning to the client. Therefore, when control returns to us, we | 511 // before returning to the client. Therefore, when control returns to us, we |
| 486 // are guaranteed that the output callback will not execute again. | 512 // are guaranteed that the output callback will not execute again. |
| 487 OSStatus status = VTCompressionSessionCreate( | 513 OSStatus status = VTCompressionSessionCreate( |
| 488 kCFAllocatorDefault, input_size.width(), input_size.height(), | 514 kCFAllocatorDefault, input_size.width(), input_size.height(), |
| 489 kCMVideoCodecType_H264, encoder_spec, | 515 kCMVideoCodecType_H264, encoder_spec, attributes, |
| 490 nullptr /* sourceImageBufferAttributes */, | |
| 491 nullptr /* compressedDataAllocator */, | 516 nullptr /* compressedDataAllocator */, |
| 492 &VTVideoEncodeAccelerator::CompressionCallback, | 517 &VTVideoEncodeAccelerator::CompressionCallback, |
| 493 reinterpret_cast<void*>(this), compression_session_.InitializeInto()); | 518 reinterpret_cast<void*>(this), compression_session_.InitializeInto()); |
| 494 if (status != noErr) { | 519 if (status != noErr) { |
| 495 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; | 520 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; |
| 496 return false; | 521 return false; |
| 497 } | 522 } |
| 498 DVLOG(3) << " VTCompressionSession created with input size=" | 523 DVLOG(3) << " VTCompressionSession created with HW encode: " |
| 499 << input_size.ToString(); | 524 << require_hw_encoding << ", input size=" << input_size.ToString(); |
| 500 return true; | 525 return true; |
| 501 } | 526 } |
| 502 | 527 |
| 503 bool VTVideoEncodeAccelerator::ConfigureCompressionSession() { | 528 bool VTVideoEncodeAccelerator::ConfigureCompressionSession() { |
| 504 DCHECK(thread_checker_.CalledOnValidThread()); | 529 DCHECK(thread_checker_.CalledOnValidThread()); |
| 505 DCHECK(compression_session_); | 530 DCHECK(compression_session_); |
| 506 | 531 |
| 507 video_toolbox::SessionPropertySetter session_property_setter( | 532 video_toolbox::SessionPropertySetter session_property_setter( |
| 508 compression_session_); | 533 compression_session_); |
| 509 bool rv = true; | 534 bool rv = true; |
| 510 rv &= session_property_setter.Set(kVTCompressionPropertyKey_ProfileLevel, | 535 rv &= session_property_setter.Set(kVTCompressionPropertyKey_ProfileLevel, |
| 511 kVTProfileLevel_H264_Baseline_AutoLevel); | 536 kVTProfileLevel_H264_Baseline_AutoLevel); |
| 512 rv &= session_property_setter.Set(kVTCompressionPropertyKey_RealTime, true); | 537 rv &= session_property_setter.Set(kVTCompressionPropertyKey_RealTime, true); |
| 513 rv &= session_property_setter.Set( | 538 rv &= session_property_setter.Set( |
| 514 kVTCompressionPropertyKey_AllowFrameReordering, false); | 539 kVTCompressionPropertyKey_AllowFrameReordering, false); |
| 515 // Limit keyframe output to 4 minutes, see crbug.com/658429. | 540 // Limit keyframe output to 4 minutes, see crbug.com/658429. |
| 516 rv &= session_property_setter.Set( | 541 rv &= session_property_setter.Set( |
| 517 kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200); | 542 kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200); |
| 518 rv &= session_property_setter.Set( | 543 rv &= session_property_setter.Set( |
| 519 kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); | 544 kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); |
| 520 rv &= | |
| 521 session_property_setter.Set(kVTCompressionPropertyKey_MaxFrameDelayCount, | |
| 522 static_cast<int>(kNumInputBuffers)); | |
| 523 DLOG_IF(ERROR, !rv) << " Setting session property failed."; | 545 DLOG_IF(ERROR, !rv) << " Setting session property failed."; |
| 524 return rv; | 546 return rv; |
| 525 } | 547 } |
| 526 | 548 |
| 527 void VTVideoEncodeAccelerator::DestroyCompressionSession() { | 549 void VTVideoEncodeAccelerator::DestroyCompressionSession() { |
| 528 DCHECK(thread_checker_.CalledOnValidThread() || | 550 DCHECK(thread_checker_.CalledOnValidThread() || |
| 529 (encoder_thread_.IsRunning() && | 551 (encoder_thread_.IsRunning() && |
| 530 encoder_thread_task_runner_->BelongsToCurrentThread())); | 552 encoder_thread_task_runner_->BelongsToCurrentThread())); |
| 531 | 553 |
| 532 if (compression_session_) { | 554 if (compression_session_) { |
| 533 VTCompressionSessionInvalidate(compression_session_); | 555 VTCompressionSessionInvalidate(compression_session_); |
| 534 compression_session_.reset(); | 556 compression_session_.reset(); |
| 535 } | 557 } |
| 536 } | 558 } |
| 537 | 559 |
| 538 } // namespace media | 560 } // namespace media |
| OLD | NEW |