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