| 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..e1f51541b931db3a0e27e82f4a77546a3b88dfca
|
| --- /dev/null
|
| +++ b/media/cast/sender/size_adaptable_video_encoder_base.cc
|
| @@ -0,0 +1,165 @@
|
| +// 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();
|
| + 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(
|
| + 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();
|
| + // Check again, since EmitFrames() is a synchronous operation with some
|
| + // encoders.
|
| + if (frames_in_encoder_ > 0)
|
| + 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
|
|
|