blob: 35f9c1f7aae81953003767f5ffd3d861ab2e5917 [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
James Dong8e9d67a2012-02-06 23:46:37 -080023#include <media/stagefright/foundation/ADebug.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070024#include <media/stagefright/ColorConverter.h>
25#include <media/stagefright/DataSource.h>
Andreas Huber27366fc2009-11-20 09:32:46 -080026#include <media/stagefright/FileSource.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070027#include <media/stagefright/MediaExtractor.h>
28#include <media/stagefright/MetaData.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070029#include <media/stagefright/OMXCodec.h>
Gloria Wangc6091dd2011-05-03 15:59:03 -070030#include <media/stagefright/MediaDefs.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070031
32namespace android {
33
Andreas Huberaee3c632010-01-11 15:35:19 -080034StagefrightMetadataRetriever::StagefrightMetadataRetriever()
35 : mParsedMetaData(false),
36 mAlbumArt(NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +010037 ALOGV("StagefrightMetadataRetriever()");
Andreas Huber53a76bd2009-10-06 16:20:44 -070038
39 DataSource::RegisterDefaultSniffers();
James Dong8e9d67a2012-02-06 23:46:37 -080040 CHECK_EQ(mClient.connect(), (status_t)OK);
Andreas Huber53a76bd2009-10-06 16:20:44 -070041}
42
43StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
Steve Block71f2cf12011-10-20 11:56:00 +010044 ALOGV("~StagefrightMetadataRetriever()");
Andreas Huberaee3c632010-01-11 15:35:19 -080045
46 delete mAlbumArt;
47 mAlbumArt = NULL;
48
Andreas Huber53a76bd2009-10-06 16:20:44 -070049 mClient.disconnect();
50}
51
Andreas Huber5b7ced62011-03-21 10:25:44 -070052status_t StagefrightMetadataRetriever::setDataSource(
53 const char *uri, const KeyedVector<String8, String8> *headers) {
Steve Block71f2cf12011-10-20 11:56:00 +010054 ALOGV("setDataSource(%s)", uri);
Andreas Huber53a76bd2009-10-06 16:20:44 -070055
Andreas Huberaee3c632010-01-11 15:35:19 -080056 mParsedMetaData = false;
57 mMetaData.clear();
58 delete mAlbumArt;
59 mAlbumArt = NULL;
Andreas Huber53a76bd2009-10-06 16:20:44 -070060
Andreas Huber5b7ced62011-03-21 10:25:44 -070061 mSource = DataSource::CreateFromURI(uri, headers);
Andreas Huberaee3c632010-01-11 15:35:19 -080062
63 if (mSource == NULL) {
64 return UNKNOWN_ERROR;
65 }
66
67 mExtractor = MediaExtractor::Create(mSource);
68
69 if (mExtractor == NULL) {
70 mSource.clear();
71
72 return UNKNOWN_ERROR;
73 }
74
75 return OK;
Andreas Huber53a76bd2009-10-06 16:20:44 -070076}
77
Andreas Huberaee3c632010-01-11 15:35:19 -080078// Warning caller retains ownership of the filedescriptor! Dup it if necessary.
Andreas Huber53a76bd2009-10-06 16:20:44 -070079status_t StagefrightMetadataRetriever::setDataSource(
80 int fd, int64_t offset, int64_t length) {
Andreas Huberaee3c632010-01-11 15:35:19 -080081 fd = dup(fd);
82
Steve Block71f2cf12011-10-20 11:56:00 +010083 ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
Andreas Huber53a76bd2009-10-06 16:20:44 -070084
Andreas Huberaee3c632010-01-11 15:35:19 -080085 mParsedMetaData = false;
86 mMetaData.clear();
87 delete mAlbumArt;
88 mAlbumArt = NULL;
89
90 mSource = new FileSource(fd, offset, length);
91
92 status_t err;
93 if ((err = mSource->initCheck()) != OK) {
94 mSource.clear();
95
96 return err;
97 }
98
99 mExtractor = MediaExtractor::Create(mSource);
100
101 if (mExtractor == NULL) {
102 mSource.clear();
103
104 return UNKNOWN_ERROR;
105 }
Andreas Huber53a76bd2009-10-06 16:20:44 -0700106
107 return OK;
108}
109
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800110static VideoFrame *extractVideoFrameWithCodecFlags(
111 OMXClient *client,
112 const sp<MetaData> &trackMeta,
James Dongfaf09ba2010-12-02 17:42:08 -0800113 const sp<MediaSource> &source,
114 uint32_t flags,
115 int64_t frameTimeUs,
116 int seekMode) {
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800117 sp<MediaSource> decoder =
118 OMXCodec::Create(
119 client->interface(), source->getFormat(), false, source,
Andreas Huber5a40e392010-10-18 09:57:42 -0700120 NULL, flags | OMXCodec::kClientNeedsFramebuffer);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800121
122 if (decoder.get() == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100123 ALOGV("unable to instantiate video decoder.");
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800124
125 return NULL;
126 }
127
Andreas Huber1919e5a2010-05-20 10:37:06 -0700128 status_t err = decoder->start();
129 if (err != OK) {
Steve Block8564c8d2012-01-05 23:22:43 +0000130 ALOGW("OMXCodec::start returned error %d (0x%08x)\n", err, err);
Andreas Huber1919e5a2010-05-20 10:37:06 -0700131 return NULL;
132 }
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800133
134 // Read one output buffer, ignore format change notifications
135 // and spurious empty buffers.
136
137 MediaSource::ReadOptions options;
James Dongfaf09ba2010-12-02 17:42:08 -0800138 if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
139 seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
140
Steve Block3762c312012-01-06 19:20:56 +0000141 ALOGE("Unknown seek mode: %d", seekMode);
James Dongfaf09ba2010-12-02 17:42:08 -0800142 return NULL;
143 }
144
145 MediaSource::ReadOptions::SeekMode mode =
146 static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
147
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800148 int64_t thumbNailTime;
Andreas Huberb1d49de2010-12-08 14:50:10 -0800149 if (frameTimeUs < 0) {
Andreas Huber87312e92011-04-11 10:57:29 -0700150 if (!trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)
151 || thumbNailTime < 0) {
Andreas Huberb1d49de2010-12-08 14:50:10 -0800152 thumbNailTime = 0;
153 }
James Dongfaf09ba2010-12-02 17:42:08 -0800154 options.setSeekTo(thumbNailTime, mode);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800155 } else {
156 thumbNailTime = -1;
James Dongfaf09ba2010-12-02 17:42:08 -0800157 options.setSeekTo(frameTimeUs, mode);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800158 }
159
160 MediaBuffer *buffer = NULL;
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800161 do {
162 if (buffer != NULL) {
163 buffer->release();
164 buffer = NULL;
165 }
166 err = decoder->read(&buffer, &options);
167 options.clearSeekTo();
168 } while (err == INFO_FORMAT_CHANGED
169 || (buffer != NULL && buffer->range_length() == 0));
170
171 if (err != OK) {
James Dong8e9d67a2012-02-06 23:46:37 -0800172 CHECK(buffer == NULL);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800173
Steve Block71f2cf12011-10-20 11:56:00 +0100174 ALOGV("decoding frame failed.");
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800175 decoder->stop();
176
177 return NULL;
178 }
179
Steve Block71f2cf12011-10-20 11:56:00 +0100180 ALOGV("successfully decoded video frame.");
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800181
Andreas Huber1e194162010-10-06 16:43:57 -0700182 int32_t unreadable;
183 if (buffer->meta_data()->findInt32(kKeyIsUnreadable, &unreadable)
184 && unreadable != 0) {
Steve Block71f2cf12011-10-20 11:56:00 +0100185 ALOGV("video frame is unreadable, decoder does not give us access "
Andreas Huber1e194162010-10-06 16:43:57 -0700186 "to the video data.");
187
188 buffer->release();
189 buffer = NULL;
190
191 decoder->stop();
192
193 return NULL;
194 }
195
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800196 int64_t timeUs;
197 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
198 if (thumbNailTime >= 0) {
199 if (timeUs != thumbNailTime) {
200 const char *mime;
201 CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
202
Steve Block71f2cf12011-10-20 11:56:00 +0100203 ALOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800204 thumbNailTime, timeUs, mime);
205 }
206 }
207
208 sp<MetaData> meta = decoder->getFormat();
209
210 int32_t width, height;
211 CHECK(meta->findInt32(kKeyWidth, &width));
212 CHECK(meta->findInt32(kKeyHeight, &height));
213
Andreas Huber1bb0ffd2010-11-22 13:06:35 -0800214 int32_t crop_left, crop_top, crop_right, crop_bottom;
215 if (!meta->findRect(
216 kKeyCropRect,
217 &crop_left, &crop_top, &crop_right, &crop_bottom)) {
218 crop_left = crop_top = 0;
219 crop_right = width - 1;
220 crop_bottom = height - 1;
221 }
222
James Dong53ebc722010-11-08 16:04:27 -0800223 int32_t rotationAngle;
224 if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
225 rotationAngle = 0; // By default, no rotation
226 }
227
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800228 VideoFrame *frame = new VideoFrame;
Andreas Huber1bb0ffd2010-11-22 13:06:35 -0800229 frame->mWidth = crop_right - crop_left + 1;
230 frame->mHeight = crop_bottom - crop_top + 1;
231 frame->mDisplayWidth = frame->mWidth;
232 frame->mDisplayHeight = frame->mHeight;
233 frame->mSize = frame->mWidth * frame->mHeight * 2;
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800234 frame->mData = new uint8_t[frame->mSize];
James Dong53ebc722010-11-08 16:04:27 -0800235 frame->mRotationAngle = rotationAngle;
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800236
James Dong9f2cde32011-03-18 17:55:06 -0700237 int32_t displayWidth, displayHeight;
238 if (meta->findInt32(kKeyDisplayWidth, &displayWidth)) {
239 frame->mDisplayWidth = displayWidth;
240 }
241 if (meta->findInt32(kKeyDisplayHeight, &displayHeight)) {
242 frame->mDisplayHeight = displayHeight;
243 }
244
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800245 int32_t srcFormat;
246 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
247
248 ColorConverter converter(
249 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
250 CHECK(converter.isValid());
251
Andreas Huberc0dbe3a2011-01-06 11:26:54 -0800252 err = converter.convert(
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800253 (const uint8_t *)buffer->data() + buffer->range_offset(),
Andreas Huber1bb0ffd2010-11-22 13:06:35 -0800254 width, height,
255 crop_left, crop_top, crop_right, crop_bottom,
256 frame->mData,
257 frame->mWidth,
258 frame->mHeight,
259 0, 0, frame->mWidth - 1, frame->mHeight - 1);
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800260
261 buffer->release();
262 buffer = NULL;
263
264 decoder->stop();
265
Andreas Huberc0dbe3a2011-01-06 11:26:54 -0800266 if (err != OK) {
Steve Block3762c312012-01-06 19:20:56 +0000267 ALOGE("Colorconverter failed to convert frame.");
Andreas Huberc0dbe3a2011-01-06 11:26:54 -0800268
269 delete frame;
270 frame = NULL;
271 }
272
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800273 return frame;
274}
275
James Dongfaf09ba2010-12-02 17:42:08 -0800276VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
277 int64_t timeUs, int option) {
Andreas Huber53a76bd2009-10-06 16:20:44 -0700278
Steve Block71f2cf12011-10-20 11:56:00 +0100279 ALOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
Andreas Hubere3452d32010-03-12 15:08:52 -0800280
Andreas Huber53a76bd2009-10-06 16:20:44 -0700281 if (mExtractor.get() == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100282 ALOGV("no extractor.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700283 return NULL;
284 }
285
Andreas Huber612e1612011-09-06 16:05:02 -0700286 sp<MetaData> fileMeta = mExtractor->getMetaData();
287
288 if (fileMeta == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100289 ALOGV("extractor doesn't publish metadata, failed to initialize?");
Andreas Huber612e1612011-09-06 16:05:02 -0700290 return NULL;
291 }
292
Glenn Kasten5f630692011-02-21 09:37:13 -0800293 int32_t drm = 0;
Andreas Huber612e1612011-09-06 16:05:02 -0700294 if (fileMeta->findInt32(kKeyIsDRM, &drm) && drm != 0) {
Steve Block3762c312012-01-06 19:20:56 +0000295 ALOGE("frame grab not allowed.");
Glenn Kasten5f630692011-02-21 09:37:13 -0800296 return NULL;
297 }
298
Andreas Huber53a76bd2009-10-06 16:20:44 -0700299 size_t n = mExtractor->countTracks();
300 size_t i;
301 for (i = 0; i < n; ++i) {
302 sp<MetaData> meta = mExtractor->getTrackMetaData(i);
303
304 const char *mime;
305 CHECK(meta->findCString(kKeyMIMEType, &mime));
306
307 if (!strncasecmp(mime, "video/", 6)) {
308 break;
309 }
310 }
311
312 if (i == n) {
Steve Block71f2cf12011-10-20 11:56:00 +0100313 ALOGV("no video track found.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700314 return NULL;
315 }
316
Andreas Hubere981c332009-10-22 13:49:30 -0700317 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
318 i, MediaExtractor::kIncludeExtensiveMetaData);
319
Andreas Huber53a76bd2009-10-06 16:20:44 -0700320 sp<MediaSource> source = mExtractor->getTrack(i);
321
322 if (source.get() == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100323 ALOGV("unable to instantiate video track.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700324 return NULL;
325 }
326
James Donge8b26dc2011-05-25 15:02:50 -0700327 const void *data;
328 uint32_t type;
329 size_t dataSize;
Andreas Huber612e1612011-09-06 16:05:02 -0700330 if (fileMeta->findData(kKeyAlbumArt, &type, &data, &dataSize)
James Donge8b26dc2011-05-25 15:02:50 -0700331 && mAlbumArt == NULL) {
332 mAlbumArt = new MediaAlbumArt;
333 mAlbumArt->mSize = dataSize;
334 mAlbumArt->mData = new uint8_t[dataSize];
335 memcpy(mAlbumArt->mData, data, dataSize);
336 }
337
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800338 VideoFrame *frame =
339 extractVideoFrameWithCodecFlags(
James Dongfaf09ba2010-12-02 17:42:08 -0800340 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
341 timeUs, option);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700342
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800343 if (frame == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100344 ALOGV("Software decoder failed to extract thumbnail, "
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800345 "trying hardware decoder.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700346
James Dongfaf09ba2010-12-02 17:42:08 -0800347 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
348 timeUs, option);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700349 }
350
Andreas Huber53a76bd2009-10-06 16:20:44 -0700351 return frame;
352}
353
354MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
Steve Block71f2cf12011-10-20 11:56:00 +0100355 ALOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700356
Andreas Huberaee3c632010-01-11 15:35:19 -0800357 if (mExtractor == NULL) {
358 return NULL;
359 }
360
361 if (!mParsedMetaData) {
362 parseMetaData();
363
364 mParsedMetaData = true;
365 }
366
367 if (mAlbumArt) {
368 return new MediaAlbumArt(*mAlbumArt);
369 }
370
Andreas Huber53a76bd2009-10-06 16:20:44 -0700371 return NULL;
372}
373
374const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
Andreas Huberaee3c632010-01-11 15:35:19 -0800375 if (mExtractor == NULL) {
376 return NULL;
377 }
378
379 if (!mParsedMetaData) {
380 parseMetaData();
381
382 mParsedMetaData = true;
383 }
384
385 ssize_t index = mMetaData.indexOfKey(keyCode);
386
387 if (index < 0) {
388 return NULL;
389 }
390
391 return strdup(mMetaData.valueAt(index).string());
Andreas Huber53a76bd2009-10-06 16:20:44 -0700392}
393
Andreas Huberaee3c632010-01-11 15:35:19 -0800394void StagefrightMetadataRetriever::parseMetaData() {
395 sp<MetaData> meta = mExtractor->getMetaData();
396
Andreas Huber612e1612011-09-06 16:05:02 -0700397 if (meta == NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +0100398 ALOGV("extractor doesn't publish metadata, failed to initialize?");
Andreas Huber612e1612011-09-06 16:05:02 -0700399 return;
400 }
401
Andreas Huberaee3c632010-01-11 15:35:19 -0800402 struct Map {
403 int from;
404 int to;
405 };
406 static const Map kMap[] = {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800407 { kKeyMIMEType, METADATA_KEY_MIMETYPE },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800408 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
Marco Nelissen655306f2010-02-08 14:50:19 -0800409 { kKeyDiscNumber, METADATA_KEY_DISC_NUMBER },
Andreas Huberaee3c632010-01-11 15:35:19 -0800410 { kKeyAlbum, METADATA_KEY_ALBUM },
411 { kKeyArtist, METADATA_KEY_ARTIST },
Marco Nelissenc5d5ee32010-02-11 13:31:44 -0800412 { kKeyAlbumArtist, METADATA_KEY_ALBUMARTIST },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800413 { kKeyAuthor, METADATA_KEY_AUTHOR },
Andreas Huberaee3c632010-01-11 15:35:19 -0800414 { kKeyComposer, METADATA_KEY_COMPOSER },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800415 { kKeyDate, METADATA_KEY_DATE },
Andreas Huberaee3c632010-01-11 15:35:19 -0800416 { kKeyGenre, METADATA_KEY_GENRE },
417 { kKeyTitle, METADATA_KEY_TITLE },
418 { kKeyYear, METADATA_KEY_YEAR },
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800419 { kKeyWriter, METADATA_KEY_WRITER },
Marco Nelissenee35aff2011-01-06 11:12:17 -0800420 { kKeyCompilation, METADATA_KEY_COMPILATION },
James Dong77c500c2011-11-09 00:48:56 -0800421 { kKeyLocation, METADATA_KEY_LOCATION },
Andreas Huberaee3c632010-01-11 15:35:19 -0800422 };
423 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
424
425 for (size_t i = 0; i < kNumMapEntries; ++i) {
426 const char *value;
427 if (meta->findCString(kMap[i].from, &value)) {
428 mMetaData.add(kMap[i].to, String8(value));
429 }
430 }
431
432 const void *data;
433 uint32_t type;
434 size_t dataSize;
James Donge8b26dc2011-05-25 15:02:50 -0700435 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)
436 && mAlbumArt == NULL) {
Andreas Huberaee3c632010-01-11 15:35:19 -0800437 mAlbumArt = new MediaAlbumArt;
438 mAlbumArt->mSize = dataSize;
439 mAlbumArt->mData = new uint8_t[dataSize];
440 memcpy(mAlbumArt->mData, data, dataSize);
441 }
442
Andreas Huber3a3656c2010-01-13 10:45:49 -0800443 size_t numTracks = mExtractor->countTracks();
444
445 char tmp[32];
446 sprintf(tmp, "%d", numTracks);
447
448 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
449
Andreas Huberc4c38fc2011-03-04 10:24:54 -0800450 bool hasAudio = false;
451 bool hasVideo = false;
452 int32_t videoWidth = -1;
453 int32_t videoHeight = -1;
454 int32_t audioBitrate = -1;
455
Andreas Huberaee3c632010-01-11 15:35:19 -0800456 // The overall duration is the duration of the longest track.
457 int64_t maxDurationUs = 0;
Gloria Wangc6091dd2011-05-03 15:59:03 -0700458 String8 timedTextLang;
Andreas Huber3a3656c2010-01-13 10:45:49 -0800459 for (size_t i = 0; i < numTracks; ++i) {
Andreas Huberaee3c632010-01-11 15:35:19 -0800460 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
461
462 int64_t durationUs;
463 if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
464 if (durationUs > maxDurationUs) {
465 maxDurationUs = durationUs;
466 }
467 }
Andreas Huberc4c38fc2011-03-04 10:24:54 -0800468
469 const char *mime;
470 if (trackMeta->findCString(kKeyMIMEType, &mime)) {
471 if (!hasAudio && !strncasecmp("audio/", mime, 6)) {
472 hasAudio = true;
473
474 if (!trackMeta->findInt32(kKeyBitRate, &audioBitrate)) {
475 audioBitrate = -1;
476 }
477 } else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
478 hasVideo = true;
479
480 CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
481 CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
Gloria Wangc6091dd2011-05-03 15:59:03 -0700482 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
483 const char *lang;
484 trackMeta->findCString(kKeyMediaLanguage, &lang);
485 timedTextLang.append(String8(lang));
486 timedTextLang.append(String8(":"));
Andreas Huberc4c38fc2011-03-04 10:24:54 -0800487 }
488 }
Andreas Huberaee3c632010-01-11 15:35:19 -0800489 }
490
Gloria Wangc6091dd2011-05-03 15:59:03 -0700491 // To save the language codes for all timed text tracks
492 // If multiple text tracks present, the format will look
493 // like "eng:chi"
494 if (!timedTextLang.isEmpty()) {
495 mMetaData.add(METADATA_KEY_TIMED_TEXT_LANGUAGES, timedTextLang);
496 }
497
Andreas Huberaee3c632010-01-11 15:35:19 -0800498 // The duration value is a string representing the duration in ms.
Andreas Huberaee3c632010-01-11 15:35:19 -0800499 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
Andreas Huberaee3c632010-01-11 15:35:19 -0800500 mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
Andreas Huber072f5242010-05-20 14:56:53 -0700501
Andreas Huberc4c38fc2011-03-04 10:24:54 -0800502 if (hasAudio) {
503 mMetaData.add(METADATA_KEY_HAS_AUDIO, String8("yes"));
504 }
505
506 if (hasVideo) {
507 mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
508
509 sprintf(tmp, "%d", videoWidth);
510 mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
511
512 sprintf(tmp, "%d", videoHeight);
513 mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
514 }
515
516 if (numTracks == 1 && hasAudio && audioBitrate >= 0) {
James Dong9f2cde32011-03-18 17:55:06 -0700517 sprintf(tmp, "%d", audioBitrate);
Andreas Huberc4c38fc2011-03-04 10:24:54 -0800518 mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
519 } else {
520 off64_t sourceSize;
521 if (mSource->getSize(&sourceSize) == OK) {
522 int64_t avgBitRate = (int64_t)(sourceSize * 8E6 / maxDurationUs);
523
524 sprintf(tmp, "%lld", avgBitRate);
525 mMetaData.add(METADATA_KEY_BITRATE, String8(tmp));
526 }
527 }
528
Andreas Huber072f5242010-05-20 14:56:53 -0700529 if (numTracks == 1) {
530 const char *fileMIME;
531 CHECK(meta->findCString(kKeyMIMEType, &fileMIME));
532
533 if (!strcasecmp(fileMIME, "video/x-matroska")) {
534 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
535 const char *trackMIME;
536 CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
537
538 if (!strncasecmp("audio/", trackMIME, 6)) {
539 // The matroska file only contains a single audio track,
540 // rewrite its mime type.
541 mMetaData.add(
542 METADATA_KEY_MIMETYPE, String8("audio/x-matroska"));
543 }
544 }
545 }
Gloria Wang82428a82011-06-27 11:09:00 -0700546
547 // To check whether the media file is drm-protected
548 if (mExtractor->getDrmFlag()) {
549 mMetaData.add(METADATA_KEY_IS_DRM, String8("1"));
550 }
Andreas Huberaee3c632010-01-11 15:35:19 -0800551}
552
Andreas Huber53a76bd2009-10-06 16:20:44 -0700553} // namespace android