| 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 47     return 7; | 47     return 7; | 
| 48 #endif | 48 #endif | 
| 49 } | 49 } | 
| 50 | 50 | 
| 51 VP9Encoder* VP9Encoder::Create() { | 51 VP9Encoder* VP9Encoder::Create() { | 
| 52   return new VP9EncoderImpl(); | 52   return new VP9EncoderImpl(); | 
| 53 } | 53 } | 
| 54 | 54 | 
| 55 void VP9EncoderImpl::EncoderOutputCodedPacketCallback(vpx_codec_cx_pkt* pkt, | 55 void VP9EncoderImpl::EncoderOutputCodedPacketCallback(vpx_codec_cx_pkt* pkt, | 
| 56                                                       void* user_data) { | 56                                                       void* user_data) { | 
| 57   VP9EncoderImpl* enc = (VP9EncoderImpl*)(user_data); | 57   VP9EncoderImpl* enc = static_cast<VP9EncoderImpl*>(user_data); | 
| 58   enc->GetEncodedLayerFrame(pkt); | 58   enc->GetEncodedLayerFrame(pkt); | 
| 59 } | 59 } | 
| 60 | 60 | 
| 61 VP9EncoderImpl::VP9EncoderImpl() | 61 VP9EncoderImpl::VP9EncoderImpl() | 
| 62     : encoded_image_(), | 62     : encoded_image_(), | 
| 63       encoded_complete_callback_(NULL), | 63       encoded_complete_callback_(NULL), | 
| 64       inited_(false), | 64       inited_(false), | 
| 65       timestamp_(0), | 65       timestamp_(0), | 
| 66       picture_id_(0), | 66       picture_id_(0), | 
| 67       cpu_speed_(3), | 67       cpu_speed_(3), | 
| (...skipping 13 matching lines...) Expand all  Loading... | 
| 81   uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); | 81   uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); | 
| 82   srand(seed); | 82   srand(seed); | 
| 83 } | 83 } | 
| 84 | 84 | 
| 85 VP9EncoderImpl::~VP9EncoderImpl() { | 85 VP9EncoderImpl::~VP9EncoderImpl() { | 
| 86   Release(); | 86   Release(); | 
| 87 } | 87 } | 
| 88 | 88 | 
| 89 int VP9EncoderImpl::Release() { | 89 int VP9EncoderImpl::Release() { | 
| 90   if (encoded_image_._buffer != NULL) { | 90   if (encoded_image_._buffer != NULL) { | 
| 91     delete [] encoded_image_._buffer; | 91     delete[] encoded_image_._buffer; | 
| 92     encoded_image_._buffer = NULL; | 92     encoded_image_._buffer = NULL; | 
| 93   } | 93   } | 
| 94   if (encoder_ != NULL) { | 94   if (encoder_ != NULL) { | 
| 95     if (vpx_codec_destroy(encoder_)) { | 95     if (vpx_codec_destroy(encoder_)) { | 
| 96       return WEBRTC_VIDEO_CODEC_MEMORY; | 96       return WEBRTC_VIDEO_CODEC_MEMORY; | 
| 97     } | 97     } | 
| 98     delete encoder_; | 98     delete encoder_; | 
| 99     encoder_ = NULL; | 99     encoder_ = NULL; | 
| 100   } | 100   } | 
| 101   if (config_ != NULL) { | 101   if (config_ != NULL) { | 
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 260   if (&codec_ != inst) { | 260   if (&codec_ != inst) { | 
| 261     codec_ = *inst; | 261     codec_ = *inst; | 
| 262   } | 262   } | 
| 263 | 263 | 
| 264   num_spatial_layers_ = inst->codecSpecific.VP9.numberOfSpatialLayers; | 264   num_spatial_layers_ = inst->codecSpecific.VP9.numberOfSpatialLayers; | 
| 265   num_temporal_layers_ = inst->codecSpecific.VP9.numberOfTemporalLayers; | 265   num_temporal_layers_ = inst->codecSpecific.VP9.numberOfTemporalLayers; | 
| 266   if (num_temporal_layers_ == 0) | 266   if (num_temporal_layers_ == 0) | 
| 267     num_temporal_layers_ = 1; | 267     num_temporal_layers_ = 1; | 
| 268 | 268 | 
| 269   // Random start 16 bits is enough. | 269   // Random start 16 bits is enough. | 
| 270   picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF; | 270   picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;  // NOLINT | 
| 271   // Allocate memory for encoded image | 271   // Allocate memory for encoded image | 
| 272   if (encoded_image_._buffer != NULL) { | 272   if (encoded_image_._buffer != NULL) { | 
| 273     delete [] encoded_image_._buffer; | 273     delete[] encoded_image_._buffer; | 
| 274   } | 274   } | 
| 275   encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height); | 275   encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height); | 
| 276   encoded_image_._buffer = new uint8_t[encoded_image_._size]; | 276   encoded_image_._buffer = new uint8_t[encoded_image_._size]; | 
| 277   encoded_image_._completeFrame = true; | 277   encoded_image_._completeFrame = true; | 
| 278   // Creating a wrapper to the image - setting image data to NULL. Actual | 278   // Creating a wrapper to the image - setting image data to NULL. Actual | 
| 279   // pointer will be set in encode. Setting align to 1, as it is meaningless | 279   // pointer will be set in encode. Setting align to 1, as it is meaningless | 
| 280   // (actual memory is not allocated). | 280   // (actual memory is not allocated). | 
| 281   raw_ = vpx_img_wrap(NULL, VPX_IMG_FMT_I420, codec_.width, codec_.height, | 281   raw_ = vpx_img_wrap(NULL, VPX_IMG_FMT_I420, codec_.width, codec_.height, 1, | 
| 282                       1, NULL); | 282                       NULL); | 
| 283   // Populate encoder configuration with default values. | 283   // Populate encoder configuration with default values. | 
| 284   if (vpx_codec_enc_config_default(vpx_codec_vp9_cx(), config_, 0)) { | 284   if (vpx_codec_enc_config_default(vpx_codec_vp9_cx(), config_, 0)) { | 
| 285     return WEBRTC_VIDEO_CODEC_ERROR; | 285     return WEBRTC_VIDEO_CODEC_ERROR; | 
| 286   } | 286   } | 
| 287   config_->g_w = codec_.width; | 287   config_->g_w = codec_.width; | 
| 288   config_->g_h = codec_.height; | 288   config_->g_h = codec_.height; | 
| 289   config_->rc_target_bitrate = inst->startBitrate;  // in kbit/s | 289   config_->rc_target_bitrate = inst->startBitrate;  // in kbit/s | 
| 290   config_->g_error_resilient = 1; | 290   config_->g_error_resilient = 1; | 
| 291   // Setting the time base of the codec. | 291   // Setting the time base of the codec. | 
| 292   config_->g_timebase.num = 1; | 292   config_->g_timebase.num = 1; | 
| 293   config_->g_timebase.den = 90000; | 293   config_->g_timebase.den = 90000; | 
| 294   config_->g_lag_in_frames = 0;  // 0- no frame lagging | 294   config_->g_lag_in_frames = 0;  // 0- no frame lagging | 
| 295   config_->g_threads = 1; | 295   config_->g_threads = 1; | 
| 296   // Rate control settings. | 296   // Rate control settings. | 
| 297   config_->rc_dropframe_thresh = inst->codecSpecific.VP9.frameDroppingOn ? | 297   config_->rc_dropframe_thresh = | 
| 298       30 : 0; | 298       inst->codecSpecific.VP9.frameDroppingOn ? 30 : 0; | 
| 299   config_->rc_end_usage = VPX_CBR; | 299   config_->rc_end_usage = VPX_CBR; | 
| 300   config_->g_pass = VPX_RC_ONE_PASS; | 300   config_->g_pass = VPX_RC_ONE_PASS; | 
| 301   config_->rc_min_quantizer = 2; | 301   config_->rc_min_quantizer = 2; | 
| 302   config_->rc_max_quantizer = 52; | 302   config_->rc_max_quantizer = 52; | 
| 303   config_->rc_undershoot_pct = 50; | 303   config_->rc_undershoot_pct = 50; | 
| 304   config_->rc_overshoot_pct = 50; | 304   config_->rc_overshoot_pct = 50; | 
| 305   config_->rc_buf_initial_sz = 500; | 305   config_->rc_buf_initial_sz = 500; | 
| 306   config_->rc_buf_optimal_sz = 600; | 306   config_->rc_buf_optimal_sz = 600; | 
| 307   config_->rc_buf_sz = 1000; | 307   config_->rc_buf_sz = 1000; | 
| 308   // Set the maximum target size of any key-frame. | 308   // Set the maximum target size of any key-frame. | 
| 309   rc_max_intra_target_ = MaxIntraTarget(config_->rc_buf_optimal_sz); | 309   rc_max_intra_target_ = MaxIntraTarget(config_->rc_buf_optimal_sz); | 
| 310   if (inst->codecSpecific.VP9.keyFrameInterval  > 0) { | 310   if (inst->codecSpecific.VP9.keyFrameInterval > 0) { | 
| 311     config_->kf_mode = VPX_KF_AUTO; | 311     config_->kf_mode = VPX_KF_AUTO; | 
| 312     config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval; | 312     config_->kf_max_dist = inst->codecSpecific.VP9.keyFrameInterval; | 
| 313     // Needs to be set (in svc mode) to get correct periodic key frame interval | 313     // Needs to be set (in svc mode) to get correct periodic key frame interval | 
| 314     // (will have no effect in non-svc). | 314     // (will have no effect in non-svc). | 
| 315     config_->kf_min_dist = config_->kf_max_dist; | 315     config_->kf_min_dist = config_->kf_max_dist; | 
| 316   } else { | 316   } else { | 
| 317     config_->kf_mode = VPX_KF_DISABLED; | 317     config_->kf_mode = VPX_KF_DISABLED; | 
| 318   } | 318   } | 
| 319   config_->rc_resize_allowed = inst->codecSpecific.VP9.automaticResizeOn ? | 319   config_->rc_resize_allowed = | 
| 320       1 : 0; | 320       inst->codecSpecific.VP9.automaticResizeOn ? 1 : 0; | 
| 321   // Determine number of threads based on the image size and #cores. | 321   // Determine number of threads based on the image size and #cores. | 
| 322   config_->g_threads = NumberOfThreads(config_->g_w, | 322   config_->g_threads = | 
| 323                                        config_->g_h, | 323       NumberOfThreads(config_->g_w, config_->g_h, number_of_cores); | 
| 324                                        number_of_cores); |  | 
| 325 | 324 | 
| 326   cpu_speed_ = GetCpuSpeed(config_->g_w, config_->g_h); | 325   cpu_speed_ = GetCpuSpeed(config_->g_w, config_->g_h); | 
| 327 | 326 | 
| 328   // TODO(asapersson): Check configuration of temporal switch up and increase | 327   // TODO(asapersson): Check configuration of temporal switch up and increase | 
| 329   // pattern length. | 328   // pattern length. | 
| 330   is_flexible_mode_ = inst->codecSpecific.VP9.flexibleMode; | 329   is_flexible_mode_ = inst->codecSpecific.VP9.flexibleMode; | 
| 331   if (is_flexible_mode_) { | 330   if (is_flexible_mode_) { | 
| 332     config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; | 331     config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; | 
| 333     config_->ts_number_layers = num_temporal_layers_; | 332     config_->ts_number_layers = num_temporal_layers_; | 
| 334     if (codec_.mode == kScreensharing) | 333     if (codec_.mode == kScreensharing) | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 358     config_->ts_rate_decimator[2] = 1; | 357     config_->ts_rate_decimator[2] = 1; | 
| 359     config_->ts_periodicity = 4; | 358     config_->ts_periodicity = 4; | 
| 360     config_->ts_layer_id[0] = 0; | 359     config_->ts_layer_id[0] = 0; | 
| 361     config_->ts_layer_id[1] = 2; | 360     config_->ts_layer_id[1] = 2; | 
| 362     config_->ts_layer_id[2] = 1; | 361     config_->ts_layer_id[2] = 1; | 
| 363     config_->ts_layer_id[3] = 2; | 362     config_->ts_layer_id[3] = 2; | 
| 364   } else { | 363   } else { | 
| 365     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 364     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 
| 366   } | 365   } | 
| 367 | 366 | 
| 368   tl0_pic_idx_ = static_cast<uint8_t>(rand()); | 367   tl0_pic_idx_ = static_cast<uint8_t>(rand());  // NOLINT | 
| 369 | 368 | 
| 370   return InitAndSetControlSettings(inst); | 369   return InitAndSetControlSettings(inst); | 
| 371 } | 370 } | 
| 372 | 371 | 
| 373 int VP9EncoderImpl::NumberOfThreads(int width, | 372 int VP9EncoderImpl::NumberOfThreads(int width, | 
| 374                                     int height, | 373                                     int height, | 
| 375                                     int number_of_cores) { | 374                                     int number_of_cores) { | 
| 376   // Keep the number of encoder threads equal to the possible number of column | 375   // Keep the number of encoder threads equal to the possible number of column | 
| 377   // tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS. | 376   // tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS. | 
| 378   if (width * height >= 1280 * 720 && number_of_cores > 4) { | 377   if (width * height >= 1280 * 720 && number_of_cores > 4) { | 
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 425 | 424 | 
| 426   vpx_codec_control( | 425   vpx_codec_control( | 
| 427       encoder_, VP9E_SET_SVC, | 426       encoder_, VP9E_SET_SVC, | 
| 428       (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) ? 1 : 0); | 427       (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) ? 1 : 0); | 
| 429   if (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) { | 428   if (num_temporal_layers_ > 1 || num_spatial_layers_ > 1) { | 
| 430     vpx_codec_control(encoder_, VP9E_SET_SVC_PARAMETERS, | 429     vpx_codec_control(encoder_, VP9E_SET_SVC_PARAMETERS, | 
| 431                       &svc_internal_.svc_params); | 430                       &svc_internal_.svc_params); | 
| 432   } | 431   } | 
| 433   // Register callback for getting each spatial layer. | 432   // Register callback for getting each spatial layer. | 
| 434   vpx_codec_priv_output_cx_pkt_cb_pair_t cbp = { | 433   vpx_codec_priv_output_cx_pkt_cb_pair_t cbp = { | 
| 435       VP9EncoderImpl::EncoderOutputCodedPacketCallback, (void*)(this)}; | 434       VP9EncoderImpl::EncoderOutputCodedPacketCallback, | 
| 436   vpx_codec_control(encoder_, VP9E_REGISTER_CX_CALLBACK, (void*)(&cbp)); | 435       reinterpret_cast<void*>(this)}; | 
|  | 436   vpx_codec_control(encoder_, VP9E_REGISTER_CX_CALLBACK, | 
|  | 437                     reinterpret_cast<void*>(&cbp)); | 
| 437 | 438 | 
| 438   // Control function to set the number of column tiles in encoding a frame, in | 439   // Control function to set the number of column tiles in encoding a frame, in | 
| 439   // log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns. | 440   // log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns. | 
| 440   // The number tile columns will be capped by the encoder based on image size | 441   // The number tile columns will be capped by the encoder based on image size | 
| 441   // (minimum width of tile column is 256 pixels, maximum is 4096). | 442   // (minimum width of tile column is 256 pixels, maximum is 4096). | 
| 442   vpx_codec_control(encoder_, VP9E_SET_TILE_COLUMNS, (config_->g_threads >> 1)); | 443   vpx_codec_control(encoder_, VP9E_SET_TILE_COLUMNS, (config_->g_threads >> 1)); | 
| 443 #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) | 444 #if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64) | 
| 444   // Note denoiser is still off by default until further testing/optimization, | 445   // Note denoiser is still off by default until further testing/optimization, | 
| 445   // i.e., codecSpecific.VP9.denoisingOn == 0. | 446   // i.e., codecSpecific.VP9.denoisingOn == 0. | 
| 446   vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, | 447   vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY, | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 461   // and scaled by a scale_par. | 462   // and scaled by a scale_par. | 
| 462   // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps]. | 463   // Max target size = scale_par * optimal_buffer_size * targetBR[Kbps]. | 
| 463   // This value is presented in percentage of perFrameBw: | 464   // This value is presented in percentage of perFrameBw: | 
| 464   // perFrameBw = targetBR[Kbps] * 1000 / framerate. | 465   // perFrameBw = targetBR[Kbps] * 1000 / framerate. | 
| 465   // The target in % is as follows: | 466   // The target in % is as follows: | 
| 466   float scale_par = 0.5; | 467   float scale_par = 0.5; | 
| 467   uint32_t target_pct = | 468   uint32_t target_pct = | 
| 468       optimal_buffer_size * scale_par * codec_.maxFramerate / 10; | 469       optimal_buffer_size * scale_par * codec_.maxFramerate / 10; | 
| 469   // Don't go below 3 times the per frame bandwidth. | 470   // Don't go below 3 times the per frame bandwidth. | 
| 470   const uint32_t min_intra_size = 300; | 471   const uint32_t min_intra_size = 300; | 
| 471   return (target_pct < min_intra_size) ? min_intra_size: target_pct; | 472   return (target_pct < min_intra_size) ? min_intra_size : target_pct; | 
| 472 } | 473 } | 
| 473 | 474 | 
| 474 int VP9EncoderImpl::Encode(const VideoFrame& input_image, | 475 int VP9EncoderImpl::Encode(const VideoFrame& input_image, | 
| 475                            const CodecSpecificInfo* codec_specific_info, | 476                            const CodecSpecificInfo* codec_specific_info, | 
| 476                            const std::vector<FrameType>* frame_types) { | 477                            const std::vector<FrameType>* frame_types) { | 
| 477   if (!inited_) { | 478   if (!inited_) { | 
| 478     return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 479     return WEBRTC_VIDEO_CODEC_UNINITIALIZED; | 
| 479   } | 480   } | 
| 480   if (input_image.IsZeroSize()) { | 481   if (input_image.IsZeroSize()) { | 
| 481     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 482     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 540   if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, | 541   if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, | 
| 541                        VPX_DL_REALTIME)) { | 542                        VPX_DL_REALTIME)) { | 
| 542     return WEBRTC_VIDEO_CODEC_ERROR; | 543     return WEBRTC_VIDEO_CODEC_ERROR; | 
| 543   } | 544   } | 
| 544   timestamp_ += duration; | 545   timestamp_ += duration; | 
| 545 | 546 | 
| 546   return WEBRTC_VIDEO_CODEC_OK; | 547   return WEBRTC_VIDEO_CODEC_OK; | 
| 547 } | 548 } | 
| 548 | 549 | 
| 549 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, | 550 void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, | 
| 550                                        const vpx_codec_cx_pkt& pkt, | 551                                            const vpx_codec_cx_pkt& pkt, | 
| 551                                        uint32_t timestamp) { | 552                                            uint32_t timestamp) { | 
| 552   assert(codec_specific != NULL); | 553   assert(codec_specific != NULL); | 
| 553   codec_specific->codecType = kVideoCodecVP9; | 554   codec_specific->codecType = kVideoCodecVP9; | 
| 554   CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9); | 555   CodecSpecificInfoVP9* vp9_info = &(codec_specific->codecSpecific.VP9); | 
| 555   // TODO(asapersson): Set correct value. | 556   // TODO(asapersson): Set correct value. | 
| 556   vp9_info->inter_pic_predicted = | 557   vp9_info->inter_pic_predicted = | 
| 557       (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? false : true; | 558       (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? false : true; | 
| 558   vp9_info->flexible_mode = codec_.codecSpecific.VP9.flexibleMode; | 559   vp9_info->flexible_mode = codec_.codecSpecific.VP9.flexibleMode; | 
| 559   vp9_info->ss_data_available = ((pkt.data.frame.flags & VPX_FRAME_IS_KEY) && | 560   vp9_info->ss_data_available = ((pkt.data.frame.flags & VPX_FRAME_IS_KEY) && | 
| 560                                  !codec_.codecSpecific.VP9.flexibleMode) | 561                                  !codec_.codecSpecific.VP9.flexibleMode) | 
| 561                                     ? true | 562                                     ? true | 
| 562                                     : false; | 563                                     : false; | 
| 563 | 564 | 
| 564   vpx_svc_layer_id_t layer_id = {0}; | 565   vpx_svc_layer_id_t layer_id = {0}; | 
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 850   if (inst == NULL) { | 851   if (inst == NULL) { | 
| 851     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 852     return WEBRTC_VIDEO_CODEC_ERR_PARAMETER; | 
| 852   } | 853   } | 
| 853   int ret_val = Release(); | 854   int ret_val = Release(); | 
| 854   if (ret_val < 0) { | 855   if (ret_val < 0) { | 
| 855     return ret_val; | 856     return ret_val; | 
| 856   } | 857   } | 
| 857   if (decoder_ == NULL) { | 858   if (decoder_ == NULL) { | 
| 858     decoder_ = new vpx_codec_ctx_t; | 859     decoder_ = new vpx_codec_ctx_t; | 
| 859   } | 860   } | 
| 860   vpx_codec_dec_cfg_t  cfg; | 861   vpx_codec_dec_cfg_t cfg; | 
| 861   // Setting number of threads to a constant value (1) | 862   // Setting number of threads to a constant value (1) | 
| 862   cfg.threads = 1; | 863   cfg.threads = 1; | 
| 863   cfg.h = cfg.w = 0;  // set after decode | 864   cfg.h = cfg.w = 0;  // set after decode | 
| 864   vpx_codec_flags_t flags = 0; | 865   vpx_codec_flags_t flags = 0; | 
| 865   if (vpx_codec_dec_init(decoder_, vpx_codec_vp9_dx(), &cfg, flags)) { | 866   if (vpx_codec_dec_init(decoder_, vpx_codec_vp9_dx(), &cfg, flags)) { | 
| 866     return WEBRTC_VIDEO_CODEC_MEMORY; | 867     return WEBRTC_VIDEO_CODEC_MEMORY; | 
| 867   } | 868   } | 
| 868   if (&codec_ != inst) { | 869   if (&codec_ != inst) { | 
| 869     // Save VideoCodec instance for later; mainly for duplicating the decoder. | 870     // Save VideoCodec instance for later; mainly for duplicating the decoder. | 
| 870     codec_ = *inst; | 871     codec_ = *inst; | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 903     } | 904     } | 
| 904   } | 905   } | 
| 905   vpx_codec_iter_t iter = NULL; | 906   vpx_codec_iter_t iter = NULL; | 
| 906   vpx_image_t* img; | 907   vpx_image_t* img; | 
| 907   uint8_t* buffer = input_image._buffer; | 908   uint8_t* buffer = input_image._buffer; | 
| 908   if (input_image._length == 0) { | 909   if (input_image._length == 0) { | 
| 909     buffer = NULL;  // Triggers full frame concealment. | 910     buffer = NULL;  // Triggers full frame concealment. | 
| 910   } | 911   } | 
| 911   // During decode libvpx may get and release buffers from |frame_buffer_pool_|. | 912   // During decode libvpx may get and release buffers from |frame_buffer_pool_|. | 
| 912   // In practice libvpx keeps a few (~3-4) buffers alive at a time. | 913   // In practice libvpx keeps a few (~3-4) buffers alive at a time. | 
| 913   if (vpx_codec_decode(decoder_, | 914   if (vpx_codec_decode(decoder_, buffer, | 
| 914                        buffer, | 915                        static_cast<unsigned int>(input_image._length), 0, | 
| 915                        static_cast<unsigned int>(input_image._length), |  | 
| 916                        0, |  | 
| 917                        VPX_DL_REALTIME)) { | 916                        VPX_DL_REALTIME)) { | 
| 918     return WEBRTC_VIDEO_CODEC_ERROR; | 917     return WEBRTC_VIDEO_CODEC_ERROR; | 
| 919   } | 918   } | 
| 920   // |img->fb_priv| contains the image data, a reference counted Vp9FrameBuffer. | 919   // |img->fb_priv| contains the image data, a reference counted Vp9FrameBuffer. | 
| 921   // It may be released by libvpx during future vpx_codec_decode or | 920   // It may be released by libvpx during future vpx_codec_decode or | 
| 922   // vpx_codec_destroy calls. | 921   // vpx_codec_destroy calls. | 
| 923   img = vpx_codec_get_frame(decoder_, &iter); | 922   img = vpx_codec_get_frame(decoder_, &iter); | 
| 924   int ret = ReturnFrame(img, input_image._timeStamp); | 923   int ret = ReturnFrame(img, input_image._timeStamp); | 
| 925   if (ret != 0) { | 924   if (ret != 0) { | 
| 926     return ret; | 925     return ret; | 
| 927   } | 926   } | 
| 928   return WEBRTC_VIDEO_CODEC_OK; | 927   return WEBRTC_VIDEO_CODEC_OK; | 
| 929 } | 928 } | 
| 930 | 929 | 
| 931 int VP9DecoderImpl::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) { | 930 int VP9DecoderImpl::ReturnFrame(const vpx_image_t* img, uint32_t timestamp) { | 
| 932   if (img == NULL) { | 931   if (img == NULL) { | 
| 933     // Decoder OK and NULL image => No show frame. | 932     // Decoder OK and NULL image => No show frame. | 
| 934     return WEBRTC_VIDEO_CODEC_NO_OUTPUT; | 933     return WEBRTC_VIDEO_CODEC_NO_OUTPUT; | 
| 935   } | 934   } | 
| 936 | 935 | 
| 937   // This buffer contains all of |img|'s image data, a reference counted | 936   // This buffer contains all of |img|'s image data, a reference counted | 
| 938   // Vp9FrameBuffer. (libvpx is done with the buffers after a few | 937   // Vp9FrameBuffer. (libvpx is done with the buffers after a few | 
| 939   // vpx_codec_decode calls or vpx_codec_destroy). | 938   // vpx_codec_decode calls or vpx_codec_destroy). | 
| 940   Vp9FrameBufferPool::Vp9FrameBuffer* img_buffer = | 939   Vp9FrameBufferPool::Vp9FrameBuffer* img_buffer = | 
| 941       static_cast<Vp9FrameBufferPool::Vp9FrameBuffer*>(img->fb_priv); | 940       static_cast<Vp9FrameBufferPool::Vp9FrameBuffer*>(img->fb_priv); | 
| 942   // The buffer can be used directly by the VideoFrame (without copy) by | 941   // The buffer can be used directly by the VideoFrame (without copy) by | 
| 943   // using a WrappedI420Buffer. | 942   // using a WrappedI420Buffer. | 
| 944   rtc::scoped_refptr<WrappedI420Buffer> img_wrapped_buffer( | 943   rtc::scoped_refptr<WrappedI420Buffer> img_wrapped_buffer( | 
| 945       new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( | 944       new rtc::RefCountedObject<webrtc::WrappedI420Buffer>( | 
| 946           img->d_w, img->d_h, | 945           img->d_w, img->d_h, img->planes[VPX_PLANE_Y], | 
| 947           img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y], | 946           img->stride[VPX_PLANE_Y], img->planes[VPX_PLANE_U], | 
| 948           img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U], | 947           img->stride[VPX_PLANE_U], img->planes[VPX_PLANE_V], | 
| 949           img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V], | 948           img->stride[VPX_PLANE_V], | 
| 950           // WrappedI420Buffer's mechanism for allowing the release of its frame | 949           // WrappedI420Buffer's mechanism for allowing the release of its frame | 
| 951           // buffer is through a callback function. This is where we should | 950           // buffer is through a callback function. This is where we should | 
| 952           // release |img_buffer|. | 951           // release |img_buffer|. | 
| 953           rtc::KeepRefUntilDone(img_buffer))); | 952           rtc::KeepRefUntilDone(img_buffer))); | 
| 954 | 953 | 
| 955   VideoFrame decoded_image; | 954   VideoFrame decoded_image; | 
| 956   decoded_image.set_video_frame_buffer(img_wrapped_buffer); | 955   decoded_image.set_video_frame_buffer(img_wrapped_buffer); | 
| 957   decoded_image.set_timestamp(timestamp); | 956   decoded_image.set_timestamp(timestamp); | 
| 958   int ret = decode_complete_callback_->Decoded(decoded_image); | 957   int ret = decode_complete_callback_->Decoded(decoded_image); | 
| 959   if (ret != 0) | 958   if (ret != 0) | 
| (...skipping 23 matching lines...) Expand all  Loading... | 
| 983   frame_buffer_pool_.ClearPool(); | 982   frame_buffer_pool_.ClearPool(); | 
| 984   inited_ = false; | 983   inited_ = false; | 
| 985   return WEBRTC_VIDEO_CODEC_OK; | 984   return WEBRTC_VIDEO_CODEC_OK; | 
| 986 } | 985 } | 
| 987 | 986 | 
| 988 const char* VP9DecoderImpl::ImplementationName() const { | 987 const char* VP9DecoderImpl::ImplementationName() const { | 
| 989   return "libvpx"; | 988   return "libvpx"; | 
| 990 } | 989 } | 
| 991 | 990 | 
| 992 }  // namespace webrtc | 991 }  // namespace webrtc | 
| OLD | NEW | 
|---|