Home | History | Annotate | Download | only in libmedia
      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 "BpMediaExtractor"
     19 #include <utils/Log.h>
     20 
     21 #include <stdint.h>
     22 #include <sys/types.h>
     23 
     24 #include <binder/IPCThreadState.h>
     25 #include <binder/Parcel.h>
     26 #include <binder/PermissionCache.h>
     27 #include <media/IMediaExtractor.h>
     28 #include <media/stagefright/MetaData.h>
     29 
     30 namespace android {
     31 
     32 enum {
     33     COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
     34     GETTRACK,
     35     GETTRACKMETADATA,
     36     GETMETADATA,
     37     FLAGS,
     38     SETMEDIACAS,
     39     NAME,
     40     GETMETRICS
     41 };
     42 
     43 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
     44 public:
     45     explicit BpMediaExtractor(const sp<IBinder>& impl)
     46         : BpInterface<IMediaExtractor>(impl)
     47     {
     48     }
     49 
     50     virtual size_t countTracks() {
     51         ALOGV("countTracks");
     52         Parcel data, reply;
     53         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     54         status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
     55         size_t numTracks = 0;
     56         if (ret == NO_ERROR) {
     57             numTracks = reply.readUint32();
     58         }
     59         return numTracks;
     60     }
     61     virtual sp<IMediaSource> getTrack(size_t index) {
     62         ALOGV("getTrack(%zu)", index);
     63         Parcel data, reply;
     64         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     65         data.writeUint32(index);
     66         status_t ret = remote()->transact(GETTRACK, data, &reply);
     67         if (ret == NO_ERROR) {
     68             return interface_cast<IMediaSource>(reply.readStrongBinder());
     69         }
     70         return NULL;
     71     }
     72 
     73     virtual sp<MetaData> getTrackMetaData(
     74             size_t index, uint32_t flags) {
     75         ALOGV("getTrackMetaData(%zu, %u)", index, flags);
     76         Parcel data, reply;
     77         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     78         data.writeUint32(index);
     79         data.writeUint32(flags);
     80         status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
     81         if (ret == NO_ERROR) {
     82             return MetaData::createFromParcel(reply);
     83         }
     84         return NULL;
     85     }
     86 
     87     virtual sp<MetaData> getMetaData() {
     88         ALOGV("getMetaData");
     89         Parcel data, reply;
     90         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     91         status_t ret = remote()->transact(GETMETADATA, data, &reply);
     92         if (ret == NO_ERROR) {
     93             return MetaData::createFromParcel(reply);
     94         }
     95         return NULL;
     96     }
     97 
     98     virtual status_t getMetrics(Parcel * reply) {
     99         Parcel data;
    100         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
    101         status_t ret = remote()->transact(GETMETRICS, data, reply);
    102         if (ret == NO_ERROR) {
    103             return OK;
    104         }
    105         return UNKNOWN_ERROR;
    106     }
    107 
    108     virtual uint32_t flags() const {
    109         ALOGV("flags NOT IMPLEMENTED");
    110         return 0;
    111     }
    112 
    113     virtual status_t setMediaCas(const HInterfaceToken &casToken) {
    114         ALOGV("setMediaCas");
    115 
    116         Parcel data, reply;
    117         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
    118         data.writeByteVector(casToken);
    119 
    120         status_t err = remote()->transact(SETMEDIACAS, data, &reply);
    121         if (err != NO_ERROR) {
    122             return err;
    123         }
    124         return reply.readInt32();
    125     }
    126 
    127     virtual const char * name() {
    128         ALOGV("name NOT IMPLEMENTED");
    129         return NULL;
    130     }
    131 };
    132 
    133 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
    134 
    135 #undef LOG_TAG
    136 #define LOG_TAG "BnMediaExtractor"
    137 
    138 status_t BnMediaExtractor::onTransact(
    139     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    140 {
    141     switch (code) {
    142         case COUNTTRACKS: {
    143             ALOGV("countTracks");
    144             CHECK_INTERFACE(IMediaExtractor, data, reply);
    145             size_t numTracks = countTracks();
    146             if (numTracks > INT32_MAX) {
    147                 numTracks = 0;
    148             }
    149             reply->writeUint32(uint32_t(numTracks));
    150             return NO_ERROR;
    151         }
    152         case GETTRACK: {
    153             ALOGV("getTrack()");
    154             CHECK_INTERFACE(IMediaExtractor, data, reply);
    155             uint32_t idx;
    156             if (data.readUint32(&idx) == NO_ERROR) {
    157                 const sp<IMediaSource> track = getTrack(size_t(idx));
    158                 registerMediaSource(this, track);
    159                 return reply->writeStrongBinder(IInterface::asBinder(track));
    160             }
    161             return UNKNOWN_ERROR;
    162         }
    163         case GETTRACKMETADATA: {
    164             ALOGV("getTrackMetaData");
    165             CHECK_INTERFACE(IMediaExtractor, data, reply);
    166             uint32_t idx;
    167             uint32_t flags;
    168             if (data.readUint32(&idx) == NO_ERROR &&
    169                     data.readUint32(&flags) == NO_ERROR) {
    170                 sp<MetaData> meta = getTrackMetaData(idx, flags);
    171                 if (meta == NULL) {
    172                     return UNKNOWN_ERROR;
    173                 }
    174                 meta->writeToParcel(*reply);
    175                 return NO_ERROR;
    176             }
    177             return UNKNOWN_ERROR;
    178         }
    179         case GETMETADATA: {
    180             ALOGV("getMetaData");
    181             CHECK_INTERFACE(IMediaExtractor, data, reply);
    182             sp<MetaData> meta = getMetaData();
    183             if (meta != NULL) {
    184                 meta->writeToParcel(*reply);
    185                 return NO_ERROR;
    186             }
    187             return UNKNOWN_ERROR;
    188         }
    189         case GETMETRICS: {
    190             CHECK_INTERFACE(IMediaExtractor, data, reply);
    191             status_t ret = getMetrics(reply);
    192             return ret;
    193         }
    194         case SETMEDIACAS: {
    195             ALOGV("setMediaCas");
    196             CHECK_INTERFACE(IMediaExtractor, data, reply);
    197 
    198             HInterfaceToken casToken;
    199             status_t err = data.readByteVector(&casToken);
    200             if (err != NO_ERROR) {
    201                 ALOGE("Error reading casToken from parcel");
    202                 return err;
    203             }
    204 
    205             reply->writeInt32(setMediaCas(casToken));
    206             return OK;
    207         }
    208         default:
    209             return BBinder::onTransact(code, data, reply, flags);
    210     }
    211 }
    212 
    213 typedef struct {
    214     String8 mime;
    215     String8 name;
    216     String8 sourceDescription;
    217     pid_t owner;
    218     wp<IMediaExtractor> extractor;
    219     Vector<wp<IMediaSource>> tracks;
    220     Vector<String8> trackDescriptions;
    221     String8 toString() const;
    222 } ExtractorInstance;
    223 
    224 String8 ExtractorInstance::toString() const {
    225     String8 str = name;
    226     str.append(" for mime ");
    227     str.append(mime);
    228     str.append(", source ");
    229     str.append(sourceDescription);
    230     str.append(String8::format(", pid %d: ", owner));
    231     if (extractor.promote() == NULL) {
    232         str.append("deleted\n");
    233     } else {
    234         str.append("active\n");
    235     }
    236     for (size_t i = 0; i < tracks.size(); i++) {
    237         const String8 desc = trackDescriptions.itemAt(i);
    238         str.appendFormat("    track {%s} ", desc.string());
    239         wp<IMediaSource> wSource = tracks.itemAt(i);
    240         if (wSource == NULL) {
    241             str.append(": null\n");
    242         } else {
    243             const sp<IMediaSource> source = wSource.promote();
    244             if (source == NULL) {
    245                 str.append(": deleted\n");
    246             } else {
    247                 str.appendFormat(": active\n");
    248             }
    249         }
    250     }
    251     return str;
    252 }
    253 
    254 static Vector<ExtractorInstance> sExtractors;
    255 static Mutex sExtractorsLock;
    256 
    257 void registerMediaSource(
    258         const sp<IMediaExtractor> &ex,
    259         const sp<IMediaSource> &source) {
    260     Mutex::Autolock lock(sExtractorsLock);
    261     for (size_t i = 0; i < sExtractors.size(); i++) {
    262         ExtractorInstance &instance = sExtractors.editItemAt(i);
    263         sp<IMediaExtractor> extractor = instance.extractor.promote();
    264         if (extractor != NULL && extractor == ex) {
    265             if (instance.tracks.size() > 5) {
    266                 instance.tracks.resize(5);
    267                 instance.trackDescriptions.resize(5);
    268             }
    269             instance.tracks.push_front(source);
    270             if (source != NULL) {
    271                 instance.trackDescriptions.push_front(source->getFormat()->toString());
    272             } else {
    273                 instance.trackDescriptions.push_front(String8::empty());
    274             }
    275             break;
    276         }
    277     }
    278 }
    279 
    280 void registerMediaExtractor(
    281         const sp<IMediaExtractor> &extractor,
    282         const sp<DataSource> &source,
    283         const char *mime) {
    284     ExtractorInstance ex;
    285     ex.mime = mime == NULL ? "NULL" : mime;
    286     ex.name = extractor->name();
    287     ex.sourceDescription = source->toString();
    288     ex.owner = IPCThreadState::self()->getCallingPid();
    289     ex.extractor = extractor;
    290 
    291     {
    292         Mutex::Autolock lock(sExtractorsLock);
    293         if (sExtractors.size() > 10) {
    294             sExtractors.resize(10);
    295         }
    296         sExtractors.push_front(ex);
    297     }
    298 }
    299 
    300 status_t dumpExtractors(int fd, const Vector<String16>&) {
    301     String8 out;
    302     const IPCThreadState* ipc = IPCThreadState::self();
    303     const int pid = ipc->getCallingPid();
    304     const int uid = ipc->getCallingUid();
    305     if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
    306         out.appendFormat("Permission Denial: "
    307                 "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
    308     } else {
    309         out.append("Recent extractors, most recent first:\n");
    310         {
    311             Mutex::Autolock lock(sExtractorsLock);
    312             for (size_t i = 0; i < sExtractors.size(); i++) {
    313                 const ExtractorInstance &instance = sExtractors.itemAt(i);
    314                 out.append("  ");
    315                 out.append(instance.toString());
    316             }
    317         }
    318     }
    319     write(fd, out.string(), out.size());
    320     return OK;
    321 }
    322 
    323 
    324 }  // namespace android
    325 
    326