Chromium Code Reviews| Index: media/cast/sender/size_adaptable_video_encoder_base.cc |
| diff --git a/media/cast/sender/size_adaptable_video_encoder_base.cc b/media/cast/sender/size_adaptable_video_encoder_base.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..a9a46b8283f431f0724fa7efcd0543d43dc76beb |
| --- /dev/null |
| +++ b/media/cast/sender/size_adaptable_video_encoder_base.cc |
| @@ -0,0 +1,162 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "media/cast/sender/size_adaptable_video_encoder_base.h" |
| + |
| +#include "base/bind.h" |
| +#include "base/location.h" |
| +#include "media/base/video_frame.h" |
| + |
| +namespace media { |
| +namespace cast { |
| + |
| +SizeAdaptableVideoEncoderBase::SizeAdaptableVideoEncoderBase( |
| + const scoped_refptr<CastEnvironment>& cast_environment, |
| + const VideoSenderConfig& video_config, |
| + const StatusChangeCallback& status_change_cb) |
| + : cast_environment_(cast_environment), |
| + video_config_(video_config), |
| + status_change_cb_(status_change_cb), |
| + frames_in_encoder_(0), |
| + last_frame_id_(kStartFrameId), |
| + weak_factory_(this) { |
| + cast_environment_->PostTask( |
| + CastEnvironment::MAIN, |
| + FROM_HERE, |
| + base::Bind(status_change_cb_, STATUS_INITIALIZED)); |
| +} |
| + |
| +SizeAdaptableVideoEncoderBase::~SizeAdaptableVideoEncoderBase() { |
| + weak_factory_.InvalidateWeakPtrs(); |
|
hubbe
2015/02/11 00:47:54
This is kind of weird.
Why invalidate weak pointer
miu
2015/02/11 02:14:23
Done. Consolidated into DestroyCurrentEncoder(),
|
| + DestroyCurrentEncoder(); |
| +} |
| + |
| +bool SizeAdaptableVideoEncoderBase::EncodeVideoFrame( |
| + const scoped_refptr<media::VideoFrame>& video_frame, |
| + const base::TimeTicks& reference_time, |
| + const FrameEncodedCallback& frame_encoded_callback) { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + |
| + const gfx::Size frame_size = video_frame->visible_rect().size(); |
| + if (frame_size.IsEmpty()) { |
| + DVLOG(1) << "Rejecting empty video frame."; |
| + return false; |
| + } |
| + if (frame_size != current_encoder_frame_size_ || !current_encoder_) { |
| + VLOG(1) << "Dropping frame (of size " << frame_size.ToString() |
| + << ") until a replacement encoder is spun-up. Current encoder " |
| + "handles frames of size " |
| + << current_encoder_frame_size_.ToString() << '.'; |
| + MaybeSpawnReplacementEncoder(frame_size); |
| + return false; |
| + } |
| + |
| + const bool is_frame_accepted = current_encoder_->EncodeVideoFrame( |
| + video_frame, |
| + reference_time, |
| + base::Bind(&SizeAdaptableVideoEncoderBase::OnEncodedVideoFrame, |
| + weak_factory_.GetWeakPtr(), |
| + frame_encoded_callback)); |
| + if (is_frame_accepted) |
| + ++frames_in_encoder_; |
| + return is_frame_accepted; |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::SetBitRate(int new_bit_rate) { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + video_config_.start_bitrate = new_bit_rate; |
| + if (current_encoder_) |
| + current_encoder_->SetBitRate(new_bit_rate); |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::GenerateKeyFrame() { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + if (current_encoder_) |
| + current_encoder_->GenerateKeyFrame(); |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::LatestFrameIdToReference(uint32 frame_id) { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + if (current_encoder_) |
| + current_encoder_->LatestFrameIdToReference(frame_id); |
| +} |
| + |
| +scoped_ptr<VideoFrameFactory> |
| + SizeAdaptableVideoEncoderBase::CreateVideoFrameFactory() { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + return nullptr; |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::EmitFrames() { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + if (current_encoder_) |
| + current_encoder_->EmitFrames(); |
| +} |
| + |
| +StatusChangeCallback |
| + SizeAdaptableVideoEncoderBase::CreateEncoderStatusChangeCallback() { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + return base::Bind(&SizeAdaptableVideoEncoderBase::OnEncoderStatusChange, |
| + weak_factory_.GetWeakPtr()); |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::OnEncoderReplaced( |
| + VideoEncoder* replacement_encoder) {} |
| + |
| +void SizeAdaptableVideoEncoderBase::DestroyCurrentEncoder() { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + current_encoder_.reset(); |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::MaybeSpawnReplacementEncoder( |
|
hubbe
2015/02/11 00:47:54
I don't like "Maybe"
I think "Try" or "" would be
miu
2015/02/11 02:14:23
Done.
|
| + const gfx::Size& size_needed) { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + |
| + // If prior frames are still encoding in the current encoder, let them finish |
| + // first. |
| + if (frames_in_encoder_ > 0) { |
| + current_encoder_->EmitFrames(); |
| + return; |
| + } |
| + |
| + if (next_encoder_.get()) |
| + return; // Already spawned. |
| + |
| + // Prevent future callbacks from |current_encoder_| and destroy it. |
| + weak_factory_.InvalidateWeakPtrs(); |
| + DestroyCurrentEncoder(); |
| + |
| + OnEncoderStatusChange(STATUS_CODEC_REINIT_PENDING); |
| + next_encoder_frame_size_ = size_needed; |
| + VLOG(1) << "Creating replacement video encoder (for frame size change from " |
| + << current_encoder_frame_size_.ToString() << " to " |
| + << next_encoder_frame_size_.ToString() << ")."; |
| + next_encoder_ = CreateReplacementEncoder().Pass(); |
| + DCHECK(next_encoder_.get()); |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::OnEncoderStatusChange( |
| + OperationalStatus status) { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + if (next_encoder_.get() && status == STATUS_INITIALIZED) { |
| + // Begin using the replacement encoder. |
| + current_encoder_ = next_encoder_.Pass(); |
| + current_encoder_frame_size_ = next_encoder_frame_size_; |
| + OnEncoderReplaced(current_encoder_.get()); |
| + } |
| + status_change_cb_.Run(status); |
| +} |
| + |
| +void SizeAdaptableVideoEncoderBase::OnEncodedVideoFrame( |
| + const FrameEncodedCallback& frame_encoded_callback, |
| + scoped_ptr<EncodedFrame> encoded_frame) { |
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN)); |
| + --frames_in_encoder_; |
| + DCHECK_GE(frames_in_encoder_, 0); |
| + last_frame_id_ = encoded_frame->frame_id; |
| + frame_encoded_callback.Run(encoded_frame.Pass()); |
| +} |
| + |
| +} // namespace cast |
| +} // namespace media |