StagefrightMetadataRetriever.cpp revision 21af757836167a328ddf1c0381909d53941528c4
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/ColorConverter.h>
24#include <media/stagefright/DataSource.h>
25#include <media/stagefright/FileSource.h>
26#include <media/stagefright/MediaDebug.h>
27#include <media/stagefright/MediaExtractor.h>
28#include <media/stagefright/MetaData.h>
29#include <media/stagefright/OMXCodec.h>
30
31namespace android {
32
33StagefrightMetadataRetriever::StagefrightMetadataRetriever()
34    : mParsedMetaData(false),
35      mAlbumArt(NULL) {
36    LOGV("StagefrightMetadataRetriever()");
37
38    DataSource::RegisterDefaultSniffers();
39    CHECK_EQ(mClient.connect(), OK);
40}
41
42StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
43    LOGV("~StagefrightMetadataRetriever()");
44
45    delete mAlbumArt;
46    mAlbumArt = NULL;
47
48    mClient.disconnect();
49}
50
51status_t StagefrightMetadataRetriever::setDataSource(
52        const char *uri, const KeyedVector<String8, String8> *headers) {
53    LOGV("setDataSource(%s)", uri);
54
55    mParsedMetaData = false;
56    mMetaData.clear();
57    delete mAlbumArt;
58    mAlbumArt = NULL;
59
60    mSource = DataSource::CreateFromURI(uri, headers);
61
62    if (mSource == NULL) {
63        return UNKNOWN_ERROR;
64    }
65
66    mExtractor = MediaExtractor::Create(mSource);
67
68    if (mExtractor == NULL) {
69        mSource.clear();
70
71        return UNKNOWN_ERROR;
72    }
73
74    return OK;
75}
76
77// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
78status_t StagefrightMetadataRetriever::setDataSource(
79        int fd, int64_t offset, int64_t length) {
80    fd = dup(fd);
81
82    LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
83
84    mParsedMetaData = false;
85    mMetaData.clear();
86    delete mAlbumArt;
87    mAlbumArt = NULL;
88
89    mSource = new FileSource(fd, offset, length);
90
91    status_t err;
92    if ((err = mSource->initCheck()) != OK) {
93        mSource.clear();
94
95        return err;
96    }
97
98    mExtractor = MediaExtractor::Create(mSource);
99
100    if (mExtractor == NULL) {
101        mSource.clear();
102
103        return UNKNOWN_ERROR;
104    }
105
106    return OK;
107}
108
109static VideoFrame *extractVideoFrameWithCodecFlags(
110        OMXClient *client,
111        const sp<MetaData> &trackMeta,
112        const sp<MediaSource> &source,
113        uint32_t flags,
114        int64_t frameTimeUs,
115        int seekMode) {
116    sp<MediaSource> decoder =
117        OMXCodec::Create(
118                client->interface(), source->getFormat(), false, source,
119                NULL, flags | OMXCodec::kClientNeedsFramebuffer);
120
121    if (decoder.get() == NULL) {
122        LOGV("unable to instantiate video decoder.");
123
124        return NULL;
125    }
126
127    status_t err = decoder->start();
128    if (err != OK) {
129        LOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
130        return NULL;
131    }
132
133    // Read one output buffer, ignore format change notifications
134    // and spurious empty buffers.
135
136    MediaSource::ReadOptions options;
137    if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
138        seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
139
140        LOGE("Unknown seek mode: %d", seekMode);
141        return NULL;
142    }
143
144    MediaSource::ReadOptions::SeekMode mode =
145            static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
146
147    int64_t thumbNailTime;
148    if (frameTimeUs < 0) {
149        if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
150                || thumbNailTime < 0) {
151            thumbNailTime = 0;
152        }
153        options.setSeekTo(thumbNailTime, mode);
154    } else {
155        thumbNailTime = -1;
156        options.setSeekTo(frameTimeUs, mode);
157    }
158
159    MediaBuffer *buffer = NULL;
160    do {
161        if (buffer != NULL) {
162            buffer->release();
163            buffer = NULL;
164        }
165        err = decoder->read(&buffer, &options);
166        options.clearSeekTo();
167    } while (err == INFO_FORMAT_CHANGED
168             || (buffer != NULL && buffer->range_length() == 0));
169
170    if (err != OK) {
171        CHECK_EQ(buffer, NULL);
172
173        LOGV("decoding frame failed.");
174        decoder->stop();
175
176        return NULL;
177    }
178
179    LOGV("successfully decoded video frame.");
180
181    int32_t unreadable;
182    if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
183            && unreadable != 0) {
184        LOGV("video frame is unreadable, decoder does not give us access "
185             "to the video data.");
186
187        buffer->release();
188        buffer = NULL;
189
190        decoder->stop();
191
192        return NULL;
193    }
194
195    int64_t timeUs;
196    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
197    if (thumbNailTime >= 0) {
198        if (timeUs != thumbNailTime) {
199            const char *mime;
200            CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
201
202            LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
203                 thumbNailTime, timeUs, mime);
204        }
205    }
206
207    sp<MetaData> meta = decoder->getFormat();
208
209    int32_t width, height;
210    CHECK(meta->findInt32(kKeyWidth, &width));
211    CHECK(meta->findInt32(kKeyHeight, &height));
212
213    int32_t crop_left, crop_top, crop_right, crop_bottom;
214    if (!meta->findRect(
215                kKeyCropRect,
216                &crop_left, &crop_top, &crop_right, &crop_bottom)) {
217        crop_left = crop_top = 0;
218        crop_right = width - 1;
219        crop_bottom = height - 1;
220    }
221
222    int32_t rotationAngle;
223    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
224        rotationAngle = 0;  // By default, no rotation
225    }
226
227    VideoFrame *frame = new VideoFrame;
228    frame->mWidth = crop_right - crop_left + 1;
229    frame->mHeight = crop_bottom - crop_top + 1;
230    frame->mDisplayWidth = frame->mWidth;
231    frame->mDisplayHeight = frame->mHeight;
232    frame->mSize = frame->mWidth * frame->mHeight * 2;
233    frame->mData = new uint8_t[frame->mSize];
234    frame->mRotationAngle = rotationAngle;
235
236    int32_t displayWidth, displayHeight;
237    if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
238        frame->mDisplayWidth = displayWidth;
239    }
240    if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
241        frame->mDisplayHeight = displayHeight;
242    }
243
244    int32_t srcFormat;
245    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
246
247    ColorConverter converter(
248            (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
249    CHECK(converter.isValid());
250
251    err = converter.convert(
252            (const uint8_t *)buffer->data() + buffer->range_offset(),
253            width, height,
254            crop_left, crop_top, crop_right, crop_bottom,
255            frame->mData,
256            frame->mWidth,
257            frame->mHeight,
258            0, 0, frame->mWidth - 1, frame->mHeight - 1);
259
260    buffer->release();
261    buffer = NULL;
262
263    decoder->stop();
264
265    if (err != OK) {
266        LOGE("Colorconverter failed to convert frame.");
267
268        delete frame;
269        frame = NULL;
270    }
271
272    return frame;
273}
274
275VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
276        int64_t timeUs, int option) {
277
278    LOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
279
280    if (mExtractor.get() == NULL) {
281        LOGV("no extractor.");
282        return NULL;
283    }
284
285    int32_t drm = 0;
286    if (mExtractor->getMetaData()->findInt32(kKeyIsDRM, &drm) && drm != 0) {
287        LOGE("frame grab not allowed.");
288        return NULL;
289    }
290
291    size_t n = mExtractor->countTracks();
292    size_t i;
293    for (i = 0; i < n; ++i) {
294        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
295
296        const char *mime;
297        CHECK(meta->findCString(kKeyMIMEType, &mime));
298
299        if (!strncasecmp(mime, "video/", 6)) {
300            break;
301        }
302    }
303
304    if (i == n) {
305        LOGV("no video track found.");
306        return NULL;
307    }
308
309    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
310            i, MediaExtractor::kIncludeExtensiveMetaData);
311
312    sp<MediaSource> source = mExtractor->getTrack(i);
313
314    if (source.get() == NULL) {
315        LOGV("unable to instantiate video track.");
316        return NULL;
317    }
318
319    VideoFrame *frame =
320        extractVideoFrameWithCodecFlags(
321                &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
322                timeUs, option);
323
324    if (frame == NULL) {
325        LOGV("Software decoder failed to extract thumbnail, "
326             "trying hardware decoder.");
327
328        frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
329                        timeUs, option);
330    }
331
332    return frame;
333}
334
335MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
336    LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
337
338    if (mExtractor == NULL) {
339        return NULL;
340    }
341
342    if (!mParsedMetaData) {
343        parseMetaData();
344
345        mParsedMetaData = true;
346    }
347
348    if (mAlbumArt) {
349        return new MediaAlbumArt(*mAlbumArt);
350    }
351
352    return NULL;
353}
354
355const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
356    if (mExtractor == NULL) {
357        return NULL;
358    }
359
360    if (!mParsedMetaData) {
361        parseMetaData();
362
363        mParsedMetaData = true;
364    }
365
366    ssize_t index = mMetaData.indexOfKey(keyCode);
367
368    if (index < 0) {
369        return NULL;
370    }
371
372    return strdup(mMetaData.valueAt(index).string());
373}
374
375void StagefrightMetadataRetriever::parseMetaData() {
376    sp<MetaData> meta = mExtractor->getMetaData();
377
378    struct Map {
379        int from;
380        int to;
381    };
382    static const Map kMap[] = {
383        { kKeyMIMEType, METADATA_KEY_MIMETYPE },
384        { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
385        { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER },
386        { kKeyAlbum, METADATA_KEY_ALBUM },
387        { kKeyArtist, METADATA_KEY_ARTIST },
388        { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST },
389        { kKeyAuthor, METADATA_KEY_AUTHOR },
390        { kKeyComposer, METADATA_KEY_COMPOSER },
391        { kKeyDate, METADATA_KEY_DATE },
392        { kKeyGenre, METADATA_KEY_GENRE },
393        { kKeyTitle, METADATA_KEY_TITLE },
394        { kKeyYear, METADATA_KEY_YEAR },
395        { kKeyWriter, METADATA_KEY_WRITER },
396        { kKeyCompilation, METADATA_KEY_COMPILATION },
397    };
398    static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
399
400    for (size_t i = 0; i < kNumMapEntries; ++i) {
401        const char *value;
402        if (meta->findCString(kMap[i].from, &value)) {
403            mMetaData.add(kMap[i].to, String8(value));
404        }
405    }
406
407    const void *data;
408    uint32_t type;
409    size_t dataSize;
410    if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) {
411        mAlbumArt = new MediaAlbumArt;
412        mAlbumArt->mSize = dataSize;
413        mAlbumArt->mData = new uint8_t[dataSize];
414        memcpy(mAlbumArt->mData, data, dataSize);
415    }
416
417    size_t numTracks = mExtractor->countTracks();
418
419    char tmp[32];
420    sprintf(tmp, "%d", numTracks);
421
422    mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
423
424    bool hasAudio = false;
425    bool hasVideo = false;
426    int32_t videoWidth = -1;
427    int32_t videoHeight = -1;
428    int32_t audioBitrate = -1;
429
430    // The overall duration is the duration of the longest track.
431    int64_t maxDurationUs = 0;
432    for (size_t i = 0; i < numTracks; ++i) {
433        sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
434
435        int64_t durationUs;
436        if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
437            if (durationUs > maxDurationUs) {
438                maxDurationUs = durationUs;
439            }
440        }
441
442        const char *mime;
443        if (trackMeta->findCString(kKeyMIMEType, &mime)) {
444            if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
445                hasAudio = true;
446
447                if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
448                    audioBitrate = -1;
449                }
450            } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
451                hasVideo = true;
452
453                CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
454                CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
455            }
456        }
457    }
458
459    // The duration value is a string representing the duration in ms.
460    sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
461    mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
462
463    if (hasAudio) {
464        mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
465    }
466
467    if (hasVideo) {
468        mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
469
470        sprintf(tmp, "%d", videoWidth);
471        mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
472
473        sprintf(tmp, "%d", videoHeight);
474        mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
475    }
476
477    if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
478        sprintf(tmp, "%d", audioBitrate);
479        mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
480    } else {
481        off64_t sourceSize;
482        if (mSource->getSize(&sourceSize) == OK) {
483            int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
484
485            sprintf(tmp, "%lld", avgBitRate);
486            mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
487        }
488    }
489
490    if (numTracks == 1) {
491        const char *fileMIME;
492        CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
493
494        if (!strcasecmp(fileMIME, "video/x-matroska")) {
495            sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
496            const char *trackMIME;
497            CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
498
499            if (!strncasecmp("audio/", trackMIME, 6)) {
500                // The matroska file only contains a single audio track,
501                // rewrite its mime type.
502                mMetaData.add(
503                        METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
504            }
505        }
506    }
507}
508
509}  // namespace android
510