Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(14)

Unified Diff: webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc

Issue 1211353002: Integration of VP9 packetization. (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: refactor and remove test helper class Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
diff --git a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
index a44d0f66bfc69869f926ffc4757dd3dbed599654..f7ff3545a0c9e4ea8d89e1193e9d25b754b96255 100644
--- a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
+++ b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc
@@ -56,7 +56,11 @@ VP9EncoderImpl::VP9EncoderImpl()
rc_max_intra_target_(0),
encoder_(NULL),
config_(NULL),
- raw_(NULL) {
+ raw_(NULL),
+ input_image_(NULL),
+ tl0_pic_idx_(0),
+ number_of_temporal_layers_(0),
+ number_of_spatial_layers_(0) {
memset(&codec_, 0, sizeof(codec_));
uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp());
srand(seed);
@@ -90,6 +94,59 @@ int VP9EncoderImpl::Release() {
return WEBRTC_VIDEO_CODEC_OK;
}
+int VP9EncoderImpl::SetSvcRates() {
+ float sRateRatio[VPX_MAX_LAYERS] = {0};
stefan-webrtc 2015/07/09 14:48:59 No camelCase.
åsapersson 2015/07/29 12:10:12 Done.
+ float total = 0;
+ uint8_t i = 0;
+
+ if (number_of_spatial_layers_ > 1) {
+ for (i = 0; i < number_of_spatial_layers_; ++i) {
+ if (svc_internal_.svc_params.scaling_factor_num[i] <= 0 ||
+ !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.
+ return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+ }
+ sRateRatio[i] =
+ (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.
+ svc_internal_.svc_params.scaling_factor_den[i]);
+ total += sRateRatio[i];
+ }
+ } else {
+ sRateRatio[0] = total = 1;
+ }
+
stefan-webrtc 2015/07/09 14:48:59 Assert that total = 1?
åsapersson 2015/07/29 12:10:12 added assert >=1?
+ for (i = 0; i < number_of_spatial_layers_; ++i) {
+ config_->ss_target_bitrate[i] =
+ (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.
+ if (number_of_temporal_layers_ == 1) {
+ config_->layer_target_bitrate[0] = config_->ss_target_bitrate[i];
+ } else if (number_of_temporal_layers_ == 2) {
+ config_->layer_target_bitrate[i * number_of_temporal_layers_] =
+ config_->ss_target_bitrate[i] * 2 / 3;
+ config_->layer_target_bitrate[i * number_of_temporal_layers_ + 1] =
+ config_->ss_target_bitrate[i];
+ } else {
+ if (number_of_temporal_layers_ != 3) {
+ return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+ }
+ config_->layer_target_bitrate[i * number_of_temporal_layers_] =
+ config_->ss_target_bitrate[i] / 2;
+ config_->layer_target_bitrate[i * number_of_temporal_layers_ + 1] =
+ config_->layer_target_bitrate[i * number_of_temporal_layers_] +
+ (config_->ss_target_bitrate[i] / 4);
+ config_->layer_target_bitrate[i * number_of_temporal_layers_ + 2] =
+ config_->ss_target_bitrate[i];
+ }
+ }
+
+ if (number_of_spatial_layers_ == 1) {
+ for (i = 0; i < VPX_TS_MAX_LAYERS; ++i) {
+ 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.
+ }
+ }
+
+ 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.
+}
+
int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
uint32_t new_framerate) {
if (!inited_) {
@@ -107,6 +164,11 @@ int VP9EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
}
config_->rc_target_bitrate = new_bitrate_kbit;
codec_.maxFramerate = new_framerate;
+
+ int ret = SetSvcRates();
+ if (ret != WEBRTC_VIDEO_CODEC_OK)
+ return ret;
+
// Update encoder context
if (vpx_codec_enc_config_set(encoder_, config_)) {
return WEBRTC_VIDEO_CODEC_ERROR;
@@ -147,6 +209,16 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
if (&codec_ != inst) {
codec_ = *inst;
}
+
+ // Member codec_ has access to VideoCodecVP9 (common_types.h), which should
+ // 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.
+ number_of_temporal_layers_ = inst->codecSpecific.VP9.numberOfTemporalLayers;
+ number_of_spatial_layers_ = inst->codecSpecific.VP9.numberOfSpatialLayers;
+ // For now, only support 1 spatial layer.
+ if (number_of_spatial_layers_ != 1) {
+ return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+ }
+
// Random start 16 bits is enough.
picture_id_ = static_cast<uint16_t>(rand()) & 0x7FFF;
// Allocate memory for encoded image
@@ -199,12 +271,53 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst,
config_->g_threads = NumberOfThreads(config_->g_w,
config_->g_h,
number_of_cores);
+
+ if (number_of_temporal_layers_ == 1) {
+ gof_.SetGofInfoVP9(kTemporalStructureMode1);
+ config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING;
+ config_->ts_number_layers = 1;
+ config_->ts_rate_decimator[0] = 1;
+ config_->ts_periodicity = 1;
+ config_->ts_layer_id[0] = 0;
+ } else if (number_of_temporal_layers_ == 2) {
+ gof_.SetGofInfoVP9(kTemporalStructureMode2);
+ config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0101;
+ config_->ts_number_layers = 2;
+ config_->ts_rate_decimator[0] = 2;
+ config_->ts_rate_decimator[1] = 1;
+ config_->ts_periodicity = 2;
+ config_->ts_layer_id[0] = 0;
+ config_->ts_layer_id[1] = 1;
+ } else if (number_of_temporal_layers_ == 3) {
+ gof_.SetGofInfoVP9(kTemporalStructureMode3);
+ config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_0212;
+ config_->ts_number_layers = 3;
+ config_->ts_rate_decimator[0] = 4;
+ config_->ts_rate_decimator[1] = 2;
+ config_->ts_rate_decimator[2] = 1;
+ config_->ts_periodicity = 4;
+ config_->ts_layer_id[0] = 0;
+ config_->ts_layer_id[1] = 2;
+ config_->ts_layer_id[2] = 1;
+ config_->ts_layer_id[3] = 2;
+ } else {
+ return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
+ }
+
+ tl0_pic_idx_ = static_cast<uint8_t>(rand());
+
return InitAndSetControlSettings(inst);
}
int VP9EncoderImpl::NumberOfThreads(int width,
int height,
int number_of_cores) {
+ // For the current libvpx library, only 1 thread is supported when SVC is
+ // turned on.
+ if (number_of_temporal_layers_ > 1 || number_of_spatial_layers_ > 1) {
+ return 1;
+ }
+
// Keep the number of encoder threads equal to the possible number of column
// tiles, which is (1, 2, 4, 8). See comments below for VP9E_SET_TILE_COLUMNS.
if (width * height >= 1280 * 720 && number_of_cores > 4) {
@@ -218,6 +331,26 @@ int VP9EncoderImpl::NumberOfThreads(int width,
}
int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) {
+
+ config_->ss_number_layers = number_of_spatial_layers_;
+
+ if (number_of_spatial_layers_ > 1) {
+ config_->rc_min_quantizer = 0;
+ config_->rc_max_quantizer = 63;
+ }
+ for (uint8_t i = 0; i < number_of_spatial_layers_; i++) {
+ svc_internal_.svc_params.max_quantizers[i] = config_->rc_max_quantizer;
+ svc_internal_.svc_params.min_quantizers[i] = config_->rc_min_quantizer;
+ /* 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.
+ svc_internal_.svc_params.scaling_factor_num[i] =
+ 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.
+ svc_internal_.svc_params.scaling_factor_den[i] = 256;
+ }
+
+ int ret = SetSvcRates();
+ if (ret != WEBRTC_VIDEO_CODEC_OK)
+ return ret;
+
if (vpx_codec_enc_init(encoder_, vpx_codec_vp9_cx(), config_, 0)) {
return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
}
@@ -231,6 +364,20 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) {
rc_max_intra_target_);
vpx_codec_control(encoder_, VP9E_SET_AQ_MODE,
inst->codecSpecific.VP9.adaptiveQpMode ? 3 : 0);
+
+ vpx_codec_control(
+ encoder_, VP9E_SET_SVC,
+ (number_of_temporal_layers_ > 1 || number_of_spatial_layers_ > 1) ? 1
+ : 0);
+ if (number_of_spatial_layers_ > 1) {
+ vpx_codec_control(encoder_, VP9E_SET_SVC_PARAMETERS,
+ &svc_internal_.svc_params);
+ }
+ // Register callback for getting each spatial layer
+ vpx_codec_priv_output_cx_pkt_cb_pair_t cbp = {
+ VP9EncoderImpl::EncocderOutputCodedPacketCb, (void*)(this)};
+ vpx_codec_control(encoder_, VP9E_REGISTER_CX_CALLBACK, (void*)(&cbp));
+
// Control function to set the number of column tiles in encoding a frame, in
// log2 unit: e.g., 0 = 1 tile column, 1 = 2 tile columns, 2 = 4 tile columns.
// The number tile columns will be capped by the encoder based on image size
@@ -242,6 +389,7 @@ int VP9EncoderImpl::InitAndSetControlSettings(const VideoCodec* inst) {
vpx_codec_control(encoder_, VP9E_SET_NOISE_SENSITIVITY,
inst->codecSpecific.VP9.denoisingOn ? 1 : 0);
#endif
+
inited_ = true;
return WEBRTC_VIDEO_CODEC_OK;
}
@@ -280,6 +428,13 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image,
}
DCHECK_EQ(input_image.width(), static_cast<int>(raw_->d_w));
DCHECK_EQ(input_image.height(), static_cast<int>(raw_->d_h));
+
+ // Set input image for use in the callback.
+ // This was necessary since you need some information from input_image.
+ // You can save only the necessary information (such as timestamp) instead of
+ // doing this.
+ input_image_ = &input_image;
+
// Image in vpx_image_t format.
// Input image is const. VPX's raw image is not defined as const.
raw_->planes[VPX_PLANE_Y] = const_cast<uint8_t*>(input_image.buffer(kYPlane));
@@ -302,7 +457,8 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image,
return WEBRTC_VIDEO_CODEC_ERROR;
}
timestamp_ += duration;
- return GetEncodedPartitions(input_image);
+
+ return WEBRTC_VIDEO_CODEC_OK;
}
void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
@@ -311,20 +467,81 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific,
assert(codec_specific != NULL);
codec_specific->codecType = kVideoCodecVP9;
CodecSpecificInfoVP9 *vp9_info = &(codec_specific->codecSpecific.VP9);
+ // TODO(asapersson): Set correct values.
+ vp9_info->interPicPredicted =
+ (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? false : true;
+ vp9_info->flexibleMode = codec_.codecSpecific.VP9.flexibleMode;
+ vp9_info->beginningOfFrame = true;
+ vp9_info->endOfFrame = true;
+ vp9_info->ssDataAvailable =
+ (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ? true : false;
+
+ 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.
+ vpx_codec_control(encoder_, VP9E_GET_SVC_LAYER_ID, &lyr);
+
+ assert(number_of_temporal_layers_ > 0);
+ assert(number_of_spatial_layers_ > 0);
+ if (number_of_temporal_layers_ == 1) {
+ assert(lyr.temporal_layer_id == 0);
+ vp9_info->temporalIdx = kNoTemporalIdx;
+ } else {
+ vp9_info->temporalIdx = lyr.temporal_layer_id;
+ }
+ if (number_of_spatial_layers_ == 1) {
+ assert(lyr.spatial_layer_id == 0);
+ vp9_info->spatialIdx = kNoSpatialIdx;
+ } else {
+ vp9_info->spatialIdx = lyr.spatial_layer_id;
+ }
+ if (lyr.spatial_layer_id != 0) {
+ vp9_info->ssDataAvailable = false;
+ }
+
+ if (vp9_info->flexibleMode) {
+ vp9_info->gofIdx = kNoGofIdx;
+ } else {
+ vp9_info->gofIdx = lyr.temporal_layer_id;
+ }
+
+ // TODO(asapersson): this info has to be obtained from the encoder.
+ vp9_info->temporalUpSwitch = true;
+
+ if (lyr.spatial_layer_id == 0) {
+ picture_id_ = (picture_id_ + 1) & 0x7FFF;
+ // TODO(asapersson): this info has to be obtained from the encoder.
+ vp9_info->interLayerPredicted = false;
+ } else {
+ // TODO(asapersson): this info has to be obtained from the encoder.
+ vp9_info->interLayerPredicted = true;
+ }
+
vp9_info->pictureId = picture_id_;
- vp9_info->keyIdx = kNoKeyIdx;
- vp9_info->nonReference = (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) != 0;
- // TODO(marpan): Temporal layers are supported in the current VP9 version,
- // but for now use 1 temporal layer encoding. Will update this when temporal
- // layer support for VP9 is added in webrtc.
- vp9_info->temporalIdx = kNoTemporalIdx;
- vp9_info->layerSync = false;
- vp9_info->tl0PicIdx = kNoTl0PicIdx;
- picture_id_ = (picture_id_ + 1) & 0x7FFF;
+
+ if (!vp9_info->flexibleMode) {
+ if (lyr.temporal_layer_id == 0 && lyr.spatial_layer_id == 0) {
+ tl0_pic_idx_++;
+ }
+ vp9_info->tl0PicIdx = tl0_pic_idx_;
+ }
+
+ if (vp9_info->ssDataAvailable) {
+ vp9_info->numSpatialLayers = number_of_spatial_layers_;
+ vp9_info->spatialLayerResolutionPresent = true;
+ for (uint8_t i = 0; i < vp9_info->numSpatialLayers; i++) {
+ vp9_info->width[i] = codec_.width *
+ svc_internal_.svc_params.scaling_factor_num[i] /
+ svc_internal_.svc_params.scaling_factor_den[i];
+ vp9_info->height[i] = codec_.height *
+ svc_internal_.svc_params.scaling_factor_num[i] /
+ svc_internal_.svc_params.scaling_factor_den[i];
+ }
+ if (!vp9_info->flexibleMode) {
+ vp9_info->gof.CopyGofInfoVP9(gof_);
+ }
+ }
}
-int VP9EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image) {
- vpx_codec_iter_t iter = NULL;
+int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) {
encoded_image_._length = 0;
encoded_image_._frameType = kDeltaFrame;
RTPFragmentationHeader frag_info;
@@ -333,44 +550,34 @@ int VP9EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image) {
frag_info.VerifyAndAllocateFragmentationHeader(1);
int part_idx = 0;
CodecSpecificInfo codec_specific;
- const vpx_codec_cx_pkt_t *pkt = NULL;
- while ((pkt = vpx_codec_get_cx_data(encoder_, &iter)) != NULL) {
- switch (pkt->kind) {
- case VPX_CODEC_CX_FRAME_PKT: {
- memcpy(&encoded_image_._buffer[encoded_image_._length],
- pkt->data.frame.buf,
- pkt->data.frame.sz);
- frag_info.fragmentationOffset[part_idx] = encoded_image_._length;
- frag_info.fragmentationLength[part_idx] =
- static_cast<uint32_t>(pkt->data.frame.sz);
- frag_info.fragmentationPlType[part_idx] = 0;
- frag_info.fragmentationTimeDiff[part_idx] = 0;
- encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz);
- assert(encoded_image_._length <= encoded_image_._size);
- break;
- }
- default: {
- break;
- }
- }
- // End of frame.
- if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
- // Check if encoded frame is a key frame.
- if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
- encoded_image_._frameType = kKeyFrame;
- }
- PopulateCodecSpecific(&codec_specific, *pkt, input_image.timestamp());
- break;
+
+ assert(pkt->kind == VPX_CODEC_CX_FRAME_PKT);
+ memcpy(&encoded_image_._buffer[encoded_image_._length], pkt->data.frame.buf,
+ pkt->data.frame.sz);
+ frag_info.fragmentationOffset[part_idx] = encoded_image_._length;
+ frag_info.fragmentationLength[part_idx] =
+ static_cast<uint32_t>(pkt->data.frame.sz);
+ frag_info.fragmentationPlType[part_idx] = 0;
+ frag_info.fragmentationTimeDiff[part_idx] = 0;
+ encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz);
+ assert(encoded_image_._length <= encoded_image_._size);
+
+ // End of frame.
+ if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
+ // Check if encoded frame is a key frame.
+ if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
+ encoded_image_._frameType = kKeyFrame;
}
+ PopulateCodecSpecific(&codec_specific, *pkt, input_image_->timestamp());
}
if (encoded_image_._length > 0) {
TRACE_COUNTER1("webrtc", "EncodedFrameSize", encoded_image_._length);
- encoded_image_._timeStamp = input_image.timestamp();
- encoded_image_.capture_time_ms_ = input_image.render_time_ms();
+ encoded_image_._timeStamp = input_image_->timestamp();
+ encoded_image_.capture_time_ms_ = input_image_->render_time_ms();
encoded_image_._encodedHeight = raw_->d_h;
encoded_image_._encodedWidth = raw_->d_w;
encoded_complete_callback_->Encoded(encoded_image_, &codec_specific,
- &frag_info);
+ &frag_info);
}
return WEBRTC_VIDEO_CODEC_OK;
}

Powered by Google App Engine
This is Rietveld 408576698