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

Unified Diff: webrtc/modules/video_coding/generic_encoder_unittest.cc

Issue 2911193002: Implement timing frames. (Closed)
Patch Set: Implement Holmer@ 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 side-by-side diff with in-line comments
Download patch
Index: webrtc/modules/video_coding/generic_encoder_unittest.cc
diff --git a/webrtc/modules/video_coding/generic_encoder_unittest.cc b/webrtc/modules/video_coding/generic_encoder_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3de5c333fb52d3aef40c17eb2cb7c4d0c3606d5b
--- /dev/null
+++ b/webrtc/modules/video_coding/generic_encoder_unittest.cc
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2017 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 <vector>
+
+#include "webrtc/modules/video_coding/encoded_frame.h"
+#include "webrtc/modules/video_coding/generic_encoder.h"
+#include "webrtc/modules/video_coding/include/video_coding_defines.h"
+#include "webrtc/test/gtest.h"
+
+namespace webrtc {
+namespace test {
+namespace {
+inline size_t FrameSize(const size_t& min_frame_size,
+ const size_t& max_frame_size,
+ const int& s,
+ const int& i) {
+ return min_frame_size + (s + 1) * i % (max_frame_size - min_frame_size);
+}
+
+class FakeEncodedImageCallback : public EncodedImageCallback {
+ public:
+ FakeEncodedImageCallback() : last_frame_was_timing_(false) {}
+ Result OnEncodedImage(const EncodedImage& encoded_image,
+ const CodecSpecificInfo* codec_specific_info,
+ const RTPFragmentationHeader* fragmentation) override {
+ last_frame_was_timing_ = encoded_image.timing_.is_timing_frame;
+ return Result::OK;
+ };
+
+ bool WasTimingFrame() { return last_frame_was_timing_; }
+
+ private:
+ bool last_frame_was_timing_;
+};
+
+enum class FrameType {
+ kNormal,
+ kTiming,
+ kDropped,
+};
+
+// Emulates |num_frames| on |num_streams| frames with capture timestamps
+// increased by 1 from 0. Size of each frame is between
+// |min_frame_size| and |max_frame_size|, outliers are counted relatevely to
+// |average_frame_sizes[]| for each stream.
+std::vector<std::vector<FrameType>> GetTimingFrames(
+ const int64_t delay_ms,
+ const size_t min_frame_size,
+ const size_t max_frame_size,
+ std::vector<size_t> average_frame_sizes,
+ const int num_streams,
+ const int num_frames) {
+ FakeEncodedImageCallback sink;
+ VCMEncodedFrameCallback callback(&sink, nullptr);
+ const size_t kFramerate = 30;
+ callback.SetTimingFramesThresholds(
+ {delay_ms, kDefaultOutlierFrameSizePercent});
+ callback.OnFrameRateChanged(kFramerate);
+ int s, i;
+ std::vector<std::vector<FrameType>> result(num_streams);
+ for (s = 0; s < num_streams; ++s)
+ callback.OnTargetBitrateChanged(average_frame_sizes[s] * kFramerate, s);
+ int64_t current_timestamp = 0;
+ for (i = 0; i < num_frames; ++i) {
+ current_timestamp += 1;
+ for (s = 0; s < num_streams; ++s) {
+ // every (5+s)-th frame is dropped on s-th stream by design.
+ bool dropped = i % (5 + s) == 0;
+
+ EncodedImage image;
+ CodecSpecificInfo codec_specific;
+ image._length = FrameSize(min_frame_size, max_frame_size, s, i);
+ image.capture_time_ms_ = current_timestamp;
+ codec_specific.codecType = kVideoCodecGeneric;
+ codec_specific.codecSpecific.generic.simulcast_idx = s;
+ callback.OnEncodeStarted(current_timestamp, s);
+ if (dropped) {
+ result[s].push_back(FrameType::kDropped);
+ continue;
+ }
+ callback.OnEncodedImage(image, &codec_specific, nullptr);
+ if (sink.WasTimingFrame()) {
+ result[s].push_back(FrameType::kTiming);
+ } else {
+ result[s].push_back(FrameType::kNormal);
+ }
+ }
+ }
+ return result;
+}
+} // namespace
+
+TEST(TestVCMEncodedFrameCallback, MarksTimingFramesPeriodicallyTogether) {
+ const int64_t kDelayMs = 29;
+ const size_t kMinFrameSize = 10;
+ const size_t kMaxFrameSize = 20;
+ const int kNumFrames = 1000;
+ const int kNumStreams = 3;
+ // No outliers as 1000 is larger than anything from range [10,20].
+ const std::vector<size_t> kAverageSize = {1000, 1000, 1000};
+ auto frames = GetTimingFrames(kDelayMs, kMinFrameSize, kMaxFrameSize,
+ kAverageSize, kNumStreams, kNumFrames);
+ // Timing frames should be tirggered every delayMs.
+ // As no outliers are expected, frames on all streams have to be
+ // marked together.
+ int last_timing_frame = -1;
+ for (int i = 0; i < kNumFrames; ++i) {
+ int num_normal = 0;
+ int num_timing = 0;
+ int num_dropped = 0;
+ for (int s = 0; s < kNumStreams; ++s) {
+ if (frames[s][i] == FrameType::kTiming) {
+ ++num_timing;
+ } else if (frames[s][i] == FrameType::kNormal) {
+ ++num_normal;
+ } else {
+ ++num_dropped;
+ }
+ }
+ // Can't have both normal and timing frames at the same timstamp.
+ EXPECT_TRUE(num_timing == 0 || num_normal == 0);
+ if (num_dropped < kNumStreams) {
+ if (last_timing_frame == -1 || i >= last_timing_frame + kDelayMs) {
+ // If didn't have timing frames for a period, current sent frame has to
+ // be one. No normal frames should be sent.
+ EXPECT_EQ(num_normal, 0);
+ } else {
+ // No unneeded timing frames should be sent.
+ EXPECT_EQ(num_timing, 0);
+ }
+ }
+ if (num_timing > 0)
+ last_timing_frame = i;
+ }
+}
+
+TEST(TestVCMEncodedFrameCallback, MarksOutliers) {
+ const int64_t kDelayMs = 29;
+ const size_t kMinFrameSize = 2495;
+ const size_t kMaxFrameSize = 2505;
+ const int kNumFrames = 1000;
+ const int kNumStreams = 3;
+ // Possible outliers as 1000 lies in range [995, 1005].
+ const std::vector<size_t> kAverageSize = {998, 1000, 1004};
+ auto frames = GetTimingFrames(kDelayMs, kMinFrameSize, kMaxFrameSize,
+ kAverageSize, kNumStreams, kNumFrames);
+ // All outliers should be marked.
+ for (int i = 0; i < kNumFrames; ++i) {
+ for (int s = 0; s < kNumStreams; ++s) {
+ if (FrameSize(kMinFrameSize, kMaxFrameSize, s, i) >=
+ kAverageSize[s] * kDefaultOutlierFrameSizePercent / 100) {
+ // Too big frame. May be dropped or timing, but not normal.
+ EXPECT_NE(frames[s][i], FrameType::kNormal);
+ }
+ }
+ }
+}
+
+} // namespace test
+} // namespace webrtc
« no previous file with comments | « webrtc/modules/video_coding/generic_encoder.cc ('k') | webrtc/modules/video_coding/include/video_coding_defines.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698