Chromium Code Reviews| 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 |