blob: 6313ca38a93d3a7f6cfeb66455388fcf6ab2af81 [file] [log] [blame]
Andreas Hubercabb7da2011-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
21#include "include/AVIExtractor.h"
22
23#include <binder/ProcessState.h>
24#include <media/stagefright/foundation/hexdump.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/DataSource.h>
28#include <media/stagefright/MediaBuffer.h>
29#include <media/stagefright/MediaBufferGroup.h>
30#include <media/stagefright/MediaDefs.h>
31#include <media/stagefright/MediaErrors.h>
32#include <media/stagefright/MetaData.h>
33#include <media/stagefright/Utils.h>
34
35namespace android {
36
37struct AVIExtractor::AVISource : public MediaSource {
38 AVISource(const sp<AVIExtractor> &extractor, size_t trackIndex);
39
40 virtual status_t start(MetaData *params);
41 virtual status_t stop();
42
43 virtual sp<MetaData> getFormat();
44
45 virtual status_t read(
46 MediaBuffer **buffer, const ReadOptions *options);
47
48protected:
49 virtual ~AVISource();
50
51private:
52 sp<AVIExtractor> mExtractor;
53 size_t mTrackIndex;
54 const AVIExtractor::Track &mTrack;
55 MediaBufferGroup *mBufferGroup;
56 size_t mSampleIndex;
57
58 DISALLOW_EVIL_CONSTRUCTORS(AVISource);
59};
60
61////////////////////////////////////////////////////////////////////////////////
62
63AVIExtractor::AVISource::AVISource(
64 const sp<AVIExtractor> &extractor, size_t trackIndex)
65 : mExtractor(extractor),
66 mTrackIndex(trackIndex),
67 mTrack(mExtractor->mTracks.itemAt(trackIndex)),
68 mBufferGroup(NULL) {
69}
70
71AVIExtractor::AVISource::~AVISource() {
72 if (mBufferGroup) {
73 stop();
74 }
75}
76
77status_t AVIExtractor::AVISource::start(MetaData *params) {
78 CHECK(!mBufferGroup);
79
80 mBufferGroup = new MediaBufferGroup;
81
82 mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
83 mBufferGroup->add_buffer(new MediaBuffer(mTrack.mMaxSampleSize));
84 mSampleIndex = 0;
85
86 return OK;
87}
88
89status_t AVIExtractor::AVISource::stop() {
90 CHECK(mBufferGroup);
91
92 delete mBufferGroup;
93 mBufferGroup = NULL;
94
95 return OK;
96}
97
98sp<MetaData> AVIExtractor::AVISource::getFormat() {
99 return mTrack.mMeta;
100}
101
102status_t AVIExtractor::AVISource::read(
103 MediaBuffer **buffer, const ReadOptions *options) {
104 CHECK(mBufferGroup);
105
106 *buffer = NULL;
107
108 int64_t seekTimeUs;
109 ReadOptions::SeekMode seekMode;
110 if (options && options->getSeekTo(&seekTimeUs, &seekMode)) {
111 status_t err =
112 mExtractor->getSampleIndexAtTime(
113 mTrackIndex, seekTimeUs, seekMode, &mSampleIndex);
114
115 if (err != OK) {
116 return ERROR_END_OF_STREAM;
117 }
118 }
119
120 int64_t timeUs =
121 (mSampleIndex * 1000000ll * mTrack.mRate) / mTrack.mScale;
122
123 off64_t offset;
124 size_t size;
125 bool isKey;
126 status_t err = mExtractor->getSampleInfo(
127 mTrackIndex, mSampleIndex, &offset, &size, &isKey);
128
129 ++mSampleIndex;
130
131 if (err != OK) {
132 return ERROR_END_OF_STREAM;
133 }
134
135 MediaBuffer *out;
136 CHECK_EQ(mBufferGroup->acquire_buffer(&out), (status_t)OK);
137
138 ssize_t n = mExtractor->mDataSource->readAt(offset, out->data(), size);
139
140 if (n < (ssize_t)size) {
141 return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
142 }
143
144 out->set_range(0, size);
145
146 out->meta_data()->setInt64(kKeyTime, timeUs);
147
148 if (isKey) {
149 out->meta_data()->setInt32(kKeyIsSyncFrame, 1);
150 }
151
152 *buffer = out;
153
154 return OK;
155}
156
157////////////////////////////////////////////////////////////////////////////////
158
159AVIExtractor::AVIExtractor(const sp<DataSource> &dataSource)
160 : mDataSource(dataSource) {
161 mInitCheck = parseHeaders();
162
163 if (mInitCheck != OK) {
164 mTracks.clear();
165 }
166}
167
168AVIExtractor::~AVIExtractor() {
169}
170
171size_t AVIExtractor::countTracks() {
172 return mTracks.size();
173}
174
175sp<MediaSource> AVIExtractor::getTrack(size_t index) {
176 return index < mTracks.size() ? new AVISource(this, index) : NULL;
177}
178
179sp<MetaData> AVIExtractor::getTrackMetaData(
180 size_t index, uint32_t flags) {
181 return index < mTracks.size() ? mTracks.editItemAt(index).mMeta : NULL;
182}
183
184sp<MetaData> AVIExtractor::getMetaData() {
185 sp<MetaData> meta = new MetaData;
186
187 if (mInitCheck == OK) {
188 meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_AVI);
189 }
190
191 return meta;
192}
193
194status_t AVIExtractor::parseHeaders() {
195 mTracks.clear();
196 mMovieOffset = 0;
197 mFoundIndex = false;
198 mOffsetsAreAbsolute = false;
199
200 ssize_t res = parseChunk(0ll, -1ll);
201
202 if (res < 0) {
203 return (status_t)res;
204 }
205
206 if (mMovieOffset == 0ll || !mFoundIndex) {
207 return ERROR_MALFORMED;
208 }
209
210 return OK;
211}
212
213ssize_t AVIExtractor::parseChunk(off64_t offset, off64_t size, int depth) {
214 if (size >= 0 && size < 8) {
215 return ERROR_MALFORMED;
216 }
217
218 uint8_t tmp[12];
219 ssize_t n = mDataSource->readAt(offset, tmp, 8);
220
221 if (n < 8) {
222 return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
223 }
224
225 uint32_t fourcc = U32_AT(tmp);
226 uint32_t chunkSize = U32LE_AT(&tmp[4]);
227
228 if (size >= 0 && chunkSize + 8 > size) {
229 return ERROR_MALFORMED;
230 }
231
232 static const char kPrefix[] = " ";
233 const char *prefix = &kPrefix[strlen(kPrefix) - 2 * depth];
234
235 if (fourcc == FOURCC('L', 'I', 'S', 'T')
236 || fourcc == FOURCC('R', 'I', 'F', 'F')) {
237 // It's a list of chunks
238
239 if (size >= 0 && size < 12) {
240 return ERROR_MALFORMED;
241 }
242
243 n = mDataSource->readAt(offset + 8, &tmp[8], 4);
244
245 if (n < 4) {
246 return (n < 0) ? n : (ssize_t)ERROR_MALFORMED;
247 }
248
249 uint32_t subFourcc = U32_AT(&tmp[8]);
250
251 LOGV("%s offset 0x%08llx LIST of '%c%c%c%c', size %d",
252 prefix,
253 offset,
254 (char)(subFourcc >> 24),
255 (char)((subFourcc >> 16) & 0xff),
256 (char)((subFourcc >> 8) & 0xff),
257 (char)(subFourcc & 0xff),
258 chunkSize - 4);
259
260 if (subFourcc == FOURCC('m', 'o', 'v', 'i')) {
261 // We're not going to parse this, but will take note of the
262 // offset.
263
264 mMovieOffset = offset;
265 } else {
266 off64_t subOffset = offset + 12;
267 off64_t subOffsetLimit = subOffset + chunkSize - 4;
268 while (subOffset < subOffsetLimit) {
269 ssize_t res =
270 parseChunk(subOffset, subOffsetLimit - subOffset, depth + 1);
271
272 if (res < 0) {
273 return res;
274 }
275
276 subOffset += res;
277 }
278 }
279 } else {
280 LOGV("%s offset 0x%08llx CHUNK '%c%c%c%c'",
281 prefix,
282 offset,
283 (char)(fourcc >> 24),
284 (char)((fourcc >> 16) & 0xff),
285 (char)((fourcc >> 8) & 0xff),
286 (char)(fourcc & 0xff));
287
288 status_t err = OK;
289
290 switch (fourcc) {
291 case FOURCC('s', 't', 'r', 'h'):
292 {
293 err = parseStreamHeader(offset + 8, chunkSize);
294 break;
295 }
296
297 case FOURCC('s', 't', 'r', 'f'):
298 {
299 err = parseStreamFormat(offset + 8, chunkSize);
300 break;
301 }
302
303 case FOURCC('i', 'd', 'x', '1'):
304 {
305 err = parseIndex(offset + 8, chunkSize);
306 break;
307 }
308
309 default:
310 break;
311 }
312
313 if (err != OK) {
314 return err;
315 }
316 }
317
318 if (chunkSize & 1) {
319 ++chunkSize;
320 }
321
322 return chunkSize + 8;
323}
324
325static const char *GetMIMETypeForHandler(uint32_t handler) {
326 switch (handler) {
327 // Wow... shamelessly copied from
328 // http://wiki.multimedia.cx/index.php?title=ISO_MPEG-4
329
330 case FOURCC('3', 'I', 'V', '2'):
331 case FOURCC('3', 'i', 'v', '2'):
332 case FOURCC('B', 'L', 'Z', '0'):
333 case FOURCC('D', 'I', 'G', 'I'):
334 case FOURCC('D', 'I', 'V', '1'):
335 case FOURCC('d', 'i', 'v', '1'):
336 case FOURCC('D', 'I', 'V', 'X'):
337 case FOURCC('d', 'i', 'v', 'x'):
338 case FOURCC('D', 'X', '5', '0'):
339 case FOURCC('d', 'x', '5', '0'):
340 case FOURCC('D', 'X', 'G', 'M'):
341 case FOURCC('E', 'M', '4', 'A'):
342 case FOURCC('E', 'P', 'H', 'V'):
343 case FOURCC('F', 'M', 'P', '4'):
344 case FOURCC('f', 'm', 'p', '4'):
345 case FOURCC('F', 'V', 'F', 'W'):
346 case FOURCC('H', 'D', 'X', '4'):
347 case FOURCC('h', 'd', 'x', '4'):
348 case FOURCC('M', '4', 'C', 'C'):
349 case FOURCC('M', '4', 'S', '2'):
350 case FOURCC('m', '4', 's', '2'):
351 case FOURCC('M', 'P', '4', 'S'):
352 case FOURCC('m', 'p', '4', 's'):
353 case FOURCC('M', 'P', '4', 'V'):
354 case FOURCC('m', 'p', '4', 'v'):
355 case FOURCC('M', 'V', 'X', 'M'):
356 case FOURCC('R', 'M', 'P', '4'):
357 case FOURCC('S', 'E', 'D', 'G'):
358 case FOURCC('S', 'M', 'P', '4'):
359 case FOURCC('U', 'M', 'P', '4'):
360 case FOURCC('W', 'V', '1', 'F'):
361 case FOURCC('X', 'V', 'I', 'D'):
362 case FOURCC('X', 'v', 'i', 'D'):
363 case FOURCC('x', 'v', 'i', 'd'):
364 case FOURCC('X', 'V', 'I', 'X'):
365 return MEDIA_MIMETYPE_VIDEO_MPEG4;
366
367 default:
368 return NULL;
369 }
370}
371
372status_t AVIExtractor::parseStreamHeader(off64_t offset, size_t size) {
373 if (size != 56) {
374 return ERROR_MALFORMED;
375 }
376
377 if (mTracks.size() > 99) {
378 return -ERANGE;
379 }
380
381 sp<ABuffer> buffer = new ABuffer(size);
382 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
383
384 if (n < (ssize_t)size) {
385 return n < 0 ? (status_t)n : ERROR_MALFORMED;
386 }
387
388 const uint8_t *data = buffer->data();
389
390 uint32_t type = U32_AT(data);
391 uint32_t handler = U32_AT(&data[4]);
392 uint32_t flags = U32LE_AT(&data[8]);
393
394 sp<MetaData> meta = new MetaData;
395
396 uint32_t rate = U32LE_AT(&data[20]);
397 uint32_t scale = U32LE_AT(&data[24]);
398
399 const char *mime = NULL;
400 Track::Kind kind = Track::OTHER;
401
402 if (type == FOURCC('v', 'i', 'd', 's')) {
403 mime = GetMIMETypeForHandler(handler);
404
405 if (mime && strncasecmp(mime, "video/", 6)) {
406 return ERROR_MALFORMED;
407 }
408
409 kind = Track::VIDEO;
410 } else if (type == FOURCC('a', 'u', 'd', 's')) {
411 if (mime && strncasecmp(mime, "audio/", 6)) {
412 return ERROR_MALFORMED;
413 }
414
415 kind = Track::AUDIO;
416 }
417
418 if (!mime) {
419 mime = "application/octet-stream";
420 }
421
422 meta->setCString(kKeyMIMEType, mime);
423
424 mTracks.push();
425 Track *track = &mTracks.editItemAt(mTracks.size() - 1);
426
427 track->mMeta = meta;
428 track->mRate = rate;
429 track->mScale = scale;
430 track->mKind = kind;
431 track->mNumSyncSamples = 0;
432 track->mThumbnailSampleSize = 0;
433 track->mThumbnailSampleIndex = -1;
434 track->mMaxSampleSize = 0;
435
436 return OK;
437}
438
439status_t AVIExtractor::parseStreamFormat(off64_t offset, size_t size) {
440 if (mTracks.isEmpty()) {
441 return ERROR_MALFORMED;
442 }
443
444 Track *track = &mTracks.editItemAt(mTracks.size() - 1);
445
446 if (track->mKind == Track::OTHER) {
447 // We don't support this content, but that's not a parsing error.
448 return OK;
449 }
450
451 bool isVideo = (track->mKind == Track::VIDEO);
452
453 if ((isVideo && size < 40) || (!isVideo && size < 18)) {
454 // Expected a BITMAPINFO or WAVEFORMATEX structure, respectively.
455 return ERROR_MALFORMED;
456 }
457
458 sp<ABuffer> buffer = new ABuffer(size);
459 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
460
461 if (n < (ssize_t)size) {
462 return n < 0 ? (status_t)n : ERROR_MALFORMED;
463 }
464
465 const uint8_t *data = buffer->data();
466
467 if (isVideo) {
468 uint32_t width = U32LE_AT(&data[4]);
469 uint32_t height = U32LE_AT(&data[8]);
470
471 track->mMeta->setInt32(kKeyWidth, width);
472 track->mMeta->setInt32(kKeyHeight, height);
473 } else {
474 uint32_t format = U16LE_AT(data);
475 if (format == 0x55) {
476 track->mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
477 }
478
479 uint32_t numChannels = U16LE_AT(&data[2]);
480 uint32_t sampleRate = U32LE_AT(&data[4]);
481
482 track->mMeta->setInt32(kKeyChannelCount, numChannels);
483 track->mMeta->setInt32(kKeySampleRate, sampleRate);
484 }
485
486 return OK;
487}
488
489// static
490bool AVIExtractor::IsCorrectChunkType(
491 ssize_t trackIndex, Track::Kind kind, uint32_t chunkType) {
492 uint32_t chunkBase = chunkType & 0xffff;
493
494 switch (kind) {
495 case Track::VIDEO:
496 {
497 if (chunkBase != FOURCC(0, 0, 'd', 'c')
498 && chunkBase != FOURCC(0, 0, 'd', 'b')) {
499 return false;
500 }
501 break;
502 }
503
504 case Track::AUDIO:
505 {
506 if (chunkBase != FOURCC(0, 0, 'w', 'b')) {
507 return false;
508 }
509 break;
510 }
511
512 default:
513 break;
514 }
515
516 if (trackIndex < 0) {
517 return true;
518 }
519
520 uint8_t hi = chunkType >> 24;
521 uint8_t lo = (chunkType >> 16) & 0xff;
522
523 if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
524 return false;
525 }
526
527 if (trackIndex != (10 * (hi - '0') + (lo - '0'))) {
528 return false;
529 }
530
531 return true;
532}
533
534status_t AVIExtractor::parseIndex(off64_t offset, size_t size) {
535 if ((size % 16) != 0) {
536 return ERROR_MALFORMED;
537 }
538
539 sp<ABuffer> buffer = new ABuffer(size);
540 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
541
542 if (n < (ssize_t)size) {
543 return n < 0 ? (status_t)n : ERROR_MALFORMED;
544 }
545
546 const uint8_t *data = buffer->data();
547
548 while (size > 0) {
549 uint32_t chunkType = U32_AT(data);
550
551 uint8_t hi = chunkType >> 24;
552 uint8_t lo = (chunkType >> 16) & 0xff;
553
554 if (hi < '0' || hi > '9' || lo < '0' || lo > '9') {
555 return ERROR_MALFORMED;
556 }
557
558 size_t trackIndex = 10 * (hi - '0') + (lo - '0');
559
560 if (trackIndex >= mTracks.size()) {
561 return ERROR_MALFORMED;
562 }
563
564 Track *track = &mTracks.editItemAt(trackIndex);
565
566 if (!IsCorrectChunkType(-1, track->mKind, chunkType)) {
567 return ERROR_MALFORMED;
568 }
569
570 if (track->mKind == Track::OTHER) {
571 data += 16;
572 size -= 16;
573 continue;
574 }
575
576 uint32_t flags = U32LE_AT(&data[4]);
577 uint32_t offset = U32LE_AT(&data[8]);
578 uint32_t chunkSize = U32LE_AT(&data[12]);
579
580 if (chunkSize > track->mMaxSampleSize) {
581 track->mMaxSampleSize = chunkSize;
582 }
583
584 track->mSamples.push();
585
586 SampleInfo *info =
587 &track->mSamples.editItemAt(track->mSamples.size() - 1);
588
589 info->mOffset = offset;
590 info->mIsKey = (flags & 0x10) != 0;
591
592 if (info->mIsKey) {
593 static const size_t kMaxNumSyncSamplesToScan = 20;
594
595 if (track->mNumSyncSamples < kMaxNumSyncSamplesToScan) {
596 if (chunkSize > track->mThumbnailSampleSize) {
597 track->mThumbnailSampleSize = chunkSize;
598
599 track->mThumbnailSampleIndex =
600 track->mSamples.size() - 1;
601 }
602 }
603
604 ++track->mNumSyncSamples;
605 }
606
607 data += 16;
608 size -= 16;
609 }
610
611 if (!mTracks.isEmpty()) {
612 off64_t offset;
613 size_t size;
614 bool isKey;
615 status_t err = getSampleInfo(0, 0, &offset, &size, &isKey);
616
617 if (err != OK) {
618 mOffsetsAreAbsolute = !mOffsetsAreAbsolute;
619 err = getSampleInfo(0, 0, &offset, &size, &isKey);
620
621 if (err != OK) {
622 return err;
623 }
624 }
625
626 LOGV("Chunk offsets are %s",
627 mOffsetsAreAbsolute ? "absolute" : "movie-chunk relative");
628 }
629
630 for (size_t i = 0; i < mTracks.size(); ++i) {
631 Track *track = &mTracks.editItemAt(i);
632
633 int64_t durationUs =
634 (track->mSamples.size() * 1000000ll * track->mRate) / track->mScale;
635
636 LOGV("track %d duration = %.2f secs", i, durationUs / 1E6);
637
638 track->mMeta->setInt64(kKeyDuration, durationUs);
639 track->mMeta->setInt32(kKeyMaxInputSize, track->mMaxSampleSize);
640
641 const char *tmp;
642 CHECK(track->mMeta->findCString(kKeyMIMEType, &tmp));
643
644 AString mime = tmp;
645
646 if (!strncasecmp("video/", mime.c_str(), 6)
647 && track->mThumbnailSampleIndex >= 0) {
648 int64_t thumbnailTimeUs =
649 (track->mThumbnailSampleIndex * 1000000ll * track->mRate)
650 / track->mScale;
651
652 track->mMeta->setInt64(kKeyThumbnailTime, thumbnailTimeUs);
653
654 if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_MPEG4)) {
655 status_t err = addMPEG4CodecSpecificData(i);
656
657 if (err != OK) {
658 return err;
659 }
660 }
661 }
662 }
663
664 mFoundIndex = true;
665
666 return OK;
667}
668
669static size_t GetSizeWidth(size_t x) {
670 size_t n = 1;
671 while (x > 127) {
672 ++n;
673 x >>= 7;
674 }
675 return n;
676}
677
678static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
679 while (x > 127) {
680 *dst++ = (x & 0x7f) | 0x80;
681 x >>= 7;
682 }
683 *dst++ = x;
684 return dst;
685}
686
687sp<ABuffer> MakeMPEG4VideoCodecSpecificData(const sp<ABuffer> &config) {
688 size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
689 size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
690 size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
691
692 sp<ABuffer> csd = new ABuffer(len3);
693 uint8_t *dst = csd->data();
694 *dst++ = 0x03;
695 dst = EncodeSize(dst, len2 + 3);
696 *dst++ = 0x00; // ES_ID
697 *dst++ = 0x00;
698 *dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
699
700 *dst++ = 0x04;
701 dst = EncodeSize(dst, len1 + 13);
702 *dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile
703 for (size_t i = 0; i < 12; ++i) {
704 *dst++ = 0x00;
705 }
706
707 *dst++ = 0x05;
708 dst = EncodeSize(dst, config->size());
709 memcpy(dst, config->data(), config->size());
710 dst += config->size();
711
712 // hexdump(csd->data(), csd->size());
713
714 return csd;
715}
716
717status_t AVIExtractor::addMPEG4CodecSpecificData(size_t trackIndex) {
718 Track *track = &mTracks.editItemAt(trackIndex);
719
720 off64_t offset;
721 size_t size;
722 bool isKey;
723 status_t err = getSampleInfo(trackIndex, 0, &offset, &size, &isKey);
724
725 if (err != OK) {
726 return err;
727 }
728
729 sp<ABuffer> buffer = new ABuffer(size);
730 ssize_t n = mDataSource->readAt(offset, buffer->data(), buffer->size());
731
732 if (n < (ssize_t)size) {
733 return n < 0 ? (status_t)n : ERROR_MALFORMED;
734 }
735
736 // Extract everything up to the first VOP start code from the first
737 // frame's encoded data and use it to construct an ESDS with the
738 // codec specific data.
739
740 size_t i = 0;
741 bool found = false;
742 while (i + 3 < buffer->size()) {
743 if (!memcmp("\x00\x00\x01\xb6", &buffer->data()[i], 4)) {
744 found = true;
745 break;
746 }
747
748 ++i;
749 }
750
751 if (!found) {
752 return ERROR_MALFORMED;
753 }
754
755 buffer->setRange(0, i);
756
757 sp<ABuffer> csd = MakeMPEG4VideoCodecSpecificData(buffer);
758 track->mMeta->setData(kKeyESDS, kTypeESDS, csd->data(), csd->size());
759
760 return OK;
761}
762
763status_t AVIExtractor::getSampleInfo(
764 size_t trackIndex, size_t sampleIndex,
765 off64_t *offset, size_t *size, bool *isKey) {
766 if (trackIndex >= mTracks.size()) {
767 return -ERANGE;
768 }
769
770 const Track &track = mTracks.itemAt(trackIndex);
771
772 if (sampleIndex >= track.mSamples.size()) {
773 return -ERANGE;
774 }
775
776 const SampleInfo &info = track.mSamples.itemAt(sampleIndex);
777
778 if (!mOffsetsAreAbsolute) {
779 *offset = info.mOffset + mMovieOffset + 8;
780 } else {
781 *offset = info.mOffset;
782 }
783
784 *size = 0;
785
786 uint8_t tmp[8];
787 ssize_t n = mDataSource->readAt(*offset, tmp, 8);
788
789 if (n < 8) {
790 return n < 0 ? (status_t)n : (status_t)ERROR_MALFORMED;
791 }
792
793 uint32_t chunkType = U32_AT(tmp);
794
795 if (!IsCorrectChunkType(trackIndex, track.mKind, chunkType)) {
796 return ERROR_MALFORMED;
797 }
798
799 *offset += 8;
800 *size = U32LE_AT(&tmp[4]);
801
802 *isKey = info.mIsKey;
803
804 return OK;
805}
806
807status_t AVIExtractor::getSampleIndexAtTime(
808 size_t trackIndex,
809 int64_t timeUs, MediaSource::ReadOptions::SeekMode mode,
810 size_t *sampleIndex) const {
811 if (trackIndex >= mTracks.size()) {
812 return -ERANGE;
813 }
814
815 const Track &track = mTracks.itemAt(trackIndex);
816
817 ssize_t closestSampleIndex =
818 timeUs / track.mRate * track.mScale / 1000000ll;
819
820 ssize_t numSamples = track.mSamples.size();
821
822 if (closestSampleIndex < 0) {
823 closestSampleIndex = 0;
824 } else if (closestSampleIndex >= numSamples) {
825 closestSampleIndex = numSamples - 1;
826 }
827
828 if (mode == MediaSource::ReadOptions::SEEK_CLOSEST) {
829 *sampleIndex = closestSampleIndex;
830
831 return OK;
832 }
833
834 ssize_t prevSyncSampleIndex = closestSampleIndex;
835 while (prevSyncSampleIndex >= 0) {
836 const SampleInfo &info =
837 track.mSamples.itemAt(prevSyncSampleIndex);
838
839 if (info.mIsKey) {
840 break;
841 }
842
843 --prevSyncSampleIndex;
844 }
845
846 ssize_t nextSyncSampleIndex = closestSampleIndex;
847 while (nextSyncSampleIndex < numSamples) {
848 const SampleInfo &info =
849 track.mSamples.itemAt(nextSyncSampleIndex);
850
851 if (info.mIsKey) {
852 break;
853 }
854
855 ++nextSyncSampleIndex;
856 }
857
858 switch (mode) {
859 case MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC:
860 {
861 *sampleIndex = prevSyncSampleIndex;
862
863 return prevSyncSampleIndex >= 0 ? OK : UNKNOWN_ERROR;
864 }
865
866 case MediaSource::ReadOptions::SEEK_NEXT_SYNC:
867 {
868 *sampleIndex = nextSyncSampleIndex;
869
870 return nextSyncSampleIndex < numSamples ? OK : UNKNOWN_ERROR;
871 }
872
873 case MediaSource::ReadOptions::SEEK_CLOSEST_SYNC:
874 {
875 if (prevSyncSampleIndex < 0 && nextSyncSampleIndex >= numSamples) {
876 return UNKNOWN_ERROR;
877 }
878
879 if (prevSyncSampleIndex < 0) {
880 *sampleIndex = nextSyncSampleIndex;
881 return OK;
882 }
883
884 if (nextSyncSampleIndex >= numSamples) {
885 *sampleIndex = prevSyncSampleIndex;
886 return OK;
887 }
888
889 size_t dist1 = closestSampleIndex - prevSyncSampleIndex;
890 size_t dist2 = nextSyncSampleIndex - closestSampleIndex;
891
892 *sampleIndex =
893 (dist1 < dist2) ? prevSyncSampleIndex : nextSyncSampleIndex;
894
895 return OK;
896 }
897
898 default:
899 TRESPASS();
900 break;
901 }
902}
903
904bool SniffAVI(
905 const sp<DataSource> &source, String8 *mimeType, float *confidence,
906 sp<AMessage> *) {
907 char tmp[12];
908 if (source->readAt(0, tmp, 12) < 12) {
909 return false;
910 }
911
912 if (!memcmp(tmp, "RIFF", 4) && !memcmp(&tmp[8], "AVI ", 4)) {
913 mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_AVI);
914 *confidence = 0.2;
915
916 return true;
917 }
918
919 return false;
920}
921
922} // namespace android