blob: 313a9ed8176fd220f25310cf2db4ad6ceb97d139 [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
23#include <media/stagefright/CachingDataSource.h>
24#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/HTTPDataSource.h>
28#include <media/stagefright/MediaDebug.h>
29#include <media/stagefright/MediaExtractor.h>
30#include <media/stagefright/MetaData.h>
Andreas Huber53a76bd2009-10-06 16:20:44 -070031#include <media/stagefright/OMXCodec.h>
32
33namespace android {
34
Andreas Huberaee3c632010-01-11 15:35:19 -080035StagefrightMetadataRetriever::StagefrightMetadataRetriever()
36 : mParsedMetaData(false),
37 mAlbumArt(NULL) {
Andreas Huber53a76bd2009-10-06 16:20:44 -070038 LOGV("StagefrightMetadataRetriever()");
39
40 DataSource::RegisterDefaultSniffers();
41 CHECK_EQ(mClient.connect(), OK);
42}
43
44StagefrightMetadataRetriever::~StagefrightMetadataRetriever() {
45 LOGV("~StagefrightMetadataRetriever()");
Andreas Huberaee3c632010-01-11 15:35:19 -080046
47 delete mAlbumArt;
48 mAlbumArt = NULL;
49
Andreas Huber53a76bd2009-10-06 16:20:44 -070050 mClient.disconnect();
51}
52
53status_t StagefrightMetadataRetriever::setDataSource(const char *uri) {
54 LOGV("setDataSource(%s)", uri);
55
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 Huberaee3c632010-01-11 15:35:19 -080061 mSource = DataSource::CreateFromURI(uri);
62
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
Andreas Huber53a76bd2009-10-06 16:20:44 -070083 LOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
84
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,
113 const sp<MediaSource> &source, uint32_t flags) {
114 sp<MediaSource> decoder =
115 OMXCodec::Create(
116 client->interface(), source->getFormat(), false, source,
117 NULL, flags);
118
119 if (decoder.get() == NULL) {
120 LOGV("unable to instantiate video decoder.");
121
122 return NULL;
123 }
124
125 decoder->start();
126
127 // Read one output buffer, ignore format change notifications
128 // and spurious empty buffers.
129
130 MediaSource::ReadOptions options;
131 int64_t thumbNailTime;
132 if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
133 options.setSeekTo(thumbNailTime);
134 } else {
135 thumbNailTime = -1;
136 }
137
138 MediaBuffer *buffer = NULL;
139 status_t err;
140 do {
141 if (buffer != NULL) {
142 buffer->release();
143 buffer = NULL;
144 }
145 err = decoder->read(&buffer, &options);
146 options.clearSeekTo();
147 } while (err == INFO_FORMAT_CHANGED
148 || (buffer != NULL && buffer->range_length() == 0));
149
150 if (err != OK) {
151 CHECK_EQ(buffer, NULL);
152
153 LOGV("decoding frame failed.");
154 decoder->stop();
155
156 return NULL;
157 }
158
159 LOGV("successfully decoded video frame.");
160
161 int64_t timeUs;
162 CHECK(buffer->meta_data()->findInt64(kKeyTime, &timeUs));
163 if (thumbNailTime >= 0) {
164 if (timeUs != thumbNailTime) {
165 const char *mime;
166 CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
167
168 LOGV("thumbNailTime = %lld us, timeUs = %lld us, mime = %s",
169 thumbNailTime, timeUs, mime);
170 }
171 }
172
173 sp<MetaData> meta = decoder->getFormat();
174
175 int32_t width, height;
176 CHECK(meta->findInt32(kKeyWidth, &width));
177 CHECK(meta->findInt32(kKeyHeight, &height));
178
179 VideoFrame *frame = new VideoFrame;
180 frame->mWidth = width;
181 frame->mHeight = height;
182 frame->mDisplayWidth = width;
183 frame->mDisplayHeight = height;
184 frame->mSize = width * height * 2;
185 frame->mData = new uint8_t[frame->mSize];
186
187 int32_t srcFormat;
188 CHECK(meta->findInt32(kKeyColorFormat, &srcFormat));
189
190 ColorConverter converter(
191 (OMX_COLOR_FORMATTYPE)srcFormat, OMX_COLOR_Format16bitRGB565);
192 CHECK(converter.isValid());
193
194 converter.convert(
195 width, height,
196 (const uint8_t *)buffer->data() + buffer->range_offset(),
197 0,
198 frame->mData, width * 2);
199
200 buffer->release();
201 buffer = NULL;
202
203 decoder->stop();
204
205 return frame;
206}
207
Andreas Huber53a76bd2009-10-06 16:20:44 -0700208VideoFrame *StagefrightMetadataRetriever::captureFrame() {
209 LOGV("captureFrame");
210
211 if (mExtractor.get() == NULL) {
Andreas Huberad285432009-10-22 09:44:00 -0700212 LOGV("no extractor.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700213 return NULL;
214 }
215
216 size_t n = mExtractor->countTracks();
217 size_t i;
218 for (i = 0; i < n; ++i) {
219 sp<MetaData> meta = mExtractor->getTrackMetaData(i);
220
221 const char *mime;
222 CHECK(meta->findCString(kKeyMIMEType, &mime));
223
224 if (!strncasecmp(mime, "video/", 6)) {
225 break;
226 }
227 }
228
229 if (i == n) {
Andreas Huberad285432009-10-22 09:44:00 -0700230 LOGV("no video track found.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700231 return NULL;
232 }
233
Andreas Hubere981c332009-10-22 13:49:30 -0700234 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
235 i, MediaExtractor::kIncludeExtensiveMetaData);
236
Andreas Huber53a76bd2009-10-06 16:20:44 -0700237 sp<MediaSource> source = mExtractor->getTrack(i);
238
239 if (source.get() == NULL) {
Andreas Huberad285432009-10-22 09:44:00 -0700240 LOGV("unable to instantiate video track.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700241 return NULL;
242 }
243
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800244 VideoFrame *frame =
245 extractVideoFrameWithCodecFlags(
246 &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700247
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800248 if (frame == NULL) {
249 LOGV("Software decoder failed to extract thumbnail, "
250 "trying hardware decoder.");
Andreas Huber53a76bd2009-10-06 16:20:44 -0700251
Andreas Huber0ffc90f2010-01-14 14:15:33 -0800252 frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700253 }
254
Andreas Huber53a76bd2009-10-06 16:20:44 -0700255 return frame;
256}
257
258MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
259 LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
260
Andreas Huberaee3c632010-01-11 15:35:19 -0800261 if (mExtractor == NULL) {
262 return NULL;
263 }
264
265 if (!mParsedMetaData) {
266 parseMetaData();
267
268 mParsedMetaData = true;
269 }
270
271 if (mAlbumArt) {
272 return new MediaAlbumArt(*mAlbumArt);
273 }
274
Andreas Huber53a76bd2009-10-06 16:20:44 -0700275 return NULL;
276}
277
278const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
Andreas Huberaee3c632010-01-11 15:35:19 -0800279 LOGV("extractMetadata %d", keyCode);
Andreas Huber53a76bd2009-10-06 16:20:44 -0700280
Andreas Huberaee3c632010-01-11 15:35:19 -0800281 if (mExtractor == NULL) {
282 return NULL;
283 }
284
285 if (!mParsedMetaData) {
286 parseMetaData();
287
288 mParsedMetaData = true;
289 }
290
291 ssize_t index = mMetaData.indexOfKey(keyCode);
292
293 if (index < 0) {
294 return NULL;
295 }
296
297 return strdup(mMetaData.valueAt(index).string());
Andreas Huber53a76bd2009-10-06 16:20:44 -0700298}
299
Andreas Huberaee3c632010-01-11 15:35:19 -0800300void StagefrightMetadataRetriever::parseMetaData() {
301 sp<MetaData> meta = mExtractor->getMetaData();
302
303 struct Map {
304 int from;
305 int to;
306 };
307 static const Map kMap[] = {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800308 { kKeyMIMEType, METADATA_KEY_MIMETYPE },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800309 { kKeyCDTrackNumber, METADATA_KEY_CD_TRACK_NUMBER },
Andreas Huberaee3c632010-01-11 15:35:19 -0800310 { kKeyAlbum, METADATA_KEY_ALBUM },
311 { kKeyArtist, METADATA_KEY_ARTIST },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800312 { kKeyAuthor, METADATA_KEY_AUTHOR },
Andreas Huberaee3c632010-01-11 15:35:19 -0800313 { kKeyComposer, METADATA_KEY_COMPOSER },
Andreas Huber3a3656c2010-01-13 10:45:49 -0800314 { kKeyDate, METADATA_KEY_DATE },
Andreas Huberaee3c632010-01-11 15:35:19 -0800315 { kKeyGenre, METADATA_KEY_GENRE },
316 { kKeyTitle, METADATA_KEY_TITLE },
317 { kKeyYear, METADATA_KEY_YEAR },
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800318 { kKeyWriter, METADATA_KEY_WRITER },
Andreas Huberaee3c632010-01-11 15:35:19 -0800319 };
320 static const size_t kNumMapEntries = sizeof(kMap) / sizeof(kMap[0]);
321
322 for (size_t i = 0; i < kNumMapEntries; ++i) {
323 const char *value;
324 if (meta->findCString(kMap[i].from, &value)) {
325 mMetaData.add(kMap[i].to, String8(value));
326 }
327 }
328
329 const void *data;
330 uint32_t type;
331 size_t dataSize;
332 if (meta->findData(kKeyAlbumArt, &type, &data, &dataSize)) {
333 mAlbumArt = new MediaAlbumArt;
334 mAlbumArt->mSize = dataSize;
335 mAlbumArt->mData = new uint8_t[dataSize];
336 memcpy(mAlbumArt->mData, data, dataSize);
337 }
338
Andreas Huber3a3656c2010-01-13 10:45:49 -0800339 size_t numTracks = mExtractor->countTracks();
340
341 char tmp[32];
342 sprintf(tmp, "%d", numTracks);
343
344 mMetaData.add(METADATA_KEY_NUM_TRACKS, String8(tmp));
345
Andreas Huberaee3c632010-01-11 15:35:19 -0800346 // The overall duration is the duration of the longest track.
347 int64_t maxDurationUs = 0;
Andreas Huber3a3656c2010-01-13 10:45:49 -0800348 for (size_t i = 0; i < numTracks; ++i) {
Andreas Huberaee3c632010-01-11 15:35:19 -0800349 sp<MetaData> trackMeta = mExtractor->getTrackMetaData(i);
350
351 int64_t durationUs;
352 if (trackMeta->findInt64(kKeyDuration, &durationUs)) {
353 if (durationUs > maxDurationUs) {
354 maxDurationUs = durationUs;
355 }
356 }
357 }
358
359 // The duration value is a string representing the duration in ms.
Andreas Huberaee3c632010-01-11 15:35:19 -0800360 sprintf(tmp, "%lld", (maxDurationUs + 500) / 1000);
Andreas Huberaee3c632010-01-11 15:35:19 -0800361 mMetaData.add(METADATA_KEY_DURATION, String8(tmp));
362}
363
364
Andreas Huber53a76bd2009-10-06 16:20:44 -0700365} // namespace android