summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/mpeg2ts/ESQueue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/mpeg2ts/ESQueue.cpp')
-rw-r--r--media/libstagefright/mpeg2ts/ESQueue.cpp954
1 files changed, 0 insertions, 954 deletions
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
deleted file mode 100644
index 7fd99a8..0000000
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ /dev/null
@@ -1,954 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "ESQueue"
-#include <media/stagefright/foundation/ADebug.h>
-
-#include "ESQueue.h"
-
-#include <media/stagefright/foundation/hexdump.h>
-#include <media/stagefright/foundation/ABitReader.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MetaData.h>
-#include <media/stagefright/Utils.h>
-
-#include "include/avc_utils.h"
-
-namespace android {
-
-ElementaryStreamQueue::ElementaryStreamQueue(Mode mode)
- : mMode(mode) {
-}
-
-sp<MetaData> ElementaryStreamQueue::getFormat() {
- return mFormat;
-}
-
-void ElementaryStreamQueue::clear(bool clearFormat) {
- if (mBuffer != NULL) {
- mBuffer->setRange(0, 0);
- }
-
- mRangeInfos.clear();
-
- if (clearFormat) {
- mFormat.clear();
- }
-}
-
-static bool IsSeeminglyValidADTSHeader(const uint8_t *ptr, size_t size) {
- if (size < 3) {
- // Not enough data to verify header.
- return false;
- }
-
- if (ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
- return false;
- }
-
- unsigned layer = (ptr[1] >> 1) & 3;
-
- if (layer != 0) {
- return false;
- }
-
- unsigned ID = (ptr[1] >> 3) & 1;
- unsigned profile_ObjectType = ptr[2] >> 6;
-
- if (ID == 1 && profile_ObjectType == 3) {
- // MPEG-2 profile 3 is reserved.
- return false;
- }
-
- return true;
-}
-
-static bool IsSeeminglyValidMPEGAudioHeader(const uint8_t *ptr, size_t size) {
- if (size < 3) {
- // Not enough data to verify header.
- return false;
- }
-
- if (ptr[0] != 0xff || (ptr[1] >> 5) != 0x07) {
- return false;
- }
-
- unsigned ID = (ptr[1] >> 3) & 3;
-
- if (ID == 1) {
- return false; // reserved
- }
-
- unsigned layer = (ptr[1] >> 1) & 3;
-
- if (layer == 0) {
- return false; // reserved
- }
-
- unsigned bitrateIndex = (ptr[2] >> 4);
-
- if (bitrateIndex == 0x0f) {
- return false; // reserved
- }
-
- unsigned samplingRateIndex = (ptr[2] >> 2) & 3;
-
- if (samplingRateIndex == 3) {
- return false; // reserved
- }
-
- return true;
-}
-
-status_t ElementaryStreamQueue::appendData(
- const void *data, size_t size, int64_t timeUs) {
- if (mBuffer == NULL || mBuffer->size() == 0) {
- switch (mMode) {
- case H264:
- case MPEG_VIDEO:
- {
-#if 0
- if (size < 4 || memcmp("\x00\x00\x00\x01", data, 4)) {
- return ERROR_MALFORMED;
- }
-#else
- uint8_t *ptr = (uint8_t *)data;
-
- ssize_t startOffset = -1;
- for (size_t i = 0; i + 3 < size; ++i) {
- if (!memcmp("\x00\x00\x00\x01", &ptr[i], 4)) {
- startOffset = i;
- break;
- }
- }
-
- if (startOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (startOffset > 0) {
- ALOGI("found something resembling an H.264/MPEG syncword at "
- "offset %ld",
- startOffset);
- }
-
- data = &ptr[startOffset];
- size -= startOffset;
-#endif
- break;
- }
-
- case MPEG4_VIDEO:
- {
-#if 0
- if (size < 3 || memcmp("\x00\x00\x01", data, 3)) {
- return ERROR_MALFORMED;
- }
-#else
- uint8_t *ptr = (uint8_t *)data;
-
- ssize_t startOffset = -1;
- for (size_t i = 0; i + 2 < size; ++i) {
- if (!memcmp("\x00\x00\x01", &ptr[i], 3)) {
- startOffset = i;
- break;
- }
- }
-
- if (startOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (startOffset > 0) {
- ALOGI("found something resembling an H.264/MPEG syncword at "
- "offset %ld",
- startOffset);
- }
-
- data = &ptr[startOffset];
- size -= startOffset;
-#endif
- break;
- }
-
- case AAC:
- {
- uint8_t *ptr = (uint8_t *)data;
-
-#if 0
- if (size < 2 || ptr[0] != 0xff || (ptr[1] >> 4) != 0x0f) {
- return ERROR_MALFORMED;
- }
-#else
- ssize_t startOffset = -1;
- for (size_t i = 0; i < size; ++i) {
- if (IsSeeminglyValidADTSHeader(&ptr[i], size - i)) {
- startOffset = i;
- break;
- }
- }
-
- if (startOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (startOffset > 0) {
- ALOGI("found something resembling an AAC syncword at offset %ld",
- startOffset);
- }
-
- data = &ptr[startOffset];
- size -= startOffset;
-#endif
- break;
- }
-
- case MPEG_AUDIO:
- {
- uint8_t *ptr = (uint8_t *)data;
-
- ssize_t startOffset = -1;
- for (size_t i = 0; i < size; ++i) {
- if (IsSeeminglyValidMPEGAudioHeader(&ptr[i], size - i)) {
- startOffset = i;
- break;
- }
- }
-
- if (startOffset < 0) {
- return ERROR_MALFORMED;
- }
-
- if (startOffset > 0) {
- ALOGI("found something resembling an MPEG audio "
- "syncword at offset %ld",
- startOffset);
- }
-
- data = &ptr[startOffset];
- size -= startOffset;
- break;
- }
-
- default:
- TRESPASS();
- break;
- }
- }
-
- size_t neededSize = (mBuffer == NULL ? 0 : mBuffer->size()) + size;
- if (mBuffer == NULL || neededSize > mBuffer->capacity()) {
- neededSize = (neededSize + 65535) & ~65535;
-
- ALOGV("resizing buffer to size %d", neededSize);
-
- sp<ABuffer> buffer = new ABuffer(neededSize);
- if (mBuffer != NULL) {
- memcpy(buffer->data(), mBuffer->data(), mBuffer->size());
- buffer->setRange(0, mBuffer->size());
- } else {
- buffer->setRange(0, 0);
- }
-
- mBuffer = buffer;
- }
-
- memcpy(mBuffer->data() + mBuffer->size(), data, size);
- mBuffer->setRange(0, mBuffer->size() + size);
-
- RangeInfo info;
- info.mLength = size;
- info.mTimestampUs = timeUs;
- mRangeInfos.push_back(info);
-
-#if 0
- if (mMode == AAC) {
- ALOGI("size = %d, timeUs = %.2f secs", size, timeUs / 1E6);
- hexdump(data, size);
- }
-#endif
-
- return OK;
-}
-
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
- switch (mMode) {
- case H264:
- return dequeueAccessUnitH264();
- case AAC:
- return dequeueAccessUnitAAC();
- case MPEG_VIDEO:
- return dequeueAccessUnitMPEGVideo();
- case MPEG4_VIDEO:
- return dequeueAccessUnitMPEG4Video();
- default:
- CHECK_EQ((unsigned)mMode, (unsigned)MPEG_AUDIO);
- return dequeueAccessUnitMPEGAudio();
- }
-}
-
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() {
- Vector<size_t> ranges;
- Vector<size_t> frameOffsets;
- Vector<size_t> frameSizes;
- size_t auSize = 0;
-
- size_t offset = 0;
- while (offset + 7 <= mBuffer->size()) {
- ABitReader bits(mBuffer->data() + offset, mBuffer->size() - offset);
-
- // adts_fixed_header
-
- CHECK_EQ(bits.getBits(12), 0xfffu);
- bits.skipBits(3); // ID, layer
- bool protection_absent = bits.getBits(1) != 0;
-
- if (mFormat == NULL) {
- unsigned profile = bits.getBits(2);
- CHECK_NE(profile, 3u);
- unsigned sampling_freq_index = bits.getBits(4);
- bits.getBits(1); // private_bit
- unsigned channel_configuration = bits.getBits(3);
- CHECK_NE(channel_configuration, 0u);
- bits.skipBits(2); // original_copy, home
-
- mFormat = MakeAACCodecSpecificData(
- profile, sampling_freq_index, channel_configuration);
-
- int32_t sampleRate;
- int32_t numChannels;
- CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate));
- CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels));
-
- ALOGI("found AAC codec config (%d Hz, %d channels)",
- sampleRate, numChannels);
- } else {
- // profile_ObjectType, sampling_frequency_index, private_bits,
- // channel_configuration, original_copy, home
- bits.skipBits(12);
- }
-
- // adts_variable_header
-
- // copyright_identification_bit, copyright_identification_start
- bits.skipBits(2);
-
- unsigned aac_frame_length = bits.getBits(13);
-
- bits.skipBits(11); // adts_buffer_fullness
-
- unsigned number_of_raw_data_blocks_in_frame = bits.getBits(2);
-
- if (number_of_raw_data_blocks_in_frame != 0) {
- // To be implemented.
- TRESPASS();
- }
-
- if (offset + aac_frame_length > mBuffer->size()) {
- break;
- }
-
- size_t headerSize = protection_absent ? 7 : 9;
-
- ranges.push(aac_frame_length);
- frameOffsets.push(offset + headerSize);
- frameSizes.push(aac_frame_length - headerSize);
- auSize += aac_frame_length - headerSize;
-
- offset += aac_frame_length;
- }
-
- if (offset == 0) {
- return NULL;
- }
-
- int64_t timeUs = -1;
-
- for (size_t i = 0; i < ranges.size(); ++i) {
- int64_t tmpUs = fetchTimestamp(ranges.itemAt(i));
-
- if (i == 0) {
- timeUs = tmpUs;
- }
- }
-
- sp<ABuffer> accessUnit = new ABuffer(auSize);
- size_t dstOffset = 0;
- for (size_t i = 0; i < frameOffsets.size(); ++i) {
- size_t frameOffset = frameOffsets.itemAt(i);
-
- memcpy(accessUnit->data() + dstOffset,
- mBuffer->data() + frameOffset,
- frameSizes.itemAt(i));
-
- dstOffset += frameSizes.itemAt(i);
- }
-
- memmove(mBuffer->data(), mBuffer->data() + offset,
- mBuffer->size() - offset);
- mBuffer->setRange(0, mBuffer->size() - offset);
-
- if (timeUs >= 0) {
- accessUnit->meta()->setInt64("timeUs", timeUs);
- } else {
- ALOGW("no time for AAC access unit");
- }
-
- return accessUnit;
-}
-
-int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) {
- int64_t timeUs = -1;
- bool first = true;
-
- while (size > 0) {
- CHECK(!mRangeInfos.empty());
-
- RangeInfo *info = &*mRangeInfos.begin();
-
- if (first) {
- timeUs = info->mTimestampUs;
- first = false;
- }
-
- if (info->mLength > size) {
- info->mLength -= size;
-
- if (first) {
- info->mTimestampUs = -1;
- }
-
- size = 0;
- } else {
- size -= info->mLength;
-
- mRangeInfos.erase(mRangeInfos.begin());
- info = NULL;
- }
- }
-
- if (timeUs == 0ll) {
- ALOGV("Returning 0 timestamp");
- }
-
- return timeUs;
-}
-
-struct NALPosition {
- size_t nalOffset;
- size_t nalSize;
-};
-
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
- const uint8_t *data = mBuffer->data();
- size_t size = mBuffer->size();
-
- Vector<NALPosition> nals;
-
- size_t totalSize = 0;
-
- status_t err;
- const uint8_t *nalStart;
- size_t nalSize;
- bool foundSlice = false;
- while ((err = getNextNALUnit(&data, &size, &nalStart, &nalSize)) == OK) {
- CHECK_GT(nalSize, 0u);
-
- unsigned nalType = nalStart[0] & 0x1f;
- bool flush = false;
-
- if (nalType == 1 || nalType == 5) {
- if (foundSlice) {
- ABitReader br(nalStart + 1, nalSize);
- unsigned first_mb_in_slice = parseUE(&br);
-
- if (first_mb_in_slice == 0) {
- // This slice starts a new frame.
-
- flush = true;
- }
- }
-
- foundSlice = true;
- } else if ((nalType == 9 || nalType == 7) && foundSlice) {
- // Access unit delimiter and SPS will be associated with the
- // next frame.
-
- flush = true;
- }
-
- if (flush) {
- // The access unit will contain all nal units up to, but excluding
- // the current one, separated by 0x00 0x00 0x00 0x01 startcodes.
-
- size_t auSize = 4 * nals.size() + totalSize;
- sp<ABuffer> accessUnit = new ABuffer(auSize);
-
-#if !LOG_NDEBUG
- AString out;
-#endif
-
- size_t dstOffset = 0;
- for (size_t i = 0; i < nals.size(); ++i) {
- const NALPosition &pos = nals.itemAt(i);
-
- unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f;
-
-#if !LOG_NDEBUG
- char tmp[128];
- sprintf(tmp, "0x%02x", nalType);
- if (i > 0) {
- out.append(", ");
- }
- out.append(tmp);
-#endif
-
- memcpy(accessUnit->data() + dstOffset, "\x00\x00\x00\x01", 4);
-
- memcpy(accessUnit->data() + dstOffset + 4,
- mBuffer->data() + pos.nalOffset,
- pos.nalSize);
-
- dstOffset += pos.nalSize + 4;
- }
-
- ALOGV("accessUnit contains nal types %s", out.c_str());
-
- const NALPosition &pos = nals.itemAt(nals.size() - 1);
- size_t nextScan = pos.nalOffset + pos.nalSize;
-
- memmove(mBuffer->data(),
- mBuffer->data() + nextScan,
- mBuffer->size() - nextScan);
-
- mBuffer->setRange(0, mBuffer->size() - nextScan);
-
- int64_t timeUs = fetchTimestamp(nextScan);
- CHECK_GE(timeUs, 0ll);
-
- accessUnit->meta()->setInt64("timeUs", timeUs);
-
- if (mFormat == NULL) {
- mFormat = MakeAVCCodecSpecificData(accessUnit);
- }
-
- return accessUnit;
- }
-
- NALPosition pos;
- pos.nalOffset = nalStart - mBuffer->data();
- pos.nalSize = nalSize;
-
- nals.push(pos);
-
- totalSize += nalSize;
- }
- CHECK_EQ(err, (status_t)-EAGAIN);
-
- return NULL;
-}
-
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() {
- const uint8_t *data = mBuffer->data();
- size_t size = mBuffer->size();
-
- if (size < 4) {
- return NULL;
- }
-
- uint32_t header = U32_AT(data);
-
- size_t frameSize;
- int samplingRate, numChannels, bitrate, numSamples;
- CHECK(GetMPEGAudioFrameSize(
- header, &frameSize, &samplingRate, &numChannels,
- &bitrate, &numSamples));
-
- if (size < frameSize) {
- return NULL;
- }
-
- unsigned layer = 4 - ((header >> 17) & 3);
-
- sp<ABuffer> accessUnit = new ABuffer(frameSize);
- memcpy(accessUnit->data(), data, frameSize);
-
- memmove(mBuffer->data(),
- mBuffer->data() + frameSize,
- mBuffer->size() - frameSize);
-
- mBuffer->setRange(0, mBuffer->size() - frameSize);
-
- int64_t timeUs = fetchTimestamp(frameSize);
- CHECK_GE(timeUs, 0ll);
-
- accessUnit->meta()->setInt64("timeUs", timeUs);
-
- if (mFormat == NULL) {
- mFormat = new MetaData;
-
- switch (layer) {
- case 1:
- mFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I);
- break;
- case 2:
- mFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II);
- break;
- case 3:
- mFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
- break;
- default:
- TRESPASS();
- }
-
- mFormat->setInt32(kKeySampleRate, samplingRate);
- mFormat->setInt32(kKeyChannelCount, numChannels);
- }
-
- return accessUnit;
-}
-
-static void EncodeSize14(uint8_t **_ptr, size_t size) {
- CHECK_LE(size, 0x3fff);
-
- uint8_t *ptr = *_ptr;
-
- *ptr++ = 0x80 | (size >> 7);
- *ptr++ = size & 0x7f;
-
- *_ptr = ptr;
-}
-
-static sp<ABuffer> MakeMPEGVideoESDS(const sp<ABuffer> &csd) {
- sp<ABuffer> esds = new ABuffer(csd->size() + 25);
-
- uint8_t *ptr = esds->data();
- *ptr++ = 0x03;
- EncodeSize14(&ptr, 22 + csd->size());
-
- *ptr++ = 0x00; // ES_ID
- *ptr++ = 0x00;
-
- *ptr++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
-
- *ptr++ = 0x04;
- EncodeSize14(&ptr, 16 + csd->size());
-
- *ptr++ = 0x40; // Audio ISO/IEC 14496-3
-
- for (size_t i = 0; i < 12; ++i) {
- *ptr++ = 0x00;
- }
-
- *ptr++ = 0x05;
- EncodeSize14(&ptr, csd->size());
-
- memcpy(ptr, csd->data(), csd->size());
-
- return esds;
-}
-
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
- const uint8_t *data = mBuffer->data();
- size_t size = mBuffer->size();
-
- bool sawPictureStart = false;
- int pprevStartCode = -1;
- int prevStartCode = -1;
- int currentStartCode = -1;
-
- size_t offset = 0;
- while (offset + 3 < size) {
- if (memcmp(&data[offset], "\x00\x00\x01", 3)) {
- ++offset;
- continue;
- }
-
- pprevStartCode = prevStartCode;
- prevStartCode = currentStartCode;
- currentStartCode = data[offset + 3];
-
- if (currentStartCode == 0xb3 && mFormat == NULL) {
- memmove(mBuffer->data(), mBuffer->data() + offset, size - offset);
- size -= offset;
- (void)fetchTimestamp(offset);
- offset = 0;
- mBuffer->setRange(0, size);
- }
-
- if ((prevStartCode == 0xb3 && currentStartCode != 0xb5)
- || (pprevStartCode == 0xb3 && prevStartCode == 0xb5)) {
- // seqHeader without/with extension
-
- if (mFormat == NULL) {
- CHECK_GE(size, 7u);
-
- unsigned width =
- (data[4] << 4) | data[5] >> 4;
-
- unsigned height =
- ((data[5] & 0x0f) << 8) | data[6];
-
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
-
- ALOGI("found MPEG2 video codec config (%d x %d)", width, height);
-
- sp<ABuffer> csd = new ABuffer(offset);
- memcpy(csd->data(), data, offset);
-
- memmove(mBuffer->data(),
- mBuffer->data() + offset,
- mBuffer->size() - offset);
-
- mBuffer->setRange(0, mBuffer->size() - offset);
- size -= offset;
- (void)fetchTimestamp(offset);
- offset = 0;
-
- // hexdump(csd->data(), csd->size());
-
- sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
- mFormat->setData(
- kKeyESDS, kTypeESDS, esds->data(), esds->size());
-
- return NULL;
- }
- }
-
- if (mFormat != NULL && currentStartCode == 0x00) {
- // Picture start
-
- if (!sawPictureStart) {
- sawPictureStart = true;
- } else {
- sp<ABuffer> accessUnit = new ABuffer(offset);
- memcpy(accessUnit->data(), data, offset);
-
- memmove(mBuffer->data(),
- mBuffer->data() + offset,
- mBuffer->size() - offset);
-
- mBuffer->setRange(0, mBuffer->size() - offset);
-
- int64_t timeUs = fetchTimestamp(offset);
- CHECK_GE(timeUs, 0ll);
-
- offset = 0;
-
- accessUnit->meta()->setInt64("timeUs", timeUs);
-
- ALOGV("returning MPEG video access unit at time %lld us",
- timeUs);
-
- // hexdump(accessUnit->data(), accessUnit->size());
-
- return accessUnit;
- }
- }
-
- ++offset;
- }
-
- return NULL;
-}
-
-static ssize_t getNextChunkSize(
- const uint8_t *data, size_t size) {
- static const char kStartCode[] = "\x00\x00\x01";
-
- if (size < 3) {
- return -EAGAIN;
- }
-
- if (memcmp(kStartCode, data, 3)) {
- TRESPASS();
- }
-
- size_t offset = 3;
- while (offset + 2 < size) {
- if (!memcmp(&data[offset], kStartCode, 3)) {
- return offset;
- }
-
- ++offset;
- }
-
- return -EAGAIN;
-}
-
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() {
- uint8_t *data = mBuffer->data();
- size_t size = mBuffer->size();
-
- enum {
- SKIP_TO_VISUAL_OBJECT_SEQ_START,
- EXPECT_VISUAL_OBJECT_START,
- EXPECT_VO_START,
- EXPECT_VOL_START,
- WAIT_FOR_VOP_START,
- SKIP_TO_VOP_START,
-
- } state;
-
- if (mFormat == NULL) {
- state = SKIP_TO_VISUAL_OBJECT_SEQ_START;
- } else {
- state = SKIP_TO_VOP_START;
- }
-
- int32_t width = -1, height = -1;
-
- size_t offset = 0;
- ssize_t chunkSize;
- while ((chunkSize = getNextChunkSize(
- &data[offset], size - offset)) > 0) {
- bool discard = false;
-
- unsigned chunkType = data[offset + 3];
-
- switch (state) {
- case SKIP_TO_VISUAL_OBJECT_SEQ_START:
- {
- if (chunkType == 0xb0) {
- // Discard anything before this marker.
-
- state = EXPECT_VISUAL_OBJECT_START;
- } else {
- discard = true;
- }
- break;
- }
-
- case EXPECT_VISUAL_OBJECT_START:
- {
- CHECK_EQ(chunkType, 0xb5);
- state = EXPECT_VO_START;
- break;
- }
-
- case EXPECT_VO_START:
- {
- CHECK_LE(chunkType, 0x1f);
- state = EXPECT_VOL_START;
- break;
- }
-
- case EXPECT_VOL_START:
- {
- CHECK((chunkType & 0xf0) == 0x20);
-
- CHECK(ExtractDimensionsFromVOLHeader(
- &data[offset], chunkSize,
- &width, &height));
-
- state = WAIT_FOR_VOP_START;
- break;
- }
-
- case WAIT_FOR_VOP_START:
- {
- if (chunkType == 0xb3 || chunkType == 0xb6) {
- // group of VOP or VOP start.
-
- mFormat = new MetaData;
- mFormat->setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
-
- mFormat->setInt32(kKeyWidth, width);
- mFormat->setInt32(kKeyHeight, height);
-
- ALOGI("found MPEG4 video codec config (%d x %d)",
- width, height);
-
- sp<ABuffer> csd = new ABuffer(offset);
- memcpy(csd->data(), data, offset);
-
- // hexdump(csd->data(), csd->size());
-
- sp<ABuffer> esds = MakeMPEGVideoESDS(csd);
- mFormat->setData(
- kKeyESDS, kTypeESDS,
- esds->data(), esds->size());
-
- discard = true;
- state = SKIP_TO_VOP_START;
- }
-
- break;
- }
-
- case SKIP_TO_VOP_START:
- {
- if (chunkType == 0xb6) {
- offset += chunkSize;
-
- sp<ABuffer> accessUnit = new ABuffer(offset);
- memcpy(accessUnit->data(), data, offset);
-
- memmove(data, &data[offset], size - offset);
- size -= offset;
- mBuffer->setRange(0, size);
-
- int64_t timeUs = fetchTimestamp(offset);
- CHECK_GE(timeUs, 0ll);
-
- offset = 0;
-
- accessUnit->meta()->setInt64("timeUs", timeUs);
-
- ALOGV("returning MPEG4 video access unit at time %lld us",
- timeUs);
-
- // hexdump(accessUnit->data(), accessUnit->size());
-
- return accessUnit;
- } else if (chunkType != 0xb3) {
- offset += chunkSize;
- discard = true;
- }
-
- break;
- }
-
- default:
- TRESPASS();
- }
-
- if (discard) {
- (void)fetchTimestamp(offset);
- memmove(data, &data[offset], size - offset);
- size -= offset;
- offset = 0;
- mBuffer->setRange(0, size);
- } else {
- offset += chunkSize;
- }
- }
-
- return NULL;
-}
-
-} // namespace android