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> ¤tTrack, 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