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/debug/crash_logging.h" |
| 8 #include "base/debug/dump_without_crashing.h" |
| 9 #include "base/format_macros.h" |
7 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/strings/stringprintf.h" |
8 #include "media/base/video_frame.h" | 12 #include "media/base/video_frame.h" |
9 #include "media/cast/cast_defines.h" | 13 #include "media/cast/cast_defines.h" |
10 #include "third_party/libvpx_new/source/libvpx/vpx/vp8cx.h" | 14 #include "third_party/libvpx_new/source/libvpx/vpx/vp8cx.h" |
11 | 15 |
12 namespace media { | 16 namespace media { |
13 namespace cast { | 17 namespace cast { |
14 | 18 |
15 namespace { | 19 namespace { |
16 | 20 |
17 // After a pause in the video stream, what is the maximum duration amount to | 21 // 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)? | 22 // 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 | 23 // This essentially controls the encoded size of the first frame that follows a |
20 // pause in the video stream. | 24 // pause in the video stream. |
21 const int kRestartFramePeriods = 3; | 25 const int kRestartFramePeriods = 3; |
22 | 26 |
23 } // namespace | 27 } // namespace |
24 | 28 |
25 Vp8Encoder::Vp8Encoder(const VideoSenderConfig& video_config) | 29 Vp8Encoder::Vp8Encoder(const VideoSenderConfig& video_config) |
26 : cast_config_(video_config), | 30 : cast_config_(video_config), |
27 use_multiple_video_buffers_( | 31 use_multiple_video_buffers_( |
28 cast_config_.max_number_of_video_buffers_used == | 32 cast_config_.max_number_of_video_buffers_used == |
29 kNumberOfVp8VideoBuffers), | 33 kNumberOfVp8VideoBuffers), |
30 key_frame_requested_(true), | 34 key_frame_requested_(true), |
31 bitrate_kbit_(cast_config_.start_bitrate / 1000), | 35 bitrate_kbit_(cast_config_.start_bitrate / 1000), |
32 last_encoded_frame_id_(kStartFrameId), | 36 last_encoded_frame_id_(kStartFrameId), |
33 last_acked_frame_id_(kStartFrameId), | 37 last_acked_frame_id_(kStartFrameId), |
34 undroppable_frames_(0) { | 38 undroppable_frames_(0), |
| 39 has_seen_zero_length_encoded_frame_(false) { |
35 config_.g_timebase.den = 0; // Not initialized. | 40 config_.g_timebase.den = 0; // Not initialized. |
36 | 41 |
37 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { | 42 for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) { |
38 buffer_state_[i].frame_id = last_encoded_frame_id_; | 43 buffer_state_[i].frame_id = last_encoded_frame_id_; |
39 buffer_state_[i].state = kBufferStartState; | 44 buffer_state_[i].state = kBufferStartState; |
40 } | 45 } |
41 | 46 |
42 // VP8 have 3 buffers available for prediction, with | 47 // VP8 have 3 buffers available for prediction, with |
43 // max_number_of_video_buffers_used set to 1 we maximize the coding efficiency | 48 // max_number_of_video_buffers_used set to 1 we maximize the coding efficiency |
44 // however in this mode we can not skip frames in the receiver to catch up | 49 // however in this mode we can not skip frames in the receiver to catch up |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); | 281 TimeDeltaToRtpDelta(video_frame->timestamp(), kVideoFrequency); |
277 encoded_frame->reference_time = reference_time; | 282 encoded_frame->reference_time = reference_time; |
278 encoded_frame->data.assign( | 283 encoded_frame->data.assign( |
279 static_cast<const uint8*>(pkt->data.frame.buf), | 284 static_cast<const uint8*>(pkt->data.frame.buf), |
280 static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz); | 285 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. | 286 break; // Done, since all data is provided in one CX_FRAME_PKT packet. |
282 } | 287 } |
283 DCHECK(!encoded_frame->data.empty()) | 288 DCHECK(!encoded_frame->data.empty()) |
284 << "BUG: Encoder must provide data since lagged encoding is disabled."; | 289 << "BUG: Encoder must provide data since lagged encoding is disabled."; |
285 | 290 |
| 291 // TODO(miu): Determine when/why encoding can produce zero-length data, |
| 292 // which causes crypto crashes. http://crbug.com/519022 |
| 293 if (!has_seen_zero_length_encoded_frame_ && encoded_frame->data.empty()) { |
| 294 has_seen_zero_length_encoded_frame_ = true; |
| 295 |
| 296 const char kZeroEncodeDetails[] = "zero-encode-details"; |
| 297 const std::string details = base::StringPrintf( |
| 298 "SV/%c,id=%" PRIu32 ",rtp=%" PRIu32 ",br=%d,kfr=%c", |
| 299 encoded_frame->dependency == EncodedFrame::KEY ? 'K' : 'D', |
| 300 encoded_frame->frame_id, encoded_frame->rtp_timestamp, |
| 301 static_cast<int>(config_.rc_target_bitrate), |
| 302 key_frame_requested_ ? 'Y' : 'N'); |
| 303 base::debug::SetCrashKeyValue(kZeroEncodeDetails, details); |
| 304 // Please forward crash reports to http://crbug.com/519022: |
| 305 base::debug::DumpWithoutCrashing(); |
| 306 base::debug::ClearCrashKey(kZeroEncodeDetails); |
| 307 } |
| 308 |
286 // Compute deadline utilization as the real-world time elapsed divided by the | 309 // Compute deadline utilization as the real-world time elapsed divided by the |
287 // frame duration. | 310 // frame duration. |
288 const base::TimeDelta processing_time = base::TimeTicks::Now() - start_time; | 311 const base::TimeDelta processing_time = base::TimeTicks::Now() - start_time; |
289 encoded_frame->deadline_utilization = | 312 encoded_frame->deadline_utilization = |
290 processing_time.InSecondsF() / predicted_frame_duration.InSecondsF(); | 313 processing_time.InSecondsF() / predicted_frame_duration.InSecondsF(); |
291 | 314 |
292 // Compute lossy utilization. The VP8 encoder took an estimated guess at what | 315 // 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 | 316 // 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 | 317 // 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 | 318 // is known, the perfect quantizer value (i.e., the one that should have been |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
509 } | 532 } |
510 } | 533 } |
511 | 534 |
512 void Vp8Encoder::GenerateKeyFrame() { | 535 void Vp8Encoder::GenerateKeyFrame() { |
513 DCHECK(thread_checker_.CalledOnValidThread()); | 536 DCHECK(thread_checker_.CalledOnValidThread()); |
514 key_frame_requested_ = true; | 537 key_frame_requested_ = true; |
515 } | 538 } |
516 | 539 |
517 } // namespace cast | 540 } // namespace cast |
518 } // namespace media | 541 } // namespace media |
OLD | NEW |