OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/cast/sender/h264_vt_encoder.h" | 5 #include "media/cast/sender/h264_vt_encoder.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/big_endian.h" | 10 #include "base/big_endian.h" |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/macros.h" | 15 #include "base/macros.h" |
| 16 #include "base/power_monitor/power_monitor.h" |
16 #include "base/synchronization/lock.h" | 17 #include "base/synchronization/lock.h" |
17 #include "media/base/mac/corevideo_glue.h" | 18 #include "media/base/mac/corevideo_glue.h" |
18 #include "media/base/mac/video_frame_mac.h" | 19 #include "media/base/mac/video_frame_mac.h" |
19 #include "media/cast/sender/video_frame_factory.h" | 20 #include "media/cast/sender/video_frame_factory.h" |
20 | 21 |
21 namespace media { | 22 namespace media { |
22 namespace cast { | 23 namespace cast { |
23 | 24 |
24 namespace { | 25 namespace { |
25 | 26 |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
314 H264VideoToolboxEncoder::H264VideoToolboxEncoder( | 315 H264VideoToolboxEncoder::H264VideoToolboxEncoder( |
315 const scoped_refptr<CastEnvironment>& cast_environment, | 316 const scoped_refptr<CastEnvironment>& cast_environment, |
316 const VideoSenderConfig& video_config, | 317 const VideoSenderConfig& video_config, |
317 const StatusChangeCallback& status_change_cb) | 318 const StatusChangeCallback& status_change_cb) |
318 : cast_environment_(cast_environment), | 319 : cast_environment_(cast_environment), |
319 videotoolbox_glue_(VideoToolboxGlue::Get()), | 320 videotoolbox_glue_(VideoToolboxGlue::Get()), |
320 video_config_(video_config), | 321 video_config_(video_config), |
321 status_change_cb_(status_change_cb), | 322 status_change_cb_(status_change_cb), |
322 last_frame_id_(kStartFrameId), | 323 last_frame_id_(kStartFrameId), |
323 encode_next_frame_as_keyframe_(false), | 324 encode_next_frame_as_keyframe_(false), |
| 325 power_suspended_(false), |
324 weak_factory_(this) { | 326 weak_factory_(this) { |
325 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); | 327 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
326 DCHECK(!status_change_cb_.is_null()); | 328 DCHECK(!status_change_cb_.is_null()); |
327 | 329 |
328 OperationalStatus operational_status = | 330 OperationalStatus operational_status = |
329 H264VideoToolboxEncoder::IsSupported(video_config) | 331 H264VideoToolboxEncoder::IsSupported(video_config) |
330 ? STATUS_INITIALIZED | 332 ? STATUS_INITIALIZED |
331 : STATUS_UNSUPPORTED_CODEC; | 333 : STATUS_UNSUPPORTED_CODEC; |
332 cast_environment_->PostTask( | 334 cast_environment_->PostTask( |
333 CastEnvironment::MAIN, FROM_HERE, | 335 CastEnvironment::MAIN, FROM_HERE, |
334 base::Bind(status_change_cb_, operational_status)); | 336 base::Bind(status_change_cb_, operational_status)); |
335 | 337 |
336 if (operational_status == STATUS_INITIALIZED) { | 338 if (operational_status == STATUS_INITIALIZED) { |
| 339 // Create the shared video frame factory. It persists for the combined |
| 340 // lifetime of the encoder and all video frame factory proxies created by |
| 341 // |CreateVideoFrameFactory| that reference it. |
337 video_frame_factory_ = | 342 video_frame_factory_ = |
338 scoped_refptr<VideoFrameFactoryImpl>(new VideoFrameFactoryImpl( | 343 scoped_refptr<VideoFrameFactoryImpl>(new VideoFrameFactoryImpl( |
339 weak_factory_.GetWeakPtr(), cast_environment_)); | 344 weak_factory_.GetWeakPtr(), cast_environment_)); |
| 345 |
| 346 // Register for power state changes. |
| 347 auto power_monitor = base::PowerMonitor::Get(); |
| 348 if (power_monitor) { |
| 349 power_monitor->AddObserver(this); |
| 350 VLOG(1) << "Registered for power state changes."; |
| 351 } else { |
| 352 DLOG(WARNING) << "No power monitor. Process suspension will invalidate " |
| 353 "the encoder."; |
| 354 } |
340 } | 355 } |
341 } | 356 } |
342 | 357 |
343 H264VideoToolboxEncoder::~H264VideoToolboxEncoder() { | 358 H264VideoToolboxEncoder::~H264VideoToolboxEncoder() { |
344 DestroyCompressionSession(); | 359 DestroyCompressionSession(); |
| 360 |
| 361 // If video_frame_factory_ is not null, the encoder registered for power state |
| 362 // changes in the ctor and it must now unregister. |
| 363 if (video_frame_factory_) { |
| 364 auto power_monitor = base::PowerMonitor::Get(); |
| 365 if (power_monitor) |
| 366 power_monitor->RemoveObserver(this); |
| 367 } |
345 } | 368 } |
346 | 369 |
347 void H264VideoToolboxEncoder::ResetCompressionSession() { | 370 void H264VideoToolboxEncoder::ResetCompressionSession() { |
348 DCHECK(thread_checker_.CalledOnValidThread()); | 371 DCHECK(thread_checker_.CalledOnValidThread()); |
349 | 372 |
| 373 // Ignore reset requests while power suspended. |
| 374 if (power_suspended_) |
| 375 return; |
| 376 |
350 // Notify that we're resetting the encoder. | 377 // Notify that we're resetting the encoder. |
351 cast_environment_->PostTask( | 378 cast_environment_->PostTask( |
352 CastEnvironment::MAIN, FROM_HERE, | 379 CastEnvironment::MAIN, FROM_HERE, |
353 base::Bind(status_change_cb_, STATUS_CODEC_REINIT_PENDING)); | 380 base::Bind(status_change_cb_, STATUS_CODEC_REINIT_PENDING)); |
354 | 381 |
355 // Destroy the current session, if any. | 382 // Destroy the current session, if any. |
356 DestroyCompressionSession(); | 383 DestroyCompressionSession(); |
357 | 384 |
358 // On OS X, allow the hardware encoder. Don't require it, it does not support | 385 // On OS X, allow the hardware encoder. Don't require it, it does not support |
359 // all configurations (some of which are used for testing). | 386 // all configurations (some of which are used for testing). |
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 if (!compression_session_) | 645 if (!compression_session_) |
619 return; | 646 return; |
620 | 647 |
621 OSStatus status = videotoolbox_glue_->VTCompressionSessionCompleteFrames( | 648 OSStatus status = videotoolbox_glue_->VTCompressionSessionCompleteFrames( |
622 compression_session_, CoreMediaGlue::CMTime{0, 0, 0, 0}); | 649 compression_session_, CoreMediaGlue::CMTime{0, 0, 0, 0}); |
623 if (status != noErr) { | 650 if (status != noErr) { |
624 DLOG(ERROR) << " VTCompressionSessionCompleteFrames failed: " << status; | 651 DLOG(ERROR) << " VTCompressionSessionCompleteFrames failed: " << status; |
625 } | 652 } |
626 } | 653 } |
627 | 654 |
| 655 void H264VideoToolboxEncoder::OnSuspend() { |
| 656 VLOG(1) |
| 657 << "OnSuspend: Emitting all frames and destroying compression session."; |
| 658 EmitFrames(); |
| 659 DestroyCompressionSession(); |
| 660 power_suspended_ = true; |
| 661 } |
| 662 |
| 663 void H264VideoToolboxEncoder::OnResume() { |
| 664 power_suspended_ = false; |
| 665 |
| 666 // Reset the compression session only if the frame size is not zero (which |
| 667 // will obviously fail). It is possible for the frame size to be zero if no |
| 668 // frame was submitted for encoding or requested from the video frame factory |
| 669 // before suspension. |
| 670 if (!frame_size_.IsEmpty()) { |
| 671 VLOG(1) << "OnResume: Resetting compression session."; |
| 672 ResetCompressionSession(); |
| 673 } |
| 674 } |
| 675 |
628 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, | 676 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, |
629 int32_t value) { | 677 int32_t value) { |
630 base::ScopedCFTypeRef<CFNumberRef> cfvalue( | 678 base::ScopedCFTypeRef<CFNumberRef> cfvalue( |
631 CFNumberCreate(nullptr, kCFNumberSInt32Type, &value)); | 679 CFNumberCreate(nullptr, kCFNumberSInt32Type, &value)); |
632 return videotoolbox_glue_->VTSessionSetProperty(compression_session_, key, | 680 return videotoolbox_glue_->VTSessionSetProperty(compression_session_, key, |
633 cfvalue) == noErr; | 681 cfvalue) == noErr; |
634 } | 682 } |
635 | 683 |
636 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, bool value) { | 684 bool H264VideoToolboxEncoder::SetSessionProperty(CFStringRef key, bool value) { |
637 CFBooleanRef cfvalue = (value) ? kCFBooleanTrue : kCFBooleanFalse; | 685 CFBooleanRef cfvalue = (value) ? kCFBooleanTrue : kCFBooleanFalse; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 CopySampleBufferToAnnexBBuffer(sbuf, &encoded_frame->data, keyframe); | 755 CopySampleBufferToAnnexBBuffer(sbuf, &encoded_frame->data, keyframe); |
708 | 756 |
709 encoder->cast_environment_->PostTask( | 757 encoder->cast_environment_->PostTask( |
710 CastEnvironment::MAIN, FROM_HERE, | 758 CastEnvironment::MAIN, FROM_HERE, |
711 base::Bind(request->frame_encoded_callback, | 759 base::Bind(request->frame_encoded_callback, |
712 base::Passed(&encoded_frame))); | 760 base::Passed(&encoded_frame))); |
713 } | 761 } |
714 | 762 |
715 } // namespace cast | 763 } // namespace cast |
716 } // namespace media | 764 } // namespace media |
OLD | NEW |