OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/cast/sender/vp8_encoder.h" | 5 #include "media/cast/sender/vp8_encoder.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
8 #include "media/base/video_frame.h" | 8 #include "media/base/video_frame.h" |
9 #include "media/cast/cast_defines.h" | 9 #include "media/cast/cast_defines.h" |
10 #include "media/cast/net/cast_transport_config.h" | |
11 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" | 10 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" |
12 | 11 |
13 namespace media { | 12 namespace media { |
14 namespace cast { | 13 namespace cast { |
15 | 14 |
16 namespace { | 15 namespace { |
17 | 16 |
18 // After a pause in the video stream, what is the maximum duration amount to | 17 // After a pause in the video stream, what is the maximum duration amount to |
19 // pass to the encoder for the next frame (in terms of 1/max_fps sized periods)? | 18 // pass to the encoder for the next frame (in terms of 1/max_fps sized periods)? |
20 // This essentially controls the encoded size of the first frame that follows a | 19 // This essentially controls the encoded size of the first frame that follows a |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
157 // Improve quality by enabling sets of codec features that utilize more CPU. | 156 // Improve quality by enabling sets of codec features that utilize more CPU. |
158 // The default is zero, with increasingly more CPU to be used as the value is | 157 // The default is zero, with increasingly more CPU to be used as the value is |
159 // more negative. | 158 // more negative. |
160 // TODO(miu): Document why this value was chosen and expected behaviors. | 159 // TODO(miu): Document why this value was chosen and expected behaviors. |
161 // Should this be dynamic w.r.t. hardware performance? | 160 // Should this be dynamic w.r.t. hardware performance? |
162 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK); | 161 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK); |
163 } | 162 } |
164 | 163 |
165 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, | 164 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, |
166 const base::TimeTicks& reference_time, | 165 const base::TimeTicks& reference_time, |
167 EncodedFrame* encoded_frame) { | 166 SenderEncodedFrame* encoded_frame) { |
168 DCHECK(thread_checker_.CalledOnValidThread()); | 167 DCHECK(thread_checker_.CalledOnValidThread()); |
169 DCHECK(encoded_frame); | 168 DCHECK(encoded_frame); |
170 | 169 |
| 170 // Note: This is used to compute the |deadline_utilization| and so it uses the |
| 171 // real-world clock instead of the CastEnvironment clock, the latter of which |
| 172 // might be simulated. |
| 173 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 174 |
171 // Initialize on-demand. Later, if the video frame size has changed, update | 175 // Initialize on-demand. Later, if the video frame size has changed, update |
172 // the encoder configuration. | 176 // the encoder configuration. |
173 const gfx::Size frame_size = video_frame->visible_rect().size(); | 177 const gfx::Size frame_size = video_frame->visible_rect().size(); |
174 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) | 178 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) |
175 ConfigureForNewFrameSize(frame_size); | 179 ConfigureForNewFrameSize(frame_size); |
176 | 180 |
177 uint32 latest_frame_id_to_reference; | 181 uint32 latest_frame_id_to_reference; |
178 Vp8Buffers buffer_to_update; | 182 Vp8Buffers buffer_to_update; |
179 vpx_codec_flags_t flags = 0; | 183 vpx_codec_flags_t flags = 0; |
180 if (key_frame_requested_) { | 184 if (key_frame_requested_) { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); | 276 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); |
273 encoded_frame->reference_time = reference_time; | 277 encoded_frame->reference_time = reference_time; |
274 encoded_frame->data.assign( | 278 encoded_frame->data.assign( |
275 static_cast<const uint8*>(pkt->data.frame.buf), | 279 static_cast<const uint8*>(pkt->data.frame.buf), |
276 static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz); | 280 static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz); |
277 break; // Done, since all data is provided in one CX_FRAME_PKT packet. | 281 break; // Done, since all data is provided in one CX_FRAME_PKT packet. |
278 } | 282 } |
279 DCHECK(!encoded_frame->data.empty()) | 283 DCHECK(!encoded_frame->data.empty()) |
280 << "BUG: Encoder must provide data since lagged encoding is disabled."; | 284 << "BUG: Encoder must provide data since lagged encoding is disabled."; |
281 | 285 |
| 286 // Compute deadline utilization as the real-world time elapsed divided by the |
| 287 // frame duration. |
| 288 const base::TimeDelta processing_time = base::TimeTicks::Now() - start_time; |
| 289 encoded_frame->deadline_utilization = |
| 290 processing_time.InSecondsF() / predicted_frame_duration.InSecondsF(); |
| 291 |
| 292 // Compute lossy utilization. The VP8 encoder took an estimated guess at what |
| 293 // quantizer value would produce an encoded frame size as close to the target |
| 294 // as possible. Now that the frame has been encoded and the number of bytes |
| 295 // is known, the perfect quantizer value (i.e., the one that should have been |
| 296 // used) can be determined. This perfect quantizer is then normalized and |
| 297 // used as the lossy utilization. |
| 298 const double actual_bitrate = |
| 299 encoded_frame->data.size() * 8.0 / predicted_frame_duration.InSecondsF(); |
| 300 const double target_bitrate = 1000.0 * config_.rc_target_bitrate; |
| 301 DCHECK_GT(target_bitrate, 0.0); |
| 302 const double bitrate_utilization = actual_bitrate / target_bitrate; |
| 303 int quantizer = -1; |
| 304 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_GET_LAST_QUANTIZER_64, &quantizer), |
| 305 VPX_CODEC_OK); |
| 306 const double perfect_quantizer = bitrate_utilization * std::max(0, quantizer); |
| 307 // Side note: If it was possible for the encoder to encode within the target |
| 308 // number of bytes, the |perfect_quantizer| will be in the range [0.0,63.0]. |
| 309 // If it was never possible, the value will be greater than 63.0. |
| 310 encoded_frame->lossy_utilization = perfect_quantizer / 63.0; |
| 311 |
282 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id | 312 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id |
283 << ", sized:" << encoded_frame->data.size(); | 313 << ", sized: " << encoded_frame->data.size() |
| 314 << ", deadline_utilization: " << encoded_frame->deadline_utilization |
| 315 << ", lossy_utilization: " << encoded_frame->lossy_utilization |
| 316 << " (quantizer chosen by the encoder was " << quantizer << ')'; |
284 | 317 |
285 if (encoded_frame->dependency == EncodedFrame::KEY) { | 318 if (encoded_frame->dependency == EncodedFrame::KEY) { |
286 key_frame_requested_ = false; | 319 key_frame_requested_ = false; |
287 | 320 |
288 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { | 321 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { |
289 buffer_state_[i].state = kBufferSent; | 322 buffer_state_[i].state = kBufferSent; |
290 buffer_state_[i].frame_id = encoded_frame->frame_id; | 323 buffer_state_[i].frame_id = encoded_frame->frame_id; |
291 } | 324 } |
292 } else { | 325 } else { |
293 if (buffer_to_update != kNoBuffer) { | 326 if (buffer_to_update != kNoBuffer) { |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 } | 509 } |
477 } | 510 } |
478 | 511 |
479 void Vp8Encoder::GenerateKeyFrame() { | 512 void Vp8Encoder::GenerateKeyFrame() { |
480 DCHECK(thread_checker_.CalledOnValidThread()); | 513 DCHECK(thread_checker_.CalledOnValidThread()); |
481 key_frame_requested_ = true; | 514 key_frame_requested_ = true; |
482 } | 515 } |
483 | 516 |
484 } // namespace cast | 517 } // namespace cast |
485 } // namespace media | 518 } // namespace media |
OLD | NEW |