blob: 5a6211e1a6174e38c69b7065725b1827ae6484be [file] [log] [blame]
Andreas Huberf8374de2011-03-24 14:18:02 -07001/*
2 * Copyright (C) 2011 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_NDEBUG 0
18#define LOG_TAG "AVIExtractor"
19#include <utils/Log.h>
20
Andreas Huberc639aad2011-09-21 13:19:54 -070021#include "include/avc_utils.h"
Andreas Huberf8374de2011-03-24 14:18:02 -070022#include "include/AVIExtractor.h"
23
24#include <binder/ProcessState.h>
25#include <media/stagefright/foundation/hexdump.h>
26#include <media/stagefright/foundation/ABuffer.h>
27#include <media/stagefright/foundation/ADebug.h>
28#include <media/stagefright/DataSource.h>
29#include <media/stagefright/MediaBuffer.h>
30#include <media/stagefright/MediaBufferGroup.h>
31#include <media/stagefright/MediaDefs.h>
32#include <media/stagefright/MediaErrors.h>
33#include <media/stagefright/MetaData.h>
34#include <media/stagefright/Utils.h>
35
36namespace android {
37
38struct AVIExtractor::AVISource : public MediaSource {
39 AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex);
40
41 virtual status_t start(MetaData *params);
42 virtual status_t stop();
43
44 virtual sp<MetaData> getFormat();
45
46 virtual status_t read(
47 MediaBuffer **buffer, const ReadOptions *options);
48
49protected:
50 virtual ~AVISource();
51
52private:
53 sp<AVIExtractor> mExtractor;
54 size_t mTrackIndex;
55 const AVIExtractor::Track &mTrack;
56 MediaBufferGroup *mBufferGroup;
57 size_t mSampleIndex;
58
Andreas Huber32e18322011-09-23 14:05:49 -070059 sp<MP3Splitter> mSplitter;
60
Andreas Huberf8374de2011-03-24 14:18:02 -070061 DISALLOW_EVIL_CONSTRUCTORS(AVISource);
62};
63
64////////////////////////////////////////////////////////////////////////////////
65
Andreas Huber32e18322011-09-23 14:05:49 -070066struct AVIExtractor::MP3Splitter : public RefBase {
67 MP3Splitter();
68
69 void clear();
70 void append(MediaBuffer *buffer);
71 status_t read(MediaBuffer **buffer);
72
73protected:
74 virtual ~MP3Splitter();
75
76private:
77 bool mFindSync;
78 int64_t mBaseTimeUs;
79 int64_t mNumSamplesRead;
80 sp<ABuffer> mBuffer;
81
82 bool resync();
83
84 DISALLOW_EVIL_CONSTRUCTORS(MP3Splitter);
85};
86
87////////////////////////////////////////////////////////////////////////////////
88
Andreas Huberf8374de2011-03-24 14:18:02 -070089AVIExtractor::AVISource::AVISource(
90 const sp<AVIExtractor> &extractor, size_t trackIndex)
91 : mExtractor(extractor),
92 mTrackIndex(trackIndex),
93 mTrack(mExtractor->mTracks.itemAt(trackIndex)),
94 mBufferGroup(NULL) {
95}
96
97AVIExtractor::AVISource::~AVISource() {
98 if (mBufferGroup) {
99 stop();
100 }
101}
102
103status_t AVIExtractor::AVISource::start(MetaData *params) {
104 CHECK(!mBufferGroup);
105
106 mBufferGroup = new MediaBufferGroup;
107
108 mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
109 mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
110 mSampleIndex = 0;
111
Andreas Huber32e18322011-09-23 14:05:49 -0700112 const char *mime;
113 CHECK(mTrack.mMeta->findCString(kKeyMIMEType, &mime));
114
115 if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
116 mSplitter = new MP3Splitter;
117 } else {
118 mSplitter.clear();
119 }
120
Andreas Huberf8374de2011-03-24 14:18:02 -0700121 return OK;
122}
123
124status_t AVIExtractor::AVISource::stop() {
125 CHECK(mBufferGroup);
126
127 delete mBufferGroup;
128 mBufferGroup = NULL;
129
Andreas Huber32e18322011-09-23 14:05:49 -0700130 mSplitter.clear();
131
Andreas Huberf8374de2011-03-24 14:18:02 -0700132 return OK;
133}
134
135sp<MetaData> AVIExtractor::AVISource::getFormat() {
136 return mTrack.mMeta;
137}
138
139status_t AVIExtractor::AVISource::read(
140 MediaBuffer **buffer, const ReadOptions *options) {
141 CHECK(mBufferGroup);
142
143 *buffer = NULL;
144
145 int64_t seekTimeUs;
146 ReadOptions::SeekMode seekMode;
147 if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
148 status_t err =
149 mExtractor->getSampleIndexAtTime(
150 mTrackIndex, seekTimeUs, seekMode, &mSampleIndex);
151
152 if (err != OK) {
153 return ERROR_END_OF_STREAM;
154 }
Andreas Huber32e18322011-09-23 14:05:49 -0700155
156 if (mSplitter != NULL) {
157 mSplitter->clear();
158 }
Andreas Huberf8374de2011-03-24 14:18:02 -0700159 }
160
Andreas Huber32e18322011-09-23 14:05:49 -0700161 for (;;) {
162 if (mSplitter != NULL) {
163 status_t err = mSplitter->read(buffer);
Andreas Huberf8374de2011-03-24 14:18:02 -0700164
Andreas Huber32e18322011-09-23 14:05:49 -0700165 if (err == OK) {
166 break;
167 } else if (err != -EAGAIN) {
168 return err;
169 }
170 }
Andreas Huberf8374de2011-03-24 14:18:02 -0700171
Andreas Huber32e18322011-09-23 14:05:49 -0700172 off64_t offset;
173 size_t size;
174 bool isKey;
175 int64_t timeUs;
176 status_t err = mExtractor->getSampleInfo(
177 mTrackIndex, mSampleIndex, &offset, &size, &isKey, &timeUs);
178
179 ++mSampleIndex;
180
181 if (err != OK) {
182 return ERROR_END_OF_STREAM;
183 }
184
185 MediaBuffer *out;
186 CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK);
187
188 ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size);
189
190 if (n < (ssize_t)size) {
191 return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
192 }
193
194 out->set_range(0, size);
195
196 out->meta_data()->setInt64(kKeyTime, timeUs);
197
198 if (isKey) {
199 out->meta_data()->setInt32(kKeyIsSyncFrame, 1);
200 }
201
202 if (mSplitter == NULL) {
203 *buffer = out;
204 break;
205 }
206
207 mSplitter->append(out);
208 out->release();
209 out = NULL;
Andreas Huberf8374de2011-03-24 14:18:02 -0700210 }
211
Andreas Huber32e18322011-09-23 14:05:49 -0700212 return OK;
213}
Andreas Huberf8374de2011-03-24 14:18:02 -0700214
Andreas Huber32e18322011-09-23 14:05:49 -0700215////////////////////////////////////////////////////////////////////////////////
Andreas Huberf8374de2011-03-24 14:18:02 -0700216
Andreas Huber32e18322011-09-23 14:05:49 -0700217AVIExtractor::MP3Splitter::MP3Splitter()
218 : mFindSync(true),
219 mBaseTimeUs(-1ll),
220 mNumSamplesRead(0) {
221}
222
223AVIExtractor::MP3Splitter::~MP3Splitter() {
224}
225
226void AVIExtractor::MP3Splitter::clear() {
227 mFindSync = true;
228 mBaseTimeUs = -1ll;
229 mNumSamplesRead = 0;
230
231 if (mBuffer != NULL) {
232 mBuffer->setRange(0, 0);
233 }
234}
235
236void AVIExtractor::MP3Splitter::append(MediaBuffer *buffer) {
237 size_t prevCapacity = (mBuffer != NULL) ? mBuffer->capacity() : 0;
238
239 if (mBaseTimeUs < 0) {
240 CHECK(mBuffer == NULL || mBuffer->size() == 0);
241 CHECK(buffer->meta_data()->findInt64(kKeyTime, &mBaseTimeUs));
242 mNumSamplesRead = 0;
Andreas Huberf8374de2011-03-24 14:18:02 -0700243 }
244
Andreas Huber32e18322011-09-23 14:05:49 -0700245 if (mBuffer != NULL && mBuffer->offset() > 0) {
246 memmove(mBuffer->base(), mBuffer->data(), mBuffer->size());
247 mBuffer->setRange(0, mBuffer->size());
Andreas Huberf8374de2011-03-24 14:18:02 -0700248 }
249
Andreas Huber32e18322011-09-23 14:05:49 -0700250 if (mBuffer == NULL
251 || mBuffer->size() + buffer->range_length() > prevCapacity) {
252 size_t newCapacity =
253 (prevCapacity + buffer->range_length() + 1023) & ~1023;
254
255 sp<ABuffer> newBuffer = new ABuffer(newCapacity);
256 if (mBuffer != NULL) {
257 memcpy(newBuffer->data(), mBuffer->data(), mBuffer->size());
258 newBuffer->setRange(0, mBuffer->size());
259 } else {
260 newBuffer->setRange(0, 0);
261 }
262 mBuffer = newBuffer;
263 }
264
265 memcpy(mBuffer->data() + mBuffer->size(),
266 (const uint8_t *)buffer->data() + buffer->range_offset(),
267 buffer->range_length());
268
269 mBuffer->setRange(0, mBuffer->size() + buffer->range_length());
270}
271
272bool AVIExtractor::MP3Splitter::resync() {
273 if (mBuffer == NULL) {
274 return false;
275 }
276
277 bool foundSync = false;
278 for (size_t offset = 0; offset + 3 < mBuffer->size(); ++offset) {
279 uint32_t firstHeader = U32_AT(mBuffer->data() + offset);
280
281 size_t frameSize;
282 if (!GetMPEGAudioFrameSize(firstHeader, &frameSize)) {
283 continue;
284 }
285
286 size_t subsequentOffset = offset + frameSize;
287 size_t i = 3;
288 while (i > 0) {
289 if (subsequentOffset + 3 >= mBuffer->size()) {
290 break;
291 }
292
293 static const uint32_t kMask = 0xfffe0c00;
294
295 uint32_t header = U32_AT(mBuffer->data() + subsequentOffset);
296 if ((header & kMask) != (firstHeader & kMask)) {
297 break;
298 }
299
300 if (!GetMPEGAudioFrameSize(header, &frameSize)) {
301 break;
302 }
303
304 subsequentOffset += frameSize;
305 --i;
306 }
307
308 if (i == 0) {
309 foundSync = true;
310 memmove(mBuffer->data(),
311 mBuffer->data() + offset,
312 mBuffer->size() - offset);
313
314 mBuffer->setRange(0, mBuffer->size() - offset);
315 break;
316 }
317 }
318
319 return foundSync;
320}
321
322status_t AVIExtractor::MP3Splitter::read(MediaBuffer **out) {
323 *out = NULL;
324
325 if (mFindSync) {
326 if (!resync()) {
327 return -EAGAIN;
328 }
329
330 mFindSync = false;
331 }
332
333 if (mBuffer->size() < 4) {
334 return -EAGAIN;
335 }
336
337 uint32_t header = U32_AT(mBuffer->data());
338 size_t frameSize;
339 int sampleRate;
340 int numSamples;
341 if (!GetMPEGAudioFrameSize(
342 header, &frameSize, &sampleRate, NULL, NULL, &numSamples)) {
343 return ERROR_MALFORMED;
344 }
345
346 if (mBuffer->size() < frameSize) {
347 return -EAGAIN;
348 }
349
350 MediaBuffer *mbuf = new MediaBuffer(frameSize);
351 memcpy(mbuf->data(), mBuffer->data(), frameSize);
352
353 int64_t timeUs = mBaseTimeUs + (mNumSamplesRead * 1000000ll) / sampleRate;
354 mNumSamplesRead += numSamples;
355
356 mbuf->meta_data()->setInt64(kKeyTime, timeUs);
357
358 mBuffer->setRange(
359 mBuffer->offset() + frameSize, mBuffer->size() - frameSize);
360
361 *out = mbuf;
Andreas Huberf8374de2011-03-24 14:18:02 -0700362
363 return OK;
364}
365
366////////////////////////////////////////////////////////////////////////////////
367
368AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource)
369 : mDataSource(dataSource) {
370 mInitCheck = parseHeaders();
371
372 if (mInitCheck != OK) {
373 mTracks.clear();
374 }
375}
376
377AVIExtractor::~AVIExtractor() {
378}
379
380size_t AVIExtractor::countTracks() {
381 return mTracks.size();
382}
383
384sp<MediaSource> AVIExtractor::getTrack(size_t index) {
385 return index < mTracks.size() ? new AVISource(this, index) : NULL;
386}
387
388sp<MetaData> AVIExtractor::getTrackMetaData(
389 size_t index, uint32_t flags) {
390 return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL;
391}
392
393sp<MetaData> AVIExtractor::getMetaData() {
394 sp<MetaData> meta = new MetaData;
395
396 if (mInitCheck == OK) {
397 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI);
398 }
399
400 return meta;
401}
402
403status_t AVIExtractor::parseHeaders() {
404 mTracks.clear();
405 mMovieOffset = 0;
406 mFoundIndex = false;
407 mOffsetsAreAbsolute = false;
408
409 ssize_t res = parseChunk(0ll, -1ll);
410
411 if (res < 0) {
412 return (status_t)res;
413 }
414
415 if (mMovieOffset == 0ll || !mFoundIndex) {
416 return ERROR_MALFORMED;
417 }
418
419 return OK;
420}
421
422ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) {
423 if (size >= 0 && size < 8) {
424 return ERROR_MALFORMED;
425 }
426
427 uint8_t tmp[12];
428 ssize_t n = mDataSource->readAt(offset, tmp, 8);
429
430 if (n < 8) {
431 return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
432 }
433
434 uint32_t fourcc = U32_AT(tmp);
435 uint32_t chunkSize = U32LE_AT(&tmp[4]);
436
437 if (size >= 0 && chunkSize + 8 > size) {
438 return ERROR_MALFORMED;
439 }
440
441 static const char kPrefix[] = " ";
442 const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth];
443
444 if (fourcc == FOURCC('L', 'I', 'S', 'T')
445 || fourcc == FOURCC('R', 'I', 'F', 'F')) {
446 // It's a list of chunks
447
448 if (size >= 0 && size < 12) {
449 return ERROR_MALFORMED;
450 }
451
452 n = mDataSource->readAt(offset + 8, &tmp[8], 4);
453
454 if (n < 4) {
455 return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
456 }
457
458 uint32_t subFourcc = U32_AT(&tmp[8]);
459
Steve Block3856b092011-10-20 11:56:00 +0100460 ALOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d",
Andreas Huberf8374de2011-03-24 14:18:02 -0700461 prefix,
462 offset,
463 (char)(subFourcc >> 24),
464 (char)((subFourcc >> 16) & 0xff),
465 (char)((subFourcc >> 8) & 0xff),
466 (char)(subFourcc & 0xff),
467 chunkSize - 4);
468
469 if (subFourcc == FOURCC('m', 'o', 'v', 'i')) {
470 // We're not going to parse this, but will take note of the
471 // offset.
472
473 mMovieOffset = offset;
474 } else {
475 off64_t subOffset = offset + 12;
476 off64_t subOffsetLimit = subOffset + chunkSize - 4;
477 while (subOffset < subOffsetLimit) {
478 ssize_t res =
479 parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1);
480
481 if (res < 0) {
482 return res;
483 }
484
485 subOffset += res;
486 }
487 }
488 } else {
Steve Block3856b092011-10-20 11:56:00 +0100489 ALOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'",
Andreas Huberf8374de2011-03-24 14:18:02 -0700490 prefix,
491 offset,
492 (char)(fourcc >> 24),
493 (char)((fourcc >> 16) & 0xff),
494 (char)((fourcc >> 8) & 0xff),
495 (char)(fourcc & 0xff));
496
497 status_t err = OK;
498
499 switch (fourcc) {
500 case FOURCC('s', 't', 'r', 'h'):
501 {
502 err = parseStreamHeader(offset + 8, chunkSize);
503 break;
504 }
505
506 case FOURCC('s', 't', 'r', 'f'):
507 {
508 err = parseStreamFormat(offset + 8, chunkSize);
509 break;
510 }
511
512 case FOURCC('i', 'd', 'x', '1'):
513 {
514 err = parseIndex(offset + 8, chunkSize);
515 break;
516 }
517
518 default:
519 break;
520 }
521
522 if (err != OK) {
523 return err;
524 }
525 }
526
527 if (chunkSize & 1) {
528 ++chunkSize;
529 }
530
531 return chunkSize + 8;
532}
533
534static const char *GetMIMETypeForHandler(uint32_t handler) {
535 switch (handler) {
536 // Wow... shamelessly copied from
537 // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4
538
539 case FOURCC('3', 'I', 'V', '2'):
540 case FOURCC('3', 'i', 'v', '2'):
541 case FOURCC('B', 'L', 'Z', '0'):
542 case FOURCC('D', 'I', 'G', 'I'):
543 case FOURCC('D', 'I', 'V', '1'):
544 case FOURCC('d', 'i', 'v', '1'):
545 case FOURCC('D', 'I', 'V', 'X'):
546 case FOURCC('d', 'i', 'v', 'x'):
547 case FOURCC('D', 'X', '5', '0'):
548 case FOURCC('d', 'x', '5', '0'):
549 case FOURCC('D', 'X', 'G', 'M'):
550 case FOURCC('E', 'M', '4', 'A'):
551 case FOURCC('E', 'P', 'H', 'V'):
552 case FOURCC('F', 'M', 'P', '4'):
553 case FOURCC('f', 'm', 'p', '4'):
554 case FOURCC('F', 'V', 'F', 'W'):
555 case FOURCC('H', 'D', 'X', '4'):
556 case FOURCC('h', 'd', 'x', '4'):
557 case FOURCC('M', '4', 'C', 'C'):
558 case FOURCC('M', '4', 'S', '2'):
559 case FOURCC('m', '4', 's', '2'):
560 case FOURCC('M', 'P', '4', 'S'):
561 case FOURCC('m', 'p', '4', 's'):
562 case FOURCC('M', 'P', '4', 'V'):
563 case FOURCC('m', 'p', '4', 'v'):
564 case FOURCC('M', 'V', 'X', 'M'):
565 case FOURCC('R', 'M', 'P', '4'):
566 case FOURCC('S', 'E', 'D', 'G'):
567 case FOURCC('S', 'M', 'P', '4'):
568 case FOURCC('U', 'M', 'P', '4'):
569 case FOURCC('W', 'V', '1', 'F'):
570 case FOURCC('X', 'V', 'I', 'D'):
571 case FOURCC('X', 'v', 'i', 'D'):
572 case FOURCC('x', 'v', 'i', 'd'):
573 case FOURCC('X', 'V', 'I', 'X'):
574 return MEDIA_MIMETYPE_VIDEO_MPEG4;
575
Andreas Huberc639aad2011-09-21 13:19:54 -0700576 // from http://wiki.multimedia.cx/index.php?title=H264
577 case FOURCC('a', 'v', 'c', '1'):
578 case FOURCC('d', 'a', 'v', 'c'):
579 case FOURCC('x', '2', '6', '4'):
Dongwon Kangec2e74b2012-01-15 12:00:34 +0900580 case FOURCC('H', '2', '6', '4'):
Andreas Huberc639aad2011-09-21 13:19:54 -0700581 case FOURCC('v', 's', 's', 'h'):
582 return MEDIA_MIMETYPE_VIDEO_AVC;
583
Andreas Huberf8374de2011-03-24 14:18:02 -0700584 default:
585 return NULL;
586 }
587}
588
589status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
590 if (size != 56) {
591 return ERROR_MALFORMED;
592 }
593
594 if (mTracks.size() > 99) {
595 return -ERANGE;
596 }
597
598 sp<ABuffer> buffer = new ABuffer(size);
599 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
600
601 if (n < (ssize_t)size) {
602 return n < 0 ? (status_t)n : ERROR_MALFORMED;
603 }
604
605 const uint8_t *data = buffer->data();
606
607 uint32_t type = U32_AT(data);
608 uint32_t handler = U32_AT(&data[4]);
609 uint32_t flags = U32LE_AT(&data[8]);
610
611 sp<MetaData> meta = new MetaData;
612
613 uint32_t rate = U32LE_AT(&data[20]);
614 uint32_t scale = U32LE_AT(&data[24]);
615
Andreas Huber7de73f42011-09-13 11:12:57 -0700616 uint32_t sampleSize = U32LE_AT(&data[44]);
617
Andreas Huberf8374de2011-03-24 14:18:02 -0700618 const char *mime = NULL;
619 Track::Kind kind = Track::OTHER;
620
621 if (type == FOURCC('v', 'i', 'd', 's')) {
622 mime = GetMIMETypeForHandler(handler);
623
624 if (mime && strncasecmp(mime, "video/", 6)) {
625 return ERROR_MALFORMED;
626 }
627
Andreas Huberc639aad2011-09-21 13:19:54 -0700628 if (mime == NULL) {
Steve Block5ff1dd52012-01-05 23:22:43 +0000629 ALOGW("Unsupported video format '%c%c%c%c'",
Andreas Huberc639aad2011-09-21 13:19:54 -0700630 (char)(handler >> 24),
631 (char)((handler >> 16) & 0xff),
632 (char)((handler >> 8) & 0xff),
633 (char)(handler & 0xff));
634 }
635
Andreas Huberf8374de2011-03-24 14:18:02 -0700636 kind = Track::VIDEO;
637 } else if (type == FOURCC('a', 'u', 'd', 's')) {
638 if (mime && strncasecmp(mime, "audio/", 6)) {
639 return ERROR_MALFORMED;
640 }
641
642 kind = Track::AUDIO;
643 }
644
645 if (!mime) {
646 mime = "application/octet-stream";
647 }
648
649 meta->setCString(kKeyMIMEType, mime);
650
651 mTracks.push();
652 Track *track = &mTracks.editItemAt(mTracks.size() - 1);
653
654 track->mMeta = meta;
655 track->mRate = rate;
656 track->mScale = scale;
Andreas Huber7de73f42011-09-13 11:12:57 -0700657 track->mBytesPerSample = sampleSize;
Andreas Huberf8374de2011-03-24 14:18:02 -0700658 track->mKind = kind;
659 track->mNumSyncSamples = 0;
660 track->mThumbnailSampleSize = 0;
661 track->mThumbnailSampleIndex = -1;
662 track->mMaxSampleSize = 0;
Andreas Huber32e18322011-09-23 14:05:49 -0700663 track->mAvgChunkSize = 1.0;
664 track->mFirstChunkSize = 0;
Andreas Huberf8374de2011-03-24 14:18:02 -0700665
666 return OK;
667}
668
669status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
670 if (mTracks.isEmpty()) {
671 return ERROR_MALFORMED;
672 }
673
674 Track *track = &mTracks.editItemAt(mTracks.size() - 1);
675
676 if (track->mKind == Track::OTHER) {
677 // We don't support this content, but that's not a parsing error.
678 return OK;
679 }
680
681 bool isVideo = (track->mKind == Track::VIDEO);
682
Andreas Huber32e18322011-09-23 14:05:49 -0700683 if ((isVideo && size < 40) || (!isVideo && size < 16)) {
684 // Expected a BITMAPINFO or WAVEFORMAT(EX) structure, respectively.
Andreas Huberf8374de2011-03-24 14:18:02 -0700685 return ERROR_MALFORMED;
686 }
687
688 sp<ABuffer> buffer = new ABuffer(size);
689 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
690
691 if (n < (ssize_t)size) {
692 return n < 0 ? (status_t)n : ERROR_MALFORMED;
693 }
694
695 const uint8_t *data = buffer->data();
696
697 if (isVideo) {
698 uint32_t width = U32LE_AT(&data[4]);
699 uint32_t height = U32LE_AT(&data[8]);
700
701 track->mMeta->setInt32(kKeyWidth, width);
702 track->mMeta->setInt32(kKeyHeight, height);
703 } else {
704 uint32_t format = U16LE_AT(data);
Andreas Huberc639aad2011-09-21 13:19:54 -0700705
Andreas Huberf8374de2011-03-24 14:18:02 -0700706 if (format == 0x55) {
707 track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
Andreas Huberc639aad2011-09-21 13:19:54 -0700708 } else {
Steve Block5ff1dd52012-01-05 23:22:43 +0000709 ALOGW("Unsupported audio format = 0x%04x", format);
Andreas Huberf8374de2011-03-24 14:18:02 -0700710 }
711
712 uint32_t numChannels = U16LE_AT(&data[2]);
713 uint32_t sampleRate = U32LE_AT(&data[4]);
714
715 track->mMeta->setInt32(kKeyChannelCount, numChannels);
716 track->mMeta->setInt32(kKeySampleRate, sampleRate);
717 }
718
719 return OK;
720}
721
722// static
723bool AVIExtractor::IsCorrectChunkType(
724 ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) {
725 uint32_t chunkBase = chunkType & 0xffff;
726
727 switch (kind) {
728 case Track::VIDEO:
729 {
730 if (chunkBase != FOURCC(0, 0, 'd', 'c')
731 && chunkBase != FOURCC(0, 0, 'd', 'b')) {
732 return false;
733 }
734 break;
735 }
736
737 case Track::AUDIO:
738 {
739 if (chunkBase != FOURCC(0, 0, 'w', 'b')) {
740 return false;
741 }
742 break;
743 }
744
745 default:
746 break;
747 }
748
749 if (trackIndex < 0) {
750 return true;
751 }
752
753 uint8_t hi = chunkType >> 24;
754 uint8_t lo = (chunkType >> 16) & 0xff;
755
756 if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
757 return false;
758 }
759
760 if (trackIndex != (10 * (hi - '0') + (lo - '0'))) {
761 return false;
762 }
763
764 return true;
765}
766
767status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
768 if ((size % 16) != 0) {
769 return ERROR_MALFORMED;
770 }
771
772 sp<ABuffer> buffer = new ABuffer(size);
773 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
774
775 if (n < (ssize_t)size) {
776 return n < 0 ? (status_t)n : ERROR_MALFORMED;
777 }
778
779 const uint8_t *data = buffer->data();
780
781 while (size > 0) {
782 uint32_t chunkType = U32_AT(data);
783
784 uint8_t hi = chunkType >> 24;
785 uint8_t lo = (chunkType >> 16) & 0xff;
786
787 if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
788 return ERROR_MALFORMED;
789 }
790
791 size_t trackIndex = 10 * (hi - '0') + (lo - '0');
792
793 if (trackIndex >= mTracks.size()) {
794 return ERROR_MALFORMED;
795 }
796
797 Track *track = &mTracks.editItemAt(trackIndex);
798
799 if (!IsCorrectChunkType(-1, track->mKind, chunkType)) {
800 return ERROR_MALFORMED;
801 }
802
803 if (track->mKind == Track::OTHER) {
804 data += 16;
805 size -= 16;
806 continue;
807 }
808
809 uint32_t flags = U32LE_AT(&data[4]);
810 uint32_t offset = U32LE_AT(&data[8]);
811 uint32_t chunkSize = U32LE_AT(&data[12]);
812
813 if (chunkSize > track->mMaxSampleSize) {
814 track->mMaxSampleSize = chunkSize;
815 }
816
817 track->mSamples.push();
818
819 SampleInfo *info =
820 &track->mSamples.editItemAt(track->mSamples.size() - 1);
821
822 info->mOffset = offset;
823 info->mIsKey = (flags & 0x10) != 0;
824
825 if (info->mIsKey) {
826 static const size_t kMaxNumSyncSamplesToScan = 20;
827
828 if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) {
829 if (chunkSize > track->mThumbnailSampleSize) {
830 track->mThumbnailSampleSize = chunkSize;
831
832 track->mThumbnailSampleIndex =
833 track->mSamples.size() - 1;
834 }
835 }
836
837 ++track->mNumSyncSamples;
838 }
839
840 data += 16;
841 size -= 16;
842 }
843
844 if (!mTracks.isEmpty()) {
845 off64_t offset;
846 size_t size;
847 bool isKey;
Andreas Huber7de73f42011-09-13 11:12:57 -0700848 int64_t timeUs;
849 status_t err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
Andreas Huberf8374de2011-03-24 14:18:02 -0700850
851 if (err != OK) {
852 mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
Andreas Huber7de73f42011-09-13 11:12:57 -0700853 err = getSampleInfo(0, 0, &offset, &size, &isKey, &timeUs);
Andreas Huberf8374de2011-03-24 14:18:02 -0700854
855 if (err != OK) {
856 return err;
857 }
858 }
859
Steve Block3856b092011-10-20 11:56:00 +0100860 ALOGV("Chunk offsets are %s",
Andreas Huberf8374de2011-03-24 14:18:02 -0700861 mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative");
862 }
863
864 for (size_t i = 0; i < mTracks.size(); ++i) {
865 Track *track = &mTracks.editItemAt(i);
866
Andreas Huber32e18322011-09-23 14:05:49 -0700867 if (track->mBytesPerSample > 0) {
868 // Assume all chunks are roughly the same size for now.
869
870 // Compute the avg. size of the first 128 chunks (if there are
871 // that many), but exclude the size of the first one, since
872 // it may be an outlier.
873 size_t numSamplesToAverage = track->mSamples.size();
874 if (numSamplesToAverage > 256) {
875 numSamplesToAverage = 256;
876 }
877
878 double avgChunkSize = 0;
879 size_t j;
880 for (j = 0; j <= numSamplesToAverage; ++j) {
881 off64_t offset;
882 size_t size;
883 bool isKey;
884 int64_t dummy;
885
886 status_t err =
887 getSampleInfo(
888 i, j,
889 &offset, &size, &isKey, &dummy);
890
891 if (err != OK) {
892 return err;
893 }
894
895 if (j == 0) {
896 track->mFirstChunkSize = size;
897 continue;
898 }
899
900 avgChunkSize += size;
901 }
902
903 avgChunkSize /= numSamplesToAverage;
904
905 track->mAvgChunkSize = avgChunkSize;
906 }
907
Andreas Huber7de73f42011-09-13 11:12:57 -0700908 int64_t durationUs;
909 CHECK_EQ((status_t)OK,
910 getSampleTime(i, track->mSamples.size() - 1, &durationUs));
Andreas Huberf8374de2011-03-24 14:18:02 -0700911
Steve Block3856b092011-10-20 11:56:00 +0100912 ALOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
Andreas Huberf8374de2011-03-24 14:18:02 -0700913
914 track->mMeta->setInt64(kKeyDuration, durationUs);
915 track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize);
916
917 const char *tmp;
918 CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp));
919
920 AString mime = tmp;
921
Andreas Huberc639aad2011-09-21 13:19:54 -0700922 if (!strncasecmp("video/", mime.c_str(), 6)) {
923 if (track->mThumbnailSampleIndex >= 0) {
924 int64_t thumbnailTimeUs;
925 CHECK_EQ((status_t)OK,
926 getSampleTime(i, track->mThumbnailSampleIndex,
927 &thumbnailTimeUs));
Andreas Huberf8374de2011-03-24 14:18:02 -0700928
Andreas Huberc639aad2011-09-21 13:19:54 -0700929 track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
930 }
931
932 status_t err = OK;
Andreas Huberf8374de2011-03-24 14:18:02 -0700933
934 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
Andreas Huberc639aad2011-09-21 13:19:54 -0700935 err = addMPEG4CodecSpecificData(i);
936 } else if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_AVC)) {
937 err = addH264CodecSpecificData(i);
938 }
Andreas Huberf8374de2011-03-24 14:18:02 -0700939
Andreas Huberc639aad2011-09-21 13:19:54 -0700940 if (err != OK) {
941 return err;
Andreas Huberf8374de2011-03-24 14:18:02 -0700942 }
943 }
944 }
945
946 mFoundIndex = true;
947
948 return OK;
949}
950
951static size_t GetSizeWidth(size_t x) {
952 size_t n = 1;
953 while (x > 127) {
954 ++n;
955 x >>= 7;
956 }
957 return n;
958}
959
960static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
961 while (x > 127) {
962 *dst++ = (x & 0x7f) | 0x80;
963 x >>= 7;
964 }
965 *dst++ = x;
966 return dst;
967}
968
969sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) {
970 size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
971 size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
972 size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
973
974 sp<ABuffer> csd = new ABuffer(len3);
975 uint8_t *dst = csd->data();
976 *dst++ = 0x03;
977 dst = EncodeSize(dst, len2 + 3);
978 *dst++ = 0x00; // ES_ID
979 *dst++ = 0x00;
980 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
981
982 *dst++ = 0x04;
983 dst = EncodeSize(dst, len1 + 13);
984 *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile
985 for (size_t i = 0; i < 12; ++i) {
986 *dst++ = 0x00;
987 }
988
989 *dst++ = 0x05;
990 dst = EncodeSize(dst, config->size());
991 memcpy(dst, config->data(), config->size());
992 dst += config->size();
993
994 // hexdump(csd->data(), csd->size());
995
996 return csd;
997}
998
999status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
1000 Track *track = &mTracks.editItemAt(trackIndex);
1001
1002 off64_t offset;
1003 size_t size;
1004 bool isKey;
Andreas Huber7de73f42011-09-13 11:12:57 -07001005 int64_t timeUs;
1006 status_t err =
1007 getSampleInfo(trackIndex, 0, &offset, &size, &isKey, &timeUs);
Andreas Huberf8374de2011-03-24 14:18:02 -07001008
1009 if (err != OK) {
1010 return err;
1011 }
1012
1013 sp<ABuffer> buffer = new ABuffer(size);
1014 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
1015
1016 if (n < (ssize_t)size) {
1017 return n < 0 ? (status_t)n : ERROR_MALFORMED;
1018 }
1019
1020 // Extract everything up to the first VOP start code from the first
1021 // frame's encoded data and use it to construct an ESDS with the
1022 // codec specific data.
1023
1024 size_t i = 0;
1025 bool found = false;
1026 while (i + 3 < buffer->size()) {
1027 if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) {
1028 found = true;
1029 break;
1030 }
1031
1032 ++i;
1033 }
1034
1035 if (!found) {
1036 return ERROR_MALFORMED;
1037 }
1038
1039 buffer->setRange(0, i);
1040
1041 sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer);
1042 track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size());
1043
1044 return OK;
1045}
1046
Andreas Huberc639aad2011-09-21 13:19:54 -07001047status_t AVIExtractor::addH264CodecSpecificData(size_t trackIndex) {
1048 Track *track = &mTracks.editItemAt(trackIndex);
1049
1050 off64_t offset;
1051 size_t size;
1052 bool isKey;
1053 int64_t timeUs;
1054
1055 // Extract codec specific data from the first non-empty sample.
1056
1057 size_t sampleIndex = 0;
1058 for (;;) {
1059 status_t err =
1060 getSampleInfo(
1061 trackIndex, sampleIndex, &offset, &size, &isKey, &timeUs);
1062
1063 if (err != OK) {
1064 return err;
1065 }
1066
1067 if (size > 0) {
1068 break;
1069 }
1070
1071 ++sampleIndex;
1072 }
1073
1074 sp<ABuffer> buffer = new ABuffer(size);
1075 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
1076
1077 if (n < (ssize_t)size) {
1078 return n < 0 ? (status_t)n : ERROR_MALFORMED;
1079 }
1080
1081 sp<MetaData> meta = MakeAVCCodecSpecificData(buffer);
1082
1083 if (meta == NULL) {
Steve Block29357bc2012-01-06 19:20:56 +00001084 ALOGE("Unable to extract AVC codec specific data");
Andreas Huberc639aad2011-09-21 13:19:54 -07001085 return ERROR_MALFORMED;
1086 }
1087
1088 int32_t width, height;
1089 CHECK(meta->findInt32(kKeyWidth, &width));
1090 CHECK(meta->findInt32(kKeyHeight, &height));
1091
1092 uint32_t type;
1093 const void *csd;
1094 size_t csdSize;
1095 CHECK(meta->findData(kKeyAVCC, &type, &csd, &csdSize));
1096
1097 track->mMeta->setInt32(kKeyWidth, width);
Andreas Huber4fe1c6c2011-12-01 10:02:37 -08001098 track->mMeta->setInt32(kKeyHeight, height);
Andreas Huberc639aad2011-09-21 13:19:54 -07001099 track->mMeta->setData(kKeyAVCC, type, csd, csdSize);
1100
1101 return OK;
1102}
1103
Andreas Huberf8374de2011-03-24 14:18:02 -07001104status_t AVIExtractor::getSampleInfo(
1105 size_t trackIndex, size_t sampleIndex,
Andreas Huber7de73f42011-09-13 11:12:57 -07001106 off64_t *offset, size_t *size, bool *isKey,
1107 int64_t *sampleTimeUs) {
Andreas Huberf8374de2011-03-24 14:18:02 -07001108 if (trackIndex >= mTracks.size()) {
1109 return -ERANGE;
1110 }
1111
1112 const Track &track = mTracks.itemAt(trackIndex);
1113
1114 if (sampleIndex >= track.mSamples.size()) {
1115 return -ERANGE;
1116 }
1117
1118 const SampleInfo &info = track.mSamples.itemAt(sampleIndex);
1119
1120 if (!mOffsetsAreAbsolute) {
1121 *offset = info.mOffset + mMovieOffset + 8;
1122 } else {
1123 *offset = info.mOffset;
1124 }
1125
1126 *size = 0;
1127
1128 uint8_t tmp[8];
1129 ssize_t n = mDataSource->readAt(*offset, tmp, 8);
1130
1131 if (n < 8) {
1132 return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
1133 }
1134
1135 uint32_t chunkType = U32_AT(tmp);
1136
1137 if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) {
1138 return ERROR_MALFORMED;
1139 }
1140
1141 *offset += 8;
1142 *size = U32LE_AT(&tmp[4]);
1143
1144 *isKey = info.mIsKey;
1145
Andreas Huber32e18322011-09-23 14:05:49 -07001146 if (track.mBytesPerSample > 0) {
1147 size_t sampleStartInBytes;
1148 if (sampleIndex == 0) {
1149 sampleStartInBytes = 0;
1150 } else {
1151 sampleStartInBytes =
1152 track.mFirstChunkSize + track.mAvgChunkSize * (sampleIndex - 1);
1153 }
1154
1155 sampleIndex = sampleStartInBytes / track.mBytesPerSample;
1156 }
1157
Andreas Huber7de73f42011-09-13 11:12:57 -07001158 *sampleTimeUs = (sampleIndex * 1000000ll * track.mRate) / track.mScale;
1159
Andreas Huberf8374de2011-03-24 14:18:02 -07001160 return OK;
1161}
1162
Andreas Huber7de73f42011-09-13 11:12:57 -07001163status_t AVIExtractor::getSampleTime(
1164 size_t trackIndex, size_t sampleIndex, int64_t *sampleTimeUs) {
1165 off64_t offset;
1166 size_t size;
1167 bool isKey;
1168 return getSampleInfo(
1169 trackIndex, sampleIndex, &offset, &size, &isKey, sampleTimeUs);
1170}
1171
Andreas Huberf8374de2011-03-24 14:18:02 -07001172status_t AVIExtractor::getSampleIndexAtTime(
1173 size_t trackIndex,
1174 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
1175 size_t *sampleIndex) const {
1176 if (trackIndex >= mTracks.size()) {
1177 return -ERANGE;
1178 }
1179
1180 const Track &track = mTracks.itemAt(trackIndex);
1181
Andreas Huber32e18322011-09-23 14:05:49 -07001182 ssize_t closestSampleIndex;
1183
1184 if (track.mBytesPerSample > 0) {
1185 size_t closestByteOffset =
1186 (timeUs * track.mBytesPerSample)
1187 / track.mRate * track.mScale / 1000000ll;
1188
1189 if (closestByteOffset <= track.mFirstChunkSize) {
1190 closestSampleIndex = 0;
1191 } else {
1192 closestSampleIndex =
1193 (closestByteOffset - track.mFirstChunkSize)
1194 / track.mAvgChunkSize;
1195 }
1196 } else {
1197 // Each chunk contains a single sample.
1198 closestSampleIndex = timeUs / track.mRate * track.mScale / 1000000ll;
1199 }
Andreas Huberf8374de2011-03-24 14:18:02 -07001200
1201 ssize_t numSamples = track.mSamples.size();
1202
1203 if (closestSampleIndex < 0) {
1204 closestSampleIndex = 0;
1205 } else if (closestSampleIndex >= numSamples) {
1206 closestSampleIndex = numSamples - 1;
1207 }
1208
1209 if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) {
1210 *sampleIndex = closestSampleIndex;
1211
1212 return OK;
1213 }
1214
1215 ssize_t prevSyncSampleIndex = closestSampleIndex;
1216 while (prevSyncSampleIndex >= 0) {
1217 const SampleInfo &info =
1218 track.mSamples.itemAt(prevSyncSampleIndex);
1219
1220 if (info.mIsKey) {
1221 break;
1222 }
1223
1224 --prevSyncSampleIndex;
1225 }
1226
1227 ssize_t nextSyncSampleIndex = closestSampleIndex;
1228 while (nextSyncSampleIndex < numSamples) {
1229 const SampleInfo &info =
1230 track.mSamples.itemAt(nextSyncSampleIndex);
1231
1232 if (info.mIsKey) {
1233 break;
1234 }
1235
1236 ++nextSyncSampleIndex;
1237 }
1238
1239 switch (mode) {
1240 case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
1241 {
1242 *sampleIndex = prevSyncSampleIndex;
1243
1244 return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR;
1245 }
1246
1247 case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
1248 {
1249 *sampleIndex = nextSyncSampleIndex;
1250
1251 return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR;
1252 }
1253
1254 case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
1255 {
1256 if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) {
1257 return UNKNOWN_ERROR;
1258 }
1259
1260 if (prevSyncSampleIndex < 0) {
1261 *sampleIndex = nextSyncSampleIndex;
1262 return OK;
1263 }
1264
1265 if (nextSyncSampleIndex >= numSamples) {
1266 *sampleIndex = prevSyncSampleIndex;
1267 return OK;
1268 }
1269
1270 size_t dist1 = closestSampleIndex - prevSyncSampleIndex;
1271 size_t dist2 = nextSyncSampleIndex - closestSampleIndex;
1272
1273 *sampleIndex =
1274 (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex;
1275
1276 return OK;
1277 }
1278
1279 default:
1280 TRESPASS();
1281 break;
1282 }
1283}
1284
1285bool SniffAVI(
1286 const sp<DataSource> &source, String8 *mimeType, float *confidence,
1287 sp<AMessage> *) {
1288 char tmp[12];
1289 if (source->readAt(0, tmp, 12) < 12) {
1290 return false;
1291 }
1292
1293 if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
1294 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
Andreas Huberc6c45722011-09-12 13:49:00 -07001295
1296 // Just a tad over the mp3 extractor's confidence, since
1297 // these .avi files may contain .mp3 content that otherwise would
1298 // mistakenly lead to us identifying the entire file as a .mp3 file.
1299 *confidence = 0.21;
Andreas Huberf8374de2011-03-24 14:18:02 -07001300
1301 return true;
1302 }
1303
1304 return false;
1305}
1306
1307} // namespace android