| 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..96c65a0d505968c669784e13a8f78af897aa716a
|
| --- /dev/null
|
| +++ b/media/cast/sender/size_adaptable_video_encoder_base.cc
|
| @@ -0,0 +1,168 @@
|
| +// 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() {
|
| + DestroyEncoder();
|
| +}
|
| +
|
| +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 (frames_in_encoder_ == kEncoderIsInitializing) {
|
| + VLOG(1) << "Dropping frame since encoder initialization is in-progress.";
|
| + return false;
|
| + }
|
| + if (frame_size != frame_size_ || !encoder_) {
|
| + VLOG(1) << "Dropping this frame, and future frames until a replacement "
|
| + "encoder is spun-up to handle size " << frame_size.ToString();
|
| + TrySpawningReplacementEncoder(frame_size);
|
| + return false;
|
| + }
|
| +
|
| + const bool is_frame_accepted = 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 (encoder_)
|
| + encoder_->SetBitRate(new_bit_rate);
|
| +}
|
| +
|
| +void SizeAdaptableVideoEncoderBase::GenerateKeyFrame() {
|
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| + if (encoder_)
|
| + encoder_->GenerateKeyFrame();
|
| +}
|
| +
|
| +void SizeAdaptableVideoEncoderBase::LatestFrameIdToReference(uint32 frame_id) {
|
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| + if (encoder_)
|
| + 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 (encoder_)
|
| + 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::DestroyEncoder() {
|
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| + // The weak pointers are invalidated to prevent future calls back to |this|.
|
| + // This effectively cancels any of |encoder_|'s posted tasks that have not yet
|
| + // run.
|
| + weak_factory_.InvalidateWeakPtrs();
|
| + encoder_.reset();
|
| +}
|
| +
|
| +void SizeAdaptableVideoEncoderBase::TrySpawningReplacementEncoder(
|
| + 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) {
|
| + encoder_->EmitFrames();
|
| + // Check again, since EmitFrames() is a synchronous operation for some
|
| + // encoders.
|
| + if (frames_in_encoder_ > 0)
|
| + return;
|
| + }
|
| +
|
| + if (frames_in_encoder_ == kEncoderIsInitializing)
|
| + return; // Already spawned.
|
| +
|
| + DestroyEncoder();
|
| + frames_in_encoder_ = kEncoderIsInitializing;
|
| + OnEncoderStatusChange(STATUS_CODEC_REINIT_PENDING);
|
| + VLOG(1) << "Creating replacement video encoder (for frame size change from "
|
| + << frame_size_.ToString() << " to "
|
| + << size_needed.ToString() << ").";
|
| + frame_size_ = size_needed;
|
| + encoder_ = CreateEncoder().Pass();
|
| + DCHECK(encoder_);
|
| +}
|
| +
|
| +void SizeAdaptableVideoEncoderBase::OnEncoderStatusChange(
|
| + OperationalStatus status) {
|
| + DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
|
| + if (frames_in_encoder_ == kEncoderIsInitializing &&
|
| + status == STATUS_INITIALIZED) {
|
| + // Begin using the replacement encoder.
|
| + frames_in_encoder_ = 0;
|
| + OnEncoderReplaced(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
|
|
|