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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 50 if (width * height <= 352 * 288) | 50 if (width * height <= 352 * 288) |
| 51 return 5; | 51 return 5; |
| 52 else | 52 else |
| 53 return 7; | 53 return 7; |
| 54 } | 54 } |
| 55 | 55 |
| 56 VP9Encoder* VP9Encoder::Create() { | 56 VP9Encoder* VP9Encoder::Create() { |
| 57 return new VP9EncoderImpl(); | 57 return new VP9EncoderImpl(); |
| 58 } | 58 } |
| 59 | 59 |
| 60 void VP9EncoderImpl::EncoderOutputCodedPacketCallback(vpx_codec_cx_pkt* pkt, | |
| 61 void* user_data) { | |
| 62 VP9EncoderImpl* enc = (VP9EncoderImpl*)(user_data); | |
| 63 enc->GetEncodedLayerFrame(pkt); | |
| 64 } | |
| 65 | |
| 60 VP9EncoderImpl::VP9EncoderImpl() | 66 VP9EncoderImpl::VP9EncoderImpl() |
| 61 : encoded_image_(), | 67 : encoded_image_(), |
| 62 encoded_complete_callback_(NULL), | 68 encoded_complete_callback_(NULL), |
| 63 inited_(false), | 69 inited_(false), |
| 64 timestamp_(0), | 70 timestamp_(0), |
| 65 picture_id_(0), | 71 picture_id_(0), |
| 66 cpu_speed_(3), | 72 cpu_speed_(3), |
| 67 rc_max_intra_target_(0), | 73 rc_max_intra_target_(0), |
| 68 encoder_(NULL), | 74 encoder_(NULL), |
| 69 config_(NULL), | 75 config_(NULL), |
| 70 raw_(NULL) { | 76 raw_(NULL), |
| 77 input_image_(NULL), | |
| 78 tl0_pic_idx_(0), | |
| 79 gof_idx_(0), | |
| 80 num_temporal_layers_(0), | |
| 81 num_spatial_layers_(0) { | |
| 71 memset(&codec_, 0, sizeof(codec_)); | 82 memset(&codec_, 0, sizeof(codec_)); |
| 72 uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); | 83 uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); |
| 73 srand(seed); | 84 srand(seed); |
| 74 } | 85 } |
| 75 | 86 |
| 76 VP9EncoderImpl::~VP9EncoderImpl() { | 87 VP9EncoderImpl::~VP9EncoderImpl() { |
| 77 Release(); | 88 Release(); |
| 78 } | 89 } |
| 79 | 90 |
| 80 int VP9EncoderImpl::Release() { | 91 int VP9EncoderImpl::Release() { |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 94 config_ = NULL; | 105 config_ = NULL; |
| 95 } | 106 } |
| 96 if (raw_ != NULL) { | 107 if (raw_ != NULL) { |
| 97 vpx_img_free(raw_); | 108 vpx_img_free(raw_); |
| 98 raw_ = NULL; | 109 raw_ = NULL; |
| 99 } | 110 } |
| 100 inited_ = false; | 111 inited_ = false; |
| 101 return WEBRTC_VIDEO_CODEC_OK; | 112 return WEBRTC_VIDEO_CODEC_OK; |
| 102 } | 113 } |
| 103 | 114 |
| 115 bool VP9EncoderImpl::SetSvcRates() { | |
| 116 float rate_ratio[VPX_MAX_LAYERS] = {0}; | |
| 117 float total = 0; | |
| 118 uint8_t i = 0; | |
| 119 | |
| 120 if (num_spatial_layers_ > 1) { | |
| 121 for (i = 0; i < num_spatial_layers_; ++i) { | |
| 122 if (svc_internal_.svc_params.scaling_factor_num[i] <= 0 || | |
| 123 svc_internal_.svc_params.scaling_factor_den[i] <= 0) { | |
| 124 return false; | |
| 125 } | |
| 126 rate_ratio[i] = static_cast<float>( | |
| 127 svc_internal_.svc_params.scaling_factor_num[i]) / | |
| 128 svc_internal_.svc_params.scaling_factor_den[i]; | |
| 129 total += rate_ratio[i]; | |
| 130 } | |
| 131 } else { | |
| 132 rate_ratio[0] = total = 1; | |
| 133 } | |
| 134 assert(total >= 1.0f); | |
|
stefan-webrtc
2015/07/29 13:13:05
Hm, seems like there could be a risk that this doe
åsapersson
2015/07/30 11:42:19
Done.
| |
| 135 | |
| 136 for (i = 0; i < num_spatial_layers_; ++i) { | |
| 137 config_->ss_target_bitrate[i] = static_cast<unsigned int>( | |
| 138 config_->rc_target_bitrate * rate_ratio[i] / total); | |
|
stefan-webrtc
2015/07/29 13:13:05
Should this really divide by total? total is expec
åsapersson
2015/07/30 11:42:19
total will be >1 for num_spatial_layers_ > 1...
stefan-webrtc
2015/07/30 12:05:25
Right, my mistake.
| |
| 139 if (num_temporal_layers_ == 1) { | |
| 140 config_->layer_target_bitrate[0] = config_->ss_target_bitrate[i]; | |
| 141 } else if (num_temporal_layers_ == 2) { | |
| 142 config_->layer_target_bitrate[i * num_temporal_layers_] = | |
| 143 config_->ss_target_bitrate[i] * 2 / 3; | |
| 144 config_->layer_target_bitrate[i * num_temporal_layers_ + 1] = | |
| 145 config_->ss_target_bitrate[i]; | |
| 146 } else if (num_temporal_layers_ == 3) { | |
| 147 config_->layer_target_bitrate[i * num_temporal_layers_] = | |
| 148 config_->ss_target_bitrate[i] / 2; | |
| 149 config_->layer_target_bitrate[i * num_temporal_layers_ + 1] = | |
| 150 config_->layer_target_bitrate[i * num_temporal_layers_] + | |
| 151 (config_->ss_target_bitrate[i] / 4); | |
| 152 config_->layer_target_bitrate[i * num_temporal_layers_ + 2] = | |
| 153 config_->ss_target_bitrate[i]; | |
| 154 } else { | |
| 155 return false; | |
| 156 } | |
| 157 } | |
| 158 | |
| 159 if (num_spatial_layers_ == 1) { | |
|
stefan-webrtc
2015/07/29 13:13:05
Comment: Currently only support temporal layers if
åsapersson
2015/07/30 11:42:19
Added a comment.
| |
| 160 for (i = 0; i < num_temporal_layers_; ++i) { | |
| 161 config_->ts_target_bitrate[i] = config_->layer_target_bitrate[i]; | |
| 162 } | |
| 163 } | |
| 164 | |
| 165 return true; | |
| 166 } | |
| 167 | |
| 104 int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit, | 168 int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit, |
| 105 uint32_t new_framerate) { | 169 uint32_t new_framerate) { |
| 106 if (!inited_) { | 170 if (!inited_) { |
| 107 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 171 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 108 } | 172 } |
| 109 if (encoder_->err) { | 173 if (encoder_->err) { |
| 110 return WEBRTC_VIDEO_CODEC_ERROR; | 174 return WEBRTC_VIDEO_CODEC_ERROR; |
| 111 } | 175 } |
| 112 if (new_framerate < 1) { | 176 if (new_framerate < 1) { |
| 113 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 177 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; |
| 114 } | 178 } |
| 115 // Update bit rate | 179 // Update bit rate |
| 116 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { | 180 if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) { |
| 117 new_bitrate_kbit = codec_.maxBitrate; | 181 new_bitrate_kbit = codec_.maxBitrate; |
| 118 } | 182 } |
| 119 config_->rc_target_bitrate = new_bitrate_kbit; | 183 config_->rc_target_bitrate = new_bitrate_kbit; |
| 120 codec_.maxFramerate = new_framerate; | 184 codec_.maxFramerate = new_framerate; |
| 185 | |
| 186 if (!SetSvcRates()) { | |
| 187 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 188 } | |
| 189 | |
| 121 // Update encoder context | 190 // Update encoder context |
| 122 if (vpx_codec_enc_config_set(encoder_, config_)) { | 191 if (vpx_codec_enc_config_set(encoder_, config_)) { |
| 123 return WEBRTC_VIDEO_CODEC_ERROR; | 192 return WEBRTC_VIDEO_CODEC_ERROR; |
| 124 } | 193 } |
| 125 return WEBRTC_VIDEO_CODEC_OK; | 194 return WEBRTC_VIDEO_CODEC_OK; |
| 126 } | 195 } |
| 127 | 196 |
| 128 int VP9EncoderImpl::InitEncode(const VideoCodec* inst, | 197 int VP9EncoderImpl::InitEncode(const VideoCodec* inst, |
| 129 int number_of_cores, | 198 int number_of_cores, |
| 130 size_t /*max_payload_size*/) { | 199 size_t /*max_payload_size*/) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 151 if (encoder_ == NULL) { | 220 if (encoder_ == NULL) { |
| 152 encoder_ = new vpx_codec_ctx_t; | 221 encoder_ = new vpx_codec_ctx_t; |
| 153 } | 222 } |
| 154 if (config_ == NULL) { | 223 if (config_ == NULL) { |
| 155 config_ = new vpx_codec_enc_cfg_t; | 224 config_ = new vpx_codec_enc_cfg_t; |
| 156 } | 225 } |
| 157 timestamp_ = 0; | 226 timestamp_ = 0; |
| 158 if (&codec_ != inst) { | 227 if (&codec_ != inst) { |
| 159 codec_ = *inst; | 228 codec_ = *inst; |
| 160 } | 229 } |
| 230 | |
| 231 num_temporal_layers_ = inst->codecSpecific.VP9.numberOfTemporalLayers; | |
| 232 num_spatial_layers_ = inst->codecSpecific.VP9.numberOfSpatialLayers; | |
| 233 // For now, only support 1 spatial layer. | |
| 234 if (num_spatial_layers_ != 1) { | |
|
stefan-webrtc
2015/07/29 13:13:05
Does this mean one more than the base layer?
åsapersson
2015/07/30 11:42:19
Only one spatial layer.
| |
| 235 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 236 } | |
| 237 | |
| 161 // Random start 16 bits is enough. | 238 // Random start 16 bits is enough. |
| 162 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; | 239 picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; |
| 163 // Allocate memory for encoded image | 240 // Allocate memory for encoded image |
| 164 if (encoded_image_._buffer != NULL) { | 241 if (encoded_image_._buffer != NULL) { |
| 165 delete [] encoded_image_._buffer; | 242 delete [] encoded_image_._buffer; |
| 166 } | 243 } |
| 167 encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height); | 244 encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height); |
| 168 encoded_image_._buffer = new uint8_t[encoded_image_._size]; | 245 encoded_image_._buffer = new uint8_t[encoded_image_._size]; |
| 169 encoded_image_._completeFrame = true; | 246 encoded_image_._completeFrame = true; |
| 170 // Creating a wrapper to the image - setting image data to NULL. Actual | 247 // Creating a wrapper to the image - setting image data to NULL. Actual |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 202 if (inst->codecSpecific.VP9.keyFrameInterval > 0) { | 279 if (inst->codecSpecific.VP9.keyFrameInterval > 0) { |
| 203 config_->kf_mode = VPX_KF_AUTO; | 280 config_->kf_mode = VPX_KF_AUTO; |
| 204 config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval; | 281 config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval; |
| 205 } else { | 282 } else { |
| 206 config_->kf_mode = VPX_KF_DISABLED; | 283 config_->kf_mode = VPX_KF_DISABLED; |
| 207 } | 284 } |
| 208 // Determine number of threads based on the image size and #cores. | 285 // Determine number of threads based on the image size and #cores. |
| 209 config_->g_threads = NumberOfThreads(config_->g_w, | 286 config_->g_threads = NumberOfThreads(config_->g_w, |
| 210 config_->g_h, | 287 config_->g_h, |
| 211 number_of_cores); | 288 number_of_cores); |
| 289 | |
| 212 cpu_speed_ = GetCpuSpeed(config_->g_w, config_->g_h); | 290 cpu_speed_ = GetCpuSpeed(config_->g_w, config_->g_h); |
| 291 | |
| 292 // TODO(asapersson): Check configuration of temporal switch up. | |
| 293 if (num_temporal_layers_ == 1) { | |
| 294 gof_.SetGofInfoVP9(kTemporalStructureMode1); | |
| 295 config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING; | |
| 296 config_->ts_number_layers = 1; | |
| 297 config_->ts_rate_decimator[0] = 1; | |
| 298 config_->ts_periodicity = 1; | |
| 299 config_->ts_layer_id[0] = 0; | |
| 300 } else if (num_temporal_layers_ == 2) { | |
| 301 gof_.SetGofInfoVP9(kTemporalStructureMode2); | |
| 302 config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0101; | |
| 303 config_->ts_number_layers = 2; | |
| 304 config_->ts_rate_decimator[0] = 2; | |
| 305 config_->ts_rate_decimator[1] = 1; | |
| 306 config_->ts_periodicity = 2; | |
| 307 config_->ts_layer_id[0] = 0; | |
| 308 config_->ts_layer_id[1] = 1; | |
| 309 } else if (num_temporal_layers_ == 3) { | |
| 310 gof_.SetGofInfoVP9(kTemporalStructureMode3); | |
| 311 config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212; | |
| 312 config_->ts_number_layers = 3; | |
| 313 config_->ts_rate_decimator[0] = 4; | |
| 314 config_->ts_rate_decimator[1] = 2; | |
| 315 config_->ts_rate_decimator[2] = 1; | |
| 316 config_->ts_periodicity = 4; | |
| 317 config_->ts_layer_id[0] = 0; | |
| 318 config_->ts_layer_id[1] = 2; | |
| 319 config_->ts_layer_id[2] = 1; | |
| 320 config_->ts_layer_id[3] = 2; | |
| 321 } else { | |
| 322 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 323 } | |
|
stefan-webrtc
2015/07/29 13:13:05
Ideally I would like this code to be shared with t
åsapersson
2015/07/30 11:42:19
Leave for follow up cl?
stefan-webrtc
2015/07/30 12:05:25
Acknowledged.
| |
| 324 | |
| 325 tl0_pic_idx_ = static_cast<uint8_t>(rand()); | |
| 326 | |
| 213 return InitAndSetControlSettings(inst); | 327 return InitAndSetControlSettings(inst); |
| 214 } | 328 } |
| 215 | 329 |
| 216 int VP9EncoderImpl::NumberOfThreads(int width, | 330 int VP9EncoderImpl::NumberOfThreads(int width, |
| 217 int height, | 331 int height, |
| 218 int number_of_cores) { | 332 int number_of_cores) { |
| 333 // For the current libvpx library, only 1 thread is supported when SVC is | |
| 334 // turned on. | |
| 335 if (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) { | |
| 336 return 1; | |
| 337 } | |
| 338 | |
| 219 // Keep the number of encoder threads equal to the possible number of column | 339 // Keep the number of encoder threads equal to the possible number of column |
| 220 // tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS. | 340 // tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS. |
| 221 if (width * height >= 1280 * 720 && number_of_cores > 4) { | 341 if (width * height >= 1280 * 720 && number_of_cores > 4) { |
| 222 return 4; | 342 return 4; |
| 223 } else if (width * height >= 640 * 480 && number_of_cores > 2) { | 343 } else if (width * height >= 640 * 480 && number_of_cores > 2) { |
| 224 return 2; | 344 return 2; |
| 225 } else { | 345 } else { |
| 226 // 1 thread less than VGA. | 346 // 1 thread less than VGA. |
| 227 return 1; | 347 return 1; |
| 228 } | 348 } |
| 229 } | 349 } |
| 230 | 350 |
| 231 int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { | 351 int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) { |
| 352 | |
| 353 config_->ss_number_layers = num_spatial_layers_; | |
| 354 | |
| 355 if (num_spatial_layers_ > 1) { | |
| 356 config_->rc_min_quantizer = 0; | |
| 357 config_->rc_max_quantizer = 63; | |
| 358 } | |
| 359 int scaling_factor_num = 256; | |
| 360 for (int i = num_spatial_layers_ - 1; i >= 0; --i, scaling_factor_num /= 2) { | |
|
stefan-webrtc
2015/07/29 13:13:05
Move scaling_factor_num /= 2 to line 366 instead.
åsapersson
2015/07/30 11:42:19
Done.
| |
| 361 svc_internal_.svc_params.max_quantizers[i] = config_->rc_max_quantizer; | |
| 362 svc_internal_.svc_params.min_quantizers[i] = config_->rc_min_quantizer; | |
| 363 // 1:2 scaling in each dimension. | |
| 364 svc_internal_.svc_params.scaling_factor_num[i] = scaling_factor_num; | |
| 365 svc_internal_.svc_params.scaling_factor_den[i] = 256; | |
| 366 } | |
| 367 | |
| 368 if (!SetSvcRates()) { | |
| 369 return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | |
| 370 } | |
| 371 | |
| 232 if (vpx_codec_enc_init(encoder_, vpx_codec_vp9_cx(), config_, 0)) { | 372 if (vpx_codec_enc_init(encoder_, vpx_codec_vp9_cx(), config_, 0)) { |
| 233 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 373 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 234 } | 374 } |
| 235 vpx_codec_control(encoder_, VP8E_SET_CPUUSED, cpu_speed_); | 375 vpx_codec_control(encoder_, VP8E_SET_CPUUSED, cpu_speed_); |
| 236 vpx_codec_control(encoder_, VP8E_SET_MAX_INTRA_BITRATE_PCT, | 376 vpx_codec_control(encoder_, VP8E_SET_MAX_INTRA_BITRATE_PCT, |
| 237 rc_max_intra_target_); | 377 rc_max_intra_target_); |
| 238 vpx_codec_control(encoder_, VP9E_SET_AQ_MODE, | 378 vpx_codec_control(encoder_, VP9E_SET_AQ_MODE, |
| 239 inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0); | 379 inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0); |
| 380 | |
| 381 vpx_codec_control( | |
| 382 encoder_, VP9E_SET_SVC, | |
| 383 (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) ? 1 : 0); | |
| 384 if (num_spatial_layers_ > 1) { | |
| 385 vpx_codec_control(encoder_, VP9E_SET_SVC_PARAMETERS, | |
| 386 &svc_internal_.svc_params); | |
|
stefan-webrtc
2015/07/29 13:13:05
Should this not be called if num_temporal_layers_
åsapersson
2015/07/30 11:42:19
Done.
| |
| 387 } | |
| 388 // Register callback for getting each spatial layer. | |
| 389 vpx_codec_priv_output_cx_pkt_cb_pair_t cbp = { | |
| 390 VP9EncoderImpl::EncoderOutputCodedPacketCallback, (void*)(this)}; | |
| 391 vpx_codec_control(encoder_, VP9E_REGISTER_CX_CALLBACK, (void*)(&cbp)); | |
| 392 | |
| 240 // Control function to set the number of column tiles in encoding a frame, in | 393 // Control function to set the number of column tiles in encoding a frame, in |
| 241 // log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns. | 394 // log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns. |
| 242 // The number tile columns will be capped by the encoder based on image size | 395 // The number tile columns will be capped by the encoder based on image size |
| 243 // (minimum width of tile column is 256 pixels, maximum is 4096). | 396 // (minimum width of tile column is 256 pixels, maximum is 4096). |
| 244 vpx_codec_control(encoder_, VP9E_SET_TILE_COLUMNS, (config_->g_threads >> 1)); | 397 vpx_codec_control(encoder_, VP9E_SET_TILE_COLUMNS, (config_->g_threads >> 1)); |
| 245 #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) | 398 #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) |
| 246 // Note denoiser is still off by default until further testing/optimization, | 399 // Note denoiser is still off by default until further testing/optimization, |
| 247 // i.e., codecSpecific.VP9.denoisingOn == 0. | 400 // i.e., codecSpecific.VP9.denoisingOn == 0. |
| 248 vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, | 401 vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, |
| 249 inst->codecSpecific.VP9.denoisingOn ? 1 : 0); | 402 inst->codecSpecific.VP9.denoisingOn ? 1 : 0); |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 279 if (encoded_complete_callback_ == NULL) { | 432 if (encoded_complete_callback_ == NULL) { |
| 280 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 433 return WEBRTC_VIDEO_CODEC_UNINITIALIZED; |
| 281 } | 434 } |
| 282 VideoFrameType frame_type = kDeltaFrame; | 435 VideoFrameType frame_type = kDeltaFrame; |
| 283 // We only support one stream at the moment. | 436 // We only support one stream at the moment. |
| 284 if (frame_types && frame_types->size() > 0) { | 437 if (frame_types && frame_types->size() > 0) { |
| 285 frame_type = (*frame_types)[0]; | 438 frame_type = (*frame_types)[0]; |
| 286 } | 439 } |
| 287 DCHECK_EQ(input_image.width(), static_cast<int>(raw_->d_w)); | 440 DCHECK_EQ(input_image.width(), static_cast<int>(raw_->d_w)); |
| 288 DCHECK_EQ(input_image.height(), static_cast<int>(raw_->d_h)); | 441 DCHECK_EQ(input_image.height(), static_cast<int>(raw_->d_h)); |
| 442 | |
| 443 // Set input image for use in the callback. | |
| 444 // This was necessary since you need some information from input_image. | |
| 445 // You can save only the necessary information (such as timestamp) instead of | |
| 446 // doing this. | |
| 447 input_image_ = &input_image; | |
| 448 | |
| 289 // Image in vpx_image_t format. | 449 // Image in vpx_image_t format. |
| 290 // Input image is const. VPX's raw image is not defined as const. | 450 // Input image is const. VPX's raw image is not defined as const. |
| 291 raw_->planes[VPX_PLANE_Y] = const_cast<uint8_t*>(input_image.buffer(kYPlane)); | 451 raw_->planes[VPX_PLANE_Y] = const_cast<uint8_t*>(input_image.buffer(kYPlane)); |
| 292 raw_->planes[VPX_PLANE_U] = const_cast<uint8_t*>(input_image.buffer(kUPlane)); | 452 raw_->planes[VPX_PLANE_U] = const_cast<uint8_t*>(input_image.buffer(kUPlane)); |
| 293 raw_->planes[VPX_PLANE_V] = const_cast<uint8_t*>(input_image.buffer(kVPlane)); | 453 raw_->planes[VPX_PLANE_V] = const_cast<uint8_t*>(input_image.buffer(kVPlane)); |
| 294 raw_->stride[VPX_PLANE_Y] = input_image.stride(kYPlane); | 454 raw_->stride[VPX_PLANE_Y] = input_image.stride(kYPlane); |
| 295 raw_->stride[VPX_PLANE_U] = input_image.stride(kUPlane); | 455 raw_->stride[VPX_PLANE_U] = input_image.stride(kUPlane); |
| 296 raw_->stride[VPX_PLANE_V] = input_image.stride(kVPlane); | 456 raw_->stride[VPX_PLANE_V] = input_image.stride(kVPlane); |
| 297 | 457 |
| 298 int flags = 0; | 458 int flags = 0; |
| 299 bool send_keyframe = (frame_type == kKeyFrame); | 459 bool send_keyframe = (frame_type == kKeyFrame); |
| 300 if (send_keyframe) { | 460 if (send_keyframe) { |
| 301 // Key frame request from caller. | 461 // Key frame request from caller. |
| 302 flags = VPX_EFLAG_FORCE_KF; | 462 flags = VPX_EFLAG_FORCE_KF; |
| 303 } | 463 } |
| 304 assert(codec_.maxFramerate > 0); | 464 assert(codec_.maxFramerate > 0); |
| 305 uint32_t duration = 90000 / codec_.maxFramerate; | 465 uint32_t duration = 90000 / codec_.maxFramerate; |
| 306 if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, | 466 if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, |
| 307 VPX_DL_REALTIME)) { | 467 VPX_DL_REALTIME)) { |
| 308 return WEBRTC_VIDEO_CODEC_ERROR; | 468 return WEBRTC_VIDEO_CODEC_ERROR; |
| 309 } | 469 } |
| 310 timestamp_ += duration; | 470 timestamp_ += duration; |
| 311 return GetEncodedPartitions(input_image); | 471 |
| 472 return WEBRTC_VIDEO_CODEC_OK; | |
| 312 } | 473 } |
| 313 | 474 |
| 314 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, | 475 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, |
| 315 const vpx_codec_cx_pkt& pkt, | 476 const vpx_codec_cx_pkt& pkt, |
| 316 uint32_t timestamp) { | 477 uint32_t timestamp) { |
| 317 assert(codec_specific != NULL); | 478 assert(codec_specific != NULL); |
| 318 codec_specific->codecType = kVideoCodecVP9; | 479 codec_specific->codecType = kVideoCodecVP9; |
| 319 CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9); | 480 CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9); |
| 320 vp9_info->pictureId = picture_id_; | 481 // TODO(asapersson): Set correct values. |
| 321 vp9_info->keyIdx = kNoKeyIdx; | 482 vp9_info->inter_pic_predicted = |
| 322 vp9_info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0; | 483 (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? false : true; |
| 323 // TODO(marpan): Temporal layers are supported in the current VP9 version, | 484 vp9_info->flexible_mode = codec_.codecSpecific.VP9.flexibleMode; |
| 324 // but for now use 1 temporal layer encoding. Will update this when temporal | 485 vp9_info->beginning_of_frame = true; |
| 325 // layer support for VP9 is added in webrtc. | 486 vp9_info->end_of_frame = true; |
|
stefan-webrtc
2015/07/29 13:13:05
Seems like these two flags aren't really needed on
åsapersson
2015/07/30 11:42:19
Removed these settings from CodecSpecificInfo and
| |
| 326 vp9_info->temporalIdx = kNoTemporalIdx; | 487 vp9_info->ss_data_available = |
| 327 vp9_info->layerSync = false; | 488 (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? true : false; |
| 328 vp9_info->tl0PicIdx = kNoTl0PicIdx; | 489 |
| 329 picture_id_ = (picture_id_ + 1) & 0x7FFF; | 490 vpx_svc_layer_id_t layer_id = {0}; |
| 491 vpx_codec_control(encoder_, VP9E_GET_SVC_LAYER_ID, &layer_id); | |
|
stefan-webrtc
2015/07/29 13:13:05
Do you know how this works? Does it return the spa
åsapersson
2015/07/30 11:42:19
Yes it looks so.
| |
| 492 | |
| 493 assert(num_temporal_layers_ > 0); | |
| 494 assert(num_spatial_layers_ > 0); | |
| 495 if (num_temporal_layers_ == 1) { | |
| 496 assert(layer_id.temporal_layer_id == 0); | |
| 497 vp9_info->temporal_idx = kNoTemporalIdx; | |
| 498 } else { | |
| 499 vp9_info->temporal_idx = layer_id.temporal_layer_id; | |
| 500 } | |
| 501 if (num_spatial_layers_ == 1) { | |
| 502 assert(layer_id.spatial_layer_id == 0); | |
| 503 vp9_info->spatial_idx = kNoSpatialIdx; | |
| 504 } else { | |
| 505 vp9_info->spatial_idx = layer_id.spatial_layer_id; | |
| 506 } | |
| 507 if (layer_id.spatial_layer_id != 0) { | |
| 508 vp9_info->ss_data_available = false; | |
| 509 } | |
|
stefan-webrtc
2015/07/29 13:13:05
Seems like we should DCHECK(layer_id.spatial_layer
åsapersson
2015/07/30 11:42:19
Skipped this as discussed offline.
| |
| 510 | |
| 511 if (vp9_info->flexible_mode) { | |
| 512 vp9_info->gof_idx = kNoGofIdx; | |
| 513 } else { | |
| 514 vp9_info->gof_idx = gof_idx_++ % gof_.num_frames_in_gof; | |
| 515 } | |
| 516 | |
| 517 // TODO(asapersson): this info has to be obtained from the encoder. | |
| 518 vp9_info->temporal_up_switch = true; | |
| 519 | |
| 520 if (layer_id.spatial_layer_id == 0) { | |
| 521 picture_id_ = (picture_id_ + 1) & 0x7FFF; | |
| 522 // TODO(asapersson): this info has to be obtained from the encoder. | |
| 523 vp9_info->inter_layer_predicted = false; | |
| 524 } else { | |
| 525 // TODO(asapersson): this info has to be obtained from the encoder. | |
| 526 vp9_info->inter_layer_predicted = true; | |
| 527 } | |
| 528 | |
| 529 vp9_info->picture_id = picture_id_; | |
| 530 | |
| 531 if (!vp9_info->flexible_mode) { | |
| 532 if (layer_id.temporal_layer_id == 0 && layer_id.spatial_layer_id == 0) { | |
| 533 tl0_pic_idx_++; | |
| 534 } | |
| 535 vp9_info->tl0_pic_idx = tl0_pic_idx_; | |
| 536 } | |
| 537 | |
| 538 if (vp9_info->ss_data_available) { | |
| 539 vp9_info->num_spatial_layers = num_spatial_layers_; | |
| 540 vp9_info->spatial_layer_resolution_present = true; | |
| 541 for (uint8_t i = 0; i < vp9_info->num_spatial_layers; i++) { | |
|
stefan-webrtc
2015/07/29 13:13:05
++i
and make i an int.
åsapersson
2015/07/30 11:42:19
Changed to size_t which num_spatial_layers is.
| |
| 542 vp9_info->width[i] = codec_.width * | |
| 543 svc_internal_.svc_params.scaling_factor_num[i] / | |
| 544 svc_internal_.svc_params.scaling_factor_den[i]; | |
| 545 vp9_info->height[i] = codec_.height * | |
| 546 svc_internal_.svc_params.scaling_factor_num[i] / | |
| 547 svc_internal_.svc_params.scaling_factor_den[i]; | |
| 548 } | |
| 549 if (!vp9_info->flexible_mode) { | |
| 550 vp9_info->gof.CopyGofInfoVP9(gof_); | |
| 551 } | |
| 552 } | |
| 330 } | 553 } |
| 331 | 554 |
| 332 int VP9EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image) { | 555 int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { |
| 333 vpx_codec_iter_t iter = NULL; | |
| 334 encoded_image_._length = 0; | 556 encoded_image_._length = 0; |
| 335 encoded_image_._frameType = kDeltaFrame; | 557 encoded_image_._frameType = kDeltaFrame; |
| 336 RTPFragmentationHeader frag_info; | 558 RTPFragmentationHeader frag_info; |
| 337 // Note: no data partitioning in VP9, so 1 partition only. We keep this | 559 // Note: no data partitioning in VP9, so 1 partition only. We keep this |
| 338 // fragmentation data for now, until VP9 packetizer is implemented. | 560 // fragmentation data for now, until VP9 packetizer is implemented. |
| 339 frag_info.VerifyAndAllocateFragmentationHeader(1); | 561 frag_info.VerifyAndAllocateFragmentationHeader(1); |
| 340 int part_idx = 0; | 562 int part_idx = 0; |
| 341 CodecSpecificInfo codec_specific; | 563 CodecSpecificInfo codec_specific; |
| 342 const vpx_codec_cx_pkt_t *pkt = NULL; | 564 |
| 343 while ((pkt = vpx_codec_get_cx_data(encoder_, &iter)) != NULL) { | 565 assert(pkt->kind == VPX_CODEC_CX_FRAME_PKT); |
| 344 switch (pkt->kind) { | 566 memcpy(&encoded_image_._buffer[encoded_image_._length], pkt->data.frame.buf, |
| 345 case VPX_CODEC_CX_FRAME_PKT: { | 567 pkt->data.frame.sz); |
| 346 memcpy(&encoded_image_._buffer[encoded_image_._length], | 568 frag_info.fragmentationOffset[part_idx] = encoded_image_._length; |
| 347 pkt->data.frame.buf, | 569 frag_info.fragmentationLength[part_idx] = |
| 348 pkt->data.frame.sz); | 570 static_cast<uint32_t>(pkt->data.frame.sz); |
| 349 frag_info.fragmentationOffset[part_idx] = encoded_image_._length; | 571 frag_info.fragmentationPlType[part_idx] = 0; |
| 350 frag_info.fragmentationLength[part_idx] = | 572 frag_info.fragmentationTimeDiff[part_idx] = 0; |
| 351 static_cast<uint32_t>(pkt->data.frame.sz); | 573 encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz); |
| 352 frag_info.fragmentationPlType[part_idx] = 0; | 574 assert(encoded_image_._length <= encoded_image_._size); |
| 353 frag_info.fragmentationTimeDiff[part_idx] = 0; | 575 |
| 354 encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz); | 576 // End of frame. |
| 355 assert(encoded_image_._length <= encoded_image_._size); | 577 if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) { |
|
stefan-webrtc
2015/07/29 13:13:05
I doubt this check is needed. Feel free to try to
åsapersson
2015/07/30 11:42:19
Seems ok to remove, done.
| |
| 356 break; | 578 // Check if encoded frame is a key frame. |
| 357 } | 579 if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) { |
| 358 default: { | 580 encoded_image_._frameType = kKeyFrame; |
| 359 break; | |
| 360 } | |
| 361 } | 581 } |
| 362 // End of frame. | 582 PopulateCodecSpecific(&codec_specific, *pkt, input_image_->timestamp()); |
| 363 if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) { | |
| 364 // Check if encoded frame is a key frame. | |
| 365 if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) { | |
| 366 encoded_image_._frameType = kKeyFrame; | |
| 367 } | |
| 368 PopulateCodecSpecific(&codec_specific, *pkt, input_image.timestamp()); | |
| 369 break; | |
| 370 } | |
| 371 } | 583 } |
| 372 if (encoded_image_._length > 0) { | 584 if (encoded_image_._length > 0) { |
| 373 TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_._length); | 585 TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_._length); |
| 374 encoded_image_._timeStamp = input_image.timestamp(); | 586 encoded_image_._timeStamp = input_image_->timestamp(); |
| 375 encoded_image_.capture_time_ms_ = input_image.render_time_ms(); | 587 encoded_image_.capture_time_ms_ = input_image_->render_time_ms(); |
| 376 encoded_image_._encodedHeight = raw_->d_h; | 588 encoded_image_._encodedHeight = raw_->d_h; |
| 377 encoded_image_._encodedWidth = raw_->d_w; | 589 encoded_image_._encodedWidth = raw_->d_w; |
| 378 encoded_complete_callback_->Encoded(encoded_image_, &codec_specific, | 590 encoded_complete_callback_->Encoded(encoded_image_, &codec_specific, |
| 379 &frag_info); | 591 &frag_info); |
| 380 } | 592 } |
| 381 return WEBRTC_VIDEO_CODEC_OK; | 593 return WEBRTC_VIDEO_CODEC_OK; |
| 382 } | 594 } |
| 383 | 595 |
| 384 int VP9EncoderImpl::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { | 596 int VP9EncoderImpl::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { |
| 385 return WEBRTC_VIDEO_CODEC_OK; | 597 return WEBRTC_VIDEO_CODEC_OK; |
| 386 } | 598 } |
| 387 | 599 |
| 388 int VP9EncoderImpl::RegisterEncodeCompleteCallback( | 600 int VP9EncoderImpl::RegisterEncodeCompleteCallback( |
| 389 EncodedImageCallback* callback) { | 601 EncodedImageCallback* callback) { |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 559 decoder_ = NULL; | 771 decoder_ = NULL; |
| 560 } | 772 } |
| 561 // Releases buffers from the pool. Any buffers not in use are deleted. Buffers | 773 // Releases buffers from the pool. Any buffers not in use are deleted. Buffers |
| 562 // still referenced externally are deleted once fully released, not returning | 774 // still referenced externally are deleted once fully released, not returning |
| 563 // to the pool. | 775 // to the pool. |
| 564 frame_buffer_pool_.ClearPool(); | 776 frame_buffer_pool_.ClearPool(); |
| 565 inited_ = false; | 777 inited_ = false; |
| 566 return WEBRTC_VIDEO_CODEC_OK; | 778 return WEBRTC_VIDEO_CODEC_OK; |
| 567 } | 779 } |
| 568 } // namespace webrtc | 780 } // namespace webrtc |
| OLD | NEW |