blob: c79d02e6fc0c25bee190e5bdf5b6f48f845f0146 [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"
23#include "include/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 Hubere46b7be2009-07-14 16:56:47 -070033#include <media/stagefright/DataSource.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070034#include <media/stagefright/MediaBuffer.h>
35#include <media/stagefright/MediaBufferGroup.h>
Andreas Hubere6c40962009-09-10 14:13:30 -070036#include <media/stagefright/MediaDefs.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070037#include <media/stagefright/MediaSource.h>
38#include <media/stagefright/MetaData.h>
Andreas Hubere46b7be2009-07-14 16:56:47 -070039#include <media/stagefright/Utils.h>
40#include <utils/String8.h>
41
42namespace android {
43
44class MPEG4Source : public MediaSource {
45public:
46 // Caller retains ownership of both "dataSource" and "sampleTable".
Andreas Huberbe06d262009-08-14 14:37:10 -070047 MPEG4Source(const sp<MetaData> &format,
48 const sp<DataSource> &dataSource,
Andreas Huberfa8de752009-10-08 10:07:49 -070049 int32_t timeScale,
Andreas Huberbe06d262009-08-14 14:37:10 -070050 const sp<SampleTable> &sampleTable);
Andreas Hubere46b7be2009-07-14 16:56:47 -070051
52 virtual status_t start(MetaData *params = NULL);
53 virtual status_t stop();
54
55 virtual sp<MetaData> getFormat();
56
57 virtual status_t read(
58 MediaBuffer **buffer, const ReadOptions *options = NULL);
59
Andreas Huberbe06d262009-08-14 14:37:10 -070060protected:
61 virtual ~MPEG4Source();
62
Andreas Hubere46b7be2009-07-14 16:56:47 -070063private:
Andreas Huberba7ec912010-02-12 10:42:02 -080064 Mutex mLock;
65
Andreas Hubere46b7be2009-07-14 16:56:47 -070066 sp<MetaData> mFormat;
Andreas Huberbe06d262009-08-14 14:37:10 -070067 sp<DataSource> mDataSource;
Andreas Hubere46b7be2009-07-14 16:56:47 -070068 int32_t mTimescale;
Andreas Huberbe06d262009-08-14 14:37:10 -070069 sp<SampleTable> mSampleTable;
Andreas Hubere46b7be2009-07-14 16:56:47 -070070 uint32_t mCurrentSampleIndex;
71
72 bool mIsAVC;
Andreas Huberdb5d6622010-01-12 16:30:44 -080073 size_t mNALLengthSize;
74
Andreas Hubere46b7be2009-07-14 16:56:47 -070075 bool mStarted;
76
77 MediaBufferGroup *mGroup;
78
79 MediaBuffer *mBuffer;
Andreas Hubere46b7be2009-07-14 16:56:47 -070080
Andreas Huber4f5e6022009-08-19 09:29:34 -070081 bool mWantsNALFragments;
Andreas Hubere46b7be2009-07-14 16:56:47 -070082
Andreas Huber8a432772009-07-28 10:03:13 -070083 uint8_t *mSrcBuffer;
84
Andreas Huberdb5d6622010-01-12 16:30:44 -080085 size_t parseNALSize(const uint8_t *data) const;
86
Andreas Hubere46b7be2009-07-14 16:56:47 -070087 MPEG4Source(const MPEG4Source &);
88 MPEG4Source &operator=(const MPEG4Source &);
89};
90
Andreas Huberaffa99c2010-01-28 14:27:37 -080091// This custom data source wraps an existing one and satisfies requests
92// falling entirely within a cached range from the cache while forwarding
93// all remaining requests to the wrapped datasource.
94// This is used to cache the full sampletable metadata for a single track,
95// possibly wrapping multiple times to cover all tracks, i.e.
96// Each MPEG4DataSource caches the sampletable metadata for a single track.
97
98struct MPEG4DataSource : public DataSource {
99 MPEG4DataSource(const sp<DataSource> &source);
100
101 virtual status_t initCheck() const;
James Dongb1262a82010-11-16 14:04:54 -0800102 virtual ssize_t readAt(off64_t offset, void *data, size_t size);
103 virtual status_t getSize(off64_t *size);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800104 virtual uint32_t flags();
105
James Dongb1262a82010-11-16 14:04:54 -0800106 status_t setCachedRange(off64_t offset, size_t size);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800107
108protected:
109 virtual ~MPEG4DataSource();
110
111private:
112 Mutex mLock;
113
114 sp<DataSource> mSource;
James Dongb1262a82010-11-16 14:04:54 -0800115 off64_t mCachedOffset;
Andreas Huberaffa99c2010-01-28 14:27:37 -0800116 size_t mCachedSize;
117 uint8_t *mCache;
118
119 void clearCache();
120
121 MPEG4DataSource(const MPEG4DataSource &);
122 MPEG4DataSource &operator=(const MPEG4DataSource &);
123};
124
125MPEG4DataSource::MPEG4DataSource(const sp<DataSource> &source)
126 : mSource(source),
127 mCachedOffset(0),
128 mCachedSize(0),
129 mCache(NULL) {
130}
131
132MPEG4DataSource::~MPEG4DataSource() {
133 clearCache();
134}
135
136void MPEG4DataSource::clearCache() {
137 if (mCache) {
138 free(mCache);
139 mCache = NULL;
140 }
141
142 mCachedOffset = 0;
143 mCachedSize = 0;
144}
145
146status_t MPEG4DataSource::initCheck() const {
147 return mSource->initCheck();
148}
149
James Dongb1262a82010-11-16 14:04:54 -0800150ssize_t MPEG4DataSource::readAt(off64_t offset, void *data, size_t size) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800151 Mutex::Autolock autoLock(mLock);
152
153 if (offset >= mCachedOffset
154 && offset + size <= mCachedOffset + mCachedSize) {
155 memcpy(data, &mCache[offset - mCachedOffset], size);
156 return size;
157 }
158
159 return mSource->readAt(offset, data, size);
160}
161
James Dongb1262a82010-11-16 14:04:54 -0800162status_t MPEG4DataSource::getSize(off64_t *size) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800163 return mSource->getSize(size);
164}
165
166uint32_t MPEG4DataSource::flags() {
167 return mSource->flags();
168}
169
James Dongb1262a82010-11-16 14:04:54 -0800170status_t MPEG4DataSource::setCachedRange(off64_t offset, size_t size) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800171 Mutex::Autolock autoLock(mLock);
172
173 clearCache();
174
175 mCache = (uint8_t *)malloc(size);
176
177 if (mCache == NULL) {
178 return -ENOMEM;
179 }
180
181 mCachedOffset = offset;
182 mCachedSize = size;
183
184 ssize_t err = mSource->readAt(mCachedOffset, mCache, mCachedSize);
185
186 if (err < (ssize_t)size) {
187 clearCache();
188
189 return ERROR_IO;
190 }
191
192 return OK;
193}
194
195////////////////////////////////////////////////////////////////////////////////
196
Andreas Hubere46b7be2009-07-14 16:56:47 -0700197static void hexdump(const void *_data, size_t size) {
198 const uint8_t *data = (const uint8_t *)_data;
199 size_t offset = 0;
200 while (offset < size) {
201 printf("0x%04x ", offset);
202
203 size_t n = size - offset;
204 if (n > 16) {
205 n = 16;
206 }
207
208 for (size_t i = 0; i < 16; ++i) {
209 if (i == 8) {
210 printf(" ");
211 }
212
213 if (offset + i < size) {
214 printf("%02x ", data[offset + i]);
215 } else {
216 printf(" ");
217 }
218 }
219
220 printf(" ");
221
222 for (size_t i = 0; i < n; ++i) {
223 if (isprint(data[offset + i])) {
224 printf("%c", data[offset + i]);
225 } else {
226 printf(".");
227 }
228 }
229
230 printf("\n");
231
232 offset += 16;
233 }
234}
235
Andreas Hubere6c40962009-09-10 14:13:30 -0700236static const char *FourCC2MIME(uint32_t fourcc) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700237 switch (fourcc) {
238 case FOURCC('m', 'p', '4', 'a'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700239 return MEDIA_MIMETYPE_AUDIO_AAC;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700240
241 case FOURCC('s', 'a', 'm', 'r'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700242 return MEDIA_MIMETYPE_AUDIO_AMR_NB;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700243
Andreas Huber2a651172009-09-09 16:32:59 -0700244 case FOURCC('s', 'a', 'w', 'b'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700245 return MEDIA_MIMETYPE_AUDIO_AMR_WB;
Andreas Huber2a651172009-09-09 16:32:59 -0700246
Andreas Hubere46b7be2009-07-14 16:56:47 -0700247 case FOURCC('m', 'p', '4', 'v'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700248 return MEDIA_MIMETYPE_VIDEO_MPEG4;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700249
250 case FOURCC('s', '2', '6', '3'):
James Dong0efdc952010-12-15 15:49:46 -0800251 case FOURCC('h', '2', '6', '3'):
252 case FOURCC('H', '2', '6', '3'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700253 return MEDIA_MIMETYPE_VIDEO_H263;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700254
255 case FOURCC('a', 'v', 'c', '1'):
Andreas Hubere6c40962009-09-10 14:13:30 -0700256 return MEDIA_MIMETYPE_VIDEO_AVC;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700257
258 default:
Andreas Huber4f5e6022009-08-19 09:29:34 -0700259 CHECK(!"should not be here.");
Andreas Hubere46b7be2009-07-14 16:56:47 -0700260 return NULL;
261 }
262}
263
Andreas Huberbe06d262009-08-14 14:37:10 -0700264MPEG4Extractor::MPEG4Extractor(const sp<DataSource> &source)
Andreas Hubere46b7be2009-07-14 16:56:47 -0700265 : mDataSource(source),
Andreas Huberf80e45a2011-03-03 13:48:41 -0800266 mInitCheck(NO_INIT),
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800267 mHasVideo(false),
Andreas Hubere46b7be2009-07-14 16:56:47 -0700268 mFirstTrack(NULL),
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800269 mLastTrack(NULL),
Gloria Wangd5770912010-06-22 13:55:38 -0700270 mFileMetaData(new MetaData),
271 mFirstSINF(NULL),
272 mIsDrm(false) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700273}
274
275MPEG4Extractor::~MPEG4Extractor() {
276 Track *track = mFirstTrack;
277 while (track) {
278 Track *next = track->next;
279
Andreas Hubere46b7be2009-07-14 16:56:47 -0700280 delete track;
281 track = next;
282 }
283 mFirstTrack = mLastTrack = NULL;
Gloria Wangd5770912010-06-22 13:55:38 -0700284
285 SINF *sinf = mFirstSINF;
286 while (sinf) {
287 SINF *next = sinf->next;
288 delete sinf->IPMPData;
289 delete sinf;
290 sinf = next;
291 }
292 mFirstSINF = NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700293}
294
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800295sp<MetaData> MPEG4Extractor::getMetaData() {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800296 status_t err;
297 if ((err = readMetaData()) != OK) {
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800298 return new MetaData;
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800299 }
300
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800301 return mFileMetaData;
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800302}
303
Andreas Huberbe06d262009-08-14 14:37:10 -0700304size_t MPEG4Extractor::countTracks() {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700305 status_t err;
306 if ((err = readMetaData()) != OK) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700307 return 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700308 }
309
Andreas Huberbe06d262009-08-14 14:37:10 -0700310 size_t n = 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700311 Track *track = mFirstTrack;
312 while (track) {
Andreas Huberbe06d262009-08-14 14:37:10 -0700313 ++n;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700314 track = track->next;
315 }
316
Andreas Huberbe06d262009-08-14 14:37:10 -0700317 return n;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700318}
319
Andreas Hubere981c332009-10-22 13:49:30 -0700320sp<MetaData> MPEG4Extractor::getTrackMetaData(
321 size_t index, uint32_t flags) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700322 status_t err;
323 if ((err = readMetaData()) != OK) {
324 return NULL;
325 }
326
327 Track *track = mFirstTrack;
328 while (index > 0) {
329 if (track == NULL) {
330 return NULL;
331 }
332
333 track = track->next;
334 --index;
335 }
336
Andreas Huber2a651172009-09-09 16:32:59 -0700337 if (track == NULL) {
338 return NULL;
339 }
340
Andreas Hubere981c332009-10-22 13:49:30 -0700341 if ((flags & kIncludeExtensiveMetaData)
342 && !track->includes_expensive_metadata) {
343 track->includes_expensive_metadata = true;
344
345 const char *mime;
346 CHECK(track->meta->findCString(kKeyMIMEType, &mime));
347 if (!strncasecmp("video/", mime, 6)) {
348 uint32_t sampleIndex;
349 uint32_t sampleTime;
350 if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
Andreas Huber1faa92a2010-01-19 10:39:21 -0800351 && track->sampleTable->getMetaDataForSample(
352 sampleIndex, NULL /* offset */, NULL /* size */,
353 &sampleTime) == OK) {
Andreas Hubere981c332009-10-22 13:49:30 -0700354 track->meta->setInt64(
355 kKeyThumbnailTime,
356 ((int64_t)sampleTime * 1000000) / track->timescale);
357 }
358 }
359 }
360
Andreas Hubere46b7be2009-07-14 16:56:47 -0700361 return track->meta;
362}
363
364status_t MPEG4Extractor::readMetaData() {
Andreas Huberf80e45a2011-03-03 13:48:41 -0800365 if (mInitCheck != NO_INIT) {
366 return mInitCheck;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700367 }
368
James Dongb1262a82010-11-16 14:04:54 -0800369 off64_t offset = 0;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700370 status_t err;
371 while ((err = parseChunk(&offset, 0)) == OK) {
372 }
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800373
Andreas Huberf80e45a2011-03-03 13:48:41 -0800374 if (mInitCheck == OK) {
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800375 if (mHasVideo) {
376 mFileMetaData->setCString(kKeyMIMEType, "video/mp4");
377 } else {
378 mFileMetaData->setCString(kKeyMIMEType, "audio/mp4");
379 }
380
Andreas Huber44fdac02011-04-15 11:52:29 -0700381 mInitCheck = OK;
Andreas Huberf80e45a2011-03-03 13:48:41 -0800382 } else {
383 mInitCheck = err;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700384 }
385
Andreas Huberf80e45a2011-03-03 13:48:41 -0800386 CHECK_NE(err, (status_t)NO_INIT);
387 return mInitCheck;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700388}
389
Gloria Wangd5770912010-06-22 13:55:38 -0700390void MPEG4Extractor::setDrmFlag(bool flag) {
391 mIsDrm = flag;
392}
393
394char* MPEG4Extractor::getDrmTrackInfo(size_t trackID, int *len) {
395 if (mFirstSINF == NULL) {
396 return NULL;
397 }
398
399 SINF *sinf = mFirstSINF;
400 while (sinf && (trackID != sinf->trackID)) {
401 sinf = sinf->next;
402 }
403
404 if (sinf == NULL) {
405 return NULL;
406 }
407
408 *len = sinf->len;
409 return sinf->IPMPData;
410}
411
412// Reads an encoded integer 7 bits at a time until it encounters the high bit clear.
James Dongb1262a82010-11-16 14:04:54 -0800413int32_t readSize(off64_t offset,
Gloria Wangd5770912010-06-22 13:55:38 -0700414 const sp<DataSource> DataSource, uint8_t *numOfBytes) {
415 uint32_t size = 0;
416 uint8_t data;
417 bool moreData = true;
418 *numOfBytes = 0;
419
420 while (moreData) {
421 if (DataSource->readAt(offset, &data, 1) < 1) {
422 return -1;
423 }
424 offset ++;
425 moreData = (data >= 128) ? true : false;
426 size = (size << 7) | (data & 0x7f); // Take last 7 bits
427 (*numOfBytes) ++;
428 }
429
430 return size;
431}
432
James Dongb1262a82010-11-16 14:04:54 -0800433status_t MPEG4Extractor::parseDrmSINF(off64_t *offset, off64_t data_offset) {
Gloria Wangd5770912010-06-22 13:55:38 -0700434 uint8_t updateIdTag;
435 if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
436 return ERROR_IO;
437 }
438 data_offset ++;
439
440 if (0x01/*OBJECT_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
441 return ERROR_MALFORMED;
442 }
443
444 uint8_t numOfBytes;
445 int32_t size = readSize(data_offset, mDataSource, &numOfBytes);
446 if (size < 0) {
447 return ERROR_IO;
448 }
449 int32_t classSize = size;
450 data_offset += numOfBytes;
451
452 while(size >= 11 ) {
453 uint8_t descriptorTag;
454 if (mDataSource->readAt(data_offset, &descriptorTag, 1) < 1) {
455 return ERROR_IO;
456 }
457 data_offset ++;
458
459 if (0x11/*OBJECT_DESCRIPTOR_ID_TAG*/ != descriptorTag) {
460 return ERROR_MALFORMED;
461 }
462
463 uint8_t buffer[8];
464 //ObjectDescriptorID and ObjectDescriptor url flag
465 if (mDataSource->readAt(data_offset, buffer, 2) < 2) {
466 return ERROR_IO;
467 }
468 data_offset += 2;
469
470 if ((buffer[1] >> 5) & 0x0001) { //url flag is set
471 return ERROR_MALFORMED;
472 }
473
474 if (mDataSource->readAt(data_offset, buffer, 8) < 8) {
475 return ERROR_IO;
476 }
477 data_offset += 8;
478
479 if ((0x0F/*ES_ID_REF_TAG*/ != buffer[1])
480 || ( 0x0A/*IPMP_DESCRIPTOR_POINTER_ID_TAG*/ != buffer[5])) {
481 return ERROR_MALFORMED;
482 }
483
484 SINF *sinf = new SINF;
485 sinf->trackID = U16_AT(&buffer[3]);
486 sinf->IPMPDescriptorID = buffer[7];
487 sinf->next = mFirstSINF;
488 mFirstSINF = sinf;
489
490 size -= (8 + 2 + 1);
491 }
492
493 if (size != 0) {
494 return ERROR_MALFORMED;
495 }
496
497 if (mDataSource->readAt(data_offset, &updateIdTag, 1) < 1) {
498 return ERROR_IO;
499 }
500 data_offset ++;
501
502 if(0x05/*IPMP_DESCRIPTOR_UPDATE_ID_TAG*/ != updateIdTag) {
503 return ERROR_MALFORMED;
504 }
505
506 size = readSize(data_offset, mDataSource, &numOfBytes);
507 if (size < 0) {
508 return ERROR_IO;
509 }
510 classSize = size;
511 data_offset += numOfBytes;
512
513 while (size > 0) {
514 uint8_t tag;
515 int32_t dataLen;
516 if (mDataSource->readAt(data_offset, &tag, 1) < 1) {
517 return ERROR_IO;
518 }
519 data_offset ++;
520
521 if (0x0B/*IPMP_DESCRIPTOR_ID_TAG*/ == tag) {
522 uint8_t id;
523 dataLen = readSize(data_offset, mDataSource, &numOfBytes);
524 if (dataLen < 0) {
525 return ERROR_IO;
526 } else if (dataLen < 4) {
527 return ERROR_MALFORMED;
528 }
529 data_offset += numOfBytes;
530
531 if (mDataSource->readAt(data_offset, &id, 1) < 1) {
532 return ERROR_IO;
533 }
534 data_offset ++;
535
536 SINF *sinf = mFirstSINF;
537 while (sinf && (sinf->IPMPDescriptorID != id)) {
538 sinf = sinf->next;
539 }
540 if (sinf == NULL) {
541 return ERROR_MALFORMED;
542 }
543 sinf->len = dataLen - 3;
544 sinf->IPMPData = new char[sinf->len];
545
546 if (mDataSource->readAt(data_offset + 2, sinf->IPMPData, sinf->len) < sinf->len) {
547 return ERROR_IO;
548 }
549 data_offset += sinf->len;
550
551 size -= (dataLen + numOfBytes + 1);
552 }
553 }
554
555 if (size != 0) {
556 return ERROR_MALFORMED;
557 }
558
559 return UNKNOWN_ERROR; // Return a dummy error.
560}
561
Andreas Hubere46b7be2009-07-14 16:56:47 -0700562static void MakeFourCCString(uint32_t x, char *s) {
563 s[0] = x >> 24;
564 s[1] = (x >> 16) & 0xff;
565 s[2] = (x >> 8) & 0xff;
566 s[3] = x & 0xff;
567 s[4] = '\0';
568}
569
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800570struct PathAdder {
571 PathAdder(Vector<uint32_t> *path, uint32_t chunkType)
572 : mPath(path) {
573 mPath->push(chunkType);
574 }
575
576 ~PathAdder() {
577 mPath->pop();
578 }
579
580private:
581 Vector<uint32_t> *mPath;
582
583 PathAdder(const PathAdder &);
584 PathAdder &operator=(const PathAdder &);
585};
586
587static bool underMetaDataPath(const Vector<uint32_t> &path) {
588 return path.size() >= 5
589 && path[0] == FOURCC('m', 'o', 'o', 'v')
590 && path[1] == FOURCC('u', 'd', 't', 'a')
591 && path[2] == FOURCC('m', 'e', 't', 'a')
592 && path[3] == FOURCC('i', 'l', 's', 't');
593}
594
595// Given a time in seconds since Jan 1 1904, produce a human-readable string.
596static void convertTimeToDate(int64_t time_1904, String8 *s) {
597 time_t time_1970 = time_1904 - (((66 * 365 + 17) * 24) * 3600);
598
599 char tmp[32];
600 strftime(tmp, sizeof(tmp), "%Y%m%dT%H%M%S.000Z", gmtime(&time_1970));
601
602 s->setTo(tmp);
603}
604
James Dongb1262a82010-11-16 14:04:54 -0800605status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700606 uint32_t hdr[2];
Andreas Huber9a12baf2009-10-23 10:22:30 -0700607 if (mDataSource->readAt(*offset, hdr, 8) < 8) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700608 return ERROR_IO;
609 }
610 uint64_t chunk_size = ntohl(hdr[0]);
611 uint32_t chunk_type = ntohl(hdr[1]);
James Dongb1262a82010-11-16 14:04:54 -0800612 off64_t data_offset = *offset + 8;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700613
614 if (chunk_size == 1) {
Andreas Huber9a12baf2009-10-23 10:22:30 -0700615 if (mDataSource->readAt(*offset + 8, &chunk_size, 8) < 8) {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700616 return ERROR_IO;
617 }
618 chunk_size = ntoh64(chunk_size);
619 data_offset += 8;
Andreas Huber736c22d2010-06-24 12:16:25 -0700620
621 if (chunk_size < 16) {
622 // The smallest valid chunk is 16 bytes long in this case.
623 return ERROR_MALFORMED;
624 }
625 } else if (chunk_size < 8) {
626 // The smallest valid chunk is 8 bytes long.
627 return ERROR_MALFORMED;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700628 }
629
630 char chunk[5];
631 MakeFourCCString(chunk_type, chunk);
632
633#if 0
634 static const char kWhitespace[] = " ";
635 const char *indent = &kWhitespace[sizeof(kWhitespace) - 1 - 2 * depth];
636 printf("%sfound chunk '%s' of size %lld\n", indent, chunk, chunk_size);
637
638 char buffer[256];
Andreas Huberdfb8eee2010-02-25 15:59:24 -0800639 size_t n = chunk_size;
640 if (n > sizeof(buffer)) {
641 n = sizeof(buffer);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700642 }
Andreas Huberdfb8eee2010-02-25 15:59:24 -0800643 if (mDataSource->readAt(*offset, buffer, n)
644 < (ssize_t)n) {
645 return ERROR_IO;
646 }
647
648 hexdump(buffer, n);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700649#endif
650
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800651 PathAdder autoAdder(&mPath, chunk_type);
652
James Dongb1262a82010-11-16 14:04:54 -0800653 off64_t chunk_data_size = *offset + chunk_size - data_offset;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700654
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800655 if (chunk_type != FOURCC('c', 'p', 'r', 't')
656 && mPath.size() == 5 && underMetaDataPath(mPath)) {
James Dongb1262a82010-11-16 14:04:54 -0800657 off64_t stop_offset = *offset + chunk_size;
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800658 *offset = data_offset;
659 while (*offset < stop_offset) {
660 status_t err = parseChunk(offset, depth + 1);
661 if (err != OK) {
662 return err;
663 }
664 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800665
666 if (*offset != stop_offset) {
667 return ERROR_MALFORMED;
668 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800669
670 return OK;
671 }
672
Andreas Hubere46b7be2009-07-14 16:56:47 -0700673 switch(chunk_type) {
674 case FOURCC('m', 'o', 'o', 'v'):
675 case FOURCC('t', 'r', 'a', 'k'):
676 case FOURCC('m', 'd', 'i', 'a'):
677 case FOURCC('m', 'i', 'n', 'f'):
678 case FOURCC('d', 'i', 'n', 'f'):
679 case FOURCC('s', 't', 'b', 'l'):
680 case FOURCC('m', 'v', 'e', 'x'):
681 case FOURCC('m', 'o', 'o', 'f'):
682 case FOURCC('t', 'r', 'a', 'f'):
683 case FOURCC('m', 'f', 'r', 'a'):
Andreas Huberc2c9dd32010-01-19 16:43:53 -0800684 case FOURCC('u', 'd', 't', 'a'):
685 case FOURCC('i', 'l', 's', 't'):
Andreas Hubere46b7be2009-07-14 16:56:47 -0700686 {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800687 if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
688 LOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
689
Andreas Huber6da2ae12010-10-15 08:38:49 -0700690 if (mDataSource->flags()
691 & (DataSource::kWantsPrefetching
692 | DataSource::kIsCachingDataSource)) {
Andreas Huberaffa99c2010-01-28 14:27:37 -0800693 sp<MPEG4DataSource> cachedSource =
694 new MPEG4DataSource(mDataSource);
695
696 if (cachedSource->setCachedRange(*offset, chunk_size) == OK) {
697 mDataSource = cachedSource;
698 }
699 }
Andreas Hubereb9128f2010-05-14 15:28:51 -0700700
701 mLastTrack->sampleTable = new SampleTable(mDataSource);
Andreas Huberaffa99c2010-01-28 14:27:37 -0800702 }
703
Andreas Huber4d60fc52010-03-12 16:15:53 -0800704 bool isTrack = false;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800705 if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
Andreas Huber4d60fc52010-03-12 16:15:53 -0800706 isTrack = true;
707
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800708 Track *track = new Track;
709 track->next = NULL;
710 if (mLastTrack) {
711 mLastTrack->next = track;
712 } else {
713 mFirstTrack = track;
714 }
715 mLastTrack = track;
716
717 track->meta = new MetaData;
718 track->includes_expensive_metadata = false;
Andreas Huber4d60fc52010-03-12 16:15:53 -0800719 track->skipTrack = false;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800720 track->timescale = 0;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800721 track->meta->setCString(kKeyMIMEType, "application/octet-stream");
722 }
723
James Dongb1262a82010-11-16 14:04:54 -0800724 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700725 *offset = data_offset;
726 while (*offset < stop_offset) {
727 status_t err = parseChunk(offset, depth + 1);
728 if (err != OK) {
729 return err;
730 }
731 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700732
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800733 if (*offset != stop_offset) {
734 return ERROR_MALFORMED;
735 }
736
Andreas Huber4d60fc52010-03-12 16:15:53 -0800737 if (isTrack) {
738 if (mLastTrack->skipTrack) {
739 Track *cur = mFirstTrack;
740
741 if (cur == mLastTrack) {
742 delete cur;
743 mFirstTrack = mLastTrack = NULL;
744 } else {
745 while (cur && cur->next != mLastTrack) {
746 cur = cur->next;
747 }
748 cur->next = NULL;
749 delete mLastTrack;
750 mLastTrack = cur;
751 }
752
753 return OK;
754 }
755
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800756 status_t err = verifyTrack(mLastTrack);
757
758 if (err != OK) {
759 return err;
760 }
761 } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
Andreas Huberf80e45a2011-03-03 13:48:41 -0800762 mInitCheck = OK;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700763
Gloria Wangd5770912010-06-22 13:55:38 -0700764 if (!mIsDrm) {
765 return UNKNOWN_ERROR; // Return a dummy error.
766 } else {
767 return OK;
768 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700769 }
770 break;
771 }
772
773 case FOURCC('t', 'k', 'h', 'd'):
774 {
Andreas Huber940c8662010-11-16 15:26:30 -0800775 status_t err;
776 if ((err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
777 return err;
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800778 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700779
Andreas Hubere46b7be2009-07-14 16:56:47 -0700780 *offset += chunk_size;
781 break;
782 }
783
784 case FOURCC('m', 'd', 'h', 'd'):
785 {
786 if (chunk_data_size < 4) {
787 return ERROR_MALFORMED;
788 }
789
790 uint8_t version;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700791 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700792 data_offset, &version, sizeof(version))
793 < (ssize_t)sizeof(version)) {
794 return ERROR_IO;
795 }
796
James Dongb1262a82010-11-16 14:04:54 -0800797 off64_t timescale_offset;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700798
799 if (version == 1) {
800 timescale_offset = data_offset + 4 + 16;
801 } else if (version == 0) {
802 timescale_offset = data_offset + 4 + 8;
803 } else {
804 return ERROR_IO;
805 }
806
807 uint32_t timescale;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700808 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700809 timescale_offset, &timescale, sizeof(timescale))
810 < (ssize_t)sizeof(timescale)) {
811 return ERROR_IO;
812 }
813
814 mLastTrack->timescale = ntohl(timescale);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700815
816 int64_t duration;
817 if (version == 1) {
Andreas Huber9a12baf2009-10-23 10:22:30 -0700818 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700819 timescale_offset + 4, &duration, sizeof(duration))
820 < (ssize_t)sizeof(duration)) {
821 return ERROR_IO;
822 }
823 duration = ntoh64(duration);
824 } else {
825 int32_t duration32;
Andreas Huber9a12baf2009-10-23 10:22:30 -0700826 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700827 timescale_offset + 4, &duration32, sizeof(duration32))
828 < (ssize_t)sizeof(duration32)) {
829 return ERROR_IO;
830 }
831 duration = ntohl(duration32);
832 }
Andreas Huberfa8de752009-10-08 10:07:49 -0700833 mLastTrack->meta->setInt64(
834 kKeyDuration, (duration * 1000000) / mLastTrack->timescale);
Andreas Hubere46b7be2009-07-14 16:56:47 -0700835
Gloria Wangc6091dd2011-05-03 15:59:03 -0700836 uint8_t lang[2];
837 off64_t lang_offset;
838 if (version == 1) {
839 lang_offset = timescale_offset + 4 + 8;
840 } else if (version == 0) {
841 lang_offset = timescale_offset + 4 + 4;
842 } else {
843 return ERROR_IO;
844 }
845
846 if (mDataSource->readAt(lang_offset, &lang, sizeof(lang))
847 < (ssize_t)sizeof(lang)) {
848 return ERROR_IO;
849 }
850
851 // To get the ISO-639-2/T three character language code
852 // 1 bit pad followed by 3 5-bits characters. Each character
853 // is packed as the difference between its ASCII value and 0x60.
854 char lang_code[4];
855 lang_code[0] = ((lang[0] >> 2) & 0x1f) + 0x60;
856 lang_code[1] = ((lang[0] & 0x3) << 3 | (lang[1] >> 5)) + 0x60;
857 lang_code[2] = (lang[1] & 0x1f) + 0x60;
858 lang_code[3] = '\0';
859
860 mLastTrack->meta->setCString(
861 kKeyMediaLanguage, lang_code);
862
Andreas Hubere46b7be2009-07-14 16:56:47 -0700863 *offset += chunk_size;
864 break;
865 }
866
Andreas Hubere46b7be2009-07-14 16:56:47 -0700867 case FOURCC('s', 't', 's', 'd'):
868 {
869 if (chunk_data_size < 8) {
870 return ERROR_MALFORMED;
871 }
872
873 uint8_t buffer[8];
James Dongb1262a82010-11-16 14:04:54 -0800874 if (chunk_data_size < (off64_t)sizeof(buffer)) {
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800875 return ERROR_MALFORMED;
876 }
877
Andreas Huber9a12baf2009-10-23 10:22:30 -0700878 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700879 data_offset, buffer, 8) < 8) {
880 return ERROR_IO;
881 }
882
883 if (U32_AT(buffer) != 0) {
884 // Should be version 0, flags 0.
885 return ERROR_MALFORMED;
886 }
887
888 uint32_t entry_count = U32_AT(&buffer[4]);
889
890 if (entry_count > 1) {
891 // For now we only support a single type of media per track.
Andreas Huber4d60fc52010-03-12 16:15:53 -0800892
893 mLastTrack->skipTrack = true;
894 *offset += chunk_size;
895 break;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700896 }
897
James Dongb1262a82010-11-16 14:04:54 -0800898 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700899 *offset = data_offset + 8;
900 for (uint32_t i = 0; i < entry_count; ++i) {
901 status_t err = parseChunk(offset, depth + 1);
902 if (err != OK) {
903 return err;
904 }
905 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800906
907 if (*offset != stop_offset) {
908 return ERROR_MALFORMED;
909 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700910 break;
911 }
912
913 case FOURCC('m', 'p', '4', 'a'):
914 case FOURCC('s', 'a', 'm', 'r'):
Andreas Huber2a651172009-09-09 16:32:59 -0700915 case FOURCC('s', 'a', 'w', 'b'):
Andreas Hubere46b7be2009-07-14 16:56:47 -0700916 {
Andreas Hubere46b7be2009-07-14 16:56:47 -0700917 uint8_t buffer[8 + 20];
918 if (chunk_data_size < (ssize_t)sizeof(buffer)) {
919 // Basic AudioSampleEntry size.
920 return ERROR_MALFORMED;
921 }
922
Andreas Huber9a12baf2009-10-23 10:22:30 -0700923 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700924 data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
925 return ERROR_IO;
926 }
927
928 uint16_t data_ref_index = U16_AT(&buffer[6]);
929 uint16_t num_channels = U16_AT(&buffer[16]);
930
Andreas Hubere46b7be2009-07-14 16:56:47 -0700931 uint16_t sample_size = U16_AT(&buffer[18]);
932 uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
933
Andreas Huberd0332ad2010-04-12 16:05:57 -0700934 if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
935 FourCC2MIME(chunk_type))) {
936 // AMR NB audio is always mono, 8kHz
937 num_channels = 1;
938 sample_rate = 8000;
939 } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
940 FourCC2MIME(chunk_type))) {
941 // AMR WB audio is always mono, 16kHz
942 num_channels = 1;
943 sample_rate = 16000;
944 }
945
946#if 0
947 printf("*** coding='%s' %d channels, size %d, rate %d\n",
948 chunk, num_channels, sample_size, sample_rate);
949#endif
Andreas Hubere46b7be2009-07-14 16:56:47 -0700950
951 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
952 mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
953 mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);
954
James Dongb1262a82010-11-16 14:04:54 -0800955 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -0700956 *offset = data_offset + sizeof(buffer);
957 while (*offset < stop_offset) {
958 status_t err = parseChunk(offset, depth + 1);
959 if (err != OK) {
960 return err;
961 }
962 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -0800963
964 if (*offset != stop_offset) {
965 return ERROR_MALFORMED;
966 }
Andreas Hubere46b7be2009-07-14 16:56:47 -0700967 break;
968 }
969
970 case FOURCC('m', 'p', '4', 'v'):
971 case FOURCC('s', '2', '6', '3'):
James Dong0efdc952010-12-15 15:49:46 -0800972 case FOURCC('H', '2', '6', '3'):
973 case FOURCC('h', '2', '6', '3'):
Andreas Hubere46b7be2009-07-14 16:56:47 -0700974 case FOURCC('a', 'v', 'c', '1'):
975 {
Andreas Huber1cb02bf2010-01-13 11:25:10 -0800976 mHasVideo = true;
977
Andreas Hubere46b7be2009-07-14 16:56:47 -0700978 uint8_t buffer[78];
979 if (chunk_data_size < (ssize_t)sizeof(buffer)) {
980 // Basic VideoSampleEntry size.
981 return ERROR_MALFORMED;
982 }
983
Andreas Huber9a12baf2009-10-23 10:22:30 -0700984 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -0700985 data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
986 return ERROR_IO;
987 }
988
989 uint16_t data_ref_index = U16_AT(&buffer[6]);
990 uint16_t width = U16_AT(&buffer[6 + 18]);
991 uint16_t height = U16_AT(&buffer[6 + 20]);
992
James Dongc9e1c802010-12-15 17:32:45 -0800993 // The video sample is not stand-compliant if it has invalid dimension.
994 // Use some default width and height value, and
995 // let the decoder figure out the actual width and height (and thus
996 // be prepared for INFO_FOMRAT_CHANGED event).
997 if (width == 0) width = 352;
998 if (height == 0) height = 288;
999
Andreas Huber2ea14e22009-12-16 09:30:55 -08001000 // printf("*** coding='%s' width=%d height=%d\n",
1001 // chunk, width, height);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001002
1003 mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
1004 mLastTrack->meta->setInt32(kKeyWidth, width);
1005 mLastTrack->meta->setInt32(kKeyHeight, height);
1006
James Dongb1262a82010-11-16 14:04:54 -08001007 off64_t stop_offset = *offset + chunk_size;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001008 *offset = data_offset + sizeof(buffer);
1009 while (*offset < stop_offset) {
1010 status_t err = parseChunk(offset, depth + 1);
1011 if (err != OK) {
1012 return err;
1013 }
1014 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001015
1016 if (*offset != stop_offset) {
1017 return ERROR_MALFORMED;
1018 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001019 break;
1020 }
1021
1022 case FOURCC('s', 't', 'c', 'o'):
1023 case FOURCC('c', 'o', '6', '4'):
1024 {
1025 status_t err =
1026 mLastTrack->sampleTable->setChunkOffsetParams(
1027 chunk_type, data_offset, chunk_data_size);
1028
1029 if (err != OK) {
1030 return err;
1031 }
1032
1033 *offset += chunk_size;
1034 break;
1035 }
1036
1037 case FOURCC('s', 't', 's', 'c'):
1038 {
1039 status_t err =
1040 mLastTrack->sampleTable->setSampleToChunkParams(
1041 data_offset, chunk_data_size);
1042
1043 if (err != OK) {
1044 return err;
1045 }
1046
1047 *offset += chunk_size;
1048 break;
1049 }
1050
1051 case FOURCC('s', 't', 's', 'z'):
1052 case FOURCC('s', 't', 'z', '2'):
1053 {
1054 status_t err =
1055 mLastTrack->sampleTable->setSampleSizeParams(
1056 chunk_type, data_offset, chunk_data_size);
1057
1058 if (err != OK) {
1059 return err;
1060 }
1061
Andreas Huber1bceff92009-11-23 14:03:32 -08001062 size_t max_size;
Andreas Huberd7f22252010-09-09 10:10:15 -07001063 err = mLastTrack->sampleTable->getMaxSampleSize(&max_size);
1064
1065 if (err != OK) {
1066 return err;
1067 }
Andreas Huber1bceff92009-11-23 14:03:32 -08001068
1069 // Assume that a given buffer only contains at most 10 fragments,
1070 // each fragment originally prefixed with a 2 byte length will
1071 // have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
1072 // and thus will grow by 2 bytes per fragment.
1073 mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size + 10 * 2);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001074 *offset += chunk_size;
James Dongcbb488d2011-01-19 00:13:55 -08001075
1076 // Calculate average frame rate.
1077 const char *mime;
1078 CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
1079 if (!strncasecmp("video/", mime, 6)) {
1080 size_t nSamples = mLastTrack->sampleTable->countSamples();
1081 int64_t durationUs;
1082 if (mLastTrack->meta->findInt64(kKeyDuration, &durationUs)) {
1083 if (durationUs > 0) {
1084 int32_t frameRate = (nSamples * 1000000LL +
1085 (durationUs >> 1)) / durationUs;
1086 mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
1087 }
1088 }
1089 }
1090
Andreas Hubere46b7be2009-07-14 16:56:47 -07001091 break;
1092 }
1093
1094 case FOURCC('s', 't', 't', 's'):
1095 {
1096 status_t err =
1097 mLastTrack->sampleTable->setTimeToSampleParams(
1098 data_offset, chunk_data_size);
1099
1100 if (err != OK) {
1101 return err;
1102 }
1103
1104 *offset += chunk_size;
1105 break;
1106 }
1107
Andreas Huberbd352c32011-02-03 13:18:16 -08001108 case FOURCC('c', 't', 't', 's'):
1109 {
1110 status_t err =
1111 mLastTrack->sampleTable->setCompositionTimeToSampleParams(
1112 data_offset, chunk_data_size);
1113
1114 if (err != OK) {
1115 return err;
1116 }
1117
1118 *offset += chunk_size;
1119 break;
1120 }
1121
Andreas Hubere46b7be2009-07-14 16:56:47 -07001122 case FOURCC('s', 't', 's', 's'):
1123 {
1124 status_t err =
1125 mLastTrack->sampleTable->setSyncSampleParams(
1126 data_offset, chunk_data_size);
1127
1128 if (err != OK) {
1129 return err;
1130 }
1131
1132 *offset += chunk_size;
1133 break;
1134 }
1135
1136 case FOURCC('e', 's', 'd', 's'):
1137 {
1138 if (chunk_data_size < 4) {
1139 return ERROR_MALFORMED;
1140 }
1141
1142 uint8_t buffer[256];
James Dongb1262a82010-11-16 14:04:54 -08001143 if (chunk_data_size > (off64_t)sizeof(buffer)) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001144 return ERROR_BUFFER_TOO_SMALL;
1145 }
1146
Andreas Huber9a12baf2009-10-23 10:22:30 -07001147 if (mDataSource->readAt(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001148 data_offset, buffer, chunk_data_size) < chunk_data_size) {
1149 return ERROR_IO;
1150 }
1151
1152 if (U32_AT(buffer) != 0) {
1153 // Should be version 0, flags 0.
1154 return ERROR_MALFORMED;
1155 }
1156
1157 mLastTrack->meta->setData(
1158 kKeyESDS, kTypeESDS, &buffer[4], chunk_data_size - 4);
1159
Andreas Huberd2315962010-01-29 14:46:59 -08001160 if (mPath.size() >= 2
1161 && mPath[mPath.size() - 2] == FOURCC('m', 'p', '4', 'a')) {
1162 // Information from the ESDS must be relied on for proper
1163 // setup of sample rate and channel count for MPEG4 Audio.
1164 // The generic header appears to only contain generic
1165 // information...
1166
1167 status_t err = updateAudioTrackInfoFromESDS_MPEG4Audio(
1168 &buffer[4], chunk_data_size - 4);
1169
1170 if (err != OK) {
1171 return err;
1172 }
1173 }
1174
Andreas Hubere46b7be2009-07-14 16:56:47 -07001175 *offset += chunk_size;
1176 break;
1177 }
1178
1179 case FOURCC('a', 'v', 'c', 'C'):
1180 {
1181 char 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 mLastTrack->meta->setData(
1192 kKeyAVCC, kTypeAVCC, buffer, chunk_data_size);
1193
1194 *offset += chunk_size;
1195 break;
1196 }
1197
James Dongfe84cf12011-02-11 15:21:45 -08001198 case FOURCC('d', '2', '6', '3'):
1199 {
James Dongbc5f1f52011-02-23 17:07:49 -08001200 /*
1201 * d263 contains a fixed 7 bytes part:
1202 * vendor - 4 bytes
1203 * version - 1 byte
1204 * level - 1 byte
1205 * profile - 1 byte
1206 * optionally, "d263" box itself may contain a 16-byte
1207 * bit rate box (bitr)
1208 * average bit rate - 4 bytes
1209 * max bit rate - 4 bytes
1210 */
1211 char buffer[23];
1212 if (chunk_data_size != 7 &&
1213 chunk_data_size != 23) {
James Dongfe84cf12011-02-11 15:21:45 -08001214 LOGE("Incorrect D263 box size %lld", chunk_data_size);
1215 return ERROR_MALFORMED;
1216 }
1217
1218 if (mDataSource->readAt(
1219 data_offset, buffer, chunk_data_size) < chunk_data_size) {
1220 return ERROR_IO;
1221 }
1222
1223 mLastTrack->meta->setData(kKeyD263, kTypeD263, buffer, chunk_data_size);
1224
1225 *offset += chunk_size;
1226 break;
1227 }
1228
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001229 case FOURCC('m', 'e', 't', 'a'):
1230 {
1231 uint8_t buffer[4];
James Dongb1262a82010-11-16 14:04:54 -08001232 if (chunk_data_size < (off64_t)sizeof(buffer)) {
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001233 return ERROR_MALFORMED;
1234 }
1235
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001236 if (mDataSource->readAt(
1237 data_offset, buffer, 4) < 4) {
1238 return ERROR_IO;
1239 }
1240
1241 if (U32_AT(buffer) != 0) {
1242 // Should be version 0, flags 0.
Andreas Huberdfb8eee2010-02-25 15:59:24 -08001243
1244 // If it's not, let's assume this is one of those
1245 // apparently malformed chunks that don't have flags
1246 // and completely different semantics than what's
1247 // in the MPEG4 specs and skip it.
1248 *offset += chunk_size;
1249 return OK;
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001250 }
1251
James Dongb1262a82010-11-16 14:04:54 -08001252 off64_t stop_offset = *offset + chunk_size;
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001253 *offset = data_offset + sizeof(buffer);
1254 while (*offset < stop_offset) {
1255 status_t err = parseChunk(offset, depth + 1);
1256 if (err != OK) {
1257 return err;
1258 }
1259 }
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001260
1261 if (*offset != stop_offset) {
1262 return ERROR_MALFORMED;
1263 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001264 break;
1265 }
1266
1267 case FOURCC('d', 'a', 't', 'a'):
1268 {
1269 if (mPath.size() == 6 && underMetaDataPath(mPath)) {
1270 status_t err = parseMetaData(data_offset, chunk_data_size);
1271
1272 if (err != OK) {
1273 return err;
1274 }
1275 }
1276
1277 *offset += chunk_size;
1278 break;
1279 }
1280
1281 case FOURCC('m', 'v', 'h', 'd'):
1282 {
1283 if (chunk_data_size < 12) {
1284 return ERROR_MALFORMED;
1285 }
1286
1287 uint8_t header[12];
1288 if (mDataSource->readAt(
1289 data_offset, header, sizeof(header))
1290 < (ssize_t)sizeof(header)) {
1291 return ERROR_IO;
1292 }
1293
1294 int64_t creationTime;
1295 if (header[0] == 1) {
1296 creationTime = U64_AT(&header[4]);
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001297 } else if (header[0] != 0) {
1298 return ERROR_MALFORMED;
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001299 } else {
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001300 creationTime = U32_AT(&header[4]);
1301 }
1302
1303 String8 s;
1304 convertTimeToDate(creationTime, &s);
1305
1306 mFileMetaData->setCString(kKeyDate, s.string());
1307
1308 *offset += chunk_size;
1309 break;
1310 }
1311
Gloria Wangd5770912010-06-22 13:55:38 -07001312 case FOURCC('m', 'd', 'a', 't'):
1313 {
1314 if (!mIsDrm) {
1315 *offset += chunk_size;
1316 break;
1317 }
1318
1319 if (chunk_size < 8) {
1320 return ERROR_MALFORMED;
1321 }
1322
1323 return parseDrmSINF(offset, data_offset);
1324 }
1325
Gloria Wangc6091dd2011-05-03 15:59:03 -07001326 case FOURCC('t', 'x', '3', 'g'):
1327 {
1328 mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_TEXT_3GPP);
1329
1330 *offset += chunk_size;
1331 break;
1332 }
1333
Andreas Hubere46b7be2009-07-14 16:56:47 -07001334 default:
1335 {
1336 *offset += chunk_size;
1337 break;
1338 }
1339 }
1340
1341 return OK;
1342}
1343
Andreas Huber940c8662010-11-16 15:26:30 -08001344status_t MPEG4Extractor::parseTrackHeader(
James Dongb1262a82010-11-16 14:04:54 -08001345 off64_t data_offset, off64_t data_size) {
Andreas Huber940c8662010-11-16 15:26:30 -08001346 if (data_size < 4) {
1347 return ERROR_MALFORMED;
1348 }
1349
1350 uint8_t version;
1351 if (mDataSource->readAt(data_offset, &version, 1) < 1) {
1352 return ERROR_IO;
1353 }
1354
1355 size_t dynSize = (version == 1) ? 36 : 24;
1356
1357 uint8_t buffer[36 + 60];
1358
James Dongb1262a82010-11-16 14:04:54 -08001359 if (data_size != (off64_t)dynSize + 60) {
Andreas Huber940c8662010-11-16 15:26:30 -08001360 return ERROR_MALFORMED;
1361 }
1362
1363 if (mDataSource->readAt(
1364 data_offset, buffer, data_size) < (ssize_t)data_size) {
1365 return ERROR_IO;
1366 }
1367
1368 uint64_t ctime, mtime, duration;
1369 int32_t id;
1370
1371 if (version == 1) {
1372 ctime = U64_AT(&buffer[4]);
1373 mtime = U64_AT(&buffer[12]);
1374 id = U32_AT(&buffer[20]);
1375 duration = U64_AT(&buffer[28]);
1376 } else {
1377 CHECK_EQ((unsigned)version, 0u);
1378
1379 ctime = U32_AT(&buffer[4]);
1380 mtime = U32_AT(&buffer[8]);
1381 id = U32_AT(&buffer[12]);
1382 duration = U32_AT(&buffer[20]);
1383 }
1384
1385 mLastTrack->meta->setInt32(kKeyTrackID, id);
1386
1387 size_t matrixOffset = dynSize + 16;
1388 int32_t a00 = U32_AT(&buffer[matrixOffset]);
1389 int32_t a01 = U32_AT(&buffer[matrixOffset + 4]);
1390 int32_t dx = U32_AT(&buffer[matrixOffset + 8]);
1391 int32_t a10 = U32_AT(&buffer[matrixOffset + 12]);
1392 int32_t a11 = U32_AT(&buffer[matrixOffset + 16]);
1393 int32_t dy = U32_AT(&buffer[matrixOffset + 20]);
1394
1395#if 0
1396 LOGI("x' = %.2f * x + %.2f * y + %.2f",
1397 a00 / 65536.0f, a01 / 65536.0f, dx / 65536.0f);
1398 LOGI("y' = %.2f * x + %.2f * y + %.2f",
1399 a10 / 65536.0f, a11 / 65536.0f, dy / 65536.0f);
1400#endif
1401
1402 uint32_t rotationDegrees;
1403
1404 static const int32_t kFixedOne = 0x10000;
1405 if (a00 == kFixedOne && a01 == 0 && a10 == 0 && a11 == kFixedOne) {
1406 // Identity, no rotation
1407 rotationDegrees = 0;
1408 } else if (a00 == 0 && a01 == kFixedOne && a10 == -kFixedOne && a11 == 0) {
1409 rotationDegrees = 90;
1410 } else if (a00 == 0 && a01 == -kFixedOne && a10 == kFixedOne && a11 == 0) {
1411 rotationDegrees = 270;
1412 } else if (a00 == -kFixedOne && a01 == 0 && a10 == 0 && a11 == -kFixedOne) {
1413 rotationDegrees = 180;
1414 } else {
1415 LOGW("We only support 0,90,180,270 degree rotation matrices");
1416 rotationDegrees = 0;
1417 }
1418
1419 if (rotationDegrees != 0) {
1420 mLastTrack->meta->setInt32(kKeyRotation, rotationDegrees);
1421 }
1422
James Dong08adfd22011-01-16 11:30:13 -08001423 // Handle presentation display size, which could be different
1424 // from the image size indicated by kKeyWidth and kKeyHeight.
Andreas Huber940c8662010-11-16 15:26:30 -08001425 uint32_t width = U32_AT(&buffer[dynSize + 52]);
1426 uint32_t height = U32_AT(&buffer[dynSize + 56]);
James Dong08adfd22011-01-16 11:30:13 -08001427 mLastTrack->meta->setInt32(kKeyDisplayWidth, width >> 16);
1428 mLastTrack->meta->setInt32(kKeyDisplayHeight, height >> 16);
Andreas Huber940c8662010-11-16 15:26:30 -08001429
1430 return OK;
1431}
1432
James Dongb1262a82010-11-16 14:04:54 -08001433status_t MPEG4Extractor::parseMetaData(off64_t offset, size_t size) {
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001434 if (size < 4) {
1435 return ERROR_MALFORMED;
1436 }
1437
1438 uint8_t *buffer = new uint8_t[size + 1];
1439 if (mDataSource->readAt(
1440 offset, buffer, size) != (ssize_t)size) {
1441 delete[] buffer;
1442 buffer = NULL;
1443
1444 return ERROR_IO;
1445 }
1446
1447 uint32_t flags = U32_AT(buffer);
1448
1449 uint32_t metadataKey = 0;
1450 switch (mPath[4]) {
1451 case FOURCC(0xa9, 'a', 'l', 'b'):
1452 {
1453 metadataKey = kKeyAlbum;
1454 break;
1455 }
1456 case FOURCC(0xa9, 'A', 'R', 'T'):
1457 {
1458 metadataKey = kKeyArtist;
1459 break;
1460 }
Marco Nelissenc5d5ee32010-02-11 13:31:44 -08001461 case FOURCC('a', 'A', 'R', 'T'):
1462 {
1463 metadataKey = kKeyAlbumArtist;
1464 break;
1465 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001466 case FOURCC(0xa9, 'd', 'a', 'y'):
1467 {
1468 metadataKey = kKeyYear;
1469 break;
1470 }
1471 case FOURCC(0xa9, 'n', 'a', 'm'):
1472 {
1473 metadataKey = kKeyTitle;
1474 break;
1475 }
1476 case FOURCC(0xa9, 'w', 'r', 't'):
1477 {
1478 metadataKey = kKeyWriter;
1479 break;
1480 }
1481 case FOURCC('c', 'o', 'v', 'r'):
1482 {
1483 metadataKey = kKeyAlbumArt;
1484 break;
1485 }
1486 case FOURCC('g', 'n', 'r', 'e'):
1487 {
1488 metadataKey = kKeyGenre;
1489 break;
1490 }
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001491 case FOURCC(0xa9, 'g', 'e', 'n'):
1492 {
1493 metadataKey = kKeyGenre;
1494 break;
1495 }
Marco Nelissenee35aff2011-01-06 11:12:17 -08001496 case FOURCC('c', 'p', 'i', 'l'):
1497 {
1498 if (size == 9 && flags == 21) {
1499 char tmp[16];
1500 sprintf(tmp, "%d",
1501 (int)buffer[size - 1]);
1502
1503 mFileMetaData->setCString(kKeyCompilation, tmp);
1504 }
1505 break;
1506 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001507 case FOURCC('t', 'r', 'k', 'n'):
1508 {
1509 if (size == 16 && flags == 0) {
1510 char tmp[16];
1511 sprintf(tmp, "%d/%d",
1512 (int)buffer[size - 5], (int)buffer[size - 3]);
1513
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001514 mFileMetaData->setCString(kKeyCDTrackNumber, tmp);
1515 }
1516 break;
1517 }
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001518 case FOURCC('d', 'i', 's', 'k'):
1519 {
1520 if (size == 14 && flags == 0) {
1521 char tmp[16];
1522 sprintf(tmp, "%d/%d",
1523 (int)buffer[size - 3], (int)buffer[size - 1]);
1524
1525 mFileMetaData->setCString(kKeyDiscNumber, tmp);
1526 }
1527 break;
1528 }
1529
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001530 default:
1531 break;
1532 }
1533
1534 if (size >= 8 && metadataKey) {
1535 if (metadataKey == kKeyAlbumArt) {
1536 mFileMetaData->setData(
1537 kKeyAlbumArt, MetaData::TYPE_NONE,
1538 buffer + 8, size - 8);
1539 } else if (metadataKey == kKeyGenre) {
1540 if (flags == 0) {
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001541 // uint8_t genre code, iTunes genre codes are
1542 // the standard id3 codes, except they start
1543 // at 1 instead of 0 (e.g. Pop is 14, not 13)
1544 // We use standard id3 numbering, so subtract 1.
1545 int genrecode = (int)buffer[size - 1];
1546 genrecode--;
1547 if (genrecode < 0) {
1548 genrecode = 255; // reserved for 'unknown genre'
1549 }
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001550 char genre[10];
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001551 sprintf(genre, "%d", genrecode);
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001552
1553 mFileMetaData->setCString(metadataKey, genre);
Marco Nelissenfe3b8e92010-02-09 14:02:16 -08001554 } else if (flags == 1) {
1555 // custom genre string
1556 buffer[size] = '\0';
1557
1558 mFileMetaData->setCString(
1559 metadataKey, (const char *)buffer + 8);
Andreas Huberc2c9dd32010-01-19 16:43:53 -08001560 }
1561 } else {
1562 buffer[size] = '\0';
1563
1564 mFileMetaData->setCString(
1565 metadataKey, (const char *)buffer + 8);
1566 }
1567 }
1568
1569 delete[] buffer;
1570 buffer = NULL;
1571
1572 return OK;
1573}
1574
Andreas Huberbe06d262009-08-14 14:37:10 -07001575sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001576 status_t err;
1577 if ((err = readMetaData()) != OK) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001578 return NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001579 }
1580
1581 Track *track = mFirstTrack;
1582 while (index > 0) {
1583 if (track == NULL) {
Andreas Huberbe06d262009-08-14 14:37:10 -07001584 return NULL;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001585 }
1586
1587 track = track->next;
1588 --index;
1589 }
1590
Andreas Huber2a651172009-09-09 16:32:59 -07001591 if (track == NULL) {
1592 return NULL;
1593 }
1594
Andreas Huberbe06d262009-08-14 14:37:10 -07001595 return new MPEG4Source(
Andreas Huberfa8de752009-10-08 10:07:49 -07001596 track->meta, mDataSource, track->timescale, track->sampleTable);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001597}
1598
Andreas Huber5ee0bce2010-02-23 10:12:02 -08001599// static
1600status_t MPEG4Extractor::verifyTrack(Track *track) {
1601 const char *mime;
1602 CHECK(track->meta->findCString(kKeyMIMEType, &mime));
1603
1604 uint32_t type;
1605 const void *data;
1606 size_t size;
1607 if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
1608 if (!track->meta->findData(kKeyAVCC, &type, &data, &size)
1609 || type != kTypeAVCC) {
1610 return ERROR_MALFORMED;
1611 }
1612 } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)
1613 || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
1614 if (!track->meta->findData(kKeyESDS, &type, &data, &size)
1615 || type != kTypeESDS) {
1616 return ERROR_MALFORMED;
1617 }
1618 }
1619
1620 return OK;
1621}
1622
Andreas Huberd2315962010-01-29 14:46:59 -08001623status_t MPEG4Extractor::updateAudioTrackInfoFromESDS_MPEG4Audio(
1624 const void *esds_data, size_t esds_size) {
1625 ESDS esds(esds_data, esds_size);
Andreas Huberd0332ad2010-04-12 16:05:57 -07001626
1627 uint8_t objectTypeIndication;
1628 if (esds.getObjectTypeIndication(&objectTypeIndication) != OK) {
1629 return ERROR_MALFORMED;
1630 }
1631
1632 if (objectTypeIndication == 0xe1) {
1633 // This isn't MPEG4 audio at all, it's QCELP 14k...
1634 mLastTrack->meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_QCELP);
1635 return OK;
1636 }
1637
James Donge883d312011-02-24 21:16:54 -08001638 if (objectTypeIndication == 0x6b) {
1639 // The media subtype is MP3 audio
1640 // Our software MP3 audio decoder may not be able to handle
1641 // packetized MP3 audio; for now, lets just return ERROR_UNSUPPORTED
1642 LOGE("MP3 track in MP4/3GPP file is not supported");
1643 return ERROR_UNSUPPORTED;
1644 }
1645
Andreas Huberd2315962010-01-29 14:46:59 -08001646 const uint8_t *csd;
1647 size_t csd_size;
1648 if (esds.getCodecSpecificInfo(
1649 (const void **)&csd, &csd_size) != OK) {
1650 return ERROR_MALFORMED;
1651 }
1652
1653#if 0
1654 printf("ESD of size %d\n", csd_size);
1655 hexdump(csd, csd_size);
1656#endif
1657
Andreas Huber08c94b22010-08-18 09:58:30 -07001658 if (csd_size == 0) {
1659 // There's no further information, i.e. no codec specific data
1660 // Let's assume that the information provided in the mpeg4 headers
1661 // is accurate and hope for the best.
1662
1663 return OK;
1664 }
1665
Andreas Huberd2315962010-01-29 14:46:59 -08001666 if (csd_size < 2) {
1667 return ERROR_MALFORMED;
1668 }
1669
1670 uint32_t objectType = csd[0] >> 3;
1671
1672 if (objectType == 31) {
1673 return ERROR_UNSUPPORTED;
1674 }
1675
1676 uint32_t freqIndex = (csd[0] & 7) << 1 | (csd[1] >> 7);
1677 int32_t sampleRate = 0;
1678 int32_t numChannels = 0;
1679 if (freqIndex == 15) {
1680 if (csd_size < 5) {
1681 return ERROR_MALFORMED;
1682 }
1683
1684 sampleRate = (csd[1] & 0x7f) << 17
1685 | csd[2] << 9
1686 | csd[3] << 1
1687 | (csd[4] >> 7);
1688
1689 numChannels = (csd[4] >> 3) & 15;
1690 } else {
Andreas Hubercc14a832010-07-20 09:21:17 -07001691 static uint32_t kSamplingRate[] = {
1692 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1693 16000, 12000, 11025, 8000, 7350
1694 };
Andreas Huberd2315962010-01-29 14:46:59 -08001695
1696 if (freqIndex == 13 || freqIndex == 14) {
1697 return ERROR_MALFORMED;
1698 }
1699
1700 sampleRate = kSamplingRate[freqIndex];
1701 numChannels = (csd[1] >> 3) & 15;
1702 }
1703
1704 if (numChannels == 0) {
1705 return ERROR_UNSUPPORTED;
1706 }
1707
1708 int32_t prevSampleRate;
1709 CHECK(mLastTrack->meta->findInt32(kKeySampleRate, &prevSampleRate));
1710
1711 if (prevSampleRate != sampleRate) {
Andreas Huber4a9375e2010-02-09 11:54:33 -08001712 LOGV("mpeg4 audio sample rate different from previous setting. "
Andreas Huberd2315962010-01-29 14:46:59 -08001713 "was: %d, now: %d", prevSampleRate, sampleRate);
1714 }
1715
1716 mLastTrack->meta->setInt32(kKeySampleRate, sampleRate);
1717
1718 int32_t prevChannelCount;
1719 CHECK(mLastTrack->meta->findInt32(kKeyChannelCount, &prevChannelCount));
1720
1721 if (prevChannelCount != numChannels) {
Andreas Huber4a9375e2010-02-09 11:54:33 -08001722 LOGV("mpeg4 audio channel count different from previous setting. "
Andreas Huberd2315962010-01-29 14:46:59 -08001723 "was: %d, now: %d", prevChannelCount, numChannels);
1724 }
1725
1726 mLastTrack->meta->setInt32(kKeyChannelCount, numChannels);
1727
1728 return OK;
1729}
1730
Andreas Hubere46b7be2009-07-14 16:56:47 -07001731////////////////////////////////////////////////////////////////////////////////
1732
1733MPEG4Source::MPEG4Source(
1734 const sp<MetaData> &format,
Andreas Huberbe06d262009-08-14 14:37:10 -07001735 const sp<DataSource> &dataSource,
Andreas Huberfa8de752009-10-08 10:07:49 -07001736 int32_t timeScale,
Andreas Huberbe06d262009-08-14 14:37:10 -07001737 const sp<SampleTable> &sampleTable)
Andreas Hubere46b7be2009-07-14 16:56:47 -07001738 : mFormat(format),
1739 mDataSource(dataSource),
Andreas Huberfa8de752009-10-08 10:07:49 -07001740 mTimescale(timeScale),
Andreas Hubere46b7be2009-07-14 16:56:47 -07001741 mSampleTable(sampleTable),
1742 mCurrentSampleIndex(0),
1743 mIsAVC(false),
Andreas Huberdb5d6622010-01-12 16:30:44 -08001744 mNALLengthSize(0),
Andreas Hubere46b7be2009-07-14 16:56:47 -07001745 mStarted(false),
1746 mGroup(NULL),
1747 mBuffer(NULL),
Andreas Huber4f5e6022009-08-19 09:29:34 -07001748 mWantsNALFragments(false),
Andreas Huber8a432772009-07-28 10:03:13 -07001749 mSrcBuffer(NULL) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07001750 const char *mime;
1751 bool success = mFormat->findCString(kKeyMIMEType, &mime);
Andreas Huber4f5e6022009-08-19 09:29:34 -07001752 CHECK(success);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001753
Andreas Hubere6c40962009-09-10 14:13:30 -07001754 mIsAVC = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
Andreas Huberdb5d6622010-01-12 16:30:44 -08001755
1756 if (mIsAVC) {
1757 uint32_t type;
1758 const void *data;
1759 size_t size;
1760 CHECK(format->findData(kKeyAVCC, &type, &data, &size));
1761
1762 const uint8_t *ptr = (const uint8_t *)data;
1763
1764 CHECK(size >= 7);
Andreas Huber940c8662010-11-16 15:26:30 -08001765 CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
Andreas Huberdb5d6622010-01-12 16:30:44 -08001766
1767 // The number of bytes used to encode the length of a NAL unit.
1768 mNALLengthSize = 1 + (ptr[4] & 3);
1769 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001770}
1771
1772MPEG4Source::~MPEG4Source() {
1773 if (mStarted) {
1774 stop();
1775 }
1776}
1777
1778status_t MPEG4Source::start(MetaData *params) {
Andreas Huberba7ec912010-02-12 10:42:02 -08001779 Mutex::Autolock autoLock(mLock);
1780
Andreas Huber4f5e6022009-08-19 09:29:34 -07001781 CHECK(!mStarted);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001782
1783 int32_t val;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001784 if (params && params->findInt32(kKeyWantsNALFragments, &val)
Andreas Hubere46b7be2009-07-14 16:56:47 -07001785 && val != 0) {
Andreas Huber4f5e6022009-08-19 09:29:34 -07001786 mWantsNALFragments = true;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001787 } else {
Andreas Huber4f5e6022009-08-19 09:29:34 -07001788 mWantsNALFragments = false;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001789 }
1790
1791 mGroup = new MediaBufferGroup;
1792
Andreas Huber1bceff92009-11-23 14:03:32 -08001793 int32_t max_size;
1794 CHECK(mFormat->findInt32(kKeyMaxInputSize, &max_size));
Andreas Hubere46b7be2009-07-14 16:56:47 -07001795
Andreas Huber1bceff92009-11-23 14:03:32 -08001796 mGroup->add_buffer(new MediaBuffer(max_size));
Andreas Huber8a432772009-07-28 10:03:13 -07001797
1798 mSrcBuffer = new uint8_t[max_size];
Andreas Hubere46b7be2009-07-14 16:56:47 -07001799
1800 mStarted = true;
1801
1802 return OK;
1803}
1804
1805status_t MPEG4Source::stop() {
Andreas Huberba7ec912010-02-12 10:42:02 -08001806 Mutex::Autolock autoLock(mLock);
1807
Andreas Huber4f5e6022009-08-19 09:29:34 -07001808 CHECK(mStarted);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001809
1810 if (mBuffer != NULL) {
1811 mBuffer->release();
1812 mBuffer = NULL;
1813 }
1814
Andreas Huber8a432772009-07-28 10:03:13 -07001815 delete[] mSrcBuffer;
1816 mSrcBuffer = NULL;
1817
Andreas Hubere46b7be2009-07-14 16:56:47 -07001818 delete mGroup;
1819 mGroup = NULL;
1820
1821 mStarted = false;
1822 mCurrentSampleIndex = 0;
1823
1824 return OK;
1825}
1826
1827sp<MetaData> MPEG4Source::getFormat() {
Andreas Huberba7ec912010-02-12 10:42:02 -08001828 Mutex::Autolock autoLock(mLock);
1829
Andreas Hubere46b7be2009-07-14 16:56:47 -07001830 return mFormat;
1831}
1832
Andreas Huberdb5d6622010-01-12 16:30:44 -08001833size_t MPEG4Source::parseNALSize(const uint8_t *data) const {
1834 switch (mNALLengthSize) {
1835 case 1:
1836 return *data;
1837 case 2:
1838 return U16_AT(data);
1839 case 3:
1840 return ((size_t)data[0] << 16) | U16_AT(&data[1]);
1841 case 4:
1842 return U32_AT(data);
1843 }
1844
1845 // This cannot happen, mNALLengthSize springs to life by adding 1 to
1846 // a 2-bit integer.
1847 CHECK(!"Should not be here.");
1848
1849 return 0;
1850}
1851
Andreas Hubere46b7be2009-07-14 16:56:47 -07001852status_t MPEG4Source::read(
1853 MediaBuffer **out, const ReadOptions *options) {
Andreas Huberba7ec912010-02-12 10:42:02 -08001854 Mutex::Autolock autoLock(mLock);
1855
Andreas Huber4f5e6022009-08-19 09:29:34 -07001856 CHECK(mStarted);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001857
1858 *out = NULL;
1859
Andreas Huber6624c9f2010-07-20 15:04:28 -07001860 int64_t targetSampleTimeUs = -1;
1861
Andreas Hubere46b7be2009-07-14 16:56:47 -07001862 int64_t seekTimeUs;
Andreas Huber6624c9f2010-07-20 15:04:28 -07001863 ReadOptions::SeekMode mode;
1864 if (options && options->getSeekTo(&seekTimeUs, &mode)) {
1865 uint32_t findFlags = 0;
1866 switch (mode) {
1867 case ReadOptions::SEEK_PREVIOUS_SYNC:
1868 findFlags = SampleTable::kFlagBefore;
1869 break;
1870 case ReadOptions::SEEK_NEXT_SYNC:
1871 findFlags = SampleTable::kFlagAfter;
1872 break;
1873 case ReadOptions::SEEK_CLOSEST_SYNC:
1874 case ReadOptions::SEEK_CLOSEST:
1875 findFlags = SampleTable::kFlagClosest;
1876 break;
1877 default:
1878 CHECK(!"Should not be here.");
1879 break;
1880 }
1881
Andreas Hubere46b7be2009-07-14 16:56:47 -07001882 uint32_t sampleIndex;
Andreas Huber6624c9f2010-07-20 15:04:28 -07001883 status_t err = mSampleTable->findSampleAtTime(
Andreas Hubere46b7be2009-07-14 16:56:47 -07001884 seekTimeUs * mTimescale / 1000000,
Andreas Huber6624c9f2010-07-20 15:04:28 -07001885 &sampleIndex, findFlags);
1886
1887 if (mode == ReadOptions::SEEK_CLOSEST) {
1888 // We found the closest sample already, now we want the sync
1889 // sample preceding it (or the sample itself of course), even
1890 // if the subsequent sync sample is closer.
1891 findFlags = SampleTable::kFlagBefore;
1892 }
1893
1894 uint32_t syncSampleIndex;
1895 if (err == OK) {
1896 err = mSampleTable->findSyncSampleNear(
1897 sampleIndex, &syncSampleIndex, findFlags);
1898 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001899
1900 if (err != OK) {
Andreas Huberd7d22eb2010-02-23 13:45:33 -08001901 if (err == ERROR_OUT_OF_RANGE) {
1902 // An attempt to seek past the end of the stream would
1903 // normally cause this ERROR_OUT_OF_RANGE error. Propagating
1904 // this all the way to the MediaPlayer would cause abnormal
1905 // termination. Legacy behaviour appears to be to behave as if
1906 // we had seeked to the end of stream, ending normally.
1907 err = ERROR_END_OF_STREAM;
1908 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001909 return err;
1910 }
1911
Andreas Huber6624c9f2010-07-20 15:04:28 -07001912 uint32_t sampleTime;
Andreas Huber940c8662010-11-16 15:26:30 -08001913 CHECK_EQ((status_t)OK, mSampleTable->getMetaDataForSample(
Andreas Huber6624c9f2010-07-20 15:04:28 -07001914 sampleIndex, NULL, NULL, &sampleTime));
1915
1916 if (mode == ReadOptions::SEEK_CLOSEST) {
1917 targetSampleTimeUs = (sampleTime * 1000000ll) / mTimescale;
1918 }
1919
1920#if 0
1921 uint32_t syncSampleTime;
1922 CHECK_EQ(OK, mSampleTable->getMetaDataForSample(
1923 syncSampleIndex, NULL, NULL, &syncSampleTime));
1924
1925 LOGI("seek to time %lld us => sample at time %lld us, "
1926 "sync sample at time %lld us",
1927 seekTimeUs,
1928 sampleTime * 1000000ll / mTimescale,
1929 syncSampleTime * 1000000ll / mTimescale);
1930#endif
1931
1932 mCurrentSampleIndex = syncSampleIndex;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001933 if (mBuffer != NULL) {
1934 mBuffer->release();
1935 mBuffer = NULL;
1936 }
1937
1938 // fall through
1939 }
1940
James Dongb1262a82010-11-16 14:04:54 -08001941 off64_t offset;
Andreas Huber8a432772009-07-28 10:03:13 -07001942 size_t size;
Andreas Huber44fdac02011-04-15 11:52:29 -07001943 uint32_t cts;
Andreas Huberad98d382010-08-06 14:13:10 -07001944 bool isSyncSample;
Andreas Huber4f5e6022009-08-19 09:29:34 -07001945 bool newBuffer = false;
1946 if (mBuffer == NULL) {
1947 newBuffer = true;
Andreas Hubere46b7be2009-07-14 16:56:47 -07001948
Andreas Huber1faa92a2010-01-19 10:39:21 -08001949 status_t err =
1950 mSampleTable->getMetaDataForSample(
Andreas Huber44fdac02011-04-15 11:52:29 -07001951 mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);
Andreas Huber4f5e6022009-08-19 09:29:34 -07001952
1953 if (err != OK) {
1954 return err;
1955 }
1956
1957 err = mGroup->acquire_buffer(&mBuffer);
Andreas Huber1faa92a2010-01-19 10:39:21 -08001958
Andreas Huber4f5e6022009-08-19 09:29:34 -07001959 if (err != OK) {
Andreas Huber940c8662010-11-16 15:26:30 -08001960 CHECK(mBuffer == NULL);
Andreas Huber4f5e6022009-08-19 09:29:34 -07001961 return err;
1962 }
Andreas Huber8a432772009-07-28 10:03:13 -07001963 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07001964
Andreas Huber4f5e6022009-08-19 09:29:34 -07001965 if (!mIsAVC || mWantsNALFragments) {
1966 if (newBuffer) {
1967 ssize_t num_bytes_read =
Andreas Huber9a12baf2009-10-23 10:22:30 -07001968 mDataSource->readAt(offset, (uint8_t *)mBuffer->data(), size);
Andreas Hubere46b7be2009-07-14 16:56:47 -07001969
Andreas Huber4f5e6022009-08-19 09:29:34 -07001970 if (num_bytes_read < (ssize_t)size) {
1971 mBuffer->release();
1972 mBuffer = NULL;
1973
1974 return ERROR_IO;
1975 }
1976
Andreas Huberba7ec912010-02-12 10:42:02 -08001977 CHECK(mBuffer != NULL);
Andreas Huber4f5e6022009-08-19 09:29:34 -07001978 mBuffer->set_range(0, size);
1979 mBuffer->meta_data()->clear();
Andreas Huberfa8de752009-10-08 10:07:49 -07001980 mBuffer->meta_data()->setInt64(
Andreas Huber44fdac02011-04-15 11:52:29 -07001981 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
Andreas Huber6624c9f2010-07-20 15:04:28 -07001982
1983 if (targetSampleTimeUs >= 0) {
1984 mBuffer->meta_data()->setInt64(
1985 kKeyTargetTime, targetSampleTimeUs);
1986 }
1987
Andreas Huberad98d382010-08-06 14:13:10 -07001988 if (isSyncSample) {
1989 mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
1990 }
1991
Andreas Huber4f5e6022009-08-19 09:29:34 -07001992 ++mCurrentSampleIndex;
1993 }
1994
1995 if (!mIsAVC) {
1996 *out = mBuffer;
1997 mBuffer = NULL;
1998
1999 return OK;
2000 }
2001
2002 // Each NAL unit is split up into its constituent fragments and
2003 // each one of them returned in its own buffer.
2004
Andreas Huberdb5d6622010-01-12 16:30:44 -08002005 CHECK(mBuffer->range_length() >= mNALLengthSize);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002006
2007 const uint8_t *src =
2008 (const uint8_t *)mBuffer->data() + mBuffer->range_offset();
2009
Andreas Huberdb5d6622010-01-12 16:30:44 -08002010 size_t nal_size = parseNALSize(src);
Andreas Huber909255a2010-01-14 14:13:15 -08002011 if (mBuffer->range_length() < mNALLengthSize + nal_size) {
2012 LOGE("incomplete NAL unit.");
2013
2014 mBuffer->release();
2015 mBuffer = NULL;
2016
2017 return ERROR_MALFORMED;
2018 }
Andreas Huber4f5e6022009-08-19 09:29:34 -07002019
2020 MediaBuffer *clone = mBuffer->clone();
Andreas Huberba7ec912010-02-12 10:42:02 -08002021 CHECK(clone != NULL);
Andreas Huberdb5d6622010-01-12 16:30:44 -08002022 clone->set_range(mBuffer->range_offset() + mNALLengthSize, nal_size);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002023
Andreas Huberba7ec912010-02-12 10:42:02 -08002024 CHECK(mBuffer != NULL);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002025 mBuffer->set_range(
Andreas Huberdb5d6622010-01-12 16:30:44 -08002026 mBuffer->range_offset() + mNALLengthSize + nal_size,
2027 mBuffer->range_length() - mNALLengthSize - nal_size);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002028
2029 if (mBuffer->range_length() == 0) {
2030 mBuffer->release();
2031 mBuffer = NULL;
2032 }
2033
2034 *out = clone;
2035
2036 return OK;
2037 } else {
2038 // Whole NAL units are returned but each fragment is prefixed by
2039 // the start code (0x00 00 00 01).
Gloria Wangd5770912010-06-22 13:55:38 -07002040 ssize_t num_bytes_read = 0;
2041 int32_t drm = 0;
2042 bool usesDRM = (mFormat->findInt32(kKeyIsDRM, &drm) && drm != 0);
2043 if (usesDRM) {
2044 num_bytes_read =
2045 mDataSource->readAt(offset, (uint8_t*)mBuffer->data(), size);
2046 } else {
2047 num_bytes_read = mDataSource->readAt(offset, mSrcBuffer, size);
2048 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002049
2050 if (num_bytes_read < (ssize_t)size) {
2051 mBuffer->release();
2052 mBuffer = NULL;
2053
Andreas Huber4f5e6022009-08-19 09:29:34 -07002054 return ERROR_IO;
Andreas Hubere46b7be2009-07-14 16:56:47 -07002055 }
2056
Gloria Wangd5770912010-06-22 13:55:38 -07002057 if (usesDRM) {
2058 CHECK(mBuffer != NULL);
2059 mBuffer->set_range(0, size);
Andreas Huberdb5d6622010-01-12 16:30:44 -08002060
Gloria Wangd5770912010-06-22 13:55:38 -07002061 } else {
2062 uint8_t *dstData = (uint8_t *)mBuffer->data();
2063 size_t srcOffset = 0;
2064 size_t dstOffset = 0;
Andreas Huber909255a2010-01-14 14:13:15 -08002065
Gloria Wangd5770912010-06-22 13:55:38 -07002066 while (srcOffset < size) {
James Dong34d76ac2011-04-22 13:21:03 -07002067 bool isMalFormed = (srcOffset + mNALLengthSize > size);
2068 size_t nalLength = 0;
2069 if (!isMalFormed) {
2070 nalLength = parseNALSize(&mSrcBuffer[srcOffset]);
2071 srcOffset += mNALLengthSize;
2072 isMalFormed = srcOffset + nalLength > size;
2073 }
Andreas Huber909255a2010-01-14 14:13:15 -08002074
James Dong34d76ac2011-04-22 13:21:03 -07002075 if (isMalFormed) {
2076 LOGE("Video is malformed");
Gloria Wangd5770912010-06-22 13:55:38 -07002077 mBuffer->release();
2078 mBuffer = NULL;
Gloria Wangd5770912010-06-22 13:55:38 -07002079 return ERROR_MALFORMED;
2080 }
2081
2082 if (nalLength == 0) {
2083 continue;
2084 }
2085
2086 CHECK(dstOffset + 4 <= mBuffer->size());
2087
2088 dstData[dstOffset++] = 0;
2089 dstData[dstOffset++] = 0;
2090 dstData[dstOffset++] = 0;
2091 dstData[dstOffset++] = 1;
2092 memcpy(&dstData[dstOffset], &mSrcBuffer[srcOffset], nalLength);
2093 srcOffset += nalLength;
2094 dstOffset += nalLength;
Andreas Huber909255a2010-01-14 14:13:15 -08002095 }
Gloria Wangd5770912010-06-22 13:55:38 -07002096 CHECK_EQ(srcOffset, size);
2097 CHECK(mBuffer != NULL);
2098 mBuffer->set_range(0, dstOffset);
Andreas Huber4f5e6022009-08-19 09:29:34 -07002099 }
2100
Andreas Hubere46b7be2009-07-14 16:56:47 -07002101 mBuffer->meta_data()->clear();
Andreas Huberfa8de752009-10-08 10:07:49 -07002102 mBuffer->meta_data()->setInt64(
Andreas Huber44fdac02011-04-15 11:52:29 -07002103 kKeyTime, ((int64_t)cts * 1000000) / mTimescale);
Andreas Huber6624c9f2010-07-20 15:04:28 -07002104
2105 if (targetSampleTimeUs >= 0) {
2106 mBuffer->meta_data()->setInt64(
2107 kKeyTargetTime, targetSampleTimeUs);
2108 }
2109
Andreas Huberad98d382010-08-06 14:13:10 -07002110 if (isSyncSample) {
2111 mBuffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);
2112 }
2113
Andreas Hubere46b7be2009-07-14 16:56:47 -07002114 ++mCurrentSampleIndex;
2115
Andreas Hubere46b7be2009-07-14 16:56:47 -07002116 *out = mBuffer;
2117 mBuffer = NULL;
2118
2119 return OK;
2120 }
Andreas Hubere46b7be2009-07-14 16:56:47 -07002121}
2122
Andreas Huberf80e45a2011-03-03 13:48:41 -08002123MPEG4Extractor::Track *MPEG4Extractor::findTrackByMimePrefix(
2124 const char *mimePrefix) {
2125 for (Track *track = mFirstTrack; track != NULL; track = track->next) {
2126 const char *mime;
2127 if (track->meta != NULL
2128 && track->meta->findCString(kKeyMIMEType, &mime)
2129 && !strncasecmp(mime, mimePrefix, strlen(mimePrefix))) {
2130 return track;
2131 }
2132 }
2133
2134 return NULL;
2135}
2136
Andreas Huber261eb0c2010-05-27 09:59:54 -07002137static bool LegacySniffMPEG4(
Andreas Huberbe06d262009-08-14 14:37:10 -07002138 const sp<DataSource> &source, String8 *mimeType, float *confidence) {
Andreas Hubere46b7be2009-07-14 16:56:47 -07002139 uint8_t header[8];
2140
Andreas Huber9a12baf2009-10-23 10:22:30 -07002141 ssize_t n = source->readAt(4, header, sizeof(header));
Andreas Hubere46b7be2009-07-14 16:56:47 -07002142 if (n < (ssize_t)sizeof(header)) {
2143 return false;
2144 }
2145
2146 if (!memcmp(header, "ftyp3gp", 7) || !memcmp(header, "ftypmp42", 8)
James Donge1130662010-04-13 15:06:41 -07002147 || !memcmp(header, "ftyp3gr6", 8) || !memcmp(header, "ftyp3gs6", 8)
2148 || !memcmp(header, "ftyp3ge6", 8) || !memcmp(header, "ftyp3gg6", 8)
Andreas Huber6bce6d82009-11-03 16:00:58 -08002149 || !memcmp(header, "ftypisom", 8) || !memcmp(header, "ftypM4V ", 8)
Andreas Huberdfb8eee2010-02-25 15:59:24 -08002150 || !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
Andreas Hubereea1eef2010-04-01 11:42:50 -07002151 || !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)) {
Andreas Hubere6c40962009-09-10 14:13:30 -07002152 *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
Andreas Huberefdd0882010-08-25 11:09:41 -07002153 *confidence = 0.4;
Andreas Hubere46b7be2009-07-14 16:56:47 -07002154
2155 return true;
2156 }
2157
2158 return false;
2159}
2160
Andreas Huber261eb0c2010-05-27 09:59:54 -07002161static bool isCompatibleBrand(uint32_t fourcc) {
2162 static const uint32_t kCompatibleBrands[] = {
2163 FOURCC('i', 's', 'o', 'm'),
2164 FOURCC('i', 's', 'o', '2'),
2165 FOURCC('a', 'v', 'c', '1'),
2166 FOURCC('3', 'g', 'p', '4'),
2167 FOURCC('m', 'p', '4', '1'),
2168 FOURCC('m', 'p', '4', '2'),
James Dong5f3586e2011-04-07 17:57:04 -07002169
2170 // Won't promise that the following file types can be played.
2171 // Just give these file types a chance.
2172 FOURCC('q', 't', ' ', ' '), // Apple's QuickTime
2173 FOURCC('M', 'S', 'N', 'V'), // Sony's PSP
Andreas Huber261eb0c2010-05-27 09:59:54 -07002174 };
2175
2176 for (size_t i = 0;
2177 i < sizeof(kCompatibleBrands) / sizeof(kCompatibleBrands[0]);
2178 ++i) {
2179 if (kCompatibleBrands[i] == fourcc) {
2180 return true;
2181 }
2182 }
2183
2184 return false;
2185}
2186
2187// Attempt to actually parse the 'ftyp' atom and determine if a suitable
2188// compatible brand is present.
2189static bool BetterSniffMPEG4(
2190 const sp<DataSource> &source, String8 *mimeType, float *confidence) {
2191 uint8_t header[12];
2192 if (source->readAt(0, header, 12) != 12
2193 || memcmp("ftyp", &header[4], 4)) {
2194 return false;
2195 }
2196
2197 size_t atomSize = U32_AT(&header[0]);
2198 if (atomSize < 16 || (atomSize % 4) != 0) {
2199 return false;
2200 }
2201
2202 bool success = false;
2203 if (isCompatibleBrand(U32_AT(&header[8]))) {
2204 success = true;
2205 } else {
2206 size_t numCompatibleBrands = (atomSize - 16) / 4;
2207 for (size_t i = 0; i < numCompatibleBrands; ++i) {
2208 uint8_t tmp[4];
2209 if (source->readAt(16 + i * 4, tmp, 4) != 4) {
2210 return false;
2211 }
2212
2213 if (isCompatibleBrand(U32_AT(&tmp[0]))) {
2214 success = true;
2215 break;
2216 }
2217 }
2218 }
2219
2220 if (!success) {
2221 return false;
2222 }
2223
2224 *mimeType = MEDIA_MIMETYPE_CONTAINER_MPEG4;
Andreas Huberefdd0882010-08-25 11:09:41 -07002225 *confidence = 0.4f;
Andreas Huber261eb0c2010-05-27 09:59:54 -07002226
2227 return true;
2228}
2229
2230bool SniffMPEG4(
Andreas Huberefdd0882010-08-25 11:09:41 -07002231 const sp<DataSource> &source, String8 *mimeType, float *confidence,
2232 sp<AMessage> *) {
Andreas Huber261eb0c2010-05-27 09:59:54 -07002233 if (BetterSniffMPEG4(source, mimeType, confidence)) {
2234 return true;
2235 }
2236
2237 if (LegacySniffMPEG4(source, mimeType, confidence)) {
2238 LOGW("Identified supported mpeg4 through LegacySniffMPEG4.");
2239 return true;
2240 }
2241
2242 return false;
2243}
2244
Andreas Hubere46b7be2009-07-14 16:56:47 -07002245} // namespace android
2246