| 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" |
| 10 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" | 11 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" |
| 11 | 12 |
| 12 namespace media { | 13 namespace media { |
| 13 namespace cast { | 14 namespace cast { |
| 14 | 15 |
| 15 namespace { | 16 namespace { |
| 16 | 17 |
| 17 // After a pause in the video stream, what is the maximum duration amount to | 18 // After a pause in the video stream, what is the maximum duration amount to |
| 18 // pass to the encoder for the next frame (in terms of 1/max_fps sized periods)? | 19 // pass to the encoder for the next frame (in terms of 1/max_fps sized periods)? |
| 19 // This essentially controls the encoded size of the first frame that follows a | 20 // 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... |
| 156 // Improve quality by enabling sets of codec features that utilize more CPU. | 157 // Improve quality by enabling sets of codec features that utilize more CPU. |
| 157 // The default is zero, with increasingly more CPU to be used as the value is | 158 // The default is zero, with increasingly more CPU to be used as the value is |
| 158 // more negative. | 159 // more negative. |
| 159 // TODO(miu): Document why this value was chosen and expected behaviors. | 160 // TODO(miu): Document why this value was chosen and expected behaviors. |
| 160 // Should this be dynamic w.r.t. hardware performance? | 161 // Should this be dynamic w.r.t. hardware performance? |
| 161 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK); | 162 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -6), VPX_CODEC_OK); |
| 162 } | 163 } |
| 163 | 164 |
| 164 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, | 165 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, |
| 165 const base::TimeTicks& reference_time, | 166 const base::TimeTicks& reference_time, |
| 166 SenderEncodedFrame* encoded_frame) { | 167 EncodedFrame* encoded_frame) { |
| 167 DCHECK(thread_checker_.CalledOnValidThread()); | 168 DCHECK(thread_checker_.CalledOnValidThread()); |
| 168 DCHECK(encoded_frame); | 169 DCHECK(encoded_frame); |
| 169 | 170 |
| 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 | |
| 175 // Initialize on-demand. Later, if the video frame size has changed, update | 171 // Initialize on-demand. Later, if the video frame size has changed, update |
| 176 // the encoder configuration. | 172 // the encoder configuration. |
| 177 const gfx::Size frame_size = video_frame->visible_rect().size(); | 173 const gfx::Size frame_size = video_frame->visible_rect().size(); |
| 178 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) | 174 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) |
| 179 ConfigureForNewFrameSize(frame_size); | 175 ConfigureForNewFrameSize(frame_size); |
| 180 | 176 |
| 181 uint32 latest_frame_id_to_reference; | 177 uint32 latest_frame_id_to_reference; |
| 182 Vp8Buffers buffer_to_update; | 178 Vp8Buffers buffer_to_update; |
| 183 vpx_codec_flags_t flags = 0; | 179 vpx_codec_flags_t flags = 0; |
| 184 if (key_frame_requested_) { | 180 if (key_frame_requested_) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 276 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); | 272 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); |
| 277 encoded_frame->reference_time = reference_time; | 273 encoded_frame->reference_time = reference_time; |
| 278 encoded_frame->data.assign( | 274 encoded_frame->data.assign( |
| 279 static_cast<const uint8*>(pkt->data.frame.buf), | 275 static_cast<const uint8*>(pkt->data.frame.buf), |
| 280 static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz); | 276 static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz); |
| 281 break; // Done, since all data is provided in one CX_FRAME_PKT packet. | 277 break; // Done, since all data is provided in one CX_FRAME_PKT packet. |
| 282 } | 278 } |
| 283 DCHECK(!encoded_frame->data.empty()) | 279 DCHECK(!encoded_frame->data.empty()) |
| 284 << "BUG: Encoder must provide data since lagged encoding is disabled."; | 280 << "BUG: Encoder must provide data since lagged encoding is disabled."; |
| 285 | 281 |
| 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 | |
| 312 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id | 282 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id |
| 313 << ", sized: " << encoded_frame->data.size() | 283 << ", 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 << ')'; | |
| 317 | 284 |
| 318 if (encoded_frame->dependency == EncodedFrame::KEY) { | 285 if (encoded_frame->dependency == EncodedFrame::KEY) { |
| 319 key_frame_requested_ = false; | 286 key_frame_requested_ = false; |
| 320 | 287 |
| 321 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { | 288 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { |
| 322 buffer_state_[i].state = kBufferSent; | 289 buffer_state_[i].state = kBufferSent; |
| 323 buffer_state_[i].frame_id = encoded_frame->frame_id; | 290 buffer_state_[i].frame_id = encoded_frame->frame_id; |
| 324 } | 291 } |
| 325 } else { | 292 } else { |
| 326 if (buffer_to_update != kNoBuffer) { | 293 if (buffer_to_update != kNoBuffer) { |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 509 } | 476 } |
| 510 } | 477 } |
| 511 | 478 |
| 512 void Vp8Encoder::GenerateKeyFrame() { | 479 void Vp8Encoder::GenerateKeyFrame() { |
| 513 DCHECK(thread_checker_.CalledOnValidThread()); | 480 DCHECK(thread_checker_.CalledOnValidThread()); |
| 514 key_frame_requested_ = true; | 481 key_frame_requested_ = true; |
| 515 } | 482 } |
| 516 | 483 |
| 517 } // namespace cast | 484 } // namespace cast |
| 518 } // namespace media | 485 } // namespace media |
| OLD | NEW |