StagefrightMetadataRetriever.cpp revision 213addfaf4b359c69da4e9b4490c511d116845bb
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 "StagefrightMetadataRetriever"
19#include <utils/Log.h>
20
21#include "include/StagefrightMetadataRetriever.h"
22
23#include <media/stagefright/CachingDataSource.h>
24#include <media/stagefright/ColorConverter.h>
25#include <media/stagefright/DataSource.h>
26#include <media/stagefright/FileSource.h>
27#include <media/stagefright/HTTPDataSource.h>
28#include <media/stagefright/MediaDebug.h>
29#include <media/stagefright/MediaExtractor.h>
30#include <media/stagefright/MetaData.h>
31#include <media/stagefright/OMXCodec.h>
32
33namespace android {
34
35StagefrightMetadataRetriever::StagefrightMetadataRetriever()
36    : mParsedMetaData(false),
37      mAlbumArt(NULL) {
38    LOGV("StagefrightMetadataRetriever()");
39
40    DataSource::RegisterDefaultSniffers();
41    CHECK_EQ(mClient.connect(), OK);
42}
43
44StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
45    LOGV("~StagefrightMetadataRetriever()");
46
47    delete mAlbumArt;
48    mAlbumArt = NULL;
49
50    mClient.disconnect();
51}
52
53status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
54    LOGV("setDataSource(%s)", uri);
55
56    mParsedMetaData = false;
57    mMetaData.clear();
58    delete mAlbumArt;
59    mAlbumArt = NULL;
60
61    mSource = DataSource::CreateFromURI(uri);
62
63    if (mSource == NULL) {
64        return UNKNOWN_ERROR;
65    }
66
67    mExtractor = MediaExtractor::Create(mSource);
68
69    if (mExtractor == NULL) {
70        mSource.clear();
71
72        return UNKNOWN_ERROR;
73    }
74
75    return OK;
76}
77
78// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
79status_t StagefrightMetadataRetriever::setDataSource(
80        int fd, int64_t offset, int64_t length) {
81    fd = dup(fd);
82
83    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
84
85    mParsedMetaData = false;
86    mMetaData.clear();
87    delete mAlbumArt;
88    mAlbumArt = NULL;
89
90    mSource = new FileSource(fd, offset, length);
91
92    status_t err;
93    if ((err = mSource->initCheck()) != OK) {
94        mSource.clear();
95
96        return err;
97    }
98
99    mExtractor = MediaExtractor::Create(mSource);
100
101    if (mExtractor == NULL) {
102        mSource.clear();
103
104        return UNKNOWN_ERROR;
105    }
106
107    return OK;
108}
109
110static VideoFrame *extractVideoFrameWithCodecFlags(
111        OMXClient *client,
112        const sp<MetaData> &trackMeta,
113        const sp<MediaSource> &source, uint32_t flags) {
114    sp<MediaSource> decoder =
115        OMXCodec::Create(
116                client->interface(), source->getFormat(), false, source,
117                NULL, flags);
118
119    if (decoder.get() == NULL) {
120        LOGV("unable to instantiate video decoder.");
121
122        return NULL;
123    }
124
125    decoder->start();
126
127    // Read one output buffer, ignore format change notifications
128    // and spurious empty buffers.
129
130    MediaSource::ReadOptions options;
131    int64_t thumbNailTime;
132    if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
133        options.setSeekTo(thumbNailTime);
134    } else {
135        thumbNailTime = -1;
136    }
137
138    MediaBuffer *buffer = NULL;
139    status_t err;
140    do {
141        if (buffer != NULL) {
142            buffer->release();
143            buffer = NULL;
144        }
145        err = decoder->read(&buffer, &options);
146        options.clearSeekTo();
147    } while (err == INFO_FORMAT_CHANGED
148             || (buffer != NULL && buffer->range_length() == 0));
149
150    if (err != OK) {
151        CHECK_EQ(buffer, NULL);
152
153        LOGV("decoding frame failed.");
154        decoder->stop();
155
156        return NULL;
157    }
158
159    LOGV("successfully decoded video frame.");
160
161    int64_t timeUs;
162    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
163    if (thumbNailTime >= 0) {
164        if (timeUs != thumbNailTime) {
165            const char *mime;
166            CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
167
168            LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
169                 thumbNailTime, timeUs, mime);
170        }
171    }
172
173    sp<MetaData> meta = decoder->getFormat();
174
175    int32_t width, height;
176    CHECK(meta->findInt32(kKeyWidth, &width));
177    CHECK(meta->findInt32(kKeyHeight, &height));
178
179    VideoFrame *frame = new VideoFrame;
180    frame->mWidth = width;
181    frame->mHeight = height;
182    frame->mDisplayWidth = width;
183    frame->mDisplayHeight = height;
184    frame->mSize = width * height * 2;
185    frame->mData = new uint8_t[frame->mSize];
186
187    int32_t srcFormat;
188    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
189
190    ColorConverter converter(
191            (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
192    CHECK(converter.isValid());
193
194    converter.convert(
195            width, height,
196            (const uint8_t *)buffer->data() + buffer->range_offset(),
197            0,
198            frame->mData, width * 2);
199
200    buffer->release();
201    buffer = NULL;
202
203    decoder->stop();
204
205    return frame;
206}
207
208VideoFrame *StagefrightMetadataRetriever::captureFrame() {
209    LOGV("captureFrame");
210
211    if (mExtractor.get() == NULL) {
212        LOGV("no extractor.");
213        return NULL;
214    }
215
216    size_t n = mExtractor->countTracks();
217    size_t i;
218    for (i = 0; i < n; ++i) {
219        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
220
221        const char *mime;
222        CHECK(meta->findCString(kKeyMIMEType, &mime));
223
224        if (!strncasecmp(mime, "video/", 6)) {
225            break;
226        }
227    }
228
229    if (i == n) {
230        LOGV("no video track found.");
231        return NULL;
232    }
233
234    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
235            i, MediaExtractor::kIncludeExtensiveMetaData);
236
237    sp<MediaSource> source = mExtractor->getTrack(i);
238
239    if (source.get() == NULL) {
240        LOGV("unable to instantiate video track.");
241        return NULL;
242    }
243
244    VideoFrame *frame =
245        extractVideoFrameWithCodecFlags(
246                &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs);
247
248    if (frame == NULL) {
249        LOGV("Software decoder failed to extract thumbnail, "
250             "trying hardware decoder.");
251
252        frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0);
253    }
254
255    return frame;
256}
257
258MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
259    LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
260
261    if (mExtractor == NULL) {
262        return NULL;
263    }
264
265    if (!mParsedMetaData) {
266        parseMetaData();
267
268        mParsedMetaData = true;
269    }
270
271    if (mAlbumArt) {
272        return new MediaAlbumArt(*mAlbumArt);
273    }
274
275    return NULL;
276}
277
278const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
279    if (mExtractor == NULL) {
280        return NULL;
281    }
282
283    if (!mParsedMetaData) {
284        parseMetaData();
285
286        mParsedMetaData = true;
287    }
288
289    ssize_t index = mMetaData.indexOfKey(keyCode);
290
291    if (index < 0) {
292        return NULL;
293    }
294
295    return strdup(mMetaData.valueAt(index).string());
296}
297
298void StagefrightMetadataRetriever::parseMetaData() {
299    sp<MetaData> meta = mExtractor->getMetaData();
300
301    struct Map {
302        int from;
303        int to;
304    };
305    static const Map kMap[] = {
306        { kKeyMIMEType, METADATA_KEY_MIMETYPE },
307        { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
308        { kKeyAlbum, METADATA_KEY_ALBUM },
309        { kKeyArtist, METADATA_KEY_ARTIST },
310        { kKeyAuthor, METADATA_KEY_AUTHOR },
311        { kKeyComposer, METADATA_KEY_COMPOSER },
312        { kKeyDate, METADATA_KEY_DATE },
313        { kKeyGenre, METADATA_KEY_GENRE },
314        { kKeyTitle, METADATA_KEY_TITLE },
315        { kKeyYear, METADATA_KEY_YEAR },
316        { kKeyWriter, METADATA_KEY_WRITER },
317    };
318    static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
319
320    for (size_t i = 0; i < kNumMapEntries; ++i) {
321        const char *value;
322        if (meta->findCString(kMap[i].from, &value)) {
323            mMetaData.add(kMap[i].to, String8(value));
324        }
325    }
326
327    const void *data;
328    uint32_t type;
329    size_t dataSize;
330    if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) {
331        mAlbumArt = new MediaAlbumArt;
332        mAlbumArt->mSize = dataSize;
333        mAlbumArt->mData = new uint8_t[dataSize];
334        memcpy(mAlbumArt->mData, data, dataSize);
335    }
336
337    size_t numTracks = mExtractor->countTracks();
338
339    char tmp[32];
340    sprintf(tmp, "%d", numTracks);
341
342    mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
343
344    // The overall duration is the duration of the longest track.
345    int64_t maxDurationUs = 0;
346    for (size_t i = 0; i < numTracks; ++i) {
347        sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
348
349        int64_t durationUs;
350        if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
351            if (durationUs > maxDurationUs) {
352                maxDurationUs = durationUs;
353            }
354        }
355    }
356
357    // The duration value is a string representing the duration in ms.
358    sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
359    mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
360}
361
362
363}  // namespace android
364