1e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber/* 2e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * Copyright (C) 2009 The Android Open Source Project 3e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * 4e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License"); 5e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * you may not use this file except in compliance with the License. 6e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * You may obtain a copy of the License at 7e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * 8e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * http://www.apache.org/licenses/LICENSE-2.0 9e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * 10e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * Unless required by applicable law or agreed to in writing, software 11e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS, 12e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * See the License for the specific language governing permissions and 14e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber * limitations under the License. 15e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber */ 16e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 17aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber//#define LOG_NDEBUG 0 18aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber#define LOG_TAG "StagefrightMediaScanner" 19aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber#include <utils/Log.h> 20aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 21e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber#include <media/stagefright/StagefrightMediaScanner.h> 22e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 231ce986767ae5998ece6810c2933d0b274c529744Andreas Huber#include <media/mediametadataretriever.h> 241ce986767ae5998ece6810c2933d0b274c529744Andreas Huber#include <private/media/VideoFrame.h> 25e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 26aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber// Sonivox includes 27aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber#include <libsonivox/eas.h> 28aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 29e4a838051de5e56f44c71117073a035b804b5d04Andreas Hubernamespace android { 30e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 318151dc3229888109f4ec699eb6311975b51a05b9Mike LockwoodStagefrightMediaScanner::StagefrightMediaScanner() {} 32e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 33e4a838051de5e56f44c71117073a035b804b5d04Andreas HuberStagefrightMediaScanner::~StagefrightMediaScanner() {} 34e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 35aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huberstatic bool FileHasAcceptableExtension(const char *extension) { 36aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber static const char *kValidExtensions[] = { 37aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2", 38aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac", 39072f5247ef893e683728263a540bb93daafda376Andreas Huber ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota", 40eecadb9a84f357fb224592cc77603ff3e7c28f08Andreas Huber ".mkv", ".mka", ".webm", ".ts", ".fl", ".flac", ".mxmf", 41bc554956128d69d8d2e60365fb6cffe6facf659bAndreas Huber ".avi", ".mpeg", ".mpg" 42aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber }; 43aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber static const size_t kNumValidExtensions = 44aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber sizeof(kValidExtensions) / sizeof(kValidExtensions[0]); 45aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 46aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber for (size_t i = 0; i < kNumValidExtensions; ++i) { 47aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (!strcasecmp(extension, kValidExtensions[i])) { 48aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber return true; 49aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 50aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 51aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 52aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber return false; 53aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber} 54aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 552c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brownstatic MediaScanResult HandleMIDI( 56aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber const char *filename, MediaScannerClient *client) { 57aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber // get the library configuration and do sanity check 58aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber const S_EAS_LIB_CONFIG* pLibConfig = EAS_Config(); 59aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) { 60aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber LOGE("EAS library/header mismatch\n"); 612c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_ERROR; 62aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 63aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_I32 temp; 64aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 65aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber // spin up a new EAS engine 66aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_DATA_HANDLE easData = NULL; 67aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_HANDLE easHandle = NULL; 68aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_RESULT result = EAS_Init(&easData); 69aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (result == EAS_SUCCESS) { 70aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_FILE file; 71aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber file.path = filename; 72aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber file.fd = 0; 73aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber file.offset = 0; 74aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber file.length = 0; 75aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber result = EAS_OpenFile(easData, &file, &easHandle); 76aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 77aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (result == EAS_SUCCESS) { 78aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber result = EAS_Prepare(easData, easHandle); 79aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 80aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (result == EAS_SUCCESS) { 81aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber result = EAS_ParseMetaData(easData, easHandle, &temp); 82aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 83aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (easHandle) { 84aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_CloseFile(easData, easHandle); 85aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 86aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (easData) { 87aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber EAS_Shutdown(easData); 88aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 89aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 90aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (result != EAS_SUCCESS) { 912c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_SKIPPED; 92aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 93aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 94aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber char buffer[20]; 95aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber sprintf(buffer, "%ld", temp); 962c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown status_t status = client->addStringTag("duration", buffer); 97d4b22ab4889f9b1885bfc0dc45667c846a171a98Marco Nelissen if (status != OK) { 982c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_ERROR; 992c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown } 1002c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_OK; 101aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber} 102aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 1032c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff BrownMediaScanResult StagefrightMediaScanner::processFile( 104e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber const char *path, const char *mimeType, 105e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber MediaScannerClient &client) { 1061ce986767ae5998ece6810c2933d0b274c529744Andreas Huber LOGV("processFile '%s'.", path); 1071ce986767ae5998ece6810c2933d0b274c529744Andreas Huber 108e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber client.setLocale(locale()); 109e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber client.beginFile(); 1102c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown MediaScanResult result = processFileInternal(path, mimeType, client); 1112c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown client.endFile(); 1122c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return result; 1132c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown} 114e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 1152c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff BrownMediaScanResult StagefrightMediaScanner::processFileInternal( 1162c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown const char *path, const char *mimeType, 1172c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown MediaScannerClient &client) { 118aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber const char *extension = strrchr(path, '.'); 119aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 120aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (!extension) { 1212c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_SKIPPED; 122aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 123aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 124aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (!FileHasAcceptableExtension(extension)) { 1252c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_SKIPPED; 126aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 127aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 128aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (!strcasecmp(extension, ".mid") 129aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber || !strcasecmp(extension, ".smf") 130aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber || !strcasecmp(extension, ".imy") 131aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber || !strcasecmp(extension, ".midi") 132aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber || !strcasecmp(extension, ".xmf") 133aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber || !strcasecmp(extension, ".rtttl") 134aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber || !strcasecmp(extension, ".rtx") 135eecadb9a84f357fb224592cc77603ff3e7c28f08Andreas Huber || !strcasecmp(extension, ".ota") 136eecadb9a84f357fb224592cc77603ff3e7c28f08Andreas Huber || !strcasecmp(extension, ".mxmf")) { 1372c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return HandleMIDI(path, &client); 1382c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown } 1392c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown 1402c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever); 1412c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown 1422c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown status_t status = mRetriever->setDataSource(path); 1432c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown if (status) { 1442c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_ERROR; 1452c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown } 1462c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown 1472c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown const char *value; 1482c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown if ((value = mRetriever->extractMetadata( 1492c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown METADATA_KEY_MIMETYPE)) != NULL) { 1502c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown status = client.setMimeType(value); 1512c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown if (status) { 1522c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_ERROR; 153dc1a26eb7870cfafe4774d0db4613025c427db23Hiroshi Takekawa } 1542c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown } 1558151dc3229888109f4ec699eb6311975b51a05b9Mike Lockwood 1562c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown struct KeyMap { 1572c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown const char *tag; 1582c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown int key; 1592c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown }; 1602c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown static const KeyMap kKeyMap[] = { 1612c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "tracknumber", METADATA_KEY_CD_TRACK_NUMBER }, 1622c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "discnumber", METADATA_KEY_DISC_NUMBER }, 1632c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "album", METADATA_KEY_ALBUM }, 1642c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "artist", METADATA_KEY_ARTIST }, 1652c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "albumartist", METADATA_KEY_ALBUMARTIST }, 1662c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "composer", METADATA_KEY_COMPOSER }, 1672c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "genre", METADATA_KEY_GENRE }, 1682c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "title", METADATA_KEY_TITLE }, 1692c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "year", METADATA_KEY_YEAR }, 1702c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "duration", METADATA_KEY_DURATION }, 1712c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "writer", METADATA_KEY_WRITER }, 1722c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "compilation", METADATA_KEY_COMPILATION }, 1732c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown { "isdrm", METADATA_KEY_IS_DRM }, 1742c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown }; 1752c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]); 1762c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown 1772c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown for (size_t i = 0; i < kNumEntries; ++i) { 1782c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown const char *value; 1792c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown if ((value = mRetriever->extractMetadata(kKeyMap[i].key)) != NULL) { 1802c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown status = client.addStringTag(kKeyMap[i].tag, value); 181d4b22ab4889f9b1885bfc0dc45667c846a171a98Marco Nelissen if (status != OK) { 1822c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_ERROR; 183e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber } 184e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber } 185e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber } 186e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 1872c70d4a372a8ce83163f19bbd6ae82483ffbe46bJeff Brown return MEDIA_SCAN_RESULT_OK; 188e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber} 189e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 190e4a838051de5e56f44c71117073a035b804b5d04Andreas Huberchar *StagefrightMediaScanner::extractAlbumArt(int fd) { 1911ce986767ae5998ece6810c2933d0b274c529744Andreas Huber LOGV("extractAlbumArt %d", fd); 1921ce986767ae5998ece6810c2933d0b274c529744Andreas Huber 193b1262a8b1dd23abad64465f9ffd25c44facdf4d2James Dong off64_t size = lseek64(fd, 0, SEEK_END); 194aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber if (size < 0) { 195aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber return NULL; 196aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 197b1262a8b1dd23abad64465f9ffd25c44facdf4d2James Dong lseek64(fd, 0, SEEK_SET); 198aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 1998151dc3229888109f4ec699eb6311975b51a05b9Mike Lockwood sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever); 20011eab056dd0133a390169d3581edf3eef26d6a54James Dong if (mRetriever->setDataSource(fd, 0, size) == OK) { 2011ce986767ae5998ece6810c2933d0b274c529744Andreas Huber sp<IMemory> mem = mRetriever->extractAlbumArt(); 2021ce986767ae5998ece6810c2933d0b274c529744Andreas Huber 2031ce986767ae5998ece6810c2933d0b274c529744Andreas Huber if (mem != NULL) { 2041ce986767ae5998ece6810c2933d0b274c529744Andreas Huber MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->pointer()); 205e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 206aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber char *data = (char *)malloc(art->mSize + 4); 207aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber *(int32_t *)data = art->mSize; 2081ce986767ae5998ece6810c2933d0b274c529744Andreas Huber memcpy(&data[4], &art[1], art->mSize); 209aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber 210aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber return data; 211aee3c6394a367abf283936cb8b8bd85ed028c050Andreas Huber } 212e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber } 213e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 214e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber return NULL; 215e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber} 216e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber 217e4a838051de5e56f44c71117073a035b804b5d04Andreas Huber} // namespace android 218