Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / cast / video_sender / codecs / vp8 / vp8_encoder.cc
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 //
5 // TODO (pwestin): add a link to the design document describing the generic
6 // protocol and the VP8 specific details.
7 #include "media/cast/video_sender/codecs/vp8/vp8_encoder.h"
8
9 #include <vector>
10
11 #include "base/logging.h"
12 #include "media/base/video_frame.h"
13 #include "media/cast/cast_defines.h"
14 #include "media/cast/transport/cast_transport_config.h"
15 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
16
17 namespace media {
18 namespace cast {
19
20 static const uint32 kMinIntra = 300;
21
22 static int ComputeMaxNumOfRepeatedBuffes(uint8 max_unacked_frames) {
23   if (max_unacked_frames > kNumberOfVp8VideoBuffers)
24     return (max_unacked_frames - 1) / kNumberOfVp8VideoBuffers;
25
26   return 0;
27 }
28
29 Vp8Encoder::Vp8Encoder(const VideoSenderConfig& video_config,
30                        uint8 max_unacked_frames)
31     : cast_config_(video_config),
32       use_multiple_video_buffers_(
33           cast_config_.max_number_of_video_buffers_used ==
34           kNumberOfVp8VideoBuffers),
35       max_number_of_repeated_buffers_in_a_row_(
36           ComputeMaxNumOfRepeatedBuffes(max_unacked_frames)),
37       key_frame_requested_(true),
38       timestamp_(0),
39       last_encoded_frame_id_(kStartFrameId),
40       number_of_repeated_buffers_(0) {
41   // TODO(pwestin): we need to figure out how to synchronize the acking with the
42   // internal state of the encoder, ideally the encoder will tell if we can
43   // send another frame.
44   DCHECK(!use_multiple_video_buffers_ ||
45          max_number_of_repeated_buffers_in_a_row_ == 0)
46       << "Invalid config";
47
48   // VP8 have 3 buffers available for prediction, with
49   // max_number_of_video_buffers_used set to 1 we maximize the coding efficiency
50   // however in this mode we can not skip frames in the receiver to catch up
51   // after a temporary network outage; with max_number_of_video_buffers_used
52   // set to 3 we allow 2 frames to be skipped by the receiver without error
53   // propagation.
54   DCHECK(cast_config_.max_number_of_video_buffers_used == 1 ||
55          cast_config_.max_number_of_video_buffers_used ==
56              kNumberOfVp8VideoBuffers)
57       << "Invalid argument";
58
59   thread_checker_.DetachFromThread();
60 }
61
62 Vp8Encoder::~Vp8Encoder() {
63   vpx_codec_destroy(encoder_.get());
64   vpx_img_free(raw_image_);
65 }
66
67 void Vp8Encoder::Initialize() {
68   DCHECK(thread_checker_.CalledOnValidThread());
69   config_.reset(new vpx_codec_enc_cfg_t());
70   encoder_.reset(new vpx_codec_ctx_t());
71
72   // Creating a wrapper to the image - setting image data to NULL. Actual
73   // pointer will be set during encode. Setting align to 1, as it is
74   // meaningless (actual memory is not allocated).
75   raw_image_ = vpx_img_wrap(
76       NULL, IMG_FMT_I420, cast_config_.width, cast_config_.height, 1, NULL);
77
78   for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
79     acked_frame_buffers_[i] = true;
80     used_buffers_frame_id_[i] = kStartFrameId;
81   }
82   InitEncode(cast_config_.number_of_cores);
83 }
84
85 void Vp8Encoder::InitEncode(int number_of_cores) {
86   DCHECK(thread_checker_.CalledOnValidThread());
87   // Populate encoder configuration with default values.
88   if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), config_.get(), 0)) {
89     DCHECK(false) << "Invalid return value";
90   }
91   config_->g_w = cast_config_.width;
92   config_->g_h = cast_config_.height;
93   config_->rc_target_bitrate = cast_config_.start_bitrate / 1000;  // In kbit/s.
94
95   // Setting the codec time base.
96   config_->g_timebase.num = 1;
97   config_->g_timebase.den = kVideoFrequency;
98   config_->g_lag_in_frames = 0;
99   config_->kf_mode = VPX_KF_DISABLED;
100   if (use_multiple_video_buffers_) {
101     // We must enable error resilience when we use multiple buffers, due to
102     // codec requirements.
103     config_->g_error_resilient = 1;
104   }
105
106   if (cast_config_.width * cast_config_.height > 640 * 480 &&
107       number_of_cores >= 2) {
108     config_->g_threads = 2;  // 2 threads for qHD/HD.
109   } else {
110     config_->g_threads = 1;  // 1 thread for VGA or less.
111   }
112
113   // Rate control settings.
114   // TODO(pwestin): revisit these constants. Currently identical to webrtc.
115   config_->rc_dropframe_thresh = 30;
116   config_->rc_end_usage = VPX_CBR;
117   config_->g_pass = VPX_RC_ONE_PASS;
118   config_->rc_resize_allowed = 0;
119   config_->rc_min_quantizer = cast_config_.min_qp;
120   config_->rc_max_quantizer = cast_config_.max_qp;
121   config_->rc_undershoot_pct = 100;
122   config_->rc_overshoot_pct = 15;
123   config_->rc_buf_initial_sz = 500;
124   config_->rc_buf_optimal_sz = 600;
125   config_->rc_buf_sz = 1000;
126
127   // set the maximum target size of any key-frame.
128   uint32 rc_max_intra_target = MaxIntraTarget(config_->rc_buf_optimal_sz);
129   vpx_codec_flags_t flags = 0;
130   // TODO(mikhal): Tune settings.
131   if (vpx_codec_enc_init(
132           encoder_.get(), vpx_codec_vp8_cx(), config_.get(), flags)) {
133     DCHECK(false) << "vpx_codec_enc_init() failed.";
134     encoder_.reset();
135     return;
136   }
137   vpx_codec_control(encoder_.get(), VP8E_SET_STATIC_THRESHOLD, 1);
138   vpx_codec_control(encoder_.get(), VP8E_SET_NOISE_SENSITIVITY, 0);
139   vpx_codec_control(encoder_.get(), VP8E_SET_CPUUSED, -6);
140   vpx_codec_control(
141       encoder_.get(), VP8E_SET_MAX_INTRA_BITRATE_PCT, rc_max_intra_target);
142 }
143
144 bool Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame,
145                         transport::EncodedVideoFrame* encoded_image) {
146   DCHECK(thread_checker_.CalledOnValidThread());
147   // Image in vpx_image_t format.
148   // Input image is const. VP8's raw image is not defined as const.
149   raw_image_->planes[PLANE_Y] =
150       const_cast<uint8*>(video_frame->data(VideoFrame::kYPlane));
151   raw_image_->planes[PLANE_U] =
152       const_cast<uint8*>(video_frame->data(VideoFrame::kUPlane));
153   raw_image_->planes[PLANE_V] =
154       const_cast<uint8*>(video_frame->data(VideoFrame::kVPlane));
155
156   raw_image_->stride[VPX_PLANE_Y] = video_frame->stride(VideoFrame::kYPlane);
157   raw_image_->stride[VPX_PLANE_U] = video_frame->stride(VideoFrame::kUPlane);
158   raw_image_->stride[VPX_PLANE_V] = video_frame->stride(VideoFrame::kVPlane);
159
160   uint8 latest_frame_id_to_reference;
161   Vp8Buffers buffer_to_update;
162   vpx_codec_flags_t flags = 0;
163   if (key_frame_requested_) {
164     flags = VPX_EFLAG_FORCE_KF;
165     // Self reference.
166     latest_frame_id_to_reference = last_encoded_frame_id_ + 1;
167     // We can pick any buffer as buffer_to_update since we update
168     // them all.
169     buffer_to_update = kLastBuffer;
170   } else {
171     // Reference all acked frames (buffers).
172     latest_frame_id_to_reference = GetLatestFrameIdToReference();
173     GetCodecReferenceFlags(&flags);
174     buffer_to_update = GetNextBufferToUpdate();
175     GetCodecUpdateFlags(buffer_to_update, &flags);
176   }
177
178   // Note: The duration does not reflect the real time between frames. This is
179   // done to keep the encoder happy.
180   uint32 duration = kVideoFrequency / cast_config_.max_frame_rate;
181   if (vpx_codec_encode(encoder_.get(),
182                        raw_image_,
183                        timestamp_,
184                        duration,
185                        flags,
186                        VPX_DL_REALTIME)) {
187     return false;
188   }
189   timestamp_ += duration;
190
191   // Get encoded frame.
192   const vpx_codec_cx_pkt_t* pkt = NULL;
193   vpx_codec_iter_t iter = NULL;
194   size_t total_size = 0;
195   while ((pkt = vpx_codec_get_cx_data(encoder_.get(), &iter)) != NULL) {
196     if (pkt->kind == VPX_CODEC_CX_FRAME_PKT) {
197       total_size += pkt->data.frame.sz;
198       encoded_image->data.reserve(total_size);
199       encoded_image->data.insert(
200           encoded_image->data.end(),
201           static_cast<const uint8*>(pkt->data.frame.buf),
202           static_cast<const uint8*>(pkt->data.frame.buf) + pkt->data.frame.sz);
203       if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
204         encoded_image->key_frame = true;
205       } else {
206         encoded_image->key_frame = false;
207       }
208     }
209   }
210   // Don't update frame_id for zero size frames.
211   if (total_size == 0)
212     return true;
213
214   // Populate the encoded frame.
215   encoded_image->codec = transport::kVp8;
216   encoded_image->last_referenced_frame_id = latest_frame_id_to_reference;
217   encoded_image->frame_id = ++last_encoded_frame_id_;
218
219   VLOG(1) << "VP8 encoded frame:" << static_cast<int>(encoded_image->frame_id)
220           << " sized:" << total_size;
221
222   if (encoded_image->key_frame) {
223     key_frame_requested_ = false;
224
225     for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
226       used_buffers_frame_id_[i] = encoded_image->frame_id;
227     }
228     // We can pick any buffer as last_used_vp8_buffer_ since we update
229     // them all.
230     last_used_vp8_buffer_ = buffer_to_update;
231   } else {
232     if (buffer_to_update != kNoBuffer) {
233       acked_frame_buffers_[buffer_to_update] = false;
234       used_buffers_frame_id_[buffer_to_update] = encoded_image->frame_id;
235       last_used_vp8_buffer_ = buffer_to_update;
236     }
237   }
238   return true;
239 }
240
241 void Vp8Encoder::GetCodecReferenceFlags(vpx_codec_flags_t* flags) {
242   if (!use_multiple_video_buffers_)
243     return;
244
245   // We need to reference something.
246   DCHECK(acked_frame_buffers_[kAltRefBuffer] ||
247          acked_frame_buffers_[kGoldenBuffer] ||
248          acked_frame_buffers_[kLastBuffer])
249       << "Invalid state";
250
251   if (!acked_frame_buffers_[kAltRefBuffer]) {
252     *flags |= VP8_EFLAG_NO_REF_ARF;
253   }
254   if (!acked_frame_buffers_[kGoldenBuffer]) {
255     *flags |= VP8_EFLAG_NO_REF_GF;
256   }
257   if (!acked_frame_buffers_[kLastBuffer]) {
258     *flags |= VP8_EFLAG_NO_REF_LAST;
259   }
260 }
261
262 uint32 Vp8Encoder::GetLatestFrameIdToReference() {
263   if (!use_multiple_video_buffers_)
264     return last_encoded_frame_id_;
265
266   int latest_frame_id_to_reference = -1;
267   if (acked_frame_buffers_[kAltRefBuffer]) {
268     latest_frame_id_to_reference = used_buffers_frame_id_[kAltRefBuffer];
269   }
270   if (acked_frame_buffers_[kGoldenBuffer]) {
271     if (latest_frame_id_to_reference == -1) {
272       latest_frame_id_to_reference = used_buffers_frame_id_[kGoldenBuffer];
273     } else {
274       if (IsNewerFrameId(used_buffers_frame_id_[kGoldenBuffer],
275                          latest_frame_id_to_reference)) {
276         latest_frame_id_to_reference = used_buffers_frame_id_[kGoldenBuffer];
277       }
278     }
279   }
280   if (acked_frame_buffers_[kLastBuffer]) {
281     if (latest_frame_id_to_reference == -1) {
282       latest_frame_id_to_reference = used_buffers_frame_id_[kLastBuffer];
283     } else {
284       if (IsNewerFrameId(used_buffers_frame_id_[kLastBuffer],
285                          latest_frame_id_to_reference)) {
286         latest_frame_id_to_reference = used_buffers_frame_id_[kLastBuffer];
287       }
288     }
289   }
290   DCHECK(latest_frame_id_to_reference != -1) << "Invalid state";
291   return static_cast<uint32>(latest_frame_id_to_reference);
292 }
293
294 Vp8Encoder::Vp8Buffers Vp8Encoder::GetNextBufferToUpdate() {
295   // Update at most one buffer, except for key-frames.
296
297   Vp8Buffers buffer_to_update;
298   if (number_of_repeated_buffers_ < max_number_of_repeated_buffers_in_a_row_) {
299     // TODO(pwestin): experiment with this. The issue with only this change is
300     // that we can end up with only 4 frames in flight when we expect 6.
301     // buffer_to_update = last_used_vp8_buffer_;
302     buffer_to_update = kNoBuffer;
303     ++number_of_repeated_buffers_;
304   } else {
305     number_of_repeated_buffers_ = 0;
306     switch (last_used_vp8_buffer_) {
307       case kAltRefBuffer:
308         buffer_to_update = kLastBuffer;
309         VLOG(1) << "VP8 update last buffer";
310         break;
311       case kLastBuffer:
312         buffer_to_update = kGoldenBuffer;
313         VLOG(1) << "VP8 update golden buffer";
314         break;
315       case kGoldenBuffer:
316         buffer_to_update = kAltRefBuffer;
317         VLOG(1) << "VP8 update alt-ref buffer";
318         break;
319       case kNoBuffer:
320         DCHECK(false) << "Invalid state";
321         break;
322     }
323   }
324   return buffer_to_update;
325 }
326
327 void Vp8Encoder::GetCodecUpdateFlags(Vp8Buffers buffer_to_update,
328                                      vpx_codec_flags_t* flags) {
329   if (!use_multiple_video_buffers_)
330     return;
331
332   // Update at most one buffer, except for key-frames.
333   switch (buffer_to_update) {
334     case kAltRefBuffer:
335       *flags |= VP8_EFLAG_NO_UPD_GF;
336       *flags |= VP8_EFLAG_NO_UPD_LAST;
337       break;
338     case kLastBuffer:
339       *flags |= VP8_EFLAG_NO_UPD_GF;
340       *flags |= VP8_EFLAG_NO_UPD_ARF;
341       break;
342     case kGoldenBuffer:
343       *flags |= VP8_EFLAG_NO_UPD_ARF;
344       *flags |= VP8_EFLAG_NO_UPD_LAST;
345       break;
346     case kNoBuffer:
347       *flags |= VP8_EFLAG_NO_UPD_ARF;
348       *flags |= VP8_EFLAG_NO_UPD_GF;
349       *flags |= VP8_EFLAG_NO_UPD_LAST;
350       *flags |= VP8_EFLAG_NO_UPD_ENTROPY;
351       break;
352   }
353 }
354
355 void Vp8Encoder::UpdateRates(uint32 new_bitrate) {
356   DCHECK(thread_checker_.CalledOnValidThread());
357   uint32 new_bitrate_kbit = new_bitrate / 1000;
358   if (config_->rc_target_bitrate == new_bitrate_kbit)
359     return;
360
361   config_->rc_target_bitrate = new_bitrate_kbit;
362
363   // Update encoder context.
364   if (vpx_codec_enc_config_set(encoder_.get(), config_.get())) {
365     DCHECK(false) << "Invalid return value";
366   }
367 }
368
369 void Vp8Encoder::LatestFrameIdToReference(uint32 frame_id) {
370   DCHECK(thread_checker_.CalledOnValidThread());
371   if (!use_multiple_video_buffers_)
372     return;
373
374   VLOG(1) << "VP8 ok to reference frame:" << static_cast<int>(frame_id);
375   for (int i = 0; i < kNumberOfVp8VideoBuffers; ++i) {
376     if (frame_id == used_buffers_frame_id_[i]) {
377       acked_frame_buffers_[i] = true;
378     }
379   }
380 }
381
382 void Vp8Encoder::GenerateKeyFrame() {
383   DCHECK(thread_checker_.CalledOnValidThread());
384   key_frame_requested_ = true;
385 }
386
387 // Calculate the max size of the key frame relative to a normal delta frame.
388 uint32 Vp8Encoder::MaxIntraTarget(uint32 optimal_buffer_size_ms) const {
389   // Set max to the optimal buffer level (normalized by target BR),
390   // and scaled by a scale_parameter.
391   // Max target size = scalePar * optimalBufferSize * targetBR[Kbps].
392   // This values is presented in percentage of perFrameBw:
393   // perFrameBw = targetBR[Kbps] * 1000 / frameRate.
394   // The target in % is as follows:
395
396   float scale_parameter = 0.5;
397   uint32 target_pct = optimal_buffer_size_ms * scale_parameter *
398                       cast_config_.max_frame_rate / 10;
399
400   // Don't go below 3 times the per frame bandwidth.
401   return std::max(target_pct, kMinIntra);
402 }
403
404 }  // namespace cast
405 }  // namespace media