1 /*
2 * Copyright (C) 2009 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 "MediaExtractor"
19 #include <utils/Log.h>
20 #include <inttypes.h>
21 #include <pwd.h>
22
23 #include "include/AMRExtractor.h"
24 #include "include/MP3Extractor.h"
25 #include "include/MPEG4Extractor.h"
26 #include "include/WAVExtractor.h"
27 #include "include/OggExtractor.h"
28 #include "include/MPEG2PSExtractor.h"
29 #include "include/MPEG2TSExtractor.h"
30 #include "include/FLACExtractor.h"
31 #include "include/AACExtractor.h"
32 #include "include/MidiExtractor.h"
33
34 #include "matroska/MatroskaExtractor.h"
35
36 #include <binder/IServiceManager.h>
37 #include <binder/MemoryDealer.h>
38
39 #include <media/MediaAnalyticsItem.h>
40 #include <media/stagefright/foundation/ADebug.h>
41 #include <media/stagefright/foundation/AMessage.h>
42 #include <media/stagefright/DataSource.h>
43 #include <media/stagefright/MediaDefs.h>
44 #include <media/stagefright/MediaExtractor.h>
45 #include <media/stagefright/MetaData.h>
46 #include <media/IMediaExtractorService.h>
47 #include <cutils/properties.h>
48 #include <utils/String8.h>
49 #include <private/android_filesystem_config.h>
50
51 // still doing some on/off toggling here.
52 #define MEDIA_LOG 1
53
54
55 namespace android {
56
57 // key for media statistics
58 static const char *kKeyExtractor = "extractor";
59 // attrs for media statistics
60 static const char *kExtractorMime = "android.media.mediaextractor.mime";
61 static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
62 static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
63
MediaExtractor()64 MediaExtractor::MediaExtractor() {
65 if (!LOG_NDEBUG) {
66 uid_t uid = getuid();
67 struct passwd *pw = getpwuid(uid);
68 ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
69 }
70
71 mAnalyticsItem = NULL;
72 if (MEDIA_LOG) {
73 mAnalyticsItem = new MediaAnalyticsItem(kKeyExtractor);
74 (void) mAnalyticsItem->generateSessionID();
75 }
76 }
77
~MediaExtractor()78 MediaExtractor::~MediaExtractor() {
79
80 // log the current record, provided it has some information worth recording
81 if (MEDIA_LOG) {
82 if (mAnalyticsItem != NULL) {
83 if (mAnalyticsItem->count() > 0) {
84 mAnalyticsItem->setFinalized(true);
85 mAnalyticsItem->selfrecord();
86 }
87 }
88 }
89 if (mAnalyticsItem != NULL) {
90 delete mAnalyticsItem;
91 mAnalyticsItem = NULL;
92 }
93 }
94
getMetaData()95 sp<MetaData> MediaExtractor::getMetaData() {
96 return new MetaData;
97 }
98
getMetrics(Parcel * reply)99 status_t MediaExtractor::getMetrics(Parcel *reply) {
100
101 if (mAnalyticsItem == NULL || reply == NULL) {
102 return UNKNOWN_ERROR;
103 }
104
105 populateMetrics();
106 mAnalyticsItem->writeToParcel(reply);
107
108 return OK;
109 }
110
populateMetrics()111 void MediaExtractor::populateMetrics() {
112 ALOGV("MediaExtractor::populateMetrics");
113 // normally overridden in subclasses
114 }
115
flags() const116 uint32_t MediaExtractor::flags() const {
117 return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
118 }
119
120 // static
Create(const sp<DataSource> & source,const char * mime)121 sp<IMediaExtractor> MediaExtractor::Create(
122 const sp<DataSource> &source, const char *mime) {
123 ALOGV("MediaExtractor::Create %s", mime);
124
125 if (!property_get_bool("media.stagefright.extractremote", true)) {
126 // local extractor
127 ALOGW("creating media extractor in calling process");
128 return CreateFromService(source, mime);
129 } else {
130 // remote extractor
131 ALOGV("get service manager");
132 sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
133
134 if (binder != 0) {
135 sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
136 sp<IMediaExtractor> ex = mediaExService->makeExtractor(source->asIDataSource(), mime);
137 return ex;
138 } else {
139 ALOGE("extractor service not running");
140 return NULL;
141 }
142 }
143 return NULL;
144 }
145
CreateFromService(const sp<DataSource> & source,const char * mime)146 sp<MediaExtractor> MediaExtractor::CreateFromService(
147 const sp<DataSource> &source, const char *mime) {
148
149 ALOGV("MediaExtractor::CreateFromService %s", mime);
150 RegisterDefaultSniffers();
151
152 // initialize source decryption if needed
153 source->DrmInitialization(nullptr /* mime */);
154
155 sp<AMessage> meta;
156
157 String8 tmp;
158 if (mime == NULL) {
159 float confidence;
160 if (!sniff(source, &tmp, &confidence, &meta)) {
161 ALOGW("FAILED to autodetect media content.");
162
163 return NULL;
164 }
165
166 mime = tmp.string();
167 ALOGV("Autodetected media content as '%s' with confidence %.2f",
168 mime, confidence);
169 }
170
171 MediaExtractor *ret = NULL;
172 if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
173 || !strcasecmp(mime, "audio/mp4")) {
174 ret = new MPEG4Extractor(source);
175 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
176 ret = new MP3Extractor(source, meta);
177 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
178 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
179 ret = new AMRExtractor(source);
180 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
181 ret = new FLACExtractor(source);
182 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
183 ret = new WAVExtractor(source);
184 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
185 ret = new OggExtractor(source);
186 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
187 ret = new MatroskaExtractor(source);
188 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
189 ret = new MPEG2TSExtractor(source);
190 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
191 ret = new AACExtractor(source, meta);
192 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
193 ret = new MPEG2PSExtractor(source);
194 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
195 ret = new MidiExtractor(source);
196 }
197
198 if (ret != NULL) {
199 // track the container format (mpeg, aac, wvm, etc)
200 if (MEDIA_LOG) {
201 if (ret->mAnalyticsItem != NULL) {
202 size_t ntracks = ret->countTracks();
203 ret->mAnalyticsItem->setCString(kExtractorFormat, ret->name());
204 // tracks (size_t)
205 ret->mAnalyticsItem->setInt32(kExtractorTracks, ntracks);
206 // metadata
207 sp<MetaData> pMetaData = ret->getMetaData();
208 if (pMetaData != NULL) {
209 String8 xx = pMetaData->toString();
210 // 'titl' -- but this verges into PII
211 // 'mime'
212 const char *mime = NULL;
213 if (pMetaData->findCString(kKeyMIMEType, &mime)) {
214 ret->mAnalyticsItem->setCString(kExtractorMime, mime);
215 }
216 // what else is interesting and not already available?
217 }
218 }
219 }
220 }
221
222 return ret;
223 }
224
225 Mutex MediaExtractor::gSnifferMutex;
226 List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers;
227 bool MediaExtractor::gSniffersRegistered = false;
228
229 // static
sniff(const sp<DataSource> & source,String8 * mimeType,float * confidence,sp<AMessage> * meta)230 bool MediaExtractor::sniff(
231 const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
232 *mimeType = "";
233 *confidence = 0.0f;
234 meta->clear();
235
236 {
237 Mutex::Autolock autoLock(gSnifferMutex);
238 if (!gSniffersRegistered) {
239 return false;
240 }
241 }
242
243 for (List<SnifferFunc>::iterator it = gSniffers.begin();
244 it != gSniffers.end(); ++it) {
245 String8 newMimeType;
246 float newConfidence;
247 sp<AMessage> newMeta;
248 if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
249 if (newConfidence > *confidence) {
250 *mimeType = newMimeType;
251 *confidence = newConfidence;
252 *meta = newMeta;
253 }
254 }
255 }
256
257 return *confidence > 0.0;
258 }
259
260 // static
RegisterSniffer_l(SnifferFunc func)261 void MediaExtractor::RegisterSniffer_l(SnifferFunc func) {
262 for (List<SnifferFunc>::iterator it = gSniffers.begin();
263 it != gSniffers.end(); ++it) {
264 if (*it == func) {
265 return;
266 }
267 }
268
269 gSniffers.push_back(func);
270 }
271
272 // static
RegisterDefaultSniffers()273 void MediaExtractor::RegisterDefaultSniffers() {
274 Mutex::Autolock autoLock(gSnifferMutex);
275 if (gSniffersRegistered) {
276 return;
277 }
278
279 RegisterSniffer_l(SniffMPEG4);
280 RegisterSniffer_l(SniffMatroska);
281 RegisterSniffer_l(SniffOgg);
282 RegisterSniffer_l(SniffWAV);
283 RegisterSniffer_l(SniffFLAC);
284 RegisterSniffer_l(SniffAMR);
285 RegisterSniffer_l(SniffMPEG2TS);
286 RegisterSniffer_l(SniffMP3);
287 RegisterSniffer_l(SniffAAC);
288 RegisterSniffer_l(SniffMPEG2PS);
289 RegisterSniffer_l(SniffMidi);
290
291 gSniffersRegistered = true;
292 }
293
294
295 } // namespace android
296