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
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "ExtractorFuzzerBase"
19 #include <utils/Log.h>
20
21 #include "ExtractorFuzzerBase.h"
22
23 using namespace android;
24
setDataSource(const uint8_t * data,size_t size)25 bool ExtractorFuzzerBase::setDataSource(const uint8_t* data, size_t size) {
26 if ((!data) || (size == 0)) {
27 return false;
28 }
29 mBufferSource = new BufferSource(data, size);
30 mDataSource = reinterpret_cast<DataSource*>(mBufferSource.get());
31 if (!mDataSource) {
32 return false;
33 }
34 return true;
35 }
36
getExtractorDef()37 void ExtractorFuzzerBase::getExtractorDef() {
38 float confidence;
39 void* meta = nullptr;
40 FreeMetaFunc freeMeta = nullptr;
41
42 ExtractorDef extractorDef = GETEXTRACTORDEF();
43 if (extractorDef.def_version == EXTRACTORDEF_VERSION_NDK_V1) {
44 extractorDef.u.v2.sniff(mDataSource->wrap(), &confidence, &meta, &freeMeta);
45 } else if (extractorDef.def_version == EXTRACTORDEF_VERSION_NDK_V2) {
46 extractorDef.u.v3.sniff(mDataSource->wrap(), &confidence, &meta, &freeMeta);
47 }
48
49 if (meta != nullptr && freeMeta != nullptr) {
50 freeMeta(meta);
51 }
52 }
53
extractTracks()54 void ExtractorFuzzerBase::extractTracks() {
55 MediaBufferGroup* bufferGroup = new MediaBufferGroup();
56 if (!bufferGroup) {
57 return;
58 }
59 size_t trackCount = mExtractor->countTracks();
60 for (size_t trackIndex = 0; trackIndex < trackCount; ++trackIndex) {
61 MediaTrackHelper* track = mExtractor->getTrack(trackIndex);
62 if (!track) {
63 continue;
64 }
65 extractTrack(track, bufferGroup);
66 delete track;
67 }
68 delete bufferGroup;
69 }
70
extractTrack(MediaTrackHelper * track,MediaBufferGroup * bufferGroup)71 void ExtractorFuzzerBase::extractTrack(MediaTrackHelper* track, MediaBufferGroup* bufferGroup) {
72 CMediaTrack* cTrack = wrap(track);
73 if (!cTrack) {
74 return;
75 }
76
77 media_status_t status = cTrack->start(track, bufferGroup->wrap());
78 if (status != AMEDIA_OK) {
79 free(cTrack);
80 return;
81 }
82
83 do {
84 MediaBufferHelper* buffer = nullptr;
85 status = track->read(&buffer);
86 if (buffer) {
87 buffer->release();
88 }
89 } while (status == AMEDIA_OK);
90
91 cTrack->stop(track);
92 free(cTrack);
93 }
94
getTracksMetadata()95 void ExtractorFuzzerBase::getTracksMetadata() {
96 AMediaFormat* format = AMediaFormat_new();
97 uint32_t flags = MediaExtractorPluginHelper::kIncludeExtensiveMetaData;
98
99 size_t trackCount = mExtractor->countTracks();
100 for (size_t trackIndex = 0; trackIndex < trackCount; ++trackIndex) {
101 mExtractor->getTrackMetaData(format, trackIndex, flags);
102 }
103
104 AMediaFormat_delete(format);
105 }
106
getMetadata()107 void ExtractorFuzzerBase::getMetadata() {
108 AMediaFormat* format = AMediaFormat_new();
109 mExtractor->getMetaData(format);
110 AMediaFormat_delete(format);
111 }
112
setDataSourceFlags(uint32_t flags)113 void ExtractorFuzzerBase::setDataSourceFlags(uint32_t flags) {
114 mBufferSource->setFlags(flags);
115 }
116
seekAndExtractTracks()117 void ExtractorFuzzerBase::seekAndExtractTracks() {
118 MediaBufferGroup* bufferGroup = new MediaBufferGroup();
119 if (!bufferGroup) {
120 return;
121 }
122 size_t trackCount = mExtractor->countTracks();
123 for (size_t trackIndex = 0; trackIndex < trackCount; ++trackIndex) {
124 MediaTrackHelper* track = mExtractor->getTrack(trackIndex);
125 if (!track) {
126 continue;
127 }
128
129 AMediaFormat* trackMetaData = AMediaFormat_new();
130 int64_t trackDuration = 0;
131 uint32_t flags = MediaExtractorPluginHelper::kIncludeExtensiveMetaData;
132 mExtractor->getTrackMetaData(trackMetaData, trackIndex, flags);
133 AMediaFormat_getInt64(trackMetaData, AMEDIAFORMAT_KEY_DURATION, &trackDuration);
134
135 seekAndExtractTrack(track, bufferGroup, trackDuration);
136 AMediaFormat_delete(trackMetaData);
137 delete track;
138 }
139 delete bufferGroup;
140 }
141
seekAndExtractTrack(MediaTrackHelper * track,MediaBufferGroup * bufferGroup,int64_t trackDuration)142 void ExtractorFuzzerBase::seekAndExtractTrack(MediaTrackHelper* track,
143 MediaBufferGroup* bufferGroup,
144 int64_t trackDuration) {
145 CMediaTrack* cTrack = wrap(track);
146 if (!cTrack) {
147 return;
148 }
149
150 media_status_t status = cTrack->start(track, bufferGroup->wrap());
151 if (status != AMEDIA_OK) {
152 free(cTrack);
153 return;
154 }
155
156 int32_t seekCount = 0;
157 std::vector<int64_t> seekToTimeStamp;
158 while (seekCount <= kFuzzerMaxSeekPointsCount) {
159 /* This ensures kFuzzerMaxSeekPointsCount seek points are within the clipDuration and 1 seek
160 * point is outside of the clipDuration.
161 */
162 int64_t timeStamp = (seekCount * trackDuration) / (kFuzzerMaxSeekPointsCount - 1);
163 seekToTimeStamp.push_back(timeStamp);
164 seekCount++;
165 }
166
167 std::vector<uint32_t> seekOptions;
168 seekOptions.push_back(CMediaTrackReadOptions::SEEK | CMediaTrackReadOptions::SEEK_CLOSEST);
169 seekOptions.push_back(CMediaTrackReadOptions::SEEK | CMediaTrackReadOptions::SEEK_CLOSEST_SYNC);
170 seekOptions.push_back(CMediaTrackReadOptions::SEEK | CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC);
171 seekOptions.push_back(CMediaTrackReadOptions::SEEK | CMediaTrackReadOptions::SEEK_NEXT_SYNC);
172 seekOptions.push_back(CMediaTrackReadOptions::SEEK | CMediaTrackReadOptions::SEEK_FRAME_INDEX);
173
174 for (uint32_t seekOption : seekOptions) {
175 for (int64_t seekPts : seekToTimeStamp) {
176 MediaTrackHelper::ReadOptions* options =
177 new MediaTrackHelper::ReadOptions(seekOption, seekPts);
178 MediaBufferHelper* buffer = nullptr;
179 track->read(&buffer, options);
180 if (buffer) {
181 buffer->release();
182 }
183 delete options;
184 }
185 }
186
187 cTrack->stop(track);
188 free(cTrack);
189 }
190
processData(const uint8_t * data,size_t size)191 void ExtractorFuzzerBase::processData(const uint8_t* data, size_t size) {
192 if (setDataSource(data, size)) {
193 if (createExtractor()) {
194 getExtractorDef();
195 getMetadata();
196 extractTracks();
197 getTracksMetadata();
198 seekAndExtractTracks();
199 }
200 }
201 }
202