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