MediaExtractor.cpp revision afb43f76821e6a63e17e6484289a40430ada6978
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
55namespace android {
56
57// key for media statistics
58static const char *kKeyExtractor = "extractor";
59// attrs for media statistics
60static const char *kExtractorMime = "android.media.mediaextractor.mime";
61static const char *kExtractorTracks = "android.media.mediaextractor.ntrk";
62static const char *kExtractorFormat = "android.media.mediaextractor.fmt";
63
64MediaExtractor::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
78MediaExtractor::~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
95sp<MetaData> MediaExtractor::getMetaData() {
96    return new MetaData;
97}
98
99status_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
111void MediaExtractor::populateMetrics() {
112    ALOGV("MediaExtractor::populateMetrics");
113    // normally overridden in subclasses
114}
115
116uint32_t MediaExtractor::flags() const {
117    return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
118}
119
120
121
122class RemoteDataSource : public BnDataSource {
123public:
124    enum {
125        kBufferSize = 64 * 1024,
126    };
127
128    static sp<IDataSource> wrap(const sp<DataSource> &source);
129    virtual ~RemoteDataSource();
130
131    virtual sp<IMemory> getIMemory();
132    virtual ssize_t readAt(off64_t offset, size_t size);
133    virtual status_t getSize(off64_t* size);
134    virtual void close();
135    virtual uint32_t getFlags();
136    virtual String8 toString();
137    virtual sp<DecryptHandle> DrmInitialization(const char *mime);
138
139private:
140    sp<IMemory> mMemory;
141    sp<DataSource> mSource;
142    String8 mName;
143    explicit RemoteDataSource(const sp<DataSource> &source);
144    DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
145};
146
147
148sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
149    return new RemoteDataSource(source);
150}
151RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) {
152    mSource = source;
153    sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
154    mMemory = memoryDealer->allocate(kBufferSize);
155    if (mMemory == NULL) {
156        ALOGE("Failed to allocate memory!");
157    }
158    mName = String8::format("RemoteDataSource(%s)", mSource->toString().string());
159}
160RemoteDataSource::~RemoteDataSource() {
161    close();
162}
163sp<IMemory> RemoteDataSource::getIMemory() {
164    return mMemory;
165}
166ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) {
167    ALOGV("readAt(%" PRId64 ", %zu)", offset, size);
168    return mSource->readAt(offset, mMemory->pointer(), size);
169}
170status_t RemoteDataSource::getSize(off64_t* size) {
171    return mSource->getSize(size);
172}
173void RemoteDataSource::close() {
174    mSource = NULL;
175}
176uint32_t RemoteDataSource::getFlags() {
177    return mSource->flags();
178}
179
180String8 RemoteDataSource::toString() {
181    return mName;
182}
183
184sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) {
185    return mSource->DrmInitialization(mime);
186}
187
188// static
189sp<IMediaExtractor> MediaExtractor::Create(
190        const sp<DataSource> &source, const char *mime) {
191    ALOGV("MediaExtractor::Create %s", mime);
192
193    if (!property_get_bool("media.stagefright.extractremote", true)) {
194        // local extractor
195        ALOGW("creating media extractor in calling process");
196        return CreateFromService(source, mime);
197    } else {
198        // remote extractor
199        ALOGV("get service manager");
200        sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
201
202        if (binder != 0) {
203            sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
204            sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
205            return ex;
206        } else {
207            ALOGE("extractor service not running");
208            return NULL;
209        }
210    }
211    return NULL;
212}
213
214sp<MediaExtractor> MediaExtractor::CreateFromService(
215        const sp<DataSource> &source, const char *mime) {
216
217    ALOGV("MediaExtractor::CreateFromService %s", mime);
218    RegisterDefaultSniffers();
219
220    // initialize source decryption if needed
221    source->DrmInitialization();
222
223    sp<AMessage> meta;
224
225    String8 tmp;
226    if (mime == NULL) {
227        float confidence;
228        if (!sniff(source, &tmp, &confidence, &meta)) {
229            ALOGV("FAILED to autodetect media content.");
230
231            return NULL;
232        }
233
234        mime = tmp.string();
235        ALOGV("Autodetected media content as '%s' with confidence %.2f",
236             mime, confidence);
237    }
238
239    MediaExtractor *ret = NULL;
240    if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
241            || !strcasecmp(mime, "audio/mp4")) {
242        ret = new MPEG4Extractor(source);
243    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
244        ret = new MP3Extractor(source, meta);
245    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
246            || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
247        ret = new AMRExtractor(source);
248    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
249        ret = new FLACExtractor(source);
250    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
251        ret = new WAVExtractor(source);
252    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
253        ret = new OggExtractor(source);
254    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
255        ret = new MatroskaExtractor(source);
256    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
257        ret = new MPEG2TSExtractor(source);
258    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
259        ret = new AACExtractor(source, meta);
260    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
261        ret = new MPEG2PSExtractor(source);
262    } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
263        ret = new MidiExtractor(source);
264    }
265
266    if (ret != NULL) {
267       // track the container format (mpeg, aac, wvm, etc)
268       if (MEDIA_LOG) {
269          if (ret->mAnalyticsItem != NULL) {
270              size_t ntracks = ret->countTracks();
271              ret->mAnalyticsItem->setCString(kExtractorFormat,  ret->name());
272              // tracks (size_t)
273              ret->mAnalyticsItem->setInt32(kExtractorTracks,  ntracks);
274              // metadata
275              sp<MetaData> pMetaData = ret->getMetaData();
276              if (pMetaData != NULL) {
277                String8 xx = pMetaData->toString();
278                // 'titl' -- but this verges into PII
279                // 'mime'
280                const char *mime = NULL;
281                if (pMetaData->findCString(kKeyMIMEType, &mime)) {
282                    ret->mAnalyticsItem->setCString(kExtractorMime,  mime);
283                }
284                // what else is interesting and not already available?
285              }
286	  }
287       }
288    }
289
290    return ret;
291}
292
293Mutex MediaExtractor::gSnifferMutex;
294List<MediaExtractor::SnifferFunc> MediaExtractor::gSniffers;
295bool MediaExtractor::gSniffersRegistered = false;
296
297// static
298bool MediaExtractor::sniff(
299        const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) {
300    *mimeType = "";
301    *confidence = 0.0f;
302    meta->clear();
303
304    {
305        Mutex::Autolock autoLock(gSnifferMutex);
306        if (!gSniffersRegistered) {
307            return false;
308        }
309    }
310
311    for (List<SnifferFunc>::iterator it = gSniffers.begin();
312         it != gSniffers.end(); ++it) {
313        String8 newMimeType;
314        float newConfidence;
315        sp<AMessage> newMeta;
316        if ((*it)(source, &newMimeType, &newConfidence, &newMeta)) {
317            if (newConfidence > *confidence) {
318                *mimeType = newMimeType;
319                *confidence = newConfidence;
320                *meta = newMeta;
321            }
322        }
323    }
324
325    return *confidence > 0.0;
326}
327
328// static
329void MediaExtractor::RegisterSniffer_l(SnifferFunc func) {
330    for (List<SnifferFunc>::iterator it = gSniffers.begin();
331         it != gSniffers.end(); ++it) {
332        if (*it == func) {
333            return;
334        }
335    }
336
337    gSniffers.push_back(func);
338}
339
340// static
341void MediaExtractor::RegisterDefaultSniffers() {
342    Mutex::Autolock autoLock(gSnifferMutex);
343    if (gSniffersRegistered) {
344        return;
345    }
346
347    RegisterSniffer_l(SniffMPEG4);
348    RegisterSniffer_l(SniffMatroska);
349    RegisterSniffer_l(SniffOgg);
350    RegisterSniffer_l(SniffWAV);
351    RegisterSniffer_l(SniffFLAC);
352    RegisterSniffer_l(SniffAMR);
353    RegisterSniffer_l(SniffMPEG2TS);
354    RegisterSniffer_l(SniffMP3);
355    RegisterSniffer_l(SniffAAC);
356    RegisterSniffer_l(SniffMPEG2PS);
357    RegisterSniffer_l(SniffMidi);
358
359    gSniffersRegistered = true;
360}
361
362
363}  // namespace android
364