Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 * | 9 * |
| 10 */ | 10 */ |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 458 kVTCompressionPropertyKey_AllowFrameReordering, | 458 kVTCompressionPropertyKey_AllowFrameReordering, |
| 459 false); | 459 false); |
| 460 SetEncoderBitrateBps(target_bitrate_bps_); | 460 SetEncoderBitrateBps(target_bitrate_bps_); |
| 461 // TODO(tkchin): Look at entropy mode and colorspace matrices. | 461 // TODO(tkchin): Look at entropy mode and colorspace matrices. |
| 462 // TODO(tkchin): Investigate to see if there's any way to make this work. | 462 // TODO(tkchin): Investigate to see if there's any way to make this work. |
| 463 // May need it to interop with Android. Currently this call just fails. | 463 // May need it to interop with Android. Currently this call just fails. |
| 464 // On inspecting encoder output on iOS8, this value is set to 6. | 464 // On inspecting encoder output on iOS8, this value is set to 6. |
| 465 // internal::SetVTSessionProperty(compression_session_, | 465 // internal::SetVTSessionProperty(compression_session_, |
| 466 // kVTCompressionPropertyKey_MaxFrameDelayCount, | 466 // kVTCompressionPropertyKey_MaxFrameDelayCount, |
| 467 // 1); | 467 // 1); |
| 468 // TODO(tkchin): See if enforcing keyframe frequency is beneficial in any | 468 |
| 469 // way. | 469 // Set a relatively large value for keyframe emission (7200 frames or |
| 470 // internal::SetVTSessionProperty( | 470 // 4 minutes). |
| 471 // compression_session_, | 471 internal::SetVTSessionProperty( |
| 472 // kVTCompressionPropertyKey_MaxKeyFrameInterval, 240); | 472 compression_session_, |
| 473 // internal::SetVTSessionProperty( | 473 kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200); |
|
mflodman
2016/06/02 05:09:35
Good to have the same on both intervals, in case o
| |
| 474 // compression_session_, | 474 internal::SetVTSessionProperty( |
| 475 // kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); | 475 compression_session_, |
| 476 kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); | |
| 476 } | 477 } |
| 477 | 478 |
| 478 void H264VideoToolboxEncoder::DestroyCompressionSession() { | 479 void H264VideoToolboxEncoder::DestroyCompressionSession() { |
| 479 if (compression_session_) { | 480 if (compression_session_) { |
| 480 VTCompressionSessionInvalidate(compression_session_); | 481 VTCompressionSessionInvalidate(compression_session_); |
| 481 CFRelease(compression_session_); | 482 CFRelease(compression_session_); |
| 482 compression_session_ = nullptr; | 483 compression_session_ = nullptr; |
| 483 } | 484 } |
| 484 } | 485 } |
| 485 | 486 |
| 486 const char* H264VideoToolboxEncoder::ImplementationName() const { | 487 const char* H264VideoToolboxEncoder::ImplementationName() const { |
| 487 return "VideoToolbox"; | 488 return "VideoToolbox"; |
| 488 } | 489 } |
| 489 | 490 |
| 490 void H264VideoToolboxEncoder::SetBitrateBps(uint32_t bitrate_bps) { | 491 void H264VideoToolboxEncoder::SetBitrateBps(uint32_t bitrate_bps) { |
| 491 if (encoder_bitrate_bps_ != bitrate_bps) { | 492 if (encoder_bitrate_bps_ != bitrate_bps) { |
| 492 SetEncoderBitrateBps(bitrate_bps); | 493 SetEncoderBitrateBps(bitrate_bps); |
| 493 } | 494 } |
| 494 } | 495 } |
| 495 | 496 |
| 496 void H264VideoToolboxEncoder::SetEncoderBitrateBps(uint32_t bitrate_bps) { | 497 void H264VideoToolboxEncoder::SetEncoderBitrateBps(uint32_t bitrate_bps) { |
| 497 if (compression_session_) { | 498 if (compression_session_) { |
| 498 internal::SetVTSessionProperty(compression_session_, | 499 internal::SetVTSessionProperty(compression_session_, |
| 499 kVTCompressionPropertyKey_AverageBitRate, | 500 kVTCompressionPropertyKey_AverageBitRate, |
| 500 bitrate_bps); | 501 bitrate_bps); |
| 502 | |
| 503 // TODO(tkchin): Add a helper method to set array value. | |
| 504 int64_t bytes_per_second_value = bitrate_bps / 8; | |
| 505 CFNumberRef bytes_per_second = | |
| 506 CFNumberCreate(kCFAllocatorDefault, | |
| 507 kCFNumberSInt64Type, | |
| 508 &bytes_per_second_value); | |
| 509 int64_t one_second_value = 1; | |
| 510 CFNumberRef one_second = | |
| 511 CFNumberCreate(kCFAllocatorDefault, | |
| 512 kCFNumberSInt64Type, | |
| 513 &one_second_value); | |
| 514 const void* nums[2] = { bytes_per_second, one_second }; | |
| 515 CFArrayRef data_rate_limits = | |
| 516 CFArrayCreate(nullptr, nums, 2, &kCFTypeArrayCallBacks); | |
| 517 OSStatus status = | |
| 518 VTSessionSetProperty(compression_session_, | |
| 519 kVTCompressionPropertyKey_DataRateLimits, | |
|
mflodman
2016/06/02 05:09:35
I didn't see any good documentation around this, b
| |
| 520 data_rate_limits); | |
| 521 if (bytes_per_second) { | |
| 522 CFRelease(bytes_per_second); | |
| 523 } | |
| 524 if (one_second) { | |
| 525 CFRelease(one_second); | |
| 526 } | |
| 527 if (data_rate_limits) { | |
| 528 CFRelease(data_rate_limits); | |
| 529 } | |
| 530 if (status != noErr) { | |
| 531 LOG(LS_ERROR) << "Failed to set data rate limit"; | |
| 532 } | |
| 533 | |
| 501 encoder_bitrate_bps_ = bitrate_bps; | 534 encoder_bitrate_bps_ = bitrate_bps; |
| 502 } | 535 } |
| 503 } | 536 } |
| 504 | 537 |
| 505 void H264VideoToolboxEncoder::OnEncodedFrame( | 538 void H264VideoToolboxEncoder::OnEncodedFrame( |
| 506 OSStatus status, | 539 OSStatus status, |
| 507 VTEncodeInfoFlags info_flags, | 540 VTEncodeInfoFlags info_flags, |
| 508 CMSampleBufferRef sample_buffer, | 541 CMSampleBufferRef sample_buffer, |
| 509 CodecSpecificInfo codec_specific_info, | 542 CodecSpecificInfo codec_specific_info, |
| 510 int32_t width, | 543 int32_t width, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 526 bool is_keyframe = false; | 559 bool is_keyframe = false; |
| 527 CFArrayRef attachments = | 560 CFArrayRef attachments = |
| 528 CMSampleBufferGetSampleAttachmentsArray(sample_buffer, 0); | 561 CMSampleBufferGetSampleAttachmentsArray(sample_buffer, 0); |
| 529 if (attachments != nullptr && CFArrayGetCount(attachments)) { | 562 if (attachments != nullptr && CFArrayGetCount(attachments)) { |
| 530 CFDictionaryRef attachment = | 563 CFDictionaryRef attachment = |
| 531 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, 0)); | 564 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(attachments, 0)); |
| 532 is_keyframe = | 565 is_keyframe = |
| 533 !CFDictionaryContainsKey(attachment, kCMSampleAttachmentKey_NotSync); | 566 !CFDictionaryContainsKey(attachment, kCMSampleAttachmentKey_NotSync); |
| 534 } | 567 } |
| 535 | 568 |
| 569 if (is_keyframe) { | |
| 570 LOG(LS_INFO) << "Generated keyframe"; | |
| 571 } | |
| 572 | |
| 536 // Convert the sample buffer into a buffer suitable for RTP packetization. | 573 // Convert the sample buffer into a buffer suitable for RTP packetization. |
| 537 // TODO(tkchin): Allocate buffers through a pool. | 574 // TODO(tkchin): Allocate buffers through a pool. |
| 538 std::unique_ptr<rtc::Buffer> buffer(new rtc::Buffer()); | 575 std::unique_ptr<rtc::Buffer> buffer(new rtc::Buffer()); |
| 539 std::unique_ptr<webrtc::RTPFragmentationHeader> header; | 576 std::unique_ptr<webrtc::RTPFragmentationHeader> header; |
| 540 { | 577 { |
| 541 webrtc::RTPFragmentationHeader* header_raw; | 578 webrtc::RTPFragmentationHeader* header_raw; |
| 542 bool result = H264CMSampleBufferToAnnexBBuffer(sample_buffer, is_keyframe, | 579 bool result = H264CMSampleBufferToAnnexBBuffer(sample_buffer, is_keyframe, |
| 543 buffer.get(), &header_raw); | 580 buffer.get(), &header_raw); |
| 544 header.reset(header_raw); | 581 header.reset(header_raw); |
| 545 if (!result) { | 582 if (!result) { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 567 if (result != 0) { | 604 if (result != 0) { |
| 568 LOG(LS_ERROR) << "Encode callback failed: " << result; | 605 LOG(LS_ERROR) << "Encode callback failed: " << result; |
| 569 return; | 606 return; |
| 570 } | 607 } |
| 571 bitrate_adjuster_.Update(frame._size); | 608 bitrate_adjuster_.Update(frame._size); |
| 572 } | 609 } |
| 573 | 610 |
| 574 } // namespace webrtc | 611 } // namespace webrtc |
| 575 | 612 |
| 576 #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) | 613 #endif // defined(WEBRTC_VIDEO_TOOLBOX_SUPPORTED) |
| OLD | NEW |