1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/cast/sender/size_adaptable_video_encoder_base.h"
8 #include "base/location.h"
9 #include "media/base/video_frame.h"
14 SizeAdaptableVideoEncoderBase::SizeAdaptableVideoEncoderBase(
15 const scoped_refptr
<CastEnvironment
>& cast_environment
,
16 const VideoSenderConfig
& video_config
,
17 const StatusChangeCallback
& status_change_cb
)
18 : cast_environment_(cast_environment
),
19 video_config_(video_config
),
20 status_change_cb_(status_change_cb
),
21 frames_in_encoder_(0),
22 last_frame_id_(kStartFrameId
),
24 cast_environment_
->PostTask(
25 CastEnvironment::MAIN
,
27 base::Bind(status_change_cb_
, STATUS_INITIALIZED
));
30 SizeAdaptableVideoEncoderBase::~SizeAdaptableVideoEncoderBase() {
34 bool SizeAdaptableVideoEncoderBase::EncodeVideoFrame(
35 const scoped_refptr
<media::VideoFrame
>& video_frame
,
36 const base::TimeTicks
& reference_time
,
37 const FrameEncodedCallback
& frame_encoded_callback
) {
38 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
40 const gfx::Size frame_size
= video_frame
->visible_rect().size();
41 if (frame_size
.IsEmpty()) {
42 DVLOG(1) << "Rejecting empty video frame.";
45 if (frames_in_encoder_
== kEncoderIsInitializing
) {
46 VLOG(1) << "Dropping frame since encoder initialization is in-progress.";
49 if (frame_size
!= frame_size_
|| !encoder_
) {
50 VLOG(1) << "Dropping this frame, and future frames until a replacement "
51 "encoder is spun-up to handle size " << frame_size
.ToString();
52 TrySpawningReplacementEncoder(frame_size
);
56 const bool is_frame_accepted
= encoder_
->EncodeVideoFrame(
59 base::Bind(&SizeAdaptableVideoEncoderBase::OnEncodedVideoFrame
,
60 weak_factory_
.GetWeakPtr(),
61 frame_encoded_callback
));
62 if (is_frame_accepted
)
64 return is_frame_accepted
;
67 void SizeAdaptableVideoEncoderBase::SetBitRate(int new_bit_rate
) {
68 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
69 video_config_
.start_bitrate
= new_bit_rate
;
71 encoder_
->SetBitRate(new_bit_rate
);
74 void SizeAdaptableVideoEncoderBase::GenerateKeyFrame() {
75 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
77 encoder_
->GenerateKeyFrame();
80 void SizeAdaptableVideoEncoderBase::LatestFrameIdToReference(uint32 frame_id
) {
81 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
83 encoder_
->LatestFrameIdToReference(frame_id
);
86 scoped_ptr
<VideoFrameFactory
>
87 SizeAdaptableVideoEncoderBase::CreateVideoFrameFactory() {
88 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
92 void SizeAdaptableVideoEncoderBase::EmitFrames() {
93 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
95 encoder_
->EmitFrames();
99 SizeAdaptableVideoEncoderBase::CreateEncoderStatusChangeCallback() {
100 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
101 return base::Bind(&SizeAdaptableVideoEncoderBase::OnEncoderStatusChange
,
102 weak_factory_
.GetWeakPtr());
105 void SizeAdaptableVideoEncoderBase::OnEncoderReplaced(
106 VideoEncoder
* replacement_encoder
) {}
108 void SizeAdaptableVideoEncoderBase::DestroyEncoder() {
109 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
110 // The weak pointers are invalidated to prevent future calls back to |this|.
111 // This effectively cancels any of |encoder_|'s posted tasks that have not yet
113 weak_factory_
.InvalidateWeakPtrs();
117 void SizeAdaptableVideoEncoderBase::TrySpawningReplacementEncoder(
118 const gfx::Size
& size_needed
) {
119 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
121 // If prior frames are still encoding in the current encoder, let them finish
123 if (frames_in_encoder_
> 0) {
124 encoder_
->EmitFrames();
125 // Check again, since EmitFrames() is a synchronous operation for some
127 if (frames_in_encoder_
> 0)
131 if (frames_in_encoder_
== kEncoderIsInitializing
)
132 return; // Already spawned.
135 frames_in_encoder_
= kEncoderIsInitializing
;
136 OnEncoderStatusChange(STATUS_CODEC_REINIT_PENDING
);
137 VLOG(1) << "Creating replacement video encoder (for frame size change from "
138 << frame_size_
.ToString() << " to "
139 << size_needed
.ToString() << ").";
140 frame_size_
= size_needed
;
141 encoder_
= CreateEncoder().Pass();
145 void SizeAdaptableVideoEncoderBase::OnEncoderStatusChange(
146 OperationalStatus status
) {
147 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
148 if (frames_in_encoder_
== kEncoderIsInitializing
&&
149 status
== STATUS_INITIALIZED
) {
150 // Begin using the replacement encoder.
151 frames_in_encoder_
= 0;
152 OnEncoderReplaced(encoder_
.get());
154 status_change_cb_
.Run(status
);
157 void SizeAdaptableVideoEncoderBase::OnEncodedVideoFrame(
158 const FrameEncodedCallback
& frame_encoded_callback
,
159 scoped_ptr
<SenderEncodedFrame
> encoded_frame
) {
160 DCHECK(cast_environment_
->CurrentlyOn(CastEnvironment::MAIN
));
161 --frames_in_encoder_
;
162 DCHECK_GE(frames_in_encoder_
, 0);
163 last_frame_id_
= encoded_frame
->frame_id
;
164 frame_encoded_callback
.Run(encoded_frame
.Pass());