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 <media/stagefright/DataSource.h>
     38 #include <private/media/VideoFrame.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*/)
     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         default:
     94             // TODO:
     95             // support for TEST_PLAYER
     96             ALOGE("player type %d is not supported",  playerType);
     97             break;
     98     }
     99     if (p == NULL) {
    100         ALOGE("failed to create a retriever object");
    101     }
    102     return p;
    103 }
    104 
    105 status_t MetadataRetrieverClient::setDataSource(
    106         const sp<IMediaHTTPService> &httpService,
    107         const char *url,
    108         const KeyedVector<String8, String8> *headers)
    109 {
    110     ALOGV("setDataSource(%s)", url);
    111     Mutex::Autolock lock(mLock);
    112     if (url == NULL) {
    113         return UNKNOWN_ERROR;
    114     }
    115 
    116     // When asking the MediaPlayerFactory subsystem to choose a media player for
    117     // a given URL, a pointer to an outer IMediaPlayer can be passed to the
    118     // factory system to be taken into consideration along with the URL.  In the
    119     // case of choosing an instance of a MediaPlayerBase for a
    120     // MetadataRetrieverClient, there is no outer IMediaPlayer which will
    121     // eventually encapsulate the result of this selection.  In this case, just
    122     // pass NULL to getPlayerType to indicate that there is no outer
    123     // IMediaPlayer to consider during selection.
    124     player_type playerType =
    125         MediaPlayerFactory::getPlayerType(NULL /* client */, url);
    126     ALOGV("player type = %d", playerType);
    127     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    128     if (p == NULL) return NO_INIT;
    129     status_t ret = p->setDataSource(httpService, url, headers);
    130     if (ret == NO_ERROR) mRetriever = p;
    131     return ret;
    132 }
    133 
    134 status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
    135 {
    136     ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
    137     Mutex::Autolock lock(mLock);
    138     struct stat sb;
    139     int ret = fstat(fd, &sb);
    140     if (ret != 0) {
    141         ALOGE("fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
    142         return BAD_VALUE;
    143     }
    144     ALOGV("st_dev  = %llu", static_cast<uint64_t>(sb.st_dev));
    145     ALOGV("st_mode = %u", sb.st_mode);
    146     ALOGV("st_uid  = %lu", static_cast<unsigned long>(sb.st_uid));
    147     ALOGV("st_gid  = %lu", static_cast<unsigned long>(sb.st_gid));
    148     ALOGV("st_size = %llu", sb.st_size);
    149 
    150     if (offset >= sb.st_size) {
    151         ALOGE("offset (%lld) bigger than file size (%llu)", offset, sb.st_size);
    152         ::close(fd);
    153         return BAD_VALUE;
    154     }
    155     if (offset + length > sb.st_size) {
    156         length = sb.st_size - offset;
    157         ALOGV("calculated length = %lld", length);
    158     }
    159 
    160     player_type playerType =
    161         MediaPlayerFactory::getPlayerType(NULL /* client */,
    162                                           fd,
    163                                           offset,
    164                                           length);
    165     ALOGV("player type = %d", playerType);
    166     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    167     if (p == NULL) {
    168         ::close(fd);
    169         return NO_INIT;
    170     }
    171     status_t status = p->setDataSource(fd, offset, length);
    172     if (status == NO_ERROR) mRetriever = p;
    173     ::close(fd);
    174     return status;
    175 }
    176 
    177 status_t MetadataRetrieverClient::setDataSource(
    178         const sp<IDataSource>& source)
    179 {
    180     ALOGV("setDataSource(IDataSource)");
    181     Mutex::Autolock lock(mLock);
    182 
    183     sp<DataSource> dataSource = DataSource::CreateFromIDataSource(source);
    184     player_type playerType =
    185         MediaPlayerFactory::getPlayerType(NULL /* client */, dataSource);
    186     ALOGV("player type = %d", playerType);
    187     sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
    188     if (p == NULL) return NO_INIT;
    189     status_t ret = p->setDataSource(dataSource);
    190     if (ret == NO_ERROR) mRetriever = p;
    191     return ret;
    192 }
    193 
    194 Mutex MetadataRetrieverClient::sLock;
    195 
    196 sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
    197 {
    198     ALOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
    199     Mutex::Autolock lock(mLock);
    200     Mutex::Autolock glock(sLock);
    201     mThumbnail.clear();
    202     if (mRetriever == NULL) {
    203         ALOGE("retriever is not initialized");
    204         return NULL;
    205     }
    206     VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
    207     if (frame == NULL) {
    208         ALOGE("failed to capture a video frame");
    209         return NULL;
    210     }
    211     size_t size = sizeof(VideoFrame) + frame->mSize;
    212     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
    213     if (heap == NULL) {
    214         ALOGE("failed to create MemoryDealer");
    215         delete frame;
    216         return NULL;
    217     }
    218     mThumbnail = new MemoryBase(heap, 0, size);
    219     if (mThumbnail == NULL) {
    220         ALOGE("not enough memory for VideoFrame size=%u", size);
    221         delete frame;
    222         return NULL;
    223     }
    224     VideoFrame *frameCopy = static_cast<VideoFrame *>(mThumbnail->pointer());
    225     frameCopy->mWidth = frame->mWidth;
    226     frameCopy->mHeight = frame->mHeight;
    227     frameCopy->mDisplayWidth = frame->mDisplayWidth;
    228     frameCopy->mDisplayHeight = frame->mDisplayHeight;
    229     frameCopy->mSize = frame->mSize;
    230     frameCopy->mRotationAngle = frame->mRotationAngle;
    231     ALOGV("rotation: %d", frameCopy->mRotationAngle);
    232     frameCopy->mData = (uint8_t *)frameCopy + sizeof(VideoFrame);
    233     memcpy(frameCopy->mData, frame->mData, frame->mSize);
    234     delete frame;  // Fix memory leakage
    235     return mThumbnail;
    236 }
    237 
    238 sp<IMemory> MetadataRetrieverClient::extractAlbumArt()
    239 {
    240     ALOGV("extractAlbumArt");
    241     Mutex::Autolock lock(mLock);
    242     mAlbumArt.clear();
    243     if (mRetriever == NULL) {
    244         ALOGE("retriever is not initialized");
    245         return NULL;
    246     }
    247     MediaAlbumArt *albumArt = mRetriever->extractAlbumArt();
    248     if (albumArt == NULL) {
    249         ALOGE("failed to extract an album art");
    250         return NULL;
    251     }
    252     size_t size = sizeof(MediaAlbumArt) + albumArt->size();
    253     sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "MetadataRetrieverClient");
    254     if (heap == NULL) {
    255         ALOGE("failed to create MemoryDealer object");
    256         delete albumArt;
    257         return NULL;
    258     }
    259     mAlbumArt = new MemoryBase(heap, 0, size);
    260     if (mAlbumArt == NULL) {
    261         ALOGE("not enough memory for MediaAlbumArt size=%u", size);
    262         delete albumArt;
    263         return NULL;
    264     }
    265     MediaAlbumArt::init((MediaAlbumArt *) mAlbumArt->pointer(),
    266                         albumArt->size(), albumArt->data());
    267     delete albumArt;  // We've taken our copy.
    268     return mAlbumArt;
    269 }
    270 
    271 const char* MetadataRetrieverClient::extractMetadata(int keyCode)
    272 {
    273     ALOGV("extractMetadata");
    274     Mutex::Autolock lock(mLock);
    275     if (mRetriever == NULL) {
    276         ALOGE("retriever is not initialized");
    277         return NULL;
    278     }
    279     return mRetriever->extractMetadata(keyCode);
    280 }
    281 
    282 }; // namespace android
    283