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 <media/IMediaExtractor.h>
     27 #include <media/stagefright/MetaData.h>
     28 
     29 namespace android {
     30 
     31 enum {
     32     COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
     33     GETTRACK,
     34     GETTRACKMETADATA,
     35     GETMETADATA,
     36     FLAGS,
     37     SETDRMFLAG,
     38     GETDRMFLAG,
     39     GETDRMTRACKINFO,
     40     SETUID,
     41     NAME
     42 };
     43 
     44 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
     45 public:
     46     BpMediaExtractor(const sp<IBinder>& impl)
     47         : BpInterface<IMediaExtractor>(impl)
     48     {
     49     }
     50 
     51     virtual size_t countTracks() {
     52         ALOGV("countTracks");
     53         Parcel data, reply;
     54         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     55         status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
     56         size_t numTracks = 0;
     57         if (ret == NO_ERROR) {
     58             numTracks = reply.readUint32();
     59         }
     60         return numTracks;
     61     }
     62     virtual sp<IMediaSource> getTrack(size_t index) {
     63         ALOGV("getTrack(%zu)", index);
     64         Parcel data, reply;
     65         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     66         data.writeUint32(index);
     67         status_t ret = remote()->transact(GETTRACK, data, &reply);
     68         if (ret == NO_ERROR) {
     69             return interface_cast<IMediaSource>(reply.readStrongBinder());
     70         }
     71         return NULL;
     72     }
     73 
     74     virtual sp<MetaData> getTrackMetaData(
     75             size_t index, uint32_t flags) {
     76         ALOGV("getTrackMetaData(%zu, %u)", index, flags);
     77         Parcel data, reply;
     78         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     79         data.writeUint32(index);
     80         data.writeUint32(flags);
     81         status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
     82         if (ret == NO_ERROR) {
     83             return MetaData::createFromParcel(reply);
     84         }
     85         return NULL;
     86     }
     87 
     88     virtual sp<MetaData> getMetaData() {
     89         ALOGV("getMetaData");
     90         Parcel data, reply;
     91         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     92         status_t ret = remote()->transact(GETMETADATA, data, &reply);
     93         if (ret == NO_ERROR) {
     94             return MetaData::createFromParcel(reply);
     95         }
     96         return NULL;
     97     }
     98 
     99     virtual uint32_t flags() const {
    100         ALOGV("flags NOT IMPLEMENTED");
    101         return 0;
    102     }
    103 
    104     virtual void setDrmFlag(bool flag __unused) {
    105         ALOGV("setDrmFlag NOT IMPLEMENTED");
    106     }
    107     virtual bool getDrmFlag() {
    108         ALOGV("getDrmFlag NOT IMPLEMENTED");
    109        return false;
    110     }
    111     virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
    112         ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
    113         return NULL;
    114     }
    115     virtual void setUID(uid_t uid __unused) {
    116         ALOGV("setUID NOT IMPLEMENTED");
    117     }
    118 
    119     virtual const char * name() {
    120         ALOGV("name NOT IMPLEMENTED");
    121         return NULL;
    122     }
    123 };
    124 
    125 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
    126 
    127 #undef LOG_TAG
    128 #define LOG_TAG "BnMediaExtractor"
    129 
    130 status_t BnMediaExtractor::onTransact(
    131     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    132 {
    133     switch (code) {
    134         case COUNTTRACKS: {
    135             ALOGV("countTracks");
    136             CHECK_INTERFACE(IMediaExtractor, data, reply);
    137             size_t numTracks = countTracks();
    138             if (numTracks > INT32_MAX) {
    139                 numTracks = 0;
    140             }
    141             reply->writeUint32(uint32_t(numTracks));
    142             return NO_ERROR;
    143         }
    144         case GETTRACK: {
    145             ALOGV("getTrack()");
    146             CHECK_INTERFACE(IMediaExtractor, data, reply);
    147             uint32_t idx;
    148             if (data.readUint32(&idx) == NO_ERROR) {
    149                 const sp<IMediaSource> track = getTrack(size_t(idx));
    150                 registerMediaSource(this, track);
    151                 return reply->writeStrongBinder(IInterface::asBinder(track));
    152             }
    153             return UNKNOWN_ERROR;
    154         }
    155         case GETTRACKMETADATA: {
    156             ALOGV("getTrackMetaData");
    157             CHECK_INTERFACE(IMediaExtractor, data, reply);
    158             uint32_t idx;
    159             uint32_t flags;
    160             if (data.readUint32(&idx) == NO_ERROR &&
    161                     data.readUint32(&flags) == NO_ERROR) {
    162                 sp<MetaData> meta = getTrackMetaData(idx, flags);
    163                 meta->writeToParcel(*reply);
    164                 return NO_ERROR;
    165             }
    166             return UNKNOWN_ERROR;
    167         }
    168         case GETMETADATA: {
    169             ALOGV("getMetaData");
    170             CHECK_INTERFACE(IMediaExtractor, data, reply);
    171             sp<MetaData> meta = getMetaData();
    172             if (meta != NULL) {
    173                 meta->writeToParcel(*reply);
    174                 return NO_ERROR;
    175             }
    176             return UNKNOWN_ERROR;
    177         }
    178         default:
    179             return BBinder::onTransact(code, data, reply, flags);
    180     }
    181 }
    182 
    183 typedef struct {
    184     String8 mime;
    185     String8 name;
    186     String8 sourceDescription;
    187     pid_t owner;
    188     wp<IMediaExtractor> extractor;
    189     Vector<wp<IMediaSource>> tracks;
    190     Vector<String8> trackDescriptions;
    191     String8 toString() const;
    192 } ExtractorInstance;
    193 
    194 String8 ExtractorInstance::toString() const {
    195     String8 str = name;
    196     str.append(" for mime ");
    197     str.append(mime);
    198     str.append(", source ");
    199     str.append(sourceDescription);
    200     str.append(String8::format(", pid %d: ", owner));
    201     if (extractor.promote() == NULL) {
    202         str.append("deleted\n");
    203     } else {
    204         str.append("active\n");
    205     }
    206     for (size_t i = 0; i < tracks.size(); i++) {
    207         const String8 desc = trackDescriptions.itemAt(i);
    208         str.appendFormat("    track {%s} ", desc.string());
    209         const sp<IMediaSource> source = tracks.itemAt(i).promote();
    210         if (source == NULL) {
    211             str.append(": deleted\n");
    212         } else {
    213             str.appendFormat(": active\n");
    214         }
    215     }
    216     return str;
    217 }
    218 
    219 static Vector<ExtractorInstance> sExtractors;
    220 static Mutex sExtractorsLock;
    221 
    222 void registerMediaSource(
    223         const sp<IMediaExtractor> &ex,
    224         const sp<IMediaSource> &source) {
    225     Mutex::Autolock lock(sExtractorsLock);
    226     for (size_t i = 0; i < sExtractors.size(); i++) {
    227         ExtractorInstance &instance = sExtractors.editItemAt(i);
    228         sp<IMediaExtractor> extractor = instance.extractor.promote();
    229         if (extractor != NULL && extractor == ex) {
    230             if (instance.tracks.size() > 5) {
    231                 instance.tracks.resize(5);
    232             }
    233             instance.tracks.push_front(source);
    234             instance.trackDescriptions.add(source->getFormat()->toString());
    235             break;
    236         }
    237     }
    238 }
    239 
    240 void registerMediaExtractor(
    241         const sp<IMediaExtractor> &extractor,
    242         const sp<DataSource> &source,
    243         const char *mime) {
    244     ExtractorInstance ex;
    245     ex.mime = mime == NULL ? "NULL" : mime;
    246     ex.name = extractor->name();
    247     ex.sourceDescription = source->toString();
    248     ex.owner = IPCThreadState::self()->getCallingPid();
    249     ex.extractor = extractor;
    250 
    251     {
    252         Mutex::Autolock lock(sExtractorsLock);
    253         if (sExtractors.size() > 10) {
    254             sExtractors.resize(10);
    255         }
    256         sExtractors.push_front(ex);
    257     }
    258 }
    259 
    260 status_t dumpExtractors(int fd, const Vector<String16>&) {
    261     String8 out;
    262     out.append("Recent extractors, most recent first:\n");
    263     {
    264         Mutex::Autolock lock(sExtractorsLock);
    265         for (size_t i = 0; i < sExtractors.size(); i++) {
    266             const ExtractorInstance &instance = sExtractors.itemAt(i);
    267             out.append("  ");
    268             out.append(instance.toString());
    269         }
    270     }
    271     write(fd, out.string(), out.size());
    272     return OK;
    273 }
    274 
    275 
    276 }  // namespace android
    277 
    278