summaryrefslogtreecommitdiff
path: root/test/fake_encoder.cc
blob: fc8712e56db6b5151dfa481c1a3dc341dd984560 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*
 *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/test/fake_encoder.h"

#include "testing/gtest/include/gtest/gtest.h"

namespace webrtc {
namespace test {

FakeEncoder::FakeEncoder(Clock* clock)
    : clock_(clock),
      callback_(NULL),
      target_bitrate_kbps_(0),
      max_target_bitrate_kbps_(-1),
      last_encode_time_ms_(0) {
  // Generate some arbitrary not-all-zero data
  for (size_t i = 0; i < sizeof(encoded_buffer_); ++i) {
    encoded_buffer_[i] = static_cast<uint8_t>(i);
  }
}

FakeEncoder::~FakeEncoder() {}

void FakeEncoder::SetCodecSettings(VideoCodec* codec,
                                   size_t num_streams) {
  assert(num_streams > 0);
  assert(num_streams <= kMaxSimulcastStreams);

  static const SimulcastStream stream_settings[] = {
      {320, 180, 0, 150, 150, 50, codec->qpMax},
      {640, 360, 0, 500, 500, 150, codec->qpMax},
      {1280, 720, 0, 1200, 1200, 600, codec->qpMax}};
  // Add more streams to the settings above with reasonable values if required.
  assert(num_streams <= sizeof(stream_settings) / sizeof(stream_settings[0]));

  codec->numberOfSimulcastStreams = static_cast<unsigned char>(num_streams);

  unsigned int sum_of_max_bitrates = 0;
  for (size_t i = 0; i < num_streams; ++i) {
    codec->simulcastStream[i] = stream_settings[i];
    sum_of_max_bitrates += stream_settings[i].maxBitrate;
  }

  size_t last_stream = num_streams - 1;
  codec->width = stream_settings[last_stream].width;
  codec->height = stream_settings[last_stream].height;
  // Start with the average for the middle stream's max/min settings.
  codec->startBitrate = (stream_settings[last_stream / 2].maxBitrate +
                         stream_settings[last_stream / 2].minBitrate) /
                        2;
  codec->minBitrate = stream_settings[0].minBitrate;
  codec->maxBitrate = sum_of_max_bitrates;

  codec->codecType = kVideoCodecGeneric;
  strcpy(codec->plName, "FAKE");
}

void FakeEncoder::SetMaxBitrate(int max_kbps) {
  assert(max_kbps >= -1);  // max_kbps == -1 disables it.
  max_target_bitrate_kbps_ = max_kbps;
}

int32_t FakeEncoder::InitEncode(const VideoCodec* config,
                                int32_t number_of_cores,
                                uint32_t max_payload_size) {
  config_ = *config;
  target_bitrate_kbps_ = config_.startBitrate;
  return 0;
}

int32_t FakeEncoder::Encode(
    const I420VideoFrame& input_image,
    const CodecSpecificInfo* codec_specific_info,
    const std::vector<VideoFrameType>* frame_types) {
  assert(config_.maxFramerate > 0);
  int time_since_last_encode_ms = 1000 / config_.maxFramerate;
  int64_t time_now_ms = clock_->TimeInMilliseconds();
  if (last_encode_time_ms_ > 0) {
    // For all frames but the first we can estimate the display time by looking
    // at the display time of the previous frame.
    time_since_last_encode_ms = time_now_ms - last_encode_time_ms_;
  }

  int bits_available = target_bitrate_kbps_ * time_since_last_encode_ms;
  int min_bits =
      config_.simulcastStream[0].minBitrate * time_since_last_encode_ms;
  if (bits_available < min_bits)
    bits_available = min_bits;
  int max_bits = max_target_bitrate_kbps_ * time_since_last_encode_ms;
  if (max_bits > 0 && max_bits < bits_available)
    bits_available = max_bits;
  last_encode_time_ms_ = time_now_ms;

  for (int i = 0; i < config_.numberOfSimulcastStreams; ++i) {
    CodecSpecificInfo specifics;
    memset(&specifics, 0, sizeof(specifics));
    specifics.codecType = kVideoCodecGeneric;
    specifics.codecSpecific.generic.simulcast_idx = i;
    int min_stream_bits =
        config_.simulcastStream[i].minBitrate * time_since_last_encode_ms;
    int max_stream_bits =
        config_.simulcastStream[i].maxBitrate * time_since_last_encode_ms;
    int stream_bits = (bits_available > max_stream_bits) ? max_stream_bits :
        bits_available;
    int stream_bytes = (stream_bits + 7) / 8;
    if (static_cast<size_t>(stream_bytes) > sizeof(encoded_buffer_))
      stream_bytes = sizeof(encoded_buffer_);

    EncodedImage encoded(
        encoded_buffer_, stream_bytes, sizeof(encoded_buffer_));
    encoded._timeStamp = input_image.timestamp();
    encoded.capture_time_ms_ = input_image.render_time_ms();
    encoded._frameType = (*frame_types)[i];
    // Always encode something on the first frame.
    if (min_stream_bits > bits_available && i > 0) {
      encoded._length = 0;
      encoded._frameType = kSkipFrame;
    }
    if (callback_->Encoded(encoded, &specifics, NULL) != 0)
      return -1;

    bits_available -= encoded._length * 8;
  }
  return 0;
}

int32_t FakeEncoder::RegisterEncodeCompleteCallback(
    EncodedImageCallback* callback) {
  callback_ = callback;
  return 0;
}

int32_t FakeEncoder::Release() { return 0; }

int32_t FakeEncoder::SetChannelParameters(uint32_t packet_loss, int rtt) {
  return 0;
}

int32_t FakeEncoder::SetRates(uint32_t new_target_bitrate, uint32_t framerate) {
  target_bitrate_kbps_ = new_target_bitrate;
  return 0;
}

}  // namespace test
}  // namespace webrtc