Home | History | Annotate | Download | only in libmediaplayerservice
      1 /*
      2 **
      3 ** Copyright (C) 2008 The Android Open Source Project
      4 **
      5 ** Licensed under the Apache License, Version 2.0 (the "License");
      6 ** you may not use this file except in compliance with the License.
      7 ** You may obtain a copy of the License at
      8 **
      9 **     http://www.apache.org/licenses/LICENSE-2.0
     10 **
     11 ** Unless required by applicable law or agreed to in writing, software
     12 ** distributed under the License is distributed on an "AS IS" BASIS,
     13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 ** See the License for the specific language governing permissions and
     15 ** limitations under the License.
     16 */
     17 
     18 //#define LOG_NDEBUG 0
     19 #define LOG_TAG "MetadataRetrieverClient"
     20 #include <utils/Log.h>
     21 
     22 #include <sys/types.h>
     23 #include <sys/stat.h>
     24 #include <dirent.h>
     25 #include <unistd.h>
     26 
     27 #include <string.h>
     28 #include <cutils/atomic.h>
     29 #include <cutils/properties.h>
     30 #include <binder/MemoryBase.h>
     31 #include <binder/MemoryHeapBase.h>
     32 #include <binder/IPCThreadState.h>
     33 #include <binder/IServiceManager.h>
     34 #include <media/IMediaHTTPService.h>
     35 #include <media/MediaMetadataRetrieverInterface.h>
     36 #include <media/MediaPlayerInterface.h>
     37 #include <private/media/VideoFrame.h>
     38 #include "MidiMetadataRetriever.h"
     39 #include "MetadataRetrieverClient.h"
     40 #include "StagefrightMetadataRetriever.h"
     41 #include "MediaPlayerFactory.h"
     42 
     43 namespace android {
     44 
     45 MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
     46 {
     47     ALOGV("MetadataRetrieverClient constructor pid(%d)", pid);
     48     mPid = pid;
     49     mThumbnail = NULL;
     50     mAlbumArt = NULL;
     51     mRetriever = NULL;
     52 }
     53 
     54 MetadataRetrieverClient::~MetadataRetrieverClient()
     55 {
     56     ALOGV("MetadataRetrieverClient destructor");
     57     disconnect();
     58 }
     59 
     60 status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& /*args*/) const
     61 {
     62     const size_t SIZE = 256;
     63     char buffer[SIZE];
     64     String8 result;
     65     result.append(" MetadataRetrieverClient\n");
     66     snprintf(buffer, 255, "  pid(%d)\n", mPid);
     67     result.append(buffer);
     68     write(fd, result.string(), result.size());
     69     write(fd, "\n", 1);
     70     return NO_ERROR;
     71 }
     72 
     73 void MetadataRetrieverClient::disconnect()
     74 {
     75     ALOGV("disconnect from pid %d", mPid);
     76     Mutex::Autolock lock(mLock);
     77     mRetriever.clear();
     78     mThumbnail.clear();
     79     mAlbumArt.clear();
     80     IPCThreadState::self()->flushCommands();
     81 }
     82 
     83 static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
     84 {
     85     sp<MediaMetadataRetrieverBase> p;
     86     switch (playerType) {
     87         case STAGEFRIGHT_PLAYER:
     88         case NU_PLAYER:
     89         {
     90             p = new StagefrightMetadataRetriever;
     91             break;
     92         }
     93         case SONIVOX_PLAYER:
     94             ALOGV("create midi metadata retriever");
     95             p = new MidiMetadataRetriever();
     96             break;
     97         default:
     98             // TODO:
     99             // support for TEST_PLAYER
    100             ALOGE("player type %d is not supported",  playerType);
    101             break;
    102     }
    103     if (p == NULL) {
    104         ALOGE("failed to create a retriever object");
    105     }
    106     return p;
    107 }
    108 
    109 status_t MetadataRetrieverClient::setDataSource(
    110         const sp<IMediaHTTPService> &httpService,
    111         const char *url,
    112         const KeyedVector<String8, String8> *headers)
    113 {
    114     ALOGV("setDataSource(%s)", url);
    115     Mutex::Autolock lock(mLock);
    116     if (url == NULL) {
    117         return UNKNOWN_ERROR;
    118     }
    119 
    120     // When asking the MediaPlayerFactory subsystem to choose a media player for
    121     // a given URL, a pointer to an outer IMediaPlayer can be passed to the
    122     // factory system to be taken into consideration along with the URL.  In the
    123     // case of choosing an instance of a MediaPlayerBase for a
    124     // MetadataRetrieverClient, there is no outer IMediaPlayer which will
    125     // eventually encapsulate the result of this selection.  In this case, just
    126     // pass NULL to getPlayerType to indicate that there is no outer
    127     // IMediaPlayer to consider during selection.
    128     player_type playerType =
    129         MediaPlayerFactory::getPlayerType(NULL /* client */, url);
    130     ALOGV("player type = %d", playerType);
    131     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    132     if (p == NULL) return NO_INIT;
    133     status_t ret = p->setDataSource(httpService, url, headers);
    134     if (ret == NO_ERROR) mRetriever = p;
    135     return ret;
    136 }
    137 
    138 status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
    139 {
    140     ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
    141     Mutex::Autolock lock(mLock);
    142     struct stat sb;
    143     int ret = fstat(fd, &sb);
    144     if (ret != 0) {
    145         ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
    146         return BAD_VALUE;
    147     }
    148     ALOGV("st_dev  = %llu", sb.st_dev);
    149     ALOGV("st_mode = %u", sb.st_mode);
    150     ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
    151     ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
    152     ALOGV("st_size = %llu", sb.st_size);
    153 
    154     if (offset >= sb.st_size) {
    155         ALOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
    156         ::close(fd);
    157         return BAD_VALUE;
    158     }
    159     if (offset + length > sb.st_size) {
    160         length = sb.st_size - offset;
    161         ALOGV("calculated length = %lld", length);
    162     }
    163 
    164     player_type playerType =
    165         MediaPlayerFactory::getPlayerType(NULL /* client */,
    166                                           fd,
    167                                           offset,
    168                                           length);
    169     ALOGV("player type = %d", playerType);
    170     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    171     if (p == NULL) {
    172         ::close(fd);
    173         return NO_INIT;
    174     }
    175     status_t status = p->setDataSource(fd, offset, length);
    176     if (status == NO_ERROR) mRetriever = p;
    177     ::close(fd);
    178     return status;
    179 }
    180 
    181 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
    182 {
    183     ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
    184     Mutex::Autolock lock(mLock);
    185     mThumbnail.clear();
    186     if (mRetriever == NULL) {
    187         ALOGE("retriever is not initialized");
    188         return NULL;
    189     }
    190     VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
    191     if (frame == NULL) {
    192         ALOGE("failed to capture a video frame");
    193         return NULL;
    194     }
    195     size_t size = sizeof(VideoFrame) + frame->mSize;
    196     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
    197     if (heap == NULL) {
    198         ALOGE("failed to create MemoryDealer");
    199         delete frame;
    200         return NULL;
    201     }
    202     mThumbnail = new MemoryBase(heap, 0, size);
    203     if (mThumbnail == NULL) {
    204         ALOGE("not enough memory for VideoFrame size=%u", size);
    205         delete frame;
    206         return NULL;
    207     }
    208     VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
    209     frameCopy->mWidth = frame->mWidth;
    210     frameCopy->mHeight = frame->mHeight;
    211     frameCopy->mDisplayWidth = frame->mDisplayWidth;
    212     frameCopy->mDisplayHeight = frame->mDisplayHeight;
    213     frameCopy->mSize = frame->mSize;
    214     frameCopy->mRotationAngle = frame->mRotationAngle;
    215     ALOGV("rotation: %d", frameCopy->mRotationAngle);
    216     frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
    217     memcpy(frameCopy->mData, frame->mData, frame->mSize);
    218     delete frame;  // Fix memory leakage
    219     return mThumbnail;
    220 }
    221 
    222 sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
    223 {
    224     ALOGV("extractAlbumArt");
    225     Mutex::Autolock lock(mLock);
    226     mAlbumArt.clear();
    227     if (mRetriever == NULL) {
    228         ALOGE("retriever is not initialized");
    229         return NULL;
    230     }
    231     MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
    232     if (albumArt == NULL) {
    233         ALOGE("failed to extract an album art");
    234         return NULL;
    235     }
    236     size_t size = sizeof(MediaAlbumArt) + albumArt->size();
    237     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
    238     if (heap == NULL) {
    239         ALOGE("failed to create MemoryDealer object");
    240         delete albumArt;
    241         return NULL;
    242     }
    243     mAlbumArt = new MemoryBase(heap, 0, size);
    244     if (mAlbumArt == NULL) {
    245         ALOGE("not enough memory for MediaAlbumArt size=%u", size);
    246         delete albumArt;
    247         return NULL;
    248     }
    249     MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->pointer(),
    250                         albumArt->size(), albumArt->data());
    251     delete albumArt;  // We've taken our copy.
    252     return mAlbumArt;
    253 }
    254 
    255 const char* MetadataRetrieverClient::extractMetadata(int keyCode)
    256 {
    257     ALOGV("extractMetadata");
    258     Mutex::Autolock lock(mLock);
    259     if (mRetriever == NULL) {
    260         ALOGE("retriever is not initialized");
    261         return NULL;
    262     }
    263     return mRetriever->extractMetadata(keyCode);
    264 }
    265 
    266 }; // namespace android
    267