StagefrightMetadataRetriever.cpp revision ce0febae177d1816ee7a6750ed9fba52472b9a71
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, uint32_t flags) {
112    sp<MediaSource> decoder =
113        OMXCodec::Create(
114                client->interface(), source->getFormat(), false, source,
115                NULL, flags | OMXCodec::kClientNeedsFramebuffer);
116
117    if (decoder.get() == NULL) {
118        LOGV("unable to instantiate video decoder.");
119
120        return NULL;
121    }
122
123    status_t err = decoder->start();
124    if (err != OK) {
125        LOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
126        return NULL;
127    }
128
129    // Read one output buffer, ignore format change notifications
130    // and spurious empty buffers.
131
132    MediaSource::ReadOptions options;
133    int64_t thumbNailTime;
134    if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
135        options.setSeekTo(thumbNailTime);
136    } else {
137        thumbNailTime = -1;
138    }
139
140    MediaBuffer *buffer = NULL;
141    do {
142        if (buffer != NULL) {
143            buffer->release();
144            buffer = NULL;
145        }
146        err = decoder->read(&buffer, &options);
147        options.clearSeekTo();
148    } while (err == INFO_FORMAT_CHANGED
149             || (buffer != NULL && buffer->range_length() == 0));
150
151    if (err != OK) {
152        CHECK_EQ(buffer, NULL);
153
154        LOGV("decoding frame failed.");
155        decoder->stop();
156
157        return NULL;
158    }
159
160    LOGV("successfully decoded video frame.");
161
162    int32_t unreadable;
163    if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
164            && unreadable != 0) {
165        LOGV("video frame is unreadable, decoder does not give us access "
166             "to the video data.");
167
168        buffer->release();
169        buffer = NULL;
170
171        decoder->stop();
172
173        return NULL;
174    }
175
176    int64_t timeUs;
177    CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
178    if (thumbNailTime >= 0) {
179        if (timeUs != thumbNailTime) {
180            const char *mime;
181            CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
182
183            LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
184                 thumbNailTime, timeUs, mime);
185        }
186    }
187
188    sp<MetaData> meta = decoder->getFormat();
189
190    int32_t width, height;
191    CHECK(meta->findInt32(kKeyWidth, &width));
192    CHECK(meta->findInt32(kKeyHeight, &height));
193
194    int32_t rotationAngle;
195    if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
196        rotationAngle = 0;  // By default, no rotation
197    }
198
199    VideoFrame *frame = new VideoFrame;
200    frame->mWidth = width;
201    frame->mHeight = height;
202    frame->mDisplayWidth = width;
203    frame->mDisplayHeight = height;
204    frame->mSize = width * height * 2;
205    frame->mData = new uint8_t[frame->mSize];
206    frame->mRotationAngle = rotationAngle;
207
208    int32_t srcFormat;
209    CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
210
211    ColorConverter converter(
212            (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
213    CHECK(converter.isValid());
214
215    converter.convert(
216            width, height,
217            (const uint8_t *)buffer->data() + buffer->range_offset(),
218            0,
219            frame->mData, width * 2);
220
221    buffer->release();
222    buffer = NULL;
223
224    decoder->stop();
225
226    return frame;
227}
228
229VideoFrame *StagefrightMetadataRetriever::captureFrame() {
230    LOGV("captureFrame");
231
232    if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) {
233        LOGV("captureFrame disabled by mode (0x%08x)", mMode);
234
235        return NULL;
236    }
237
238    if (mExtractor.get() == NULL) {
239        LOGV("no extractor.");
240        return NULL;
241    }
242
243    size_t n = mExtractor->countTracks();
244    size_t i;
245    for (i = 0; i < n; ++i) {
246        sp<MetaData> meta = mExtractor->getTrackMetaData(i);
247
248        const char *mime;
249        CHECK(meta->findCString(kKeyMIMEType, &mime));
250
251        if (!strncasecmp(mime, "video/", 6)) {
252            break;
253        }
254    }
255
256    if (i == n) {
257        LOGV("no video track found.");
258        return NULL;
259    }
260
261    sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
262            i, MediaExtractor::kIncludeExtensiveMetaData);
263
264    sp<MediaSource> source = mExtractor->getTrack(i);
265
266    if (source.get() == NULL) {
267        LOGV("unable to instantiate video track.");
268        return NULL;
269    }
270
271    VideoFrame *frame =
272        extractVideoFrameWithCodecFlags(
273                &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs);
274
275    if (frame == NULL) {
276        LOGV("Software decoder failed to extract thumbnail, "
277             "trying hardware decoder.");
278
279        frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0);
280    }
281
282    return frame;
283}
284
285MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
286    LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
287
288    if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
289        LOGV("extractAlbumArt/metadata retrieval disabled by mode");
290
291        return NULL;
292    }
293
294    if (mExtractor == NULL) {
295        return NULL;
296    }
297
298    if (!mParsedMetaData) {
299        parseMetaData();
300
301        mParsedMetaData = true;
302    }
303
304    if (mAlbumArt) {
305        return new MediaAlbumArt(*mAlbumArt);
306    }
307
308    return NULL;
309}
310
311const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
312    if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
313        LOGV("extractAlbumArt/metadata retrieval disabled by mode");
314
315        return NULL;
316    }
317
318    if (mExtractor == NULL) {
319        return NULL;
320    }
321
322    if (!mParsedMetaData) {
323        parseMetaData();
324
325        mParsedMetaData = true;
326    }
327
328    ssize_t index = mMetaData.indexOfKey(keyCode);
329
330    if (index < 0) {
331        return NULL;
332    }
333
334    return strdup(mMetaData.valueAt(index).string());
335}
336
337void StagefrightMetadataRetriever::parseMetaData() {
338    sp<MetaData> meta = mExtractor->getMetaData();
339
340    struct Map {
341        int from;
342        int to;
343    };
344    static const Map kMap[] = {
345        { kKeyMIMEType, METADATA_KEY_MIMETYPE },
346        { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
347        { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER },
348        { kKeyAlbum, METADATA_KEY_ALBUM },
349        { kKeyArtist, METADATA_KEY_ARTIST },
350        { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST },
351        { kKeyAuthor, METADATA_KEY_AUTHOR },
352        { kKeyComposer, METADATA_KEY_COMPOSER },
353        { kKeyDate, METADATA_KEY_DATE },
354        { kKeyGenre, METADATA_KEY_GENRE },
355        { kKeyTitle, METADATA_KEY_TITLE },
356        { kKeyYear, METADATA_KEY_YEAR },
357        { kKeyWriter, METADATA_KEY_WRITER },
358    };
359    static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
360
361    for (size_t i = 0; i < kNumMapEntries; ++i) {
362        const char *value;
363        if (meta->findCString(kMap[i].from, &value)) {
364            mMetaData.add(kMap[i].to, String8(value));
365        }
366    }
367
368    const void *data;
369    uint32_t type;
370    size_t dataSize;
371    if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) {
372        mAlbumArt = new MediaAlbumArt;
373        mAlbumArt->mSize = dataSize;
374        mAlbumArt->mData = new uint8_t[dataSize];
375        memcpy(mAlbumArt->mData, data, dataSize);
376    }
377
378    size_t numTracks = mExtractor->countTracks();
379
380    char tmp[32];
381    sprintf(tmp, "%d", numTracks);
382
383    mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
384
385    // The overall duration is the duration of the longest track.
386    int64_t maxDurationUs = 0;
387    for (size_t i = 0; i < numTracks; ++i) {
388        sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
389
390        int64_t durationUs;
391        if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
392            if (durationUs > maxDurationUs) {
393                maxDurationUs = durationUs;
394            }
395        }
396    }
397
398    // The duration value is a string representing the duration in ms.
399    sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
400    mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
401
402    if (numTracks == 1) {
403        const char *fileMIME;
404        CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
405
406        if (!strcasecmp(fileMIME, "video/x-matroska")) {
407            sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
408            const char *trackMIME;
409            CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
410
411            if (!strncasecmp("audio/", trackMIME, 6)) {
412                // The matroska file only contains a single audio track,
413                // rewrite its mime type.
414                mMetaData.add(
415                        METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
416            }
417        }
418    }
419}
420
421
422}  // namespace android
423