1 /******************************************************************************
2 *
3 * Copyright (C) 2020 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 *****************************************************************************
18 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
19 */
20
21 #include <stdint.h>
22 #include <string.h>
23 #include <algorithm>
24 #include "aacdecoder_lib.h"
25
26 constexpr uint8_t kNumberOfLayers = 1;
27 constexpr uint8_t kMaxChannelCount = 8;
28 constexpr uint32_t kMaxConfigurationSize = 1024;
29 constexpr uint32_t kMaxOutBufferSize = 2048 * kMaxChannelCount;
30
31 // Value indicating the start of AAC Header Segment
32 constexpr const char *kAacSegStartSeq = "AAC_STRT";
33 constexpr uint8_t kAacSegStartSeqLen = sizeof(kAacSegStartSeq);
34 // Value indicating the end of AAC Header Segment
35 constexpr const char *kAacSegEndSeq = "AAC_ENDS";
36 constexpr uint8_t kAacSegEndSeqLen = sizeof(kAacSegEndSeq);
37
38 // Number of bytes used to signal the length of the header
39 constexpr uint8_t kHeaderLengthBytes = 2;
40 // Minimum size of an AAC header is 2
41 // Minimum data required is
42 // strlen(AAC_STRT) + strlen(AAC_ENDS) + kHeaderLengthBytes + 2;
43 constexpr UINT kMinDataSize = kAacSegStartSeqLen + kAacSegEndSeqLen + kHeaderLengthBytes + 2;
44
getHeaderSize(UCHAR * data,UINT size)45 UINT getHeaderSize(UCHAR *data, UINT size) {
46 if (size < kMinDataSize) {
47 return 0;
48 }
49
50 int32_t result = memcmp(data, kAacSegStartSeq, kAacSegStartSeqLen);
51 if (result) {
52 return 0;
53 }
54 data += kAacSegStartSeqLen;
55 size -= kAacSegStartSeqLen;
56
57 uint32_t headerLengthInBytes = (data[0] << 8 | data[1]) & 0xFFFF;
58 data += kHeaderLengthBytes;
59 size -= kHeaderLengthBytes;
60
61 if (headerLengthInBytes + kAacSegEndSeqLen > size) {
62 return 0;
63 }
64
65 data += headerLengthInBytes;
66 size -= headerLengthInBytes;
67 result = memcmp(data, kAacSegEndSeq, kAacSegEndSeqLen);
68 if (result) {
69 return 0;
70 }
71
72 return std::min(headerLengthInBytes, kMaxConfigurationSize);
73 }
74
75 class Codec {
76 public:
77 Codec() = default;
~Codec()78 ~Codec() { deInitDecoder(); }
79 bool initDecoder();
80 void decodeFrames(UCHAR *data, UINT size);
81 void deInitDecoder();
82
83 private:
84 HANDLE_AACDECODER mAacDecoderHandle = nullptr;
85 AAC_DECODER_ERROR mErrorCode = AAC_DEC_OK;
86 };
87
initDecoder()88 bool Codec::initDecoder() {
89 mAacDecoderHandle = aacDecoder_Open(TT_MP4_ADIF, kNumberOfLayers);
90 if (!mAacDecoderHandle) {
91 return false;
92 }
93 return true;
94 }
95
deInitDecoder()96 void Codec::deInitDecoder() {
97 aacDecoder_Close(mAacDecoderHandle);
98 mAacDecoderHandle = nullptr;
99 }
100
decodeFrames(UCHAR * data,UINT size)101 void Codec::decodeFrames(UCHAR *data, UINT size) {
102 UINT headerSize = getHeaderSize(data, size);
103 if (headerSize != 0) {
104 data += kAacSegStartSeqLen + kHeaderLengthBytes;
105 size -= kAacSegStartSeqLen + kHeaderLengthBytes;
106 aacDecoder_ConfigRaw(mAacDecoderHandle, &data, &headerSize);
107 data += headerSize + kAacSegEndSeqLen;
108 size -= headerSize + kAacSegEndSeqLen;
109 }
110 while (size > 0) {
111 UINT inputSize = size;
112 UINT valid = size;
113 mErrorCode = aacDecoder_Fill(mAacDecoderHandle, &data, &inputSize, &valid);
114 if (mErrorCode != AAC_DEC_OK) {
115 ++data;
116 --size;
117 } else {
118 INT_PCM outputBuf[kMaxOutBufferSize];
119 do {
120 mErrorCode =
121 aacDecoder_DecodeFrame(mAacDecoderHandle, outputBuf,
122 kMaxOutBufferSize /*size in number of INT_PCM, not bytes*/, 0);
123 } while (mErrorCode == AAC_DEC_OK);
124 UINT offset = inputSize - valid;
125 data += offset;
126 size = valid;
127 }
128 }
129 }
130
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)131 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
132 Codec *codec = new Codec();
133 if (!codec) {
134 return 0;
135 }
136 if (codec->initDecoder()) {
137 codec->decodeFrames((UCHAR *)(data), static_cast<UINT>(size));
138 }
139 delete codec;
140 return 0;
141 }
142