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