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