• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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