1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
24ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
108d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org
11e07c661a29058aac858f99c5d0701a52969dfbe4mikhal@webrtc.org#include "webrtc/modules/video_coding/codecs/vp8/vp8_impl.h"
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <stdlib.h>
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <string.h>
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include <time.h>
169115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org#include <algorithm>
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org// NOTE(ajm): Path provided by gyp.
19cce46fc108a70336f0477fd58d41f38e547eeb25philipel#include "libyuv/scale.h"    // NOLINT
2073d763e71f5c77cac82aa65d737e64d893f190a0magjed@webrtc.org#include "libyuv/convert.h"  // NOLINT
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
22e155dbeae972f788b8766b4d0d2cefde2e952a10magjed@webrtc.org#include "webrtc/base/checks.h"
23e4f96501fc5b3e6de0d1ccd262372afcda1f5b4ftommi#include "webrtc/base/trace_event.h"
245500d93fe55702af0b254e5718fcc085298c99abandresp@webrtc.org#include "webrtc/common.h"
259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org#include "webrtc/common_types.h"
26e07c661a29058aac858f99c5d0701a52969dfbe4mikhal@webrtc.org#include "webrtc/common_video/libyuv/include/webrtc_libyuv.h"
27ff761fba8274d93bd73e76c8b8a1f2d0776dd840Henrik Kjellander#include "webrtc/modules/include/module_common_types.h"
282557b86e7648ffebc5781df9f093ca5a84efc219Henrik Kjellander#include "webrtc/modules/video_coding/include/video_codec_interface.h"
299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org#include "webrtc/modules/video_coding/codecs/vp8/include/vp8_common_types.h"
309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org#include "webrtc/modules/video_coding/codecs/vp8/screenshare_layers.h"
315500d93fe55702af0b254e5718fcc085298c99abandresp@webrtc.org#include "webrtc/modules/video_coding/codecs/vp8/temporal_layers.h"
3298f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/tick_util.h"
338d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org
349115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgnamespace webrtc {
359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgnamespace {
369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
371af915d8aeba410ad13f857eb89686dd0f0686d0mikhal@webrtc.orgenum { kVp8ErrorPropagationTh = 30 };
389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgenum { kVp832ByteAlign = 32 };
399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
409115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org// VP8 denoiser states.
419115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgenum denoiserState {
429115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  kDenoiserOff,
439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  kDenoiserOnYOnly,
449115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  kDenoiserOnYUV,
459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  kDenoiserOnYUVAggressive,
469115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Adaptive mode defaults to kDenoiserOnYUV on key frame, but may switch
479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // to kDenoiserOnYUVAggressive based on a computed noise metric.
489115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  kDenoiserOnAdaptive
499115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org};
509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org// Greatest common divisior
529115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgint GCD(int a, int b) {
539115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int c = a % b;
549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  while (c != 0) {
559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    a = b;
569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    b = c;
579115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    c = a % b;
589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
599115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return b;
609115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
61470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
621b9add9df9cdab004a11e75900a341a346ce2049Peter Boströmstd::vector<int> GetStreamBitratesKbps(const VideoCodec& codec,
631b9add9df9cdab004a11e75900a341a346ce2049Peter Boström                                       int bitrate_to_allocate_kbps) {
641b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  if (codec.numberOfSimulcastStreams <= 1) {
651b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    return std::vector<int>(1, bitrate_to_allocate_kbps);
661b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  }
671b9add9df9cdab004a11e75900a341a346ce2049Peter Boström
681b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  std::vector<int> bitrates_kbps(codec.numberOfSimulcastStreams);
691b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // Allocate min -> target bitrates as long as we have bitrate to spend.
701b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  size_t last_active_stream = 0;
71cce46fc108a70336f0477fd58d41f38e547eeb25philipel  for (size_t i = 0; i < static_cast<size_t>(codec.numberOfSimulcastStreams) &&
72cce46fc108a70336f0477fd58d41f38e547eeb25philipel                     bitrate_to_allocate_kbps >=
73cce46fc108a70336f0477fd58d41f38e547eeb25philipel                         static_cast<int>(codec.simulcastStream[i].minBitrate);
741b9add9df9cdab004a11e75900a341a346ce2049Peter Boström       ++i) {
751b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    last_active_stream = i;
761b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    int allocated_bitrate_kbps =
771b9add9df9cdab004a11e75900a341a346ce2049Peter Boström        std::min(static_cast<int>(codec.simulcastStream[i].targetBitrate),
781b9add9df9cdab004a11e75900a341a346ce2049Peter Boström                 bitrate_to_allocate_kbps);
791b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    bitrates_kbps[i] = allocated_bitrate_kbps;
801b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    bitrate_to_allocate_kbps -= allocated_bitrate_kbps;
811b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  }
821b9add9df9cdab004a11e75900a341a346ce2049Peter Boström
831b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // Spend additional bits on the highest-quality active layer, up to max
841b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // bitrate.
851b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // TODO(pbos): Consider spending additional bits on last_active_stream-1 down
861b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // to 0 and not just the top layer when we have additional bitrate to spend.
871b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  int allocated_bitrate_kbps = std::min(
881b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      static_cast<int>(codec.simulcastStream[last_active_stream].maxBitrate -
891b9add9df9cdab004a11e75900a341a346ce2049Peter Boström                       bitrates_kbps[last_active_stream]),
901b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      bitrate_to_allocate_kbps);
911b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  bitrates_kbps[last_active_stream] += allocated_bitrate_kbps;
921b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  bitrate_to_allocate_kbps -= allocated_bitrate_kbps;
931b9add9df9cdab004a11e75900a341a346ce2049Peter Boström
941b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // Make sure we can always send something. Suspending below min bitrate is
951b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  // controlled outside the codec implementation and is not overriden by this.
961b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  if (bitrates_kbps[0] < static_cast<int>(codec.simulcastStream[0].minBitrate))
971b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    bitrates_kbps[0] = static_cast<int>(codec.simulcastStream[0].minBitrate);
981b9add9df9cdab004a11e75900a341a346ce2049Peter Boström
991b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  return bitrates_kbps;
1009115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
1019115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
1029115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orguint32_t SumStreamMaxBitrate(int streams, const VideoCodec& codec) {
1039115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  uint32_t bitrate_sum = 0;
1049115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (int i = 0; i < streams; ++i) {
1059115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    bitrate_sum += codec.simulcastStream[i].maxBitrate;
1069115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
1079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return bitrate_sum;
1089115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
1099115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
1109115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgint NumberOfStreams(const VideoCodec& codec) {
1119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int streams =
1129115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      codec.numberOfSimulcastStreams < 1 ? 1 : codec.numberOfSimulcastStreams;
1139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  uint32_t simulcast_max_bitrate = SumStreamMaxBitrate(streams, codec);
1149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (simulcast_max_bitrate == 0) {
1159115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    streams = 1;
1169115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
1179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return streams;
1189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
1199115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
1209115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgbool ValidSimulcastResolutions(const VideoCodec& codec, int num_streams) {
1219115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (codec.width != codec.simulcastStream[num_streams - 1].width ||
1229115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      codec.height != codec.simulcastStream[num_streams - 1].height) {
1239115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return false;
1249115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
1259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (int i = 0; i < num_streams; ++i) {
1269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (codec.width * codec.simulcastStream[i].height !=
1279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        codec.height * codec.simulcastStream[i].width) {
1289115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      return false;
1299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
1309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
1319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return true;
1329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
133da535c405597864b8396b2029dec70ab9fb76e8basapersson
134cce46fc108a70336f0477fd58d41f38e547eeb25philipelint NumStreamsDisabled(const std::vector<bool>& streams) {
135da535c405597864b8396b2029dec70ab9fb76e8basapersson  int num_disabled = 0;
136da535c405597864b8396b2029dec70ab9fb76e8basapersson  for (bool stream : streams) {
137da535c405597864b8396b2029dec70ab9fb76e8basapersson    if (!stream)
138da535c405597864b8396b2029dec70ab9fb76e8basapersson      ++num_disabled;
139da535c405597864b8396b2029dec70ab9fb76e8basapersson  }
140da535c405597864b8396b2029dec70ab9fb76e8basapersson  return num_disabled;
141da535c405597864b8396b2029dec70ab9fb76e8basapersson}
1429115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}  // namespace
1439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
1449115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgconst float kTl1MaxTimeToDropFrames = 20.0f;
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1468d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgVP8EncoderImpl::VP8EncoderImpl()
1479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    : encoded_complete_callback_(NULL),
1484ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      inited_(false),
1494ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      timestamp_(0),
1504ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      feedback_mode_(false),
1519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      qp_max_(56),  // Setting for max quantizer.
1526daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org      cpu_speed_default_(-6),
1534ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      rc_max_intra_target_(0),
1544ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      token_partitions_(VP8_ONE_TOKENPARTITION),
1559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      down_scale_requested_(false),
1569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      down_scale_bitrate_(0),
1579115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      tl0_frame_dropper_(),
1589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      tl1_frame_dropper_(kTl1MaxTimeToDropFrames),
1594306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson      key_frame_request_(kMaxSimulcastStreams, false),
1604306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson      quality_scaler_enabled_(false) {
1614ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  uint32_t seed = static_cast<uint32_t>(TickTime::MillisecondTimestamp());
1624ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  srand(seed);
1639115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
1649115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  picture_id_.reserve(kMaxSimulcastStreams);
1659115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  last_key_frame_picture_id_.reserve(kMaxSimulcastStreams);
1669115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  temporal_layers_.reserve(kMaxSimulcastStreams);
1679115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_.reserve(kMaxSimulcastStreams);
1689115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  encoded_images_.reserve(kMaxSimulcastStreams);
1699115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  send_stream_.reserve(kMaxSimulcastStreams);
1709115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  cpu_speed_.assign(kMaxSimulcastStreams, -6);  // Set default to -6.
1719115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  encoders_.reserve(kMaxSimulcastStreams);
1729115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_.reserve(kMaxSimulcastStreams);
1739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  downsampling_factors_.reserve(kMaxSimulcastStreams);
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1768d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgVP8EncoderImpl::~VP8EncoderImpl() {
1774ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  Release();
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1808d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8EncoderImpl::Release() {
1819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int ret_val = WEBRTC_VIDEO_CODEC_OK;
1829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
1839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  while (!encoded_images_.empty()) {
1849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    EncodedImage& image = encoded_images_.back();
185cce46fc108a70336f0477fd58d41f38e547eeb25philipel    delete[] image._buffer;
1869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoded_images_.pop_back();
1874ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  while (!encoders_.empty()) {
1899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_ctx_t& encoder = encoders_.back();
1909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (vpx_codec_destroy(&encoder)) {
1919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      ret_val = WEBRTC_VIDEO_CODEC_MEMORY;
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
1939115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoders_.pop_back();
1944ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_.clear();
1969115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  send_stream_.clear();
1979115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  cpu_speed_.clear();
1989115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  while (!raw_images_.empty()) {
1999115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_img_free(&raw_images_.back());
2009115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    raw_images_.pop_back();
2014ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2029115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  while (!temporal_layers_.empty()) {
2039115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    delete temporal_layers_.back();
2049115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    temporal_layers_.pop_back();
2054ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2064ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  inited_ = false;
2079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return ret_val;
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2108d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8EncoderImpl::SetRates(uint32_t new_bitrate_kbit,
2111b9add9df9cdab004a11e75900a341a346ce2049Peter Boström                             uint32_t new_framerate) {
2124ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (!inited_) {
2134ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
2144ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2159115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (encoders_[0].err) {
2164ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
2174ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2184ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (new_framerate < 1) {
2194ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
2204ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2214ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (codec_.maxBitrate > 0 && new_bitrate_kbit > codec_.maxBitrate) {
2224ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    new_bitrate_kbit = codec_.maxBitrate;
2234ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2249115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (new_bitrate_kbit < codec_.minBitrate) {
2259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    new_bitrate_kbit = codec_.minBitrate;
2269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
2279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (codec_.numberOfSimulcastStreams > 0 &&
2289115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      new_bitrate_kbit < codec_.simulcastStream[0].minBitrate) {
2299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    new_bitrate_kbit = codec_.simulcastStream[0].minBitrate;
2309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
2314ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  codec_.maxFramerate = new_framerate;
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
2339115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (encoders_.size() == 1) {
2349115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // 1:1.
2359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Calculate a rough limit for when to trigger a potental down scale.
2369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    uint32_t k_pixels_per_frame = codec_.width * codec_.height / 1000;
2379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // TODO(pwestin): we currently lack CAMA, this is a temporary fix to work
2389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // around the current limitations.
2399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Only trigger keyframes if we are allowed to scale down.
2409115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (configurations_[0].rc_resize_allowed) {
2419115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      if (!down_scale_requested_) {
2429115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        if (k_pixels_per_frame > new_bitrate_kbit) {
2439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          down_scale_requested_ = true;
2449115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          down_scale_bitrate_ = new_bitrate_kbit;
2459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          key_frame_request_[0] = true;
2469115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        }
2479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      } else {
2489115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        if (new_bitrate_kbit > (2 * down_scale_bitrate_) ||
2499115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            new_bitrate_kbit < (down_scale_bitrate_ / 2)) {
2509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          down_scale_requested_ = false;
2519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        }
2529115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      }
2539115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
2549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else {
2559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // If we have more than 1 stream, reduce the qp_max for the low resolution
2569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // stream if frame rate is not too low. The trade-off with lower qp_max is
2579115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // possibly more dropped frames, so we only do this if the frame rate is
2589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // above some threshold (base temporal layer is down to 1/4 for 3 layers).
2599115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // We may want to condition this on bitrate later.
2609115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (new_framerate > 20) {
2619115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[encoders_.size() - 1].rc_max_quantizer = 45;
2629115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    } else {
2639115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // Go back to default value set in InitEncode.
2649115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[encoders_.size() - 1].rc_max_quantizer = qp_max_;
2659115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
2669115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
2679115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
2681b9add9df9cdab004a11e75900a341a346ce2049Peter Boström  std::vector<int> stream_bitrates =
2691b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      GetStreamBitratesKbps(codec_, new_bitrate_kbit);
2709115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  size_t stream_idx = encoders_.size() - 1;
2719115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) {
2721b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    if (encoders_.size() > 1)
2731b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
2749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
2751b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    unsigned int target_bitrate = stream_bitrates[stream_idx];
2769115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    unsigned int max_bitrate = codec_.maxBitrate;
2779115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int framerate = new_framerate;
2789115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // TODO(holmer): This is a temporary hack for screensharing, where we
2799115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // interpret the startBitrate as the encoder target bitrate. This is
2809115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // to allow for a different max bitrate, so if the codec can't meet
2819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // the target we still allow it to overshoot up to the max before dropping
2829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // frames. This hack should be improved.
2839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (codec_.targetBitrate > 0 &&
2849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        (codec_.codecSpecific.VP8.numberOfTemporalLayers == 2 ||
2859115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org         codec_.simulcastStream[0].numberOfTemporalLayers == 2)) {
2869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      int tl0_bitrate = std::min(codec_.targetBitrate, target_bitrate);
2879115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      max_bitrate = std::min(codec_.maxBitrate, target_bitrate);
2889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      target_bitrate = tl0_bitrate;
2899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
2909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[i].rc_target_bitrate = target_bitrate;
291cce46fc108a70336f0477fd58d41f38e547eeb25philipel    temporal_layers_[stream_idx]->ConfigureBitrates(
292cce46fc108a70336f0477fd58d41f38e547eeb25philipel        target_bitrate, max_bitrate, framerate, &configurations_[i]);
2939115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (vpx_codec_enc_config_set(&encoders_[i], &configurations_[i])) {
2949115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
2959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
2964ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
2979115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  quality_scaler_.ReportFramerate(new_framerate);
2984ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
301b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boströmconst char* VP8EncoderImpl::ImplementationName() const {
302b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström  return "libvpx";
303b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström}
304b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström
3059115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgvoid VP8EncoderImpl::SetStreamState(bool send_stream,
3069115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                                            int stream_idx) {
3079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (send_stream && !send_stream_[stream_idx]) {
3089115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Need a key frame if we have not sent this stream before.
3099115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    key_frame_request_[stream_idx] = true;
3109115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
3119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  send_stream_[stream_idx] = send_stream;
3129115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
3139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgvoid VP8EncoderImpl::SetupTemporalLayers(int num_streams,
315cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                         int num_temporal_layers,
316cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                         const VideoCodec& codec) {
3179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  const Config default_options;
3189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  const TemporalLayers::Factory& tl_factory =
3199115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      (codec.extra_options ? codec.extra_options : &default_options)
3209115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          ->Get<TemporalLayers::Factory>();
3219115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (num_streams == 1) {
3229115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (codec.mode == kScreensharing) {
3239115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // Special mode when screensharing on a single stream.
3242c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng      temporal_layers_.push_back(
3252c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng          new ScreenshareLayers(num_temporal_layers, rand()));
3269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    } else {
3279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      temporal_layers_.push_back(
3289115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          tl_factory.Create(num_temporal_layers, rand()));
3299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
3309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else {
3319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    for (int i = 0; i < num_streams; ++i) {
3329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // TODO(andresp): crash if layers is invalid.
3339115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      int layers = codec.simulcastStream[i].numberOfTemporalLayers;
334cce46fc108a70336f0477fd58d41f38e547eeb25philipel      if (layers < 1)
335cce46fc108a70336f0477fd58d41f38e547eeb25philipel        layers = 1;
3369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      temporal_layers_.push_back(tl_factory.Create(layers, rand()));
3379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
3389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
3399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
3409115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3418d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8EncoderImpl::InitEncode(const VideoCodec* inst,
342cce46fc108a70336f0477fd58d41f38e547eeb25philipel                               int number_of_cores,
343cce46fc108a70336f0477fd58d41f38e547eeb25philipel                               size_t /*maxPayloadSize */) {
3444ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (inst == NULL) {
3454ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3464ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
3474ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (inst->maxFramerate < 1) {
3484ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3494ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
3504ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // allow zero to represent an unspecified maxBitRate
3514ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {
3524ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3534ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
3549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (inst->width <= 1 || inst->height <= 1) {
3554ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3564ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
3574ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (number_of_cores < 1) {
3584ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3594ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
3609115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (inst->codecSpecific.VP8.feedbackModeOn &&
3619115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      inst->numberOfSimulcastStreams > 1) {
3629115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3639115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
3649115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (inst->codecSpecific.VP8.automaticResizeOn &&
3659115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      inst->numberOfSimulcastStreams > 1) {
3669115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
3679115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
3684ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  int retVal = Release();
3694ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (retVal < 0) {
3704ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return retVal;
3714ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
3739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int number_of_streams = NumberOfStreams(*inst);
3749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  bool doing_simulcast = (number_of_streams > 1);
3759115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3769115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (doing_simulcast && !ValidSimulcastResolutions(*inst, number_of_streams)) {
3779115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
378d25b602dc0e70282e1f0223e5909534fa81053f0pbos@webrtc.org  }
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
380cce46fc108a70336f0477fd58d41f38e547eeb25philipel  int num_temporal_layers =
381cce46fc108a70336f0477fd58d41f38e547eeb25philipel      doing_simulcast ? inst->simulcastStream[0].numberOfTemporalLayers
382cce46fc108a70336f0477fd58d41f38e547eeb25philipel                      : inst->codecSpecific.VP8.numberOfTemporalLayers;
3839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // TODO(andresp): crash if num temporal layers is bananas.
385cce46fc108a70336f0477fd58d41f38e547eeb25philipel  if (num_temporal_layers < 1)
386cce46fc108a70336f0477fd58d41f38e547eeb25philipel    num_temporal_layers = 1;
3879115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  SetupTemporalLayers(number_of_streams, num_temporal_layers, *inst);
3889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  feedback_mode_ = inst->codecSpecific.VP8.feedbackModeOn;
3909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  timestamp_ = 0;
3929115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  codec_ = *inst;
3939115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
3949115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Code expects simulcastStream resolutions to be correct, make sure they are
3959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // filled even when there are no simulcast layers.
3969115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (codec_.numberOfSimulcastStreams == 0) {
3979115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    codec_.simulcastStream[0].width = codec_.width;
3989115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    codec_.simulcastStream[0].height = codec_.height;
3999115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
4009115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
4019115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  picture_id_.resize(number_of_streams);
4029115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  last_key_frame_picture_id_.resize(number_of_streams);
4039115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  encoded_images_.resize(number_of_streams);
4049115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  encoders_.resize(number_of_streams);
4059115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_.resize(number_of_streams);
4069115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  downsampling_factors_.resize(number_of_streams);
4079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_.resize(number_of_streams);
4089115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  send_stream_.resize(number_of_streams);
4099115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  send_stream_[0] = true;  // For non-simulcast case.
4109115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  cpu_speed_.resize(number_of_streams);
4119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  std::fill(key_frame_request_.begin(), key_frame_request_.end(), false);
4129115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
4139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int idx = number_of_streams - 1;
4149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (int i = 0; i < (number_of_streams - 1); ++i, --idx) {
4159115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int gcd = GCD(inst->simulcastStream[idx].width,
416cce46fc108a70336f0477fd58d41f38e547eeb25philipel                  inst->simulcastStream[idx - 1].width);
4179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    downsampling_factors_[i].num = inst->simulcastStream[idx].width / gcd;
4189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    downsampling_factors_[i].den = inst->simulcastStream[idx - 1].width / gcd;
4199115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    send_stream_[i] = false;
4209115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
4219115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (number_of_streams > 1) {
4229115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    send_stream_[number_of_streams - 1] = false;
4239115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    downsampling_factors_[number_of_streams - 1].num = 1;
4249115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    downsampling_factors_[number_of_streams - 1].den = 1;
4259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
4269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (int i = 0; i < number_of_streams; ++i) {
4279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Random start, 16 bits is enough.
428cce46fc108a70336f0477fd58d41f38e547eeb25philipel    picture_id_[i] = static_cast<uint16_t>(rand()) & 0x7FFF;  // NOLINT
4299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    last_key_frame_picture_id_[i] = -1;
4309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // allocate memory for encoded image
4319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (encoded_images_[i]._buffer != NULL) {
432cce46fc108a70336f0477fd58d41f38e547eeb25philipel      delete[] encoded_images_[i]._buffer;
4339115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
434cce46fc108a70336f0477fd58d41f38e547eeb25philipel    encoded_images_[i]._size =
435cce46fc108a70336f0477fd58d41f38e547eeb25philipel        CalcBufferSize(kI420, codec_.width, codec_.height);
4369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoded_images_[i]._buffer = new uint8_t[encoded_images_[i]._size];
4379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoded_images_[i]._completeFrame = true;
4389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
4394ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // populate encoder configuration with default values
440cce46fc108a70336f0477fd58d41f38e547eeb25philipel  if (vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &configurations_[0],
441cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                   0)) {
4424ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
4434ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
4444ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // setting the time base of the codec
4459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_timebase.num = 1;
4469115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_timebase.den = 90000;
4479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_lag_in_frames = 0;  // 0- no frame lagging
4484ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org
4494ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Set the error resilience mode according to user settings.
4504ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  switch (inst->codecSpecific.VP8.resilience) {
4514ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    case kResilienceOff:
4529115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // TODO(marpan): We should set keep error resilience off for this mode,
4539115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // independent of temporal layer settings, and make sure we set
4549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // |codecSpecific.VP8.resilience| = |kResilientStream| at higher level
4559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // code if we want to get error resilience on.
4569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[0].g_error_resilient = 1;
4574ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
4584ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    case kResilientStream:
4599115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[0].g_error_resilient = 1;  // TODO(holmer): Replace with
4604ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // VPX_ERROR_RESILIENT_DEFAULT when we
4614ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // drop support for libvpx 9.6.0.
4624ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
4634ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    case kResilientFrames:
464c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#ifdef INDEPENDENT_PARTITIONS
465cce46fc108a70336f0477fd58d41f38e547eeb25philipel      configurations_[0] - g_error_resilient =
466cce46fc108a70336f0477fd58d41f38e547eeb25philipel          VPX_ERROR_RESILIENT_DEFAULT | VPX_ERROR_RESILIENT_PARTITIONS;
4674ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
468c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#else
4694ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  // Not supported
470c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#endif
4714ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
472a4a88f90c44c6ee287baccae10c7f7ff556dcb20stefan@webrtc.org
4734ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // rate control settings
4749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_dropframe_thresh =
4759115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      inst->codecSpecific.VP8.frameDroppingOn ? 30 : 0;
4769115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_end_usage = VPX_CBR;
4779115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_pass = VPX_RC_ONE_PASS;
4789115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // TODO(hellner): investigate why the following two lines produce
4799115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // automaticResizeOn value of 3 when running
4809115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // WebRtcVideoMediaChannelTest.GetStatsMultipleSendStreams inside the talk
4819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // framework.
4829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // configurations_[0].rc_resize_allowed =
4839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  //    inst->codecSpecific.VP8.automaticResizeOn ? 1 : 0;
4849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_resize_allowed = 0;
4859115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Handle resizing outside of libvpx when doing single-stream.
4869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (inst->codecSpecific.VP8.automaticResizeOn && number_of_streams > 1) {
4879115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[0].rc_resize_allowed = 1;
4889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
4899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_min_quantizer = 2;
4909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (inst->qpMax >= configurations_[0].rc_min_quantizer) {
4919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    qp_max_ = inst->qpMax;
4929115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
4939115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_max_quantizer = qp_max_;
4949115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_undershoot_pct = 100;
4959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_overshoot_pct = 15;
4969115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_buf_initial_sz = 500;
4979115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_buf_optimal_sz = 600;
4989115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].rc_buf_sz = 1000;
4999115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5009115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Set the maximum target size of any key-frame.
5019115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  rc_max_intra_target_ = MaxIntraTarget(configurations_[0].rc_buf_optimal_sz);
5024ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org
5034ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (feedback_mode_) {
5044ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Disable periodic key frames if we get feedback from the decoder
5054ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // through SLI and RPSI.
5069115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[0].kf_mode = VPX_KF_DISABLED;
5079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else if (inst->codecSpecific.VP8.keyFrameInterval > 0) {
5089115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[0].kf_mode = VPX_KF_AUTO;
5099115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[0].kf_max_dist = inst->codecSpecific.VP8.keyFrameInterval;
510e07c661a29058aac858f99c5d0701a52969dfbe4mikhal@webrtc.org  } else {
5119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[0].kf_mode = VPX_KF_DISABLED;
5124ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
5139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Allow the user to set the complexity for the base stream.
5154ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  switch (inst->codecSpecific.VP8.complexity) {
5164ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    case kComplexityHigh:
5179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      cpu_speed_[0] = -5;
5184ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
5194ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    case kComplexityHigher:
5209115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      cpu_speed_[0] = -4;
5214ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
5224ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    case kComplexityMax:
5239115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      cpu_speed_[0] = -3;
5244ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
5254ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    default:
5269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      cpu_speed_[0] = -6;
5274ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      break;
5284ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
5296daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  cpu_speed_default_ = cpu_speed_[0];
5306daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // Set encoding complexity (cpu_speed) based on resolution and/or platform.
5316daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  cpu_speed_[0] = SetCpuSpeed(inst->width, inst->height);
5329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (int i = 1; i < number_of_streams; ++i) {
5336daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org    cpu_speed_[i] =
5346daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org        SetCpuSpeed(inst->simulcastStream[number_of_streams - 1 - i].width,
5356daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org                    inst->simulcastStream[number_of_streams - 1 - i].height);
5369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
5379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_w = inst->width;
5389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_h = inst->height;
5399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5409115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Determine number of threads based on the image size and #cores.
5419115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // TODO(fbarchard): Consider number of Simulcast layers.
542cce46fc108a70336f0477fd58d41f38e547eeb25philipel  configurations_[0].g_threads = NumberOfThreads(
543cce46fc108a70336f0477fd58d41f38e547eeb25philipel      configurations_[0].g_w, configurations_[0].g_h, number_of_cores);
5449115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Creating a wrapper to the image - setting image data to NULL.
5469115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Actual pointer will be set in encode. Setting align to 1, as it
5479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // is meaningless (no memory allocation is done here).
548cce46fc108a70336f0477fd58d41f38e547eeb25philipel  vpx_img_wrap(&raw_images_[0], VPX_IMG_FMT_I420, inst->width, inst->height, 1,
549cce46fc108a70336f0477fd58d41f38e547eeb25philipel               NULL);
5509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (encoders_.size() == 1) {
5529115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    configurations_[0].rc_target_bitrate = inst->startBitrate;
553cce46fc108a70336f0477fd58d41f38e547eeb25philipel    temporal_layers_[0]->ConfigureBitrates(inst->startBitrate, inst->maxBitrate,
5549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                                           inst->maxFramerate,
5559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                                           &configurations_[0]);
5569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else {
5579115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Note the order we use is different from webm, we have lowest resolution
5589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // at position 0 and they have highest resolution at position 0.
5599115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int stream_idx = encoders_.size() - 1;
5601b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    std::vector<int> stream_bitrates =
5611b9add9df9cdab004a11e75900a341a346ce2049Peter Boström        GetStreamBitratesKbps(codec_, inst->startBitrate);
5621b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
5631b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    configurations_[0].rc_target_bitrate = stream_bitrates[stream_idx];
5641b9add9df9cdab004a11e75900a341a346ce2049Peter Boström    temporal_layers_[stream_idx]->ConfigureBitrates(
5651b9add9df9cdab004a11e75900a341a346ce2049Peter Boström        stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate,
5661b9add9df9cdab004a11e75900a341a346ce2049Peter Boström        &configurations_[0]);
5679115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    --stream_idx;
5689115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    for (size_t i = 1; i < encoders_.size(); ++i, --stream_idx) {
5699115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      memcpy(&configurations_[i], &configurations_[0],
5709115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org             sizeof(configurations_[0]));
5719115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5729115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[i].g_w = inst->simulcastStream[stream_idx].width;
5739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[i].g_h = inst->simulcastStream[stream_idx].height;
5749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5759115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // Use 1 thread for lower resolutions.
5769115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      configurations_[i].g_threads = 1;
5779115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5789115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // Setting alignment to 32 - as that ensures at least 16 for all
5799115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // planes (32 for Y, 16 for U,V). Libvpx sets the requested stride for
5809115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // the y plane, but only half of it to the u and v planes.
5819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      vpx_img_alloc(&raw_images_[i], VPX_IMG_FMT_I420,
5829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                    inst->simulcastStream[stream_idx].width,
5839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                    inst->simulcastStream[stream_idx].height, kVp832ByteAlign);
5841b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      SetStreamState(stream_bitrates[stream_idx] > 0, stream_idx);
5851b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      configurations_[i].rc_target_bitrate = stream_bitrates[stream_idx];
5861b9add9df9cdab004a11e75900a341a346ce2049Peter Boström      temporal_layers_[stream_idx]->ConfigureBitrates(
5871b9add9df9cdab004a11e75900a341a346ce2049Peter Boström          stream_bitrates[stream_idx], inst->maxBitrate, inst->maxFramerate,
5881b9add9df9cdab004a11e75900a341a346ce2049Peter Boström          &configurations_[i]);
5899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
5909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
5919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
5929115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  rps_.Init();
59317417707428816ffb88d9c71dcc8a5d492cf9fdfPeter Boström  // Disable both high-QP limits and framedropping. Both are handled by libvpx
59417417707428816ffb88d9c71dcc8a5d492cf9fdfPeter Boström  // internally.
59517417707428816ffb88d9c71dcc8a5d492cf9fdfPeter Boström  const int kDisabledBadQpThreshold = 64;
5966e2ce6e1ae41d8eeb0f233cbd26087daa03ab702jackychen  quality_scaler_.Init(codec_.qpMax / QualityScaler::kDefaultLowQpDenominator,
59717417707428816ffb88d9c71dcc8a5d492cf9fdfPeter Boström                       kDisabledBadQpThreshold, false);
598a0d7827b1631fa8e2cf8957a76736ab159cb962apbos@webrtc.org  quality_scaler_.ReportFramerate(codec_.maxFramerate);
5999115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
6004306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson  // Only apply scaling to improve for single-layer streams. The scaling metrics
6014306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson  // use frame drops as a signal and is only applicable when we drop frames.
6024306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson  quality_scaler_enabled_ = encoders_.size() == 1 &&
6034306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson                            configurations_[0].rc_dropframe_thresh > 0 &&
6044306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson                            codec_.codecSpecific.VP8.automaticResizeOn;
6054306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson
6069115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return InitAndSetControlSettings();
6079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org}
6089115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
6096daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.orgint VP8EncoderImpl::SetCpuSpeed(int width, int height) {
610e87d48719f8478148fc6ec28c3b3663709d585a4Stefan Holmer#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)
6116daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // On mobile platform, always set to -12 to leverage between cpu usage
6126daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // and video quality.
6136daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  return -12;
6146daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org#else
6156daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // For non-ARM, increase encoding complexity (i.e., use lower speed setting)
6166daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // if resolution is below CIF. Otherwise, keep the default/user setting
6176daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // (|cpu_speed_default_|) set on InitEncode via codecSpecific.VP8.complexity.
6186daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  if (width * height < 352 * 288)
6196daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org    return (cpu_speed_default_ < -4) ? -4 : cpu_speed_default_;
6206daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  else
6216daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org    return cpu_speed_default_;
6226daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org#endif
6236daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org}
6246daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org
6259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgint VP8EncoderImpl::NumberOfThreads(int width, int height, int cpus) {
6269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (width * height >= 1920 * 1080 && cpus > 8) {
6279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return 8;  // 8 threads for 1080p on high perf machines.
6289115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else if (width * height > 1280 * 960 && cpus >= 6) {
6299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // 3 threads for 1080p.
6309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return 3;
6319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else if (width * height > 640 * 480 && cpus >= 3) {
6329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // 2 threads for qHD/HD.
6339115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return 2;
6349115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else {
6359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // 1 thread for VGA or less.
6369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    return 1;
6379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
638470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
639470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6409115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgint VP8EncoderImpl::InitAndSetControlSettings() {
6414ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  vpx_codec_flags_t flags = 0;
6424ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  flags |= VPX_CODEC_USE_OUTPUT_PARTITION;
6439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
6449115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (encoders_.size() > 1) {
645cce46fc108a70336f0477fd58d41f38e547eeb25philipel    int error = vpx_codec_enc_init_multi(&encoders_[0], vpx_codec_vp8_cx(),
646cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                         &configurations_[0], encoders_.size(),
647cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                         flags, &downsampling_factors_[0]);
6489115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (error) {
6499115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
6509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
6519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else {
652cce46fc108a70336f0477fd58d41f38e547eeb25philipel    if (vpx_codec_enc_init(&encoders_[0], vpx_codec_vp8_cx(),
653cce46fc108a70336f0477fd58d41f38e547eeb25philipel                           &configurations_[0], flags)) {
6549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
6559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
6564ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
6579115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Enable denoising for the highest resolution stream, and for
6589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // the second highest resolution if we are doing more than 2
6599115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // spatial layers/streams.
6609115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // TODO(holmer): Investigate possibility of adding a libvpx API
6619115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // for getting the denoised frame from the encoder and using that
6629115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // when encoding lower resolution streams. Would it work with the
6639115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // multi-res encoding feature?
6649115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  denoiserState denoiser_state = kDenoiserOnYOnly;
665e87d48719f8478148fc6ec28c3b3663709d585a4Stefan Holmer#if defined(WEBRTC_ARCH_ARM) || defined(WEBRTC_ARCH_ARM64)
6669115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  denoiser_state = kDenoiserOnYOnly;
6679115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org#else
6689115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  denoiser_state = kDenoiserOnAdaptive;
669662651ac958ccc785c638f7bcf44e08f11eb95a8fbarchard@google.com#endif
670cce46fc108a70336f0477fd58d41f38e547eeb25philipel  vpx_codec_control(
671cce46fc108a70336f0477fd58d41f38e547eeb25philipel      &encoders_[0], VP8E_SET_NOISE_SENSITIVITY,
672cce46fc108a70336f0477fd58d41f38e547eeb25philipel      codec_.codecSpecific.VP8.denoisingOn ? denoiser_state : kDenoiserOff);
6739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (encoders_.size() > 2) {
674cce46fc108a70336f0477fd58d41f38e547eeb25philipel    vpx_codec_control(
675cce46fc108a70336f0477fd58d41f38e547eeb25philipel        &encoders_[1], VP8E_SET_NOISE_SENSITIVITY,
676cce46fc108a70336f0477fd58d41f38e547eeb25philipel        codec_.codecSpecific.VP8.denoisingOn ? denoiser_state : kDenoiserOff);
6779115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
6789115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t i = 0; i < encoders_.size(); ++i) {
679fb30c1b5d1effcc82a96fdf40814a03baf0727bfsprang    // Allow more screen content to be detected as static.
680fb30c1b5d1effcc82a96fdf40814a03baf0727bfsprang    vpx_codec_control(&(encoders_[i]), VP8E_SET_STATIC_THRESHOLD,
681fb30c1b5d1effcc82a96fdf40814a03baf0727bfsprang                      codec_.mode == kScreensharing ? 300 : 1);
6829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_control(&(encoders_[i]), VP8E_SET_CPUUSED, cpu_speed_[i]);
6839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_control(&(encoders_[i]), VP8E_SET_TOKEN_PARTITIONS,
6849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                      static_cast<vp8e_token_partitions>(token_partitions_));
6859115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_control(&(encoders_[i]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
6869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                      rc_max_intra_target_);
6872c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    // VP8E_SET_SCREEN_CONTENT_MODE 2 = screen content with more aggressive
6882c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    // rate control (drop frames on large target bitrate overshoot)
6899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_control(&(encoders_[i]), VP8E_SET_SCREEN_CONTENT_MODE,
6902c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng                      codec_.mode == kScreensharing ? 2 : 0);
6919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
6924ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  inited_ = true;
6934ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
694470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
695470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
6968d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orguint32_t VP8EncoderImpl::MaxIntraTarget(uint32_t optimalBuffersize) {
6974ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Set max to the optimal buffer level (normalized by target BR),
6984ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // and scaled by a scalePar.
6994ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Max target size = scalePar * optimalBufferSize * targetBR[Kbps].
7004ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // This values is presented in percentage of perFrameBw:
7014ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // perFrameBw = targetBR[Kbps] * 1000 / frameRate.
7024ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // The target in % is as follows:
7034ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org
7044ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  float scalePar = 0.5;
7054ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  uint32_t targetPct = optimalBuffersize * scalePar * codec_.maxFramerate / 10;
7064ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org
7074ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Don't go below 3 times the per frame bandwidth.
7084ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  const uint32_t minIntraTh = 300;
709cce46fc108a70336f0477fd58d41f38e547eeb25philipel  return (targetPct < minIntraTh) ? minIntraTh : targetPct;
710470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
711470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
7124765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchezint VP8EncoderImpl::Encode(const VideoFrame& frame,
7134765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchez                           const CodecSpecificInfo* codec_specific_info,
71422993e1a0c114122fc1b9de0fc74d4096ec868bdpbos                           const std::vector<FrameType>* frame_types) {
7152c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng  if (!inited_)
7164ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
7172c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng  if (frame.IsZeroSize())
7184ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
7192c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng  if (encoded_complete_callback_ == NULL)
7204ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
72126762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org
7224306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson  if (quality_scaler_enabled_)
7236e2ce6e1ae41d8eeb0f233cbd26087daa03ab702jackychen    quality_scaler_.OnEncodeFrame(frame);
7244765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchez  const VideoFrame& input_image =
7254306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson      quality_scaler_enabled_ ? quality_scaler_.GetScaledFrame(frame) : frame;
726c5300436841092d6d2b01eae1179a2c1eb373f1bstefan@webrtc.org
7274306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson  if (quality_scaler_enabled_ && (input_image.width() != codec_.width ||
728cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                  input_image.height() != codec_.height)) {
7299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int ret = UpdateCodecFrameSize(input_image);
7309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (ret < 0)
7319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      return ret;
7329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
733a0d7827b1631fa8e2cf8957a76736ab159cb962apbos@webrtc.org
734e155dbeae972f788b8766b4d0d2cefde2e952a10magjed@webrtc.org  // Since we are extracting raw pointers from |input_image| to
735e155dbeae972f788b8766b4d0d2cefde2e952a10magjed@webrtc.org  // |raw_images_[0]|, the resolution of these frames must match. Note that
736e155dbeae972f788b8766b4d0d2cefde2e952a10magjed@webrtc.org  // |input_image| might be scaled from |frame|. In that case, the resolution of
737e155dbeae972f788b8766b4d0d2cefde2e952a10magjed@webrtc.org  // |raw_images_[0]| should have been updated in UpdateCodecFrameSize.
73891d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK_EQ(input_image.width(), static_cast<int>(raw_images_[0].d_w));
73991d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK_EQ(input_image.height(), static_cast<int>(raw_images_[0].d_h));
740e155dbeae972f788b8766b4d0d2cefde2e952a10magjed@webrtc.org
7419115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Image in vpx_image_t format.
7429115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Input image is const. VP8's raw image is not defined as const.
7439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].planes[VPX_PLANE_Y] =
744cce46fc108a70336f0477fd58d41f38e547eeb25philipel      const_cast<uint8_t*>(input_image.buffer(kYPlane));
7459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].planes[VPX_PLANE_U] =
746cce46fc108a70336f0477fd58d41f38e547eeb25philipel      const_cast<uint8_t*>(input_image.buffer(kUPlane));
7479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].planes[VPX_PLANE_V] =
748cce46fc108a70336f0477fd58d41f38e547eeb25philipel      const_cast<uint8_t*>(input_image.buffer(kVPlane));
7499115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
7509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].stride[VPX_PLANE_Y] = input_image.stride(kYPlane);
7519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].stride[VPX_PLANE_U] = input_image.stride(kUPlane);
7529115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].stride[VPX_PLANE_V] = input_image.stride(kVPlane);
7539115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
7549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t i = 1; i < encoders_.size(); ++i) {
7559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Scale the image down a number of times by downsampling factor
7569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    libyuv::I420Scale(
757cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].planes[VPX_PLANE_Y],
758cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].stride[VPX_PLANE_Y],
759cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].planes[VPX_PLANE_U],
760cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].stride[VPX_PLANE_U],
761cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].planes[VPX_PLANE_V],
762cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].stride[VPX_PLANE_V], raw_images_[i - 1].d_w,
763cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i - 1].d_h, raw_images_[i].planes[VPX_PLANE_Y],
764cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i].stride[VPX_PLANE_Y], raw_images_[i].planes[VPX_PLANE_U],
765cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i].stride[VPX_PLANE_U], raw_images_[i].planes[VPX_PLANE_V],
766cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i].stride[VPX_PLANE_V], raw_images_[i].d_w,
767cce46fc108a70336f0477fd58d41f38e547eeb25philipel        raw_images_[i].d_h, libyuv::kFilterBilinear);
7689115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
7699115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  vpx_enc_frame_flags_t flags[kMaxSimulcastStreams];
7709115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t i = 0; i < encoders_.size(); ++i) {
7719115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int ret = temporal_layers_[i]->EncodeFlags(input_image.timestamp());
77226762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org    if (ret < 0) {
7739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // Drop this frame.
7749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      return WEBRTC_VIDEO_CODEC_OK;
77526762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org    }
7769115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    flags[i] = ret;
77726762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org  }
7789115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  bool send_key_frame = false;
7799115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t i = 0; i < key_frame_request_.size() && i < send_stream_.size();
7809115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org       ++i) {
7819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (key_frame_request_[i] && send_stream_[i]) {
7829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      send_key_frame = true;
7839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      break;
7849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
7859115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
7869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (!send_key_frame && frame_types) {
7879115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    for (size_t i = 0; i < frame_types->size() && i < send_stream_.size();
7889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org         ++i) {
78949e196af4060624d620297a6bc017699daa33550Peter Boström      if ((*frame_types)[i] == kVideoFrameKey && send_stream_[i]) {
7909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        send_key_frame = true;
7919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        break;
7929115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      }
7939115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
7949115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
7959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // The flag modification below (due to forced key frame, RPS, etc.,) for now
7969115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // will be the same for all encoders/spatial layers.
7979115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // TODO(marpan/holmer): Allow for key frame request to be set per encoder.
7989115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  bool only_predict_from_key_frame = false;
7999115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (send_key_frame) {
8009115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // Adapt the size of the key frame when in screenshare with 1 temporal
8019115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // layer.
802cce46fc108a70336f0477fd58d41f38e547eeb25philipel    if (encoders_.size() == 1 && codec_.mode == kScreensharing &&
803cce46fc108a70336f0477fd58d41f38e547eeb25philipel        codec_.codecSpecific.VP8.numberOfTemporalLayers <= 1) {
8049115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      const uint32_t forceKeyFrameIntraTh = 100;
8059115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      vpx_codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
8069115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                        forceKeyFrameIntraTh);
8079115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
8084ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Key frame request from caller.
8094ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Will update both golden and alt-ref.
8109115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    for (size_t i = 0; i < encoders_.size(); ++i) {
8119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      flags[i] = VPX_EFLAG_FORCE_KF;
8129115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
8139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    std::fill(key_frame_request_.begin(), key_frame_request_.end(), false);
8149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  } else if (codec_specific_info &&
815cce46fc108a70336f0477fd58d41f38e547eeb25philipel             codec_specific_info->codecType == kVideoCodecVP8) {
8169115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (feedback_mode_) {
8179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // Handle RPSI and SLI messages and set up the appropriate encode flags.
8189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      bool sendRefresh = false;
8194ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      if (codec_specific_info->codecSpecific.VP8.hasReceivedRPSI) {
820cce46fc108a70336f0477fd58d41f38e547eeb25philipel        rps_.ReceivedRPSI(codec_specific_info->codecSpecific.VP8.pictureIdRPSI);
8214ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      }
8224ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      if (codec_specific_info->codecSpecific.VP8.hasReceivedSLI) {
8239115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        sendRefresh = rps_.ReceivedSLI(input_image.timestamp());
8249115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      }
8259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      for (size_t i = 0; i < encoders_.size(); ++i) {
8269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        flags[i] = rps_.EncodeFlags(picture_id_[i], sendRefresh,
8279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                                    input_image.timestamp());
8289115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      }
8299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    } else {
8309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      if (codec_specific_info->codecSpecific.VP8.hasReceivedRPSI) {
8319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        // Is this our last key frame? If not ignore.
8329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        // |picture_id_| is defined per spatial stream/layer, so check that
8339115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        // |RPSI| matches the last key frame from any of the spatial streams.
8349115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        // If so, then all spatial streams for this encoding will predict from
8359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        // its long-term reference (last key frame).
8369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        int RPSI = codec_specific_info->codecSpecific.VP8.pictureIdRPSI;
8379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        for (size_t i = 0; i < encoders_.size(); ++i) {
8389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          if (last_key_frame_picture_id_[i] == RPSI) {
8399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            // Request for a long term reference frame.
8409115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            // Note 1: overwrites any temporal settings.
8419115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            // Note 2: VP8_EFLAG_NO_UPD_ENTROPY is not needed as that flag is
8429115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            //         set by error_resilient mode.
8439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            for (size_t j = 0; j < encoders_.size(); ++j) {
8449115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org              flags[j] = VP8_EFLAG_NO_UPD_ARF;
8459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org              flags[j] |= VP8_EFLAG_NO_REF_GF;
8469115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org              flags[j] |= VP8_EFLAG_NO_REF_LAST;
8479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            }
8489115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            only_predict_from_key_frame = true;
8499115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            break;
8509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          }
8519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        }
852a4a88f90c44c6ee287baccae10c7f7ff556dcb20stefan@webrtc.org      }
853470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
8544ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
8559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Set the encoder frame flags and temporal layer_id for each spatial stream.
8569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Note that |temporal_layers_| are defined starting from lowest resolution at
8579115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // position 0 to highest resolution at position |encoders_.size() - 1|,
8589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // whereas |encoder_| is from highest to lowest resolution.
8599115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  size_t stream_idx = encoders_.size() - 1;
8609115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t i = 0; i < encoders_.size(); ++i, --stream_idx) {
8612c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    // Allow the layers adapter to temporarily modify the configuration. This
8622c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    // change isn't stored in configurations_ so change will be discarded at
8632c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    // the next update.
8642c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    vpx_codec_enc_cfg_t temp_config;
8652c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    memcpy(&temp_config, &configurations_[i], sizeof(vpx_codec_enc_cfg_t));
8662c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    if (temporal_layers_[stream_idx]->UpdateConfiguration(&temp_config)) {
8672c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng      if (vpx_codec_enc_config_set(&encoders_[i], &temp_config))
8682c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng        return WEBRTC_VIDEO_CODEC_ERROR;
8692c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    }
8702c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng
8719115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_control(&encoders_[i], VP8E_SET_FRAME_FLAGS, flags[stream_idx]);
872cce46fc108a70336f0477fd58d41f38e547eeb25philipel    vpx_codec_control(&encoders_[i], VP8E_SET_TEMPORAL_LAYER_ID,
8739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                      temporal_layers_[stream_idx]->CurrentLayerId());
8749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
8754ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // TODO(holmer): Ideally the duration should be the timestamp diff of this
8764ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // frame and the next frame to be encoded, which we don't have. Instead we
8774ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // would like to use the duration of the previous frame. Unfortunately the
8784ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // rate control seems to be off with that setup. Using the average input
8794ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // frame rate to calculate an average duration for now.
8804ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  assert(codec_.maxFramerate > 0);
8814ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  uint32_t duration = 90000 / codec_.maxFramerate;
8829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org
8839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Note we must pass 0 for |flags| field in encode call below since they are
8849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // set above in |vpx_codec_control| function for each encoder/spatial layer.
8859115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int error = vpx_codec_encode(&encoders_[0], &raw_images_[0], timestamp_,
8869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                               duration, 0, VPX_DL_REALTIME);
8879115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Reset specific intra frame thresholds, following the key frame.
8889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (send_key_frame) {
8899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_control(&(encoders_[0]), VP8E_SET_MAX_INTRA_BITRATE_PCT,
890cce46fc108a70336f0477fd58d41f38e547eeb25philipel                      rc_max_intra_target_);
8919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
8922c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng  if (error)
8934ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
8944ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  timestamp_ += duration;
8959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  return GetEncodedPartitions(input_image, only_predict_from_key_frame);
896c3d891059e117357011e414263af0f519313d440stefan@webrtc.org}
897c3d891059e117357011e414263af0f519313d440stefan@webrtc.org
8989115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org// TODO(pbos): Make sure this works for properly for >1 encoders.
8994765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchezint VP8EncoderImpl::UpdateCodecFrameSize(const VideoFrame& input_image) {
9003263a7a61610c9029ef9bcec6dddf50fcacd1c27mikhal@webrtc.org  codec_.width = input_image.width();
9013263a7a61610c9029ef9bcec6dddf50fcacd1c27mikhal@webrtc.org  codec_.height = input_image.height();
902110443c1ec40b764db81a6b9679885aec3e4a218Asa Persson  if (codec_.numberOfSimulcastStreams <= 1) {
903110443c1ec40b764db81a6b9679885aec3e4a218Asa Persson    // For now scaling is only used for single-layer streams.
904110443c1ec40b764db81a6b9679885aec3e4a218Asa Persson    codec_.simulcastStream[0].width = input_image.width();
905110443c1ec40b764db81a6b9679885aec3e4a218Asa Persson    codec_.simulcastStream[0].height = input_image.height();
906110443c1ec40b764db81a6b9679885aec3e4a218Asa Persson  }
9076daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org  // Update the cpu_speed setting for resolution change.
908cce46fc108a70336f0477fd58d41f38e547eeb25philipel  vpx_codec_control(&(encoders_[0]), VP8E_SET_CPUUSED,
9096daacbc8aea2e3e14a320b28502c4dc1db21d175marpan@webrtc.org                    SetCpuSpeed(codec_.width, codec_.height));
9109115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].w = codec_.width;
9119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].h = codec_.height;
9129115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].d_w = codec_.width;
9139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  raw_images_[0].d_h = codec_.height;
9149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  vpx_img_set_rect(&raw_images_[0], 0, 0, codec_.width, codec_.height);
91526762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org
91626762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org  // Update encoder context for new frame size.
91726762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org  // Change of frame size will automatically trigger a key frame.
9189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_w = codec_.width;
9199115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  configurations_[0].g_h = codec_.height;
9209115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (vpx_codec_enc_config_set(&encoders_[0], &configurations_[0])) {
92126762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
92226762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org  }
92326762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
92426762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org}
92526762e3e40f682d37f33fd797383de1c7562f855marpan@webrtc.org
9269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgvoid VP8EncoderImpl::PopulateCodecSpecific(
9279115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    CodecSpecificInfo* codec_specific,
9289115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    const vpx_codec_cx_pkt_t& pkt,
9299115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int stream_idx,
9309115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    uint32_t timestamp,
9319115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    bool only_predicting_from_key_frame) {
932c3d891059e117357011e414263af0f519313d440stefan@webrtc.org  assert(codec_specific != NULL);
933c3d891059e117357011e414263af0f519313d440stefan@webrtc.org  codec_specific->codecType = kVideoCodecVP8;
9349115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  CodecSpecificInfoVP8* vp8Info = &(codec_specific->codecSpecific.VP8);
9359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  vp8Info->pictureId = picture_id_[stream_idx];
9369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (pkt.data.frame.flags & VPX_FRAME_IS_KEY) {
9379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    last_key_frame_picture_id_[stream_idx] = picture_id_[stream_idx];
9389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  }
9399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  vp8Info->simulcastIdx = stream_idx;
940859626570a75caa06346e112d1b6b2628f11074fhenrik.lundin@webrtc.org  vp8Info->keyIdx = kNoKeyIdx;  // TODO(hlundin) populate this
941cce46fc108a70336f0477fd58d41f38e547eeb25philipel  vp8Info->nonReference =
942cce46fc108a70336f0477fd58d41f38e547eeb25philipel      (pkt.data.frame.flags & VPX_FRAME_IS_DROPPABLE) ? true : false;
9439115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  bool base_layer_sync_point = (pkt.data.frame.flags & VPX_FRAME_IS_KEY) ||
944cce46fc108a70336f0477fd58d41f38e547eeb25philipel                               only_predicting_from_key_frame;
9459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  temporal_layers_[stream_idx]->PopulateCodecSpecific(base_layer_sync_point,
946cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                                      vp8Info, timestamp);
9479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Prepare next.
9489115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  picture_id_[stream_idx] = (picture_id_[stream_idx] + 1) & 0x7FFF;
949c3d891059e117357011e414263af0f519313d440stefan@webrtc.org}
950c3d891059e117357011e414263af0f519313d440stefan@webrtc.org
9514765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchezint VP8EncoderImpl::GetEncodedPartitions(const VideoFrame& input_image,
9524765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchez                                         bool only_predicting_from_key_frame) {
953da535c405597864b8396b2029dec70ab9fb76e8basapersson  int bw_resolutions_disabled =
954da535c405597864b8396b2029dec70ab9fb76e8basapersson      (encoders_.size() > 1) ? NumStreamsDisabled(send_stream_) : -1;
955da535c405597864b8396b2029dec70ab9fb76e8basapersson
9569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  int stream_idx = static_cast<int>(encoders_.size()) - 1;
9572c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng  int result = WEBRTC_VIDEO_CODEC_OK;
9589115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  for (size_t encoder_idx = 0; encoder_idx < encoders_.size();
959cce46fc108a70336f0477fd58d41f38e547eeb25philipel       ++encoder_idx, --stream_idx) {
9609115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    vpx_codec_iter_t iter = NULL;
9619115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    int part_idx = 0;
9629115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoded_images_[encoder_idx]._length = 0;
96349e196af4060624d620297a6bc017699daa33550Peter Boström    encoded_images_[encoder_idx]._frameType = kVideoFrameDelta;
9649115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    RTPFragmentationHeader frag_info;
9659115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // token_partitions_ is number of bits used.
966cce46fc108a70336f0477fd58d41f38e547eeb25philipel    frag_info.VerifyAndAllocateFragmentationHeader((1 << token_partitions_) +
967cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                                   1);
9689115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    CodecSpecificInfo codec_specific;
969cce46fc108a70336f0477fd58d41f38e547eeb25philipel    const vpx_codec_cx_pkt_t* pkt = NULL;
970cce46fc108a70336f0477fd58d41f38e547eeb25philipel    while ((pkt = vpx_codec_get_cx_data(&encoders_[encoder_idx], &iter)) !=
971cce46fc108a70336f0477fd58d41f38e547eeb25philipel           NULL) {
9729115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      switch (pkt->kind) {
9739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        case VPX_CODEC_CX_FRAME_PKT: {
9749115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          uint32_t length = encoded_images_[encoder_idx]._length;
9759115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          memcpy(&encoded_images_[encoder_idx]._buffer[length],
976cce46fc108a70336f0477fd58d41f38e547eeb25philipel                 pkt->data.frame.buf, pkt->data.frame.sz);
9779115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          frag_info.fragmentationOffset[part_idx] = length;
978cce46fc108a70336f0477fd58d41f38e547eeb25philipel          frag_info.fragmentationLength[part_idx] = pkt->data.frame.sz;
9799115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          frag_info.fragmentationPlType[part_idx] = 0;  // not known here
9809115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          frag_info.fragmentationTimeDiff[part_idx] = 0;
9819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          encoded_images_[encoder_idx]._length += pkt->data.frame.sz;
9829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          assert(length <= encoded_images_[encoder_idx]._size);
9839115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          ++part_idx;
9849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          break;
9859115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        }
9869115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        default:
9879115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          break;
988c3d891059e117357011e414263af0f519313d440stefan@webrtc.org      }
9899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      // End of frame
9909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      if ((pkt->data.frame.flags & VPX_FRAME_IS_FRAGMENT) == 0) {
9919115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        // check if encoded frame is a key frame
9929115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        if (pkt->data.frame.flags & VPX_FRAME_IS_KEY) {
99349e196af4060624d620297a6bc017699daa33550Peter Boström          encoded_images_[encoder_idx]._frameType = kVideoFrameKey;
9949115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org          rps_.EncodedKeyFrame(picture_id_[stream_idx]);
9959115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        }
9969115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        PopulateCodecSpecific(&codec_specific, *pkt, stream_idx,
9979115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                              input_image.timestamp(),
9989115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                              only_predicting_from_key_frame);
999c3d891059e117357011e414263af0f519313d440stefan@webrtc.org        break;
1000c3d891059e117357011e414263af0f519313d440stefan@webrtc.org      }
1001c3d891059e117357011e414263af0f519313d440stefan@webrtc.org    }
10029115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoded_images_[encoder_idx]._timeStamp = input_image.timestamp();
10039115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    encoded_images_[encoder_idx].capture_time_ms_ =
10049115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        input_image.render_time_ms();
10052c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng
10062c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    int qp = -1;
10072c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng    vpx_codec_control(&encoders_[encoder_idx], VP8E_GET_LAST_QUANTIZER_64, &qp);
10089115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    temporal_layers_[stream_idx]->FrameEncoded(
10099115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        encoded_images_[encoder_idx]._length,
10102c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng        encoded_images_[encoder_idx]._timeStamp, qp);
10119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (send_stream_[stream_idx]) {
10129115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      if (encoded_images_[encoder_idx]._length > 0) {
10139115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        TRACE_COUNTER_ID1("webrtc", "EncodedFrameSize", encoder_idx,
10149115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                          encoded_images_[encoder_idx]._length);
10159115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        encoded_images_[encoder_idx]._encodedHeight =
10169115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            codec_.simulcastStream[stream_idx].height;
10179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        encoded_images_[encoder_idx]._encodedWidth =
10189115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org            codec_.simulcastStream[stream_idx].width;
10194306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson        encoded_images_[encoder_idx]
10204306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson            .adapt_reason_.quality_resolution_downscales =
10214306fc70d778887d8a2ea71b6f4bc6a12d1d9447asapersson            quality_scaler_enabled_ ? quality_scaler_.downscale_shift() : -1;
1022da535c405597864b8396b2029dec70ab9fb76e8basapersson        // Report once per frame (lowest stream always sent).
1023da535c405597864b8396b2029dec70ab9fb76e8basapersson        encoded_images_[encoder_idx].adapt_reason_.bw_resolutions_disabled =
1024da535c405597864b8396b2029dec70ab9fb76e8basapersson            (stream_idx == 0) ? bw_resolutions_disabled : -1;
10259115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org        encoded_complete_callback_->Encoded(encoded_images_[encoder_idx],
10269115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org                                            &codec_specific, &frag_info);
10272c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng      } else if (codec_.mode == kScreensharing) {
10282c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng        result = WEBRTC_VIDEO_CODEC_TARGET_BITRATE_OVERSHOOT;
1029c3d891059e117357011e414263af0f519313d440stefan@webrtc.org      }
1030c3d891059e117357011e414263af0f519313d440stefan@webrtc.org    }
1031c3d891059e117357011e414263af0f519313d440stefan@webrtc.org  }
10329115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (encoders_.size() == 1 && send_stream_[0]) {
10339115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (encoded_images_[0]._length > 0) {
10349115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      int qp;
10359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      vpx_codec_control(&encoders_[0], VP8E_GET_LAST_QUANTIZER_64, &qp);
103698d8cf58ee8c7c7b0672ce7955313a31824d6f3ajackychen      quality_scaler_.ReportQP(qp);
10379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    } else {
10389115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      quality_scaler_.ReportDroppedFrame();
10399115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
10400c2adf0b75e74bbd0af0970c913f240b3b4947c3stefan@webrtc.org  }
10412c4c9148191a10c0e82c9a209d454c6b1ebbaf20Erik Språng  return result;
1042c3d891059e117357011e414263af0f519313d440stefan@webrtc.org}
1043c3d891059e117357011e414263af0f519313d440stefan@webrtc.org
104416825b1a828bb4ff40f7682040e43a239b7b8ca3pkasting@chromium.orgint VP8EncoderImpl::SetChannelParameters(uint32_t packetLoss, int64_t rtt) {
10459115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  rps_.SetRtt(rtt);
1046a4a88f90c44c6ee287baccae10c7f7ff556dcb20stefan@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1047470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1048470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10498d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8EncoderImpl::RegisterEncodeCompleteCallback(
10504ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    EncodedImageCallback* callback) {
10514ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  encoded_complete_callback_ = callback;
10524ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1053470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1054470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10558d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgVP8DecoderImpl::VP8DecoderImpl()
10564ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    : decode_complete_callback_(NULL),
10574ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      inited_(false),
10584ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      feedback_mode_(false),
10594ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      decoder_(NULL),
10604ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      last_keyframe_(),
10614ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      image_format_(VPX_IMG_FMT_NONE),
10624ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      ref_frame_(NULL),
10634ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_(-1),
10649115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      last_frame_width_(0),
10659115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      last_frame_height_(0),
1066cce46fc108a70336f0477fd58d41f38e547eeb25philipel      key_frame_required_(true) {}
1067470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10688d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgVP8DecoderImpl::~VP8DecoderImpl() {
10698d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org  inited_ = true;  // in order to do the actual release
10704ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  Release();
1071470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1072470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
10738d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8DecoderImpl::Reset() {
10744ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (!inited_) {
10754ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
10764ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
10774ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  InitDecode(&codec_, 1);
10784ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  propagation_cnt_ = -1;
10794ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
10804ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org}
1081470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1082cce46fc108a70336f0477fd58d41f38e547eeb25philipelint VP8DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) {
10834ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  int ret_val = Release();
10848d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org  if (ret_val < 0) {
10854ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return ret_val;
10864ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
10874ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (decoder_ == NULL) {
10889115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    decoder_ = new vpx_codec_ctx_t;
10894ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
10909115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (inst && inst->codecType == kVideoCodecVP8) {
10914ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    feedback_mode_ = inst->codecSpecific.VP8.feedbackModeOn;
10924ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1093cce46fc108a70336f0477fd58d41f38e547eeb25philipel  vpx_codec_dec_cfg_t cfg;
10944ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Setting number of threads to a constant value (1)
10954ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  cfg.threads = 1;
10968d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org  cfg.h = cfg.w = 0;  // set after decode
1097470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1098cce46fc108a70336f0477fd58d41f38e547eeb25philipel  vpx_codec_flags_t flags = 0;
1099e87d48719f8478148fc6ec28c3b3663709d585a4Stefan Holmer#if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64)
1100dc257b578188c0bd4a3ee153b42cc7558f725bb9stefan@webrtc.org  flags = VPX_CODEC_USE_POSTPROC;
1101c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#ifdef INDEPENDENT_PARTITIONS
11024ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  flags |= VPX_CODEC_USE_INPUT_PARTITION;
1103c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#endif
11046724cf8183f30408a483639db4c622456b94f656mikhal@webrtc.org#endif
11052cdc7b94d2784121c57aa4e7062c5a3468f3a701holmer@google.com
11064ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (vpx_codec_dec_init(decoder_, vpx_codec_vp8_dx(), &cfg, flags)) {
11074ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_MEMORY;
11084ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1109470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11109115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Save VideoCodec instance for later; mainly for duplicating the decoder.
11119115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (&codec_ != inst)
1112d25b602dc0e70282e1f0223e5909534fa81053f0pbos@webrtc.org    codec_ = *inst;
11134ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  propagation_cnt_ = -1;
1114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11154ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  inited_ = true;
1116b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org
1117b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org  // Always start with a complete key frame.
1118b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org  key_frame_required_ = true;
11194ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11228d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8DecoderImpl::Decode(const EncodedImage& input_image,
1123cce46fc108a70336f0477fd58d41f38e547eeb25philipel                           bool missing_frames,
1124cce46fc108a70336f0477fd58d41f38e547eeb25philipel                           const RTPFragmentationHeader* fragmentation,
1125cce46fc108a70336f0477fd58d41f38e547eeb25philipel                           const CodecSpecificInfo* codec_specific_info,
1126cce46fc108a70336f0477fd58d41f38e547eeb25philipel                           int64_t /*render_time_ms*/) {
11274ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (!inited_) {
11284ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
11294ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
11304ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (decode_complete_callback_ == NULL) {
11314ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_UNINITIALIZED;
11324ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
11334ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (input_image._buffer == NULL && input_image._length > 0) {
11344ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Reset to avoid requesting key frames too often.
11354ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (propagation_cnt_ > 0)
11364ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_ = 0;
11374ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
11384ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
11394c059d87b3cd38495479d649ce716054815ecfc8stefan@webrtc.org
1140c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#ifdef INDEPENDENT_PARTITIONS
11414ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (fragmentation == NULL) {
11424ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;
11434ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1144c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#endif
1145a1ec48dec2ec49dfa0f3e84a6d4362fcb478bcf0marpan@google.com
1146e87d48719f8478148fc6ec28c3b3663709d585a4Stefan Holmer#if !defined(WEBRTC_ARCH_ARM) && !defined(WEBRTC_ARCH_ARM64)
11479115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  vp8_postproc_cfg_t ppcfg;
11489115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // MFQE enabled to reduce key frame popping.
11499115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  ppcfg.post_proc_flag = VP8_MFQE | VP8_DEBLOCK;
11509115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // For VGA resolutions and lower, enable the demacroblocker postproc.
11519115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (last_frame_width_ * last_frame_height_ <= 640 * 360) {
11529115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    ppcfg.post_proc_flag |= VP8_DEMACROBLOCK;
11531bb1da4c30ca92c7164fbfa4447f94eaacd60852stefan@webrtc.org  }
11549115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Strength of deblocking filter. Valid range:[0,16]
11559115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  ppcfg.deblocking_level = 3;
11569115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  vpx_codec_control(decoder_, VP8_SET_POSTPROC, &ppcfg);
11571bb1da4c30ca92c7164fbfa4447f94eaacd60852stefan@webrtc.org#endif
11581bb1da4c30ca92c7164fbfa4447f94eaacd60852stefan@webrtc.org
1159b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org  // Always start with a complete key frame.
1160b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org  if (key_frame_required_) {
116149e196af4060624d620297a6bc017699daa33550Peter Boström    if (input_image._frameType != kVideoFrameKey)
1162b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
1163b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org    // We have a key frame - is it complete?
1164b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org    if (input_image._completeFrame) {
1165b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org      key_frame_required_ = false;
1166b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org    } else {
1167b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
1168b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org    }
1169b2c28c3699f701e2e3e51ea1d361a2f66cf5f4e2mikhal@webrtc.org  }
11704ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Restrict error propagation using key frame requests. Disabled when
11714ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // the feedback mode is enabled (RPS).
11724ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Reset on a key frame refresh.
11734ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (!feedback_mode_) {
117449e196af4060624d620297a6bc017699daa33550Peter Boström    if (input_image._frameType == kVideoFrameKey &&
117549e196af4060624d620297a6bc017699daa33550Peter Boström        input_image._completeFrame) {
11764ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_ = -1;
1177cce46fc108a70336f0477fd58d41f38e547eeb25philipel      // Start count on first loss.
11789115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    } else if ((!input_image._completeFrame || missing_frames) &&
1179cce46fc108a70336f0477fd58d41f38e547eeb25philipel               propagation_cnt_ == -1) {
11804ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_ = 0;
11819115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
11829115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (propagation_cnt_ >= 0) {
11834ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_++;
11849115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
11854ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1186ffd28f95c5f7a7c23a14cecb82f02b4b85eda658stefan@webrtc.org
1187f5d934dfd8e25c8ac1fdecb1f2b829d175f436a9stefan@webrtc.org  vpx_codec_iter_t iter = NULL;
11884ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  vpx_image_t* img;
11894ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  int ret;
11904ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org
11914ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Check for missing frames.
11924ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (missing_frames) {
11934ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Call decoder with zero data length to signal missing frames.
11944ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (vpx_codec_decode(decoder_, NULL, 0, 0, VPX_DL_REALTIME)) {
11954ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // Reset to avoid requesting key frames too often.
11964ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      if (propagation_cnt_ > 0)
11974ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org        propagation_cnt_ = 0;
11984ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
1199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
12009115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    img = vpx_codec_get_frame(decoder_, &iter);
12014ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    iter = NULL;
12024ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1204c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#ifdef INDEPENDENT_PARTITIONS
12054ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (DecodePartitions(inputImage, fragmentation)) {
12064ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Reset to avoid requesting key frames too often.
12074ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (propagation_cnt_ > 0) {
12084ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_ = 0;
1209c3d891059e117357011e414263af0f519313d440stefan@webrtc.org    }
12104ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
12114ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1212c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#else
12134ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  uint8_t* buffer = input_image._buffer;
12144ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (input_image._length == 0) {
12158d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org    buffer = NULL;  // Triggers full frame concealment.
12164ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
12179115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  if (vpx_codec_decode(decoder_, buffer, input_image._length, 0,
12184ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org                       VPX_DL_REALTIME)) {
12194ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Reset to avoid requesting key frames too often.
12209115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    if (propagation_cnt_ > 0) {
12214ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_ = 0;
12229115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    }
12234ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
12244ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1225c3d891059e117357011e414263af0f519313d440stefan@webrtc.org#endif
1226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12274ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Store encoded frame if key frame. (Used in Copy method.)
122849e196af4060624d620297a6bc017699daa33550Peter Boström  if (input_image._frameType == kVideoFrameKey && input_image._buffer != NULL) {
12294ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    const uint32_t bytes_to_copy = input_image._length;
12304ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (last_keyframe_._size < bytes_to_copy) {
1231cce46fc108a70336f0477fd58d41f38e547eeb25philipel      delete[] last_keyframe_._buffer;
12324ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      last_keyframe_._buffer = NULL;
12334ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      last_keyframe_._size = 0;
12344ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    }
12358d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org    uint8_t* temp_buffer = last_keyframe_._buffer;  // Save buffer ptr.
1236cce46fc108a70336f0477fd58d41f38e547eeb25philipel    uint32_t temp_size = last_keyframe_._size;      // Save size.
1237cce46fc108a70336f0477fd58d41f38e547eeb25philipel    last_keyframe_ = input_image;                   // Shallow copy.
1238cce46fc108a70336f0477fd58d41f38e547eeb25philipel    last_keyframe_._buffer = temp_buffer;           // Restore buffer ptr.
1239cce46fc108a70336f0477fd58d41f38e547eeb25philipel    last_keyframe_._size = temp_size;               // Restore buffer size.
12404ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (!last_keyframe_._buffer) {
12414ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // Allocate memory.
12424ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      last_keyframe_._size = bytes_to_copy;
12434ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      last_keyframe_._buffer = new uint8_t[last_keyframe_._size];
12444ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    }
12454ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Copy encoded frame.
12464ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    memcpy(last_keyframe_._buffer, input_image._buffer, bytes_to_copy);
12474ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    last_keyframe_._length = bytes_to_copy;
12484ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
12504ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  img = vpx_codec_get_frame(decoder_, &iter);
12516c75c989648018a1537bb29d41fbcb730b143c15wu@webrtc.org  ret = ReturnFrame(img, input_image._timeStamp, input_image.ntp_time_ms_);
12524ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (ret != 0) {
12534ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Reset to avoid requesting key frames too often.
12544ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (ret < 0 && propagation_cnt_ > 0)
12554ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      propagation_cnt_ = 0;
12564ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return ret;
12574ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
12584ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (feedback_mode_) {
12594ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Whenever we receive an incomplete key frame all reference buffers will
12604ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // be corrupt. If that happens we must request new key frames until we
12619115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org    // decode a complete key frame.
126249e196af4060624d620297a6bc017699daa33550Peter Boström    if (input_image._frameType == kVideoFrameKey && !input_image._completeFrame)
12634ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
12644ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Check for reference updates and last reference buffer corruption and
12654ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // signal successful reference propagation or frame corruption to the
12664ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // encoder.
12674ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    int reference_updates = 0;
12684ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (vpx_codec_control(decoder_, VP8D_GET_LAST_REF_UPDATES,
12694ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org                          &reference_updates)) {
12704ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // Reset to avoid requesting key frames too often.
12719115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      if (propagation_cnt_ > 0) {
12724ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org        propagation_cnt_ = 0;
12739115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org      }
12744ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
12754ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    }
12764ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    int corrupted = 0;
12774ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (vpx_codec_control(decoder_, VP8D_GET_FRAME_CORRUPTED, &corrupted)) {
12784ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // Reset to avoid requesting key frames too often.
12794ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      if (propagation_cnt_ > 0)
12804ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org        propagation_cnt_ = 0;
12814ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
12824ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    }
12834ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    int16_t picture_id = -1;
12844ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (codec_specific_info) {
12854ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      picture_id = codec_specific_info->codecSpecific.VP8.pictureId;
12864ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    }
12874ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (picture_id > -1) {
12884ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      if (((reference_updates & VP8_GOLD_FRAME) ||
1289cce46fc108a70336f0477fd58d41f38e547eeb25philipel           (reference_updates & VP8_ALTR_FRAME)) &&
1290cce46fc108a70336f0477fd58d41f38e547eeb25philipel          !corrupted) {
12914ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org        decode_complete_callback_->ReceivedDecodedReferenceFrame(picture_id);
1292a4a88f90c44c6ee287baccae10c7f7ff556dcb20stefan@webrtc.org      }
12934ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      decode_complete_callback_->ReceivedDecodedFrame(picture_id);
1294470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
12954ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    if (corrupted) {
12964ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      // we can decode but with artifacts
12974ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_REQUEST_SLI;
1298ffd28f95c5f7a7c23a14cecb82f02b4b85eda658stefan@webrtc.org    }
12994ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
13004ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Check Vs. threshold
13014ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (propagation_cnt_ > kVp8ErrorPropagationTh) {
13024ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Reset to avoid requesting key frames too often.
13034ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    propagation_cnt_ = 0;
13044ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
13054ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
13064ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1307c3d891059e117357011e414263af0f519313d440stefan@webrtc.org}
1308c3d891059e117357011e414263af0f519313d440stefan@webrtc.org
13098d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8DecoderImpl::DecodePartitions(
13104ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    const EncodedImage& input_image,
13114ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    const RTPFragmentationHeader* fragmentation) {
1312c3d891059e117357011e414263af0f519313d440stefan@webrtc.org  for (int i = 0; i < fragmentation->fragmentationVectorSize; ++i) {
1313cce46fc108a70336f0477fd58d41f38e547eeb25philipel    const uint8_t* partition =
1314cce46fc108a70336f0477fd58d41f38e547eeb25philipel        input_image._buffer + fragmentation->fragmentationOffset[i];
1315cce46fc108a70336f0477fd58d41f38e547eeb25philipel    const uint32_t partition_length = fragmentation->fragmentationLength[i];
1316cce46fc108a70336f0477fd58d41f38e547eeb25philipel    if (vpx_codec_decode(decoder_, partition, partition_length, 0,
1317c3d891059e117357011e414263af0f519313d440stefan@webrtc.org                         VPX_DL_REALTIME)) {
13184c059d87b3cd38495479d649ce716054815ecfc8stefan@webrtc.org      return WEBRTC_VIDEO_CODEC_ERROR;
1319c3d891059e117357011e414263af0f519313d440stefan@webrtc.org    }
1320c3d891059e117357011e414263af0f519313d440stefan@webrtc.org  }
13214c059d87b3cd38495479d649ce716054815ecfc8stefan@webrtc.org  // Signal end of frame data. If there was no frame data this will trigger
13224c059d87b3cd38495479d649ce716054815ecfc8stefan@webrtc.org  // a full frame concealment.
13234ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (vpx_codec_decode(decoder_, NULL, 0, 0, VPX_DL_REALTIME))
1324c3d891059e117357011e414263af0f519313d440stefan@webrtc.org    return WEBRTC_VIDEO_CODEC_ERROR;
1325c3d891059e117357011e414263af0f519313d440stefan@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
132693d216c23faaa509b798dc8f2d2b58b30714cd1estefan@webrtc.org}
132793d216c23faaa509b798dc8f2d2b58b30714cd1estefan@webrtc.org
13286c75c989648018a1537bb29d41fbcb730b143c15wu@webrtc.orgint VP8DecoderImpl::ReturnFrame(const vpx_image_t* img,
1329cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                uint32_t timestamp,
1330cce46fc108a70336f0477fd58d41f38e547eeb25philipel                                int64_t ntp_time_ms) {
13314ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (img == NULL) {
13324ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    // Decoder OK and NULL image => No show frame
13334ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return WEBRTC_VIDEO_CODEC_NO_OUTPUT;
13344ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
13359115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  last_frame_width_ = img->d_w;
13369115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  last_frame_height_ = img->d_h;
13379115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.org  // Allocate memory for decoded image.
13384765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchez  VideoFrame decoded_image(buffer_pool_.CreateBuffer(img->d_w, img->d_h),
13394765070b8d6f024509c717c04d9b708750666927Miguel Casas-Sanchez                           timestamp, 0, kVideoRotation_0);
1340cce46fc108a70336f0477fd58d41f38e547eeb25philipel  libyuv::I420Copy(img->planes[VPX_PLANE_Y], img->stride[VPX_PLANE_Y],
1341cce46fc108a70336f0477fd58d41f38e547eeb25philipel                   img->planes[VPX_PLANE_U], img->stride[VPX_PLANE_U],
1342cce46fc108a70336f0477fd58d41f38e547eeb25philipel                   img->planes[VPX_PLANE_V], img->stride[VPX_PLANE_V],
1343cce46fc108a70336f0477fd58d41f38e547eeb25philipel                   decoded_image.buffer(kYPlane), decoded_image.stride(kYPlane),
1344cce46fc108a70336f0477fd58d41f38e547eeb25philipel                   decoded_image.buffer(kUPlane), decoded_image.stride(kUPlane),
1345cce46fc108a70336f0477fd58d41f38e547eeb25philipel                   decoded_image.buffer(kVPlane), decoded_image.stride(kVPlane),
1346cce46fc108a70336f0477fd58d41f38e547eeb25philipel                   img->d_w, img->d_h);
134773d763e71f5c77cac82aa65d737e64d893f190a0magjed@webrtc.org  decoded_image.set_ntp_time_ms(ntp_time_ms);
134873d763e71f5c77cac82aa65d737e64d893f190a0magjed@webrtc.org  int ret = decode_complete_callback_->Decoded(decoded_image);
13494ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (ret != 0)
13504ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return ret;
13514ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org
13524ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // Remember image format for later
13534ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  image_format_ = img->fmt;
13544ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13578d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8DecoderImpl::RegisterDecodeCompleteCallback(
13584ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    DecodedImageCallback* callback) {
13594ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  decode_complete_callback_ = callback;
13604ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
13638d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.orgint VP8DecoderImpl::Release() {
13644ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (last_keyframe_._buffer != NULL) {
1365cce46fc108a70336f0477fd58d41f38e547eeb25philipel    delete[] last_keyframe_._buffer;
13664ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    last_keyframe_._buffer = NULL;
13674ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
13684ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (decoder_ != NULL) {
13698d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org    if (vpx_codec_destroy(decoder_)) {
13704ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org      return WEBRTC_VIDEO_CODEC_MEMORY;
1371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
13724ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    delete decoder_;
13734ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    decoder_ = NULL;
13744ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
13754ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  if (ref_frame_ != NULL) {
13764ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    vpx_img_free(&ref_frame_->img);
13774ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    delete ref_frame_;
13784ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    ref_frame_ = NULL;
13794ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1380a3209a2b27b7bf2059f8119a126a1b1be9f0377fpbos@webrtc.org  buffer_pool_.Release();
13814ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  inited_ = false;
13824ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return WEBRTC_VIDEO_CODEC_OK;
1383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1384470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
1385b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boströmconst char* VP8DecoderImpl::ImplementationName() const {
1386b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström  return "libvpx";
1387b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström}
1388b7d9a97ce41022e984348efb5f28bf6dd6c6b779Peter Boström
13899115cde6c9c8f5d749b349d7d10a570e4cb32803pbos@webrtc.orgint VP8DecoderImpl::CopyReference(VP8DecoderImpl* copy) {
13904ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // The type of frame to copy should be set in ref_frame_->frame_type
13914ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  // before the call to this function.
1392cce46fc108a70336f0477fd58d41f38e547eeb25philipel  if (vpx_codec_control(decoder_, VP8_COPY_REFERENCE, ref_frame_) !=
1393cce46fc108a70336f0477fd58d41f38e547eeb25philipel      VPX_CODEC_OK) {
13944ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return -1;
13954ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
1396cce46fc108a70336f0477fd58d41f38e547eeb25philipel  if (vpx_codec_control(copy->decoder_, VP8_SET_REFERENCE, ref_frame_) !=
1397cce46fc108a70336f0477fd58d41f38e547eeb25philipel      VPX_CODEC_OK) {
13984ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org    return -1;
13994ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  }
14004ea57e5e26eb91812826903753e7260654bd42d9pwestin@webrtc.org  return 0;
1401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
1402470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
14038d89b58d65f1b59f5ea758142ae28de323276229pwestin@webrtc.org}  // namespace webrtc
1404