StagefrightMediaScanner.cpp revision 0a095d09464ba18e288a3f529410af0f1257ac2a
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 <media/stagefright/StagefrightMediaScanner.h>
22
23#include <media/mediametadataretriever.h>
24#include <private/media/VideoFrame.h>
25
26// Sonivox includes
27#include <libsonivox/eas.h>
28
29namespace android {
30
31StagefrightMediaScanner::StagefrightMediaScanner() {}
32
33StagefrightMediaScanner::~StagefrightMediaScanner() {}
34
35static bool FileHasAcceptableExtension(const char *extension) {
36    static const char *kValidExtensions[] = {
37        ".mp3", ".mp4", ".m4a", ".3gp", ".3gpp", ".3g2", ".3gpp2",
38        ".mpeg", ".ogg", ".mid", ".smf", ".imy", ".wma", ".aac",
39        ".wav", ".amr", ".midi", ".xmf", ".rtttl", ".rtx", ".ota",
40        ".mkv", ".mka", ".webm", ".ts", ".fl"
41    };
42    static const size_t kNumValidExtensions =
43        sizeof(kValidExtensions) / sizeof(kValidExtensions[0]);
44
45    for (size_t i = 0; i < kNumValidExtensions; ++i) {
46        if (!strcasecmp(extension, kValidExtensions[i])) {
47            return true;
48        }
49    }
50
51    return false;
52}
53
54static status_t HandleMIDI(
55        const char *filename, MediaScannerClient *client) {
56    // get the library configuration and do sanity check
57    const S_EAS_LIB_CONFIG* pLibConfig = EAS_Config();
58    if ((pLibConfig == NULL) || (LIB_VERSION != pLibConfig->libVersion)) {
59        LOGE("EAS library/header mismatch\n");
60        return UNKNOWN_ERROR;
61    }
62    EAS_I32 temp;
63
64    // spin up a new EAS engine
65    EAS_DATA_HANDLE easData = NULL;
66    EAS_HANDLE easHandle = NULL;
67    EAS_RESULT result = EAS_Init(&easData);
68    if (result == EAS_SUCCESS) {
69        EAS_FILE file;
70        file.path = filename;
71        file.fd = 0;
72        file.offset = 0;
73        file.length = 0;
74        result = EAS_OpenFile(easData, &file, &easHandle);
75    }
76    if (result == EAS_SUCCESS) {
77        result = EAS_Prepare(easData, easHandle);
78    }
79    if (result == EAS_SUCCESS) {
80        result = EAS_ParseMetaData(easData, easHandle, &temp);
81    }
82    if (easHandle) {
83        EAS_CloseFile(easData, easHandle);
84    }
85    if (easData) {
86        EAS_Shutdown(easData);
87    }
88
89    if (result != EAS_SUCCESS) {
90        return UNKNOWN_ERROR;
91    }
92
93    char buffer[20];
94    sprintf(buffer, "%ld", temp);
95    if (!client->addStringTag("duration", buffer)) return UNKNOWN_ERROR;
96
97    return OK;
98}
99
100status_t StagefrightMediaScanner::processFile(
101        const char *path, const char *mimeType,
102        MediaScannerClient &client) {
103    LOGV("processFile '%s'.", path);
104
105    client.setLocale(locale());
106    client.beginFile();
107
108    const char *extension = strrchr(path, '.');
109
110    if (!extension) {
111        return UNKNOWN_ERROR;
112    }
113
114    if (!FileHasAcceptableExtension(extension)) {
115        client.endFile();
116
117        return UNKNOWN_ERROR;
118    }
119
120    if (!strcasecmp(extension, ".mid")
121            || !strcasecmp(extension, ".smf")
122            || !strcasecmp(extension, ".imy")
123            || !strcasecmp(extension, ".midi")
124            || !strcasecmp(extension, ".xmf")
125            || !strcasecmp(extension, ".rtttl")
126            || !strcasecmp(extension, ".rtx")
127            || !strcasecmp(extension, ".ota")) {
128        status_t status = HandleMIDI(path, &client);
129        if (status != OK) {
130            return status;
131        }
132    } else {
133        sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
134
135         if (mRetriever->setDataSource(path) == OK) {
136            const char *value;
137            if ((value = mRetriever->extractMetadata(
138                            METADATA_KEY_MIMETYPE)) != NULL) {
139                client.setMimeType(value);
140            }
141
142            struct KeyMap {
143                const char *tag;
144                int key;
145            };
146            static const KeyMap kKeyMap[] = {
147                { "tracknumber", METADATA_KEY_CD_TRACK_NUMBER },
148                { "discnumber", METADATA_KEY_DISC_NUMBER },
149                { "album", METADATA_KEY_ALBUM },
150                { "artist", METADATA_KEY_ARTIST },
151                { "albumartist", METADATA_KEY_ALBUMARTIST },
152                { "composer", METADATA_KEY_COMPOSER },
153                { "genre", METADATA_KEY_GENRE },
154                { "title", METADATA_KEY_TITLE },
155                { "year", METADATA_KEY_YEAR },
156                { "duration", METADATA_KEY_DURATION },
157                { "writer", METADATA_KEY_WRITER },
158                { "compilation", METADATA_KEY_COMPILATION },
159            };
160            static const size_t kNumEntries = sizeof(kKeyMap) / sizeof(kKeyMap[0]);
161
162            for (size_t i = 0; i < kNumEntries; ++i) {
163                const char *value;
164                if ((value = mRetriever->extractMetadata(kKeyMap[i].key)) != NULL) {
165                    client.addStringTag(kKeyMap[i].tag, value);
166                }
167            }
168        }
169    }
170
171    client.endFile();
172
173    return OK;
174}
175
176char *StagefrightMediaScanner::extractAlbumArt(int fd) {
177    LOGV("extractAlbumArt %d", fd);
178
179    off64_t size = lseek64(fd, 0, SEEK_END);
180    if (size < 0) {
181        return NULL;
182    }
183    lseek64(fd, 0, SEEK_SET);
184
185    sp<MediaMetadataRetriever> mRetriever(new MediaMetadataRetriever);
186    if (mRetriever->setDataSource(fd, 0, size) == OK) {
187        sp<IMemory> mem = mRetriever->extractAlbumArt();
188
189        if (mem != NULL) {
190            MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->pointer());
191
192            char *data = (char *)malloc(art->mSize + 4);
193            *(int32_t *)data = art->mSize;
194            memcpy(&data[4], &art[1], art->mSize);
195
196            return data;
197        }
198    }
199
200    return NULL;
201}
202
203}  // namespace android
204