OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2014 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 */ |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
49 VP9EncoderImpl::VP9EncoderImpl() | 49 VP9EncoderImpl::VP9EncoderImpl() |
50 : encoded_image_(), | 50 : encoded_image_(), |
51 encoded_complete_callback_(NULL), | 51 encoded_complete_callback_(NULL), |
52 inited_(false), | 52 inited_(false), |
53 timestamp_(0), | 53 timestamp_(0), |
54 picture_id_(0), | 54 picture_id_(0), |
55 cpu_speed_(3), | 55 cpu_speed_(3), |
56 rc_max_intra_target_(0), | 56 rc_max_intra_target_(0), |
57 encoder_(NULL), | 57 encoder_(NULL), |
58 config_(NULL), | 58 config_(NULL), |
59 raw_(NULL) { | 59 raw_(NULL), |
60 input_image_(NULL), | |
61 tl0_pic_idx_(0), | |
62 number_of_temporal_layers_(0), | |
63 number_of_spatial_layers_(0) { | |
60 memset(&codec_, 0, sizeof(codec_)); | 64 memset(&codec_, 0, sizeof(codec_)); |
61 uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); | 65 uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); |
62 srand(seed); | 66 srand(seed); |
63 } | 67 } |
64 | 68 |
65 VP9EncoderImpl::~VP9EncoderImpl() { | 69 VP9EncoderImpl::~VP9EncoderImpl() { |
66 Release(); | 70 Release(); |
67 } | 71 } |
68 | 72 |
69 int VP9EncoderImpl::Release() { | 73 int VP9EncoderImpl::Release() { |
(...skipping 13 matching lines...) Expand all Loading... | |
83 config_ = NULL; | 87 config_ = NULL; |
84 } | 88 } |
85 if (raw_ != NULL) { | 89 if (raw_ != NULL) { |
86 vpx_img_free(raw_); | 90 vpx_img_free(raw_); |
87 raw_ = NULL; | 91 raw_ = NULL; |
88 } | 92 } |
89 inited_ = false; | 93 inited_ = false; |
90 return WEBRTC_VIDEO_CODEC_OK; | 94 return WEBRTC_VIDEO_CODEC_OK; |
91 } | 95 } |
92 | 96 |
97 int VP9EncoderImpl::SetSvcRates() { | |
98 float sRateRatio[VPX_MAX_LAYERS] = {0}; | |
stefan-webrtc
2015/07/09 14:48:59
No camelCase.
åsapersson
2015/07/29 12:10:12
Done.
| |
99 float total = 0; | |
100 uint8_t i = 0; | |
101 | |
102 if (number_of_spatial_layers_ > 1) { | |
103 for (i = 0; i < number_of_spatial_layers_; ++i) { | |
104 if (svc_internal_.svc_params.scaling_factor_num[i] <= 0 || | |
105 !svc_internal_.svc_params.scaling_factor_den[i]) { | |
stefan-webrtc
2015/07/09 14:48:59
svc_internal_.svc_params.scaling_factor_den[i] <=
åsapersson
2015/07/29 12:10:12
Done.
| |
106 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
107 } | |
108 sRateRatio[i] = | |
109 (float)(svc_internal_.svc_params.scaling_factor_num[i] * 1.0 / | |
stefan-webrtc
2015/07/09 14:48:59
static_cast. I don't think the * 1.0 matters.
åsapersson
2015/07/29 12:10:12
Changed parenthesis -> removed 1.0.
| |
110 svc_internal_.svc_params.scaling_factor_den[i]); | |
111 total += sRateRatio[i]; | |
112 } | |
113 } else { | |
114 sRateRatio[0] = total = 1; | |
115 } | |
116 | |
stefan-webrtc
2015/07/09 14:48:59
Assert that total = 1?
åsapersson
2015/07/29 12:10:12
added assert >=1?
| |
117 for (i = 0; i < number_of_spatial_layers_; ++i) { | |
118 config_->ss_target_bitrate[i] = | |
119 (unsigned int)(config_->rc_target_bitrate * sRateRatio[i] / total); | |
stefan-webrtc
2015/07/09 14:48:59
static_cast
åsapersson
2015/07/29 12:10:12
Done.
| |
120 if (number_of_temporal_layers_ == 1) { | |
121 config_->layer_target_bitrate[0] = config_->ss_target_bitrate[i]; | |
122 } else if (number_of_temporal_layers_ == 2) { | |
123 config_->layer_target_bitrate[i * number_of_temporal_layers_] = | |
124 config_->ss_target_bitrate[i] * 2 / 3; | |
125 config_->layer_target_bitrate[i * number_of_temporal_layers_ + 1] = | |
126 config_->ss_target_bitrate[i]; | |
127 } else { | |
128 if (number_of_temporal_layers_ != 3) { | |
129 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
130 } | |
131 config_->layer_target_bitrate[i * number_of_temporal_layers_] = | |
132 config_->ss_target_bitrate[i] / 2; | |
133 config_->layer_target_bitrate[i * number_of_temporal_layers_ + 1] = | |
134 config_->layer_target_bitrate[i * number_of_temporal_layers_] + | |
135 (config_->ss_target_bitrate[i] / 4); | |
136 config_->layer_target_bitrate[i * number_of_temporal_layers_ + 2] = | |
137 config_->ss_target_bitrate[i]; | |
138 } | |
139 } | |
140 | |
141 if (number_of_spatial_layers_ == 1) { | |
142 for (i = 0; i < VPX_TS_MAX_LAYERS; ++i) { | |
143 config_->ts_target_bitrate[i] = config_->layer_target_bitrate[i]; | |
stefan-webrtc
2015/07/09 14:48:59
Are all VPX_TS_MAX_LAYERS elements of layer_target
åsapersson
2015/07/29 12:10:12
Changed to number of temporal layers.
| |
144 } | |
145 } | |
146 | |
147 return WEBRTC_VIDEO_CODEC_OK; | |
stefan-webrtc
2015/07/09 14:48:59
Make this method return bool instead.
åsapersson
2015/07/29 12:10:12
Done.
| |
148 } | |
149 | |
93 int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit, | 150 int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
94 uint32_t new_framerate) { | 151 uint32_t new_framerate) { |
95 if (!inited_) { | 152 if (!inited_) { |
96 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 153 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
97 } | 154 } |
98 if (encoder_->err) { | 155 if (encoder_->err) { |
99 return WEBRTC_VIDEO_CODEC_ERROR; | 156 return WEBRTC_VIDEO_CODEC_ERROR; |
100 } | 157 } |
101 if (new_framerate < 1) { | 158 if (new_framerate < 1) { |
102 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 159 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
103 } | 160 } |
104 // Update bit rate | 161 // Update bit rate |
105 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { | 162 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { |
106 new_bitrate_kbit = codec_.maxBitrate; | 163 new_bitrate_kbit = codec_.maxBitrate; |
107 } | 164 } |
108 config_->rc_target_bitrate = new_bitrate_kbit; | 165 config_->rc_target_bitrate = new_bitrate_kbit; |
109 codec_.maxFramerate = new_framerate; | 166 codec_.maxFramerate = new_framerate; |
167 | |
168 int ret = SetSvcRates(); | |
169 if (ret != WEBRTC_VIDEO_CODEC_OK) | |
170 return ret; | |
171 | |
110 // Update encoder context | 172 // Update encoder context |
111 if (vpx_codec_enc_config_set(encoder_, config_)) { | 173 if (vpx_codec_enc_config_set(encoder_, config_)) { |
112 return WEBRTC_VIDEO_CODEC_ERROR; | 174 return WEBRTC_VIDEO_CODEC_ERROR; |
113 } | 175 } |
114 return WEBRTC_VIDEO_CODEC_OK; | 176 return WEBRTC_VIDEO_CODEC_OK; |
115 } | 177 } |
116 | 178 |
117 int VP9EncoderImpl::InitEncode(const VideoCodec* inst, | 179 int VP9EncoderImpl::InitEncode(const VideoCodec* inst, |
118 int number_of_cores, | 180 int number_of_cores, |
119 size_t /*max_payload_size*/) { | 181 size_t /*max_payload_size*/) { |
(...skipping 20 matching lines...) Expand all Loading... | |
140 if (encoder_ == NULL) { | 202 if (encoder_ == NULL) { |
141 encoder_ = new vpx_codec_ctx_t; | 203 encoder_ = new vpx_codec_ctx_t; |
142 } | 204 } |
143 if (config_ == NULL) { | 205 if (config_ == NULL) { |
144 config_ = new vpx_codec_enc_cfg_t; | 206 config_ = new vpx_codec_enc_cfg_t; |
145 } | 207 } |
146 timestamp_ = 0; | 208 timestamp_ = 0; |
147 if (&codec_ != inst) { | 209 if (&codec_ != inst) { |
148 codec_ = *inst; | 210 codec_ = *inst; |
149 } | 211 } |
212 | |
213 // Member codec_ has access to VideoCodecVP9 (common_types.h), which should | |
214 // have number of spatial layers and temporal structure mode set. | |
stefan-webrtc
2015/07/09 14:48:59
Not sure if this comment is useful?
åsapersson
2015/07/29 12:10:12
Removed.
| |
215 number_of_temporal_layers_ = inst->codecSpecific.VP9.numberOfTemporalLayers; | |
216 number_of_spatial_layers_ = inst->codecSpecific.VP9.numberOfSpatialLayers; | |
217 // For now, only support 1 spatial layer. | |
218 if (number_of_spatial_layers_ != 1) { | |
219 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
220 } | |
221 | |
150 // Random start 16 bits is enough. | 222 // Random start 16 bits is enough. |
151 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; | 223 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; |
152 // Allocate memory for encoded image | 224 // Allocate memory for encoded image |
153 if (encoded_image_._buffer != NULL) { | 225 if (encoded_image_._buffer != NULL) { |
154 delete [] encoded_image_._buffer; | 226 delete [] encoded_image_._buffer; |
155 } | 227 } |
156 encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height); | 228 encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height); |
157 encoded_image_._buffer = new uint8_t[encoded_image_._size]; | 229 encoded_image_._buffer = new uint8_t[encoded_image_._size]; |
158 encoded_image_._completeFrame = true; | 230 encoded_image_._completeFrame = true; |
159 // Creating a wrapper to the image - setting image data to NULL. Actual | 231 // Creating a wrapper to the image - setting image data to NULL. Actual |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
192 config_->kf_mode = VPX_KF_AUTO; | 264 config_->kf_mode = VPX_KF_AUTO; |
193 config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval; | 265 config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval; |
194 } else { | 266 } else { |
195 config_->kf_mode = VPX_KF_DISABLED; | 267 config_->kf_mode = VPX_KF_DISABLED; |
196 } | 268 } |
197 | 269 |
198 // Determine number of threads based on the image size and #cores. | 270 // Determine number of threads based on the image size and #cores. |
199 config_->g_threads = NumberOfThreads(config_->g_w, | 271 config_->g_threads = NumberOfThreads(config_->g_w, |
200 config_->g_h, | 272 config_->g_h, |
201 number_of_cores); | 273 number_of_cores); |
274 | |
275 if (number_of_temporal_layers_ == 1) { | |
276 gof_.SetGofInfoVP9(kTemporalStructureMode1); | |
277 config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING; | |
278 config_->ts_number_layers = 1; | |
279 config_->ts_rate_decimator[0] = 1; | |
280 config_->ts_periodicity = 1; | |
281 config_->ts_layer_id[0] = 0; | |
282 } else if (number_of_temporal_layers_ == 2) { | |
283 gof_.SetGofInfoVP9(kTemporalStructureMode2); | |
284 config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0101; | |
285 config_->ts_number_layers = 2; | |
286 config_->ts_rate_decimator[0] = 2; | |
287 config_->ts_rate_decimator[1] = 1; | |
288 config_->ts_periodicity = 2; | |
289 config_->ts_layer_id[0] = 0; | |
290 config_->ts_layer_id[1] = 1; | |
291 } else if (number_of_temporal_layers_ == 3) { | |
292 gof_.SetGofInfoVP9(kTemporalStructureMode3); | |
293 config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212; | |
294 config_->ts_number_layers = 3; | |
295 config_->ts_rate_decimator[0] = 4; | |
296 config_->ts_rate_decimator[1] = 2; | |
297 config_->ts_rate_decimator[2] = 1; | |
298 config_->ts_periodicity = 4; | |
299 config_->ts_layer_id[0] = 0; | |
300 config_->ts_layer_id[1] = 2; | |
301 config_->ts_layer_id[2] = 1; | |
302 config_->ts_layer_id[3] = 2; | |
303 } else { | |
304 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
305 } | |
306 | |
307 tl0_pic_idx_ = static_cast<uint8_t>(rand()); | |
308 | |
202 return InitAndSetControlSettings(inst); | 309 return InitAndSetControlSettings(inst); |
203 } | 310 } |
204 | 311 |
205 int VP9EncoderImpl::NumberOfThreads(int width, | 312 int VP9EncoderImpl::NumberOfThreads(int width, |
206 int height, | 313 int height, |
207 int number_of_cores) { | 314 int number_of_cores) { |
315 // For the current libvpx library, only 1 thread is supported when SVC is | |
316 // turned on. | |
317 if (number_of_temporal_layers_ > 1 || number_of_spatial_layers_ > 1) { | |
318 return 1; | |
319 } | |
320 | |
208 // Keep the number of encoder threads equal to the possible number of column | 321 // Keep the number of encoder threads equal to the possible number of column |
209 // tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS. | 322 // tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS. |
210 if (width * height >= 1280 * 720 && number_of_cores > 4) { | 323 if (width * height >= 1280 * 720 && number_of_cores > 4) { |
211 return 4; | 324 return 4; |
212 } else if (width * height >= 640 * 480 && number_of_cores > 2) { | 325 } else if (width * height >= 640 * 480 && number_of_cores > 2) { |
213 return 2; | 326 return 2; |
214 } else { | 327 } else { |
215 // 1 thread less than VGA. | 328 // 1 thread less than VGA. |
216 return 1; | 329 return 1; |
217 } | 330 } |
218 } | 331 } |
219 | 332 |
220 int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { | 333 int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { |
334 | |
335 config_->ss_number_layers = number_of_spatial_layers_; | |
336 | |
337 if (number_of_spatial_layers_ > 1) { | |
338 config_->rc_min_quantizer = 0; | |
339 config_->rc_max_quantizer = 63; | |
340 } | |
341 for (uint8_t i = 0; i < number_of_spatial_layers_; i++) { | |
342 svc_internal_.svc_params.max_quantizers[i] = config_->rc_max_quantizer; | |
343 svc_internal_.svc_params.min_quantizers[i] = config_->rc_min_quantizer; | |
344 /* 1:2 scaling in each dimension */ | |
stefan-webrtc
2015/07/09 14:48:59
Fix this comment.
åsapersson
2015/07/29 12:10:12
Done.
| |
345 svc_internal_.svc_params.scaling_factor_num[i] = | |
346 256 >> (number_of_spatial_layers_ - i - 1); | |
stefan-webrtc
2015/07/09 14:48:59
Can't we divide instead of shifting? I think it ma
åsapersson
2015/07/29 12:10:12
Done.
| |
347 svc_internal_.svc_params.scaling_factor_den[i] = 256; | |
348 } | |
349 | |
350 int ret = SetSvcRates(); | |
351 if (ret != WEBRTC_VIDEO_CODEC_OK) | |
352 return ret; | |
353 | |
221 if (vpx_codec_enc_init(encoder_, vpx_codec_vp9_cx(), config_, 0)) { | 354 if (vpx_codec_enc_init(encoder_, vpx_codec_vp9_cx(), config_, 0)) { |
222 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 355 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
223 } | 356 } |
224 // Only positive speeds, currently: 0 - 8. | 357 // Only positive speeds, currently: 0 - 8. |
225 // O means slowest/best quality, 8 means fastest/lower quality. | 358 // O means slowest/best quality, 8 means fastest/lower quality. |
226 cpu_speed_ = 7; | 359 cpu_speed_ = 7; |
227 // Note: some of these codec controls still use "VP8" in the control name. | 360 // Note: some of these codec controls still use "VP8" in the control name. |
228 // TODO(marpan): Update this in the next/future libvpx version. | 361 // TODO(marpan): Update this in the next/future libvpx version. |
229 vpx_codec_control(encoder_, VP8E_SET_CPUUSED, cpu_speed_); | 362 vpx_codec_control(encoder_, VP8E_SET_CPUUSED, cpu_speed_); |
230 vpx_codec_control(encoder_, VP8E_SET_MAX_INTRA_BITRATE_PCT, | 363 vpx_codec_control(encoder_, VP8E_SET_MAX_INTRA_BITRATE_PCT, |
231 rc_max_intra_target_); | 364 rc_max_intra_target_); |
232 vpx_codec_control(encoder_, VP9E_SET_AQ_MODE, | 365 vpx_codec_control(encoder_, VP9E_SET_AQ_MODE, |
233 inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0); | 366 inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0); |
367 | |
368 vpx_codec_control( | |
369 encoder_, VP9E_SET_SVC, | |
370 (number_of_temporal_layers_ > 1 || number_of_spatial_layers_ > 1) ? 1 | |
371 : 0); | |
372 if (number_of_spatial_layers_ > 1) { | |
373 vpx_codec_control(encoder_, VP9E_SET_SVC_PARAMETERS, | |
374 &svc_internal_.svc_params); | |
375 } | |
376 // Register callback for getting each spatial layer | |
377 vpx_codec_priv_output_cx_pkt_cb_pair_t cbp = { | |
378 VP9EncoderImpl::EncocderOutputCodedPacketCb, (void*)(this)}; | |
379 vpx_codec_control(encoder_, VP9E_REGISTER_CX_CALLBACK, (void*)(&cbp)); | |
380 | |
234 // Control function to set the number of column tiles in encoding a frame, in | 381 // Control function to set the number of column tiles in encoding a frame, in |
235 // log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns. | 382 // log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns. |
236 // The number tile columns will be capped by the encoder based on image size | 383 // The number tile columns will be capped by the encoder based on image size |
237 // (minimum width of tile column is 256 pixels, maximum is 4096). | 384 // (minimum width of tile column is 256 pixels, maximum is 4096). |
238 vpx_codec_control(encoder_, VP9E_SET_TILE_COLUMNS, (config_->g_threads >> 1)); | 385 vpx_codec_control(encoder_, VP9E_SET_TILE_COLUMNS, (config_->g_threads >> 1)); |
239 #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) | 386 #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) |
240 // Note denoiser is still off by default until further testing/optimization, | 387 // Note denoiser is still off by default until further testing/optimization, |
241 // i.e., codecSpecific.VP9.denoisingOn == 0. | 388 // i.e., codecSpecific.VP9.denoisingOn == 0. |
242 vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, | 389 vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, |
243 inst->codecSpecific.VP9.denoisingOn ? 1 : 0); | 390 inst->codecSpecific.VP9.denoisingOn ? 1 : 0); |
244 #endif | 391 #endif |
392 | |
245 inited_ = true; | 393 inited_ = true; |
246 return WEBRTC_VIDEO_CODEC_OK; | 394 return WEBRTC_VIDEO_CODEC_OK; |
247 } | 395 } |
248 | 396 |
249 uint32_t VP9EncoderImpl::MaxIntraTarget(uint32_t optimal_buffer_size) { | 397 uint32_t VP9EncoderImpl::MaxIntraTarget(uint32_t optimal_buffer_size) { |
250 // Set max to the optimal buffer level (normalized by target BR), | 398 // Set max to the optimal buffer level (normalized by target BR), |
251 // and scaled by a scale_par. | 399 // and scaled by a scale_par. |
252 // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps]. | 400 // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps]. |
253 // This value is presented in percentage of perFrameBw: | 401 // This value is presented in percentage of perFrameBw: |
254 // perFrameBw = targetBR[Kbps] * 1000 / framerate. | 402 // perFrameBw = targetBR[Kbps] * 1000 / framerate. |
(...skipping 18 matching lines...) Expand all Loading... | |
273 if (encoded_complete_callback_ == NULL) { | 421 if (encoded_complete_callback_ == NULL) { |
274 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 422 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
275 } | 423 } |
276 VideoFrameType frame_type = kDeltaFrame; | 424 VideoFrameType frame_type = kDeltaFrame; |
277 // We only support one stream at the moment. | 425 // We only support one stream at the moment. |
278 if (frame_types && frame_types->size() > 0) { | 426 if (frame_types && frame_types->size() > 0) { |
279 frame_type = (*frame_types)[0]; | 427 frame_type = (*frame_types)[0]; |
280 } | 428 } |
281 DCHECK_EQ(input_image.width(), static_cast<int>(raw_->d_w)); | 429 DCHECK_EQ(input_image.width(), static_cast<int>(raw_->d_w)); |
282 DCHECK_EQ(input_image.height(), static_cast<int>(raw_->d_h)); | 430 DCHECK_EQ(input_image.height(), static_cast<int>(raw_->d_h)); |
431 | |
432 // Set input image for use in the callback. | |
433 // This was necessary since you need some information from input_image. | |
434 // You can save only the necessary information (such as timestamp) instead of | |
435 // doing this. | |
436 input_image_ = &input_image; | |
437 | |
283 // Image in vpx_image_t format. | 438 // Image in vpx_image_t format. |
284 // Input image is const. VPX's raw image is not defined as const. | 439 // Input image is const. VPX's raw image is not defined as const. |
285 raw_->planes[VPX_PLANE_Y] = const_cast<uint8_t*>(input_image.buffer(kYPlane)); | 440 raw_->planes[VPX_PLANE_Y] = const_cast<uint8_t*>(input_image.buffer(kYPlane)); |
286 raw_->planes[VPX_PLANE_U] = const_cast<uint8_t*>(input_image.buffer(kUPlane)); | 441 raw_->planes[VPX_PLANE_U] = const_cast<uint8_t*>(input_image.buffer(kUPlane)); |
287 raw_->planes[VPX_PLANE_V] = const_cast<uint8_t*>(input_image.buffer(kVPlane)); | 442 raw_->planes[VPX_PLANE_V] = const_cast<uint8_t*>(input_image.buffer(kVPlane)); |
288 raw_->stride[VPX_PLANE_Y] = input_image.stride(kYPlane); | 443 raw_->stride[VPX_PLANE_Y] = input_image.stride(kYPlane); |
289 raw_->stride[VPX_PLANE_U] = input_image.stride(kUPlane); | 444 raw_->stride[VPX_PLANE_U] = input_image.stride(kUPlane); |
290 raw_->stride[VPX_PLANE_V] = input_image.stride(kVPlane); | 445 raw_->stride[VPX_PLANE_V] = input_image.stride(kVPlane); |
291 | 446 |
292 int flags = 0; | 447 int flags = 0; |
293 bool send_keyframe = (frame_type == kKeyFrame); | 448 bool send_keyframe = (frame_type == kKeyFrame); |
294 if (send_keyframe) { | 449 if (send_keyframe) { |
295 // Key frame request from caller. | 450 // Key frame request from caller. |
296 flags = VPX_EFLAG_FORCE_KF; | 451 flags = VPX_EFLAG_FORCE_KF; |
297 } | 452 } |
298 assert(codec_.maxFramerate > 0); | 453 assert(codec_.maxFramerate > 0); |
299 uint32_t duration = 90000 / codec_.maxFramerate; | 454 uint32_t duration = 90000 / codec_.maxFramerate; |
300 if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, | 455 if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, |
301 VPX_DL_REALTIME)) { | 456 VPX_DL_REALTIME)) { |
302 return WEBRTC_VIDEO_CODEC_ERROR; | 457 return WEBRTC_VIDEO_CODEC_ERROR; |
303 } | 458 } |
304 timestamp_ += duration; | 459 timestamp_ += duration; |
305 return GetEncodedPartitions(input_image); | 460 |
461 return WEBRTC_VIDEO_CODEC_OK; | |
306 } | 462 } |
307 | 463 |
308 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, | 464 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, |
309 const vpx_codec_cx_pkt& pkt, | 465 const vpx_codec_cx_pkt& pkt, |
310 uint32_t timestamp) { | 466 uint32_t timestamp) { |
311 assert(codec_specific != NULL); | 467 assert(codec_specific != NULL); |
312 codec_specific->codecType = kVideoCodecVP9; | 468 codec_specific->codecType = kVideoCodecVP9; |
313 CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9); | 469 CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9); |
470 // TODO(asapersson): Set correct values. | |
471 vp9_info->interPicPredicted = | |
472 (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? false : true; | |
473 vp9_info->flexibleMode = codec_.codecSpecific.VP9.flexibleMode; | |
474 vp9_info->beginningOfFrame = true; | |
475 vp9_info->endOfFrame = true; | |
476 vp9_info->ssDataAvailable = | |
477 (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? true : false; | |
478 | |
479 vpx_svc_layer_id_t lyr = {0}; | |
stefan-webrtc
2015/07/09 14:48:59
layer_id
åsapersson
2015/07/29 12:10:12
Done.
| |
480 vpx_codec_control(encoder_, VP9E_GET_SVC_LAYER_ID, &lyr); | |
481 | |
482 assert(number_of_temporal_layers_ > 0); | |
483 assert(number_of_spatial_layers_ > 0); | |
484 if (number_of_temporal_layers_ == 1) { | |
485 assert(lyr.temporal_layer_id == 0); | |
486 vp9_info->temporalIdx = kNoTemporalIdx; | |
487 } else { | |
488 vp9_info->temporalIdx = lyr.temporal_layer_id; | |
489 } | |
490 if (number_of_spatial_layers_ == 1) { | |
491 assert(lyr.spatial_layer_id == 0); | |
492 vp9_info->spatialIdx = kNoSpatialIdx; | |
493 } else { | |
494 vp9_info->spatialIdx = lyr.spatial_layer_id; | |
495 } | |
496 if (lyr.spatial_layer_id != 0) { | |
497 vp9_info->ssDataAvailable = false; | |
498 } | |
499 | |
500 if (vp9_info->flexibleMode) { | |
501 vp9_info->gofIdx = kNoGofIdx; | |
502 } else { | |
503 vp9_info->gofIdx = lyr.temporal_layer_id; | |
504 } | |
505 | |
506 // TODO(asapersson): this info has to be obtained from the encoder. | |
507 vp9_info->temporalUpSwitch = true; | |
508 | |
509 if (lyr.spatial_layer_id == 0) { | |
510 picture_id_ = (picture_id_ + 1) & 0x7FFF; | |
511 // TODO(asapersson): this info has to be obtained from the encoder. | |
512 vp9_info->interLayerPredicted = false; | |
513 } else { | |
514 // TODO(asapersson): this info has to be obtained from the encoder. | |
515 vp9_info->interLayerPredicted = true; | |
516 } | |
517 | |
314 vp9_info->pictureId = picture_id_; | 518 vp9_info->pictureId = picture_id_; |
315 vp9_info->keyIdx = kNoKeyIdx; | 519 |
316 vp9_info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0; | 520 if (!vp9_info->flexibleMode) { |
317 // TODO(marpan): Temporal layers are supported in the current VP9 version, | 521 if (lyr.temporal_layer_id == 0 && lyr.spatial_layer_id == 0) { |
318 // but for now use 1 temporal layer encoding. Will update this when temporal | 522 tl0_pic_idx_++; |
319 // layer support for VP9 is added in webrtc. | 523 } |
320 vp9_info->temporalIdx = kNoTemporalIdx; | 524 vp9_info->tl0PicIdx = tl0_pic_idx_; |
321 vp9_info->layerSync = false; | 525 } |
322 vp9_info->tl0PicIdx = kNoTl0PicIdx; | 526 |
323 picture_id_ = (picture_id_ + 1) & 0x7FFF; | 527 if (vp9_info->ssDataAvailable) { |
528 vp9_info->numSpatialLayers = number_of_spatial_layers_; | |
529 vp9_info->spatialLayerResolutionPresent = true; | |
530 for (uint8_t i = 0; i < vp9_info->numSpatialLayers; i++) { | |
531 vp9_info->width[i] = codec_.width * | |
532 svc_internal_.svc_params.scaling_factor_num[i] / | |
533 svc_internal_.svc_params.scaling_factor_den[i]; | |
534 vp9_info->height[i] = codec_.height * | |
535 svc_internal_.svc_params.scaling_factor_num[i] / | |
536 svc_internal_.svc_params.scaling_factor_den[i]; | |
537 } | |
538 if (!vp9_info->flexibleMode) { | |
539 vp9_info->gof.CopyGofInfoVP9(gof_); | |
540 } | |
541 } | |
324 } | 542 } |
325 | 543 |
326 int VP9EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image) { | 544 int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { |
327 vpx_codec_iter_t iter = NULL; | |
328 encoded_image_._length = 0; | 545 encoded_image_._length = 0; |
329 encoded_image_._frameType = kDeltaFrame; | 546 encoded_image_._frameType = kDeltaFrame; |
330 RTPFragmentationHeader frag_info; | 547 RTPFragmentationHeader frag_info; |
331 // Note: no data partitioning in VP9, so 1 partition only. We keep this | 548 // Note: no data partitioning in VP9, so 1 partition only. We keep this |
332 // fragmentation data for now, until VP9 packetizer is implemented. | 549 // fragmentation data for now, until VP9 packetizer is implemented. |
333 frag_info.VerifyAndAllocateFragmentationHeader(1); | 550 frag_info.VerifyAndAllocateFragmentationHeader(1); |
334 int part_idx = 0; | 551 int part_idx = 0; |
335 CodecSpecificInfo codec_specific; | 552 CodecSpecificInfo codec_specific; |
336 const vpx_codec_cx_pkt_t *pkt = NULL; | 553 |
337 while ((pkt = vpx_codec_get_cx_data(encoder_, &iter)) != NULL) { | 554 assert(pkt->kind == VPX_CODEC_CX_FRAME_PKT); |
338 switch (pkt->kind) { | 555 memcpy(&encoded_image_._buffer[encoded_image_._length], pkt->data.frame.buf, |
339 case VPX_CODEC_CX_FRAME_PKT: { | 556 pkt->data.frame.sz); |
340 memcpy(&encoded_image_._buffer[encoded_image_._length], | 557 frag_info.fragmentationOffset[part_idx] = encoded_image_._length; |
341 pkt->data.frame.buf, | 558 frag_info.fragmentationLength[part_idx] = |
342 pkt->data.frame.sz); | 559 static_cast<uint32_t>(pkt->data.frame.sz); |
343 frag_info.fragmentationOffset[part_idx] = encoded_image_._length; | 560 frag_info.fragmentationPlType[part_idx] = 0; |
344 frag_info.fragmentationLength[part_idx] = | 561 frag_info.fragmentationTimeDiff[part_idx] = 0; |
345 static_cast<uint32_t>(pkt->data.frame.sz); | 562 encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz); |
346 frag_info.fragmentationPlType[part_idx] = 0; | 563 assert(encoded_image_._length <= encoded_image_._size); |
347 frag_info.fragmentationTimeDiff[part_idx] = 0; | 564 |
348 encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz); | 565 // End of frame. |
349 assert(encoded_image_._length <= encoded_image_._size); | 566 if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) { |
350 break; | 567 // Check if encoded frame is a key frame. |
351 } | 568 if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) { |
352 default: { | 569 encoded_image_._frameType = kKeyFrame; |
353 break; | |
354 } | |
355 } | 570 } |
356 // End of frame. | 571 PopulateCodecSpecific(&codec_specific, *pkt, input_image_->timestamp()); |
357 if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) { | |
358 // Check if encoded frame is a key frame. | |
359 if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) { | |
360 encoded_image_._frameType = kKeyFrame; | |
361 } | |
362 PopulateCodecSpecific(&codec_specific, *pkt, input_image.timestamp()); | |
363 break; | |
364 } | |
365 } | 572 } |
366 if (encoded_image_._length > 0) { | 573 if (encoded_image_._length > 0) { |
367 TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_._length); | 574 TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_._length); |
368 encoded_image_._timeStamp = input_image.timestamp(); | 575 encoded_image_._timeStamp = input_image_->timestamp(); |
369 encoded_image_.capture_time_ms_ = input_image.render_time_ms(); | 576 encoded_image_.capture_time_ms_ = input_image_->render_time_ms(); |
370 encoded_image_._encodedHeight = raw_->d_h; | 577 encoded_image_._encodedHeight = raw_->d_h; |
371 encoded_image_._encodedWidth = raw_->d_w; | 578 encoded_image_._encodedWidth = raw_->d_w; |
372 encoded_complete_callback_->Encoded(encoded_image_, &codec_specific, | 579 encoded_complete_callback_->Encoded(encoded_image_, &codec_specific, |
373 &frag_info); | 580 &frag_info); |
374 } | 581 } |
375 return WEBRTC_VIDEO_CODEC_OK; | 582 return WEBRTC_VIDEO_CODEC_OK; |
376 } | 583 } |
377 | 584 |
378 int VP9EncoderImpl::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { | 585 int VP9EncoderImpl::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { |
379 return WEBRTC_VIDEO_CODEC_OK; | 586 return WEBRTC_VIDEO_CODEC_OK; |
380 } | 587 } |
381 | 588 |
382 int VP9EncoderImpl::RegisterEncodeCompleteCallback( | 589 int VP9EncoderImpl::RegisterEncodeCompleteCallback( |
383 EncodedImageCallback* callback) { | 590 EncodedImageCallback* callback) { |
(...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
553 decoder_ = NULL; | 760 decoder_ = NULL; |
554 } | 761 } |
555 // Releases buffers from the pool. Any buffers not in use are deleted. Buffers | 762 // Releases buffers from the pool. Any buffers not in use are deleted. Buffers |
556 // still referenced externally are deleted once fully released, not returning | 763 // still referenced externally are deleted once fully released, not returning |
557 // to the pool. | 764 // to the pool. |
558 frame_buffer_pool_.ClearPool(); | 765 frame_buffer_pool_.ClearPool(); |
559 inited_ = false; | 766 inited_ = false; |
560 return WEBRTC_VIDEO_CODEC_OK; | 767 return WEBRTC_VIDEO_CODEC_OK; |
561 } | 768 } |
562 } // namespace webrtc | 769 } // namespace webrtc |
OLD | NEW |