Chromium Code Reviews| 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 73beab37b0627c44f065a784afd7e8f601281894..e59ddc302389ed375b73a6fde6830030567b28a4 100644 |
| --- a/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc |
| +++ b/webrtc/modules/video_coding/codecs/vp9/vp9_impl.cc |
| @@ -76,9 +76,10 @@ VP9EncoderImpl::VP9EncoderImpl() |
| raw_(NULL), |
| input_image_(NULL), |
| tl0_pic_idx_(0), |
| - gof_idx_(0), |
| + frames_since_kf_(0), |
| num_temporal_layers_(0), |
| - num_spatial_layers_(0) { |
| + num_spatial_layers_(0), |
| + frames_encoded_(0) { |
| memset(&codec_, 0, sizeof(codec_)); |
| uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp()); |
| srand(seed); |
| @@ -292,7 +293,26 @@ int VP9EncoderImpl::InitEncode(const VideoCodec* inst, |
| // TODO(asapersson): Check configuration of temporal switch up and increase |
| // pattern length. |
| - if (num_temporal_layers_ == 1) { |
| + is_flexible_mode_ = inst->codecSpecific.VP9.flexibleMode; |
| + if (is_flexible_mode_) { |
| + config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_BYPASS; |
| + config_->ts_number_layers = num_temporal_layers_; |
| + |
| + if (codec_.mode == kScreensharing) { |
| + // TODO(philipel): Using VP8 style screen sharing. Change conditions |
| + // when flexible mode + spatial layers become available. |
| + assert(inst->codecSpecific.VP9.numberOfTemporalLayers == 2); |
|
sprang_webrtc
2015/09/07 14:39:05
CHECK_EQ(2, ...)
philipel
2015/09/10 14:47:02
Code removed, now use spatial layers instead. Hurr
|
| + 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; |
| + |
| + // TODO(philipel): The following should be configurable, not fixed: |
| + temporal_layer_.ConfigureBitrate(1000); |
|
sprang_webrtc
2015/09/07 14:39:05
Why not set to start bitrate from VideoCodec param
philipel
2015/09/10 14:47:02
Done.
|
| + } |
| + } else if (num_temporal_layers_ == 1) { |
| gof_.SetGofInfoVP9(kTemporalStructureMode1); |
| config_->temporal_layering_mode = VP9E_TEMPORAL_LAYERING_MODE_NOLAYERING; |
| config_->ts_number_layers = 1; |
| @@ -458,12 +478,64 @@ int VP9EncoderImpl::Encode(const VideoFrame& input_image, |
| raw_->stride[VPX_PLANE_U] = input_image.stride(kUPlane); |
| raw_->stride[VPX_PLANE_V] = input_image.stride(kVPlane); |
| - int flags = 0; |
| + vpx_enc_frame_flags_t flags = 0; |
| bool send_keyframe = (frame_type == kKeyFrame); |
| if (send_keyframe) { |
| // Key frame request from caller. |
| flags = VPX_EFLAG_FORCE_KF; |
| } |
| + |
| + if (is_flexible_mode_) { |
| + vpx_svc_layer_id_t svc_layer; |
| + svc_layer.spatial_layer_id = 0; |
| + if (send_keyframe) { |
| + flags = GenerateRefsAndFlags(); |
| + } else if (codec_.mode == kRealtimeVideo) { |
| + // TODO(philipel): For now produce the 0-2-1-2 mod 8 pattern |
| + switch ((frames_since_kf_ - 1) % 8) { |
| + case 0: { |
| + flags = GenerateRefsAndFlags(0, 0); |
| + break; |
| + } |
| + case 1: { |
| + flags = GenerateRefsAndFlags(2, 0); |
| + break; |
| + } |
| + case 2: { |
| + flags = GenerateRefsAndFlags(1, 0); |
| + break; |
| + } |
| + case 3: { |
| + flags = GenerateRefsAndFlags(2, 0, 1, 2); |
| + break; |
| + } |
| + case 4: { |
| + flags = GenerateRefsAndFlags(0, 0); |
| + break; |
| + } |
| + case 5: { |
| + flags = GenerateRefsAndFlags(2, 0, 1, 2); |
| + break; |
| + } |
| + case 6: { |
| + flags = GenerateRefsAndFlags(1, 0, 1); |
| + break; |
| + } |
| + case 7: { |
| + flags = GenerateRefsAndFlags(2, 0, 1, 2); |
| + break; |
| + } |
| + } |
| + static const int temporal_layers[4] = {0, 2, 1, 2}; |
| + svc_layer.temporal_layer_id = temporal_layers[(frames_since_kf_ - 1) % 4]; |
| + } else { |
| + flags = GenerateRefsAndFlags( |
| + temporal_layer_.BufferArguments(input_image.timestamp())); |
| + svc_layer.temporal_layer_id = temporal_layer_.CurrentLayer(); |
| + } |
| + vpx_codec_control(encoder_, VP9E_SET_SVC_LAYER_ID, &svc_layer); |
| + } |
| + |
| assert(codec_.maxFramerate > 0); |
| uint32_t duration = 90000 / codec_.maxFramerate; |
| if (vpx_codec_encode(encoder_, raw_, timestamp_, duration, flags, |
| @@ -489,9 +561,8 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, |
| !codec_.codecSpecific.VP9.flexibleMode) |
| ? true |
| : false; |
| - if (pkt.data.frame.flags & VPX_FRAME_IS_KEY) { |
| - gof_idx_ = 0; |
| - } |
| + if (pkt.data.frame.flags & VPX_FRAME_IS_KEY) |
| + frames_since_kf_ = 0; |
| vpx_svc_layer_id_t layer_id = {0}; |
| vpx_codec_control(encoder_, VP9E_GET_SVC_LAYER_ID, &layer_id); |
| @@ -514,13 +585,6 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, |
| vp9_info->ss_data_available = false; |
| } |
| - if (vp9_info->flexible_mode) { |
| - vp9_info->gof_idx = kNoGofIdx; |
| - } else { |
| - vp9_info->gof_idx = |
| - static_cast<uint8_t>(gof_idx_++ % gof_.num_frames_in_gof); |
| - } |
| - |
| // TODO(asapersson): this info has to be obtained from the encoder. |
| vp9_info->temporal_up_switch = true; |
| @@ -542,6 +606,21 @@ void VP9EncoderImpl::PopulateCodecSpecific(CodecSpecificInfo* codec_specific, |
| vp9_info->tl0_pic_idx = tl0_pic_idx_; |
| } |
| + vp9_info->num_ref_pics = 0; |
| + if (vp9_info->flexible_mode) { |
| + vp9_info->gof_idx = kNoGofIdx; |
| + if (!(pkt.data.frame.flags & VPX_FRAME_IS_KEY)) { |
| + vp9_info->num_ref_pics = num_refs_pics_; |
| + for (int i = 0; i < num_refs_pics_; ++i) { |
| + vp9_info->p_diff[i] = p_diff_[i]; |
| + } |
| + } |
| + } else { |
| + vp9_info->gof_idx = |
| + static_cast<uint8_t>(frames_since_kf_ % gof_.num_frames_in_gof); |
| + } |
| + ++frames_since_kf_; |
| + |
| if (vp9_info->ss_data_available) { |
| vp9_info->num_spatial_layers = num_spatial_layers_; |
| vp9_info->spatial_layer_resolution_present = true; |
| @@ -578,6 +657,9 @@ int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { |
| frag_info.fragmentationPlType[part_idx] = 0; |
| frag_info.fragmentationTimeDiff[part_idx] = 0; |
| encoded_image_._length += static_cast<uint32_t>(pkt->data.frame.sz); |
| + if (is_flexible_mode_ && codec_.mode == kScreensharing) { |
| + temporal_layer_.FrameEncoded(encoded_image_._length); |
| + } |
|
sprang_webrtc
2015/09/07 14:39:05
Remove {}
philipel
2015/09/10 14:47:02
Done.
|
| assert(encoded_image_._length <= encoded_image_._size); |
| // End of frame. |
| @@ -599,6 +681,94 @@ int VP9EncoderImpl::GetEncodedLayerFrame(const vpx_codec_cx_pkt* pkt) { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |
| +vpx_enc_frame_flags_t VP9EncoderImpl::GenerateRefsAndFlags(int8_t upd_buffer, |
| + int8_t ref_buf1, |
| + int8_t ref_buf2, |
| + int8_t ref_buf3) { |
| + // For now we only use 3 out of the 8 buffers available |
| + DCHECK(upd_buffer < 3); |
|
sprang_webrtc
2015/09/07 14:39:05
DCHECK_LT
philipel
2015/09/10 14:47:02
Code removed.
|
| + |
| + // BUF0 = LAST |
| + // BUF1 = GF |
| + // BUF2 = ARF |
| + num_refs_pics_ = 0; |
| + vpx_enc_frame_flags_t flags = VP8_EFLAG_NO_REF_ARF | VP8_EFLAG_NO_REF_LAST | |
| + VP8_EFLAG_NO_REF_GF | VP8_EFLAG_NO_UPD_ARF | |
| + VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_LAST; |
| + if (upd_buffer == -2) { |
|
sprang_webrtc
2015/09/07 14:39:05
Have a named constant for -2?
philipel
2015/09/10 14:47:02
Code removed.
|
| +#ifdef NDEBUG |
|
sprang_webrtc
2015/09/07 14:39:05
Can't just always do this? memset it?
philipel
2015/09/10 14:47:02
Done.
|
| + // Used later on to make sure we don't make any invalid references. |
| + for (int i = 0; i < 8; ++i) |
| + buf_upd_at_frame_[i] = -1; |
| +#endif |
| + |
| + // Keyframe, always stored in BUF0. Why? Because of line 161 in |
|
sprang_webrtc
2015/09/07 14:39:05
This comment may grow stale quickly :)
"Keyframe a
philipel
2015/09/10 14:47:02
Changed so that the keyframes are stored in the bu
|
| + // vpx_temporal_svc_encoder.c. I'm not sure if that comment applies here |
| + buf_upd_at_frame_[0] = frames_encoded_; |
| + flags = VPX_EFLAG_FORCE_KF | VP8_EFLAG_NO_UPD_GF | VP8_EFLAG_NO_UPD_ARF; |
| + } else { |
| + int8_t refs[3] = {ref_buf1, ref_buf2, ref_buf3}; |
|
sprang_webrtc
2015/09/07 14:39:05
I'd probably add a named constant for 3 and use he
philipel
2015/09/10 14:47:01
Now use the kMaxVp9RefPics instead of '3'.
|
| + for (int i = 0; i < 3; ++i) { |
| + switch (refs[i]) { |
| + case -1: |
| + goto done; |
|
sprang_webrtc
2015/09/07 14:39:05
Ugh! How bout:
i = kNumReferences;
continue;
Per
philipel
2015/09/10 14:47:02
Code removed.
|
| + case 0: { |
| + flags ^= VP8_EFLAG_NO_REF_LAST; |
| + break; |
| + } |
| + case 1: { |
| + flags ^= VP8_EFLAG_NO_REF_GF; |
| + break; |
| + } |
| + case 2: { |
| + flags ^= VP8_EFLAG_NO_REF_ARF; |
| + break; |
| + } |
| + default: |
| + DCHECK(false); |
|
sprang_webrtc
2015/09/07 14:39:05
RTC_NOTREACHED();
philipel
2015/09/10 14:47:02
Code removed.
|
| + } |
| + |
| + // Make sure this frame doesn't reference to an unavailable |
| + // buffer, either because it has not yet been used or |
| + // because a KF has occurred since it was used. |
| + DCHECK(buf_upd_at_frame_[refs[i]] != -1); |
| + |
| + p_diff_[i] = frames_encoded_ - buf_upd_at_frame_[refs[i]]; |
| + num_refs_pics_++; |
| + } |
| + // Everybody love gotos! |
|
sprang_webrtc
2015/09/07 14:39:05
No. :)
philipel
2015/09/10 14:47:02
Yes!
|
| + done: |
| + |
| + buf_upd_at_frame_[upd_buffer] = frames_encoded_; |
| + switch (upd_buffer) { |
| + case -1: |
| + break; |
| + case 0: { |
| + flags ^= VP8_EFLAG_NO_UPD_LAST; |
| + break; |
| + } |
| + case 1: { |
| + flags ^= VP8_EFLAG_NO_UPD_GF; |
| + break; |
| + } |
| + case 2: { |
| + flags ^= VP8_EFLAG_NO_UPD_ARF; |
| + break; |
| + } |
| + default: |
| + DCHECK(false); |
|
sprang_webrtc
2015/09/07 14:39:05
RTC_NOTREACHED();
philipel
2015/09/10 14:47:01
Code removed.
|
| + } |
| + } |
| + |
| + frames_encoded_++; |
| + return flags; |
| +} |
| + |
| +vpx_enc_frame_flags_t VP9EncoderImpl::GenerateRefsAndFlags( |
| + std::array<int8_t, 4> args) { |
| + return GenerateRefsAndFlags(args[0], args[1], args[2], args[3]); |
| +} |
| + |
| int VP9EncoderImpl::SetChannelParameters(uint32_t packet_loss, int64_t rtt) { |
| return WEBRTC_VIDEO_CODEC_OK; |
| } |