ESQueue.cpp revision 5ff1dd576bb93c45b44088a51544a18fc43ebf58
1/* 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> 30#include <media/stagefright/Utils.h> 31 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 44void ElementaryStreamQueue::clear(bool clearFormat) { 45 if (mBuffer != NULL) { 46 mBuffer->setRange(0, 0); 47 } 48 49 mRangeInfos.clear(); 50 51 if (clearFormat) { 52 mFormat.clear(); 53 } 54} 55 56static 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 83static 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 120status_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: 125 case MPEG_VIDEO: 126 { 127#if 0 128 if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) { 129 return ERROR_MALFORMED; 130 } 131#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) { 147 ALOGI("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 ALOGI("found something resembling an H.264/MPEG syncword at " 181 "offset %ld", 182 startOffset); 183 } 184 185 data = &ptr[startOffset]; 186 size -= startOffset; 187#endif 188 break; 189 } 190 191 case AAC: 192 { 193 uint8_t *ptr = (uint8_t *)data; 194 195#if 0 196 if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) { 197 return ERROR_MALFORMED; 198 } 199#else 200 ssize_t startOffset = -1; 201 for (size_t i = 0; i < size; ++i) { 202 if (IsSeeminglyValidADTSHeader(&ptr[i], size - i)) { 203 startOffset = i; 204 break; 205 } 206 } 207 208 if (startOffset < 0) { 209 return ERROR_MALFORMED; 210 } 211 212 if (startOffset > 0) { 213 ALOGI("found something resembling an AAC syncword at offset %ld", 214 startOffset); 215 } 216 217 data = &ptr[startOffset]; 218 size -= startOffset; 219#endif 220 break; 221 } 222 223 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 ALOGI("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 250 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 260 ALOGV("resizing buffer to size %d", neededSize); 261 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 276 RangeInfo info; 277 info.mLength = size; 278 info.mTimestampUs = timeUs; 279 mRangeInfos.push_back(info); 280 281#if 0 282 if (mMode == AAC) { 283 ALOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6); 284 hexdump(data, size); 285 } 286#endif 287 288 return OK; 289} 290 291sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() { 292 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(); 304 } 305} 306 307sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { 308 Vector<size_t> ranges; 309 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); 334 335 int32_t sampleRate; 336 int32_t numChannels; 337 CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate)); 338 CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels)); 339 340 ALOGI("found AAC codec config (%d Hz, %d channels)", 341 sampleRate, numChannels); 342 } 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 370 ranges.push(aac_frame_length); 371 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 382 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 392 sp<ABuffer> accessUnit = new ABuffer(auSize); 393 size_t dstOffset = 0; 394 for (size_t i = 0; i < frameOffsets.size(); ++i) { 395 size_t frameOffset = frameOffsets.itemAt(i); 396 397 memcpy(accessUnit->data() + dstOffset, 398 mBuffer->data() + frameOffset, 399 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 408 if (timeUs >= 0) { 409 accessUnit->meta()->setInt64("timeUs", timeUs); 410 } else { 411 ALOGW("no time for AAC access unit"); 412 } 413 414 return accessUnit; 415} 416 417int64_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 447 if (timeUs == 0ll) { 448 ALOGV("Returning 0 timestamp"); 449 } 450 451 return timeUs; 452} 453 454struct 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 ALOGV("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 543 int64_t timeUs = fetchTimestamp(nextScan); 544 CHECK_GE(timeUs, 0ll); 545 546 accessUnit->meta()->setInt64("timeUs", timeUs); 547 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 568sp<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 588 unsigned layer = 4 - ((header >> 17) & 3); 589 590 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; 606 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 624 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 ALOGI("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 ALOGV("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 ALOGI("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 ALOGV("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 954} // namespace android 955