Home | History | Annotate | Download | only in libstagefright
      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 "StagefrightMediaScanner"
     19 #include <utils/Log.h>
     20 
     21 #include <sys/types.h>
     22 #include <sys/stat.h>
     23 #include <fcntl.h>
     24 
     25 #include <media/stagefright/StagefrightMediaScanner.h>
     26 
     27 #include <media/IMediaHTTPService.h>
     28 #include <media/mediametadataretriever.h>
     29 #include <private/media/VideoFrame.h>
     30 
     31 namespace android {
     32 
     33 StagefrightMediaScanner::StagefrightMediaScanner() {}
     34 
     35 StagefrightMediaScanner::~StagefrightMediaScanner() {}
     36 
     37 static bool FileHasAcceptableExtension(const char *extension) {
     38     static const char *kValidExtensions[] = {
     39         ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
     40         ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
     41         ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
     42         ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf",
     43         ".avi", ".mpeg", ".mpg", ".awb", ".mpga"
     44     };
     45     static const size_t kNumValidExtensions =
     46         sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
     47 
     48     for (size_t i = 0; i < kNumValidExtensions; ++i) {
     49         if (!strcasecmp(extension, kValidExtensions[i])) {
     50             return true;
     51         }
     52     }
     53 
     54     return false;
     55 }
     56 
     57 MediaScanResult StagefrightMediaScanner::processFile(
     58         const char *path, const char *mimeType,
     59         MediaScannerClient &client) {
     60     ALOGV("processFile '%s'.", path);
     61 
     62     client.setLocale(locale());
     63     client.beginFile();
     64     MediaScanResult result = processFileInternal(path, mimeType, client);
     65     client.endFile();
     66     return result;
     67 }
     68 
     69 MediaScanResult StagefrightMediaScanner::processFileInternal(
     70         const char *path, const char * /* mimeType */,
     71         MediaScannerClient &client) {
     72     const char *extension = strrchr(path, '.');
     73 
     74     if (!extension) {
     75         return MEDIA_SCAN_RESULT_SKIPPED;
     76     }
     77 
     78     if (!FileHasAcceptableExtension(extension)) {
     79         return MEDIA_SCAN_RESULT_SKIPPED;
     80     }
     81 
     82     sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
     83 
     84     int fd = open(path, O_RDONLY | O_LARGEFILE);
     85     status_t status;
     86     if (fd < 0) {
     87         // couldn't open it locally, maybe the media server can?
     88         status = mRetriever->setDataSource(NULL /* httpService */, path);
     89     } else {
     90         status = mRetriever->setDataSource(fd, 0, 0x7ffffffffffffffL);
     91         close(fd);
     92     }
     93 
     94     if (status) {
     95         return MEDIA_SCAN_RESULT_ERROR;
     96     }
     97 
     98     const char *value;
     99     if ((value = mRetriever->extractMetadata(
    100                     METADATA_KEY_MIMETYPE)) != NULL) {
    101         status = client.setMimeType(value);
    102         if (status) {
    103             return MEDIA_SCAN_RESULT_ERROR;
    104         }
    105     }
    106 
    107     struct KeyMap {
    108         const char *tag;
    109         int key;
    110     };
    111     static const KeyMap kKeyMap[] = {
    112         { "tracknumber", METADATA_KEY_CD_TRACK_NUMBER },
    113         { "discnumber", METADATA_KEY_DISC_NUMBER },
    114         { "album", METADATA_KEY_ALBUM },
    115         { "artist", METADATA_KEY_ARTIST },
    116         { "albumartist", METADATA_KEY_ALBUMARTIST },
    117         { "composer", METADATA_KEY_COMPOSER },
    118         { "genre", METADATA_KEY_GENRE },
    119         { "title", METADATA_KEY_TITLE },
    120         { "year", METADATA_KEY_YEAR },
    121         { "duration", METADATA_KEY_DURATION },
    122         { "writer", METADATA_KEY_WRITER },
    123         { "compilation", METADATA_KEY_COMPILATION },
    124         { "isdrm", METADATA_KEY_IS_DRM },
    125         { "width", METADATA_KEY_VIDEO_WIDTH },
    126         { "height", METADATA_KEY_VIDEO_HEIGHT },
    127     };
    128     static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
    129 
    130     for (size_t i = 0; i < kNumEntries; ++i) {
    131         const char *value;
    132         if ((value = mRetriever->extractMetadata(kKeyMap[i].key)) != NULL) {
    133             status = client.addStringTag(kKeyMap[i].tag, value);
    134             if (status != OK) {
    135                 return MEDIA_SCAN_RESULT_ERROR;
    136             }
    137         }
    138     }
    139 
    140     return MEDIA_SCAN_RESULT_OK;
    141 }
    142 
    143 MediaAlbumArt *StagefrightMediaScanner::extractAlbumArt(int fd) {
    144     ALOGV("extractAlbumArt %d", fd);
    145 
    146     off64_t size = lseek64(fd, 0, SEEK_END);
    147     if (size < 0) {
    148         return NULL;
    149     }
    150     lseek64(fd, 0, SEEK_SET);
    151 
    152     sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
    153     if (mRetriever->setDataSource(fd, 0, size) == OK) {
    154         sp<IMemory> mem = mRetriever->extractAlbumArt();
    155         if (mem != NULL) {
    156             MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->pointer());
    157             return art->clone();
    158         }
    159     }
    160 
    161     return NULL;
    162 }
    163 
    164 }  // namespace android
    165