blob: 26b8a4200c614e17274b9714302774725fcfd2bb [file] [log] [blame]
Andreas Hubere46b7be2009-07-14 16:56:47 -07001/*
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_TAG "MPEG4Extractor"
18#include <utils/Log.h>
19
Andreas Huber57515f32009-10-23 09:55:10 -070020#include "include/MPEG4Extractor.h"
Andreas Huberbd7b43b2009-10-13 10:22:55 -070021#include "include/SampleTable.h"
Gloria Wangc6091dd2011-05-03 15:59:03 -070022#include "include/ESDS.h"
Gloria Wang13bc8cd2011-05-11 11:24:09 -070023#include "timedtext/TimedTextPlayer.h"
Andreas Huberbd7b43b2009-10-13 10:22:55 -070024
Andreas Hubere46b7be2009-07-14 16:56:47 -070025#include <arpa/inet.h>
26
Andreas Hubere46b7be2009-07-14 16:56:47 -070027#include <ctype.h>
28#include <stdint.h>
29#include <stdlib.h>
30#include <string.h>
31
Andreas Huber940c8662010-11-16 15:26:30 -080032#include <media/stagefright/foundation/ADebug.h>
Andreas Huberb8e651a2011-12-05 11:34:43 -080033#include <media/stagefright/foundation/AMessage.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070034#include <media/stagefright/DataSource.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070035#include <media/stagefright/MediaBuffer.h>
36#include <media/stagefright/MediaBufferGroup.h>
Andreas Hubere6c40962009-09-10 14:13:30 -070037#include <media/stagefright/MediaDefs.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070038#include <media/stagefright/MediaSource.h>
39#include <media/stagefright/MetaData.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070040#include <media/stagefright/Utils.h>
41#include <utils/String8.h>
42
43namespace android {
44
45class MPEG4Source : public MediaSource {
46public:
47 // Caller retains ownership of both "dataSource" and "sampleTable".
Andreas Huberbe06d262009-08-14 14:37:10 -070048 MPEG4Source(const sp<MetaData> &format,
49 const sp<DataSource> &dataSource,
Andreas Huberfa8de752009-10-08 10:07:49 -070050 int32_t timeScale,
Andreas Huberbe06d262009-08-14 14:37:10 -070051 const sp<SampleTable> &sampleTable);
Andreas Hubere46b7be2009-07-14 16:56:47 -070052
53 virtual status_t start(MetaData *params = NULL);
54 virtual status_t stop();
55
56 virtual sp<MetaData> getFormat();
57
58 virtual status_t read(
59 MediaBuffer **buffer, const ReadOptions *options = NULL);
60
Andreas Huberbe06d262009-08-14 14:37:10 -070061protected:
62 virtual ~MPEG4Source();
63
Andreas Hubere46b7be2009-07-14 16:56:47 -070064private:
Andreas Huberba7ec912010-02-12 10:42:02 -080065 Mutex mLock;
66
Andreas Hubere46b7be2009-07-14 16:56:47 -070067 sp<MetaData> mFormat;
Andreas Huberbe06d262009-08-14 14:37:10 -070068 sp<DataSource> mDataSource;
Andreas Hubere46b7be2009-07-14 16:56:47 -070069 int32_t mTimescale;
Andreas Huberbe06d262009-08-14 14:37:10 -070070 sp<SampleTable> mSampleTable;
Andreas Hubere46b7be2009-07-14 16:56:47 -070071 uint32_t mCurrentSampleIndex;
72
73 bool mIsAVC;
Andreas Huberdb5d6622010-01-12 16:30:44 -080074 size_t mNALLengthSize;
75
Andreas Hubere46b7be2009-07-14 16:56:47 -070076 bool mStarted;
77
78 MediaBufferGroup *mGroup;
79
80 MediaBuffer *mBuffer;
Andreas Hubere46b7be2009-07-14 16:56:47 -070081
Andreas Huber4f5e6022009-08-19 09:29:34 -070082 bool mWantsNALFragments;
Andreas Hubere46b7be2009-07-14 16:56:47 -070083
Andreas Huber8a432772009-07-28 10:03:13 -070084 uint8_t *mSrcBuffer;
85
Andreas Huberdb5d6622010-01-12 16:30:44 -080086 size_t parseNALSize(const uint8_t *data) const;
87
Andreas Hubere46b7be2009-07-14 16:56:47 -070088 MPEG4Source(const MPEG4Source &);
89 MPEG4Source &operator=(const MPEG4Source &);
90};
91
Andreas Huberaffa99c2010-01-28 14:27:37 -080092// This custom data source wraps an existing one and satisfies requests
93// falling entirely within a cached range from the cache while forwarding
94// all remaining requests to the wrapped datasource.
95// This is used to cache the full sampletable metadata for a single track,
96// possibly wrapping multiple times to cover all tracks, i.e.
97// Each MPEG4DataSource caches the sampletable metadata for a single track.
98
99struct MPEG4DataSource : public DataSource {
100 MPEG4DataSource(const sp<DataSource> &source);
101
102 virtual status_t initCheck() const;
James Dongb1262a82010-11-16 14:04:54 -0800103 virtual ssize_t readAt(off64_t offset, void *data, size_t size);
104 virtual status_t getSize(off64_t *size);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800105 virtual uint32_t flags();
106
James Dongb1262a82010-11-16 14:04:54 -0800107 status_t setCachedRange(off64_t offset, size_t size);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800108
109protected:
110 virtual ~MPEG4DataSource();
111
112private:
113 Mutex mLock;
114
115 sp<DataSource> mSource;
James Dongb1262a82010-11-16 14:04:54 -0800116 off64_t mCachedOffset;
Andreas Huberaffa99c2010-01-28 14:27:37 -0800117 size_t mCachedSize;
118 uint8_t *mCache;
119
120 void clearCache();
121
122 MPEG4DataSource(const MPEG4DataSource &);
123 MPEG4DataSource &operator=(const MPEG4DataSource &);
124};
125
126MPEG4DataSource::MPEG4DataSource(const sp<DataSource> &source)
127 : mSource(source),
128 mCachedOffset(0),
129 mCachedSize(0),
130 mCache(NULL) {
131}
132
133MPEG4DataSource::~MPEG4DataSource() {
134 clearCache();
135}
136
137void MPEG4DataSource::clearCache() {
138 if (mCache) {
139 free(mCache);
140 mCache = NULL;
141 }
142
143 mCachedOffset = 0;
144 mCachedSize = 0;
145}
146
147status_t MPEG4DataSource::initCheck() const {
148 return mSource->initCheck();
149}
150
James Dongb1262a82010-11-16 14:04:54 -0800151ssize_t MPEG4DataSource::readAt(off64_t offset, void *data, size_t size) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800152 Mutex::Autolock autoLock(mLock);
153
154 if (offset >= mCachedOffset
155 && offset + size <= mCachedOffset + mCachedSize) {
156 memcpy(data, &mCache[offset - mCachedOffset], size);
157 return size;
158 }
159
160 return mSource->readAt(offset, data, size);
161}
162
James Dongb1262a82010-11-16 14:04:54 -0800163status_t MPEG4DataSource::getSize(off64_t *size) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800164 return mSource->getSize(size);
165}
166
167uint32_t MPEG4DataSource::flags() {
168 return mSource->flags();
169}
170
James Dongb1262a82010-11-16 14:04:54 -0800171status_t MPEG4DataSource::setCachedRange(off64_t offset, size_t size) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800172 Mutex::Autolock autoLock(mLock);
173
174 clearCache();
175
176 mCache = (uint8_t *)malloc(size);
177
178 if (mCache == NULL) {
179 return -ENOMEM;
180 }
181
182 mCachedOffset = offset;
183 mCachedSize = size;
184
185 ssize_t err = mSource->readAt(mCachedOffset, mCache, mCachedSize);
186
187 if (err < (ssize_t)size) {
188 clearCache();
189
190 return ERROR_IO;
191 }
192
193 return OK;
194}
195
196////////////////////////////////////////////////////////////////////////////////
197
Andreas Hubere46b7be2009-07-14 16:56:47 -0700198static void hexdump(const void *_data, size_t size) {
199 const uint8_t *data = (const uint8_t *)_data;
200 size_t offset = 0;
201 while (offset < size) {
202 printf("0x%04x ", offset);
203
204 size_t n = size - offset;
205 if (n > 16) {
206 n = 16;
207 }
208
209 for (size_t i = 0; i < 16; ++i) {
210 if (i == 8) {
211 printf(" ");
212 }
213
214 if (offset + i < size) {
215 printf("%02x ", data[offset + i]);
216 } else {
217 printf(" ");
218 }
219 }
220
221 printf(" ");
222
223 for (size_t i = 0; i < n; ++i) {
224 if (isprint(data[offset + i])) {
225 printf("%c", data[offset + i]);
226 } else {
227 printf(".");
228 }
229 }
230
231 printf("\n");
232
233 offset += 16;
234 }
235}
236
Andreas Hubere6c40962009-09-10 14:13:30 -0700237static const char *FourCC2MIME(uint32_t fourcc) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700238 switch (fourcc) {
239 case FOURCC('m', 'p', '4', 'a'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700240 return MEDIA_MIMETYPE_AUDIO_AAC;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700241
242 case FOURCC('s', 'a', 'm', 'r'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700243 return MEDIA_MIMETYPE_AUDIO_AMR_NB;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700244
Andreas Huber2a651172009-09-09 16:32:59 -0700245 case FOURCC('s', 'a', 'w', 'b'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700246 return MEDIA_MIMETYPE_AUDIO_AMR_WB;
Andreas Huber2a651172009-09-09 16:32:59 -0700247
Andreas Hubere46b7be2009-07-14 16:56:47 -0700248 case FOURCC('m', 'p', '4', 'v'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700249 return MEDIA_MIMETYPE_VIDEO_MPEG4;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700250
251 case FOURCC('s', '2', '6', '3'):
James Dong0efdc952010-12-15 15:49:46 -0800252 case FOURCC('h', '2', '6', '3'):
253 case FOURCC('H', '2', '6', '3'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700254 return MEDIA_MIMETYPE_VIDEO_H263;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700255
256 case FOURCC('a', 'v', 'c', '1'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700257 return MEDIA_MIMETYPE_VIDEO_AVC;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700258
259 default:
Andreas Huber4f5e6022009-08-19 09:29:34 -0700260 CHECK(!"should not be here.");
Andreas Hubere46b7be2009-07-14 16:56:47 -0700261 return NULL;
262 }
263}
264
Andreas Huberbe06d262009-08-14 14:37:10 -0700265MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
Andreas Hubere46b7be2009-07-14 16:56:47 -0700266 : mDataSource(source),
Andreas Huberf80e45a2011-03-03 13:48:41 -0800267 mInitCheck(NO_INIT),
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800268 mHasVideo(false),
Andreas Hubere46b7be2009-07-14 16:56:47 -0700269 mFirstTrack(NULL),
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800270 mLastTrack(NULL),
Gloria Wangd5770912010-06-22 13:55:38 -0700271 mFileMetaData(new MetaData),
272 mFirstSINF(NULL),
273 mIsDrm(false) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700274}
275
276MPEG4Extractor::~MPEG4Extractor() {
277 Track *track = mFirstTrack;
278 while (track) {
279 Track *next = track->next;
280
Andreas Hubere46b7be2009-07-14 16:56:47 -0700281 delete track;
282 track = next;
283 }
284 mFirstTrack = mLastTrack = NULL;
Gloria Wangd5770912010-06-22 13:55:38 -0700285
286 SINF *sinf = mFirstSINF;
287 while (sinf) {
288 SINF *next = sinf->next;
289 delete sinf->IPMPData;
290 delete sinf;
291 sinf = next;
292 }
293 mFirstSINF = NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700294}
295
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800296sp<MetaData> MPEG4Extractor::getMetaData() {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800297 status_t err;
298 if ((err = readMetaData()) != OK) {
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800299 return new MetaData;
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800300 }
301
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800302 return mFileMetaData;
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800303}
304
Andreas Huberbe06d262009-08-14 14:37:10 -0700305size_t MPEG4Extractor::countTracks() {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700306 status_t err;
307 if ((err = readMetaData()) != OK) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700308 return 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700309 }
310
Andreas Huberbe06d262009-08-14 14:37:10 -0700311 size_t n = 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700312 Track *track = mFirstTrack;
313 while (track) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700314 ++n;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700315 track = track->next;
316 }
317
Andreas Huberbe06d262009-08-14 14:37:10 -0700318 return n;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700319}
320
Andreas Hubere981c332009-10-22 13:49:30 -0700321sp<MetaData> MPEG4Extractor::getTrackMetaData(
322 size_t index, uint32_t flags) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700323 status_t err;
324 if ((err = readMetaData()) != OK) {
325 return NULL;
326 }
327
328 Track *track = mFirstTrack;
329 while (index > 0) {
330 if (track == NULL) {
331 return NULL;
332 }
333
334 track = track->next;
335 --index;
336 }
337
Andreas Huber2a651172009-09-09 16:32:59 -0700338 if (track == NULL) {
339 return NULL;
340 }
341
Andreas Hubere981c332009-10-22 13:49:30 -0700342 if ((flags & kIncludeExtensiveMetaData)
343 && !track->includes_expensive_metadata) {
344 track->includes_expensive_metadata = true;
345
346 const char *mime;
347 CHECK(track->meta->findCString(kKeyMIMEType, &mime));
348 if (!strncasecmp("video/", mime, 6)) {
349 uint32_t sampleIndex;
350 uint32_t sampleTime;
351 if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
Andreas Huber1faa92a2010-01-19 10:39:21 -0800352 && track->sampleTable->getMetaDataForSample(
353 sampleIndex, NULL /* offset */, NULL /* size */,
354 &sampleTime) == OK) {
Andreas Hubere981c332009-10-22 13:49:30 -0700355 track->meta->setInt64(
356 kKeyThumbnailTime,
357 ((int64_t)sampleTime * 1000000) / track->timescale);
358 }
359 }
360 }
361
Andreas Hubere46b7be2009-07-14 16:56:47 -0700362 return track->meta;
363}
364
365status_t MPEG4Extractor::readMetaData() {
Andreas Huberf80e45a2011-03-03 13:48:41 -0800366 if (mInitCheck != NO_INIT) {
367 return mInitCheck;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700368 }
369
James Dongb1262a82010-11-16 14:04:54 -0800370 off64_t offset = 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700371 status_t err;
372 while ((err = parseChunk(&offset, 0)) == OK) {
373 }
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800374
Andreas Huberf80e45a2011-03-03 13:48:41 -0800375 if (mInitCheck == OK) {
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800376 if (mHasVideo) {
377 mFileMetaData->setCString(kKeyMIMEType, "video/mp4");
378 } else {
379 mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
380 }
381
Andreas Huber44fdac02011-04-15 11:52:29 -0700382 mInitCheck = OK;
Andreas Huberf80e45a2011-03-03 13:48:41 -0800383 } else {
384 mInitCheck = err;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700385 }
386
Andreas Huberf80e45a2011-03-03 13:48:41 -0800387 CHECK_NE(err, (status_t)NO_INIT);
388 return mInitCheck;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700389}
390
Gloria Wangd5770912010-06-22 13:55:38 -0700391char* MPEG4Extractor::getDrmTrackInfo(size_t trackID, int *len) {
392 if (mFirstSINF == NULL) {
393 return NULL;
394 }
395
396 SINF *sinf = mFirstSINF;
397 while (sinf && (trackID != sinf->trackID)) {
398 sinf = sinf->next;
399 }
400
401 if (sinf == NULL) {
402 return NULL;
403 }
404
405 *len = sinf->len;
406 return sinf->IPMPData;
407}
408
409// Reads an encoded integer 7 bits at a time until it encounters the high bit clear.
James Dongb1262a82010-11-16 14:04:54 -0800410int32_t readSize(off64_t offset,
Gloria Wangd5770912010-06-22 13:55:38 -0700411 const sp<DataSource> DataSource, uint8_t *numOfBytes) {
412 uint32_t size = 0;
413 uint8_t data;
414 bool moreData = true;
415 *numOfBytes = 0;
416
417 while (moreData) {
418 if (DataSource->readAt(offset, &data, 1) < 1) {
419 return -1;
420 }
421 offset ++;
422 moreData = (data >= 128) ? true : false;
423 size = (size << 7) | (data & 0x7f); // Take last 7 bits
424 (*numOfBytes) ++;
425 }
426
427 return size;
428}
429
James Dongb1262a82010-11-16 14:04:54 -0800430status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) {
Gloria Wangd5770912010-06-22 13:55:38 -0700431 uint8_t updateIdTag;
432 if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
433 return ERROR_IO;
434 }
435 data_offset ++;
436
437 if (0x01/*OBJECT_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
438 return ERROR_MALFORMED;
439 }
440
441 uint8_t numOfBytes;
442 int32_t size = readSize(data_offset, mDataSource, &numOfBytes);
443 if (size < 0) {
444 return ERROR_IO;
445 }
446 int32_t classSize = size;
447 data_offset += numOfBytes;
448
449 while(size >= 11 ) {
450 uint8_t descriptorTag;
451 if (mDataSource->readAt(data_offset, &descriptorTag, 1) < 1) {
452 return ERROR_IO;
453 }
454 data_offset ++;
455
456 if (0x11/*OBJECT_DESCRIPTOR_ID_TAG*/ != descriptorTag) {
457 return ERROR_MALFORMED;
458 }
459
460 uint8_t buffer[8];
461 //ObjectDescriptorID and ObjectDescriptor url flag
462 if (mDataSource->readAt(data_offset, buffer, 2) < 2) {
463 return ERROR_IO;
464 }
465 data_offset += 2;
466
467 if ((buffer[1] >> 5) & 0x0001) { //url flag is set
468 return ERROR_MALFORMED;
469 }
470
471 if (mDataSource->readAt(data_offset, buffer, 8) < 8) {
472 return ERROR_IO;
473 }
474 data_offset += 8;
475
476 if ((0x0F/*ES_ID_REF_TAG*/ != buffer[1])
477 || ( 0x0A/*IPMP_DESCRIPTOR_POINTER_ID_TAG*/ != buffer[5])) {
478 return ERROR_MALFORMED;
479 }
480
481 SINF *sinf = new SINF;
482 sinf->trackID = U16_AT(&buffer[3]);
483 sinf->IPMPDescriptorID = buffer[7];
484 sinf->next = mFirstSINF;
485 mFirstSINF = sinf;
486
487 size -= (8 + 2 + 1);
488 }
489
490 if (size != 0) {
491 return ERROR_MALFORMED;
492 }
493
494 if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
495 return ERROR_IO;
496 }
497 data_offset ++;
498
499 if(0x05/*IPMP_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
500 return ERROR_MALFORMED;
501 }
502
503 size = readSize(data_offset, mDataSource, &numOfBytes);
504 if (size < 0) {
505 return ERROR_IO;
506 }
507 classSize = size;
508 data_offset += numOfBytes;
509
510 while (size > 0) {
511 uint8_t tag;
512 int32_t dataLen;
513 if (mDataSource->readAt(data_offset, &tag, 1) < 1) {
514 return ERROR_IO;
515 }
516 data_offset ++;
517
518 if (0x0B/*IPMP_DESCRIPTOR_ID_TAG*/ == tag) {
519 uint8_t id;
520 dataLen = readSize(data_offset, mDataSource, &numOfBytes);
521 if (dataLen < 0) {
522 return ERROR_IO;
523 } else if (dataLen < 4) {
524 return ERROR_MALFORMED;
525 }
526 data_offset += numOfBytes;
527
528 if (mDataSource->readAt(data_offset, &id, 1) < 1) {
529 return ERROR_IO;
530 }
531 data_offset ++;
532
533 SINF *sinf = mFirstSINF;
534 while (sinf && (sinf->IPMPDescriptorID != id)) {
535 sinf = sinf->next;
536 }
537 if (sinf == NULL) {
538 return ERROR_MALFORMED;
539 }
540 sinf->len = dataLen - 3;
541 sinf->IPMPData = new char[sinf->len];
542
543 if (mDataSource->readAt(data_offset + 2, sinf->IPMPData, sinf->len) < sinf->len) {
544 return ERROR_IO;
545 }
546 data_offset += sinf->len;
547
548 size -= (dataLen + numOfBytes + 1);
549 }
550 }
551
552 if (size != 0) {
553 return ERROR_MALFORMED;
554 }
555
556 return UNKNOWN_ERROR; // Return a dummy error.
557}
558
Andreas Hubere46b7be2009-07-14 16:56:47 -0700559static void MakeFourCCString(uint32_t x, char *s) {
560 s[0] = x >> 24;
561 s[1] = (x >> 16) & 0xff;
562 s[2] = (x >> 8) & 0xff;
563 s[3] = x & 0xff;
564 s[4] = '\0';
565}
566
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800567struct PathAdder {
568 PathAdder(Vector<uint32_t> *path, uint32_t chunkType)
569 : mPath(path) {
570 mPath->push(chunkType);
571 }
572
573 ~PathAdder() {
574 mPath->pop();
575 }
576
577private:
578 Vector<uint32_t> *mPath;
579
580 PathAdder(const PathAdder &);
581 PathAdder &operator=(const PathAdder &);
582};
583
584static bool underMetaDataPath(const Vector<uint32_t> &path) {
585 return path.size() >= 5
586 && path[0] == FOURCC('m', 'o', 'o', 'v')
587 && path[1] == FOURCC('u', 'd', 't', 'a')
588 && path[2] == FOURCC('m', 'e', 't', 'a')
589 && path[3] == FOURCC('i', 'l', 's', 't');
590}
591
592// Given a time in seconds since Jan 1 1904, produce a human-readable string.
593static void convertTimeToDate(int64_t time_1904, String8 *s) {
594 time_t time_1970 = time_1904 - (((66 * 365 + 17) * 24) * 3600);
595
596 char tmp[32];
597 strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S.000Z", gmtime(&time_1970));
598
599 s->setTo(tmp);
600}
601
James Dongb1262a82010-11-16 14:04:54 -0800602status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700603 uint32_t hdr[2];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700604 if (mDataSource->readAt(*offset, hdr, 8) < 8) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700605 return ERROR_IO;
606 }
607 uint64_t chunk_size = ntohl(hdr[0]);
608 uint32_t chunk_type = ntohl(hdr[1]);
James Dongb1262a82010-11-16 14:04:54 -0800609 off64_t data_offset = *offset + 8;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700610
611 if (chunk_size == 1) {
Andreas Huber9a12baf2009-10-23 10:22:30 -0700612 if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700613 return ERROR_IO;
614 }
615 chunk_size = ntoh64(chunk_size);
616 data_offset += 8;
Andreas Huber736c22d2010-06-24 12:16:25 -0700617
618 if (chunk_size < 16) {
619 // The smallest valid chunk is 16 bytes long in this case.
620 return ERROR_MALFORMED;
621 }
622 } else if (chunk_size < 8) {
623 // The smallest valid chunk is 8 bytes long.
624 return ERROR_MALFORMED;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700625 }
626
627 char chunk[5];
628 MakeFourCCString(chunk_type, chunk);
629
630#if 0
631 static const char kWhitespace[] = " ";
632 const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
633 printf("%sfound chunk '%s' of size %lld\n", indent, chunk, chunk_size);
634
635 char buffer[256];
Andreas Huberdfb8eee2010-02-25 15:59:24 -0800636 size_t n = chunk_size;
637 if (n > sizeof(buffer)) {
638 n = sizeof(buffer);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700639 }
Andreas Huberdfb8eee2010-02-25 15:59:24 -0800640 if (mDataSource->readAt(*offset, buffer, n)
641 < (ssize_t)n) {
642 return ERROR_IO;
643 }
644
645 hexdump(buffer, n);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700646#endif
647
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800648 PathAdder autoAdder(&mPath, chunk_type);
649
James Dongb1262a82010-11-16 14:04:54 -0800650 off64_t chunk_data_size = *offset + chunk_size - data_offset;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700651
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800652 if (chunk_type != FOURCC('c', 'p', 'r', 't')
James Donge8b26dc2011-05-25 15:02:50 -0700653 && chunk_type != FOURCC('c', 'o', 'v', 'r')
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800654 && mPath.size() == 5 && underMetaDataPath(mPath)) {
James Dongb1262a82010-11-16 14:04:54 -0800655 off64_t stop_offset = *offset + chunk_size;
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800656 *offset = data_offset;
657 while (*offset < stop_offset) {
658 status_t err = parseChunk(offset, depth + 1);
659 if (err != OK) {
660 return err;
661 }
662 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800663
664 if (*offset != stop_offset) {
665 return ERROR_MALFORMED;
666 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800667
668 return OK;
669 }
670
Andreas Hubere46b7be2009-07-14 16:56:47 -0700671 switch(chunk_type) {
672 case FOURCC('m', 'o', 'o', 'v'):
673 case FOURCC('t', 'r', 'a', 'k'):
674 case FOURCC('m', 'd', 'i', 'a'):
675 case FOURCC('m', 'i', 'n', 'f'):
676 case FOURCC('d', 'i', 'n', 'f'):
677 case FOURCC('s', 't', 'b', 'l'):
678 case FOURCC('m', 'v', 'e', 'x'):
679 case FOURCC('m', 'o', 'o', 'f'):
680 case FOURCC('t', 'r', 'a', 'f'):
681 case FOURCC('m', 'f', 'r', 'a'):
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800682 case FOURCC('u', 'd', 't', 'a'):
683 case FOURCC('i', 'l', 's', 't'):
Andreas Hubere46b7be2009-07-14 16:56:47 -0700684 {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800685 if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
Steve Block71f2cf12011-10-20 11:56:00 +0100686 ALOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800687
Andreas Huber6da2ae12010-10-15 08:38:49 -0700688 if (mDataSource->flags()
689 & (DataSource::kWantsPrefetching
690 | DataSource::kIsCachingDataSource)) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800691 sp<MPEG4DataSource> cachedSource =
692 new MPEG4DataSource(mDataSource);
693
694 if (cachedSource->setCachedRange(*offset, chunk_size) == OK) {
695 mDataSource = cachedSource;
696 }
697 }
Andreas Hubereb9128f2010-05-14 15:28:51 -0700698
699 mLastTrack->sampleTable = new SampleTable(mDataSource);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800700 }
701
Andreas Huber4d60fc52010-03-12 16:15:53 -0800702 bool isTrack = false;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800703 if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
Andreas Huber4d60fc52010-03-12 16:15:53 -0800704 isTrack = true;
705
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800706 Track *track = new Track;
707 track->next = NULL;
708 if (mLastTrack) {
709 mLastTrack->next = track;
710 } else {
711 mFirstTrack = track;
712 }
713 mLastTrack = track;
714
715 track->meta = new MetaData;
716 track->includes_expensive_metadata = false;
Andreas Huber4d60fc52010-03-12 16:15:53 -0800717 track->skipTrack = false;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800718 track->timescale = 0;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800719 track->meta->setCString(kKeyMIMEType, "application/octet-stream");
720 }
721
James Dongb1262a82010-11-16 14:04:54 -0800722 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700723 *offset = data_offset;
724 while (*offset < stop_offset) {
725 status_t err = parseChunk(offset, depth + 1);
726 if (err != OK) {
727 return err;
728 }
729 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700730
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800731 if (*offset != stop_offset) {
732 return ERROR_MALFORMED;
733 }
734
Andreas Huber4d60fc52010-03-12 16:15:53 -0800735 if (isTrack) {
736 if (mLastTrack->skipTrack) {
737 Track *cur = mFirstTrack;
738
739 if (cur == mLastTrack) {
740 delete cur;
741 mFirstTrack = mLastTrack = NULL;
742 } else {
743 while (cur && cur->next != mLastTrack) {
744 cur = cur->next;
745 }
746 cur->next = NULL;
747 delete mLastTrack;
748 mLastTrack = cur;
749 }
750
751 return OK;
752 }
753
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800754 status_t err = verifyTrack(mLastTrack);
755
756 if (err != OK) {
757 return err;
758 }
759 } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
Andreas Huberf80e45a2011-03-03 13:48:41 -0800760 mInitCheck = OK;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700761
Gloria Wangd5770912010-06-22 13:55:38 -0700762 if (!mIsDrm) {
763 return UNKNOWN_ERROR; // Return a dummy error.
764 } else {
765 return OK;
766 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700767 }
768 break;
769 }
770
771 case FOURCC('t', 'k', 'h', 'd'):
772 {
Andreas Huber940c8662010-11-16 15:26:30 -0800773 status_t err;
774 if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
775 return err;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800776 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700777
Andreas Hubere46b7be2009-07-14 16:56:47 -0700778 *offset += chunk_size;
779 break;
780 }
781
782 case FOURCC('m', 'd', 'h', 'd'):
783 {
784 if (chunk_data_size < 4) {
785 return ERROR_MALFORMED;
786 }
787
788 uint8_t version;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700789 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700790 data_offset, &version, sizeof(version))
791 < (ssize_t)sizeof(version)) {
792 return ERROR_IO;
793 }
794
James Dongb1262a82010-11-16 14:04:54 -0800795 off64_t timescale_offset;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700796
797 if (version == 1) {
798 timescale_offset = data_offset + 4 + 16;
799 } else if (version == 0) {
800 timescale_offset = data_offset + 4 + 8;
801 } else {
802 return ERROR_IO;
803 }
804
805 uint32_t timescale;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700806 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700807 timescale_offset, &timescale, sizeof(timescale))
808 < (ssize_t)sizeof(timescale)) {
809 return ERROR_IO;
810 }
811
812 mLastTrack->timescale = ntohl(timescale);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700813
814 int64_t duration;
815 if (version == 1) {
Andreas Huber9a12baf2009-10-23 10:22:30 -0700816 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700817 timescale_offset + 4, &duration, sizeof(duration))
818 < (ssize_t)sizeof(duration)) {
819 return ERROR_IO;
820 }
821 duration = ntoh64(duration);
822 } else {
823 int32_t duration32;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700824 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700825 timescale_offset + 4, &duration32, sizeof(duration32))
826 < (ssize_t)sizeof(duration32)) {
827 return ERROR_IO;
828 }
829 duration = ntohl(duration32);
830 }
Andreas Huberfa8de752009-10-08 10:07:49 -0700831 mLastTrack->meta->setInt64(
832 kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700833
Gloria Wangc6091dd2011-05-03 15:59:03 -0700834 uint8_t lang[2];
835 off64_t lang_offset;
836 if (version == 1) {
837 lang_offset = timescale_offset + 4 + 8;
838 } else if (version == 0) {
839 lang_offset = timescale_offset + 4 + 4;
840 } else {
841 return ERROR_IO;
842 }
843
844 if (mDataSource->readAt(lang_offset, &lang, sizeof(lang))
845 < (ssize_t)sizeof(lang)) {
846 return ERROR_IO;
847 }
848
849 // To get the ISO-639-2/T three character language code
850 // 1 bit pad followed by 3 5-bits characters. Each character
851 // is packed as the difference between its ASCII value and 0x60.
852 char lang_code[4];
853 lang_code[0] = ((lang[0] >> 2) & 0x1f) + 0x60;
854 lang_code[1] = ((lang[0] & 0x3) << 3 | (lang[1] >> 5)) + 0x60;
855 lang_code[2] = (lang[1] & 0x1f) + 0x60;
856 lang_code[3] = '\0';
857
858 mLastTrack->meta->setCString(
859 kKeyMediaLanguage, lang_code);
860
Andreas Hubere46b7be2009-07-14 16:56:47 -0700861 *offset += chunk_size;
862 break;
863 }
864
Andreas Hubere46b7be2009-07-14 16:56:47 -0700865 case FOURCC('s', 't', 's', 'd'):
866 {
867 if (chunk_data_size < 8) {
868 return ERROR_MALFORMED;
869 }
870
871 uint8_t buffer[8];
James Dongb1262a82010-11-16 14:04:54 -0800872 if (chunk_data_size < (off64_t)sizeof(buffer)) {
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800873 return ERROR_MALFORMED;
874 }
875
Andreas Huber9a12baf2009-10-23 10:22:30 -0700876 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700877 data_offset, buffer, 8) < 8) {
878 return ERROR_IO;
879 }
880
881 if (U32_AT(buffer) != 0) {
882 // Should be version 0, flags 0.
883 return ERROR_MALFORMED;
884 }
885
886 uint32_t entry_count = U32_AT(&buffer[4]);
887
888 if (entry_count > 1) {
Gloria Wangeaa5d8f2011-05-31 16:08:47 -0700889 // For 3GPP timed text, there could be multiple tx3g boxes contain
890 // multiple text display formats. These formats will be used to
891 // display the timed text.
892 const char *mime;
893 CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
894 if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
895 // For now we only support a single type of media per track.
896 mLastTrack->skipTrack = true;
897 *offset += chunk_size;
898 break;
899 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700900 }
901
James Dongb1262a82010-11-16 14:04:54 -0800902 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700903 *offset = data_offset + 8;
904 for (uint32_t i = 0; i < entry_count; ++i) {
905 status_t err = parseChunk(offset, depth + 1);
906 if (err != OK) {
907 return err;
908 }
909 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800910
911 if (*offset != stop_offset) {
912 return ERROR_MALFORMED;
913 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700914 break;
915 }
916
917 case FOURCC('m', 'p', '4', 'a'):
918 case FOURCC('s', 'a', 'm', 'r'):
Andreas Huber2a651172009-09-09 16:32:59 -0700919 case FOURCC('s', 'a', 'w', 'b'):
Andreas Hubere46b7be2009-07-14 16:56:47 -0700920 {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700921 uint8_t buffer[8 + 20];
922 if (chunk_data_size < (ssize_t)sizeof(buffer)) {
923 // Basic AudioSampleEntry size.
924 return ERROR_MALFORMED;
925 }
926
Andreas Huber9a12baf2009-10-23 10:22:30 -0700927 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700928 data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
929 return ERROR_IO;
930 }
931
932 uint16_t data_ref_index = U16_AT(&buffer[6]);
933 uint16_t num_channels = U16_AT(&buffer[16]);
934
Andreas Hubere46b7be2009-07-14 16:56:47 -0700935 uint16_t sample_size = U16_AT(&buffer[18]);
936 uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
937
Andreas Huberd0332ad2010-04-12 16:05:57 -0700938 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
939 FourCC2MIME(chunk_type))) {
940 // AMR NB audio is always mono, 8kHz
941 num_channels = 1;
942 sample_rate = 8000;
943 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
944 FourCC2MIME(chunk_type))) {
945 // AMR WB audio is always mono, 16kHz
946 num_channels = 1;
947 sample_rate = 16000;
948 }
949
950#if 0
951 printf("*** coding='%s' %d channels, size %d, rate %d\n",
952 chunk, num_channels, sample_size, sample_rate);
953#endif
Andreas Hubere46b7be2009-07-14 16:56:47 -0700954
955 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
956 mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
957 mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
958
James Dongb1262a82010-11-16 14:04:54 -0800959 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700960 *offset = data_offset + sizeof(buffer);
961 while (*offset < stop_offset) {
962 status_t err = parseChunk(offset, depth + 1);
963 if (err != OK) {
964 return err;
965 }
966 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800967
968 if (*offset != stop_offset) {
969 return ERROR_MALFORMED;
970 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700971 break;
972 }
973
974 case FOURCC('m', 'p', '4', 'v'):
975 case FOURCC('s', '2', '6', '3'):
James Dong0efdc952010-12-15 15:49:46 -0800976 case FOURCC('H', '2', '6', '3'):
977 case FOURCC('h', '2', '6', '3'):
Andreas Hubere46b7be2009-07-14 16:56:47 -0700978 case FOURCC('a', 'v', 'c', '1'):
979 {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800980 mHasVideo = true;
981
Andreas Hubere46b7be2009-07-14 16:56:47 -0700982 uint8_t buffer[78];
983 if (chunk_data_size < (ssize_t)sizeof(buffer)) {
984 // Basic VideoSampleEntry size.
985 return ERROR_MALFORMED;
986 }
987
Andreas Huber9a12baf2009-10-23 10:22:30 -0700988 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700989 data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
990 return ERROR_IO;
991 }
992
993 uint16_t data_ref_index = U16_AT(&buffer[6]);
994 uint16_t width = U16_AT(&buffer[6 + 18]);
995 uint16_t height = U16_AT(&buffer[6 + 20]);
996
James Dongc9e1c802010-12-15 17:32:45 -0800997 // The video sample is not stand-compliant if it has invalid dimension.
998 // Use some default width and height value, and
999 // let the decoder figure out the actual width and height (and thus
1000 // be prepared for INFO_FOMRAT_CHANGED event).
1001 if (width == 0) width = 352;
1002 if (height == 0) height = 288;
1003
Andreas Huber2ea14e22009-12-16 09:30:55 -08001004 // printf("*** coding='%s' width=%d height=%d\n",
1005 // chunk, width, height);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001006
1007 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
1008 mLastTrack->meta->setInt32(kKeyWidth, width);
1009 mLastTrack->meta->setInt32(kKeyHeight, height);
1010
James Dongb1262a82010-11-16 14:04:54 -08001011 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001012 *offset = data_offset + sizeof(buffer);
1013 while (*offset < stop_offset) {
1014 status_t err = parseChunk(offset, depth + 1);
1015 if (err != OK) {
1016 return err;
1017 }
1018 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001019
1020 if (*offset != stop_offset) {
1021 return ERROR_MALFORMED;
1022 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001023 break;
1024 }
1025
1026 case FOURCC('s', 't', 'c', 'o'):
1027 case FOURCC('c', 'o', '6', '4'):
1028 {
1029 status_t err =
1030 mLastTrack->sampleTable->setChunkOffsetParams(
1031 chunk_type, data_offset, chunk_data_size);
1032
1033 if (err != OK) {
1034 return err;
1035 }
1036
1037 *offset += chunk_size;
1038 break;
1039 }
1040
1041 case FOURCC('s', 't', 's', 'c'):
1042 {
1043 status_t err =
1044 mLastTrack->sampleTable->setSampleToChunkParams(
1045 data_offset, chunk_data_size);
1046
1047 if (err != OK) {
1048 return err;
1049 }
1050
1051 *offset += chunk_size;
1052 break;
1053 }
1054
1055 case FOURCC('s', 't', 's', 'z'):
1056 case FOURCC('s', 't', 'z', '2'):
1057 {
1058 status_t err =
1059 mLastTrack->sampleTable->setSampleSizeParams(
1060 chunk_type, data_offset, chunk_data_size);
1061
1062 if (err != OK) {
1063 return err;
1064 }
1065
Andreas Huber1bceff92009-11-23 14:03:32 -08001066 size_t max_size;
Andreas Huberd7f22252010-09-09 10:10:15 -07001067 err = mLastTrack->sampleTable->getMaxSampleSize(&max_size);
1068
1069 if (err != OK) {
1070 return err;
1071 }
Andreas Huber1bceff92009-11-23 14:03:32 -08001072
1073 // Assume that a given buffer only contains at most 10 fragments,
1074 // each fragment originally prefixed with a 2 byte length will
1075 // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
1076 // and thus will grow by 2 bytes per fragment.
1077 mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size + 10 * 2);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001078 *offset += chunk_size;
James Dongcbb488d2011-01-19 00:13:55 -08001079
1080 // Calculate average frame rate.
1081 const char *mime;
1082 CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
1083 if (!strncasecmp("video/", mime, 6)) {
1084 size_t nSamples = mLastTrack->sampleTable->countSamples();
1085 int64_t durationUs;
1086 if (mLastTrack->meta->findInt64(kKeyDuration, &durationUs)) {
1087 if (durationUs > 0) {
1088 int32_t frameRate = (nSamples * 1000000LL +
1089 (durationUs >> 1)) / durationUs;
1090 mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
1091 }
1092 }
1093 }
1094
Andreas Hubere46b7be2009-07-14 16:56:47 -07001095 break;
1096 }
1097
1098 case FOURCC('s', 't', 't', 's'):
1099 {
1100 status_t err =
1101 mLastTrack->sampleTable->setTimeToSampleParams(
1102 data_offset, chunk_data_size);
1103
1104 if (err != OK) {
1105 return err;
1106 }
1107
1108 *offset += chunk_size;
1109 break;
1110 }
1111
Andreas Huberbd352c32011-02-03 13:18:16 -08001112 case FOURCC('c', 't', 't', 's'):
1113 {
1114 status_t err =
1115 mLastTrack->sampleTable->setCompositionTimeToSampleParams(
1116 data_offset, chunk_data_size);
1117
1118 if (err != OK) {
1119 return err;
1120 }
1121
1122 *offset += chunk_size;
1123 break;
1124 }
1125
Andreas Hubere46b7be2009-07-14 16:56:47 -07001126 case FOURCC('s', 't', 's', 's'):
1127 {
1128 status_t err =
1129 mLastTrack->sampleTable->setSyncSampleParams(
1130 data_offset, chunk_data_size);
1131
1132 if (err != OK) {
1133 return err;
1134 }
1135
1136 *offset += chunk_size;
1137 break;
1138 }
1139
James Dong77c500c2011-11-09 00:48:56 -08001140 // @xyz
1141 case FOURCC('\xA9', 'x', 'y', 'z'):
1142 {
1143 // Best case the total data length inside "@xyz" box
1144 // would be 8, for instance "@xyz" + "\x00\x04\x15\xc7" + "0+0/",
1145 // where "\x00\x04" is the text string length with value = 4,
1146 // "\0x15\xc7" is the language code = en, and "0+0" is a
1147 // location (string) value with longitude = 0 and latitude = 0.
1148 if (chunk_data_size < 8) {
1149 return ERROR_MALFORMED;
1150 }
1151
1152 // Worst case the location string length would be 18,
1153 // for instance +90.0000-180.0000, without the trailing "/" and
1154 // the string length + language code.
1155 char buffer[18];
1156
1157 // Substracting 5 from the data size is because the text string length +
1158 // language code takes 4 bytes, and the trailing slash "/" takes 1 byte.
1159 off64_t location_length = chunk_data_size - 5;
1160 if (location_length >= (off64_t) sizeof(buffer)) {
1161 return ERROR_MALFORMED;
1162 }
1163
1164 if (mDataSource->readAt(
1165 data_offset + 4, buffer, location_length) < location_length) {
1166 return ERROR_IO;
1167 }
1168
1169 buffer[location_length] = '\0';
1170 mFileMetaData->setCString(kKeyLocation, buffer);
1171 *offset += chunk_size;
1172 break;
1173 }
1174
Andreas Hubere46b7be2009-07-14 16:56:47 -07001175 case FOURCC('e', 's', 'd', 's'):
1176 {
1177 if (chunk_data_size < 4) {
1178 return ERROR_MALFORMED;
1179 }
1180
1181 uint8_t buffer[256];
James Dongb1262a82010-11-16 14:04:54 -08001182 if (chunk_data_size > (off64_t)sizeof(buffer)) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001183 return ERROR_BUFFER_TOO_SMALL;
1184 }
1185
Andreas Huber9a12baf2009-10-23 10:22:30 -07001186 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001187 data_offset, buffer, chunk_data_size) < chunk_data_size) {
1188 return ERROR_IO;
1189 }
1190
1191 if (U32_AT(buffer) != 0) {
1192 // Should be version 0, flags 0.
1193 return ERROR_MALFORMED;
1194 }
1195
1196 mLastTrack->meta->setData(
1197 kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
1198
Andreas Huberd2315962010-01-29 14:46:59 -08001199 if (mPath.size() >= 2
1200 && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a')) {
1201 // Information from the ESDS must be relied on for proper
1202 // setup of sample rate and channel count for MPEG4 Audio.
1203 // The generic header appears to only contain generic
1204 // information...
1205
1206 status_t err = updateAudioTrackInfoFromESDS_MPEG4Audio(
1207 &buffer[4], chunk_data_size - 4);
1208
1209 if (err != OK) {
1210 return err;
1211 }
1212 }
1213
Andreas Hubere46b7be2009-07-14 16:56:47 -07001214 *offset += chunk_size;
1215 break;
1216 }
1217
1218 case FOURCC('a', 'v', 'c', 'C'):
1219 {
1220 char buffer[256];
James Dongb1262a82010-11-16 14:04:54 -08001221 if (chunk_data_size > (off64_t)sizeof(buffer)) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001222 return ERROR_BUFFER_TOO_SMALL;
1223 }
1224
Andreas Huber9a12baf2009-10-23 10:22:30 -07001225 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001226 data_offset, buffer, chunk_data_size) < chunk_data_size) {
1227 return ERROR_IO;
1228 }
1229
1230 mLastTrack->meta->setData(
1231 kKeyAVCC, kTypeAVCC, buffer, chunk_data_size);
1232
1233 *offset += chunk_size;
1234 break;
1235 }
1236
James Dongfe84cf12011-02-11 15:21:45 -08001237 case FOURCC('d', '2', '6', '3'):
1238 {
James Dongbc5f1f52011-02-23 17:07:49 -08001239 /*
1240 * d263 contains a fixed 7 bytes part:
1241 * vendor - 4 bytes
1242 * version - 1 byte
1243 * level - 1 byte
1244 * profile - 1 byte
1245 * optionally, "d263" box itself may contain a 16-byte
1246 * bit rate box (bitr)
1247 * average bit rate - 4 bytes
1248 * max bit rate - 4 bytes
1249 */
1250 char buffer[23];
1251 if (chunk_data_size != 7 &&
1252 chunk_data_size != 23) {
James Dongfe84cf12011-02-11 15:21:45 -08001253 LOGE("Incorrect D263 box size %lld", chunk_data_size);
1254 return ERROR_MALFORMED;
1255 }
1256
1257 if (mDataSource->readAt(
1258 data_offset, buffer, chunk_data_size) < chunk_data_size) {
1259 return ERROR_IO;
1260 }
1261
1262 mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size);
1263
1264 *offset += chunk_size;
1265 break;
1266 }
1267
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001268 case FOURCC('m', 'e', 't', 'a'):
1269 {
1270 uint8_t buffer[4];
James Dongb1262a82010-11-16 14:04:54 -08001271 if (chunk_data_size < (off64_t)sizeof(buffer)) {
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001272 return ERROR_MALFORMED;
1273 }
1274
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001275 if (mDataSource->readAt(
1276 data_offset, buffer, 4) < 4) {
1277 return ERROR_IO;
1278 }
1279
1280 if (U32_AT(buffer) != 0) {
1281 // Should be version 0, flags 0.
Andreas Huberdfb8eee2010-02-25 15:59:24 -08001282
1283 // If it's not, let's assume this is one of those
1284 // apparently malformed chunks that don't have flags
1285 // and completely different semantics than what's
1286 // in the MPEG4 specs and skip it.
1287 *offset += chunk_size;
1288 return OK;
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001289 }
1290
James Dongb1262a82010-11-16 14:04:54 -08001291 off64_t stop_offset = *offset + chunk_size;
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001292 *offset = data_offset + sizeof(buffer);
1293 while (*offset < stop_offset) {
1294 status_t err = parseChunk(offset, depth + 1);
1295 if (err != OK) {
1296 return err;
1297 }
1298 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001299
1300 if (*offset != stop_offset) {
1301 return ERROR_MALFORMED;
1302 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001303 break;
1304 }
1305
1306 case FOURCC('d', 'a', 't', 'a'):
1307 {
1308 if (mPath.size() == 6 && underMetaDataPath(mPath)) {
1309 status_t err = parseMetaData(data_offset, chunk_data_size);
1310
1311 if (err != OK) {
1312 return err;
1313 }
1314 }
1315
1316 *offset += chunk_size;
1317 break;
1318 }
1319
1320 case FOURCC('m', 'v', 'h', 'd'):
1321 {
1322 if (chunk_data_size < 12) {
1323 return ERROR_MALFORMED;
1324 }
1325
1326 uint8_t header[12];
1327 if (mDataSource->readAt(
1328 data_offset, header, sizeof(header))
1329 < (ssize_t)sizeof(header)) {
1330 return ERROR_IO;
1331 }
1332
1333 int64_t creationTime;
1334 if (header[0] == 1) {
1335 creationTime = U64_AT(&header[4]);
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001336 } else if (header[0] != 0) {
1337 return ERROR_MALFORMED;
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001338 } else {
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001339 creationTime = U32_AT(&header[4]);
1340 }
1341
1342 String8 s;
1343 convertTimeToDate(creationTime, &s);
1344
1345 mFileMetaData->setCString(kKeyDate, s.string());
1346
1347 *offset += chunk_size;
1348 break;
1349 }
1350
Gloria Wangd5770912010-06-22 13:55:38 -07001351 case FOURCC('m', 'd', 'a', 't'):
1352 {
1353 if (!mIsDrm) {
1354 *offset += chunk_size;
1355 break;
1356 }
1357
1358 if (chunk_size < 8) {
1359 return ERROR_MALFORMED;
1360 }
1361
1362 return parseDrmSINF(offset, data_offset);
1363 }
1364
Gloria Wangeaa5d8f2011-05-31 16:08:47 -07001365 case FOURCC('h', 'd', 'l', 'r'):
1366 {
1367 uint32_t buffer;
1368 if (mDataSource->readAt(
1369 data_offset + 8, &buffer, 4) < 4) {
1370 return ERROR_IO;
1371 }
1372
1373 uint32_t type = ntohl(buffer);
1374 // For the 3GPP file format, the handler-type within the 'hdlr' box
Insun Kang1bc76122011-11-10 16:11:26 +09001375 // shall be 'text'. We also want to support 'sbtl' handler type
1376 // for a practical reason as various MPEG4 containers use it.
1377 if (type == FOURCC('t', 'e', 'x', 't') || type == FOURCC('s', 'b', 't', 'l')) {
Gloria Wangeaa5d8f2011-05-31 16:08:47 -07001378 mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
1379 }
1380
1381 *offset += chunk_size;
1382 break;
1383 }
1384
Gloria Wangc6091dd2011-05-03 15:59:03 -07001385 case FOURCC('t', 'x', '3', 'g'):
1386 {
Gloria Wangeaa5d8f2011-05-31 16:08:47 -07001387 uint32_t type;
1388 const void *data;
1389 size_t size = 0;
1390 if (!mLastTrack->meta->findData(
1391 kKeyTextFormatData, &type, &data, &size)) {
1392 size = 0;
1393 }
1394
1395 uint8_t *buffer = new uint8_t[size + chunk_size];
1396
1397 if (size > 0) {
1398 memcpy(buffer, data, size);
1399 }
1400
1401 if ((size_t)(mDataSource->readAt(*offset, buffer + size, chunk_size))
1402 < chunk_size) {
1403 delete[] buffer;
1404 buffer = NULL;
1405
1406 return ERROR_IO;
1407 }
1408
1409 mLastTrack->meta->setData(
1410 kKeyTextFormatData, 0, buffer, size + chunk_size);
1411
1412 delete[] buffer;
Gloria Wangc6091dd2011-05-03 15:59:03 -07001413
1414 *offset += chunk_size;
1415 break;
1416 }
1417
James Donge8b26dc2011-05-25 15:02:50 -07001418 case FOURCC('c', 'o', 'v', 'r'):
1419 {
1420 if (mFileMetaData != NULL) {
Steve Block71f2cf12011-10-20 11:56:00 +01001421 ALOGV("chunk_data_size = %lld and data_offset = %lld",
James Donge8b26dc2011-05-25 15:02:50 -07001422 chunk_data_size, data_offset);
1423 uint8_t *buffer = new uint8_t[chunk_data_size + 1];
1424 if (mDataSource->readAt(
1425 data_offset, buffer, chunk_data_size) != (ssize_t)chunk_data_size) {
1426 delete[] buffer;
1427 buffer = NULL;
1428
1429 return ERROR_IO;
1430 }
1431 const int kSkipBytesOfDataBox = 16;
1432 mFileMetaData->setData(
1433 kKeyAlbumArt, MetaData::TYPE_NONE,
1434 buffer + kSkipBytesOfDataBox, chunk_data_size - kSkipBytesOfDataBox);
1435 }
1436
1437 *offset += chunk_size;
1438 break;
1439 }
1440
Andreas Hubere46b7be2009-07-14 16:56:47 -07001441 default:
1442 {
1443 *offset += chunk_size;
1444 break;
1445 }
1446 }
1447
1448 return OK;
1449}
1450
Andreas Huber940c8662010-11-16 15:26:30 -08001451status_t MPEG4Extractor::parseTrackHeader(
James Dongb1262a82010-11-16 14:04:54 -08001452 off64_t data_offset, off64_t data_size) {
Andreas Huber940c8662010-11-16 15:26:30 -08001453 if (data_size < 4) {
1454 return ERROR_MALFORMED;
1455 }
1456
1457 uint8_t version;
1458 if (mDataSource->readAt(data_offset, &version, 1) < 1) {
1459 return ERROR_IO;
1460 }
1461
1462 size_t dynSize = (version == 1) ? 36 : 24;
1463
1464 uint8_t buffer[36 + 60];
1465
James Dongb1262a82010-11-16 14:04:54 -08001466 if (data_size != (off64_t)dynSize + 60) {
Andreas Huber940c8662010-11-16 15:26:30 -08001467 return ERROR_MALFORMED;
1468 }
1469
1470 if (mDataSource->readAt(
1471 data_offset, buffer, data_size) < (ssize_t)data_size) {
1472 return ERROR_IO;
1473 }
1474
1475 uint64_t ctime, mtime, duration;
1476 int32_t id;
1477
1478 if (version == 1) {
1479 ctime = U64_AT(&buffer[4]);
1480 mtime = U64_AT(&buffer[12]);
1481 id = U32_AT(&buffer[20]);
1482 duration = U64_AT(&buffer[28]);
1483 } else {
1484 CHECK_EQ((unsigned)version, 0u);
1485
1486 ctime = U32_AT(&buffer[4]);
1487 mtime = U32_AT(&buffer[8]);
1488 id = U32_AT(&buffer[12]);
1489 duration = U32_AT(&buffer[20]);
1490 }
1491
1492 mLastTrack->meta->setInt32(kKeyTrackID, id);
1493
1494 size_t matrixOffset = dynSize + 16;
1495 int32_t a00 = U32_AT(&buffer[matrixOffset]);
1496 int32_t a01 = U32_AT(&buffer[matrixOffset + 4]);
1497 int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
1498 int32_t a10 = U32_AT(&buffer[matrixOffset + 12]);
1499 int32_t a11 = U32_AT(&buffer[matrixOffset + 16]);
1500 int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
1501
1502#if 0
Steve Block6215d3f2012-01-04 20:05:49 +00001503 ALOGI("x' = %.2f * x + %.2f * y + %.2f",
Andreas Huber940c8662010-11-16 15:26:30 -08001504 a00 / 65536.0f, a01 / 65536.0f, dx / 65536.0f);
Steve Block6215d3f2012-01-04 20:05:49 +00001505 ALOGI("y' = %.2f * x + %.2f * y + %.2f",
Andreas Huber940c8662010-11-16 15:26:30 -08001506 a10 / 65536.0f, a11 / 65536.0f, dy / 65536.0f);
1507#endif
1508
1509 uint32_t rotationDegrees;
1510
1511 static const int32_t kFixedOne = 0x10000;
1512 if (a00 == kFixedOne && a01 == 0 && a10 == 0 && a11 == kFixedOne) {
1513 // Identity, no rotation
1514 rotationDegrees = 0;
1515 } else if (a00 == 0 && a01 == kFixedOne && a10 == -kFixedOne && a11 == 0) {
1516 rotationDegrees = 90;
1517 } else if (a00 == 0 && a01 == -kFixedOne && a10 == kFixedOne && a11 == 0) {
1518 rotationDegrees = 270;
1519 } else if (a00 == -kFixedOne && a01 == 0 && a10 == 0 && a11 == -kFixedOne) {
1520 rotationDegrees = 180;
1521 } else {
1522 LOGW("We only support 0,90,180,270 degree rotation matrices");
1523 rotationDegrees = 0;
1524 }
1525
1526 if (rotationDegrees != 0) {
1527 mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
1528 }
1529
James Dong08adfd22011-01-16 11:30:13 -08001530 // Handle presentation display size, which could be different
1531 // from the image size indicated by kKeyWidth and kKeyHeight.
Andreas Huber940c8662010-11-16 15:26:30 -08001532 uint32_t width = U32_AT(&buffer[dynSize + 52]);
1533 uint32_t height = U32_AT(&buffer[dynSize + 56]);
James Dong08adfd22011-01-16 11:30:13 -08001534 mLastTrack->meta->setInt32(kKeyDisplayWidth, width >> 16);
1535 mLastTrack->meta->setInt32(kKeyDisplayHeight, height >> 16);
Andreas Huber940c8662010-11-16 15:26:30 -08001536
1537 return OK;
1538}
1539
James Dongb1262a82010-11-16 14:04:54 -08001540status_t MPEG4Extractor::parseMetaData(off64_t offset, size_t size) {
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001541 if (size < 4) {
1542 return ERROR_MALFORMED;
1543 }
1544
1545 uint8_t *buffer = new uint8_t[size + 1];
1546 if (mDataSource->readAt(
1547 offset, buffer, size) != (ssize_t)size) {
1548 delete[] buffer;
1549 buffer = NULL;
1550
1551 return ERROR_IO;
1552 }
1553
1554 uint32_t flags = U32_AT(buffer);
1555
1556 uint32_t metadataKey = 0;
1557 switch (mPath[4]) {
1558 case FOURCC(0xa9, 'a', 'l', 'b'):
1559 {
1560 metadataKey = kKeyAlbum;
1561 break;
1562 }
1563 case FOURCC(0xa9, 'A', 'R', 'T'):
1564 {
1565 metadataKey = kKeyArtist;
1566 break;
1567 }
Marco Nelissenc5d5ee32010-02-11 13:31:44 -08001568 case FOURCC('a', 'A', 'R', 'T'):
1569 {
1570 metadataKey = kKeyAlbumArtist;
1571 break;
1572 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001573 case FOURCC(0xa9, 'd', 'a', 'y'):
1574 {
1575 metadataKey = kKeyYear;
1576 break;
1577 }
1578 case FOURCC(0xa9, 'n', 'a', 'm'):
1579 {
1580 metadataKey = kKeyTitle;
1581 break;
1582 }
1583 case FOURCC(0xa9, 'w', 'r', 't'):
1584 {
1585 metadataKey = kKeyWriter;
1586 break;
1587 }
1588 case FOURCC('c', 'o', 'v', 'r'):
1589 {
1590 metadataKey = kKeyAlbumArt;
1591 break;
1592 }
1593 case FOURCC('g', 'n', 'r', 'e'):
1594 {
1595 metadataKey = kKeyGenre;
1596 break;
1597 }
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001598 case FOURCC(0xa9, 'g', 'e', 'n'):
1599 {
1600 metadataKey = kKeyGenre;
1601 break;
1602 }
Marco Nelissenee35aff2011-01-06 11:12:17 -08001603 case FOURCC('c', 'p', 'i', 'l'):
1604 {
1605 if (size == 9 && flags == 21) {
1606 char tmp[16];
1607 sprintf(tmp, "%d",
1608 (int)buffer[size - 1]);
1609
1610 mFileMetaData->setCString(kKeyCompilation, tmp);
1611 }
1612 break;
1613 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001614 case FOURCC('t', 'r', 'k', 'n'):
1615 {
1616 if (size == 16 && flags == 0) {
1617 char tmp[16];
1618 sprintf(tmp, "%d/%d",
1619 (int)buffer[size - 5], (int)buffer[size - 3]);
1620
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001621 mFileMetaData->setCString(kKeyCDTrackNumber, tmp);
1622 }
1623 break;
1624 }
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001625 case FOURCC('d', 'i', 's', 'k'):
1626 {
1627 if (size == 14 && flags == 0) {
1628 char tmp[16];
1629 sprintf(tmp, "%d/%d",
1630 (int)buffer[size - 3], (int)buffer[size - 1]);
1631
1632 mFileMetaData->setCString(kKeyDiscNumber, tmp);
1633 }
1634 break;
1635 }
1636
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001637 default:
1638 break;
1639 }
1640
1641 if (size >= 8 && metadataKey) {
1642 if (metadataKey == kKeyAlbumArt) {
1643 mFileMetaData->setData(
1644 kKeyAlbumArt, MetaData::TYPE_NONE,
1645 buffer + 8, size - 8);
1646 } else if (metadataKey == kKeyGenre) {
1647 if (flags == 0) {
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001648 // uint8_t genre code, iTunes genre codes are
1649 // the standard id3 codes, except they start
1650 // at 1 instead of 0 (e.g. Pop is 14, not 13)
1651 // We use standard id3 numbering, so subtract 1.
1652 int genrecode = (int)buffer[size - 1];
1653 genrecode--;
1654 if (genrecode < 0) {
1655 genrecode = 255; // reserved for 'unknown genre'
1656 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001657 char genre[10];
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001658 sprintf(genre, "%d", genrecode);
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001659
1660 mFileMetaData->setCString(metadataKey, genre);
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001661 } else if (flags == 1) {
1662 // custom genre string
1663 buffer[size] = '\0';
1664
1665 mFileMetaData->setCString(
1666 metadataKey, (const char *)buffer + 8);
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001667 }
1668 } else {
1669 buffer[size] = '\0';
1670
1671 mFileMetaData->setCString(
1672 metadataKey, (const char *)buffer + 8);
1673 }
1674 }
1675
1676 delete[] buffer;
1677 buffer = NULL;
1678
1679 return OK;
1680}
1681
Andreas Huberbe06d262009-08-14 14:37:10 -07001682sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001683 status_t err;
1684 if ((err = readMetaData()) != OK) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001685 return NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001686 }
1687
1688 Track *track = mFirstTrack;
1689 while (index > 0) {
1690 if (track == NULL) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001691 return NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001692 }
1693
1694 track = track->next;
1695 --index;
1696 }
1697
Andreas Huber2a651172009-09-09 16:32:59 -07001698 if (track == NULL) {
1699 return NULL;
1700 }
1701
Andreas Huberbe06d262009-08-14 14:37:10 -07001702 return new MPEG4Source(
Andreas Huberfa8de752009-10-08 10:07:49 -07001703 track->meta, mDataSource, track->timescale, track->sampleTable);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001704}
1705
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001706// static
1707status_t MPEG4Extractor::verifyTrack(Track *track) {
1708 const char *mime;
1709 CHECK(track->meta->findCString(kKeyMIMEType, &mime));
1710
1711 uint32_t type;
1712 const void *data;
1713 size_t size;
1714 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1715 if (!track->meta->findData(kKeyAVCC, &type, &data, &size)
1716 || type != kTypeAVCC) {
1717 return ERROR_MALFORMED;
1718 }
1719 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
1720 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
1721 if (!track->meta->findData(kKeyESDS, &type, &data, &size)
1722 || type != kTypeESDS) {
1723 return ERROR_MALFORMED;
1724 }
1725 }
1726
Andreas Huber987cb2e2011-08-17 13:03:51 -07001727 if (!track->sampleTable->isValid()) {
1728 // Make sure we have all the metadata we need.
1729 return ERROR_MALFORMED;
1730 }
1731
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001732 return OK;
1733}
1734
Andreas Huberd2315962010-01-29 14:46:59 -08001735status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
1736 const void *esds_data, size_t esds_size) {
1737 ESDS esds(esds_data, esds_size);
Andreas Huberd0332ad2010-04-12 16:05:57 -07001738
1739 uint8_t objectTypeIndication;
1740 if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) {
1741 return ERROR_MALFORMED;
1742 }
1743
1744 if (objectTypeIndication == 0xe1) {
1745 // This isn't MPEG4 audio at all, it's QCELP 14k...
1746 mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
1747 return OK;
1748 }
1749
James Donge883d312011-02-24 21:16:54 -08001750 if (objectTypeIndication == 0x6b) {
1751 // The media subtype is MP3 audio
1752 // Our software MP3 audio decoder may not be able to handle
1753 // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED
1754 LOGE("MP3 track in MP4/3GPP file is not supported");
1755 return ERROR_UNSUPPORTED;
1756 }
1757
Andreas Huberd2315962010-01-29 14:46:59 -08001758 const uint8_t *csd;
1759 size_t csd_size;
1760 if (esds.getCodecSpecificInfo(
1761 (const void **)&csd, &csd_size) != OK) {
1762 return ERROR_MALFORMED;
1763 }
1764
1765#if 0
1766 printf("ESD of size %d\n", csd_size);
1767 hexdump(csd, csd_size);
1768#endif
1769
Andreas Huber08c94b22010-08-18 09:58:30 -07001770 if (csd_size == 0) {
1771 // There's no further information, i.e. no codec specific data
1772 // Let's assume that the information provided in the mpeg4 headers
1773 // is accurate and hope for the best.
1774
1775 return OK;
1776 }
1777
Andreas Huberd2315962010-01-29 14:46:59 -08001778 if (csd_size < 2) {
1779 return ERROR_MALFORMED;
1780 }
1781
1782 uint32_t objectType = csd[0] >> 3;
1783
1784 if (objectType == 31) {
1785 return ERROR_UNSUPPORTED;
1786 }
1787
1788 uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7);
1789 int32_t sampleRate = 0;
1790 int32_t numChannels = 0;
1791 if (freqIndex == 15) {
1792 if (csd_size < 5) {
1793 return ERROR_MALFORMED;
1794 }
1795
1796 sampleRate = (csd[1] & 0x7f) << 17
1797 | csd[2] << 9
1798 | csd[3] << 1
1799 | (csd[4] >> 7);
1800
1801 numChannels = (csd[4] >> 3) & 15;
1802 } else {
Andreas Hubercc14a832010-07-20 09:21:17 -07001803 static uint32_t kSamplingRate[] = {
1804 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1805 16000, 12000, 11025, 8000, 7350
1806 };
Andreas Huberd2315962010-01-29 14:46:59 -08001807
1808 if (freqIndex == 13 || freqIndex == 14) {
1809 return ERROR_MALFORMED;
1810 }
1811
1812 sampleRate = kSamplingRate[freqIndex];
1813 numChannels = (csd[1] >> 3) & 15;
1814 }
1815
1816 if (numChannels == 0) {
1817 return ERROR_UNSUPPORTED;
1818 }
1819
1820 int32_t prevSampleRate;
1821 CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
1822
1823 if (prevSampleRate != sampleRate) {
Steve Block71f2cf12011-10-20 11:56:00 +01001824 ALOGV("mpeg4 audio sample rate different from previous setting. "
Andreas Huberd2315962010-01-29 14:46:59 -08001825 "was: %d, now: %d", prevSampleRate, sampleRate);
1826 }
1827
1828 mLastTrack->meta->setInt32(kKeySampleRate, sampleRate);
1829
1830 int32_t prevChannelCount;
1831 CHECK(mLastTrack->meta->findInt32(kKeyChannelCount, &prevChannelCount));
1832
1833 if (prevChannelCount != numChannels) {
Steve Block71f2cf12011-10-20 11:56:00 +01001834 ALOGV("mpeg4 audio channel count different from previous setting. "
Andreas Huberd2315962010-01-29 14:46:59 -08001835 "was: %d, now: %d", prevChannelCount, numChannels);
1836 }
1837
1838 mLastTrack->meta->setInt32(kKeyChannelCount, numChannels);
1839
1840 return OK;
1841}
1842
Andreas Hubere46b7be2009-07-14 16:56:47 -07001843////////////////////////////////////////////////////////////////////////////////
1844
1845MPEG4Source::MPEG4Source(
1846 const sp<MetaData> &format,
Andreas Huberbe06d262009-08-14 14:37:10 -07001847 const sp<DataSource> &dataSource,
Andreas Huberfa8de752009-10-08 10:07:49 -07001848 int32_t timeScale,
Andreas Huberbe06d262009-08-14 14:37:10 -07001849 const sp<SampleTable> &sampleTable)
Andreas Hubere46b7be2009-07-14 16:56:47 -07001850 : mFormat(format),
1851 mDataSource(dataSource),
Andreas Huberfa8de752009-10-08 10:07:49 -07001852 mTimescale(timeScale),
Andreas Hubere46b7be2009-07-14 16:56:47 -07001853 mSampleTable(sampleTable),
1854 mCurrentSampleIndex(0),
1855 mIsAVC(false),
Andreas Huberdb5d6622010-01-12 16:30:44 -08001856 mNALLengthSize(0),
Andreas Hubere46b7be2009-07-14 16:56:47 -07001857 mStarted(false),
1858 mGroup(NULL),
1859 mBuffer(NULL),
Andreas Huber4f5e6022009-08-19 09:29:34 -07001860 mWantsNALFragments(false),
Andreas Huber8a432772009-07-28 10:03:13 -07001861 mSrcBuffer(NULL) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001862 const char *mime;
1863 bool success = mFormat->findCString(kKeyMIMEType, &mime);
Andreas Huber4f5e6022009-08-19 09:29:34 -07001864 CHECK(success);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001865
Andreas Hubere6c40962009-09-10 14:13:30 -07001866 mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberdb5d6622010-01-12 16:30:44 -08001867
1868 if (mIsAVC) {
1869 uint32_t type;
1870 const void *data;
1871 size_t size;
1872 CHECK(format->findData(kKeyAVCC, &type, &data, &size));
1873
1874 const uint8_t *ptr = (const uint8_t *)data;
1875
1876 CHECK(size >= 7);
Andreas Huber940c8662010-11-16 15:26:30 -08001877 CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
Andreas Huberdb5d6622010-01-12 16:30:44 -08001878
1879 // The number of bytes used to encode the length of a NAL unit.
1880 mNALLengthSize = 1 + (ptr[4] & 3);
1881 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001882}
1883
1884MPEG4Source::~MPEG4Source() {
1885 if (mStarted) {
1886 stop();
1887 }
1888}
1889
1890status_t MPEG4Source::start(MetaData *params) {
Andreas Huberba7ec912010-02-12 10:42:02 -08001891 Mutex::Autolock autoLock(mLock);
1892
Andreas Huber4f5e6022009-08-19 09:29:34 -07001893 CHECK(!mStarted);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001894
1895 int32_t val;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001896 if (params && params->findInt32(kKeyWantsNALFragments, &val)
Andreas Hubere46b7be2009-07-14 16:56:47 -07001897 && val != 0) {
Andreas Huber4f5e6022009-08-19 09:29:34 -07001898 mWantsNALFragments = true;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001899 } else {
Andreas Huber4f5e6022009-08-19 09:29:34 -07001900 mWantsNALFragments = false;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001901 }
1902
1903 mGroup = new MediaBufferGroup;
1904
Andreas Huber1bceff92009-11-23 14:03:32 -08001905 int32_t max_size;
1906 CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
Andreas Hubere46b7be2009-07-14 16:56:47 -07001907
Andreas Huber1bceff92009-11-23 14:03:32 -08001908 mGroup->add_buffer(new MediaBuffer(max_size));
Andreas Huber8a432772009-07-28 10:03:13 -07001909
1910 mSrcBuffer = new uint8_t[max_size];
Andreas Hubere46b7be2009-07-14 16:56:47 -07001911
1912 mStarted = true;
1913
1914 return OK;
1915}
1916
1917status_t MPEG4Source::stop() {
Andreas Huberba7ec912010-02-12 10:42:02 -08001918 Mutex::Autolock autoLock(mLock);
1919
Andreas Huber4f5e6022009-08-19 09:29:34 -07001920 CHECK(mStarted);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001921
1922 if (mBuffer != NULL) {
1923 mBuffer->release();
1924 mBuffer = NULL;
1925 }
1926
Andreas Huber8a432772009-07-28 10:03:13 -07001927 delete[] mSrcBuffer;
1928 mSrcBuffer = NULL;
1929
Andreas Hubere46b7be2009-07-14 16:56:47 -07001930 delete mGroup;
1931 mGroup = NULL;
1932
1933 mStarted = false;
1934 mCurrentSampleIndex = 0;
1935
1936 return OK;
1937}
1938
1939sp<MetaData> MPEG4Source::getFormat() {
Andreas Huberba7ec912010-02-12 10:42:02 -08001940 Mutex::Autolock autoLock(mLock);
1941
Andreas Hubere46b7be2009-07-14 16:56:47 -07001942 return mFormat;
1943}
1944
Andreas Huberdb5d6622010-01-12 16:30:44 -08001945size_t MPEG4Source::parseNALSize(const uint8_t *data) const {
1946 switch (mNALLengthSize) {
1947 case 1:
1948 return *data;
1949 case 2:
1950 return U16_AT(data);
1951 case 3:
1952 return ((size_t)data[0] << 16) | U16_AT(&data[1]);
1953 case 4:
1954 return U32_AT(data);
1955 }
1956
1957 // This cannot happen, mNALLengthSize springs to life by adding 1 to
1958 // a 2-bit integer.
1959 CHECK(!"Should not be here.");
1960
1961 return 0;
1962}
1963
Andreas Hubere46b7be2009-07-14 16:56:47 -07001964status_t MPEG4Source::read(
1965 MediaBuffer **out, const ReadOptions *options) {
Andreas Huberba7ec912010-02-12 10:42:02 -08001966 Mutex::Autolock autoLock(mLock);
1967
Andreas Huber4f5e6022009-08-19 09:29:34 -07001968 CHECK(mStarted);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001969
1970 *out = NULL;
1971
Andreas Huber6624c9f2010-07-20 15:04:28 -07001972 int64_t targetSampleTimeUs = -1;
1973
Andreas Hubere46b7be2009-07-14 16:56:47 -07001974 int64_t seekTimeUs;
Andreas Huber6624c9f2010-07-20 15:04:28 -07001975 ReadOptions::SeekMode mode;
1976 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
1977 uint32_t findFlags = 0;
1978 switch (mode) {
1979 case ReadOptions::SEEK_PREVIOUS_SYNC:
1980 findFlags = SampleTable::kFlagBefore;
1981 break;
1982 case ReadOptions::SEEK_NEXT_SYNC:
1983 findFlags = SampleTable::kFlagAfter;
1984 break;
1985 case ReadOptions::SEEK_CLOSEST_SYNC:
1986 case ReadOptions::SEEK_CLOSEST:
1987 findFlags = SampleTable::kFlagClosest;
1988 break;
1989 default:
1990 CHECK(!"Should not be here.");
1991 break;
1992 }
1993
Andreas Hubere46b7be2009-07-14 16:56:47 -07001994 uint32_t sampleIndex;
Andreas Huber6624c9f2010-07-20 15:04:28 -07001995 status_t err = mSampleTable->findSampleAtTime(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001996 seekTimeUs * mTimescale / 1000000,
Andreas Huber6624c9f2010-07-20 15:04:28 -07001997 &sampleIndex, findFlags);
1998
1999 if (mode == ReadOptions::SEEK_CLOSEST) {
2000 // We found the closest sample already, now we want the sync
2001 // sample preceding it (or the sample itself of course), even
2002 // if the subsequent sync sample is closer.
2003 findFlags = SampleTable::kFlagBefore;
2004 }
2005
2006 uint32_t syncSampleIndex;
2007 if (err == OK) {
2008 err = mSampleTable->findSyncSampleNear(
2009 sampleIndex, &syncSampleIndex, findFlags);
2010 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002011
Andreas Huber90ba1072011-10-06 09:07:12 -07002012 uint32_t sampleTime;
2013 if (err == OK) {
2014 err = mSampleTable->getMetaDataForSample(
2015 sampleIndex, NULL, NULL, &sampleTime);
2016 }
2017
Andreas Hubere46b7be2009-07-14 16:56:47 -07002018 if (err != OK) {
Andreas Huberd7d22eb2010-02-23 13:45:33 -08002019 if (err == ERROR_OUT_OF_RANGE) {
2020 // An attempt to seek past the end of the stream would
2021 // normally cause this ERROR_OUT_OF_RANGE error. Propagating
2022 // this all the way to the MediaPlayer would cause abnormal
2023 // termination. Legacy behaviour appears to be to behave as if
2024 // we had seeked to the end of stream, ending normally.
2025 err = ERROR_END_OF_STREAM;
2026 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002027 return err;
2028 }
2029
Andreas Huber6624c9f2010-07-20 15:04:28 -07002030 if (mode == ReadOptions::SEEK_CLOSEST) {
2031 targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
2032 }
2033
2034#if 0
2035 uint32_t syncSampleTime;
2036 CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
2037 syncSampleIndex, NULL, NULL, &syncSampleTime));
2038
Steve Block6215d3f2012-01-04 20:05:49 +00002039 ALOGI("seek to time %lld us => sample at time %lld us, "
Andreas Huber6624c9f2010-07-20 15:04:28 -07002040 "sync sample at time %lld us",
2041 seekTimeUs,
2042 sampleTime * 1000000ll / mTimescale,
2043 syncSampleTime * 1000000ll / mTimescale);
2044#endif
2045
2046 mCurrentSampleIndex = syncSampleIndex;
Andreas Hubere46b7be2009-07-14 16:56:47 -07002047 if (mBuffer != NULL) {
2048 mBuffer->release();
2049 mBuffer = NULL;
2050 }
2051
2052 // fall through
2053 }
2054
James Dongb1262a82010-11-16 14:04:54 -08002055 off64_t offset;
Andreas Huber8a432772009-07-28 10:03:13 -07002056 size_t size;
Andreas Huber44fdac02011-04-15 11:52:29 -07002057 uint32_t cts;
Andreas Huberad98d382010-08-06 14:13:10 -07002058 bool isSyncSample;
Andreas Huber4f5e6022009-08-19 09:29:34 -07002059 bool newBuffer = false;
2060 if (mBuffer == NULL) {
2061 newBuffer = true;
Andreas Hubere46b7be2009-07-14 16:56:47 -07002062
Andreas Huber1faa92a2010-01-19 10:39:21 -08002063 status_t err =
2064 mSampleTable->getMetaDataForSample(
Andreas Huber44fdac02011-04-15 11:52:29 -07002065 mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002066
2067 if (err != OK) {
2068 return err;
2069 }
2070
2071 err = mGroup->acquire_buffer(&mBuffer);
Andreas Huber1faa92a2010-01-19 10:39:21 -08002072
Andreas Huber4f5e6022009-08-19 09:29:34 -07002073 if (err != OK) {
Andreas Huber940c8662010-11-16 15:26:30 -08002074 CHECK(mBuffer == NULL);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002075 return err;
2076 }
Andreas Huber8a432772009-07-28 10:03:13 -07002077 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002078
Andreas Huber4f5e6022009-08-19 09:29:34 -07002079 if (!mIsAVC || mWantsNALFragments) {
2080 if (newBuffer) {
2081 ssize_t num_bytes_read =
Andreas Huber9a12baf2009-10-23 10:22:30 -07002082 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
Andreas Hubere46b7be2009-07-14 16:56:47 -07002083
Andreas Huber4f5e6022009-08-19 09:29:34 -07002084 if (num_bytes_read < (ssize_t)size) {
2085 mBuffer->release();
2086 mBuffer = NULL;
2087
2088 return ERROR_IO;
2089 }
2090
Andreas Huberba7ec912010-02-12 10:42:02 -08002091 CHECK(mBuffer != NULL);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002092 mBuffer->set_range(0, size);
2093 mBuffer->meta_data()->clear();
Andreas Huberfa8de752009-10-08 10:07:49 -07002094 mBuffer->meta_data()->setInt64(
Andreas Huber44fdac02011-04-15 11:52:29 -07002095 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
Andreas Huber6624c9f2010-07-20 15:04:28 -07002096
2097 if (targetSampleTimeUs >= 0) {
2098 mBuffer->meta_data()->setInt64(
2099 kKeyTargetTime, targetSampleTimeUs);
2100 }
2101
Andreas Huberad98d382010-08-06 14:13:10 -07002102 if (isSyncSample) {
2103 mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
2104 }
2105
Andreas Huber4f5e6022009-08-19 09:29:34 -07002106 ++mCurrentSampleIndex;
2107 }
2108
2109 if (!mIsAVC) {
2110 *out = mBuffer;
2111 mBuffer = NULL;
2112
2113 return OK;
2114 }
2115
2116 // Each NAL unit is split up into its constituent fragments and
2117 // each one of them returned in its own buffer.
2118
Andreas Huberdb5d6622010-01-12 16:30:44 -08002119 CHECK(mBuffer->range_length() >= mNALLengthSize);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002120
2121 const uint8_t *src =
2122 (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
2123
Andreas Huberdb5d6622010-01-12 16:30:44 -08002124 size_t nal_size = parseNALSize(src);
Andreas Huber909255a2010-01-14 14:13:15 -08002125 if (mBuffer->range_length() < mNALLengthSize + nal_size) {
2126 LOGE("incomplete NAL unit.");
2127
2128 mBuffer->release();
2129 mBuffer = NULL;
2130
2131 return ERROR_MALFORMED;
2132 }
Andreas Huber4f5e6022009-08-19 09:29:34 -07002133
2134 MediaBuffer *clone = mBuffer->clone();
Andreas Huberba7ec912010-02-12 10:42:02 -08002135 CHECK(clone != NULL);
Andreas Huberdb5d6622010-01-12 16:30:44 -08002136 clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002137
Andreas Huberba7ec912010-02-12 10:42:02 -08002138 CHECK(mBuffer != NULL);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002139 mBuffer->set_range(
Andreas Huberdb5d6622010-01-12 16:30:44 -08002140 mBuffer->range_offset() + mNALLengthSize + nal_size,
2141 mBuffer->range_length() - mNALLengthSize - nal_size);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002142
2143 if (mBuffer->range_length() == 0) {
2144 mBuffer->release();
2145 mBuffer = NULL;
2146 }
2147
2148 *out = clone;
2149
2150 return OK;
2151 } else {
2152 // Whole NAL units are returned but each fragment is prefixed by
2153 // the start code (0x00 00 00 01).
Gloria Wangd5770912010-06-22 13:55:38 -07002154 ssize_t num_bytes_read = 0;
2155 int32_t drm = 0;
2156 bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
2157 if (usesDRM) {
2158 num_bytes_read =
2159 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
2160 } else {
2161 num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
2162 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002163
2164 if (num_bytes_read < (ssize_t)size) {
2165 mBuffer->release();
2166 mBuffer = NULL;
2167
Andreas Huber4f5e6022009-08-19 09:29:34 -07002168 return ERROR_IO;
Andreas Hubere46b7be2009-07-14 16:56:47 -07002169 }
2170
Gloria Wangd5770912010-06-22 13:55:38 -07002171 if (usesDRM) {
2172 CHECK(mBuffer != NULL);
2173 mBuffer->set_range(0, size);
Andreas Huberdb5d6622010-01-12 16:30:44 -08002174
Gloria Wangd5770912010-06-22 13:55:38 -07002175 } else {
2176 uint8_t *dstData = (uint8_t *)mBuffer->data();
2177 size_t srcOffset = 0;
2178 size_t dstOffset = 0;
Andreas Huber909255a2010-01-14 14:13:15 -08002179
Gloria Wangd5770912010-06-22 13:55:38 -07002180 while (srcOffset < size) {
James Dong34d76ac2011-04-22 13:21:03 -07002181 bool isMalFormed = (srcOffset + mNALLengthSize > size);
2182 size_t nalLength = 0;
2183 if (!isMalFormed) {
2184 nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
2185 srcOffset += mNALLengthSize;
2186 isMalFormed = srcOffset + nalLength > size;
2187 }
Andreas Huber909255a2010-01-14 14:13:15 -08002188
James Dong34d76ac2011-04-22 13:21:03 -07002189 if (isMalFormed) {
2190 LOGE("Video is malformed");
Gloria Wangd5770912010-06-22 13:55:38 -07002191 mBuffer->release();
2192 mBuffer = NULL;
Gloria Wangd5770912010-06-22 13:55:38 -07002193 return ERROR_MALFORMED;
2194 }
2195
2196 if (nalLength == 0) {
2197 continue;
2198 }
2199
2200 CHECK(dstOffset + 4 <= mBuffer->size());
2201
2202 dstData[dstOffset++] = 0;
2203 dstData[dstOffset++] = 0;
2204 dstData[dstOffset++] = 0;
2205 dstData[dstOffset++] = 1;
2206 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
2207 srcOffset += nalLength;
2208 dstOffset += nalLength;
Andreas Huber909255a2010-01-14 14:13:15 -08002209 }
Gloria Wangd5770912010-06-22 13:55:38 -07002210 CHECK_EQ(srcOffset, size);
2211 CHECK(mBuffer != NULL);
2212 mBuffer->set_range(0, dstOffset);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002213 }
2214
Andreas Hubere46b7be2009-07-14 16:56:47 -07002215 mBuffer->meta_data()->clear();
Andreas Huberfa8de752009-10-08 10:07:49 -07002216 mBuffer->meta_data()->setInt64(
Andreas Huber44fdac02011-04-15 11:52:29 -07002217 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
Andreas Huber6624c9f2010-07-20 15:04:28 -07002218
2219 if (targetSampleTimeUs >= 0) {
2220 mBuffer->meta_data()->setInt64(
2221 kKeyTargetTime, targetSampleTimeUs);
2222 }
2223
Andreas Huberad98d382010-08-06 14:13:10 -07002224 if (isSyncSample) {
2225 mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
2226 }
2227
Andreas Hubere46b7be2009-07-14 16:56:47 -07002228 ++mCurrentSampleIndex;
2229
Andreas Hubere46b7be2009-07-14 16:56:47 -07002230 *out = mBuffer;
2231 mBuffer = NULL;
2232
2233 return OK;
2234 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002235}
2236
Andreas Huberf80e45a2011-03-03 13:48:41 -08002237MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix(
2238 const char *mimePrefix) {
2239 for (Track *track = mFirstTrack; track != NULL; track = track->next) {
2240 const char *mime;
2241 if (track->meta != NULL
2242 && track->meta->findCString(kKeyMIMEType, &mime)
2243 && !strncasecmp(mime, mimePrefix, strlen(mimePrefix))) {
2244 return track;
2245 }
2246 }
2247
2248 return NULL;
2249}
2250
Andreas Huber261eb0c2010-05-27 09:59:54 -07002251static bool LegacySniffMPEG4(
Andreas Huberbe06d262009-08-14 14:37:10 -07002252 const sp<DataSource> &source, String8 *mimeType, float *confidence) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07002253 uint8_t header[8];
2254
Andreas Huber9a12baf2009-10-23 10:22:30 -07002255 ssize_t n = source->readAt(4, header, sizeof(header));
Andreas Hubere46b7be2009-07-14 16:56:47 -07002256 if (n < (ssize_t)sizeof(header)) {
2257 return false;
2258 }
2259
2260 if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
James Donge1130662010-04-13 15:06:41 -07002261 || !memcmp(header, "ftyp3gr6", 8) || !memcmp(header, "ftyp3gs6", 8)
2262 || !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8)
Andreas Huber6bce6d82009-11-03 16:00:58 -08002263 || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
Andreas Huberdfb8eee2010-02-25 15:59:24 -08002264 || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
Andreas Hubereea1eef2010-04-01 11:42:50 -07002265 || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002266 *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
Andreas Huberefdd0882010-08-25 11:09:41 -07002267 *confidence = 0.4;
Andreas Hubere46b7be2009-07-14 16:56:47 -07002268
2269 return true;
2270 }
2271
2272 return false;
2273}
2274
Andreas Huber261eb0c2010-05-27 09:59:54 -07002275static bool isCompatibleBrand(uint32_t fourcc) {
2276 static const uint32_t kCompatibleBrands[] = {
2277 FOURCC('i', 's', 'o', 'm'),
2278 FOURCC('i', 's', 'o', '2'),
2279 FOURCC('a', 'v', 'c', '1'),
2280 FOURCC('3', 'g', 'p', '4'),
2281 FOURCC('m', 'p', '4', '1'),
2282 FOURCC('m', 'p', '4', '2'),
James Dong5f3586e2011-04-07 17:57:04 -07002283
2284 // Won't promise that the following file types can be played.
2285 // Just give these file types a chance.
2286 FOURCC('q', 't', ' ', ' '), // Apple's QuickTime
2287 FOURCC('M', 'S', 'N', 'V'), // Sony's PSP
Andreas Huber708d9082011-05-17 10:12:34 -07002288
2289 FOURCC('3', 'g', '2', 'a'), // 3GPP2
2290 FOURCC('3', 'g', '2', 'b'),
Andreas Huber261eb0c2010-05-27 09:59:54 -07002291 };
2292
2293 for (size_t i = 0;
2294 i < sizeof(kCompatibleBrands) / sizeof(kCompatibleBrands[0]);
2295 ++i) {
2296 if (kCompatibleBrands[i] == fourcc) {
2297 return true;
2298 }
2299 }
2300
2301 return false;
2302}
2303
2304// Attempt to actually parse the 'ftyp' atom and determine if a suitable
2305// compatible brand is present.
Andreas Huberb8e651a2011-12-05 11:34:43 -08002306// Also try to identify where this file's metadata ends
2307// (end of the 'moov' atom) and report it to the caller as part of
2308// the metadata.
Andreas Huber261eb0c2010-05-27 09:59:54 -07002309static bool BetterSniffMPEG4(
Andreas Huberb8e651a2011-12-05 11:34:43 -08002310 const sp<DataSource> &source, String8 *mimeType, float *confidence,
2311 sp<AMessage> *meta) {
2312 // We scan up to 128 bytes to identify this file as an MP4.
2313 static const off64_t kMaxScanOffset = 128ll;
Andreas Huber261eb0c2010-05-27 09:59:54 -07002314
Andreas Huberb8e651a2011-12-05 11:34:43 -08002315 off64_t offset = 0ll;
2316 bool foundGoodFileType = false;
2317 off64_t moovAtomEndOffset = -1ll;
2318 bool done = false;
Andreas Huber261eb0c2010-05-27 09:59:54 -07002319
Andreas Huberb8e651a2011-12-05 11:34:43 -08002320 while (!done && offset < kMaxScanOffset) {
2321 uint32_t hdr[2];
2322 if (source->readAt(offset, hdr, 8) < 8) {
2323 return false;
2324 }
2325
2326 uint64_t chunkSize = ntohl(hdr[0]);
2327 uint32_t chunkType = ntohl(hdr[1]);
2328 off64_t chunkDataOffset = offset + 8;
2329
2330 if (chunkSize == 1) {
2331 if (source->readAt(offset + 8, &chunkSize, 8) < 8) {
Andreas Huber261eb0c2010-05-27 09:59:54 -07002332 return false;
2333 }
2334
Andreas Huberb8e651a2011-12-05 11:34:43 -08002335 chunkSize = ntoh64(chunkSize);
2336 chunkDataOffset += 8;
2337
2338 if (chunkSize < 16) {
2339 // The smallest valid chunk is 16 bytes long in this case.
2340 return false;
2341 }
2342 } else if (chunkSize < 8) {
2343 // The smallest valid chunk is 8 bytes long.
2344 return false;
2345 }
2346
2347 off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
2348
2349 switch (chunkType) {
2350 case FOURCC('f', 't', 'y', 'p'):
2351 {
2352 if (chunkDataSize < 8) {
2353 return false;
2354 }
2355
2356 uint32_t numCompatibleBrands = (chunkDataSize - 8) / 4;
2357 for (size_t i = 0; i < numCompatibleBrands + 2; ++i) {
2358 if (i == 1) {
2359 // Skip this index, it refers to the minorVersion,
2360 // not a brand.
2361 continue;
2362 }
2363
2364 uint32_t brand;
2365 if (source->readAt(
2366 chunkDataOffset + 4 * i, &brand, 4) < 4) {
2367 return false;
2368 }
2369
2370 brand = ntohl(brand);
2371
2372 if (isCompatibleBrand(brand)) {
2373 foundGoodFileType = true;
2374 break;
2375 }
2376 }
2377
2378 if (!foundGoodFileType) {
2379 return false;
2380 }
2381
Andreas Huber261eb0c2010-05-27 09:59:54 -07002382 break;
2383 }
Andreas Huberb8e651a2011-12-05 11:34:43 -08002384
2385 case FOURCC('m', 'o', 'o', 'v'):
2386 {
2387 moovAtomEndOffset = offset + chunkSize;
2388
2389 done = true;
2390 break;
2391 }
2392
2393 default:
2394 break;
Andreas Huber261eb0c2010-05-27 09:59:54 -07002395 }
Andreas Huberb8e651a2011-12-05 11:34:43 -08002396
2397 offset += chunkSize;
Andreas Huber261eb0c2010-05-27 09:59:54 -07002398 }
2399
Andreas Huberb8e651a2011-12-05 11:34:43 -08002400 if (!foundGoodFileType) {
Andreas Huber261eb0c2010-05-27 09:59:54 -07002401 return false;
2402 }
2403
2404 *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
Andreas Huberefdd0882010-08-25 11:09:41 -07002405 *confidence = 0.4f;
Andreas Huber261eb0c2010-05-27 09:59:54 -07002406
Andreas Huberb8e651a2011-12-05 11:34:43 -08002407 if (moovAtomEndOffset >= 0) {
2408 *meta = new AMessage;
2409 (*meta)->setInt64("meta-data-size", moovAtomEndOffset);
2410
Andreas Huber68d2f952011-12-05 13:30:52 -08002411 ALOGV("found metadata size: %lld", moovAtomEndOffset);
Andreas Huberb8e651a2011-12-05 11:34:43 -08002412 }
2413
Andreas Huber261eb0c2010-05-27 09:59:54 -07002414 return true;
2415}
2416
2417bool SniffMPEG4(
Andreas Huberefdd0882010-08-25 11:09:41 -07002418 const sp<DataSource> &source, String8 *mimeType, float *confidence,
Andreas Huberb8e651a2011-12-05 11:34:43 -08002419 sp<AMessage> *meta) {
2420 if (BetterSniffMPEG4(source, mimeType, confidence, meta)) {
Andreas Huber261eb0c2010-05-27 09:59:54 -07002421 return true;
2422 }
2423
2424 if (LegacySniffMPEG4(source, mimeType, confidence)) {
2425 LOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
2426 return true;
2427 }
2428
2429 return false;
2430}
2431
Andreas Hubere46b7be2009-07-14 16:56:47 -07002432} // namespace android
2433