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/MediaMetadataRetrieverInterface.h>
     35 #include <media/MediaPlayerInterface.h>
     36 #include <private/media/VideoFrame.h>
     37 #include "MidiMetadataRetriever.h"
     38 #include "MetadataRetrieverClient.h"
     39 #include "StagefrightMetadataRetriever.h"
     40 
     41 namespace android {
     42 
     43 extern player_type getPlayerType(const char* url);
     44 extern player_type getPlayerType(int fd, int64_t offset, int64_t length);
     45 
     46 MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
     47 {
     48     ALOGV("MetadataRetrieverClient constructor pid(%d)", pid);
     49     mPid = pid;
     50     mThumbnail = NULL;
     51     mAlbumArt = NULL;
     52     mRetriever = NULL;
     53 }
     54 
     55 MetadataRetrieverClient::~MetadataRetrieverClient()
     56 {
     57     ALOGV("MetadataRetrieverClient destructor");
     58     disconnect();
     59 }
     60 
     61 status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) const
     62 {
     63     const size_t SIZE = 256;
     64     char buffer[SIZE];
     65     String8 result;
     66     result.append(" MetadataRetrieverClient\n");
     67     snprintf(buffer, 255, "  pid(%d)\n", mPid);
     68     result.append(buffer);
     69     write(fd, result.string(), result.size());
     70     write(fd, "\n", 1);
     71     return NO_ERROR;
     72 }
     73 
     74 void MetadataRetrieverClient::disconnect()
     75 {
     76     ALOGV("disconnect from pid %d", mPid);
     77     Mutex::Autolock lock(mLock);
     78     mRetriever.clear();
     79     mThumbnail.clear();
     80     mAlbumArt.clear();
     81     IPCThreadState::self()->flushCommands();
     82 }
     83 
     84 static sp<MediaMetadataRetrieverBase> createRetriever(player_type playerType)
     85 {
     86     sp<MediaMetadataRetrieverBase> p;
     87     switch (playerType) {
     88         case STAGEFRIGHT_PLAYER:
     89         case NU_PLAYER:
     90         {
     91             p = new StagefrightMetadataRetriever;
     92             break;
     93         }
     94         case SONIVOX_PLAYER:
     95             ALOGV("create midi metadata retriever");
     96             p = new MidiMetadataRetriever();
     97             break;
     98         default:
     99             // TODO:
    100             // support for TEST_PLAYER
    101             ALOGE("player type %d is not supported",  playerType);
    102             break;
    103     }
    104     if (p == NULL) {
    105         ALOGE("failed to create a retriever object");
    106     }
    107     return p;
    108 }
    109 
    110 status_t MetadataRetrieverClient::setDataSource(
    111         const char *url, const KeyedVector<String8, String8> *headers)
    112 {
    113     ALOGV("setDataSource(%s)", url);
    114     Mutex::Autolock lock(mLock);
    115     if (url == NULL) {
    116         return UNKNOWN_ERROR;
    117     }
    118     player_type playerType = getPlayerType(url);
    119     ALOGV("player type = %d", playerType);
    120     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    121     if (p == NULL) return NO_INIT;
    122     status_t ret = p->setDataSource(url, headers);
    123     if (ret == NO_ERROR) mRetriever = p;
    124     return ret;
    125 }
    126 
    127 status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
    128 {
    129     ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
    130     Mutex::Autolock lock(mLock);
    131     struct stat sb;
    132     int ret = fstat(fd, &sb);
    133     if (ret != 0) {
    134         ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
    135         return BAD_VALUE;
    136     }
    137     ALOGV("st_dev  = %llu", sb.st_dev);
    138     ALOGV("st_mode = %u", sb.st_mode);
    139     ALOGV("st_uid  = %lu", sb.st_uid);
    140     ALOGV("st_gid  = %lu", sb.st_gid);
    141     ALOGV("st_size = %llu", sb.st_size);
    142 
    143     if (offset >= sb.st_size) {
    144         ALOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
    145         ::close(fd);
    146         return BAD_VALUE;
    147     }
    148     if (offset + length > sb.st_size) {
    149         length = sb.st_size - offset;
    150         ALOGV("calculated length = %lld", length);
    151     }
    152 
    153     player_type playerType = getPlayerType(fd, offset, length);
    154     ALOGV("player type = %d", playerType);
    155     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    156     if (p == NULL) {
    157         ::close(fd);
    158         return NO_INIT;
    159     }
    160     status_t status = p->setDataSource(fd, offset, length);
    161     if (status == NO_ERROR) mRetriever = p;
    162     ::close(fd);
    163     return status;
    164 }
    165 
    166 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
    167 {
    168     ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
    169     Mutex::Autolock lock(mLock);
    170     mThumbnail.clear();
    171     if (mRetriever == NULL) {
    172         ALOGE("retriever is not initialized");
    173         return NULL;
    174     }
    175     VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
    176     if (frame == NULL) {
    177         ALOGE("failed to capture a video frame");
    178         return NULL;
    179     }
    180     size_t size = sizeof(VideoFrame) + frame->mSize;
    181     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
    182     if (heap == NULL) {
    183         ALOGE("failed to create MemoryDealer");
    184         delete frame;
    185         return NULL;
    186     }
    187     mThumbnail = new MemoryBase(heap, 0, size);
    188     if (mThumbnail == NULL) {
    189         ALOGE("not enough memory for VideoFrame size=%u", size);
    190         delete frame;
    191         return NULL;
    192     }
    193     VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
    194     frameCopy->mWidth = frame->mWidth;
    195     frameCopy->mHeight = frame->mHeight;
    196     frameCopy->mDisplayWidth = frame->mDisplayWidth;
    197     frameCopy->mDisplayHeight = frame->mDisplayHeight;
    198     frameCopy->mSize = frame->mSize;
    199     frameCopy->mRotationAngle = frame->mRotationAngle;
    200     ALOGV("rotation: %d", frameCopy->mRotationAngle);
    201     frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
    202     memcpy(frameCopy->mData, frame->mData, frame->mSize);
    203     delete frame;  // Fix memory leakage
    204     return mThumbnail;
    205 }
    206 
    207 sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
    208 {
    209     ALOGV("extractAlbumArt");
    210     Mutex::Autolock lock(mLock);
    211     mAlbumArt.clear();
    212     if (mRetriever == NULL) {
    213         ALOGE("retriever is not initialized");
    214         return NULL;
    215     }
    216     MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
    217     if (albumArt == NULL) {
    218         ALOGE("failed to extract an album art");
    219         return NULL;
    220     }
    221     size_t size = sizeof(MediaAlbumArt) + albumArt->mSize;
    222     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
    223     if (heap == NULL) {
    224         ALOGE("failed to create MemoryDealer object");
    225         delete albumArt;
    226         return NULL;
    227     }
    228     mAlbumArt = new MemoryBase(heap, 0, size);
    229     if (mAlbumArt == NULL) {
    230         ALOGE("not enough memory for MediaAlbumArt size=%u", size);
    231         delete albumArt;
    232         return NULL;
    233     }
    234     MediaAlbumArt *albumArtCopy = static_cast<MediaAlbumArt *>(mAlbumArt->pointer());
    235     albumArtCopy->mSize = albumArt->mSize;
    236     albumArtCopy->mData = (uint8_t *)albumArtCopy + sizeof(MediaAlbumArt);
    237     memcpy(albumArtCopy->mData, albumArt->mData, albumArt->mSize);
    238     delete albumArt;  // Fix memory leakage
    239     return mAlbumArt;
    240 }
    241 
    242 const char* MetadataRetrieverClient::extractMetadata(int keyCode)
    243 {
    244     ALOGV("extractMetadata");
    245     Mutex::Autolock lock(mLock);
    246     if (mRetriever == NULL) {
    247         ALOGE("retriever is not initialized");
    248         return NULL;
    249     }
    250     return mRetriever->extractMetadata(keyCode);
    251 }
    252 
    253 }; // namespace android
    254