blob: 19af4fbd31f1a5a27df6b845deeaa53001b29052 [file] [log] [blame]
Andreas Huber2a4a7d52009-10-06 16:20:44 -07001/*
Andreas Huberfc9ba092010-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 Huber2a4a7d52009-10-06 16:20:44 -070016
17//#define LOG_NDEBUG 0
18#define LOG_TAG "StagefrightMetadataRetriever"
19#include <utils/Log.h>
20
Andreas Huber67e5a4f2010-01-08 10:57:34 -080021#include "include/StagefrightMetadataRetriever.h"
Andreas Huber2a4a7d52009-10-06 16:20:44 -070022
James Dongf1d5aa12012-02-06 23:46:37 -080023#include <media/stagefright/foundation/ADebug.h>
Andreas Huber2a4a7d52009-10-06 16:20:44 -070024#include <media/stagefright/ColorConverter.h>
25#include <media/stagefright/DataSource.h>
Andreas Huberbfa6b2d2009-11-20 09:32:46 -080026#include <media/stagefright/FileSource.h>
Andreas Huber2a4a7d52009-10-06 16:20:44 -070027#include <media/stagefright/MediaExtractor.h>
28#include <media/stagefright/MetaData.h>
Andreas Huber2a4a7d52009-10-06 16:20:44 -070029#include <media/stagefright/OMXCodec.h>
Gloria Wang7a1e3e82011-05-03 15:59:03 -070030#include <media/stagefright/MediaDefs.h>
Andreas Huber2a4a7d52009-10-06 16:20:44 -070031
32namespace android {
33
Andreas Huberfc9ba092010-01-11 15:35:19 -080034StagefrightMetadataRetriever::StagefrightMetadataRetriever()
35 : mParsedMetaData(false),
36 mAlbumArt(NULL) {
Steve Block3856b092011-10-20 11:56:00 +010037 ALOGV("StagefrightMetadataRetriever()");
Andreas Huber2a4a7d52009-10-06 16:20:44 -070038
39 DataSource::RegisterDefaultSniffers();
James Dongf1d5aa12012-02-06 23:46:37 -080040 CHECK_EQ(mClient.connect(), (status_t)OK);
Andreas Huber2a4a7d52009-10-06 16:20:44 -070041}
42
43StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
Steve Block3856b092011-10-20 11:56:00 +010044 ALOGV("~StagefrightMetadataRetriever()");
Andreas Huberfc9ba092010-01-11 15:35:19 -080045
46 delete mAlbumArt;
47 mAlbumArt = NULL;
48
Andreas Huber2a4a7d52009-10-06 16:20:44 -070049 mClient.disconnect();
50}
51
Andreas Huberaf8791e2011-03-21 10:25:44 -070052status_t StagefrightMetadataRetriever::setDataSource(
53 const char *uri, const KeyedVector<String8, String8> *headers) {
Steve Block3856b092011-10-20 11:56:00 +010054 ALOGV("setDataSource(%s)", uri);
Andreas Huber2a4a7d52009-10-06 16:20:44 -070055
Andreas Huberfc9ba092010-01-11 15:35:19 -080056 mParsedMetaData = false;
57 mMetaData.clear();
58 delete mAlbumArt;
59 mAlbumArt = NULL;
Andreas Huber2a4a7d52009-10-06 16:20:44 -070060
Andreas Huberaf8791e2011-03-21 10:25:44 -070061 mSource = DataSource::CreateFromURI(uri, headers);
Andreas Huberfc9ba092010-01-11 15:35:19 -080062
63 if (mSource == NULL) {
Andreas Huberf4b7d942012-04-11 11:52:03 -070064 ALOGE("Unable to create data source for '%s'.", uri);
Andreas Huberfc9ba092010-01-11 15:35:19 -080065 return UNKNOWN_ERROR;
66 }
67
68 mExtractor = MediaExtractor::Create(mSource);
69
70 if (mExtractor == NULL) {
Andreas Huberf4b7d942012-04-11 11:52:03 -070071 ALOGE("Unable to instantiate an extractor for '%s'.", uri);
72
Andreas Huberfc9ba092010-01-11 15:35:19 -080073 mSource.clear();
74
75 return UNKNOWN_ERROR;
76 }
77
78 return OK;
Andreas Huber2a4a7d52009-10-06 16:20:44 -070079}
80
Andreas Huberfc9ba092010-01-11 15:35:19 -080081// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
Andreas Huber2a4a7d52009-10-06 16:20:44 -070082status_t StagefrightMetadataRetriever::setDataSource(
83 int fd, int64_t offset, int64_t length) {
Andreas Huberfc9ba092010-01-11 15:35:19 -080084 fd = dup(fd);
85
Steve Block3856b092011-10-20 11:56:00 +010086 ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
Andreas Huber2a4a7d52009-10-06 16:20:44 -070087
Andreas Huberfc9ba092010-01-11 15:35:19 -080088 mParsedMetaData = false;
89 mMetaData.clear();
90 delete mAlbumArt;
91 mAlbumArt = NULL;
92
93 mSource = new FileSource(fd, offset, length);
94
95 status_t err;
96 if ((err = mSource->initCheck()) != OK) {
97 mSource.clear();
98
99 return err;
100 }
101
102 mExtractor = MediaExtractor::Create(mSource);
103
104 if (mExtractor == NULL) {
105 mSource.clear();
106
107 return UNKNOWN_ERROR;
108 }
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700109
110 return OK;
111}
112
James Dong20208012012-09-07 17:27:50 -0700113static bool isYUV420PlanarSupported(
114 OMXClient *client,
115 const sp<MetaData> &trackMeta) {
116
117 const char *mime;
118 CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
119
120 Vector<CodecCapabilities> caps;
121 if (QueryCodecs(client->interface(), mime,
122 true, /* queryDecoders */
123 true, /* hwCodecOnly */
124 &caps) == OK) {
125
126 for (size_t j = 0; j < caps.size(); ++j) {
127 CodecCapabilities cap = caps[j];
128 for (size_t i = 0; i < cap.mColorFormats.size(); ++i) {
129 if (cap.mColorFormats[i] == OMX_COLOR_FormatYUV420Planar) {
130 return true;
131 }
132 }
133 }
134 }
135 return false;
136}
137
Andreas Huber4e202e72010-01-14 14:15:33 -0800138static VideoFrame *extractVideoFrameWithCodecFlags(
139 OMXClient *client,
140 const sp<MetaData> &trackMeta,
James Dong16afe2f2010-12-02 17:42:08 -0800141 const sp<MediaSource> &source,
142 uint32_t flags,
143 int64_t frameTimeUs,
144 int seekMode) {
James Dong20208012012-09-07 17:27:50 -0700145
146 sp<MetaData> format = source->getFormat();
147
148 // XXX:
149 // Once all vendors support OMX_COLOR_FormatYUV420Planar, we can
150 // remove this check and always set the decoder output color format
151 if (isYUV420PlanarSupported(client, trackMeta)) {
152 format->setInt32(kKeyColorFormat, OMX_COLOR_FormatYUV420Planar);
153 }
154
Andreas Huber4e202e72010-01-14 14:15:33 -0800155 sp<MediaSource> decoder =
156 OMXCodec::Create(
James Dong20208012012-09-07 17:27:50 -0700157 client->interface(), format, false, source,
Andreas Huberf3712f02010-10-18 09:57:42 -0700158 NULL, flags | OMXCodec::kClientNeedsFramebuffer);
Andreas Huber4e202e72010-01-14 14:15:33 -0800159
160 if (decoder.get() == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100161 ALOGV("unable to instantiate video decoder.");
Andreas Huber4e202e72010-01-14 14:15:33 -0800162
163 return NULL;
164 }
165
Andreas Huber139a5d52010-05-20 10:37:06 -0700166 status_t err = decoder->start();
167 if (err != OK) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000168 ALOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
Andreas Huber139a5d52010-05-20 10:37:06 -0700169 return NULL;
170 }
Andreas Huber4e202e72010-01-14 14:15:33 -0800171
172 // Read one output buffer, ignore format change notifications
173 // and spurious empty buffers.
174
175 MediaSource::ReadOptions options;
James Dong16afe2f2010-12-02 17:42:08 -0800176 if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
177 seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
178
Steve Block29357bc2012-01-06 19:20:56 +0000179 ALOGE("Unknown seek mode: %d", seekMode);
James Dong16afe2f2010-12-02 17:42:08 -0800180 return NULL;
181 }
182
183 MediaSource::ReadOptions::SeekMode mode =
184 static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
185
Andreas Huber4e202e72010-01-14 14:15:33 -0800186 int64_t thumbNailTime;
Andreas Hubercb0cb252010-12-08 14:50:10 -0800187 if (frameTimeUs < 0) {
Andreas Huber21af7572011-04-11 10:57:29 -0700188 if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
189 || thumbNailTime < 0) {
Andreas Hubercb0cb252010-12-08 14:50:10 -0800190 thumbNailTime = 0;
191 }
James Dong16afe2f2010-12-02 17:42:08 -0800192 options.setSeekTo(thumbNailTime, mode);
Andreas Huber4e202e72010-01-14 14:15:33 -0800193 } else {
194 thumbNailTime = -1;
James Dong16afe2f2010-12-02 17:42:08 -0800195 options.setSeekTo(frameTimeUs, mode);
Andreas Huber4e202e72010-01-14 14:15:33 -0800196 }
197
198 MediaBuffer *buffer = NULL;
Andreas Huber4e202e72010-01-14 14:15:33 -0800199 do {
200 if (buffer != NULL) {
201 buffer->release();
202 buffer = NULL;
203 }
204 err = decoder->read(&buffer, &options);
205 options.clearSeekTo();
206 } while (err == INFO_FORMAT_CHANGED
207 || (buffer != NULL && buffer->range_length() == 0));
208
209 if (err != OK) {
James Dongf1d5aa12012-02-06 23:46:37 -0800210 CHECK(buffer == NULL);
Andreas Huber4e202e72010-01-14 14:15:33 -0800211
Steve Block3856b092011-10-20 11:56:00 +0100212 ALOGV("decoding frame failed.");
Andreas Huber4e202e72010-01-14 14:15:33 -0800213 decoder->stop();
214
215 return NULL;
216 }
217
Steve Block3856b092011-10-20 11:56:00 +0100218 ALOGV("successfully decoded video frame.");
Andreas Huber4e202e72010-01-14 14:15:33 -0800219
Andreas Huber2b82e962010-10-06 16:43:57 -0700220 int32_t unreadable;
221 if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
222 && unreadable != 0) {
Steve Block3856b092011-10-20 11:56:00 +0100223 ALOGV("video frame is unreadable, decoder does not give us access "
Andreas Huber2b82e962010-10-06 16:43:57 -0700224 "to the video data.");
225
226 buffer->release();
227 buffer = NULL;
228
229 decoder->stop();
230
231 return NULL;
232 }
233
Andreas Huber4e202e72010-01-14 14:15:33 -0800234 int64_t timeUs;
235 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
236 if (thumbNailTime >= 0) {
237 if (timeUs != thumbNailTime) {
238 const char *mime;
239 CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
240
Steve Block3856b092011-10-20 11:56:00 +0100241 ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
Andreas Huber4e202e72010-01-14 14:15:33 -0800242 thumbNailTime, timeUs, mime);
243 }
244 }
245
246 sp<MetaData> meta = decoder->getFormat();
247
248 int32_t width, height;
249 CHECK(meta->findInt32(kKeyWidth, &width));
250 CHECK(meta->findInt32(kKeyHeight, &height));
251
Andreas Huberf5ab57c2010-11-22 13:06:35 -0800252 int32_t crop_left, crop_top, crop_right, crop_bottom;
253 if (!meta->findRect(
254 kKeyCropRect,
255 &crop_left, &crop_top, &crop_right, &crop_bottom)) {
256 crop_left = crop_top = 0;
257 crop_right = width - 1;
258 crop_bottom = height - 1;
259 }
260
James Dongce0feba2010-11-08 16:04:27 -0800261 int32_t rotationAngle;
262 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
263 rotationAngle = 0; // By default, no rotation
264 }
265
Andreas Huber4e202e72010-01-14 14:15:33 -0800266 VideoFrame *frame = new VideoFrame;
Andreas Huberf5ab57c2010-11-22 13:06:35 -0800267 frame->mWidth = crop_right - crop_left + 1;
268 frame->mHeight = crop_bottom - crop_top + 1;
269 frame->mDisplayWidth = frame->mWidth;
270 frame->mDisplayHeight = frame->mHeight;
271 frame->mSize = frame->mWidth * frame->mHeight * 2;
Andreas Huber4e202e72010-01-14 14:15:33 -0800272 frame->mData = new uint8_t[frame->mSize];
James Dongce0feba2010-11-08 16:04:27 -0800273 frame->mRotationAngle = rotationAngle;
Andreas Huber4e202e72010-01-14 14:15:33 -0800274
James Dong1d54b3e2011-03-18 17:55:06 -0700275 int32_t displayWidth, displayHeight;
276 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
277 frame->mDisplayWidth = displayWidth;
278 }
279 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
280 frame->mDisplayHeight = displayHeight;
281 }
282
Andreas Huber4e202e72010-01-14 14:15:33 -0800283 int32_t srcFormat;
284 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
285
286 ColorConverter converter(
287 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
Andreas Huber4e202e72010-01-14 14:15:33 -0800288
Andreas Huberde321c32012-05-15 12:38:36 -0700289 if (converter.isValid()) {
290 err = converter.convert(
291 (const uint8_t *)buffer->data() + buffer->range_offset(),
292 width, height,
293 crop_left, crop_top, crop_right, crop_bottom,
294 frame->mData,
295 frame->mWidth,
296 frame->mHeight,
297 0, 0, frame->mWidth - 1, frame->mHeight - 1);
298 } else {
299 ALOGE("Unable to instantiate color conversion from format 0x%08x to "
300 "RGB565",
301 srcFormat);
302
303 err = ERROR_UNSUPPORTED;
304 }
Andreas Huber4e202e72010-01-14 14:15:33 -0800305
306 buffer->release();
307 buffer = NULL;
308
309 decoder->stop();
310
Andreas Huberb1787e32011-01-06 11:26:54 -0800311 if (err != OK) {
Steve Block29357bc2012-01-06 19:20:56 +0000312 ALOGE("Colorconverter failed to convert frame.");
Andreas Huberb1787e32011-01-06 11:26:54 -0800313
314 delete frame;
315 frame = NULL;
316 }
317
Andreas Huber4e202e72010-01-14 14:15:33 -0800318 return frame;
319}
320
James Dong16afe2f2010-12-02 17:42:08 -0800321VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
322 int64_t timeUs, int option) {
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700323
Steve Block3856b092011-10-20 11:56:00 +0100324 ALOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
Andreas Huber93e1fb92010-03-12 15:08:52 -0800325
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700326 if (mExtractor.get() == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100327 ALOGV("no extractor.");
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700328 return NULL;
329 }
330
Andreas Hubere7484f32011-09-06 16:05:02 -0700331 sp<MetaData> fileMeta = mExtractor->getMetaData();
332
333 if (fileMeta == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100334 ALOGV("extractor doesn't publish metadata, failed to initialize?");
Andreas Hubere7484f32011-09-06 16:05:02 -0700335 return NULL;
336 }
337
Glenn Kasten8ddeebb2011-02-21 09:37:13 -0800338 int32_t drm = 0;
Andreas Hubere7484f32011-09-06 16:05:02 -0700339 if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
Steve Block29357bc2012-01-06 19:20:56 +0000340 ALOGE("frame grab not allowed.");
Glenn Kasten8ddeebb2011-02-21 09:37:13 -0800341 return NULL;
342 }
343
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700344 size_t n = mExtractor->countTracks();
345 size_t i;
346 for (i = 0; i < n; ++i) {
347 sp<MetaData> meta = mExtractor->getTrackMetaData(i);
348
349 const char *mime;
350 CHECK(meta->findCString(kKeyMIMEType, &mime));
351
352 if (!strncasecmp(mime, "video/", 6)) {
353 break;
354 }
355 }
356
357 if (i == n) {
Steve Block3856b092011-10-20 11:56:00 +0100358 ALOGV("no video track found.");
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700359 return NULL;
360 }
361
Andreas Huber7e04dcf2009-10-22 13:49:30 -0700362 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
363 i, MediaExtractor::kIncludeExtensiveMetaData);
364
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700365 sp<MediaSource> source = mExtractor->getTrack(i);
366
367 if (source.get() == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100368 ALOGV("unable to instantiate video track.");
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700369 return NULL;
370 }
371
James Dong515e8552011-05-25 15:02:50 -0700372 const void *data;
373 uint32_t type;
374 size_t dataSize;
Andreas Hubere7484f32011-09-06 16:05:02 -0700375 if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
James Dong515e8552011-05-25 15:02:50 -0700376 && mAlbumArt == NULL) {
377 mAlbumArt = new MediaAlbumArt;
378 mAlbumArt->mSize = dataSize;
379 mAlbumArt->mData = new uint8_t[dataSize];
380 memcpy(mAlbumArt->mData, data, dataSize);
381 }
382
Andreas Huber4e202e72010-01-14 14:15:33 -0800383 VideoFrame *frame =
384 extractVideoFrameWithCodecFlags(
James Dong16afe2f2010-12-02 17:42:08 -0800385 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
386 timeUs, option);
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700387
Andreas Huber4e202e72010-01-14 14:15:33 -0800388 if (frame == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100389 ALOGV("Software decoder failed to extract thumbnail, "
Andreas Huber4e202e72010-01-14 14:15:33 -0800390 "trying hardware decoder.");
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700391
James Dong16afe2f2010-12-02 17:42:08 -0800392 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
393 timeUs, option);
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700394 }
395
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700396 return frame;
397}
398
399MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
Steve Block3856b092011-10-20 11:56:00 +0100400 ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700401
Andreas Huberfc9ba092010-01-11 15:35:19 -0800402 if (mExtractor == NULL) {
403 return NULL;
404 }
405
406 if (!mParsedMetaData) {
407 parseMetaData();
408
409 mParsedMetaData = true;
410 }
411
412 if (mAlbumArt) {
413 return new MediaAlbumArt(*mAlbumArt);
414 }
415
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700416 return NULL;
417}
418
419const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
Andreas Huberfc9ba092010-01-11 15:35:19 -0800420 if (mExtractor == NULL) {
421 return NULL;
422 }
423
424 if (!mParsedMetaData) {
425 parseMetaData();
426
427 mParsedMetaData = true;
428 }
429
430 ssize_t index = mMetaData.indexOfKey(keyCode);
431
432 if (index < 0) {
433 return NULL;
434 }
435
David Williams8a1016a2012-11-19 09:52:16 +0100436 return mMetaData.valueAt(index).string();
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700437}
438
Andreas Huberfc9ba092010-01-11 15:35:19 -0800439void StagefrightMetadataRetriever::parseMetaData() {
440 sp<MetaData> meta = mExtractor->getMetaData();
441
Andreas Hubere7484f32011-09-06 16:05:02 -0700442 if (meta == NULL) {
Steve Block3856b092011-10-20 11:56:00 +0100443 ALOGV("extractor doesn't publish metadata, failed to initialize?");
Andreas Hubere7484f32011-09-06 16:05:02 -0700444 return;
445 }
446
Andreas Huberfc9ba092010-01-11 15:35:19 -0800447 struct Map {
448 int from;
449 int to;
450 };
451 static const Map kMap[] = {
Andreas Huber7be64072010-01-13 11:25:10 -0800452 { kKeyMIMEType, METADATA_KEY_MIMETYPE },
Andreas Huberbd4bc592010-01-13 10:45:49 -0800453 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
Marco Nelissen6c8a9a42010-02-08 14:50:19 -0800454 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER },
Andreas Huberfc9ba092010-01-11 15:35:19 -0800455 { kKeyAlbum, METADATA_KEY_ALBUM },
456 { kKeyArtist, METADATA_KEY_ARTIST },
Marco Nelissen66ac4df2010-02-11 13:31:44 -0800457 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST },
Andreas Huberbd4bc592010-01-13 10:45:49 -0800458 { kKeyAuthor, METADATA_KEY_AUTHOR },
Andreas Huberfc9ba092010-01-11 15:35:19 -0800459 { kKeyComposer, METADATA_KEY_COMPOSER },
Andreas Huberbd4bc592010-01-13 10:45:49 -0800460 { kKeyDate, METADATA_KEY_DATE },
Andreas Huberfc9ba092010-01-11 15:35:19 -0800461 { kKeyGenre, METADATA_KEY_GENRE },
462 { kKeyTitle, METADATA_KEY_TITLE },
463 { kKeyYear, METADATA_KEY_YEAR },
Andreas Huber72b8c5a2010-01-19 16:43:53 -0800464 { kKeyWriter, METADATA_KEY_WRITER },
Marco Nelissen11f81092011-01-06 11:12:17 -0800465 { kKeyCompilation, METADATA_KEY_COMPILATION },
James Dong49488182011-11-09 00:48:56 -0800466 { kKeyLocation, METADATA_KEY_LOCATION },
Andreas Huberfc9ba092010-01-11 15:35:19 -0800467 };
468 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
469
470 for (size_t i = 0; i < kNumMapEntries; ++i) {
471 const char *value;
472 if (meta->findCString(kMap[i].from, &value)) {
473 mMetaData.add(kMap[i].to, String8(value));
474 }
475 }
476
477 const void *data;
478 uint32_t type;
479 size_t dataSize;
James Dong515e8552011-05-25 15:02:50 -0700480 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
481 && mAlbumArt == NULL) {
Andreas Huberfc9ba092010-01-11 15:35:19 -0800482 mAlbumArt = new MediaAlbumArt;
483 mAlbumArt->mSize = dataSize;
484 mAlbumArt->mData = new uint8_t[dataSize];
485 memcpy(mAlbumArt->mData, data, dataSize);
486 }
487
Andreas Huberbd4bc592010-01-13 10:45:49 -0800488 size_t numTracks = mExtractor->countTracks();
489
490 char tmp[32];
491 sprintf(tmp, "%d", numTracks);
492
493 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
494
Andreas Huber2256d512011-03-04 10:24:54 -0800495 bool hasAudio = false;
496 bool hasVideo = false;
497 int32_t videoWidth = -1;
498 int32_t videoHeight = -1;
499 int32_t audioBitrate = -1;
James Dong5a81ad82012-07-31 14:41:35 -0700500 int32_t rotationAngle = -1;
Andreas Huber2256d512011-03-04 10:24:54 -0800501
Andreas Huberfc9ba092010-01-11 15:35:19 -0800502 // The overall duration is the duration of the longest track.
503 int64_t maxDurationUs = 0;
Gloria Wang7a1e3e82011-05-03 15:59:03 -0700504 String8 timedTextLang;
Andreas Huberbd4bc592010-01-13 10:45:49 -0800505 for (size_t i = 0; i < numTracks; ++i) {
Andreas Huberfc9ba092010-01-11 15:35:19 -0800506 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
507
508 int64_t durationUs;
509 if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
510 if (durationUs > maxDurationUs) {
511 maxDurationUs = durationUs;
512 }
513 }
Andreas Huber2256d512011-03-04 10:24:54 -0800514
515 const char *mime;
516 if (trackMeta->findCString(kKeyMIMEType, &mime)) {
517 if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
518 hasAudio = true;
519
520 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
521 audioBitrate = -1;
522 }
523 } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
524 hasVideo = true;
525
526 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
527 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
James Dong5a81ad82012-07-31 14:41:35 -0700528 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
529 rotationAngle = 0;
530 }
Gloria Wang7a1e3e82011-05-03 15:59:03 -0700531 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
532 const char *lang;
533 trackMeta->findCString(kKeyMediaLanguage, &lang);
534 timedTextLang.append(String8(lang));
535 timedTextLang.append(String8(":"));
Andreas Huber2256d512011-03-04 10:24:54 -0800536 }
537 }
Andreas Huberfc9ba092010-01-11 15:35:19 -0800538 }
539
Gloria Wang7a1e3e82011-05-03 15:59:03 -0700540 // To save the language codes for all timed text tracks
541 // If multiple text tracks present, the format will look
542 // like "eng:chi"
543 if (!timedTextLang.isEmpty()) {
544 mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
545 }
546
Andreas Huberfc9ba092010-01-11 15:35:19 -0800547 // The duration value is a string representing the duration in ms.
Andreas Huberfc9ba092010-01-11 15:35:19 -0800548 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
Andreas Huberfc9ba092010-01-11 15:35:19 -0800549 mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
Andreas Huber093437c2010-05-20 14:56:53 -0700550
Andreas Huber2256d512011-03-04 10:24:54 -0800551 if (hasAudio) {
552 mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
553 }
554
555 if (hasVideo) {
556 mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
557
558 sprintf(tmp, "%d", videoWidth);
559 mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
560
561 sprintf(tmp, "%d", videoHeight);
562 mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
James Dong5a81ad82012-07-31 14:41:35 -0700563
564 sprintf(tmp, "%d", rotationAngle);
565 mMetaData.add(METADATA_KEY_VIDEO_ROTATION, String8(tmp));
Andreas Huber2256d512011-03-04 10:24:54 -0800566 }
567
568 if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
James Dong1d54b3e2011-03-18 17:55:06 -0700569 sprintf(tmp, "%d", audioBitrate);
Andreas Huber2256d512011-03-04 10:24:54 -0800570 mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
571 } else {
572 off64_t sourceSize;
573 if (mSource->getSize(&sourceSize) == OK) {
574 int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
575
576 sprintf(tmp, "%lld", avgBitRate);
577 mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
578 }
579 }
580
Andreas Huber093437c2010-05-20 14:56:53 -0700581 if (numTracks == 1) {
582 const char *fileMIME;
583 CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
584
585 if (!strcasecmp(fileMIME, "video/x-matroska")) {
586 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
587 const char *trackMIME;
588 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
589
590 if (!strncasecmp("audio/", trackMIME, 6)) {
591 // The matroska file only contains a single audio track,
592 // rewrite its mime type.
593 mMetaData.add(
594 METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
595 }
596 }
597 }
Gloria Wang0d0edfb2011-06-27 11:09:00 -0700598
599 // To check whether the media file is drm-protected
600 if (mExtractor->getDrmFlag()) {
601 mMetaData.add(METADATA_KEY_IS_DRM, String8("1"));
602 }
Andreas Huberfc9ba092010-01-11 15:35:19 -0800603}
604
Andreas Huber2a4a7d52009-10-06 16:20:44 -0700605} // namespace android