OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 * | 9 * |
10 */ | 10 */ |
11 | 11 |
12 #include "webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h" | 12 #include "webrtc/modules/video_coding/codecs/h264/h264_encoder_impl.h" |
13 | 13 |
14 #include <limits> | 14 #include <limits> |
15 #include <string> | 15 #include <string> |
16 | 16 |
17 #include "third_party/openh264/src/codec/api/svc/codec_api.h" | 17 #include "third_party/openh264/src/codec/api/svc/codec_api.h" |
18 #include "third_party/openh264/src/codec/api/svc/codec_app_def.h" | 18 #include "third_party/openh264/src/codec/api/svc/codec_app_def.h" |
19 #include "third_party/openh264/src/codec/api/svc/codec_def.h" | 19 #include "third_party/openh264/src/codec/api/svc/codec_def.h" |
20 #include "third_party/openh264/src/codec/api/svc/codec_ver.h" | 20 #include "third_party/openh264/src/codec/api/svc/codec_ver.h" |
21 | 21 |
22 #include "webrtc/base/checks.h" | 22 #include "webrtc/base/checks.h" |
23 #include "webrtc/base/logging.h" | 23 #include "webrtc/base/logging.h" |
| 24 #include "webrtc/base/timeutils.h" |
24 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" | 25 #include "webrtc/common_video/libyuv/include/webrtc_libyuv.h" |
25 #include "webrtc/media/base/mediaconstants.h" | |
26 #include "webrtc/system_wrappers/include/metrics.h" | 26 #include "webrtc/system_wrappers/include/metrics.h" |
27 | 27 |
28 namespace webrtc { | 28 namespace webrtc { |
29 | 29 |
30 namespace { | 30 namespace { |
31 | 31 |
32 const bool kOpenH264EncoderDetailedLogging = false; | 32 const bool kOpenH264EncoderDetailedLogging = false; |
33 | 33 |
34 // Used by histograms. Values of entries should not be changed. | 34 // Used by histograms. Values of entries should not be changed. |
35 enum H264EncoderImplEvent { | 35 enum H264EncoderImplEvent { |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 target_bps_(0), | 160 target_bps_(0), |
161 max_bps_(0), | 161 max_bps_(0), |
162 mode_(kRealtimeVideo), | 162 mode_(kRealtimeVideo), |
163 frame_dropping_on_(false), | 163 frame_dropping_on_(false), |
164 key_frame_interval_(0), | 164 key_frame_interval_(0), |
165 packetization_mode_(H264PacketizationMode::SingleNalUnit), | 165 packetization_mode_(H264PacketizationMode::SingleNalUnit), |
166 max_payload_size_(0), | 166 max_payload_size_(0), |
167 number_of_cores_(0), | 167 number_of_cores_(0), |
168 encoded_image_callback_(nullptr), | 168 encoded_image_callback_(nullptr), |
169 has_reported_init_(false), | 169 has_reported_init_(false), |
170 has_reported_error_(false) { | 170 has_reported_error_(false), |
| 171 last_timing_frame_time_ms_(-1), |
| 172 timing_frames_delay_ms_(0), |
| 173 timing_frames_outlier_size_percent_(0) { |
171 RTC_CHECK(cricket::CodecNamesEq(codec.name, cricket::kH264CodecName)); | 174 RTC_CHECK(cricket::CodecNamesEq(codec.name, cricket::kH264CodecName)); |
172 std::string packetization_mode_string; | 175 std::string packetization_mode_string; |
173 if (codec.GetParam(cricket::kH264FmtpPacketizationMode, | 176 if (codec.GetParam(cricket::kH264FmtpPacketizationMode, |
174 &packetization_mode_string) && | 177 &packetization_mode_string) && |
175 packetization_mode_string == "1") { | 178 packetization_mode_string == "1") { |
176 packetization_mode_ = H264PacketizationMode::NonInterleaved; | 179 packetization_mode_ = H264PacketizationMode::NonInterleaved; |
177 } | 180 } |
178 } | 181 } |
179 | 182 |
180 H264EncoderImpl::~H264EncoderImpl() { | 183 H264EncoderImpl::~H264EncoderImpl() { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
224 | 227 |
225 number_of_cores_ = number_of_cores; | 228 number_of_cores_ = number_of_cores; |
226 // Set internal settings from codec_settings | 229 // Set internal settings from codec_settings |
227 width_ = codec_settings->width; | 230 width_ = codec_settings->width; |
228 height_ = codec_settings->height; | 231 height_ = codec_settings->height; |
229 max_frame_rate_ = static_cast<float>(codec_settings->maxFramerate); | 232 max_frame_rate_ = static_cast<float>(codec_settings->maxFramerate); |
230 mode_ = codec_settings->mode; | 233 mode_ = codec_settings->mode; |
231 frame_dropping_on_ = codec_settings->H264().frameDroppingOn; | 234 frame_dropping_on_ = codec_settings->H264().frameDroppingOn; |
232 key_frame_interval_ = codec_settings->H264().keyFrameInterval; | 235 key_frame_interval_ = codec_settings->H264().keyFrameInterval; |
233 max_payload_size_ = max_payload_size; | 236 max_payload_size_ = max_payload_size; |
| 237 timing_frames_outlier_size_percent_ = |
| 238 codec_settings->timingFrameTriggerThresholds.outlier_ratio_percent; |
| 239 timing_frames_delay_ms_ = |
| 240 codec_settings->timingFrameTriggerThresholds.delay_ms; |
234 | 241 |
235 // Codec_settings uses kbits/second; encoder uses bits/second. | 242 // Codec_settings uses kbits/second; encoder uses bits/second. |
236 max_bps_ = codec_settings->maxBitrate * 1000; | 243 max_bps_ = codec_settings->maxBitrate * 1000; |
237 if (codec_settings->targetBitrate == 0) | 244 if (codec_settings->targetBitrate == 0) |
238 target_bps_ = codec_settings->startBitrate * 1000; | 245 target_bps_ = codec_settings->startBitrate * 1000; |
239 else | 246 else |
240 target_bps_ = codec_settings->targetBitrate * 1000; | 247 target_bps_ = codec_settings->targetBitrate * 1000; |
241 | 248 |
242 SEncParamExt encoder_params = CreateEncoderParams(); | 249 SEncParamExt encoder_params = CreateEncoderParams(); |
243 | 250 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 return WEBRTC_VIDEO_CODEC_OK; | 308 return WEBRTC_VIDEO_CODEC_OK; |
302 } | 309 } |
303 | 310 |
304 int32_t H264EncoderImpl::Encode(const VideoFrame& input_frame, | 311 int32_t H264EncoderImpl::Encode(const VideoFrame& input_frame, |
305 const CodecSpecificInfo* codec_specific_info, | 312 const CodecSpecificInfo* codec_specific_info, |
306 const std::vector<FrameType>* frame_types) { | 313 const std::vector<FrameType>* frame_types) { |
307 if (!IsInitialized()) { | 314 if (!IsInitialized()) { |
308 ReportError(); | 315 ReportError(); |
309 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 316 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
310 } | 317 } |
| 318 int64_t encode_start_ms = rtc::TimeMillis(); |
311 if (!encoded_image_callback_) { | 319 if (!encoded_image_callback_) { |
312 LOG(LS_WARNING) << "InitEncode() has been called, but a callback function " | 320 LOG(LS_WARNING) << "InitEncode() has been called, but a callback function " |
313 << "has not been set with RegisterEncodeCompleteCallback()"; | 321 << "has not been set with RegisterEncodeCompleteCallback()"; |
314 ReportError(); | 322 ReportError(); |
315 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 323 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
316 } | 324 } |
317 | 325 |
318 bool force_key_frame = false; | 326 bool force_key_frame = false; |
319 if (frame_types != nullptr) { | 327 if (frame_types != nullptr) { |
320 // We only support a single stream. | 328 // We only support a single stream. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
378 &frag_header); | 386 &frag_header); |
379 | 387 |
380 // Encoder can skip frames to save bandwidth in which case | 388 // Encoder can skip frames to save bandwidth in which case |
381 // |encoded_image_._length| == 0. | 389 // |encoded_image_._length| == 0. |
382 if (encoded_image_._length > 0) { | 390 if (encoded_image_._length > 0) { |
383 // Parse QP. | 391 // Parse QP. |
384 h264_bitstream_parser_.ParseBitstream(encoded_image_._buffer, | 392 h264_bitstream_parser_.ParseBitstream(encoded_image_._buffer, |
385 encoded_image_._length); | 393 encoded_image_._length); |
386 h264_bitstream_parser_.GetLastSliceQp(&encoded_image_.qp_); | 394 h264_bitstream_parser_.GetLastSliceQp(&encoded_image_.qp_); |
387 | 395 |
| 396 // Add timing information if needed. Timing delay is counted based on |
| 397 // capture time to ensure that simulcast encoders will mark frames on all |
| 398 // the streams together. |
| 399 int64_t now_ms = rtc::TimeMillis(); |
| 400 bool is_time_for_timing_frame = (last_timing_frame_time_ms_ == -1) || |
| 401 (encoded_image_.capture_time_ms_ - last_timing_frame_time_ms_ >= |
| 402 timing_frames_delay_ms_); |
| 403 if (is_time_for_timing_frame) { |
| 404 last_timing_frame_time_ms_ = encoded_image_.capture_time_ms_; |
| 405 } |
| 406 size_t outlier_frame_size_bytes = |
| 407 timing_frames_outlier_size_percent_ / 100.0 * // outlier coefficient |
| 408 target_bps_ / 8 / max_frame_rate_; // target_bps in bytes / fps |
| 409 if (is_time_for_timing_frame || |
| 410 encoded_image_._length >= outlier_frame_size_bytes) { |
| 411 encoded_image_.timing_.is_timing_frame = true; |
| 412 encoded_image_.timing_.encode_start_ms = encode_start_ms; |
| 413 encoded_image_.timing_.encode_finish_ms = now_ms; |
| 414 } else { |
| 415 encoded_image_.timing_.is_timing_frame = false; |
| 416 } |
| 417 |
388 // Deliver encoded image. | 418 // Deliver encoded image. |
389 CodecSpecificInfo codec_specific; | 419 CodecSpecificInfo codec_specific; |
390 codec_specific.codecType = kVideoCodecH264; | 420 codec_specific.codecType = kVideoCodecH264; |
391 codec_specific.codecSpecific.H264.packetization_mode = packetization_mode_; | 421 codec_specific.codecSpecific.H264.packetization_mode = packetization_mode_; |
392 encoded_image_callback_->OnEncodedImage(encoded_image_, &codec_specific, | 422 encoded_image_callback_->OnEncodedImage(encoded_image_, &codec_specific, |
393 &frag_header); | 423 &frag_header); |
394 } | 424 } |
395 return WEBRTC_VIDEO_CODEC_OK; | 425 return WEBRTC_VIDEO_CODEC_OK; |
396 } | 426 } |
397 | 427 |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
497 | 527 |
498 int32_t H264EncoderImpl::SetPeriodicKeyFrames(bool enable) { | 528 int32_t H264EncoderImpl::SetPeriodicKeyFrames(bool enable) { |
499 return WEBRTC_VIDEO_CODEC_OK; | 529 return WEBRTC_VIDEO_CODEC_OK; |
500 } | 530 } |
501 | 531 |
502 VideoEncoder::ScalingSettings H264EncoderImpl::GetScalingSettings() const { | 532 VideoEncoder::ScalingSettings H264EncoderImpl::GetScalingSettings() const { |
503 return VideoEncoder::ScalingSettings(true); | 533 return VideoEncoder::ScalingSettings(true); |
504 } | 534 } |
505 | 535 |
506 } // namespace webrtc | 536 } // namespace webrtc |
OLD | NEW |