Simplify web_view.js
[chromium-blink-merge.git] / media / cast / sender / video_sender.cc
blob16b7159befe1fd001ceb676d9ba1596a1ca90d99
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
3 // found in the LICENSE file.
5 #include "media/cast/sender/video_sender.h"
7 #include <algorithm>
8 #include <cstring>
10 #include "base/bind.h"
11 #include "base/debug/trace_event.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "media/cast/cast_defines.h"
15 #include "media/cast/net/cast_transport_config.h"
16 #include "media/cast/sender/external_video_encoder.h"
17 #include "media/cast/sender/video_encoder_impl.h"
19 namespace media {
20 namespace cast {
22 namespace {
24 // The following two constants are used to adjust the target
25 // playout delay (when allowed). They were calculated using
26 // a combination of cast_benchmark runs and manual testing.
28 // This is how many round trips we think we need on the network.
29 const int kRoundTripsNeeded = 4;
30 // This is an estimate of all the the constant time needed independent of
31 // network quality (e.g., additional time that accounts for encode and decode
32 // time).
33 const int kConstantTimeMs = 75;
35 } // namespace
37 // Note, we use a fixed bitrate value when external video encoder is used.
38 // Some hardware encoder shows bad behavior if we set the bitrate too
39 // frequently, e.g. quality drop, not abiding by target bitrate, etc.
40 // See details: crbug.com/392086.
41 VideoSender::VideoSender(
42 scoped_refptr<CastEnvironment> cast_environment,
43 const VideoSenderConfig& video_config,
44 const CastInitializationCallback& initialization_cb,
45 const CreateVideoEncodeAcceleratorCallback& create_vea_cb,
46 const CreateVideoEncodeMemoryCallback& create_video_encode_mem_cb,
47 CastTransportSender* const transport_sender,
48 const PlayoutDelayChangeCB& playout_delay_change_cb)
49 : FrameSender(
50 cast_environment,
51 false,
52 transport_sender,
53 base::TimeDelta::FromMilliseconds(video_config.rtcp_interval),
54 kVideoFrequency,
55 video_config.ssrc,
56 video_config.max_frame_rate,
57 video_config.min_playout_delay,
58 video_config.max_playout_delay,
59 video_config.use_external_encoder ?
60 NewFixedCongestionControl(
61 (video_config.min_bitrate + video_config.max_bitrate) / 2) :
62 NewAdaptiveCongestionControl(cast_environment->Clock(),
63 video_config.max_bitrate,
64 video_config.min_bitrate,
65 video_config.max_frame_rate)),
66 frames_in_encoder_(0),
67 last_bitrate_(0),
68 playout_delay_change_cb_(playout_delay_change_cb),
69 weak_factory_(this) {
70 cast_initialization_status_ = STATUS_VIDEO_UNINITIALIZED;
72 if (video_config.use_external_encoder) {
73 video_encoder_.reset(new ExternalVideoEncoder(
74 cast_environment,
75 video_config,
76 base::Bind(&VideoSender::OnEncoderInitialized,
77 weak_factory_.GetWeakPtr(), initialization_cb),
78 create_vea_cb,
79 create_video_encode_mem_cb));
80 } else {
81 // Software encoder is initialized immediately.
82 video_encoder_.reset(new VideoEncoderImpl(cast_environment, video_config));
83 cast_initialization_status_ = STATUS_VIDEO_INITIALIZED;
86 if (cast_initialization_status_ == STATUS_VIDEO_INITIALIZED) {
87 cast_environment->PostTask(
88 CastEnvironment::MAIN,
89 FROM_HERE,
90 base::Bind(initialization_cb, cast_initialization_status_));
93 media::cast::CastTransportRtpConfig transport_config;
94 transport_config.ssrc = video_config.ssrc;
95 transport_config.feedback_ssrc = video_config.incoming_feedback_ssrc;
96 transport_config.rtp_payload_type = video_config.rtp_payload_type;
97 transport_config.aes_key = video_config.aes_key;
98 transport_config.aes_iv_mask = video_config.aes_iv_mask;
100 transport_sender->InitializeVideo(
101 transport_config,
102 base::Bind(&VideoSender::OnReceivedCastFeedback,
103 weak_factory_.GetWeakPtr()),
104 base::Bind(&VideoSender::OnMeasuredRoundTripTime,
105 weak_factory_.GetWeakPtr()));
108 VideoSender::~VideoSender() {
111 void VideoSender::InsertRawVideoFrame(
112 const scoped_refptr<media::VideoFrame>& video_frame,
113 const base::TimeTicks& reference_time) {
114 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
115 if (cast_initialization_status_ != STATUS_VIDEO_INITIALIZED) {
116 NOTREACHED();
117 return;
119 DCHECK(video_encoder_.get()) << "Invalid state";
121 const RtpTimestamp rtp_timestamp =
122 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency);
123 const base::TimeTicks insertion_time = cast_environment_->Clock()->NowTicks();
124 // TODO(miu): Plumb in capture timestamps. For now, make it look like capture
125 // took zero time by setting the BEGIN and END event to the same timestamp.
126 cast_environment_->Logging()->InsertFrameEvent(
127 insertion_time, FRAME_CAPTURE_BEGIN, VIDEO_EVENT, rtp_timestamp,
128 kFrameIdUnknown);
129 cast_environment_->Logging()->InsertFrameEvent(
130 insertion_time, FRAME_CAPTURE_END, VIDEO_EVENT, rtp_timestamp,
131 kFrameIdUnknown);
133 // Used by chrome/browser/extension/api/cast_streaming/performance_test.cc
134 TRACE_EVENT_INSTANT2(
135 "cast_perf_test", "InsertRawVideoFrame",
136 TRACE_EVENT_SCOPE_THREAD,
137 "timestamp", reference_time.ToInternalValue(),
138 "rtp_timestamp", rtp_timestamp);
140 // Drop the frame if either its RTP or reference timestamp is not an increase
141 // over the last frame's. This protects: 1) the duration calculations that
142 // assume timestamps are monotonically non-decreasing, and 2) assumptions made
143 // deeper in the implementation where each frame's RTP timestamp needs to be
144 // unique.
145 if (!last_enqueued_frame_reference_time_.is_null() &&
146 (!IsNewerRtpTimestamp(rtp_timestamp,
147 last_enqueued_frame_rtp_timestamp_) ||
148 reference_time <= last_enqueued_frame_reference_time_)) {
149 VLOG(1) << "Dropping video frame: RTP or reference time did not increase.";
150 return;
153 // Two video frames are needed to compute the exact media duration added by
154 // the next frame. If there are no frames in the encoder, compute a guess
155 // based on the configured |max_frame_rate_|. Any error introduced by this
156 // guess will be eliminated when |duration_in_encoder_| is updated in
157 // OnEncodedVideoFrame().
158 const base::TimeDelta duration_added_by_next_frame = frames_in_encoder_ > 0 ?
159 reference_time - last_enqueued_frame_reference_time_ :
160 base::TimeDelta::FromSecondsD(1.0 / max_frame_rate_);
162 if (ShouldDropNextFrame(duration_added_by_next_frame)) {
163 base::TimeDelta new_target_delay = std::min(
164 current_round_trip_time_ * kRoundTripsNeeded +
165 base::TimeDelta::FromMilliseconds(kConstantTimeMs),
166 max_playout_delay_);
167 if (new_target_delay > target_playout_delay_) {
168 VLOG(1) << "New target delay: " << new_target_delay.InMilliseconds();
169 playout_delay_change_cb_.Run(new_target_delay);
171 return;
174 uint32 bitrate = congestion_control_->GetBitrate(
175 reference_time + target_playout_delay_, target_playout_delay_);
176 if (bitrate != last_bitrate_) {
177 video_encoder_->SetBitRate(bitrate);
178 last_bitrate_ = bitrate;
181 if (video_encoder_->EncodeVideoFrame(
182 video_frame,
183 reference_time,
184 base::Bind(&VideoSender::OnEncodedVideoFrame,
185 weak_factory_.GetWeakPtr(),
186 bitrate))) {
187 frames_in_encoder_++;
188 duration_in_encoder_ += duration_added_by_next_frame;
189 last_enqueued_frame_rtp_timestamp_ = rtp_timestamp;
190 last_enqueued_frame_reference_time_ = reference_time;
191 } else {
192 VLOG(1) << "Encoder rejected a frame. Skipping...";
196 int VideoSender::GetNumberOfFramesInEncoder() const {
197 return frames_in_encoder_;
200 base::TimeDelta VideoSender::GetInFlightMediaDuration() const {
201 if (GetUnacknowledgedFrameCount() > 0) {
202 const uint32 oldest_unacked_frame_id = latest_acked_frame_id_ + 1;
203 return last_enqueued_frame_reference_time_ -
204 GetRecordedReferenceTime(oldest_unacked_frame_id);
205 } else {
206 return duration_in_encoder_;
210 void VideoSender::OnAck(uint32 frame_id) {
211 video_encoder_->LatestFrameIdToReference(frame_id);
214 void VideoSender::OnEncoderInitialized(
215 const CastInitializationCallback& initialization_cb,
216 CastInitializationStatus status) {
217 cast_initialization_status_ = status;
218 initialization_cb.Run(status);
221 void VideoSender::OnEncodedVideoFrame(
222 int encoder_bitrate,
223 scoped_ptr<EncodedFrame> encoded_frame) {
224 DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
226 frames_in_encoder_--;
227 DCHECK_GE(frames_in_encoder_, 0);
229 duration_in_encoder_ =
230 last_enqueued_frame_reference_time_ - encoded_frame->reference_time;
232 SendEncodedFrame(encoder_bitrate, encoded_frame.Pass());
235 } // namespace cast
236 } // namespace media