1 /*
2 * Copyright (c) 2018 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 <memory>
12
13 #include "api/rtp_packet_infos.h"
14 #include "modules/video_coding/frame_object.h"
15 #include "modules/video_coding/packet_buffer.h"
16 #include "modules/video_coding/rtp_frame_reference_finder.h"
17 #include "system_wrappers/include/clock.h"
18
19 namespace webrtc {
20
21 namespace {
22 class DataReader {
23 public:
DataReader(const uint8_t * data,size_t size)24 DataReader(const uint8_t* data, size_t size) : data_(data), size_(size) {}
25
26 template <typename T>
CopyTo(T * object)27 void CopyTo(T* object) {
28 static_assert(std::is_pod<T>(), "");
29 uint8_t* destination = reinterpret_cast<uint8_t*>(object);
30 size_t object_size = sizeof(T);
31 size_t num_bytes = std::min(size_ - offset_, object_size);
32 memcpy(destination, data_ + offset_, num_bytes);
33 offset_ += num_bytes;
34
35 // If we did not have enough data, fill the rest with 0.
36 object_size -= num_bytes;
37 memset(destination + num_bytes, 0, object_size);
38 }
39
40 template <typename T>
GetNum()41 T GetNum() {
42 T res;
43 if (offset_ + sizeof(res) < size_) {
44 memcpy(&res, data_ + offset_, sizeof(res));
45 offset_ += sizeof(res);
46 return res;
47 }
48
49 offset_ = size_;
50 return T(0);
51 }
52
MoreToRead()53 bool MoreToRead() { return offset_ < size_; }
54
55 private:
56 const uint8_t* data_;
57 size_t size_;
58 size_t offset_ = 0;
59 };
60
61 class NullCallback : public video_coding::OnCompleteFrameCallback {
OnCompleteFrame(std::unique_ptr<video_coding::EncodedFrame> frame)62 void OnCompleteFrame(
63 std::unique_ptr<video_coding::EncodedFrame> frame) override {}
64 };
65
66 absl::optional<RTPVideoHeader::GenericDescriptorInfo>
GenerateGenericFrameDependencies(DataReader * reader)67 GenerateGenericFrameDependencies(DataReader* reader) {
68 absl::optional<RTPVideoHeader::GenericDescriptorInfo> result;
69 uint8_t flags = reader->GetNum<uint8_t>();
70 if (flags & 0b1000'0000) {
71 // i.e. with 50% chance there are no generic dependencies.
72 // in such case codec-specfic code path of the RtpFrameReferenceFinder will
73 // be validated.
74 return result;
75 }
76
77 result.emplace();
78 result->frame_id = reader->GetNum<int32_t>();
79 result->spatial_index = (flags & 0b0111'0000) >> 4;
80 result->temporal_index = (flags & 0b0000'1110) >> 1;
81
82 // Larger than supported by the RtpFrameReferenceFinder.
83 int num_diffs = (reader->GetNum<uint8_t>() % 16);
84 for (int i = 0; i < num_diffs; ++i) {
85 result->dependencies.push_back(result->frame_id -
86 (reader->GetNum<uint16_t>() % (1 << 14)));
87 }
88
89 return result;
90 }
91 } // namespace
92
FuzzOneInput(const uint8_t * data,size_t size)93 void FuzzOneInput(const uint8_t* data, size_t size) {
94 DataReader reader(data, size);
95 NullCallback cb;
96 video_coding::RtpFrameReferenceFinder reference_finder(&cb);
97
98 auto codec = static_cast<VideoCodecType>(reader.GetNum<uint8_t>() % 5);
99
100 while (reader.MoreToRead()) {
101 uint16_t first_seq_num = reader.GetNum<uint16_t>();
102 uint16_t last_seq_num = reader.GetNum<uint16_t>();
103 bool marker_bit = reader.GetNum<uint8_t>();
104
105 RTPVideoHeader video_header;
106 switch (reader.GetNum<uint8_t>() % 3) {
107 case 0:
108 video_header.frame_type = VideoFrameType::kEmptyFrame;
109 break;
110 case 1:
111 video_header.frame_type = VideoFrameType::kVideoFrameKey;
112 break;
113 case 2:
114 video_header.frame_type = VideoFrameType::kVideoFrameDelta;
115 break;
116 }
117
118 switch (codec) {
119 case kVideoCodecVP8:
120 reader.CopyTo(
121 &video_header.video_type_header.emplace<RTPVideoHeaderVP8>());
122 break;
123 case kVideoCodecVP9:
124 reader.CopyTo(
125 &video_header.video_type_header.emplace<RTPVideoHeaderVP9>());
126 break;
127 case kVideoCodecH264:
128 reader.CopyTo(
129 &video_header.video_type_header.emplace<RTPVideoHeaderH264>());
130 break;
131 default:
132 break;
133 }
134
135 video_header.generic = GenerateGenericFrameDependencies(&reader);
136
137 // clang-format off
138 auto frame = std::make_unique<video_coding::RtpFrameObject>(
139 first_seq_num,
140 last_seq_num,
141 marker_bit,
142 /*times_nacked=*/0,
143 /*first_packet_received_time=*/0,
144 /*last_packet_received_time=*/0,
145 /*rtp_timestamp=*/0,
146 /*ntp_time_ms=*/0,
147 VideoSendTiming(),
148 /*payload_type=*/0,
149 codec,
150 kVideoRotation_0,
151 VideoContentType::UNSPECIFIED,
152 video_header,
153 /*color_space=*/absl::nullopt,
154 RtpPacketInfos(),
155 EncodedImageBuffer::Create(/*size=*/0));
156 // clang-format on
157
158 reference_finder.ManageFrame(std::move(frame));
159 }
160 }
161
162 } // namespace webrtc
163