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