Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(538)

Side by Side Diff: webrtc/modules/video_coding/generic_encoder.cc

Issue 2911193002: Implement timing frames. (Closed)
Patch Set: Implement Holmer@ comments Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 2 * Copyright (c) 2012 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 #include "webrtc/modules/video_coding/generic_encoder.h" 11 #include "webrtc/modules/video_coding/generic_encoder.h"
12 12
13 #include <vector> 13 #include <vector>
14 14
15 #include "webrtc/api/video/i420_buffer.h" 15 #include "webrtc/api/video/i420_buffer.h"
16 #include "webrtc/base/checks.h" 16 #include "webrtc/base/checks.h"
17 #include "webrtc/base/logging.h" 17 #include "webrtc/base/logging.h"
18 #include "webrtc/base/timeutils.h"
18 #include "webrtc/base/trace_event.h" 19 #include "webrtc/base/trace_event.h"
19 #include "webrtc/modules/video_coding/encoded_frame.h" 20 #include "webrtc/modules/video_coding/encoded_frame.h"
20 #include "webrtc/modules/video_coding/media_optimization.h" 21 #include "webrtc/modules/video_coding/media_optimization.h"
21 22
22 namespace webrtc { 23 namespace webrtc {
23 24
24 VCMGenericEncoder::VCMGenericEncoder( 25 VCMGenericEncoder::VCMGenericEncoder(
25 VideoEncoder* encoder, 26 VideoEncoder* encoder,
26 VCMEncodedFrameCallback* encoded_frame_callback, 27 VCMEncodedFrameCallback* encoded_frame_callback,
27 bool internal_source) 28 bool internal_source)
28 : encoder_(encoder), 29 : encoder_(encoder),
29 vcm_encoded_frame_callback_(encoded_frame_callback), 30 vcm_encoded_frame_callback_(encoded_frame_callback),
30 internal_source_(internal_source), 31 internal_source_(internal_source),
31 encoder_params_({BitrateAllocation(), 0, 0, 0}), 32 encoder_params_({BitrateAllocation(), 0, 0, 0}),
32 is_screenshare_(false) {} 33 is_screenshare_(false),
34 streams_or_svc_num_(0) {}
33 35
34 VCMGenericEncoder::~VCMGenericEncoder() {} 36 VCMGenericEncoder::~VCMGenericEncoder() {}
35 37
36 int32_t VCMGenericEncoder::Release() { 38 int32_t VCMGenericEncoder::Release() {
37 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 39 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
38 TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release"); 40 TRACE_EVENT0("webrtc", "VCMGenericEncoder::Release");
39 return encoder_->Release(); 41 return encoder_->Release();
40 } 42 }
41 43
42 int32_t VCMGenericEncoder::InitEncode(const VideoCodec* settings, 44 int32_t VCMGenericEncoder::InitEncode(const VideoCodec* settings,
43 int32_t number_of_cores, 45 int32_t number_of_cores,
44 size_t max_payload_size) { 46 size_t max_payload_size) {
45 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 47 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
46 TRACE_EVENT0("webrtc", "VCMGenericEncoder::InitEncode"); 48 TRACE_EVENT0("webrtc", "VCMGenericEncoder::InitEncode");
47 is_screenshare_ = settings->mode == VideoCodecMode::kScreensharing; 49 is_screenshare_ = settings->mode == VideoCodecMode::kScreensharing;
50 streams_or_svc_num_ = settings->numberOfSimulcastStreams;
51 if (settings->codecType == kVideoCodecVP9) {
52 streams_or_svc_num_ = settings->VP9().numberOfSpatialLayers;
53 }
54 if (streams_or_svc_num_ == 0)
55 streams_or_svc_num_ = 1;
56
57 vcm_encoded_frame_callback_->SetTimingFramesThresholds(
58 settings->timing_frame_thresholds);
59 vcm_encoded_frame_callback_->OnFrameRateChanged(settings->maxFramerate);
60
48 if (encoder_->InitEncode(settings, number_of_cores, max_payload_size) != 0) { 61 if (encoder_->InitEncode(settings, number_of_cores, max_payload_size) != 0) {
49 LOG(LS_ERROR) << "Failed to initialize the encoder associated with " 62 LOG(LS_ERROR) << "Failed to initialize the encoder associated with "
50 "payload name: " 63 "payload name: "
51 << settings->plName; 64 << settings->plName;
52 return -1; 65 return -1;
53 } 66 }
54 encoder_->RegisterEncodeCompleteCallback(vcm_encoded_frame_callback_); 67 encoder_->RegisterEncodeCompleteCallback(vcm_encoded_frame_callback_);
55 return 0; 68 return 0;
56 } 69 }
57 70
58 int32_t VCMGenericEncoder::Encode(const VideoFrame& frame, 71 int32_t VCMGenericEncoder::Encode(const VideoFrame& frame,
59 const CodecSpecificInfo* codec_specific, 72 const CodecSpecificInfo* codec_specific,
60 const std::vector<FrameType>& frame_types) { 73 const std::vector<FrameType>& frame_types) {
61 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 74 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
62 TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp", 75 TRACE_EVENT1("webrtc", "VCMGenericEncoder::Encode", "timestamp",
63 frame.timestamp()); 76 frame.timestamp());
64 77
65 for (FrameType frame_type : frame_types) 78 for (FrameType frame_type : frame_types)
66 RTC_DCHECK(frame_type == kVideoFrameKey || frame_type == kVideoFrameDelta); 79 RTC_DCHECK(frame_type == kVideoFrameKey || frame_type == kVideoFrameDelta);
67 80
81 for (size_t i = 0; i < streams_or_svc_num_; ++i)
82 vcm_encoded_frame_callback_->OnEncodeStarted(frame.render_time_ms(), i);
68 int32_t result = encoder_->Encode(frame, codec_specific, &frame_types); 83 int32_t result = encoder_->Encode(frame, codec_specific, &frame_types);
69 84
70 if (is_screenshare_ && 85 if (is_screenshare_ &&
71 result == WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT) { 86 result == WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT) {
72 // Target bitrate exceeded, encoder state has been reset - try again. 87 // Target bitrate exceeded, encoder state has been reset - try again.
73 return encoder_->Encode(frame, codec_specific, &frame_types); 88 return encoder_->Encode(frame, codec_specific, &frame_types);
74 } 89 }
75 90
76 return result; 91 return result;
77 } 92 }
(...skipping 22 matching lines...) Expand all
100 } 115 }
101 if (rates_have_changed) { 116 if (rates_have_changed) {
102 int res = encoder_->SetRateAllocation(params.target_bitrate, 117 int res = encoder_->SetRateAllocation(params.target_bitrate,
103 params.input_frame_rate); 118 params.input_frame_rate);
104 if (res != 0) { 119 if (res != 0) {
105 LOG(LS_WARNING) << "Error set encoder rate (total bitrate bps = " 120 LOG(LS_WARNING) << "Error set encoder rate (total bitrate bps = "
106 << params.target_bitrate.get_sum_bps() 121 << params.target_bitrate.get_sum_bps()
107 << ", framerate = " << params.input_frame_rate 122 << ", framerate = " << params.input_frame_rate
108 << "): " << res; 123 << "): " << res;
109 } 124 }
125 vcm_encoded_frame_callback_->OnFrameRateChanged(params.input_frame_rate);
126 for (size_t i = 0; i < streams_or_svc_num_; ++i) {
127 size_t layer_bitrate_bytes_per_sec =
128 params.target_bitrate.GetSpatialLayerSum(i) / 8;
129 // VP9 rate control is not yet moved out of VP9Impl. Due to that rates
130 // are not split among spatial layers.
131 if (layer_bitrate_bytes_per_sec == 0)
132 layer_bitrate_bytes_per_sec = params.target_bitrate.get_sum_bps() / 8;
133 vcm_encoded_frame_callback_->OnTargetBitrateChanged(
134 layer_bitrate_bytes_per_sec, i);
135 }
110 } 136 }
111 } 137 }
112 138
113 EncoderParameters VCMGenericEncoder::GetEncoderParameters() const { 139 EncoderParameters VCMGenericEncoder::GetEncoderParameters() const {
114 rtc::CritScope lock(&params_lock_); 140 rtc::CritScope lock(&params_lock_);
115 return encoder_params_; 141 return encoder_params_;
116 } 142 }
117 143
118 int32_t VCMGenericEncoder::SetPeriodicKeyFrames(bool enable) { 144 int32_t VCMGenericEncoder::SetPeriodicKeyFrames(bool enable) {
119 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 145 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
120 return encoder_->SetPeriodicKeyFrames(enable); 146 return encoder_->SetPeriodicKeyFrames(enable);
121 } 147 }
122 148
123 int32_t VCMGenericEncoder::RequestFrame( 149 int32_t VCMGenericEncoder::RequestFrame(
124 const std::vector<FrameType>& frame_types) { 150 const std::vector<FrameType>& frame_types) {
125 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 151 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
126 152
153 for (size_t i = 0; i < streams_or_svc_num_; ++i)
154 vcm_encoded_frame_callback_->OnEncodeStarted(0, i);
127 // TODO(nisse): Used only with internal source. Delete as soon as 155 // TODO(nisse): Used only with internal source. Delete as soon as
128 // that feature is removed. The only implementation I've been able 156 // that feature is removed. The only implementation I've been able
129 // to find ignores what's in the frame. With one exception: It seems 157 // to find ignores what's in the frame. With one exception: It seems
130 // a few test cases, e.g., 158 // a few test cases, e.g.,
131 // VideoSendStreamTest.VideoSendStreamStopSetEncoderRateToZero, set 159 // VideoSendStreamTest.VideoSendStreamStopSetEncoderRateToZero, set
132 // internal_source to true and use FakeEncoder. And the latter will 160 // internal_source to true and use FakeEncoder. And the latter will
133 // happily encode this 1x1 frame and pass it on down the pipeline. 161 // happily encode this 1x1 frame and pass it on down the pipeline.
134 return encoder_->Encode(VideoFrame(I420Buffer::Create(1, 1), 162 return encoder_->Encode(VideoFrame(I420Buffer::Create(1, 1),
135 kVideoRotation_0, 0), 163 kVideoRotation_0, 0),
136 NULL, &frame_types); 164 NULL, &frame_types);
137 return 0; 165 return 0;
138 } 166 }
139 167
140 bool VCMGenericEncoder::InternalSource() const { 168 bool VCMGenericEncoder::InternalSource() const {
141 return internal_source_; 169 return internal_source_;
142 } 170 }
143 171
144 bool VCMGenericEncoder::SupportsNativeHandle() const { 172 bool VCMGenericEncoder::SupportsNativeHandle() const {
145 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_); 173 RTC_DCHECK_RUNS_SERIALIZED(&race_checker_);
146 return encoder_->SupportsNativeHandle(); 174 return encoder_->SupportsNativeHandle();
147 } 175 }
148 176
149 VCMEncodedFrameCallback::VCMEncodedFrameCallback( 177 VCMEncodedFrameCallback::VCMEncodedFrameCallback(
150 EncodedImageCallback* post_encode_callback, 178 EncodedImageCallback* post_encode_callback,
151 media_optimization::MediaOptimization* media_opt) 179 media_optimization::MediaOptimization* media_opt)
152 : internal_source_(false), 180 : internal_source_(false),
153 post_encode_callback_(post_encode_callback), 181 post_encode_callback_(post_encode_callback),
154 media_opt_(media_opt) {} 182 media_opt_(media_opt),
183 framerate_(1),
184 last_timing_frame_time_ms_(-1),
185 timing_frames_thresholds_({-1, 0}) {}
155 186
156 VCMEncodedFrameCallback::~VCMEncodedFrameCallback() {} 187 VCMEncodedFrameCallback::~VCMEncodedFrameCallback() {}
157 188
189 void VCMEncodedFrameCallback::OnTargetBitrateChanged(
190 size_t bitrate_bytes_per_second,
191 size_t simulcast_svc_idx) {
192 rtc::CritScope crit(&timing_params_lock_);
193 if (timing_frames_info_.size() < simulcast_svc_idx + 1)
194 timing_frames_info_.resize(simulcast_svc_idx + 1);
195 timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec =
196 bitrate_bytes_per_second;
197 }
198
199 void VCMEncodedFrameCallback::OnFrameRateChanged(size_t framerate) {
200 rtc::CritScope crit(&timing_params_lock_);
201 framerate_ = framerate;
202 }
203
204 void VCMEncodedFrameCallback::OnEncodeStarted(int64_t capture_time_ms,
205 size_t simulcast_svc_idx) {
206 rtc::CritScope crit(&timing_params_lock_);
207 if (timing_frames_info_.size() < simulcast_svc_idx + 1)
208 timing_frames_info_.resize(simulcast_svc_idx + 1);
209 timing_frames_info_[simulcast_svc_idx].encode_start_time_ms[capture_time_ms] =
210 rtc::TimeMillis();
211 }
212
158 EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage( 213 EncodedImageCallback::Result VCMEncodedFrameCallback::OnEncodedImage(
159 const EncodedImage& encoded_image, 214 const EncodedImage& encoded_image,
160 const CodecSpecificInfo* codec_specific, 215 const CodecSpecificInfo* codec_specific,
161 const RTPFragmentationHeader* fragmentation_header) { 216 const RTPFragmentationHeader* fragmentation_header) {
162 TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded", 217 TRACE_EVENT_INSTANT1("webrtc", "VCMEncodedFrameCallback::Encoded",
163 "timestamp", encoded_image._timeStamp); 218 "timestamp", encoded_image._timeStamp);
219 bool is_timing_frame = false;
220 size_t outlier_frame_size = 0;
221 int64_t encode_start_ms = -1;
222 size_t simulcast_svc_idx = 0;
223 if (codec_specific->codecType == kVideoCodecVP9) {
224 if (codec_specific->codecSpecific.VP9.num_spatial_layers > 1)
225 simulcast_svc_idx = codec_specific->codecSpecific.VP9.spatial_idx;
226 } else if (codec_specific->codecType == kVideoCodecVP8) {
227 simulcast_svc_idx = codec_specific->codecSpecific.VP8.simulcastIdx;
228 } else if (codec_specific->codecType == kVideoCodecGeneric) {
229 simulcast_svc_idx = codec_specific->codecSpecific.generic.simulcast_idx;
230 } else if (codec_specific->codecType == kVideoCodecH264) {
231 // TODO(ilnik): When h264 simulcast is landed, extract simulcast idx here.
232 }
233
234 {
235 rtc::CritScope crit(&timing_params_lock_);
236 RTC_CHECK_LT(simulcast_svc_idx, timing_frames_info_.size());
237
238 auto encode_start_map =
239 &timing_frames_info_[simulcast_svc_idx].encode_start_time_ms;
240 auto it = encode_start_map->find(encoded_image.capture_time_ms_);
241 if (it != encode_start_map->end()) {
242 encode_start_ms = it->second;
243 // Assuming all encoders do not reorder frames within single stream,
244 // there may be some dropped frames with smaller timestamps. These should
245 // be purged.
246 encode_start_map->erase(encode_start_map->begin(), it);
247 encode_start_map->erase(it);
248 } else {
249 // Some chromium remoting unittests use generic encoder incorrectly
250 // If timestamps do not match, purge them all.
251 encode_start_map->erase(encode_start_map->begin(),
252 encode_start_map->end());
253 }
254
255 int64_t timing_frame_delay_ms =
256 encoded_image.capture_time_ms_ - last_timing_frame_time_ms_;
257 if (last_timing_frame_time_ms_ == -1 ||
258 timing_frame_delay_ms >= timing_frames_thresholds_.delay_ms ||
259 timing_frame_delay_ms == 0) {
260 is_timing_frame = true;
261 last_timing_frame_time_ms_ = encoded_image.capture_time_ms_;
262 }
263 RTC_CHECK_GT(framerate_, 0);
264 size_t average_frame_size =
265 timing_frames_info_[simulcast_svc_idx].target_bitrate_bytes_per_sec /
266 framerate_;
267 outlier_frame_size = average_frame_size *
268 timing_frames_thresholds_.outlier_ratio_percent / 100;
269 }
270
271 if (encoded_image._length >= outlier_frame_size) {
272 is_timing_frame = true;
273 }
274 if (encode_start_ms >= 0 && is_timing_frame) {
275 encoded_image.SetEncodeTime(encode_start_ms, rtc::TimeMillis());
276 }
277
164 Result result = post_encode_callback_->OnEncodedImage( 278 Result result = post_encode_callback_->OnEncodedImage(
165 encoded_image, codec_specific, fragmentation_header); 279 encoded_image, codec_specific, fragmentation_header);
166 if (result.error != Result::OK) 280 if (result.error != Result::OK)
167 return result; 281 return result;
168 282
169 if (media_opt_) { 283 if (media_opt_) {
170 media_opt_->UpdateWithEncodedData(encoded_image); 284 media_opt_->UpdateWithEncodedData(encoded_image);
171 if (internal_source_) { 285 if (internal_source_) {
172 // Signal to encoder to drop next frame. 286 // Signal to encoder to drop next frame.
173 result.drop_next_frame = media_opt_->DropFrame(); 287 result.drop_next_frame = media_opt_->DropFrame();
174 } 288 }
175 } 289 }
176 return result; 290 return result;
177 } 291 }
178 292
179 } // namespace webrtc 293 } // namespace webrtc
OLDNEW
« no previous file with comments | « webrtc/modules/video_coding/generic_encoder.h ('k') | webrtc/modules/video_coding/generic_encoder_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698