blob: 763a914d465a2ee090c2d9e96d87b8d7b06aaca7 [file] [log] [blame]
Andreas Huber53a76bd2009-10-06 16:20:44 -07001/*
Andreas Huberaee3c632010-01-11 15:35:19 -08002 * 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 */
Andreas Huber53a76bd2009-10-06 16:20:44 -070016
17//#define LOG_NDEBUG 0
18#define LOG_TAG "StagefrightMetadataRetriever"
19#include <utils/Log.h>
20
Andreas Hubere4a83802010-01-08 10:57:34 -080021#include "include/StagefrightMetadataRetriever.h"
Andreas Huber53a76bd2009-10-06 16:20:44 -070022
Andreas Huber53a76bd2009-10-06 16:20:44 -070023#include <media/stagefright/ColorConverter.h>
24#include <media/stagefright/DataSource.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080025#include <media/stagefright/FileSource.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070026#include <media/stagefright/MediaDebug.h>
27#include <media/stagefright/MediaExtractor.h>
28#include <media/stagefright/MetaData.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070029#include <media/stagefright/OMXCodec.h>
30
31namespace android {
32
Andreas Huberaee3c632010-01-11 15:35:19 -080033StagefrightMetadataRetriever::StagefrightMetadataRetriever()
34 : mParsedMetaData(false),
35 mAlbumArt(NULL) {
Andreas Huber53a76bd2009-10-06 16:20:44 -070036 LOGV("StagefrightMetadataRetriever()");
37
38 DataSource::RegisterDefaultSniffers();
39 CHECK_EQ(mClient.connect(), OK);
40}
41
42StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
43 LOGV("~StagefrightMetadataRetriever()");
Andreas Huberaee3c632010-01-11 15:35:19 -080044
45 delete mAlbumArt;
46 mAlbumArt = NULL;
47
Andreas Huber53a76bd2009-10-06 16:20:44 -070048 mClient.disconnect();
49}
50
51status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
52 LOGV("setDataSource(%s)", uri);
53
Andreas Huberaee3c632010-01-11 15:35:19 -080054 mParsedMetaData = false;
55 mMetaData.clear();
56 delete mAlbumArt;
57 mAlbumArt = NULL;
Andreas Huber53a76bd2009-10-06 16:20:44 -070058
Andreas Huberaee3c632010-01-11 15:35:19 -080059 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;
Andreas Huber53a76bd2009-10-06 16:20:44 -070074}
75
Andreas Huberaee3c632010-01-11 15:35:19 -080076// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
Andreas Huber53a76bd2009-10-06 16:20:44 -070077status_t StagefrightMetadataRetriever::setDataSource(
78 int fd, int64_t offset, int64_t length) {
Andreas Huberaee3c632010-01-11 15:35:19 -080079 fd = dup(fd);
80
Andreas Huber53a76bd2009-10-06 16:20:44 -070081 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
82
Andreas Huberaee3c632010-01-11 15:35:19 -080083 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 }
Andreas Huber53a76bd2009-10-06 16:20:44 -0700104
105 return OK;
106}
107
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800108static 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,
Andreas Huber5a40e392010-10-18 09:57:42 -0700115 NULL, flags | OMXCodec::kClientNeedsFramebuffer);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800116
117 if (decoder.get() == NULL) {
118 LOGV("unable to instantiate video decoder.");
119
120 return NULL;
121 }
122
Andreas Huber1919e5a2010-05-20 10:37:06 -0700123 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 }
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800128
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;
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800141 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
Andreas Huber1e194162010-10-06 16:43:57 -0700162 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
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800176 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
Andreas Huber1bb0ffd2010-11-22 13:06:35 -0800194 int32_t crop_left, crop_top, crop_right, crop_bottom;
195 if (!meta->findRect(
196 kKeyCropRect,
197 &crop_left, &crop_top, &crop_right, &crop_bottom)) {
198 crop_left = crop_top = 0;
199 crop_right = width - 1;
200 crop_bottom = height - 1;
201 }
202
James Dong53ebc722010-11-08 16:04:27 -0800203 int32_t rotationAngle;
204 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
205 rotationAngle = 0; // By default, no rotation
206 }
207
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800208 VideoFrame *frame = new VideoFrame;
Andreas Huber1bb0ffd2010-11-22 13:06:35 -0800209 frame->mWidth = crop_right - crop_left + 1;
210 frame->mHeight = crop_bottom - crop_top + 1;
211 frame->mDisplayWidth = frame->mWidth;
212 frame->mDisplayHeight = frame->mHeight;
213 frame->mSize = frame->mWidth * frame->mHeight * 2;
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800214 frame->mData = new uint8_t[frame->mSize];
James Dong53ebc722010-11-08 16:04:27 -0800215 frame->mRotationAngle = rotationAngle;
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800216
217 int32_t srcFormat;
218 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
219
220 ColorConverter converter(
221 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
222 CHECK(converter.isValid());
223
224 converter.convert(
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800225 (const uint8_t *)buffer->data() + buffer->range_offset(),
Andreas Huber1bb0ffd2010-11-22 13:06:35 -0800226 width, height,
227 crop_left, crop_top, crop_right, crop_bottom,
228 frame->mData,
229 frame->mWidth,
230 frame->mHeight,
231 0, 0, frame->mWidth - 1, frame->mHeight - 1);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800232
233 buffer->release();
234 buffer = NULL;
235
236 decoder->stop();
237
238 return frame;
239}
240
Andreas Huber53a76bd2009-10-06 16:20:44 -0700241VideoFrame *StagefrightMetadataRetriever::captureFrame() {
242 LOGV("captureFrame");
243
Andreas Hubere3452d32010-03-12 15:08:52 -0800244 if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) {
245 LOGV("captureFrame disabled by mode (0x%08x)", mMode);
246
247 return NULL;
248 }
249
Andreas Huber53a76bd2009-10-06 16:20:44 -0700250 if (mExtractor.get() == NULL) {
Andreas Huberad285432009-10-22 09:44:00 -0700251 LOGV("no extractor.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700252 return NULL;
253 }
254
255 size_t n = mExtractor->countTracks();
256 size_t i;
257 for (i = 0; i < n; ++i) {
258 sp<MetaData> meta = mExtractor->getTrackMetaData(i);
259
260 const char *mime;
261 CHECK(meta->findCString(kKeyMIMEType, &mime));
262
263 if (!strncasecmp(mime, "video/", 6)) {
264 break;
265 }
266 }
267
268 if (i == n) {
Andreas Huberad285432009-10-22 09:44:00 -0700269 LOGV("no video track found.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700270 return NULL;
271 }
272
Andreas Hubere981c332009-10-22 13:49:30 -0700273 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
274 i, MediaExtractor::kIncludeExtensiveMetaData);
275
Andreas Huber53a76bd2009-10-06 16:20:44 -0700276 sp<MediaSource> source = mExtractor->getTrack(i);
277
278 if (source.get() == NULL) {
Andreas Huberad285432009-10-22 09:44:00 -0700279 LOGV("unable to instantiate video track.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700280 return NULL;
281 }
282
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800283 VideoFrame *frame =
284 extractVideoFrameWithCodecFlags(
285 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700286
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800287 if (frame == NULL) {
288 LOGV("Software decoder failed to extract thumbnail, "
289 "trying hardware decoder.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700290
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800291 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700292 }
293
Andreas Huber53a76bd2009-10-06 16:20:44 -0700294 return frame;
295}
296
297MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
298 LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
299
Andreas Hubere3452d32010-03-12 15:08:52 -0800300 if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
301 LOGV("extractAlbumArt/metadata retrieval disabled by mode");
302
303 return NULL;
304 }
305
Andreas Huberaee3c632010-01-11 15:35:19 -0800306 if (mExtractor == NULL) {
307 return NULL;
308 }
309
310 if (!mParsedMetaData) {
311 parseMetaData();
312
313 mParsedMetaData = true;
314 }
315
316 if (mAlbumArt) {
317 return new MediaAlbumArt(*mAlbumArt);
318 }
319
Andreas Huber53a76bd2009-10-06 16:20:44 -0700320 return NULL;
321}
322
323const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
Andreas Hubere3452d32010-03-12 15:08:52 -0800324 if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
325 LOGV("extractAlbumArt/metadata retrieval disabled by mode");
326
327 return NULL;
328 }
329
Andreas Huberaee3c632010-01-11 15:35:19 -0800330 if (mExtractor == NULL) {
331 return NULL;
332 }
333
334 if (!mParsedMetaData) {
335 parseMetaData();
336
337 mParsedMetaData = true;
338 }
339
340 ssize_t index = mMetaData.indexOfKey(keyCode);
341
342 if (index < 0) {
343 return NULL;
344 }
345
346 return strdup(mMetaData.valueAt(index).string());
Andreas Huber53a76bd2009-10-06 16:20:44 -0700347}
348
Andreas Huberaee3c632010-01-11 15:35:19 -0800349void StagefrightMetadataRetriever::parseMetaData() {
350 sp<MetaData> meta = mExtractor->getMetaData();
351
352 struct Map {
353 int from;
354 int to;
355 };
356 static const Map kMap[] = {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800357 { kKeyMIMEType, METADATA_KEY_MIMETYPE },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800358 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
Marco Nelissen655306f2010-02-08 14:50:19 -0800359 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER },
Andreas Huberaee3c632010-01-11 15:35:19 -0800360 { kKeyAlbum, METADATA_KEY_ALBUM },
361 { kKeyArtist, METADATA_KEY_ARTIST },
Marco Nelissenc5d5ee32010-02-11 13:31:44 -0800362 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800363 { kKeyAuthor, METADATA_KEY_AUTHOR },
Andreas Huberaee3c632010-01-11 15:35:19 -0800364 { kKeyComposer, METADATA_KEY_COMPOSER },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800365 { kKeyDate, METADATA_KEY_DATE },
Andreas Huberaee3c632010-01-11 15:35:19 -0800366 { kKeyGenre, METADATA_KEY_GENRE },
367 { kKeyTitle, METADATA_KEY_TITLE },
368 { kKeyYear, METADATA_KEY_YEAR },
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800369 { kKeyWriter, METADATA_KEY_WRITER },
Andreas Huberaee3c632010-01-11 15:35:19 -0800370 };
371 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
372
373 for (size_t i = 0; i < kNumMapEntries; ++i) {
374 const char *value;
375 if (meta->findCString(kMap[i].from, &value)) {
376 mMetaData.add(kMap[i].to, String8(value));
377 }
378 }
379
380 const void *data;
381 uint32_t type;
382 size_t dataSize;
383 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) {
384 mAlbumArt = new MediaAlbumArt;
385 mAlbumArt->mSize = dataSize;
386 mAlbumArt->mData = new uint8_t[dataSize];
387 memcpy(mAlbumArt->mData, data, dataSize);
388 }
389
Andreas Huber3a3656c2010-01-13 10:45:49 -0800390 size_t numTracks = mExtractor->countTracks();
391
392 char tmp[32];
393 sprintf(tmp, "%d", numTracks);
394
395 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
396
Andreas Huberaee3c632010-01-11 15:35:19 -0800397 // The overall duration is the duration of the longest track.
398 int64_t maxDurationUs = 0;
Andreas Huber3a3656c2010-01-13 10:45:49 -0800399 for (size_t i = 0; i < numTracks; ++i) {
Andreas Huberaee3c632010-01-11 15:35:19 -0800400 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
401
402 int64_t durationUs;
403 if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
404 if (durationUs > maxDurationUs) {
405 maxDurationUs = durationUs;
406 }
407 }
408 }
409
410 // The duration value is a string representing the duration in ms.
Andreas Huberaee3c632010-01-11 15:35:19 -0800411 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
Andreas Huberaee3c632010-01-11 15:35:19 -0800412 mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
Andreas Huber072f5242010-05-20 14:56:53 -0700413
414 if (numTracks == 1) {
415 const char *fileMIME;
416 CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
417
418 if (!strcasecmp(fileMIME, "video/x-matroska")) {
419 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
420 const char *trackMIME;
421 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
422
423 if (!strncasecmp("audio/", trackMIME, 6)) {
424 // The matroska file only contains a single audio track,
425 // rewrite its mime type.
426 mMetaData.add(
427 METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
428 }
429 }
430 }
Andreas Huberaee3c632010-01-11 15:35:19 -0800431}
432
Andreas Huber53a76bd2009-10-06 16:20:44 -0700433} // namespace android