Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Side by Side Diff: webrtc/modules/video_coding/generic_encoder_unittest.cc

Issue 2911193002: Implement timing frames. (Closed)
Patch Set: Implement Asapersson@ comments Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include <vector>
12
13 #include "webrtc/modules/video_coding/encoded_frame.h"
14 #include "webrtc/modules/video_coding/generic_encoder.h"
15 #include "webrtc/modules/video_coding/include/video_coding_defines.h"
16 #include "webrtc/test/gtest.h"
17
18 namespace webrtc {
19 namespace generic_encoder_tests {
sprang_webrtc 2017/06/13 14:14:14 Usually only call the namespace test, but up to yo
ilnik 2017/06/13 14:55:44 Done.
nisse-webrtc 2017/06/14 09:24:43 Since this is in a cc file, why not simply use the
ilnik 2017/06/14 11:10:37 The FrameType enum, even if in anonymous namespace
nisse-webrtc 2017/06/14 11:16:04 I see. Keeping the namespace for now seems ok, but
20
21 inline size_t FrameSize(const size_t& min_frame_size,
22 const size_t& max_frame_size,
23 const int& s,
24 const int& i) {
25 return min_frame_size + (s + 1) * i % (max_frame_size - min_frame_size);
26 }
27
28 class FakeEncodedImageCallback : public EncodedImageCallback {
29 public:
30 FakeEncodedImageCallback() : last_frame_was_timing_(false) {}
31 Result OnEncodedImage(const EncodedImage& encoded_image,
32 const CodecSpecificInfo* codec_specific_info,
33 const RTPFragmentationHeader* fragmentation) override {
34 last_frame_was_timing_ = encoded_image.timing_.is_timing_frame;
35 return Result::OK;
36 };
37
38 bool WasTimingFrame() { return last_frame_was_timing_; }
39
40 private:
41 bool last_frame_was_timing_;
42 };
sprang_webrtc 2017/06/13 14:14:14 You can probably replace this with a gmock instead
ilnik 2017/06/13 14:55:44 I think it will be too hard, because it will requi
43
44 enum class FrameType {
45 Normal,
46 Timing,
47 Dropped,
sprang_webrtc 2017/06/13 14:14:14 nit: kCamelCase or ALL_CAPS
ilnik 2017/06/13 14:55:44 Done.
48 };
49
50 // Emulates |num_frames| on |num_streams| frames with capture timestamps
51 // increased by 1 from 0. Size of each frame is between
52 // |min_frame_size| and |max_frame_size|, outliers are counted relatevely to
53 // |average_frame_sizes[]| for each stream.
54 std::vector<std::vector<FrameType>> GetTimingFrames(
55 const int64_t delay_ms,
56 const size_t min_frame_size,
57 const size_t max_frame_size,
58 std::vector<size_t> average_frame_sizes,
59 const int num_streams,
60 const int num_frames) {
61 FakeEncodedImageCallback sink;
62 VCMEncodedFrameCallback callback(&sink, nullptr);
sprang_webrtc 2017/06/13 14:14:14 Maybe it would be a good idea to have a TestVCMEnc
ilnik 2017/06/13 14:55:44 Done.
63 const size_t kFramerate = 30;
64 callback.SetTimingFramesThresholds(
65 {delay_ms, kDefaultOutlierFrameSizePercent});
66 callback.OnFrameRateChanged(kFramerate);
67 int s, i;
68 std::vector<std::vector<FrameType>> result(num_streams);
69 for (s = 0; s < num_streams; ++s)
70 callback.OnTargetBitrateChanged(average_frame_sizes[s] * kFramerate, s);
71 int64_t current_timestamp = 0;
72 for (i = 0; i < num_frames; ++i) {
73 current_timestamp += 1;
74 for (s = 0; s < num_streams; ++s) {
75 // every (5+s)-th frame is dropped on s-th stream by design.
76 bool dropped = i % (5 + s) == 0;
77
78 EncodedImage image;
79 CodecSpecificInfo codec_specific;
80 image._length = FrameSize(min_frame_size, max_frame_size, s, i);
81 image.capture_time_ms_ = current_timestamp;
82 codec_specific.codecType = kVideoCodecGeneric;
83 codec_specific.codecSpecific.generic.simulcast_idx = s;
84 callback.OnEncodeStarted(current_timestamp, s);
85 if (dropped) {
86 result[s].push_back(FrameType::Dropped);
87 continue;
88 }
89 callback.OnEncodedImage(image, &codec_specific, nullptr);
90 if (sink.WasTimingFrame()) {
91 result[s].push_back(FrameType::Timing);
92 } else {
93 result[s].push_back(FrameType::Normal);
94 }
95 }
96 }
97 return result;
98 }
99
100 TEST(TestVCMEncodedFrameCallback, MarksTimingFramesPeriodicallyTogether) {
101 const int64_t kDelayMs = 29;
102 const size_t kMinFrameSize = 10;
103 const size_t kMaxFrameSize = 20;
104 const int kNumFrames = 1000;
105 const int kNumStreams = 3;
106 // No outliers as 1000 is larger than anything from range [10,20].
107 const std::vector<size_t> kAverageSize = {1000, 1000, 1000};
108 auto frames = GetTimingFrames(kDelayMs, kMinFrameSize, kMaxFrameSize,
109 kAverageSize, kNumStreams, kNumFrames);
110 // Timing frames should be tirggered every delayMs.
111 // As no outliers are expected, frames on all streams have to be
112 // marked together.
113 int last_timing_frame = -1;
114 int i, s;
sprang_webrtc 2017/06/13 14:14:14 Why not just declare in the for statements?
ilnik 2017/06/13 14:55:44 Done.
115 for (i = 0; i < kNumFrames; ++i) {
116 int num_normal = 0;
117 int num_timing = 0;
118 int num_dropped = 0;
119 for (s = 0; s < kNumStreams; ++s) {
120 if (frames[s][i] == FrameType::Timing)
121 ++num_timing;
122 else if (frames[s][i] == FrameType::Normal)
123 ++num_normal;
124 else
125 ++num_dropped;
sprang_webrtc 2017/06/13 14:14:14 nit: Use brackets for if/else
ilnik 2017/06/13 14:55:44 Done.
126 }
127 // Can't have both normal and timing frames at the same timstamp.
128 EXPECT_TRUE(num_timing == 0 || num_normal == 0);
129 if (num_dropped < kNumStreams) {
130 if (last_timing_frame == -1 || i >= last_timing_frame + kDelayMs) {
131 // If didn't have timing frames for a period, current sent frame has to
132 // be one. No normal frames should be sent.
133 EXPECT_EQ(num_normal, 0);
134 } else {
135 // No unneeded timing frames should be sent.
136 EXPECT_EQ(num_timing, 0);
137 }
138 }
139 if (num_timing > 0)
140 last_timing_frame = i;
141 }
142 }
143
144 TEST(TestVCMEncodedFrameCallback, MarksOutliers) {
145 const int64_t kDelayMs = 29;
146 const size_t kMinFrameSize = 2495;
147 const size_t kMaxFrameSize = 2505;
148 const int kNumFrames = 1000;
149 const int kNumStreams = 3;
150 // Possible outliers as 1000 lies in range [995, 1005].
151 const std::vector<size_t> kAverageSize = {998, 1000, 1004};
152 auto frames = GetTimingFrames(kDelayMs, kMinFrameSize, kMaxFrameSize,
153 kAverageSize, kNumStreams, kNumFrames);
154 // All outliers should be marked.
155 int i, s;
156 for (i = 0; i < kNumFrames; ++i) {
157 for (s = 0; s < kNumStreams; ++s) {
158 if (FrameSize(kMinFrameSize, kMaxFrameSize, s, i) >=
159 kAverageSize[s] * kDefaultOutlierFrameSizePercent / 100) {
160 // Too big frame. May be dropped or timing, but not normal.
161 EXPECT_NE(frames[s][i], FrameType::Normal);
162 }
163 }
164 }
165 }
166
167 } // namespace generic_encoder_tests
168 } // namespace webrtc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698