1 /*
2  *  Copyright (c) 2019 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 "video/frame_encode_metadata_writer.h"
12 
13 #include <cstddef>
14 #include <vector>
15 
16 #include "api/video/i420_buffer.h"
17 #include "api/video/video_frame.h"
18 #include "api/video/video_timing.h"
19 #include "common_video/h264/h264_common.h"
20 #include "common_video/test/utilities.h"
21 #include "modules/video_coding/include/video_coding_defines.h"
22 #include "rtc_base/time_utils.h"
23 #include "test/gmock.h"
24 #include "test/gtest.h"
25 
26 namespace webrtc {
27 namespace test {
28 namespace {
29 
30 const rtc::scoped_refptr<I420Buffer> kFrameBuffer = I420Buffer::Create(4, 4);
31 
FrameSize(const size_t & min_frame_size,const size_t & max_frame_size,const int & s,const int & i)32 inline size_t FrameSize(const size_t& min_frame_size,
33                         const size_t& max_frame_size,
34                         const int& s,
35                         const int& i) {
36   return min_frame_size + (s + 1) * i % (max_frame_size - min_frame_size);
37 }
38 
39 class FakeEncodedImageCallback : public EncodedImageCallback {
40  public:
FakeEncodedImageCallback()41   FakeEncodedImageCallback() : num_frames_dropped_(0) {}
OnEncodedImage(const EncodedImage & encoded_image,const CodecSpecificInfo * codec_specific_info)42   Result OnEncodedImage(const EncodedImage& encoded_image,
43                         const CodecSpecificInfo* codec_specific_info) override {
44     return Result(Result::OK);
45   }
OnDroppedFrame(DropReason reason)46   void OnDroppedFrame(DropReason reason) override { ++num_frames_dropped_; }
GetNumFramesDropped()47   size_t GetNumFramesDropped() { return num_frames_dropped_; }
48 
49  private:
50   size_t num_frames_dropped_;
51 };
52 
53 enum class FrameType {
54   kNormal,
55   kTiming,
56   kDropped,
57 };
58 
IsTimingFrame(const EncodedImage & image)59 bool IsTimingFrame(const EncodedImage& image) {
60   return image.timing_.flags != VideoSendTiming::kInvalid &&
61          image.timing_.flags != VideoSendTiming::kNotTriggered;
62 }
63 
64 // Emulates |num_frames| on |num_streams| frames with capture timestamps
65 // increased by 1 from 0. Size of each frame is between
66 // |min_frame_size| and |max_frame_size|, outliers are counted relatevely to
67 // |average_frame_sizes[]| for each stream.
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)68 std::vector<std::vector<FrameType>> GetTimingFrames(
69     const int64_t delay_ms,
70     const size_t min_frame_size,
71     const size_t max_frame_size,
72     std::vector<size_t> average_frame_sizes,
73     const int num_streams,
74     const int num_frames) {
75   FakeEncodedImageCallback sink;
76   FrameEncodeMetadataWriter encode_timer(&sink);
77   VideoCodec codec_settings;
78   codec_settings.numberOfSimulcastStreams = num_streams;
79   codec_settings.timing_frame_thresholds = {delay_ms,
80                                             kDefaultOutlierFrameSizePercent};
81   encode_timer.OnEncoderInit(codec_settings, false);
82   const size_t kFramerate = 30;
83   VideoBitrateAllocation bitrate_allocation;
84   for (int si = 0; si < num_streams; ++si) {
85     bitrate_allocation.SetBitrate(si, 0,
86                                   average_frame_sizes[si] * 8 * kFramerate);
87   }
88   encode_timer.OnSetRates(bitrate_allocation, kFramerate);
89 
90   std::vector<std::vector<FrameType>> result(num_streams);
91   int64_t current_timestamp = 0;
92   for (int i = 0; i < num_frames; ++i) {
93     current_timestamp += 1;
94     VideoFrame frame = VideoFrame::Builder()
95                            .set_timestamp_rtp(current_timestamp * 90)
96                            .set_timestamp_ms(current_timestamp)
97                            .set_video_frame_buffer(kFrameBuffer)
98                            .build();
99     encode_timer.OnEncodeStarted(frame);
100     for (int si = 0; si < num_streams; ++si) {
101       // every (5+s)-th frame is dropped on s-th stream by design.
102       bool dropped = i % (5 + si) == 0;
103 
104       EncodedImage image;
105       image.SetEncodedData(EncodedImageBuffer::Create(max_frame_size));
106       image.set_size(FrameSize(min_frame_size, max_frame_size, si, i));
107       image.capture_time_ms_ = current_timestamp;
108       image.SetTimestamp(static_cast<uint32_t>(current_timestamp * 90));
109       image.SetSpatialIndex(si);
110 
111       if (dropped) {
112         result[si].push_back(FrameType::kDropped);
113         continue;
114       }
115 
116       encode_timer.FillTimingInfo(si, &image);
117 
118       if (IsTimingFrame(image)) {
119         result[si].push_back(FrameType::kTiming);
120       } else {
121         result[si].push_back(FrameType::kNormal);
122       }
123     }
124   }
125   return result;
126 }
127 }  // namespace
128 
TEST(FrameEncodeMetadataWriterTest,MarksTimingFramesPeriodicallyTogether)129 TEST(FrameEncodeMetadataWriterTest, MarksTimingFramesPeriodicallyTogether) {
130   const int64_t kDelayMs = 29;
131   const size_t kMinFrameSize = 10;
132   const size_t kMaxFrameSize = 20;
133   const int kNumFrames = 1000;
134   const int kNumStreams = 3;
135   // No outliers as 1000 is larger than anything from range [10,20].
136   const std::vector<size_t> kAverageSize = {1000, 1000, 1000};
137   auto frames = GetTimingFrames(kDelayMs, kMinFrameSize, kMaxFrameSize,
138                                 kAverageSize, kNumStreams, kNumFrames);
139   // Timing frames should be tirggered every delayMs.
140   // As no outliers are expected, frames on all streams have to be
141   // marked together.
142   int last_timing_frame = -1;
143   for (int i = 0; i < kNumFrames; ++i) {
144     int num_normal = 0;
145     int num_timing = 0;
146     int num_dropped = 0;
147     for (int s = 0; s < kNumStreams; ++s) {
148       if (frames[s][i] == FrameType::kTiming) {
149         ++num_timing;
150       } else if (frames[s][i] == FrameType::kNormal) {
151         ++num_normal;
152       } else {
153         ++num_dropped;
154       }
155     }
156     // Can't have both normal and timing frames at the same timstamp.
157     EXPECT_TRUE(num_timing == 0 || num_normal == 0);
158     if (num_dropped < kNumStreams) {
159       if (last_timing_frame == -1 || i >= last_timing_frame + kDelayMs) {
160         // If didn't have timing frames for a period, current sent frame has to
161         // be one. No normal frames should be sent.
162         EXPECT_EQ(num_normal, 0);
163       } else {
164         // No unneeded timing frames should be sent.
165         EXPECT_EQ(num_timing, 0);
166       }
167     }
168     if (num_timing > 0)
169       last_timing_frame = i;
170   }
171 }
172 
TEST(FrameEncodeMetadataWriterTest,MarksOutliers)173 TEST(FrameEncodeMetadataWriterTest, MarksOutliers) {
174   const int64_t kDelayMs = 29;
175   const size_t kMinFrameSize = 2495;
176   const size_t kMaxFrameSize = 2505;
177   const int kNumFrames = 1000;
178   const int kNumStreams = 3;
179   // Possible outliers as 1000 lies in range [995, 1005].
180   const std::vector<size_t> kAverageSize = {998, 1000, 1004};
181   auto frames = GetTimingFrames(kDelayMs, kMinFrameSize, kMaxFrameSize,
182                                 kAverageSize, kNumStreams, kNumFrames);
183   // All outliers should be marked.
184   for (int i = 0; i < kNumFrames; ++i) {
185     for (int s = 0; s < kNumStreams; ++s) {
186       if (FrameSize(kMinFrameSize, kMaxFrameSize, s, i) >=
187           kAverageSize[s] * kDefaultOutlierFrameSizePercent / 100) {
188         // Too big frame. May be dropped or timing, but not normal.
189         EXPECT_NE(frames[s][i], FrameType::kNormal);
190       }
191     }
192   }
193 }
194 
TEST(FrameEncodeMetadataWriterTest,NoTimingFrameIfNoEncodeStartTime)195 TEST(FrameEncodeMetadataWriterTest, NoTimingFrameIfNoEncodeStartTime) {
196   int64_t timestamp = 1;
197   constexpr size_t kFrameSize = 500;
198   EncodedImage image;
199   image.SetEncodedData(EncodedImageBuffer::Create(kFrameSize));
200   image.capture_time_ms_ = timestamp;
201   image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
202 
203   FakeEncodedImageCallback sink;
204   FrameEncodeMetadataWriter encode_timer(&sink);
205   VideoCodec codec_settings;
206   // Make all frames timing frames.
207   codec_settings.timing_frame_thresholds.delay_ms = 1;
208   encode_timer.OnEncoderInit(codec_settings, false);
209   VideoBitrateAllocation bitrate_allocation;
210   bitrate_allocation.SetBitrate(0, 0, 500000);
211   encode_timer.OnSetRates(bitrate_allocation, 30);
212 
213   // Verify a single frame works with encode start time set.
214   VideoFrame frame = VideoFrame::Builder()
215                          .set_timestamp_ms(timestamp)
216                          .set_timestamp_rtp(timestamp * 90)
217                          .set_video_frame_buffer(kFrameBuffer)
218                          .build();
219   encode_timer.OnEncodeStarted(frame);
220   encode_timer.FillTimingInfo(0, &image);
221   EXPECT_TRUE(IsTimingFrame(image));
222 
223   // New frame, now skip OnEncodeStarted. Should not result in timing frame.
224   image.capture_time_ms_ = ++timestamp;
225   image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
226   image.timing_ = EncodedImage::Timing();
227   encode_timer.FillTimingInfo(0, &image);
228   EXPECT_FALSE(IsTimingFrame(image));
229 }
230 
TEST(FrameEncodeMetadataWriterTest,AdjustsCaptureTimeForInternalSourceEncoder)231 TEST(FrameEncodeMetadataWriterTest,
232      AdjustsCaptureTimeForInternalSourceEncoder) {
233   const int64_t kEncodeStartDelayMs = 2;
234   const int64_t kEncodeFinishDelayMs = 10;
235   constexpr size_t kFrameSize = 500;
236 
237   int64_t timestamp = 1;
238   EncodedImage image;
239   image.SetEncodedData(EncodedImageBuffer::Create(kFrameSize));
240   image.capture_time_ms_ = timestamp;
241   image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
242 
243   FakeEncodedImageCallback sink;
244   FrameEncodeMetadataWriter encode_timer(&sink);
245 
246   VideoCodec codec_settings;
247   // Make all frames timing frames.
248   codec_settings.timing_frame_thresholds.delay_ms = 1;
249   encode_timer.OnEncoderInit(codec_settings, true);
250 
251   VideoBitrateAllocation bitrate_allocation;
252   bitrate_allocation.SetBitrate(0, 0, 500000);
253   encode_timer.OnSetRates(bitrate_allocation, 30);
254 
255   // Verify a single frame without encode timestamps isn't a timing frame.
256   encode_timer.FillTimingInfo(0, &image);
257   EXPECT_FALSE(IsTimingFrame(image));
258 
259   // New frame, but this time with encode timestamps set in timing_.
260   // This should be a timing frame.
261   image.capture_time_ms_ = ++timestamp;
262   image.SetTimestamp(static_cast<uint32_t>(timestamp * 90));
263   image.timing_ = EncodedImage::Timing();
264   image.timing_.encode_start_ms = timestamp + kEncodeStartDelayMs;
265   image.timing_.encode_finish_ms = timestamp + kEncodeFinishDelayMs;
266 
267   encode_timer.FillTimingInfo(0, &image);
268   EXPECT_TRUE(IsTimingFrame(image));
269 
270   // Frame is captured kEncodeFinishDelayMs before it's encoded, so restored
271   // capture timestamp should be kEncodeFinishDelayMs in the past.
272   EXPECT_NEAR(image.capture_time_ms_, rtc::TimeMillis() - kEncodeFinishDelayMs,
273               1);
274 }
275 
TEST(FrameEncodeMetadataWriterTest,NotifiesAboutDroppedFrames)276 TEST(FrameEncodeMetadataWriterTest, NotifiesAboutDroppedFrames) {
277   const int64_t kTimestampMs1 = 47721840;
278   const int64_t kTimestampMs2 = 47721850;
279   const int64_t kTimestampMs3 = 47721860;
280   const int64_t kTimestampMs4 = 47721870;
281 
282   FakeEncodedImageCallback sink;
283   FrameEncodeMetadataWriter encode_timer(&sink);
284   encode_timer.OnEncoderInit(VideoCodec(), false);
285   // Any non-zero bitrate needed to be set before the first frame.
286   VideoBitrateAllocation bitrate_allocation;
287   bitrate_allocation.SetBitrate(0, 0, 500000);
288   encode_timer.OnSetRates(bitrate_allocation, 30);
289 
290   EncodedImage image;
291   VideoFrame frame = VideoFrame::Builder()
292                          .set_timestamp_rtp(kTimestampMs1 * 90)
293                          .set_timestamp_ms(kTimestampMs1)
294                          .set_video_frame_buffer(kFrameBuffer)
295                          .build();
296 
297   image.capture_time_ms_ = kTimestampMs1;
298   image.SetTimestamp(static_cast<uint32_t>(image.capture_time_ms_ * 90));
299   frame.set_timestamp(image.capture_time_ms_ * 90);
300   frame.set_timestamp_us(image.capture_time_ms_ * 1000);
301   encode_timer.OnEncodeStarted(frame);
302 
303   EXPECT_EQ(0u, sink.GetNumFramesDropped());
304   encode_timer.FillTimingInfo(0, &image);
305 
306   image.capture_time_ms_ = kTimestampMs2;
307   image.SetTimestamp(static_cast<uint32_t>(image.capture_time_ms_ * 90));
308   image.timing_ = EncodedImage::Timing();
309   frame.set_timestamp(image.capture_time_ms_ * 90);
310   frame.set_timestamp_us(image.capture_time_ms_ * 1000);
311   encode_timer.OnEncodeStarted(frame);
312   // No OnEncodedImageCall for timestamp2. Yet, at this moment it's not known
313   // that frame with timestamp2 was dropped.
314   EXPECT_EQ(0u, sink.GetNumFramesDropped());
315 
316   image.capture_time_ms_ = kTimestampMs3;
317   image.SetTimestamp(static_cast<uint32_t>(image.capture_time_ms_ * 90));
318   image.timing_ = EncodedImage::Timing();
319   frame.set_timestamp(image.capture_time_ms_ * 90);
320   frame.set_timestamp_us(image.capture_time_ms_ * 1000);
321   encode_timer.OnEncodeStarted(frame);
322   encode_timer.FillTimingInfo(0, &image);
323   EXPECT_EQ(1u, sink.GetNumFramesDropped());
324 
325   image.capture_time_ms_ = kTimestampMs4;
326   image.SetTimestamp(static_cast<uint32_t>(image.capture_time_ms_ * 90));
327   image.timing_ = EncodedImage::Timing();
328   frame.set_timestamp(image.capture_time_ms_ * 90);
329   frame.set_timestamp_us(image.capture_time_ms_ * 1000);
330   encode_timer.OnEncodeStarted(frame);
331   encode_timer.FillTimingInfo(0, &image);
332   EXPECT_EQ(1u, sink.GetNumFramesDropped());
333 }
334 
TEST(FrameEncodeMetadataWriterTest,RestoresCaptureTimestamps)335 TEST(FrameEncodeMetadataWriterTest, RestoresCaptureTimestamps) {
336   EncodedImage image;
337   const int64_t kTimestampMs = 123456;
338   FakeEncodedImageCallback sink;
339 
340   FrameEncodeMetadataWriter encode_timer(&sink);
341   encode_timer.OnEncoderInit(VideoCodec(), false);
342   // Any non-zero bitrate needed to be set before the first frame.
343   VideoBitrateAllocation bitrate_allocation;
344   bitrate_allocation.SetBitrate(0, 0, 500000);
345   encode_timer.OnSetRates(bitrate_allocation, 30);
346 
347   image.capture_time_ms_ = kTimestampMs;  // Correct timestamp.
348   image.SetTimestamp(static_cast<uint32_t>(image.capture_time_ms_ * 90));
349   VideoFrame frame = VideoFrame::Builder()
350                          .set_timestamp_ms(image.capture_time_ms_)
351                          .set_timestamp_rtp(image.capture_time_ms_ * 90)
352                          .set_video_frame_buffer(kFrameBuffer)
353                          .build();
354   encode_timer.OnEncodeStarted(frame);
355   image.capture_time_ms_ = 0;  // Incorrect timestamp.
356   encode_timer.FillTimingInfo(0, &image);
357   EXPECT_EQ(kTimestampMs, image.capture_time_ms_);
358 }
359 
TEST(FrameEncodeMetadataWriterTest,CopiesRotation)360 TEST(FrameEncodeMetadataWriterTest, CopiesRotation) {
361   EncodedImage image;
362   const int64_t kTimestampMs = 123456;
363   FakeEncodedImageCallback sink;
364 
365   FrameEncodeMetadataWriter encode_timer(&sink);
366   encode_timer.OnEncoderInit(VideoCodec(), false);
367   // Any non-zero bitrate needed to be set before the first frame.
368   VideoBitrateAllocation bitrate_allocation;
369   bitrate_allocation.SetBitrate(0, 0, 500000);
370   encode_timer.OnSetRates(bitrate_allocation, 30);
371 
372   image.SetTimestamp(static_cast<uint32_t>(kTimestampMs * 90));
373   VideoFrame frame = VideoFrame::Builder()
374                          .set_timestamp_ms(kTimestampMs)
375                          .set_timestamp_rtp(kTimestampMs * 90)
376                          .set_rotation(kVideoRotation_180)
377                          .set_video_frame_buffer(kFrameBuffer)
378                          .build();
379   encode_timer.OnEncodeStarted(frame);
380   encode_timer.FillTimingInfo(0, &image);
381   EXPECT_EQ(kVideoRotation_180, image.rotation_);
382 }
383 
TEST(FrameEncodeMetadataWriterTest,SetsContentType)384 TEST(FrameEncodeMetadataWriterTest, SetsContentType) {
385   EncodedImage image;
386   const int64_t kTimestampMs = 123456;
387   FakeEncodedImageCallback sink;
388 
389   FrameEncodeMetadataWriter encode_timer(&sink);
390   VideoCodec codec;
391   codec.mode = VideoCodecMode::kScreensharing;
392   encode_timer.OnEncoderInit(codec, false);
393   // Any non-zero bitrate needed to be set before the first frame.
394   VideoBitrateAllocation bitrate_allocation;
395   bitrate_allocation.SetBitrate(0, 0, 500000);
396   encode_timer.OnSetRates(bitrate_allocation, 30);
397 
398   image.SetTimestamp(static_cast<uint32_t>(kTimestampMs * 90));
399   VideoFrame frame = VideoFrame::Builder()
400                          .set_timestamp_ms(kTimestampMs)
401                          .set_timestamp_rtp(kTimestampMs * 90)
402                          .set_rotation(kVideoRotation_180)
403                          .set_video_frame_buffer(kFrameBuffer)
404                          .build();
405   encode_timer.OnEncodeStarted(frame);
406   encode_timer.FillTimingInfo(0, &image);
407   EXPECT_EQ(VideoContentType::SCREENSHARE, image.content_type_);
408 }
409 
TEST(FrameEncodeMetadataWriterTest,CopiesColorSpace)410 TEST(FrameEncodeMetadataWriterTest, CopiesColorSpace) {
411   EncodedImage image;
412   const int64_t kTimestampMs = 123456;
413   FakeEncodedImageCallback sink;
414 
415   FrameEncodeMetadataWriter encode_timer(&sink);
416   encode_timer.OnEncoderInit(VideoCodec(), false);
417   // Any non-zero bitrate needed to be set before the first frame.
418   VideoBitrateAllocation bitrate_allocation;
419   bitrate_allocation.SetBitrate(0, 0, 500000);
420   encode_timer.OnSetRates(bitrate_allocation, 30);
421 
422   webrtc::ColorSpace color_space =
423       CreateTestColorSpace(/*with_hdr_metadata=*/true);
424   image.SetTimestamp(static_cast<uint32_t>(kTimestampMs * 90));
425   VideoFrame frame = VideoFrame::Builder()
426                          .set_timestamp_ms(kTimestampMs)
427                          .set_timestamp_rtp(kTimestampMs * 90)
428                          .set_color_space(color_space)
429                          .set_video_frame_buffer(kFrameBuffer)
430                          .build();
431   encode_timer.OnEncodeStarted(frame);
432   encode_timer.FillTimingInfo(0, &image);
433   ASSERT_NE(image.ColorSpace(), nullptr);
434   EXPECT_EQ(color_space, *image.ColorSpace());
435 }
436 
TEST(FrameEncodeMetadataWriterTest,CopiesPacketInfos)437 TEST(FrameEncodeMetadataWriterTest, CopiesPacketInfos) {
438   EncodedImage image;
439   const int64_t kTimestampMs = 123456;
440   FakeEncodedImageCallback sink;
441 
442   FrameEncodeMetadataWriter encode_timer(&sink);
443   encode_timer.OnEncoderInit(VideoCodec(), false);
444   // Any non-zero bitrate needed to be set before the first frame.
445   VideoBitrateAllocation bitrate_allocation;
446   bitrate_allocation.SetBitrate(0, 0, 500000);
447   encode_timer.OnSetRates(bitrate_allocation, 30);
448 
449   RtpPacketInfos packet_infos = CreatePacketInfos(3);
450   image.SetTimestamp(static_cast<uint32_t>(kTimestampMs * 90));
451   VideoFrame frame = VideoFrame::Builder()
452                          .set_timestamp_ms(kTimestampMs)
453                          .set_timestamp_rtp(kTimestampMs * 90)
454                          .set_packet_infos(packet_infos)
455                          .set_video_frame_buffer(kFrameBuffer)
456                          .build();
457   encode_timer.OnEncodeStarted(frame);
458   encode_timer.FillTimingInfo(0, &image);
459   EXPECT_EQ(image.PacketInfos().size(), 3U);
460 }
461 
TEST(FrameEncodeMetadataWriterTest,DoesNotRewriteBitstreamWithoutCodecInfo)462 TEST(FrameEncodeMetadataWriterTest, DoesNotRewriteBitstreamWithoutCodecInfo) {
463   uint8_t buffer[] = {1, 2, 3};
464   EncodedImage image(buffer, sizeof(buffer), sizeof(buffer));
465 
466   FakeEncodedImageCallback sink;
467   FrameEncodeMetadataWriter encode_metadata_writer(&sink);
468   encode_metadata_writer.UpdateBitstream(nullptr, &image);
469   EXPECT_EQ(image.data(), buffer);
470   EXPECT_EQ(image.size(), sizeof(buffer));
471 }
472 
TEST(FrameEncodeMetadataWriterTest,DoesNotRewriteVp8Bitstream)473 TEST(FrameEncodeMetadataWriterTest, DoesNotRewriteVp8Bitstream) {
474   uint8_t buffer[] = {1, 2, 3};
475   EncodedImage image(buffer, sizeof(buffer), sizeof(buffer));
476   CodecSpecificInfo codec_specific_info;
477   codec_specific_info.codecType = kVideoCodecVP8;
478 
479   FakeEncodedImageCallback sink;
480   FrameEncodeMetadataWriter encode_metadata_writer(&sink);
481   encode_metadata_writer.UpdateBitstream(&codec_specific_info, &image);
482   EXPECT_EQ(image.data(), buffer);
483   EXPECT_EQ(image.size(), sizeof(buffer));
484 }
485 
TEST(FrameEncodeMetadataWriterTest,RewritesH264BitstreamWithNonOptimalSps)486 TEST(FrameEncodeMetadataWriterTest, RewritesH264BitstreamWithNonOptimalSps) {
487   uint8_t original_sps[] = {0,    0,    0,    1,    H264::NaluType::kSps,
488                             0x00, 0x00, 0x03, 0x03, 0xF4,
489                             0x05, 0x03, 0xC7, 0xC0};
490   const uint8_t kRewrittenSps[] = {0,    0,    0,    1,    H264::NaluType::kSps,
491                                    0x00, 0x00, 0x03, 0x03, 0xF4,
492                                    0x05, 0x03, 0xC7, 0xE0, 0x1B,
493                                    0x41, 0x10, 0x8D, 0x00};
494 
495   EncodedImage image(original_sps, sizeof(original_sps), sizeof(original_sps));
496   image._frameType = VideoFrameType::kVideoFrameKey;
497 
498   CodecSpecificInfo codec_specific_info;
499   codec_specific_info.codecType = kVideoCodecH264;
500 
501   FakeEncodedImageCallback sink;
502   FrameEncodeMetadataWriter encode_metadata_writer(&sink);
503   encode_metadata_writer.UpdateBitstream(&codec_specific_info, &image);
504 
505   EXPECT_THAT(std::vector<uint8_t>(image.data(), image.data() + image.size()),
506               testing::ElementsAreArray(kRewrittenSps));
507 }
508 
509 }  // namespace test
510 }  // namespace webrtc
511