blob: b9a482614ed10e9ee16a604f3cbd91d0a5b8a424 [file] [log] [blame]
Andreas Huberb72c7e32010-10-01 10:51:41 -07001/*
2 * Copyright (C) 2010 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 "ESQueue"
19#include <media/stagefright/foundation/ADebug.h>
20
21#include "ESQueue.h"
22
23#include <media/stagefright/foundation/hexdump.h>
24#include <media/stagefright/foundation/ABitReader.h>
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/AMessage.h>
27#include <media/stagefright/MediaErrors.h>
28#include <media/stagefright/MediaDefs.h>
29#include <media/stagefright/MetaData.h>
Andreas Hubereb2f9c12011-05-19 08:37:39 -070030#include <media/stagefright/Utils.h>
Andreas Huberb72c7e32010-10-01 10:51:41 -070031
32#include "include/avc_utils.h"
33
34namespace android {
35
36ElementaryStreamQueue::ElementaryStreamQueue(Mode mode)
37 : mMode(mode) {
38}
39
40sp<MetaData> ElementaryStreamQueue::getFormat() {
41 return mFormat;
42}
43
Andreas Hubera1587462010-12-15 15:17:42 -080044void ElementaryStreamQueue::clear(bool clearFormat) {
Andreas Huber6a1f5f92010-11-15 09:03:03 -080045 if (mBuffer != NULL) {
46 mBuffer->setRange(0, 0);
47 }
48
Andreas Huber9c5d62a2010-12-15 14:07:50 -080049 mRangeInfos.clear();
Andreas Hubera1587462010-12-15 15:17:42 -080050
51 if (clearFormat) {
52 mFormat.clear();
53 }
Andreas Huber4c19bf92010-09-08 14:32:20 -070054}
55
Andreas Huberb5590842010-12-03 16:12:25 -080056static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
57 if (size < 3) {
58 // Not enough data to verify header.
59 return false;
60 }
61
62 if (ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
63 return false;
64 }
65
66 unsigned layer = (ptr[1] >> 1) & 3;
67
68 if (layer != 0) {
69 return false;
70 }
71
72 unsigned ID = (ptr[1] >> 3) & 1;
73 unsigned profile_ObjectType = ptr[2] >> 6;
74
75 if (ID == 1 && profile_ObjectType == 3) {
76 // MPEG-2 profile 3 is reserved.
77 return false;
78 }
79
80 return true;
81}
82
Andreas Hubereb2f9c12011-05-19 08:37:39 -070083static bool IsSeeminglyValidMPEGAudioHeader(const uint8_t *ptr, size_t size) {
84 if (size < 3) {
85 // Not enough data to verify header.
86 return false;
87 }
88
89 if (ptr[0] != 0xff || (ptr[1] >> 5) != 0x07) {
90 return false;
91 }
92
93 unsigned ID = (ptr[1] >> 3) & 3;
94
95 if (ID == 1) {
96 return false; // reserved
97 }
98
99 unsigned layer = (ptr[1] >> 1) & 3;
100
101 if (layer == 0) {
102 return false; // reserved
103 }
104
105 unsigned bitrateIndex = (ptr[2] >> 4);
106
107 if (bitrateIndex == 0x0f) {
108 return false; // reserved
109 }
110
111 unsigned samplingRateIndex = (ptr[2] >> 2) & 3;
112
113 if (samplingRateIndex == 3) {
114 return false; // reserved
115 }
116
117 return true;
118}
119
Andreas Huberb72c7e32010-10-01 10:51:41 -0700120status_t ElementaryStreamQueue::appendData(
121 const void *data, size_t size, int64_t timeUs) {
122 if (mBuffer == NULL || mBuffer->size() == 0) {
123 switch (mMode) {
124 case H264:
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700125 case MPEG_VIDEO:
Andreas Huberb72c7e32010-10-01 10:51:41 -0700126 {
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800127#if 0
Andreas Huberb72c7e32010-10-01 10:51:41 -0700128 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
129 return ERROR_MALFORMED;
130 }
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800131#else
132 uint8_t *ptr = (uint8_t *)data;
133
134 ssize_t startOffset = -1;
135 for (size_t i = 0; i + 3 < size; ++i) {
136 if (!memcmp("\x00\x00\x00\x01", &ptr[i], 4)) {
137 startOffset = i;
138 break;
139 }
140 }
141
142 if (startOffset < 0) {
143 return ERROR_MALFORMED;
144 }
145
146 if (startOffset > 0) {
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700147 LOGI("found something resembling an H.264/MPEG syncword at "
148 "offset %ld",
149 startOffset);
150 }
151
152 data = &ptr[startOffset];
153 size -= startOffset;
154#endif
155 break;
156 }
157
158 case MPEG4_VIDEO:
159 {
160#if 0
161 if (size < 3 || memcmp("\x00\x00\x01", data, 3)) {
162 return ERROR_MALFORMED;
163 }
164#else
165 uint8_t *ptr = (uint8_t *)data;
166
167 ssize_t startOffset = -1;
168 for (size_t i = 0; i + 2 < size; ++i) {
169 if (!memcmp("\x00\x00\x01", &ptr[i], 3)) {
170 startOffset = i;
171 break;
172 }
173 }
174
175 if (startOffset < 0) {
176 return ERROR_MALFORMED;
177 }
178
179 if (startOffset > 0) {
180 LOGI("found something resembling an H.264/MPEG syncword at "
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800181 "offset %ld",
182 startOffset);
183 }
184
185 data = &ptr[startOffset];
186 size -= startOffset;
187#endif
Andreas Huberb72c7e32010-10-01 10:51:41 -0700188 break;
189 }
190
191 case AAC:
192 {
193 uint8_t *ptr = (uint8_t *)data;
194
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800195#if 0
Andreas Huberb72c7e32010-10-01 10:51:41 -0700196 if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
197 return ERROR_MALFORMED;
198 }
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800199#else
200 ssize_t startOffset = -1;
Andreas Huberb5590842010-12-03 16:12:25 -0800201 for (size_t i = 0; i < size; ++i) {
202 if (IsSeeminglyValidADTSHeader(&ptr[i], size - i)) {
Andreas Huberb5c6afc2010-12-02 13:27:47 -0800203 startOffset = i;
204 break;
205 }
206 }
207
208 if (startOffset < 0) {
209 return ERROR_MALFORMED;
210 }
211
212 if (startOffset > 0) {
213 LOGI("found something resembling an AAC syncword at offset %ld",
214 startOffset);
215 }
216
217 data = &ptr[startOffset];
218 size -= startOffset;
219#endif
Andreas Huberb72c7e32010-10-01 10:51:41 -0700220 break;
221 }
222
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700223 case MPEG_AUDIO:
224 {
225 uint8_t *ptr = (uint8_t *)data;
226
227 ssize_t startOffset = -1;
228 for (size_t i = 0; i < size; ++i) {
229 if (IsSeeminglyValidMPEGAudioHeader(&ptr[i], size - i)) {
230 startOffset = i;
231 break;
232 }
233 }
234
235 if (startOffset < 0) {
236 return ERROR_MALFORMED;
237 }
238
239 if (startOffset > 0) {
240 LOGI("found something resembling an MPEG audio "
241 "syncword at offset %ld",
242 startOffset);
243 }
244
245 data = &ptr[startOffset];
246 size -= startOffset;
247 break;
248 }
249
Andreas Huberb72c7e32010-10-01 10:51:41 -0700250 default:
251 TRESPASS();
252 break;
253 }
254 }
255
256 size_t neededSize = (mBuffer == NULL ? 0 : mBuffer->size()) + size;
257 if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
258 neededSize = (neededSize + 65535) & ~65535;
259
Andreas Huber4c19bf92010-09-08 14:32:20 -0700260 LOGV("resizing buffer to size %d", neededSize);
Andreas Huberb72c7e32010-10-01 10:51:41 -0700261
262 sp<ABuffer> buffer = new ABuffer(neededSize);
263 if (mBuffer != NULL) {
264 memcpy(buffer->data(), mBuffer->data(), mBuffer->size());
265 buffer->setRange(0, mBuffer->size());
266 } else {
267 buffer->setRange(0, 0);
268 }
269
270 mBuffer = buffer;
271 }
272
273 memcpy(mBuffer->data() + mBuffer->size(), data, size);
274 mBuffer->setRange(0, mBuffer->size() + size);
275
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800276 RangeInfo info;
277 info.mLength = size;
278 info.mTimestampUs = timeUs;
279 mRangeInfos.push_back(info);
280
281#if 0
282 if (mMode == AAC) {
283 LOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6);
284 hexdump(data, size);
285 }
286#endif
Andreas Huberb72c7e32010-10-01 10:51:41 -0700287
288 return OK;
289}
290
291sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700292 switch (mMode) {
293 case H264:
294 return dequeueAccessUnitH264();
295 case AAC:
296 return dequeueAccessUnitAAC();
297 case MPEG_VIDEO:
298 return dequeueAccessUnitMPEGVideo();
299 case MPEG4_VIDEO:
300 return dequeueAccessUnitMPEG4Video();
301 default:
302 CHECK_EQ((unsigned)mMode, (unsigned)MPEG_AUDIO);
303 return dequeueAccessUnitMPEGAudio();
Andreas Huberb72c7e32010-10-01 10:51:41 -0700304 }
305}
306
307sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800308 Vector<size_t> ranges;
Andreas Huberb72c7e32010-10-01 10:51:41 -0700309 Vector<size_t> frameOffsets;
310 Vector<size_t> frameSizes;
311 size_t auSize = 0;
312
313 size_t offset = 0;
314 while (offset + 7 <= mBuffer->size()) {
315 ABitReader bits(mBuffer->data() + offset, mBuffer->size() - offset);
316
317 // adts_fixed_header
318
319 CHECK_EQ(bits.getBits(12), 0xfffu);
320 bits.skipBits(3); // ID, layer
321 bool protection_absent = bits.getBits(1) != 0;
322
323 if (mFormat == NULL) {
324 unsigned profile = bits.getBits(2);
325 CHECK_NE(profile, 3u);
326 unsigned sampling_freq_index = bits.getBits(4);
327 bits.getBits(1); // private_bit
328 unsigned channel_configuration = bits.getBits(3);
329 CHECK_NE(channel_configuration, 0u);
330 bits.skipBits(2); // original_copy, home
331
332 mFormat = MakeAACCodecSpecificData(
333 profile, sampling_freq_index, channel_configuration);
Andreas Huber54e66492010-12-23 10:27:40 -0800334
335 int32_t sampleRate;
336 int32_t numChannels;
337 CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate));
338 CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels));
339
340 LOGI("found AAC codec config (%d Hz, %d channels)",
341 sampleRate, numChannels);
Andreas Huberb72c7e32010-10-01 10:51:41 -0700342 } else {
343 // profile_ObjectType, sampling_frequency_index, private_bits,
344 // channel_configuration, original_copy, home
345 bits.skipBits(12);
346 }
347
348 // adts_variable_header
349
350 // copyright_identification_bit, copyright_identification_start
351 bits.skipBits(2);
352
353 unsigned aac_frame_length = bits.getBits(13);
354
355 bits.skipBits(11); // adts_buffer_fullness
356
357 unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
358
359 if (number_of_raw_data_blocks_in_frame != 0) {
360 // To be implemented.
361 TRESPASS();
362 }
363
364 if (offset + aac_frame_length > mBuffer->size()) {
365 break;
366 }
367
368 size_t headerSize = protection_absent ? 7 : 9;
369
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800370 ranges.push(aac_frame_length);
Andreas Huberb72c7e32010-10-01 10:51:41 -0700371 frameOffsets.push(offset + headerSize);
372 frameSizes.push(aac_frame_length - headerSize);
373 auSize += aac_frame_length - headerSize;
374
375 offset += aac_frame_length;
376 }
377
378 if (offset == 0) {
379 return NULL;
380 }
381
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800382 int64_t timeUs = -1;
383
384 for (size_t i = 0; i < ranges.size(); ++i) {
385 int64_t tmpUs = fetchTimestamp(ranges.itemAt(i));
386
387 if (i == 0) {
388 timeUs = tmpUs;
389 }
390 }
391
Andreas Huberb72c7e32010-10-01 10:51:41 -0700392 sp<ABuffer> accessUnit = new ABuffer(auSize);
393 size_t dstOffset = 0;
394 for (size_t i = 0; i < frameOffsets.size(); ++i) {
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800395 size_t frameOffset = frameOffsets.itemAt(i);
396
Andreas Huberb72c7e32010-10-01 10:51:41 -0700397 memcpy(accessUnit->data() + dstOffset,
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800398 mBuffer->data() + frameOffset,
Andreas Huberb72c7e32010-10-01 10:51:41 -0700399 frameSizes.itemAt(i));
400
401 dstOffset += frameSizes.itemAt(i);
402 }
403
404 memmove(mBuffer->data(), mBuffer->data() + offset,
405 mBuffer->size() - offset);
406 mBuffer->setRange(0, mBuffer->size() - offset);
407
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800408 if (timeUs >= 0) {
Andreas Hubera1587462010-12-15 15:17:42 -0800409 accessUnit->meta()->setInt64("timeUs", timeUs);
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800410 } else {
411 LOGW("no time for AAC access unit");
412 }
Andreas Huberb72c7e32010-10-01 10:51:41 -0700413
414 return accessUnit;
415}
416
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800417int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) {
418 int64_t timeUs = -1;
419 bool first = true;
420
421 while (size > 0) {
422 CHECK(!mRangeInfos.empty());
423
424 RangeInfo *info = &*mRangeInfos.begin();
425
426 if (first) {
427 timeUs = info->mTimestampUs;
428 first = false;
429 }
430
431 if (info->mLength > size) {
432 info->mLength -= size;
433
434 if (first) {
435 info->mTimestampUs = -1;
436 }
437
438 size = 0;
439 } else {
440 size -= info->mLength;
441
442 mRangeInfos.erase(mRangeInfos.begin());
443 info = NULL;
444 }
445 }
446
Andreas Huber33d94062011-10-12 12:14:23 -0700447 if (timeUs == 0ll) {
448 LOGV("Returning 0 timestamp");
449 }
450
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800451 return timeUs;
452}
453
Andreas Huberb72c7e32010-10-01 10:51:41 -0700454struct NALPosition {
455 size_t nalOffset;
456 size_t nalSize;
457};
458
459sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
460 const uint8_t *data = mBuffer->data();
461 size_t size = mBuffer->size();
462
463 Vector<NALPosition> nals;
464
465 size_t totalSize = 0;
466
467 status_t err;
468 const uint8_t *nalStart;
469 size_t nalSize;
470 bool foundSlice = false;
471 while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) {
472 CHECK_GT(nalSize, 0u);
473
474 unsigned nalType = nalStart[0] & 0x1f;
475 bool flush = false;
476
477 if (nalType == 1 || nalType == 5) {
478 if (foundSlice) {
479 ABitReader br(nalStart + 1, nalSize);
480 unsigned first_mb_in_slice = parseUE(&br);
481
482 if (first_mb_in_slice == 0) {
483 // This slice starts a new frame.
484
485 flush = true;
486 }
487 }
488
489 foundSlice = true;
490 } else if ((nalType == 9 || nalType == 7) && foundSlice) {
491 // Access unit delimiter and SPS will be associated with the
492 // next frame.
493
494 flush = true;
495 }
496
497 if (flush) {
498 // The access unit will contain all nal units up to, but excluding
499 // the current one, separated by 0x00 0x00 0x00 0x01 startcodes.
500
501 size_t auSize = 4 * nals.size() + totalSize;
502 sp<ABuffer> accessUnit = new ABuffer(auSize);
503
504#if !LOG_NDEBUG
505 AString out;
506#endif
507
508 size_t dstOffset = 0;
509 for (size_t i = 0; i < nals.size(); ++i) {
510 const NALPosition &pos = nals.itemAt(i);
511
512 unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
513
514#if !LOG_NDEBUG
515 char tmp[128];
516 sprintf(tmp, "0x%02x", nalType);
517 if (i > 0) {
518 out.append(", ");
519 }
520 out.append(tmp);
521#endif
522
523 memcpy(accessUnit->data() + dstOffset, "\x00\x00\x00\x01", 4);
524
525 memcpy(accessUnit->data() + dstOffset + 4,
526 mBuffer->data() + pos.nalOffset,
527 pos.nalSize);
528
529 dstOffset += pos.nalSize + 4;
530 }
531
532 LOGV("accessUnit contains nal types %s", out.c_str());
533
534 const NALPosition &pos = nals.itemAt(nals.size() - 1);
535 size_t nextScan = pos.nalOffset + pos.nalSize;
536
537 memmove(mBuffer->data(),
538 mBuffer->data() + nextScan,
539 mBuffer->size() - nextScan);
540
541 mBuffer->setRange(0, mBuffer->size() - nextScan);
542
Andreas Huber9c5d62a2010-12-15 14:07:50 -0800543 int64_t timeUs = fetchTimestamp(nextScan);
544 CHECK_GE(timeUs, 0ll);
Andreas Huberb72c7e32010-10-01 10:51:41 -0700545
Andreas Hubera1587462010-12-15 15:17:42 -0800546 accessUnit->meta()->setInt64("timeUs", timeUs);
Andreas Huberb72c7e32010-10-01 10:51:41 -0700547
548 if (mFormat == NULL) {
549 mFormat = MakeAVCCodecSpecificData(accessUnit);
550 }
551
552 return accessUnit;
553 }
554
555 NALPosition pos;
556 pos.nalOffset = nalStart - mBuffer->data();
557 pos.nalSize = nalSize;
558
559 nals.push(pos);
560
561 totalSize += nalSize;
562 }
563 CHECK_EQ(err, (status_t)-EAGAIN);
564
565 return NULL;
566}
567
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700568sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() {
569 const uint8_t *data = mBuffer->data();
570 size_t size = mBuffer->size();
571
572 if (size < 4) {
573 return NULL;
574 }
575
576 uint32_t header = U32_AT(data);
577
578 size_t frameSize;
579 int samplingRate, numChannels, bitrate, numSamples;
580 CHECK(GetMPEGAudioFrameSize(
581 header, &frameSize, &samplingRate, &numChannels,
582 &bitrate, &numSamples));
583
584 if (size < frameSize) {
585 return NULL;
586 }
587
Andreas Huberbc554952011-09-08 14:12:44 -0700588 unsigned layer = 4 - ((header >> 17) & 3);
589
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700590 sp<ABuffer> accessUnit = new ABuffer(frameSize);
591 memcpy(accessUnit->data(), data, frameSize);
592
593 memmove(mBuffer->data(),
594 mBuffer->data() + frameSize,
595 mBuffer->size() - frameSize);
596
597 mBuffer->setRange(0, mBuffer->size() - frameSize);
598
599 int64_t timeUs = fetchTimestamp(frameSize);
600 CHECK_GE(timeUs, 0ll);
601
602 accessUnit->meta()->setInt64("timeUs", timeUs);
603
604 if (mFormat == NULL) {
605 mFormat = new MetaData;
Andreas Huberbc554952011-09-08 14:12:44 -0700606
607 switch (layer) {
608 case 1:
609 mFormat->setCString(
610 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
611 break;
612 case 2:
613 mFormat->setCString(
614 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
615 break;
616 case 3:
617 mFormat->setCString(
618 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
619 break;
620 default:
621 TRESPASS();
622 }
623
Andreas Hubereb2f9c12011-05-19 08:37:39 -0700624 mFormat->setInt32(kKeySampleRate, samplingRate);
625 mFormat->setInt32(kKeyChannelCount, numChannels);
626 }
627
628 return accessUnit;
629}
630
631static void EncodeSize14(uint8_t **_ptr, size_t size) {
632 CHECK_LE(size, 0x3fff);
633
634 uint8_t *ptr = *_ptr;
635
636 *ptr++ = 0x80 | (size >> 7);
637 *ptr++ = size & 0x7f;
638
639 *_ptr = ptr;
640}
641
642static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) {
643 sp<ABuffer> esds = new ABuffer(csd->size() + 25);
644
645 uint8_t *ptr = esds->data();
646 *ptr++ = 0x03;
647 EncodeSize14(&ptr, 22 + csd->size());
648
649 *ptr++ = 0x00; // ES_ID
650 *ptr++ = 0x00;
651
652 *ptr++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
653
654 *ptr++ = 0x04;
655 EncodeSize14(&ptr, 16 + csd->size());
656
657 *ptr++ = 0x40; // Audio ISO/IEC 14496-3
658
659 for (size_t i = 0; i < 12; ++i) {
660 *ptr++ = 0x00;
661 }
662
663 *ptr++ = 0x05;
664 EncodeSize14(&ptr, csd->size());
665
666 memcpy(ptr, csd->data(), csd->size());
667
668 return esds;
669}
670
671sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
672 const uint8_t *data = mBuffer->data();
673 size_t size = mBuffer->size();
674
675 bool sawPictureStart = false;
676 int pprevStartCode = -1;
677 int prevStartCode = -1;
678 int currentStartCode = -1;
679
680 size_t offset = 0;
681 while (offset + 3 < size) {
682 if (memcmp(&data[offset], "\x00\x00\x01", 3)) {
683 ++offset;
684 continue;
685 }
686
687 pprevStartCode = prevStartCode;
688 prevStartCode = currentStartCode;
689 currentStartCode = data[offset + 3];
690
691 if (currentStartCode == 0xb3 && mFormat == NULL) {
692 memmove(mBuffer->data(), mBuffer->data() + offset, size - offset);
693 size -= offset;
694 (void)fetchTimestamp(offset);
695 offset = 0;
696 mBuffer->setRange(0, size);
697 }
698
699 if ((prevStartCode == 0xb3 && currentStartCode != 0xb5)
700 || (pprevStartCode == 0xb3 && prevStartCode == 0xb5)) {
701 // seqHeader without/with extension
702
703 if (mFormat == NULL) {
704 CHECK_GE(size, 7u);
705
706 unsigned width =
707 (data[4] << 4) | data[5] >> 4;
708
709 unsigned height =
710 ((data[5] & 0x0f) << 8) | data[6];
711
712 mFormat = new MetaData;
713 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
714 mFormat->setInt32(kKeyWidth, width);
715 mFormat->setInt32(kKeyHeight, height);
716
717 LOGI("found MPEG2 video codec config (%d x %d)", width, height);
718
719 sp<ABuffer> csd = new ABuffer(offset);
720 memcpy(csd->data(), data, offset);
721
722 memmove(mBuffer->data(),
723 mBuffer->data() + offset,
724 mBuffer->size() - offset);
725
726 mBuffer->setRange(0, mBuffer->size() - offset);
727 size -= offset;
728 (void)fetchTimestamp(offset);
729 offset = 0;
730
731 // hexdump(csd->data(), csd->size());
732
733 sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
734 mFormat->setData(
735 kKeyESDS, kTypeESDS, esds->data(), esds->size());
736
737 return NULL;
738 }
739 }
740
741 if (mFormat != NULL && currentStartCode == 0x00) {
742 // Picture start
743
744 if (!sawPictureStart) {
745 sawPictureStart = true;
746 } else {
747 sp<ABuffer> accessUnit = new ABuffer(offset);
748 memcpy(accessUnit->data(), data, offset);
749
750 memmove(mBuffer->data(),
751 mBuffer->data() + offset,
752 mBuffer->size() - offset);
753
754 mBuffer->setRange(0, mBuffer->size() - offset);
755
756 int64_t timeUs = fetchTimestamp(offset);
757 CHECK_GE(timeUs, 0ll);
758
759 offset = 0;
760
761 accessUnit->meta()->setInt64("timeUs", timeUs);
762
763 LOGV("returning MPEG video access unit at time %lld us",
764 timeUs);
765
766 // hexdump(accessUnit->data(), accessUnit->size());
767
768 return accessUnit;
769 }
770 }
771
772 ++offset;
773 }
774
775 return NULL;
776}
777
778static ssize_t getNextChunkSize(
779 const uint8_t *data, size_t size) {
780 static const char kStartCode[] = "\x00\x00\x01";
781
782 if (size < 3) {
783 return -EAGAIN;
784 }
785
786 if (memcmp(kStartCode, data, 3)) {
787 TRESPASS();
788 }
789
790 size_t offset = 3;
791 while (offset + 2 < size) {
792 if (!memcmp(&data[offset], kStartCode, 3)) {
793 return offset;
794 }
795
796 ++offset;
797 }
798
799 return -EAGAIN;
800}
801
802sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() {
803 uint8_t *data = mBuffer->data();
804 size_t size = mBuffer->size();
805
806 enum {
807 SKIP_TO_VISUAL_OBJECT_SEQ_START,
808 EXPECT_VISUAL_OBJECT_START,
809 EXPECT_VO_START,
810 EXPECT_VOL_START,
811 WAIT_FOR_VOP_START,
812 SKIP_TO_VOP_START,
813
814 } state;
815
816 if (mFormat == NULL) {
817 state = SKIP_TO_VISUAL_OBJECT_SEQ_START;
818 } else {
819 state = SKIP_TO_VOP_START;
820 }
821
822 int32_t width = -1, height = -1;
823
824 size_t offset = 0;
825 ssize_t chunkSize;
826 while ((chunkSize = getNextChunkSize(
827 &data[offset], size - offset)) > 0) {
828 bool discard = false;
829
830 unsigned chunkType = data[offset + 3];
831
832 switch (state) {
833 case SKIP_TO_VISUAL_OBJECT_SEQ_START:
834 {
835 if (chunkType == 0xb0) {
836 // Discard anything before this marker.
837
838 state = EXPECT_VISUAL_OBJECT_START;
839 } else {
840 discard = true;
841 }
842 break;
843 }
844
845 case EXPECT_VISUAL_OBJECT_START:
846 {
847 CHECK_EQ(chunkType, 0xb5);
848 state = EXPECT_VO_START;
849 break;
850 }
851
852 case EXPECT_VO_START:
853 {
854 CHECK_LE(chunkType, 0x1f);
855 state = EXPECT_VOL_START;
856 break;
857 }
858
859 case EXPECT_VOL_START:
860 {
861 CHECK((chunkType & 0xf0) == 0x20);
862
863 CHECK(ExtractDimensionsFromVOLHeader(
864 &data[offset], chunkSize,
865 &width, &height));
866
867 state = WAIT_FOR_VOP_START;
868 break;
869 }
870
871 case WAIT_FOR_VOP_START:
872 {
873 if (chunkType == 0xb3 || chunkType == 0xb6) {
874 // group of VOP or VOP start.
875
876 mFormat = new MetaData;
877 mFormat->setCString(
878 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
879
880 mFormat->setInt32(kKeyWidth, width);
881 mFormat->setInt32(kKeyHeight, height);
882
883 LOGI("found MPEG4 video codec config (%d x %d)",
884 width, height);
885
886 sp<ABuffer> csd = new ABuffer(offset);
887 memcpy(csd->data(), data, offset);
888
889 // hexdump(csd->data(), csd->size());
890
891 sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
892 mFormat->setData(
893 kKeyESDS, kTypeESDS,
894 esds->data(), esds->size());
895
896 discard = true;
897 state = SKIP_TO_VOP_START;
898 }
899
900 break;
901 }
902
903 case SKIP_TO_VOP_START:
904 {
905 if (chunkType == 0xb6) {
906 offset += chunkSize;
907
908 sp<ABuffer> accessUnit = new ABuffer(offset);
909 memcpy(accessUnit->data(), data, offset);
910
911 memmove(data, &data[offset], size - offset);
912 size -= offset;
913 mBuffer->setRange(0, size);
914
915 int64_t timeUs = fetchTimestamp(offset);
916 CHECK_GE(timeUs, 0ll);
917
918 offset = 0;
919
920 accessUnit->meta()->setInt64("timeUs", timeUs);
921
922 LOGV("returning MPEG4 video access unit at time %lld us",
923 timeUs);
924
925 // hexdump(accessUnit->data(), accessUnit->size());
926
927 return accessUnit;
928 } else if (chunkType != 0xb3) {
929 offset += chunkSize;
930 discard = true;
931 }
932
933 break;
934 }
935
936 default:
937 TRESPASS();
938 }
939
940 if (discard) {
941 (void)fetchTimestamp(offset);
942 memmove(data, &data[offset], size - offset);
943 size -= offset;
944 offset = 0;
945 mBuffer->setRange(0, size);
946 } else {
947 offset += chunkSize;
948 }
949 }
950
951 return NULL;
952}
953
Andreas Huberb72c7e32010-10-01 10:51:41 -0700954} // namespace android