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; | 
| } |