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