Home | History | Annotate | Download | only in libstagefright
      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/DRMExtractor.h"
     31 #include "include/WVMExtractor.h"
     32 #include "include/FLACExtractor.h"
     33 #include "include/AACExtractor.h"
     34 #include "include/MidiExtractor.h"
     35 
     36 #include "matroska/MatroskaExtractor.h"
     37 
     38 #include <binder/IServiceManager.h>
     39 #include <binder/MemoryDealer.h>
     40 
     41 #include <media/stagefright/foundation/ADebug.h>
     42 #include <media/stagefright/foundation/AMessage.h>
     43 #include <media/stagefright/DataSource.h>
     44 #include <media/stagefright/MediaDefs.h>
     45 #include <media/stagefright/MediaExtractor.h>
     46 #include <media/stagefright/MetaData.h>
     47 #include <media/IMediaExtractorService.h>
     48 #include <cutils/properties.h>
     49 #include <utils/String8.h>
     50 #include <private/android_filesystem_config.h>
     51 
     52 
     53 namespace android {
     54 
     55 MediaExtractor::MediaExtractor():
     56     mIsDrm(false) {
     57     if (!LOG_NDEBUG) {
     58         uid_t uid = getuid();
     59         struct passwd *pw = getpwuid(uid);
     60         ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
     61     }
     62 
     63 }
     64 
     65 
     66 sp<MetaData> MediaExtractor::getMetaData() {
     67     return new MetaData;
     68 }
     69 
     70 uint32_t MediaExtractor::flags() const {
     71     return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
     72 }
     73 
     74 
     75 
     76 class RemoteDataSource : public BnDataSource {
     77 public:
     78     enum {
     79         kBufferSize = 64 * 1024,
     80     };
     81 
     82     static sp<IDataSource> wrap(const sp<DataSource> &source);
     83     virtual ~RemoteDataSource();
     84 
     85     virtual sp<IMemory> getIMemory();
     86     virtual ssize_t readAt(off64_t offset, size_t size);
     87     virtual status_t getSize(off64_t* size);
     88     virtual void close();
     89     virtual uint32_t getFlags();
     90     virtual String8 toString();
     91     virtual sp<DecryptHandle> DrmInitialization(const char *mime);
     92 
     93 private:
     94     sp<IMemory> mMemory;
     95     sp<DataSource> mSource;
     96     String8 mName;
     97     RemoteDataSource(const sp<DataSource> &source);
     98     DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
     99 };
    100 
    101 
    102 sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
    103     return new RemoteDataSource(source);
    104 }
    105 RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) {
    106     mSource = source;
    107     sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
    108     mMemory = memoryDealer->allocate(kBufferSize);
    109     if (mMemory == NULL) {
    110         ALOGE("Failed to allocate memory!");
    111     }
    112     mName = String8::format("RemoteDataSource(%s)", mSource->toString().string());
    113 }
    114 RemoteDataSource::~RemoteDataSource() {
    115     close();
    116 }
    117 sp<IMemory> RemoteDataSource::getIMemory() {
    118     return mMemory;
    119 }
    120 ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) {
    121     ALOGV("readAt(%" PRId64 ", %zu)", offset, size);
    122     return mSource->readAt(offset, mMemory->pointer(), size);
    123 }
    124 status_t RemoteDataSource::getSize(off64_t* size) {
    125     return mSource->getSize(size);
    126 }
    127 void RemoteDataSource::close() {
    128     mSource = NULL;
    129 }
    130 uint32_t RemoteDataSource::getFlags() {
    131     return mSource->flags();
    132 }
    133 
    134 String8 RemoteDataSource::toString() {
    135     return mName;
    136 }
    137 
    138 sp<DecryptHandle> RemoteDataSource::DrmInitialization(const char *mime) {
    139     return mSource->DrmInitialization(mime);
    140 }
    141 
    142 // static
    143 sp<IMediaExtractor> MediaExtractor::Create(
    144         const sp<DataSource> &source, const char *mime) {
    145     ALOGV("MediaExtractor::Create %s", mime);
    146 
    147     char value[PROPERTY_VALUE_MAX];
    148     if (property_get("media.stagefright.extractremote", value, NULL)
    149             && (!strcmp("0", value) || !strcasecmp("false", value))) {
    150         // local extractor
    151         ALOGW("creating media extractor in calling process");
    152         return CreateFromService(source, mime);
    153     } else {
    154         // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
    155         // not the extractor process.
    156         String8 mime8;
    157         float confidence;
    158         sp<AMessage> meta;
    159         if (SniffWVM(source, &mime8, &confidence, &meta) &&
    160                 !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
    161             return new WVMExtractor(source);
    162         }
    163 
    164         // Check if it's es-based DRM, since DRMExtractor needs to be created in the media server
    165         // process, not the extractor process.
    166         if (SniffDRM(source, &mime8, &confidence, &meta)) {
    167             const char *drmMime = mime8.string();
    168             ALOGV("Detected media content as '%s' with confidence %.2f", drmMime, confidence);
    169             if (!strncmp(drmMime, "drm+es_based+", 13)) {
    170                 // DRMExtractor sets container metadata kKeyIsDRM to 1
    171                 return new DRMExtractor(source, drmMime + 14);
    172             }
    173         }
    174 
    175         // remote extractor
    176         ALOGV("get service manager");
    177         sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
    178 
    179         if (binder != 0) {
    180             sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
    181             sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
    182             return ex;
    183         } else {
    184             ALOGE("extractor service not running");
    185             return NULL;
    186         }
    187     }
    188     return NULL;
    189 }
    190 
    191 sp<MediaExtractor> MediaExtractor::CreateFromService(
    192         const sp<DataSource> &source, const char *mime) {
    193 
    194     ALOGV("MediaExtractor::CreateFromService %s", mime);
    195     DataSource::RegisterDefaultSniffers();
    196 
    197     sp<AMessage> meta;
    198 
    199     String8 tmp;
    200     if (mime == NULL) {
    201         float confidence;
    202         if (!source->sniff(&tmp, &confidence, &meta)) {
    203             ALOGV("FAILED to autodetect media content.");
    204 
    205             return NULL;
    206         }
    207 
    208         mime = tmp.string();
    209         ALOGV("Autodetected media content as '%s' with confidence %.2f",
    210              mime, confidence);
    211     }
    212 
    213     bool isDrm = false;
    214     // DRM MIME type syntax is "drm+type+original" where
    215     // type is "es_based" or "container_based" and
    216     // original is the content's cleartext MIME type
    217     if (!strncmp(mime, "drm+", 4)) {
    218         const char *originalMime = strchr(mime+4, '+');
    219         if (originalMime == NULL) {
    220             // second + not found
    221             return NULL;
    222         }
    223         ++originalMime;
    224         if (!strncmp(mime, "drm+es_based+", 13)) {
    225             // DRMExtractor sets container metadata kKeyIsDRM to 1
    226             return new DRMExtractor(source, originalMime);
    227         } else if (!strncmp(mime, "drm+container_based+", 20)) {
    228             mime = originalMime;
    229             isDrm = true;
    230         } else {
    231             return NULL;
    232         }
    233     }
    234 
    235     MediaExtractor *ret = NULL;
    236     if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
    237             || !strcasecmp(mime, "audio/mp4")) {
    238         ret = new MPEG4Extractor(source);
    239     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
    240         ret = new MP3Extractor(source, meta);
    241     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
    242             || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
    243         ret = new AMRExtractor(source);
    244     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
    245         ret = new FLACExtractor(source);
    246     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
    247         ret = new WAVExtractor(source);
    248     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
    249         ret = new OggExtractor(source);
    250     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
    251         ret = new MatroskaExtractor(source);
    252     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
    253         ret = new MPEG2TSExtractor(source);
    254     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
    255         // Return now.  WVExtractor should not have the DrmFlag set in the block below.
    256         return new WVMExtractor(source);
    257     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
    258         ret = new AACExtractor(source, meta);
    259     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
    260         ret = new MPEG2PSExtractor(source);
    261     } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MIDI)) {
    262         ret = new MidiExtractor(source);
    263     }
    264 
    265     if (ret != NULL) {
    266        if (isDrm) {
    267            ret->setDrmFlag(true);
    268        } else {
    269            ret->setDrmFlag(false);
    270        }
    271     }
    272 
    273     return ret;
    274 }
    275 
    276 }  // namespace android
    277