1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <utils/Log.h>
17 
18 #include "WriterFuzzerBase.h"
19 
20 using namespace android;
21 
22 /**
23  * Buffer source implementations to parse input file
24  */
25 
getNumTracks()26 uint32_t WriterFuzzerBase::BufferSource::getNumTracks() {
27     uint32_t numTracks = 0;
28     if (mSize > sizeof(uint8_t)) {
29         numTracks = min(mData[0], kMaxTrackCount);
30         mReadIndex += sizeof(uint8_t);
31     }
32     return numTracks;
33 }
34 
searchForMarker(size_t startIndex)35 bool WriterFuzzerBase::BufferSource::searchForMarker(size_t startIndex) {
36     while (true) {
37         if (isMarker()) {
38             return true;
39         }
40         --mReadIndex;
41         if (mReadIndex < startIndex) {
42             break;
43         }
44     }
45     return false;
46 }
47 
getConfigFormat(int32_t trackIndex)48 ConfigFormat WriterFuzzerBase::BufferSource::getConfigFormat(int32_t trackIndex) {
49     return mParams[trackIndex];
50 }
51 
getNumCsds(int32_t trackIndex)52 int32_t WriterFuzzerBase::BufferSource::getNumCsds(int32_t trackIndex) {
53     return mNumCsds[trackIndex];
54 }
55 
getFrameList(int32_t trackIndex)56 vector<FrameData> &WriterFuzzerBase::BufferSource::getFrameList(int32_t trackIndex) {
57     return mFrameList[trackIndex];
58 }
59 
getFrameInfo()60 void WriterFuzzerBase::BufferSource::getFrameInfo() {
61     size_t readIndexStart = mReadIndex;
62     if (mSize - mReadIndex > kMarkerSize + kMarkerSuffixSize) {
63         bool isFrameAvailable = true;
64         size_t bytesRemaining = mSize;
65         mReadIndex = mSize - kMarkerSize;
66         while (isFrameAvailable) {
67             isFrameAvailable = searchForMarker(readIndexStart);
68             if (isFrameAvailable) {
69                 size_t location = mReadIndex + kMarkerSize;
70                 if (location + kMarkerSuffixSize >= bytesRemaining) {
71                     break;
72                 }
73                 bool isCSD = isCSDMarker(location);
74                 location += kMarkerSuffixSize;
75                 uint8_t *framePtr = const_cast<uint8_t *>(&mData[location]);
76                 size_t frameSize = bytesRemaining - location, bufferSize = 0;
77                 uint8_t trackIndex = framePtr[0] % kMaxTrackCount;
78                 ++framePtr;
79                 uint8_t flags = 0;
80                 int64_t pts = 0;
81                 if (isCSD && frameSize > 1) {
82                     flags |= kCodecConfigFlag;
83                     pts = 0;
84                     ++mNumCsds[trackIndex];
85                     bufferSize = frameSize - 1;
86                 } else if (frameSize > sizeof(uint8_t) + sizeof(int64_t) + 1) {
87                     flags = flagTypes[framePtr[0] % size(flagTypes)];
88                     ++framePtr;
89                     copy(framePtr, framePtr + sizeof(int64_t), reinterpret_cast<uint8_t *>(&pts));
90                     framePtr += sizeof(int64_t);
91                     bufferSize = frameSize - (sizeof(uint8_t) + sizeof(int64_t)) - 1;
92                 } else {
93                     break;
94                 }
95                 mFrameList[trackIndex].insert(mFrameList[trackIndex].begin(),
96                                               FrameData{bufferSize, flags, pts, framePtr});
97                 bytesRemaining -= (frameSize + kMarkerSize + kMarkerSuffixSize);
98                 --mReadIndex;
99             }
100         }
101     }
102     if (mFrameList[0].empty() && mFrameList[1].empty()) {
103         /**
104          * Scenario where input data does not contain the custom frame markers.
105          * Hence feed the entire data as single frame.
106          */
107         mFrameList[0].emplace_back(FrameData{mSize - readIndexStart, 0, 0, mData + readIndexStart});
108     }
109 }
getTrackInfo(int32_t trackIndex)110 bool WriterFuzzerBase::BufferSource::getTrackInfo(int32_t trackIndex) {
111     if (mSize <= mReadIndex + sizeof(uint8_t)) {
112         return false;
113     }
114     size_t mimeTypeIdx = mData[mReadIndex] % kSupportedMimeTypes;
115     char *mime = (char *)supportedMimeTypes[mimeTypeIdx].c_str();
116     mParams[trackIndex].mime = mime;
117     mReadIndex += sizeof(uint8_t);
118 
119     if (mSize > mReadIndex + 2 * sizeof(int32_t)) {
120         if (!strncmp(mime, "audio/", 6)) {
121             copy(mData + mReadIndex, mData + mReadIndex + sizeof(int32_t),
122                  reinterpret_cast<char *>(&mParams[trackIndex].channelCount));
123             copy(mData + mReadIndex + sizeof(int32_t), mData + mReadIndex + 2 * sizeof(int32_t),
124                  reinterpret_cast<char *>(&mParams[trackIndex].sampleRate));
125         } else if (!strncmp(mime, "video/", 6)) {
126             copy(mData + mReadIndex, mData + mReadIndex + sizeof(int32_t),
127                  reinterpret_cast<char *>(&mParams[trackIndex].height));
128             copy(mData + mReadIndex + sizeof(int32_t), mData + mReadIndex + 2 * sizeof(int32_t),
129                  reinterpret_cast<char *>(&mParams[trackIndex].width));
130         }
131         mReadIndex += 2 * sizeof(int32_t);
132     } else {
133         if (strncmp(mime, "text/", 5) && strncmp(mime, "application/", 12)) {
134             return false;
135         }
136     }
137     return true;
138 }
139 
writeHeaderBuffers(vector<FrameData> & bufferInfo,sp<AMessage> & format,int32_t numCsds)140 void writeHeaderBuffers(vector<FrameData> &bufferInfo, sp<AMessage> &format, int32_t numCsds) {
141     char csdName[kMaxCSDStrlen];
142     for (int csdId = 0; csdId < numCsds; ++csdId) {
143         int32_t flags = bufferInfo[csdId].flags;
144         if (flags == kCodecConfigFlag) {
145             sp<ABuffer> csdBuffer =
146                 ABuffer::CreateAsCopy((void *)bufferInfo[csdId].buf, bufferInfo[csdId].size);
147             if (csdBuffer.get() == nullptr || csdBuffer->base() == nullptr) {
148                 return;
149             }
150             snprintf(csdName, sizeof(csdName), "csd-%d", csdId);
151             format->setBuffer(csdName, csdBuffer);
152         }
153     }
154 }
155 
createOutputFile()156 bool WriterFuzzerBase::createOutputFile() {
157     mFd = memfd_create(mOutputFileName.c_str(), MFD_ALLOW_SEALING);
158     if (mFd == -1) {
159         return false;
160     }
161     return true;
162 }
163 
addWriterSource(int32_t trackIndex)164 void WriterFuzzerBase::addWriterSource(int32_t trackIndex) {
165     ConfigFormat params = mBufferSource->getConfigFormat(trackIndex);
166     sp<AMessage> format = new AMessage;
167     format->setString("mime", params.mime);
168     if (!strncmp(params.mime, "audio/", 6)) {
169         if (!strncmp(params.mime, "audio/3gpp", 10)) {
170             params.channelCount = 1;
171             params.sampleRate = 8000;
172         } else if (!strncmp(params.mime, "audio/amr-wb", 12)) {
173             params.channelCount = 1;
174             params.sampleRate = 16000;
175         } else {
176             params.sampleRate = max(1, params.sampleRate);
177             params.channelCount = max(0, params.channelCount);
178         }
179         format->setInt32("channel-count", params.channelCount);
180         format->setInt32("sample-rate", params.sampleRate);
181     } else if (!strncmp(params.mime, "video/", 6)) {
182         params.width = max(1, params.width);
183         params.height = max(1, params.height);
184         format->setInt32("width", params.width);
185         format->setInt32("height", params.height);
186     }
187     int32_t numCsds = mBufferSource->getNumCsds(trackIndex);
188     if (numCsds) {
189         vector<FrameData> mFrames = mBufferSource->getFrameList(trackIndex);
190         writeHeaderBuffers(mFrames, format, numCsds);
191     }
192     sp<MetaData> trackMeta = new MetaData;
193     convertMessageToMetaData(format, trackMeta);
194     mCurrentTrack[trackIndex] = new MediaAdapter(trackMeta);
195     if (mWriter->addSource(mCurrentTrack[trackIndex]) != OK) {
196         mCurrentTrack[trackIndex] = nullptr;
197     }
198 }
199 
start()200 void WriterFuzzerBase::start() {
201     mFileMeta->setInt32(kKeyRealTimeRecording, false);
202     mWriter->start(mFileMeta.get());
203 }
204 
sendBuffersToWriter(sp<MediaAdapter> & currentTrack,int32_t trackIndex,int32_t startFrameIndex,int32_t endFrameIndex)205 void WriterFuzzerBase::sendBuffersToWriter(sp<MediaAdapter> &currentTrack, int32_t trackIndex,
206                                            int32_t startFrameIndex, int32_t endFrameIndex) {
207     if (!mCurrentTrack[trackIndex]) {
208         return;
209     }
210     vector<FrameData> bufferInfo = mBufferSource->getFrameList(trackIndex);
211     for (int idx = startFrameIndex; idx < endFrameIndex; ++idx) {
212         if (!mWriter->isSampleMetadataValid(trackIndex, bufferInfo[idx].timeUs)) {
213             continue;
214         }
215         sp<ABuffer> buffer = new ABuffer((void *)bufferInfo[idx].buf, bufferInfo[idx].size);
216         MediaBuffer *mediaBuffer = new MediaBuffer(buffer);
217 
218         mediaBuffer->set_range(buffer->offset(), buffer->size());
219         MetaDataBase &sampleMetaData = mediaBuffer->meta_data();
220         sampleMetaData.setInt64(kKeyTime, bufferInfo[idx].timeUs);
221 
222         // Just set the kKeyDecodingTime as the presentation time for now.
223         sampleMetaData.setInt64(kKeyDecodingTime, bufferInfo[idx].timeUs);
224         if (bufferInfo[idx].flags == SampleFlag::SYNC_FLAG) {
225             sampleMetaData.setInt32(kKeyIsSyncFrame, true);
226         }
227 
228         // Released in MediaAdapter::signalBufferReturned().
229         mediaBuffer->add_ref();
230 
231         // This pushBuffer will wait until the mediaBuffer is consumed.
232         android::status_t pushStatus = currentTrack->pushBuffer(mediaBuffer);
233 
234         if (pushStatus != OK) {
235             if (pushStatus == INVALID_OPERATION) {
236                 // In Case of INVALID_OPERATION, mObserver needs to be set before calling release()
237                 mediaBuffer->setObserver(currentTrack.get());
238             }
239             mediaBuffer->release();
240         }
241     }
242 }
243 
sendBuffersInterleave(int32_t numTracks,uint8_t numBuffersInterleave)244 void WriterFuzzerBase::sendBuffersInterleave(int32_t numTracks, uint8_t numBuffersInterleave) {
245     int32_t currentFrameIndex[numTracks], remainingNumFrames[numTracks], numTrackFramesDone;
246     for (int32_t idx = 0; idx < numTracks; ++idx) {
247         currentFrameIndex[idx] = mBufferSource->getNumCsds(idx);
248         remainingNumFrames[idx] = mBufferSource->getFrameList(idx).size() - currentFrameIndex[idx];
249     }
250     do {
251         numTrackFramesDone = numTracks;
252         for (int32_t idx = 0; idx < numTracks; ++idx) {
253             if (remainingNumFrames[idx] > 0) {
254                 int32_t numFramesInterleave =
255                     min(remainingNumFrames[idx], static_cast<int32_t>(numBuffersInterleave));
256                 sendBuffersToWriter(mCurrentTrack[idx], idx, currentFrameIndex[idx],
257                                     currentFrameIndex[idx] + numFramesInterleave);
258                 currentFrameIndex[idx] += numFramesInterleave;
259                 remainingNumFrames[idx] -= numFramesInterleave;
260                 --numTrackFramesDone;
261             }
262         }
263     } while (numTrackFramesDone < numTracks);
264 }
265 
initFileWriterAndProcessData(const uint8_t * data,size_t size)266 void WriterFuzzerBase::initFileWriterAndProcessData(const uint8_t *data, size_t size) {
267     if (!createOutputFile()) {
268         return;
269     }
270     if (!createWriter()) {
271         return;
272     }
273 
274     if (size < 1) {
275         return;
276     }
277     uint8_t numBuffersInterleave = (data[0] == 0 ? 1 : data[0]);
278     ++data;
279     --size;
280 
281     mBufferSource = new BufferSource(data, size);
282     if (!mBufferSource) {
283         return;
284     }
285     mNumTracks = mBufferSource->getNumTracks();
286     if (mNumTracks > 0) {
287         for (int32_t idx = 0; idx < mNumTracks; ++idx) {
288             if (!mBufferSource->getTrackInfo(idx)) {
289                 if (idx == 0) {
290                     delete mBufferSource;
291                     return;
292                 }
293                 mNumTracks = idx;
294                 break;
295             }
296         }
297         mBufferSource->getFrameInfo();
298         for (int32_t idx = 0; idx < mNumTracks; ++idx) {
299             addWriterSource(idx);
300         }
301         start();
302         sendBuffersInterleave(mNumTracks, numBuffersInterleave);
303         for (int32_t idx = 0; idx < mNumTracks; ++idx) {
304             if (mCurrentTrack[idx]) {
305                 mCurrentTrack[idx]->stop();
306             }
307         }
308     }
309     delete mBufferSource;
310     mWriter->stop();
311 }
312