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 34 namespace android { 35 36 ElementaryStreamQueue::ElementaryStreamQueue(Mode mode) 37 : mMode(mode) { 38 } 39 40 sp<MetaData> ElementaryStreamQueue::getFormat() { 41 return mFormat; 42 } 43 44 void 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 56 static 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 83 static 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 120 status_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 291 sp<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 307 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { 308 int64_t timeUs; 309 310 size_t offset = 0; 311 while (offset + 7 <= mBuffer->size()) { 312 ABitReader bits(mBuffer->data() + offset, mBuffer->size() - offset); 313 314 // adts_fixed_header 315 316 CHECK_EQ(bits.getBits(12), 0xfffu); 317 bits.skipBits(3); // ID, layer 318 bool protection_absent = bits.getBits(1) != 0; 319 320 if (mFormat == NULL) { 321 unsigned profile = bits.getBits(2); 322 CHECK_NE(profile, 3u); 323 unsigned sampling_freq_index = bits.getBits(4); 324 bits.getBits(1); // private_bit 325 unsigned channel_configuration = bits.getBits(3); 326 CHECK_NE(channel_configuration, 0u); 327 bits.skipBits(2); // original_copy, home 328 329 mFormat = MakeAACCodecSpecificData( 330 profile, sampling_freq_index, channel_configuration); 331 332 mFormat->setInt32(kKeyIsADTS, true); 333 334 int32_t sampleRate; 335 int32_t numChannels; 336 CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate)); 337 CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels)); 338 339 ALOGI("found AAC codec config (%d Hz, %d channels)", 340 sampleRate, numChannels); 341 } else { 342 // profile_ObjectType, sampling_frequency_index, private_bits, 343 // channel_configuration, original_copy, home 344 bits.skipBits(12); 345 } 346 347 // adts_variable_header 348 349 // copyright_identification_bit, copyright_identification_start 350 bits.skipBits(2); 351 352 unsigned aac_frame_length = bits.getBits(13); 353 354 bits.skipBits(11); // adts_buffer_fullness 355 356 unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2); 357 358 if (number_of_raw_data_blocks_in_frame != 0) { 359 // To be implemented. 360 TRESPASS(); 361 } 362 363 if (offset + aac_frame_length > mBuffer->size()) { 364 break; 365 } 366 367 size_t headerSize = protection_absent ? 7 : 9; 368 369 int64_t tmpUs = fetchTimestamp(aac_frame_length); 370 CHECK_GE(tmpUs, 0ll); 371 372 if (offset == 0) { 373 timeUs = tmpUs; 374 } 375 376 offset += aac_frame_length; 377 } 378 379 if (offset == 0) { 380 return NULL; 381 } 382 383 sp<ABuffer> accessUnit = new ABuffer(offset); 384 memcpy(accessUnit->data(), mBuffer->data(), offset); 385 386 memmove(mBuffer->data(), mBuffer->data() + offset, 387 mBuffer->size() - offset); 388 mBuffer->setRange(0, mBuffer->size() - offset); 389 390 accessUnit->meta()->setInt64("timeUs", timeUs); 391 392 return accessUnit; 393 } 394 395 int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) { 396 int64_t timeUs = -1; 397 bool first = true; 398 399 while (size > 0) { 400 CHECK(!mRangeInfos.empty()); 401 402 RangeInfo *info = &*mRangeInfos.begin(); 403 404 if (first) { 405 timeUs = info->mTimestampUs; 406 first = false; 407 } 408 409 if (info->mLength > size) { 410 info->mLength -= size; 411 412 if (first) { 413 info->mTimestampUs = -1; 414 } 415 416 size = 0; 417 } else { 418 size -= info->mLength; 419 420 mRangeInfos.erase(mRangeInfos.begin()); 421 info = NULL; 422 } 423 } 424 425 if (timeUs == 0ll) { 426 ALOGV("Returning 0 timestamp"); 427 } 428 429 return timeUs; 430 } 431 432 struct NALPosition { 433 size_t nalOffset; 434 size_t nalSize; 435 }; 436 437 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { 438 const uint8_t *data = mBuffer->data(); 439 size_t size = mBuffer->size(); 440 441 Vector<NALPosition> nals; 442 443 size_t totalSize = 0; 444 445 status_t err; 446 const uint8_t *nalStart; 447 size_t nalSize; 448 bool foundSlice = false; 449 while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) { 450 CHECK_GT(nalSize, 0u); 451 452 unsigned nalType = nalStart[0] & 0x1f; 453 bool flush = false; 454 455 if (nalType == 1 || nalType == 5) { 456 if (foundSlice) { 457 ABitReader br(nalStart + 1, nalSize); 458 unsigned first_mb_in_slice = parseUE(&br); 459 460 if (first_mb_in_slice == 0) { 461 // This slice starts a new frame. 462 463 flush = true; 464 } 465 } 466 467 foundSlice = true; 468 } else if ((nalType == 9 || nalType == 7) && foundSlice) { 469 // Access unit delimiter and SPS will be associated with the 470 // next frame. 471 472 flush = true; 473 } 474 475 if (flush) { 476 // The access unit will contain all nal units up to, but excluding 477 // the current one, separated by 0x00 0x00 0x00 0x01 startcodes. 478 479 size_t auSize = 4 * nals.size() + totalSize; 480 sp<ABuffer> accessUnit = new ABuffer(auSize); 481 482 #if !LOG_NDEBUG 483 AString out; 484 #endif 485 486 size_t dstOffset = 0; 487 for (size_t i = 0; i < nals.size(); ++i) { 488 const NALPosition &pos = nals.itemAt(i); 489 490 unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f; 491 492 #if !LOG_NDEBUG 493 char tmp[128]; 494 sprintf(tmp, "0x%02x", nalType); 495 if (i > 0) { 496 out.append(", "); 497 } 498 out.append(tmp); 499 #endif 500 501 memcpy(accessUnit->data() + dstOffset, "\x00\x00\x00\x01", 4); 502 503 memcpy(accessUnit->data() + dstOffset + 4, 504 mBuffer->data() + pos.nalOffset, 505 pos.nalSize); 506 507 dstOffset += pos.nalSize + 4; 508 } 509 510 ALOGV("accessUnit contains nal types %s", out.c_str()); 511 512 const NALPosition &pos = nals.itemAt(nals.size() - 1); 513 size_t nextScan = pos.nalOffset + pos.nalSize; 514 515 memmove(mBuffer->data(), 516 mBuffer->data() + nextScan, 517 mBuffer->size() - nextScan); 518 519 mBuffer->setRange(0, mBuffer->size() - nextScan); 520 521 int64_t timeUs = fetchTimestamp(nextScan); 522 CHECK_GE(timeUs, 0ll); 523 524 accessUnit->meta()->setInt64("timeUs", timeUs); 525 526 if (mFormat == NULL) { 527 mFormat = MakeAVCCodecSpecificData(accessUnit); 528 } 529 530 return accessUnit; 531 } 532 533 NALPosition pos; 534 pos.nalOffset = nalStart - mBuffer->data(); 535 pos.nalSize = nalSize; 536 537 nals.push(pos); 538 539 totalSize += nalSize; 540 } 541 CHECK_EQ(err, (status_t)-EAGAIN); 542 543 return NULL; 544 } 545 546 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { 547 const uint8_t *data = mBuffer->data(); 548 size_t size = mBuffer->size(); 549 550 if (size < 4) { 551 return NULL; 552 } 553 554 uint32_t header = U32_AT(data); 555 556 size_t frameSize; 557 int samplingRate, numChannels, bitrate, numSamples; 558 CHECK(GetMPEGAudioFrameSize( 559 header, &frameSize, &samplingRate, &numChannels, 560 &bitrate, &numSamples)); 561 562 if (size < frameSize) { 563 return NULL; 564 } 565 566 unsigned layer = 4 - ((header >> 17) & 3); 567 568 sp<ABuffer> accessUnit = new ABuffer(frameSize); 569 memcpy(accessUnit->data(), data, frameSize); 570 571 memmove(mBuffer->data(), 572 mBuffer->data() + frameSize, 573 mBuffer->size() - frameSize); 574 575 mBuffer->setRange(0, mBuffer->size() - frameSize); 576 577 int64_t timeUs = fetchTimestamp(frameSize); 578 CHECK_GE(timeUs, 0ll); 579 580 accessUnit->meta()->setInt64("timeUs", timeUs); 581 582 if (mFormat == NULL) { 583 mFormat = new MetaData; 584 585 switch (layer) { 586 case 1: 587 mFormat->setCString( 588 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I); 589 break; 590 case 2: 591 mFormat->setCString( 592 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II); 593 break; 594 case 3: 595 mFormat->setCString( 596 kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); 597 break; 598 default: 599 TRESPASS(); 600 } 601 602 mFormat->setInt32(kKeySampleRate, samplingRate); 603 mFormat->setInt32(kKeyChannelCount, numChannels); 604 } 605 606 return accessUnit; 607 } 608 609 static void EncodeSize14(uint8_t **_ptr, size_t size) { 610 CHECK_LE(size, 0x3fff); 611 612 uint8_t *ptr = *_ptr; 613 614 *ptr++ = 0x80 | (size >> 7); 615 *ptr++ = size & 0x7f; 616 617 *_ptr = ptr; 618 } 619 620 static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) { 621 sp<ABuffer> esds = new ABuffer(csd->size() + 25); 622 623 uint8_t *ptr = esds->data(); 624 *ptr++ = 0x03; 625 EncodeSize14(&ptr, 22 + csd->size()); 626 627 *ptr++ = 0x00; // ES_ID 628 *ptr++ = 0x00; 629 630 *ptr++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag 631 632 *ptr++ = 0x04; 633 EncodeSize14(&ptr, 16 + csd->size()); 634 635 *ptr++ = 0x40; // Audio ISO/IEC 14496-3 636 637 for (size_t i = 0; i < 12; ++i) { 638 *ptr++ = 0x00; 639 } 640 641 *ptr++ = 0x05; 642 EncodeSize14(&ptr, csd->size()); 643 644 memcpy(ptr, csd->data(), csd->size()); 645 646 return esds; 647 } 648 649 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { 650 const uint8_t *data = mBuffer->data(); 651 size_t size = mBuffer->size(); 652 653 bool sawPictureStart = false; 654 int pprevStartCode = -1; 655 int prevStartCode = -1; 656 int currentStartCode = -1; 657 658 size_t offset = 0; 659 while (offset + 3 < size) { 660 if (memcmp(&data[offset], "\x00\x00\x01", 3)) { 661 ++offset; 662 continue; 663 } 664 665 pprevStartCode = prevStartCode; 666 prevStartCode = currentStartCode; 667 currentStartCode = data[offset + 3]; 668 669 if (currentStartCode == 0xb3 && mFormat == NULL) { 670 memmove(mBuffer->data(), mBuffer->data() + offset, size - offset); 671 size -= offset; 672 (void)fetchTimestamp(offset); 673 offset = 0; 674 mBuffer->setRange(0, size); 675 } 676 677 if ((prevStartCode == 0xb3 && currentStartCode != 0xb5) 678 || (pprevStartCode == 0xb3 && prevStartCode == 0xb5)) { 679 // seqHeader without/with extension 680 681 if (mFormat == NULL) { 682 CHECK_GE(size, 7u); 683 684 unsigned width = 685 (data[4] << 4) | data[5] >> 4; 686 687 unsigned height = 688 ((data[5] & 0x0f) << 8) | data[6]; 689 690 mFormat = new MetaData; 691 mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2); 692 mFormat->setInt32(kKeyWidth, width); 693 mFormat->setInt32(kKeyHeight, height); 694 695 ALOGI("found MPEG2 video codec config (%d x %d)", width, height); 696 697 sp<ABuffer> csd = new ABuffer(offset); 698 memcpy(csd->data(), data, offset); 699 700 memmove(mBuffer->data(), 701 mBuffer->data() + offset, 702 mBuffer->size() - offset); 703 704 mBuffer->setRange(0, mBuffer->size() - offset); 705 size -= offset; 706 (void)fetchTimestamp(offset); 707 offset = 0; 708 709 // hexdump(csd->data(), csd->size()); 710 711 sp<ABuffer> esds = MakeMPEGVideoESDS(csd); 712 mFormat->setData( 713 kKeyESDS, kTypeESDS, esds->data(), esds->size()); 714 715 return NULL; 716 } 717 } 718 719 if (mFormat != NULL && currentStartCode == 0x00) { 720 // Picture start 721 722 if (!sawPictureStart) { 723 sawPictureStart = true; 724 } else { 725 sp<ABuffer> accessUnit = new ABuffer(offset); 726 memcpy(accessUnit->data(), data, offset); 727 728 memmove(mBuffer->data(), 729 mBuffer->data() + offset, 730 mBuffer->size() - offset); 731 732 mBuffer->setRange(0, mBuffer->size() - offset); 733 734 int64_t timeUs = fetchTimestamp(offset); 735 CHECK_GE(timeUs, 0ll); 736 737 offset = 0; 738 739 accessUnit->meta()->setInt64("timeUs", timeUs); 740 741 ALOGV("returning MPEG video access unit at time %lld us", 742 timeUs); 743 744 // hexdump(accessUnit->data(), accessUnit->size()); 745 746 return accessUnit; 747 } 748 } 749 750 ++offset; 751 } 752 753 return NULL; 754 } 755 756 static ssize_t getNextChunkSize( 757 const uint8_t *data, size_t size) { 758 static const char kStartCode[] = "\x00\x00\x01"; 759 760 if (size < 3) { 761 return -EAGAIN; 762 } 763 764 if (memcmp(kStartCode, data, 3)) { 765 TRESPASS(); 766 } 767 768 size_t offset = 3; 769 while (offset + 2 < size) { 770 if (!memcmp(&data[offset], kStartCode, 3)) { 771 return offset; 772 } 773 774 ++offset; 775 } 776 777 return -EAGAIN; 778 } 779 780 sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { 781 uint8_t *data = mBuffer->data(); 782 size_t size = mBuffer->size(); 783 784 enum { 785 SKIP_TO_VISUAL_OBJECT_SEQ_START, 786 EXPECT_VISUAL_OBJECT_START, 787 EXPECT_VO_START, 788 EXPECT_VOL_START, 789 WAIT_FOR_VOP_START, 790 SKIP_TO_VOP_START, 791 792 } state; 793 794 if (mFormat == NULL) { 795 state = SKIP_TO_VISUAL_OBJECT_SEQ_START; 796 } else { 797 state = SKIP_TO_VOP_START; 798 } 799 800 int32_t width = -1, height = -1; 801 802 size_t offset = 0; 803 ssize_t chunkSize; 804 while ((chunkSize = getNextChunkSize( 805 &data[offset], size - offset)) > 0) { 806 bool discard = false; 807 808 unsigned chunkType = data[offset + 3]; 809 810 switch (state) { 811 case SKIP_TO_VISUAL_OBJECT_SEQ_START: 812 { 813 if (chunkType == 0xb0) { 814 // Discard anything before this marker. 815 816 state = EXPECT_VISUAL_OBJECT_START; 817 } else { 818 discard = true; 819 } 820 break; 821 } 822 823 case EXPECT_VISUAL_OBJECT_START: 824 { 825 CHECK_EQ(chunkType, 0xb5); 826 state = EXPECT_VO_START; 827 break; 828 } 829 830 case EXPECT_VO_START: 831 { 832 CHECK_LE(chunkType, 0x1f); 833 state = EXPECT_VOL_START; 834 break; 835 } 836 837 case EXPECT_VOL_START: 838 { 839 CHECK((chunkType & 0xf0) == 0x20); 840 841 CHECK(ExtractDimensionsFromVOLHeader( 842 &data[offset], chunkSize, 843 &width, &height)); 844 845 state = WAIT_FOR_VOP_START; 846 break; 847 } 848 849 case WAIT_FOR_VOP_START: 850 { 851 if (chunkType == 0xb3 || chunkType == 0xb6) { 852 // group of VOP or VOP start. 853 854 mFormat = new MetaData; 855 mFormat->setCString( 856 kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4); 857 858 mFormat->setInt32(kKeyWidth, width); 859 mFormat->setInt32(kKeyHeight, height); 860 861 ALOGI("found MPEG4 video codec config (%d x %d)", 862 width, height); 863 864 sp<ABuffer> csd = new ABuffer(offset); 865 memcpy(csd->data(), data, offset); 866 867 // hexdump(csd->data(), csd->size()); 868 869 sp<ABuffer> esds = MakeMPEGVideoESDS(csd); 870 mFormat->setData( 871 kKeyESDS, kTypeESDS, 872 esds->data(), esds->size()); 873 874 discard = true; 875 state = SKIP_TO_VOP_START; 876 } 877 878 break; 879 } 880 881 case SKIP_TO_VOP_START: 882 { 883 if (chunkType == 0xb6) { 884 offset += chunkSize; 885 886 sp<ABuffer> accessUnit = new ABuffer(offset); 887 memcpy(accessUnit->data(), data, offset); 888 889 memmove(data, &data[offset], size - offset); 890 size -= offset; 891 mBuffer->setRange(0, size); 892 893 int64_t timeUs = fetchTimestamp(offset); 894 CHECK_GE(timeUs, 0ll); 895 896 offset = 0; 897 898 accessUnit->meta()->setInt64("timeUs", timeUs); 899 900 ALOGV("returning MPEG4 video access unit at time %lld us", 901 timeUs); 902 903 // hexdump(accessUnit->data(), accessUnit->size()); 904 905 return accessUnit; 906 } else if (chunkType != 0xb3) { 907 offset += chunkSize; 908 discard = true; 909 } 910 911 break; 912 } 913 914 default: 915 TRESPASS(); 916 } 917 918 if (discard) { 919 (void)fetchTimestamp(offset); 920 memmove(data, &data[offset], size - offset); 921 size -= offset; 922 offset = 0; 923 mBuffer->setRange(0, size); 924 } else { 925 offset += chunkSize; 926 } 927 } 928 929 return NULL; 930 } 931 932 } // namespace android 933