1*09537850SAkhilesh Sanikop // Copyright 2020 The libgav1 Authors
2*09537850SAkhilesh Sanikop //
3*09537850SAkhilesh Sanikop // Licensed under the Apache License, Version 2.0 (the "License");
4*09537850SAkhilesh Sanikop // you may not use this file except in compliance with the License.
5*09537850SAkhilesh Sanikop // You may obtain a copy of the License at
6*09537850SAkhilesh Sanikop //
7*09537850SAkhilesh Sanikop // http://www.apache.org/licenses/LICENSE-2.0
8*09537850SAkhilesh Sanikop //
9*09537850SAkhilesh Sanikop // Unless required by applicable law or agreed to in writing, software
10*09537850SAkhilesh Sanikop // distributed under the License is distributed on an "AS IS" BASIS,
11*09537850SAkhilesh Sanikop // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*09537850SAkhilesh Sanikop // See the License for the specific language governing permissions and
13*09537850SAkhilesh Sanikop // limitations under the License.
14*09537850SAkhilesh Sanikop
15*09537850SAkhilesh Sanikop #include <cstddef>
16*09537850SAkhilesh Sanikop #include <cstdint>
17*09537850SAkhilesh Sanikop #include <memory>
18*09537850SAkhilesh Sanikop #include <vector>
19*09537850SAkhilesh Sanikop
20*09537850SAkhilesh Sanikop #include "examples/file_reader.h"
21*09537850SAkhilesh Sanikop #include "examples/file_reader_constants.h"
22*09537850SAkhilesh Sanikop #include "examples/file_reader_interface.h"
23*09537850SAkhilesh Sanikop #include "src/gav1/decoder.h"
24*09537850SAkhilesh Sanikop #include "tests/fuzzer/fuzzer_temp_file.h"
25*09537850SAkhilesh Sanikop
26*09537850SAkhilesh Sanikop namespace {
27*09537850SAkhilesh Sanikop
28*09537850SAkhilesh Sanikop #if defined(LIBGAV1_EXHAUSTIVE_FUZZING)
29*09537850SAkhilesh Sanikop // Set a large upper bound to give more coverage of a single input; this value
30*09537850SAkhilesh Sanikop // should be larger than most of the frame counts in the corpus.
31*09537850SAkhilesh Sanikop constexpr int kMaxFrames = 100;
32*09537850SAkhilesh Sanikop constexpr size_t kMaxDataSize = 400 * 1024;
33*09537850SAkhilesh Sanikop #else
34*09537850SAkhilesh Sanikop // Restrict the number of frames to improve fuzzer throughput.
35*09537850SAkhilesh Sanikop constexpr int kMaxFrames = 5;
36*09537850SAkhilesh Sanikop constexpr size_t kMaxDataSize = 200 * 1024;
37*09537850SAkhilesh Sanikop #endif
38*09537850SAkhilesh Sanikop
Decode(const uint8_t * const data,const size_t size,libgav1::Decoder * const decoder)39*09537850SAkhilesh Sanikop void Decode(const uint8_t* const data, const size_t size,
40*09537850SAkhilesh Sanikop libgav1::Decoder* const decoder) {
41*09537850SAkhilesh Sanikop decoder->EnqueueFrame(data, size, /*user_private_data=*/0,
42*09537850SAkhilesh Sanikop /*buffer_private_data=*/nullptr);
43*09537850SAkhilesh Sanikop const libgav1::DecoderBuffer* buffer;
44*09537850SAkhilesh Sanikop decoder->DequeueFrame(&buffer);
45*09537850SAkhilesh Sanikop }
46*09537850SAkhilesh Sanikop
47*09537850SAkhilesh Sanikop } // namespace
48*09537850SAkhilesh Sanikop
49*09537850SAkhilesh Sanikop // Always returns 0. Nonzero return values are reserved by libFuzzer for future
50*09537850SAkhilesh Sanikop // use.
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)51*09537850SAkhilesh Sanikop extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
52*09537850SAkhilesh Sanikop // Reject large chunks of data to improve fuzzer throughput.
53*09537850SAkhilesh Sanikop if (size > kMaxDataSize) return 0;
54*09537850SAkhilesh Sanikop
55*09537850SAkhilesh Sanikop libgav1::Decoder decoder;
56*09537850SAkhilesh Sanikop libgav1::DecoderSettings settings = {};
57*09537850SAkhilesh Sanikop // Use the low byte of the width to seed the number of threads.
58*09537850SAkhilesh Sanikop // We use both nibbles of the lower byte as this results in values != 1 much
59*09537850SAkhilesh Sanikop // more quickly than using the lower nibble alone.
60*09537850SAkhilesh Sanikop settings.threads = (size >= 13) ? ((data[12] >> 4 | data[12]) & 0xF) + 1 : 1;
61*09537850SAkhilesh Sanikop if (decoder.Init(&settings) != libgav1::kStatusOk) return 0;
62*09537850SAkhilesh Sanikop
63*09537850SAkhilesh Sanikop // Treat the input as a raw OBU stream.
64*09537850SAkhilesh Sanikop Decode(data, size, &decoder);
65*09537850SAkhilesh Sanikop
66*09537850SAkhilesh Sanikop // Use the first frame from an IVF to bypass any read errors from the parser.
67*09537850SAkhilesh Sanikop static constexpr size_t kIvfHeaderSize =
68*09537850SAkhilesh Sanikop libgav1::kIvfFileHeaderSize + libgav1::kIvfFrameHeaderSize;
69*09537850SAkhilesh Sanikop if (size >= kIvfHeaderSize) {
70*09537850SAkhilesh Sanikop Decode(data + kIvfHeaderSize, size - kIvfHeaderSize, &decoder);
71*09537850SAkhilesh Sanikop }
72*09537850SAkhilesh Sanikop
73*09537850SAkhilesh Sanikop FuzzerTemporaryFile tempfile(data, size);
74*09537850SAkhilesh Sanikop auto file_reader =
75*09537850SAkhilesh Sanikop libgav1::FileReader::Open(tempfile.filename(), /*error_tolerant=*/true);
76*09537850SAkhilesh Sanikop if (file_reader == nullptr) return 0;
77*09537850SAkhilesh Sanikop
78*09537850SAkhilesh Sanikop std::vector<uint8_t> buffer;
79*09537850SAkhilesh Sanikop int decoded_frames = 0;
80*09537850SAkhilesh Sanikop do {
81*09537850SAkhilesh Sanikop if (!file_reader->ReadTemporalUnit(&buffer, nullptr)) break;
82*09537850SAkhilesh Sanikop Decode(buffer.data(), buffer.size(), &decoder);
83*09537850SAkhilesh Sanikop if (++decoded_frames >= kMaxFrames) break;
84*09537850SAkhilesh Sanikop } while (!file_reader->IsEndOfFile());
85*09537850SAkhilesh Sanikop
86*09537850SAkhilesh Sanikop return 0;
87*09537850SAkhilesh Sanikop }
88