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/coremedia_glue.h" | |
11 #include "media/base/mac/corevideo_glue.h" | |
12 #include "media/base/mac/video_frame_mac.h" | 10 #include "media/base/mac/video_frame_mac.h" |
13 #include "third_party/webrtc/system_wrappers/include/clock.h" | 11 #include "third_party/webrtc/system_wrappers/include/clock.h" |
14 | 12 |
15 namespace media { | 13 namespace media { |
16 | 14 |
17 namespace { | 15 namespace { |
18 | 16 |
19 // TODO(emircan): Check if we can find the actual system capabilities via | 17 // TODO(emircan): Check if we can find the actual system capabilities via |
20 // creating VTCompressionSessions with varying requirements. | 18 // creating VTCompressionSessions with varying requirements. |
21 // See crbug.com/584784. | 19 // See crbug.com/584784. |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
92 DCHECK(!encoder_thread_.IsRunning()); | 90 DCHECK(!encoder_thread_.IsRunning()); |
93 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); | 91 DCHECK(!encoder_task_weak_factory_.HasWeakPtrs()); |
94 } | 92 } |
95 | 93 |
96 VideoEncodeAccelerator::SupportedProfiles | 94 VideoEncodeAccelerator::SupportedProfiles |
97 VTVideoEncodeAccelerator::GetSupportedProfiles() { | 95 VTVideoEncodeAccelerator::GetSupportedProfiles() { |
98 DVLOG(3) << __FUNCTION__; | 96 DVLOG(3) << __FUNCTION__; |
99 DCHECK(thread_checker_.CalledOnValidThread()); | 97 DCHECK(thread_checker_.CalledOnValidThread()); |
100 | 98 |
101 SupportedProfiles profiles; | 99 SupportedProfiles profiles; |
102 // Check if HW encoder is supported initially. | |
103 videotoolbox_glue_ = VideoToolboxGlue::Get(); | |
104 if (!videotoolbox_glue_) { | |
105 DLOG(ERROR) << "Failed creating VideoToolbox glue."; | |
106 return profiles; | |
107 } | |
108 const bool rv = CreateCompressionSession( | 100 const bool rv = CreateCompressionSession( |
109 video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0), | 101 video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0), |
110 gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight), true); | 102 gfx::Size(kDefaultResolutionWidth, kDefaultResolutionHeight), true); |
111 DestroyCompressionSession(); | 103 DestroyCompressionSession(); |
112 if (!rv) { | 104 if (!rv) { |
113 VLOG(1) | 105 VLOG(1) |
114 << "Hardware encode acceleration is not available on this platform."; | 106 << "Hardware encode acceleration is not available on this platform."; |
115 return profiles; | 107 return profiles; |
116 } | 108 } |
117 | 109 |
(...skipping 22 matching lines...) Expand all Loading... |
140 if (PIXEL_FORMAT_I420 != format) { | 132 if (PIXEL_FORMAT_I420 != format) { |
141 DLOG(ERROR) << "Input format not supported= " | 133 DLOG(ERROR) << "Input format not supported= " |
142 << VideoPixelFormatToString(format); | 134 << VideoPixelFormatToString(format); |
143 return false; | 135 return false; |
144 } | 136 } |
145 if (H264PROFILE_BASELINE != output_profile) { | 137 if (H264PROFILE_BASELINE != output_profile) { |
146 DLOG(ERROR) << "Output profile not supported= " << output_profile; | 138 DLOG(ERROR) << "Output profile not supported= " << output_profile; |
147 return false; | 139 return false; |
148 } | 140 } |
149 | 141 |
150 videotoolbox_glue_ = VideoToolboxGlue::Get(); | |
151 if (!videotoolbox_glue_) { | |
152 DLOG(ERROR) << "Failed creating VideoToolbox glue."; | |
153 return false; | |
154 } | |
155 | |
156 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); | 142 client_ptr_factory_.reset(new base::WeakPtrFactory<Client>(client)); |
157 client_ = client_ptr_factory_->GetWeakPtr(); | 143 client_ = client_ptr_factory_->GetWeakPtr(); |
158 input_visible_size_ = input_visible_size; | 144 input_visible_size_ = input_visible_size; |
159 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; | 145 frame_rate_ = kMaxFrameRateNumerator / kMaxFrameRateDenominator; |
160 initial_bitrate_ = initial_bitrate; | 146 initial_bitrate_ = initial_bitrate; |
161 bitstream_buffer_size_ = input_visible_size.GetArea(); | 147 bitstream_buffer_size_ = input_visible_size.GetArea(); |
162 | 148 |
163 if (!encoder_thread_.Start()) { | 149 if (!encoder_thread_.Start()) { |
164 DLOG(ERROR) << "Failed spawning encoder thread."; | 150 DLOG(ERROR) << "Failed spawning encoder thread."; |
165 return false; | 151 return false; |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
253 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 239 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
254 DCHECK(compression_session_); | 240 DCHECK(compression_session_); |
255 DCHECK(frame); | 241 DCHECK(frame); |
256 | 242 |
257 // TODO(emircan): See if we can eliminate a copy here by using | 243 // TODO(emircan): See if we can eliminate a copy here by using |
258 // CVPixelBufferPool for the allocation of incoming VideoFrames. | 244 // CVPixelBufferPool for the allocation of incoming VideoFrames. |
259 base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer = | 245 base::ScopedCFTypeRef<CVPixelBufferRef> pixel_buffer = |
260 WrapVideoFrameInCVPixelBuffer(*frame); | 246 WrapVideoFrameInCVPixelBuffer(*frame); |
261 base::ScopedCFTypeRef<CFDictionaryRef> frame_props = | 247 base::ScopedCFTypeRef<CFDictionaryRef> frame_props = |
262 video_toolbox::DictionaryWithKeyValue( | 248 video_toolbox::DictionaryWithKeyValue( |
263 videotoolbox_glue_->kVTEncodeFrameOptionKey_ForceKeyFrame(), | 249 kVTEncodeFrameOptionKey_ForceKeyFrame, |
264 force_keyframe ? kCFBooleanTrue : kCFBooleanFalse); | 250 force_keyframe ? kCFBooleanTrue : kCFBooleanFalse); |
265 | 251 |
266 base::TimeTicks ref_time; | 252 base::TimeTicks ref_time; |
267 if (!frame->metadata()->GetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, | 253 if (!frame->metadata()->GetTimeTicks(VideoFrameMetadata::REFERENCE_TIME, |
268 &ref_time)) { | 254 &ref_time)) { |
269 ref_time = base::TimeTicks::Now(); | 255 ref_time = base::TimeTicks::Now(); |
270 } | 256 } |
271 auto timestamp_cm = CoreMediaGlue::CMTimeMake( | 257 auto timestamp_cm = |
272 frame->timestamp().InMicroseconds(), USEC_PER_SEC); | 258 CMTimeMake(frame->timestamp().InMicroseconds(), USEC_PER_SEC); |
273 // Wrap information we'll need after the frame is encoded in a heap object. | 259 // Wrap information we'll need after the frame is encoded in a heap object. |
274 // We'll get the pointer back from the VideoToolbox completion callback. | 260 // We'll get the pointer back from the VideoToolbox completion callback. |
275 std::unique_ptr<InProgressFrameEncode> request( | 261 std::unique_ptr<InProgressFrameEncode> request( |
276 new InProgressFrameEncode(frame->timestamp(), ref_time)); | 262 new InProgressFrameEncode(frame->timestamp(), ref_time)); |
277 | 263 |
278 // Update the bitrate if needed. | 264 // Update the bitrate if needed. |
279 SetAdjustedBitrate(bitrate_adjuster_.GetAdjustedBitrateBps()); | 265 SetAdjustedBitrate(bitrate_adjuster_.GetAdjustedBitrateBps()); |
280 | 266 |
281 // We can pass the ownership of |request| to the encode callback if | 267 // We can pass the ownership of |request| to the encode callback if |
282 // successful. Otherwise let it fall out of scope. | 268 // successful. Otherwise let it fall out of scope. |
283 OSStatus status = videotoolbox_glue_->VTCompressionSessionEncodeFrame( | 269 OSStatus status = VTCompressionSessionEncodeFrame( |
284 compression_session_, pixel_buffer, timestamp_cm, | 270 compression_session_, pixel_buffer, timestamp_cm, CMTime{0, 0, 0, 0}, |
285 CoreMediaGlue::CMTime{0, 0, 0, 0}, frame_props, | 271 frame_props, reinterpret_cast<void*>(request.get()), nullptr); |
286 reinterpret_cast<void*>(request.get()), nullptr); | |
287 if (status != noErr) { | 272 if (status != noErr) { |
288 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; | 273 DLOG(ERROR) << " VTCompressionSessionEncodeFrame failed: " << status; |
289 NotifyError(kPlatformFailureError); | 274 NotifyError(kPlatformFailureError); |
290 } else { | 275 } else { |
291 CHECK(request.release()); | 276 CHECK(request.release()); |
292 } | 277 } |
293 } | 278 } |
294 | 279 |
295 void VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask( | 280 void VTVideoEncodeAccelerator::UseOutputBitstreamBufferTask( |
296 std::unique_ptr<BitstreamBufferRef> buffer_ref) { | 281 std::unique_ptr<BitstreamBufferRef> buffer_ref) { |
(...skipping 16 matching lines...) Expand all Loading... |
313 uint32_t framerate) { | 298 uint32_t framerate) { |
314 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 299 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
315 | 300 |
316 if (!compression_session_) { | 301 if (!compression_session_) { |
317 NotifyError(kPlatformFailureError); | 302 NotifyError(kPlatformFailureError); |
318 return; | 303 return; |
319 } | 304 } |
320 | 305 |
321 if (framerate != static_cast<uint32_t>(frame_rate_)) { | 306 if (framerate != static_cast<uint32_t>(frame_rate_)) { |
322 video_toolbox::SessionPropertySetter session_property_setter( | 307 video_toolbox::SessionPropertySetter session_property_setter( |
323 compression_session_, videotoolbox_glue_); | 308 compression_session_); |
324 session_property_setter.Set( | 309 session_property_setter.Set(kVTCompressionPropertyKey_ExpectedFrameRate, |
325 videotoolbox_glue_->kVTCompressionPropertyKey_ExpectedFrameRate(), | 310 frame_rate_); |
326 frame_rate_); | |
327 } | 311 } |
328 | 312 |
329 if (bitrate != static_cast<uint32_t>(target_bitrate_) && bitrate > 0) { | 313 if (bitrate != static_cast<uint32_t>(target_bitrate_) && bitrate > 0) { |
330 target_bitrate_ = bitrate; | 314 target_bitrate_ = bitrate; |
331 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_); | 315 bitrate_adjuster_.SetTargetBitrateBps(target_bitrate_); |
332 SetAdjustedBitrate(bitrate_adjuster_.GetAdjustedBitrateBps()); | 316 SetAdjustedBitrate(bitrate_adjuster_.GetAdjustedBitrateBps()); |
333 } | 317 } |
334 } | 318 } |
335 | 319 |
336 void VTVideoEncodeAccelerator::SetAdjustedBitrate(int32_t bitrate) { | 320 void VTVideoEncodeAccelerator::SetAdjustedBitrate(int32_t bitrate) { |
337 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 321 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
338 | 322 |
339 if (bitrate == encoder_set_bitrate_) | 323 if (bitrate == encoder_set_bitrate_) |
340 return; | 324 return; |
341 | 325 |
342 encoder_set_bitrate_ = bitrate; | 326 encoder_set_bitrate_ = bitrate; |
343 video_toolbox::SessionPropertySetter session_property_setter( | 327 video_toolbox::SessionPropertySetter session_property_setter( |
344 compression_session_, videotoolbox_glue_); | 328 compression_session_); |
345 bool rv = session_property_setter.Set( | 329 bool rv = session_property_setter.Set( |
346 videotoolbox_glue_->kVTCompressionPropertyKey_AverageBitRate(), | 330 kVTCompressionPropertyKey_AverageBitRate, encoder_set_bitrate_); |
347 encoder_set_bitrate_); | |
348 rv &= session_property_setter.Set( | 331 rv &= session_property_setter.Set( |
349 videotoolbox_glue_->kVTCompressionPropertyKey_DataRateLimits(), | 332 kVTCompressionPropertyKey_DataRateLimits, |
350 video_toolbox::ArrayWithIntegerAndFloat( | 333 video_toolbox::ArrayWithIntegerAndFloat( |
351 encoder_set_bitrate_ / kBitsPerByte, 1.0f)); | 334 encoder_set_bitrate_ / kBitsPerByte, 1.0f)); |
352 DLOG_IF(ERROR, !rv) | 335 DLOG_IF(ERROR, !rv) |
353 << "Couldn't change bitrate parameters of encode session."; | 336 << "Couldn't change bitrate parameters of encode session."; |
354 } | 337 } |
355 | 338 |
356 void VTVideoEncodeAccelerator::DestroyTask() { | 339 void VTVideoEncodeAccelerator::DestroyTask() { |
357 DCHECK(thread_checker_.CalledOnValidThread() || | 340 DCHECK(thread_checker_.CalledOnValidThread() || |
358 (encoder_thread_.IsRunning() && | 341 (encoder_thread_.IsRunning() && |
359 encoder_thread_task_runner_->BelongsToCurrentThread())); | 342 encoder_thread_task_runner_->BelongsToCurrentThread())); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
425 bitstream_buffer_queue_.pop_front(); | 408 bitstream_buffer_queue_.pop_front(); |
426 ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref)); | 409 ReturnBitstreamBuffer(std::move(encode_output), std::move(buffer_ref)); |
427 } | 410 } |
428 | 411 |
429 void VTVideoEncodeAccelerator::ReturnBitstreamBuffer( | 412 void VTVideoEncodeAccelerator::ReturnBitstreamBuffer( |
430 std::unique_ptr<EncodeOutput> encode_output, | 413 std::unique_ptr<EncodeOutput> encode_output, |
431 std::unique_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref) { | 414 std::unique_ptr<VTVideoEncodeAccelerator::BitstreamBufferRef> buffer_ref) { |
432 DVLOG(3) << __FUNCTION__; | 415 DVLOG(3) << __FUNCTION__; |
433 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); | 416 DCHECK(encoder_thread_task_runner_->BelongsToCurrentThread()); |
434 | 417 |
435 if (encode_output->info & VideoToolboxGlue::kVTEncodeInfo_FrameDropped) { | 418 if (encode_output->info & kVTEncodeInfo_FrameDropped) { |
436 DVLOG(2) << " frame dropped"; | 419 DVLOG(2) << " frame dropped"; |
437 client_task_runner_->PostTask( | 420 client_task_runner_->PostTask( |
438 FROM_HERE, | 421 FROM_HERE, |
439 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, 0, | 422 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, 0, |
440 false, encode_output->capture_timestamp)); | 423 false, encode_output->capture_timestamp)); |
441 return; | 424 return; |
442 } | 425 } |
443 | 426 |
444 auto* sample_attachments = | 427 auto* sample_attachments = static_cast<CFDictionaryRef>( |
445 static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex( | 428 CFArrayGetValueAtIndex(CMSampleBufferGetSampleAttachmentsArray( |
446 CoreMediaGlue::CMSampleBufferGetSampleAttachmentsArray( | 429 encode_output->sample_buffer.get(), true), |
447 encode_output->sample_buffer.get(), true), | 430 0)); |
448 0)); | |
449 const bool keyframe = !CFDictionaryContainsKey( | 431 const bool keyframe = !CFDictionaryContainsKey( |
450 sample_attachments, CoreMediaGlue::kCMSampleAttachmentKey_NotSync()); | 432 sample_attachments, kCMSampleAttachmentKey_NotSync); |
451 | 433 |
452 size_t used_buffer_size = 0; | 434 size_t used_buffer_size = 0; |
453 const bool copy_rv = video_toolbox::CopySampleBufferToAnnexBBuffer( | 435 const bool copy_rv = video_toolbox::CopySampleBufferToAnnexBBuffer( |
454 encode_output->sample_buffer.get(), keyframe, buffer_ref->size, | 436 encode_output->sample_buffer.get(), keyframe, buffer_ref->size, |
455 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); | 437 reinterpret_cast<char*>(buffer_ref->shm->memory()), &used_buffer_size); |
456 if (!copy_rv) { | 438 if (!copy_rv) { |
457 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; | 439 DLOG(ERROR) << "Cannot copy output from SampleBuffer to AnnexBBuffer."; |
458 used_buffer_size = 0; | 440 used_buffer_size = 0; |
459 } | 441 } |
460 bitrate_adjuster_.Update(used_buffer_size); | 442 bitrate_adjuster_.Update(used_buffer_size); |
461 | 443 |
462 client_task_runner_->PostTask( | 444 client_task_runner_->PostTask( |
463 FROM_HERE, | 445 FROM_HERE, |
464 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, | 446 base::Bind(&Client::BitstreamBufferReady, client_, buffer_ref->id, |
465 used_buffer_size, keyframe, encode_output->capture_timestamp)); | 447 used_buffer_size, keyframe, encode_output->capture_timestamp)); |
466 } | 448 } |
467 | 449 |
468 bool VTVideoEncodeAccelerator::ResetCompressionSession() { | 450 bool VTVideoEncodeAccelerator::ResetCompressionSession() { |
469 DCHECK(thread_checker_.CalledOnValidThread()); | 451 DCHECK(thread_checker_.CalledOnValidThread()); |
470 | 452 |
471 DestroyCompressionSession(); | 453 DestroyCompressionSession(); |
472 | 454 |
473 CFTypeRef attributes_keys[] = {kCVPixelBufferOpenGLCompatibilityKey, | 455 CFTypeRef attributes_keys[] = {kCVPixelBufferOpenGLCompatibilityKey, |
474 kCVPixelBufferIOSurfacePropertiesKey, | 456 kCVPixelBufferIOSurfacePropertiesKey, |
475 kCVPixelBufferPixelFormatTypeKey}; | 457 kCVPixelBufferPixelFormatTypeKey}; |
476 const int format[] = { | 458 const int format[] = {kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; |
477 CoreVideoGlue::kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange}; | |
478 CFTypeRef attributes_values[] = { | 459 CFTypeRef attributes_values[] = { |
479 kCFBooleanTrue, | 460 kCFBooleanTrue, |
480 video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0).release(), | 461 video_toolbox::DictionaryWithKeysAndValues(nullptr, nullptr, 0).release(), |
481 video_toolbox::ArrayWithIntegers(format, arraysize(format)).release()}; | 462 video_toolbox::ArrayWithIntegers(format, arraysize(format)).release()}; |
482 const base::ScopedCFTypeRef<CFDictionaryRef> attributes = | 463 const base::ScopedCFTypeRef<CFDictionaryRef> attributes = |
483 video_toolbox::DictionaryWithKeysAndValues( | 464 video_toolbox::DictionaryWithKeysAndValues( |
484 attributes_keys, attributes_values, arraysize(attributes_keys)); | 465 attributes_keys, attributes_values, arraysize(attributes_keys)); |
485 for (auto* v : attributes_values) | 466 for (auto* v : attributes_values) |
486 CFRelease(v); | 467 CFRelease(v); |
487 | 468 |
(...skipping 13 matching lines...) Expand all Loading... |
501 bool VTVideoEncodeAccelerator::CreateCompressionSession( | 482 bool VTVideoEncodeAccelerator::CreateCompressionSession( |
502 base::ScopedCFTypeRef<CFDictionaryRef> attributes, | 483 base::ScopedCFTypeRef<CFDictionaryRef> attributes, |
503 const gfx::Size& input_size, | 484 const gfx::Size& input_size, |
504 bool require_hw_encoding) { | 485 bool require_hw_encoding) { |
505 DCHECK(thread_checker_.CalledOnValidThread()); | 486 DCHECK(thread_checker_.CalledOnValidThread()); |
506 | 487 |
507 std::vector<CFTypeRef> encoder_keys; | 488 std::vector<CFTypeRef> encoder_keys; |
508 std::vector<CFTypeRef> encoder_values; | 489 std::vector<CFTypeRef> encoder_values; |
509 if (require_hw_encoding) { | 490 if (require_hw_encoding) { |
510 encoder_keys.push_back( | 491 encoder_keys.push_back( |
511 videotoolbox_glue_ | 492 kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder); |
512 ->kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncode
r()); | |
513 encoder_values.push_back(kCFBooleanTrue); | 493 encoder_values.push_back(kCFBooleanTrue); |
514 } else { | 494 } else { |
515 encoder_keys.push_back( | 495 encoder_keys.push_back( |
516 videotoolbox_glue_ | 496 kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder); |
517 ->kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder
()); | |
518 encoder_values.push_back(kCFBooleanTrue); | 497 encoder_values.push_back(kCFBooleanTrue); |
519 } | 498 } |
520 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec = | 499 base::ScopedCFTypeRef<CFDictionaryRef> encoder_spec = |
521 video_toolbox::DictionaryWithKeysAndValues( | 500 video_toolbox::DictionaryWithKeysAndValues( |
522 encoder_keys.data(), encoder_values.data(), encoder_keys.size()); | 501 encoder_keys.data(), encoder_values.data(), encoder_keys.size()); |
523 | 502 |
524 // Create the compression session. | 503 // Create the compression session. |
525 // Note that the encoder object is given to the compression session as the | 504 // Note that the encoder object is given to the compression session as the |
526 // callback context using a raw pointer. The C API does not allow us to use a | 505 // callback context using a raw pointer. The C API does not allow us to use a |
527 // smart pointer, nor is this encoder ref counted. However, this is still | 506 // smart pointer, nor is this encoder ref counted. However, this is still |
528 // safe, because we 1) we own the compression session and 2) we tear it down | 507 // safe, because we 1) we own the compression session and 2) we tear it down |
529 // safely. When destructing the encoder, the compression session is flushed | 508 // safely. When destructing the encoder, the compression session is flushed |
530 // and invalidated. Internally, VideoToolbox will join all of its threads | 509 // and invalidated. Internally, VideoToolbox will join all of its threads |
531 // before returning to the client. Therefore, when control returns to us, we | 510 // before returning to the client. Therefore, when control returns to us, we |
532 // are guaranteed that the output callback will not execute again. | 511 // are guaranteed that the output callback will not execute again. |
533 OSStatus status = videotoolbox_glue_->VTCompressionSessionCreate( | 512 OSStatus status = VTCompressionSessionCreate( |
534 kCFAllocatorDefault, input_size.width(), input_size.height(), | 513 kCFAllocatorDefault, input_size.width(), input_size.height(), |
535 CoreMediaGlue::kCMVideoCodecType_H264, encoder_spec, attributes, | 514 kCMVideoCodecType_H264, encoder_spec, attributes, |
536 nullptr /* compressedDataAllocator */, | 515 nullptr /* compressedDataAllocator */, |
537 &VTVideoEncodeAccelerator::CompressionCallback, | 516 &VTVideoEncodeAccelerator::CompressionCallback, |
538 reinterpret_cast<void*>(this), compression_session_.InitializeInto()); | 517 reinterpret_cast<void*>(this), compression_session_.InitializeInto()); |
539 if (status != noErr) { | 518 if (status != noErr) { |
540 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; | 519 DLOG(ERROR) << " VTCompressionSessionCreate failed: " << status; |
541 return false; | 520 return false; |
542 } | 521 } |
543 DVLOG(3) << " VTCompressionSession created with HW encode: " | 522 DVLOG(3) << " VTCompressionSession created with HW encode: " |
544 << require_hw_encoding << ", input size=" << input_size.ToString(); | 523 << require_hw_encoding << ", input size=" << input_size.ToString(); |
545 return true; | 524 return true; |
546 } | 525 } |
547 | 526 |
548 bool VTVideoEncodeAccelerator::ConfigureCompressionSession() { | 527 bool VTVideoEncodeAccelerator::ConfigureCompressionSession() { |
549 DCHECK(thread_checker_.CalledOnValidThread()); | 528 DCHECK(thread_checker_.CalledOnValidThread()); |
550 DCHECK(compression_session_); | 529 DCHECK(compression_session_); |
551 | 530 |
552 video_toolbox::SessionPropertySetter session_property_setter( | 531 video_toolbox::SessionPropertySetter session_property_setter( |
553 compression_session_, videotoolbox_glue_); | 532 compression_session_); |
554 bool rv = true; | 533 bool rv = true; |
| 534 rv &= session_property_setter.Set(kVTCompressionPropertyKey_ProfileLevel, |
| 535 kVTProfileLevel_H264_Baseline_AutoLevel); |
| 536 rv &= session_property_setter.Set(kVTCompressionPropertyKey_RealTime, true); |
555 rv &= session_property_setter.Set( | 537 rv &= session_property_setter.Set( |
556 videotoolbox_glue_->kVTCompressionPropertyKey_ProfileLevel(), | 538 kVTCompressionPropertyKey_AllowFrameReordering, false); |
557 videotoolbox_glue_->kVTProfileLevel_H264_Baseline_AutoLevel()); | |
558 rv &= session_property_setter.Set( | |
559 videotoolbox_glue_->kVTCompressionPropertyKey_RealTime(), true); | |
560 rv &= session_property_setter.Set( | |
561 videotoolbox_glue_->kVTCompressionPropertyKey_AllowFrameReordering(), | |
562 false); | |
563 // Limit keyframe output to 4 minutes, see crbug.com/658429. | 539 // Limit keyframe output to 4 minutes, see crbug.com/658429. |
564 rv &= session_property_setter.Set( | 540 rv &= session_property_setter.Set( |
565 videotoolbox_glue_->kVTCompressionPropertyKey_MaxKeyFrameInterval(), | 541 kVTCompressionPropertyKey_MaxKeyFrameInterval, 7200); |
566 7200); | |
567 rv &= session_property_setter.Set( | 542 rv &= session_property_setter.Set( |
568 videotoolbox_glue_ | 543 kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration, 240); |
569 ->kVTCompressionPropertyKey_MaxKeyFrameIntervalDuration(), | |
570 240); | |
571 DLOG_IF(ERROR, !rv) << " Setting session property failed."; | 544 DLOG_IF(ERROR, !rv) << " Setting session property failed."; |
572 return rv; | 545 return rv; |
573 } | 546 } |
574 | 547 |
575 void VTVideoEncodeAccelerator::DestroyCompressionSession() { | 548 void VTVideoEncodeAccelerator::DestroyCompressionSession() { |
576 DCHECK(thread_checker_.CalledOnValidThread() || | 549 DCHECK(thread_checker_.CalledOnValidThread() || |
577 (encoder_thread_.IsRunning() && | 550 (encoder_thread_.IsRunning() && |
578 encoder_thread_task_runner_->BelongsToCurrentThread())); | 551 encoder_thread_task_runner_->BelongsToCurrentThread())); |
579 | 552 |
580 if (compression_session_) { | 553 if (compression_session_) { |
581 videotoolbox_glue_->VTCompressionSessionInvalidate(compression_session_); | 554 VTCompressionSessionInvalidate(compression_session_); |
582 compression_session_.reset(); | 555 compression_session_.reset(); |
583 } | 556 } |
584 } | 557 } |
585 | 558 |
586 } // namespace media | 559 } // namespace media |
OLD | NEW |