namespace android { // static const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); // static const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); // static const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); // static const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); //////////////////////////////////////////////////////////////////////////////// struct SampleTable::CompositionDeltaLookup { CompositionDeltaLookup(); void setEntries( const uint32_t *deltaEntries, size_t numDeltaEntries); uint32_t getCompositionTimeOffset(uint32_t sampleIndex); private: Mutex mLock; const uint32_t *mDeltaEntries; size_t mNumDeltaEntries; size_t mCurrentDeltaEntry; size_t mCurrentEntrySampleIndex; DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup); }; SampleTable::CompositionDeltaLookup::CompositionDeltaLookup() : mDeltaEntries(NULL), mNumDeltaEntries(0), mCurrentDeltaEntry(0), mCurrentEntrySampleIndex(0) { } void SampleTable::CompositionDeltaLookup::setEntries( const uint32_t *deltaEntries, size_t numDeltaEntries) { Mutex::Autolock autolock(mLock); mDeltaEntries = deltaEntries; mNumDeltaEntries = numDeltaEntries; mCurrentDeltaEntry = 0; mCurrentEntrySampleIndex = 0; } uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset( uint32_t sampleIndex) { Mutex::Autolock autolock(mLock); if (mDeltaEntries == NULL) { return 0; } if (sampleIndex < mCurrentEntrySampleIndex) { mCurrentDeltaEntry = 0; mCurrentEntrySampleIndex = 0; } while (mCurrentDeltaEntry < mNumDeltaEntries) { uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry]; if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) { return mDeltaEntries[2 * mCurrentDeltaEntry + 1]; } mCurrentEntrySampleIndex += sampleCount; ++mCurrentDeltaEntry; } return 0; } //////////////////////////////////////////////////////////////////////////////// SampleTable::SampleTable(const sp<DataSource> &source) : mDataSource(source), mChunkOffsetOffset(-1), mChunkOffsetType(0), mNumChunkOffsets(0), mSampleToChunkOffset(-1), mNumSampleToChunkOffsets(0), mSampleSizeOffset(-1), mSampleSizeFieldSize(0), mDefaultSampleSize(0), mNumSampleSizes(0), mTimeToSampleCount(0), mTimeToSample(NULL), mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), mCompositionDeltaLookup(new CompositionDeltaLookup), mSyncSampleOffset(-1), mNumSyncSamples(0), mSyncSamples(NULL), mLastSyncSampleIndex(0), mSampleToChunkEntries(NULL) { mSampleIterator = new SampleIterator(this); } SampleTable::~SampleTable() { delete[] mSampleToChunkEntries; mSampleToChunkEntries = NULL; delete[] mSyncSamples; mSyncSamples = NULL; delete mCompositionDeltaLookup; mCompositionDeltaLookup = NULL; delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; delete[] mSampleTimeEntries; mSampleTimeEntries = NULL; delete[] mTimeToSample; mTimeToSample = NULL; delete mSampleIterator; mSampleIterator = NULL; } bool SampleTable::isValid() const { return mChunkOffsetOffset >= 0 && mSampleToChunkOffset >= 0 && mSampleSizeOffset >= 0 && mTimeToSample != NULL; } status_t SampleTable::setChunkOffsetParams( uint32_t type, off64_t data_offset, size_t data_size) { if (mChunkOffsetOffset >= 0) { return ERROR_MALFORMED; } CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); mChunkOffsetOffset = data_offset; mChunkOffsetType = type; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumChunkOffsets = U32_AT(&header[4]); if (mChunkOffsetType == kChunkOffsetType32) { if (data_size < 8 + mNumChunkOffsets * 4) { return ERROR_MALFORMED; } } else { if (data_size < 8 + mNumChunkOffsets * 8) { return ERROR_MALFORMED; } } return OK; } status_t SampleTable::setSampleToChunkParams( off64_t data_offset, size_t data_size) { if (mSampleToChunkOffset >= 0) { return ERROR_MALFORMED; } mSampleToChunkOffset = data_offset; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSampleToChunkOffsets = U32_AT(&header[4]); if (data_size < 8 + mNumSampleToChunkOffsets * 12) { return ERROR_MALFORMED; } mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets]; for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; if (mDataSource->readAt( mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) { return ERROR_IO; } CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. // We want the chunk index to be 0-based. mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); } return OK; } status_t SampleTable::setSampleSizeParams( uint32_t type, off64_t data_offset, size_t data_size) { if (mSampleSizeOffset >= 0) { return ERROR_MALFORMED; } CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); mSampleSizeOffset = data_offset; if (data_size < 12) { return ERROR_MALFORMED; } uint8_t header[12]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mDefaultSampleSize = U32_AT(&header[4]); mNumSampleSizes = U32_AT(&header[8]); if (type == kSampleSizeType32) { mSampleSizeFieldSize = 32; if (mDefaultSampleSize != 0) { return OK; } if (data_size < 12 + mNumSampleSizes * 4) { return ERROR_MALFORMED; } } else { if ((mDefaultSampleSize & 0xffffff00) != 0) { // The high 24 bits are reserved and must be 0. return ERROR_MALFORMED; } mSampleSizeFieldSize = mDefaultSampleSize & 0xff; mDefaultSampleSize = 0; if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 && mSampleSizeFieldSize != 16) { return ERROR_MALFORMED; } if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { return ERROR_MALFORMED; } } return OK; } status_t SampleTable::setTimeToSampleParams( off64_t data_offset, size_t data_size) { if (mTimeToSample != NULL || data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mTimeToSampleCount = U32_AT(&header[4]); mTimeToSample = new uint32_t[mTimeToSampleCount * 2]; size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; if (mDataSource->readAt( data_offset + 8, mTimeToSample, size) < (ssize_t)size) { return ERROR_IO; } for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { mTimeToSample[i] = ntohl(mTimeToSample[i]); } return OK; } status_t SampleTable::setCompositionTimeToSampleParams( off64_t data_offset, size_t data_size) { LOGI("There are reordered frames present."); if (mCompositionTimeDeltaEntries != NULL || data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } size_t numEntries = U32_AT(&header[4]); if (data_size != (numEntries + 1) * 8) { return ERROR_MALFORMED; } mNumCompositionTimeDeltaEntries = numEntries; mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries]; if (mDataSource->readAt( data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8) < (ssize_t)numEntries * 8) { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; return ERROR_IO; } for (size_t i = 0; i < 2 * numEntries; ++i) { mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]); } mCompositionDeltaLookup->setEntries( mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries); return OK; } status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) { if (mSyncSampleOffset >= 0 || data_size < 8) { return ERROR_MALFORMED; } mSyncSampleOffset = data_offset; uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSyncSamples = U32_AT(&header[4]); if (mNumSyncSamples < 2) { ALOGV("Table of sync samples is empty or has only a single entry!"); } mSyncSamples = new uint32_t[mNumSyncSamples]; size_t size = mNumSyncSamples * sizeof(uint32_t); if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) != (ssize_t)size) { return ERROR_IO; } for (size_t i = 0; i < mNumSyncSamples; ++i) { mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1; } return OK; } uint32_t SampleTable::countChunkOffsets() const { return mNumChunkOffsets; } uint32_t SampleTable::countSamples() const { return mNumSampleSizes; } status_t SampleTable::getMaxSampleSize(size_t *max_size) { Mutex::Autolock autoLock(mLock); *max_size = 0; for (uint32_t i = 0; i < mNumSampleSizes; ++i) { size_t sample_size; status_t err = getSampleSize_l(i, &sample_size); if (err != OK) { return err; } if (sample_size > *max_size) { *max_size = sample_size; } } return OK; } uint32_t abs_difference(uint32_t time1, uint32_t time2) { return time1 > time2 ? time1 - time2 : time2 - time1; } // static int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) { const SampleTimeEntry *a = (const SampleTimeEntry *)_a; const SampleTimeEntry *b = (const SampleTimeEntry *)_b; if (a->mCompositionTime < b->mCompositionTime) { return -1; } else if (a->mCompositionTime > b->mCompositionTime) { return 1; } return 0; } void SampleTable::buildSampleEntriesTable() { Mutex::Autolock autoLock(mLock); if (mSampleTimeEntries != NULL) { return; } mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes]; uint32_t sampleIndex = 0; uint32_t sampleTime = 0; for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { uint32_t n = mTimeToSample[2 * i]; uint32_t delta = mTimeToSample[2 * i + 1]; for (uint32_t j = 0; j < n; ++j) { if (sampleIndex < mNumSampleSizes) { // Technically this should always be the case if the file // is well-formed, but you know... there's (gasp) malformed // content out there. mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; uint32_t compTimeDelta = mCompositionDeltaLookup->getCompositionTimeOffset( sampleIndex); mSampleTimeEntries[sampleIndex].mCompositionTime = sampleTime + compTimeDelta; } ++sampleIndex; sampleTime += delta; } } qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), CompareIncreasingTime); } status_t SampleTable::findSampleAtTime( uint32_t req_time, uint32_t *sample_index, uint32_t flags) { buildSampleEntriesTable(); uint32_t left = 0; uint32_t right = mNumSampleSizes; while (left < right) { uint32_t center = (left + right) / 2; uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime; if (req_time < centerTime) { right = center; } else if (req_time > centerTime) { left = center + 1; } else { left = center; break; } } if (left == mNumSampleSizes) { if (flags == kFlagAfter) { return ERROR_OUT_OF_RANGE; } --left; } uint32_t closestIndex = left; switch (flags) { case kFlagBefore: { while (closestIndex > 0 && mSampleTimeEntries[closestIndex].mCompositionTime > req_time) { --closestIndex; } break; } case kFlagAfter: { while (closestIndex + 1 < mNumSampleSizes && mSampleTimeEntries[closestIndex].mCompositionTime < req_time) { ++closestIndex; } break; } default: { CHECK(flags == kFlagClosest); if (closestIndex > 0) { // Check left neighbour and pick closest. uint32_t absdiff1 = abs_difference( mSampleTimeEntries[closestIndex].mCompositionTime, req_time); uint32_t absdiff2 = abs_difference( mSampleTimeEntries[closestIndex - 1].mCompositionTime, req_time); if (absdiff1 > absdiff2) { closestIndex = closestIndex - 1; } } break; } } *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; return OK; } status_t SampleTable::findSyncSampleNear( uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) { Mutex::Autolock autoLock(mLock); *sample_index = 0; if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = start_sample_index; return OK; } if (mNumSyncSamples == 0) { *sample_index = 0; return OK; } uint32_t left = 0; while (left < mNumSyncSamples) { uint32_t x = mSyncSamples[left]; if (x >= start_sample_index) { break; } ++left; } if (left == mNumSyncSamples) { if (flags == kFlagAfter) { LOGE("tried to find a sync frame after the last one: %d", left); return ERROR_OUT_OF_RANGE; } } if (left > 0) { --left; } uint32_t x = mSyncSamples[left]; if (left + 1 < mNumSyncSamples) { uint32_t y = mSyncSamples[left + 1]; // our sample lies between sync samples x and y. status_t err = mSampleIterator->seekTo(start_sample_index); if (err != OK) { return err; } uint32_t sample_time = mSampleIterator->getSampleTime(); err = mSampleIterator->seekTo(x); if (err != OK) { return err; } uint32_t x_time = mSampleIterator->getSampleTime(); err = mSampleIterator->seekTo(y); if (err != OK) { return err; } uint32_t y_time = mSampleIterator->getSampleTime(); if (abs_difference(x_time, sample_time) > abs_difference(y_time, sample_time)) { // Pick the sync sample closest (timewise) to the start-sample. x = y; ++left; } } switch (flags) { case kFlagBefore: { if (x > start_sample_index) { CHECK(left > 0); x = mSyncSamples[left - 1]; CHECK(x <= start_sample_index); } break; } case kFlagAfter: { if (x < start_sample_index) { if (left + 1 >= mNumSyncSamples) { return ERROR_OUT_OF_RANGE; } x = mSyncSamples[left + 1]; CHECK(x >= start_sample_index); } break; } default: break; } *sample_index = x; return OK; } status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { Mutex::Autolock autoLock(mLock); if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = 0; return OK; } uint32_t bestSampleIndex = 0; size_t maxSampleSize = 0; static const size_t kMaxNumSyncSamplesToScan = 20; // Consider the first kMaxNumSyncSamplesToScan sync samples and // pick the one with the largest (compressed) size as the thumbnail. size_t numSamplesToScan = mNumSyncSamples; if (numSamplesToScan > kMaxNumSyncSamplesToScan) { numSamplesToScan = kMaxNumSyncSamplesToScan; } for (size_t i = 0; i < numSamplesToScan; ++i) { uint32_t x = mSyncSamples[i]; // Now x is a sample index. size_t sampleSize; status_t err = getSampleSize_l(x, &sampleSize); if (err != OK) { return err; } if (i == 0 || sampleSize > maxSampleSize) { bestSampleIndex = x; maxSampleSize = sampleSize; } } *sample_index = bestSampleIndex; return OK; } status_t SampleTable::getSampleSize_l( uint32_t sampleIndex, size_t *sampleSize) { return mSampleIterator->getSampleSizeDirect( sampleIndex, sampleSize); } status_t SampleTable::getMetaDataForSample( uint32_t sampleIndex, off64_t *offset, size_t *size, uint32_t *compositionTime, bool *isSyncSample) { Mutex::Autolock autoLock(mLock); status_t err; if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { return err; } if (offset) { *offset = mSampleIterator->getSampleOffset(); } if (size) { *size = mSampleIterator->getSampleSize(); } if (compositionTime) { *compositionTime = mSampleIterator->getSampleTime(); } if (isSyncSample) { *isSyncSample = false; if (mSyncSampleOffset < 0) { // Every sample is a sync sample. *isSyncSample = true; } else { size_t i = (mLastSyncSampleIndex < mNumSyncSamples) && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex) ? mLastSyncSampleIndex : 0; while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) { ++i; } if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) { *isSyncSample = true; } mLastSyncSampleIndex = i; } } return OK; } uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex); } } // namespace android
// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel status_t TextDescriptions::extract3GPPGlobalDescriptions( const uint8_t *data, ssize_t size, Parcel *parcel) { parcel->writeInt32(KEY_GLOBAL_SETTING); while (size >= 8) { ssize_t chunkSize = U32_AT(data); uint32_t chunkType = U32_AT(data + 4); const uint8_t *tmpData = data; tmpData += 8; size_t remaining = size - 8; if (size < chunkSize) { return OK; } switch(chunkType) { case FOURCC('t', 'x', '3', 'g'): { if (remaining < 18) { // 8 just below, and another 10 a little further down return OK; } tmpData += 8; // skip the first 8 bytes remaining -=8; parcel->writeInt32(KEY_DISPLAY_FLAGS); parcel->writeInt32(U32_AT(tmpData)); parcel->writeInt32(KEY_STRUCT_JUSTIFICATION); parcel->writeInt32(tmpData[4]); parcel->writeInt32(tmpData[5]); parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA); uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16 | *(tmpData + 8) << 8 | *(tmpData + 9); parcel->writeInt32(rgba); tmpData += 10; remaining -= 10; if (remaining < 8) { return OK; } parcel->writeInt32(KEY_STRUCT_TEXT_POS); parcel->writeInt32(U16_AT(tmpData)); parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(U16_AT(tmpData + 6)); tmpData += 8; remaining -= 8; if (remaining < 12) { return OK; } parcel->writeInt32(KEY_STRUCT_STYLE_LIST); parcel->writeInt32(KEY_START_CHAR); parcel->writeInt32(U16_AT(tmpData)); parcel->writeInt32(KEY_END_CHAR); parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(KEY_FONT_ID); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(KEY_STYLE_FLAGS); parcel->writeInt32(*(tmpData + 6)); parcel->writeInt32(KEY_FONT_SIZE); parcel->writeInt32(*(tmpData + 7)); parcel->writeInt32(KEY_TEXT_COLOR_RGBA); rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 | *(tmpData + 10) << 8 | *(tmpData + 11); parcel->writeInt32(rgba); tmpData += 12; remaining -= 12; if (remaining < 2) { return OK; } size_t dataPos = parcel->dataPosition(); parcel->writeInt32(KEY_STRUCT_FONT_LIST); uint16_t count = U16_AT(tmpData); parcel->writeInt32(count); tmpData += 2; remaining -= 2; for (int i = 0; i < count; i++) { if (remaining < 3) { // roll back parcel->setDataPosition(dataPos); return OK; } // font ID parcel->writeInt32(U16_AT(tmpData)); // font name length parcel->writeInt32(*(tmpData + 2)); size_t len = *(tmpData + 2); tmpData += 3; remaining -= 3; if (remaining < len) { // roll back parcel->setDataPosition(dataPos); return OK; } parcel->write(tmpData, len); tmpData += len; remaining -= len; } // there is a "DisparityBox" after this according to the spec, but we ignore it break; } default: { break; } } data += chunkSize; size -= chunkSize; } return OK; }
// $Version$ // $Revision:$ // // DESCRIPTION: GFX Font Class Member Functions // // (c) Copyright 1995, Dynamix Inc. All rights reserved. // //======================================================================== #include <filstrm.h> #include "g_font.h" #include "g_bitmap.h" #include "g_pal.h" #include "resManager.h" IMPLEMENT_PERSISTENT_TAG(GFXFont, FOURCC('P','F','O','N')); static void SetMonoBits( GFXBitmap *pBitmap, UInt32 obgc, UInt32 nfgc, UInt32 nbgc, Int32 flags ); #define TRANSLATE_FOREGROUND (1<<1) #define TRANSLATE_BACKGROUND (1<<2) //======================================================================== // Definitions and Structure Declerations //======================================================================== #define DEREF(x,y) ((y->fi.flags&FONT_UNICODE)? (UInt32 *)x:(char *)x) #define NEXT(x,y) ( x += (y->fi.flags&FONT_UNICODE)? 2:1) struct Header { DWORD ver_nc;
bool eZ80AccessorSZX::SetState(xIo::eStreamMemory& is) { ZXSTHEADER header; if(is.Read(&header, sizeof(header)) != sizeof(header)) return false; if(header.dwMagic != FOURCC('Z', 'X', 'S', 'T')) return false; bool model48k = false; switch(header.chMachineId) { case ZXSTMID_16K: case ZXSTMID_48K: case ZXSTMID_NTSC48K: model48k = true; break; case ZXSTMID_128K: case ZXSTMID_PENTAGON128: break; default: return false; } SetupDevices(model48k); ZXSTBLOCK block; while(is.Read(&block, sizeof(block)) == sizeof(block)) { switch(block.dwId) { case FOURCC('Z', '8', '0', 'R'): { ZXSTZ80REGS regs; if(!ReadBlock(is, ®s, block)) return false; af = SwapWord(regs.AF); bc = SwapWord(regs.BC); de = SwapWord(regs.DE); hl = SwapWord(regs.HL); alt.af = SwapWord(regs.AF1); alt.bc = SwapWord(regs.BC1); alt.de = SwapWord(regs.DE1); alt.hl = SwapWord(regs.HL1); ix = SwapWord(regs.IX); iy = SwapWord(regs.IY); sp = SwapWord(regs.SP); pc = SwapWord(regs.PC); i = regs.I; r_low = regs.R; r_hi = regs.R & 0x80; im = regs.IM; iff1 = regs.IFF1; iff2 = regs.IFF2; t = Dword((const byte*)®s.dwCyclesStart) % frame_tacts; if(regs.wMemPtr) memptr = SwapWord(regs.wMemPtr); } break; case FOURCC('S', 'P', 'C', 'R'): { ZXSTSPECREGS regs; if(!ReadBlock(is, ®s, block)) return false; devices->IoWrite(0xfe, (regs.chFe&0x18) | regs.chBorder, t); devices->IoWrite(0x7ffd, model48k ? 0x30 : regs.ch7ffd, t); if(model48k) devices->Get<eMemory>()->SetRomPage(eMemory::P_ROM_48); else devices->Get<eMemory>()->SetRomPage((regs.ch7ffd & 0x10) ? eMemory::P_ROM_128_0 : eMemory::P_ROM_128_1); } break; case FOURCC('R', 'A', 'M', 'P'): { ZXSTRAMPAGE ram_page; if(!ReadBlock(is, &ram_page, block, sizeof(ZXSTRAMPAGE) - sizeof(ZXSTBLOCK) - 1)) return false; byte* buf = new byte[eMemory::PAGE_SIZE]; bool ok = false; if(SwapWord(ram_page.wFlags)&ZXSTRF_COMPRESSED) { #ifdef USE_ZIP size_t size = ram_page.blk.dwSize - (sizeof(ZXSTRAMPAGE) - sizeof(ZXSTBLOCK) - 1); byte* buf_compr = new byte[size]; ok = is.Read(buf_compr, size) == size; if(ok) { z_stream zs; memset(&zs, 0, sizeof(zs)); zs.next_in = buf_compr; zs.avail_in = size; zs.next_out = buf; zs.avail_out = eMemory::PAGE_SIZE; ok = inflateInit2(&zs, 15) == Z_OK; if(ok) ok = inflate(&zs, Z_NO_FLUSH) == Z_STREAM_END; inflateEnd(&zs); } SAFE_DELETE_ARRAY(buf_compr); #endif//USE_ZIP } else { size_t size = ram_page.blk.dwSize - (sizeof(ZXSTRAMPAGE) - sizeof(ZXSTBLOCK) - 1); ok = size == eMemory::PAGE_SIZE; if(ok) { ok = is.Read(buf, size) == size; } } if(ok && ram_page.chPageNo <= 7) { memcpy(memory->Get(eMemory::P_RAM0 + ram_page.chPageNo), buf, eMemory::PAGE_SIZE); } SAFE_DELETE(buf); if(!ok) return false; } break; case FOURCC('A', 'Y', '\0', '\0'): { ZXSTAYBLOCK ay_state; if(!ReadBlock(is, &ay_state, block)) return false; devices->Get<eAY>()->SetRegs(ay_state.chAyRegs); devices->Get<eAY>()->Select(ay_state.chCurrentRegister); } break; default: if(is.Seek(block.dwSize, xIo::eStreamMemory::S_CUR) != 0) return false; } if(is.Pos() == is.Size()) return true; } return false; }
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include "codeclib.h" #include "codecs/libpcm/support_formats.h" CODEC_HEADER #define FOURCC(c1, c2, c3, c4) \ ((((uint32_t)c1)<<24)|(((uint32_t)c2)<<16)|(((uint32_t)c3)<<8)|((uint32_t)c4)) /* This codec supports the following AIFC compressionType formats */ enum { AIFC_FORMAT_PCM = FOURCC('N', 'O', 'N', 'E'), /* AIFC PCM Format (big endian) */ AIFC_FORMAT_ALAW = FOURCC('a', 'l', 'a', 'w'), /* AIFC ALaw compressed */ AIFC_FORMAT_MULAW = FOURCC('u', 'l', 'a', 'w'), /* AIFC uLaw compressed */ AIFC_FORMAT_IEEE_FLOAT32 = FOURCC('f', 'l', '3', '2'), /* AIFC IEEE float 32 bit */ AIFC_FORMAT_IEEE_FLOAT64 = FOURCC('f', 'l', '6', '4'), /* AIFC IEEE float 64 bit */ AIFC_FORMAT_QT_IMA_ADPCM = FOURCC('i', 'm', 'a', '4'), /* AIFC QuickTime IMA ADPCM */ }; static const struct pcm_entry pcm_codecs[] = { { AIFC_FORMAT_PCM, get_linear_pcm_codec }, { AIFC_FORMAT_ALAW, get_itut_g711_alaw_codec }, { AIFC_FORMAT_MULAW, get_itut_g711_mulaw_codec }, { AIFC_FORMAT_IEEE_FLOAT32, get_ieee_float_codec }, { AIFC_FORMAT_IEEE_FLOAT64, get_ieee_float_codec }, { AIFC_FORMAT_QT_IMA_ADPCM, get_qt_ima_adpcm_codec }, };
namespace android { // static const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); // static const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); // static const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); // static const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); //////////////////////////////////////////////////////////////////////////////// struct SampleTable::CompositionDeltaLookup { CompositionDeltaLookup(); void setEntries( const uint32_t *deltaEntries, size_t numDeltaEntries); uint32_t getCompositionTimeOffset(uint32_t sampleIndex); private: Mutex mLock; const uint32_t *mDeltaEntries; size_t mNumDeltaEntries; size_t mCurrentDeltaEntry; size_t mCurrentEntrySampleIndex; DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup); }; SampleTable::CompositionDeltaLookup::CompositionDeltaLookup() : mDeltaEntries(NULL), mNumDeltaEntries(0), mCurrentDeltaEntry(0), mCurrentEntrySampleIndex(0) { } void SampleTable::CompositionDeltaLookup::setEntries( const uint32_t *deltaEntries, size_t numDeltaEntries) { Mutex::Autolock autolock(mLock); mDeltaEntries = deltaEntries; mNumDeltaEntries = numDeltaEntries; mCurrentDeltaEntry = 0; mCurrentEntrySampleIndex = 0; } uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset( uint32_t sampleIndex) { Mutex::Autolock autolock(mLock); if (mDeltaEntries == NULL) { return 0; } if (sampleIndex < mCurrentEntrySampleIndex) { mCurrentDeltaEntry = 0; mCurrentEntrySampleIndex = 0; } while (mCurrentDeltaEntry < mNumDeltaEntries) { uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry]; if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) { return mDeltaEntries[2 * mCurrentDeltaEntry + 1]; } mCurrentEntrySampleIndex += sampleCount; ++mCurrentDeltaEntry; } return 0; } //////////////////////////////////////////////////////////////////////////////// SampleTable::SampleTable(const sp<DataSource> &source) : mDataSource(source), mChunkOffsetOffset(-1), mChunkOffsetType(0), mNumChunkOffsets(0), mSampleToChunkOffset(-1), mNumSampleToChunkOffsets(0), mSampleSizeOffset(-1), mSampleSizeFieldSize(0), mDefaultSampleSize(0), mNumSampleSizes(0), mTimeToSampleCount(0), mTimeToSample(NULL), mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), mCompositionDeltaLookup(new CompositionDeltaLookup), mSyncSampleOffset(-1), mNumSyncSamples(0), mSyncSamples(NULL), mLastSyncSampleIndex(0), mSampleToChunkEntries(NULL) { mSampleIterator = new SampleIterator(this); } SampleTable::~SampleTable() { delete[] mSampleToChunkEntries; mSampleToChunkEntries = NULL; delete[] mSyncSamples; mSyncSamples = NULL; delete mCompositionDeltaLookup; mCompositionDeltaLookup = NULL; delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; delete[] mSampleTimeEntries; mSampleTimeEntries = NULL; delete[] mTimeToSample; mTimeToSample = NULL; delete mSampleIterator; mSampleIterator = NULL; while (!mSampleDescAtoms.empty()) { List<SampleDescAtom *>::iterator it = mSampleDescAtoms.begin(); delete (*it)->ptr; (*it) = NULL; mSampleDescAtoms.erase(it); } mSampleDescAtoms.clear(); } bool SampleTable::isValid() const { return mChunkOffsetOffset >= 0 && mSampleToChunkOffset >= 0 && mSampleSizeOffset >= 0 && mTimeToSample != NULL; } status_t SampleTable::setChunkOffsetParams( uint32_t type, off64_t data_offset, size_t data_size) { if (mChunkOffsetOffset >= 0) { return ERROR_MALFORMED; } CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); mChunkOffsetOffset = data_offset; mChunkOffsetType = type; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumChunkOffsets = U32_AT(&header[4]); if (mChunkOffsetType == kChunkOffsetType32) { if (data_size < 8 + mNumChunkOffsets * 4) { return ERROR_MALFORMED; } } else { if (data_size < 8 + mNumChunkOffsets * 8) { return ERROR_MALFORMED; } } return OK; } status_t SampleTable::setSampleToChunkParams( off64_t data_offset, size_t data_size) { if (mSampleToChunkOffset >= 0) { return ERROR_MALFORMED; } mSampleToChunkOffset = data_offset; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSampleToChunkOffsets = U32_AT(&header[4]); if (data_size < 8 + mNumSampleToChunkOffsets * 12) { return ERROR_MALFORMED; } mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets]; for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; if (mDataSource->readAt( mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) { return ERROR_IO; } //CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. if(U32_AT(buffer) <= 0) { LOGE("Non Standard Chunk index\n"); return ERROR_MALFORMED; } // We want the chunk index to be 0-based. mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); } return OK; } status_t SampleTable::setSampleSizeParams( uint32_t type, off64_t data_offset, size_t data_size) { if (mSampleSizeOffset >= 0) { return ERROR_MALFORMED; } CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); mSampleSizeOffset = data_offset; if (data_size < 12) { return ERROR_MALFORMED; } uint8_t header[12]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mDefaultSampleSize = U32_AT(&header[4]); mNumSampleSizes = U32_AT(&header[8]); if (type == kSampleSizeType32) { mSampleSizeFieldSize = 32; // this needs to be 64 or overflow may occur from the calculation uint64_t expectedDataSize = (uint64_t)12 + (uint64_t)mNumSampleSizes * (uint64_t)4; // mDefaultSampleSize = 0 means sample table follows the field if (((uint64_t)data_size < expectedDataSize) && (mDefaultSampleSize == 0)){ return ERROR_MALFORMED; } if (((uint64_t)data_size < expectedDataSize) && ((mDefaultSampleSize & 0xFF000000) != 0) ) { return ERROR_MALFORMED; } if (mDefaultSampleSize != 0) { return OK; } } else { if ((mDefaultSampleSize & 0xffffff00) != 0) { // The high 24 bits are reserved and must be 0. return ERROR_MALFORMED; } mSampleSizeFieldSize = mDefaultSampleSize & 0xff; mDefaultSampleSize = 0; if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 && mSampleSizeFieldSize != 16) { return ERROR_MALFORMED; } if (data_size < 12 + (mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { return ERROR_MALFORMED; } } return OK; } status_t SampleTable::setTimeToSampleParams( off64_t data_offset, size_t data_size) { if (mTimeToSample != NULL || data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mTimeToSampleCount = U32_AT(&header[4]); mTimeToSample = new uint32_t[mTimeToSampleCount * 2]; size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; if (mDataSource->readAt( data_offset + 8, mTimeToSample, size) < (ssize_t)size) { return ERROR_IO; } for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { mTimeToSample[i] = ntohl(mTimeToSample[i]); } return OK; } status_t SampleTable::setCompositionTimeToSampleParams( off64_t data_offset, size_t data_size) { LOGI("There are reordered frames present."); if (mCompositionTimeDeltaEntries != NULL || data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0 && U32_AT(header) != 0x00010000) { // Expected version = 0 or 1, flags = 0. return ERROR_MALFORMED; } size_t numEntries = U32_AT(&header[4]); if (data_size != (numEntries + 1) * 8) { return ERROR_MALFORMED; } mNumCompositionTimeDeltaEntries = numEntries; mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries]; if (mDataSource->readAt( data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8) < (ssize_t)numEntries * 8) { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; return ERROR_IO; } for (size_t i = 0; i < 2 * numEntries; ++i) { mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]); } mCompositionDeltaLookup->setEntries( mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries); return OK; } status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) { if (mSyncSampleOffset >= 0 || data_size < 8) { return ERROR_MALFORMED; } mSyncSampleOffset = data_offset; uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSyncSamples = U32_AT(&header[4]); if (mNumSyncSamples < 2) { LOGV("Table of sync samples is empty or has only a single entry!"); } mSyncSamples = new uint32_t[mNumSyncSamples]; size_t size = mNumSyncSamples * sizeof(uint32_t); if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) != (ssize_t)size) { return ERROR_IO; } for (size_t i = 0; i < mNumSyncSamples; ++i) { mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1; } return OK; } uint32_t SampleTable::countChunkOffsets() const { return mNumChunkOffsets; } uint32_t SampleTable::countSamples() const { return mNumSampleSizes; } status_t SampleTable::getMaxSampleSize(size_t *max_size) { Mutex::Autolock autoLock(mLock); *max_size = 0; if(mDefaultSampleSize > 0){ *max_size = mDefaultSampleSize; return OK; } for (uint32_t i = 0; i < mNumSampleSizes; ++i) { size_t sample_size; status_t err = getSampleSize_l(i, &sample_size); if (err != OK) { return err; } if (sample_size > *max_size) { *max_size = sample_size; } } return OK; } uint32_t abs_difference(uint32_t time1, uint32_t time2) { return time1 > time2 ? time1 - time2 : time2 - time1; } // static int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) { const SampleTimeEntry *a = (const SampleTimeEntry *)_a; const SampleTimeEntry *b = (const SampleTimeEntry *)_b; if (a->mCompositionTime < b->mCompositionTime) { return -1; } else if (a->mCompositionTime > b->mCompositionTime) { return 1; } return 0; } void SampleTable::buildSampleEntriesTable() { Mutex::Autolock autoLock(mLock); if (mSampleTimeEntries != NULL) { return; } mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes]; uint32_t sampleIndex = 0; uint32_t sampleTime = 0; for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { uint32_t n = mTimeToSample[2 * i]; uint32_t delta = mTimeToSample[2 * i + 1]; for (uint32_t j = 0; j < n; ++j) { if (sampleIndex < mNumSampleSizes) { // Technically this should always be the case if the file // is well-formed, but you know... there's (gasp) malformed // content out there. mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; int32_t compTimeDelta = (int32_t) mCompositionDeltaLookup->getCompositionTimeOffset( sampleIndex); mSampleTimeEntries[sampleIndex].mCompositionTime = sampleTime + compTimeDelta; } ++sampleIndex; sampleTime += delta; } } qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), CompareIncreasingTime); } status_t SampleTable::findSampleAtTime( uint32_t req_time, uint32_t *sample_index, uint32_t flags) { buildSampleEntriesTable(); uint32_t left = 0; uint32_t right = mNumSampleSizes; while (left < right) { uint32_t center = (left + right) / 2; uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime; if (req_time < centerTime) { right = center; } else if (req_time > centerTime) { left = center + 1; } else { left = center; break; } } if (left == mNumSampleSizes) { if (flags == kFlagAfter) { return ERROR_OUT_OF_RANGE; } --left; } uint32_t closestIndex = left; switch (flags) { case kFlagBefore: { while (closestIndex > 0 && mSampleTimeEntries[closestIndex].mCompositionTime > req_time) { --closestIndex; } break; } case kFlagAfter: { while (closestIndex + 1 < mNumSampleSizes && mSampleTimeEntries[closestIndex].mCompositionTime < req_time) { ++closestIndex; } break; } default: { CHECK(flags == kFlagClosest); if (closestIndex > 0) { // Check left neighbour and pick closest. uint32_t absdiff1 = abs_difference( mSampleTimeEntries[closestIndex].mCompositionTime, req_time); uint32_t absdiff2 = abs_difference( mSampleTimeEntries[closestIndex - 1].mCompositionTime, req_time); if (absdiff1 > absdiff2) { closestIndex = closestIndex - 1; } } break; } } *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; return OK; } status_t SampleTable::findSyncSampleNear( uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) { Mutex::Autolock autoLock(mLock); *sample_index = 0; if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = start_sample_index; return OK; } if (mNumSyncSamples == 0) { *sample_index = 0; return OK; } uint32_t left = 0; while (left < mNumSyncSamples) { uint32_t x = mSyncSamples[left]; if (x >= start_sample_index) { break; } ++left; } if (left == mNumSyncSamples) { if (flags == kFlagAfter) { LOGE("tried to find a sync frame after the last one: %d", left); return ERROR_OUT_OF_RANGE; } } if (left > 0) { --left; } uint32_t x = mSyncSamples[left]; if (left + 1 < mNumSyncSamples) { uint32_t y = mSyncSamples[left + 1]; // our sample lies between sync samples x and y. status_t err = mSampleIterator->seekTo(start_sample_index); if (err != OK) { return err; } uint32_t sample_time = mSampleIterator->getSampleTime(); err = mSampleIterator->seekTo(x); if (err != OK) { return err; } uint32_t x_time = mSampleIterator->getSampleTime(); err = mSampleIterator->seekTo(y); if (err != OK) { return err; } uint32_t y_time = mSampleIterator->getSampleTime(); if (abs_difference(x_time, sample_time) > abs_difference(y_time, sample_time)) { // Pick the sync sample closest (timewise) to the start-sample. x = y; ++left; } } switch (flags) { case kFlagBefore: { if (x > start_sample_index) { CHECK(left > 0); x = mSyncSamples[left - 1]; CHECK(x <= start_sample_index); } break; } case kFlagAfter: { if (x < start_sample_index) { if (left + 1 >= mNumSyncSamples) { return ERROR_OUT_OF_RANGE; } x = mSyncSamples[left + 1]; CHECK(x >= start_sample_index); } break; } default: break; } *sample_index = x; return OK; } status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { Mutex::Autolock autoLock(mLock); if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = 0; return OK; } uint32_t bestSampleIndex = 0; size_t maxSampleSize = 0; static const size_t kMaxNumSyncSamplesToScan = 20; // Consider the first kMaxNumSyncSamplesToScan sync samples and // pick the one with the largest (compressed) size as the thumbnail. size_t numSamplesToScan = mNumSyncSamples; if (numSamplesToScan > kMaxNumSyncSamplesToScan) { numSamplesToScan = kMaxNumSyncSamplesToScan; } for (size_t i = 0; i < numSamplesToScan; ++i) { uint32_t x = mSyncSamples[i]; // Now x is a sample index. size_t sampleSize; status_t err = getSampleSize_l(x, &sampleSize); if (err != OK) { return err; } if (i == 0 || sampleSize > maxSampleSize) { bestSampleIndex = x; maxSampleSize = sampleSize; } } *sample_index = bestSampleIndex; return OK; } status_t SampleTable::getSampleSize_l( uint32_t sampleIndex, size_t *sampleSize) { return mSampleIterator->getSampleSizeDirect( sampleIndex, sampleSize); } status_t SampleTable::getMetaDataForSample( uint32_t sampleIndex, off64_t *offset, size_t *size, uint32_t *compositionTime, bool *isSyncSample, uint32_t *sampleDescIndex) { Mutex::Autolock autoLock(mLock); status_t err; if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { return err; } if (offset) { *offset = mSampleIterator->getSampleOffset(); } if (size) { *size = mSampleIterator->getSampleSize(); } if (compositionTime) { *compositionTime = mSampleIterator->getSampleTime(); } if (sampleDescIndex) { *sampleDescIndex = mSampleIterator->getDescIndex(); } if (isSyncSample) { *isSyncSample = false; if (mSyncSampleOffset < 0) { // Every sample is a sync sample. *isSyncSample = true; } else { size_t i = (mLastSyncSampleIndex < mNumSyncSamples) && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex) ? mLastSyncSampleIndex : 0; while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) { ++i; } if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) { *isSyncSample = true; } mLastSyncSampleIndex = i; } } return OK; } uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex); } uint32_t SampleTable::getNumSyncSamples() { return mNumSyncSamples; } status_t SampleTable::setSampleDescParams(uint32_t count, off64_t offset, size_t size) { // avcC atom will start after 78 bytes in avC1 atom const uint32_t avcC_offset = 78; for(uint32_t i = 0; i < count; ++i) { uint32_t hdr[2]; if (mDataSource->readAt(offset, hdr, 8) < 8) { return ERROR_IO; } uint64_t avc1_chunk_size = ntohl(hdr[0]); uint32_t avc1_chunk_type = ntohl(hdr[1]); off64_t avc1_data_offset = offset + 8; if(avc1_chunk_size == 0) return ERROR_MALFORMED; if (avc1_chunk_size == 1) { if (mDataSource->readAt(offset + 8, &avc1_chunk_size, 8) < 8) { return ERROR_IO; } avc1_chunk_size = ntoh64(avc1_chunk_size); if (avc1_chunk_size == 0) return ERROR_MALFORMED; avc1_data_offset += 8; if (avc1_chunk_size < 16) { // The smallest valid chunk is 16 bytes long in this case. return ERROR_MALFORMED; } } else if (avc1_chunk_size < 8) { // The smallest valid chunk is 8 bytes long. return ERROR_MALFORMED; } off64_t avc1_chunk_data_size = offset + avc1_chunk_size - avc1_data_offset; LOGV("parsing chunk %c%c%c%c", ((char *)&avc1_chunk_type)[3], ((char *)&avc1_chunk_type)[2], ((char *)&avc1_chunk_type)[1], ((char *)&avc1_chunk_type)[0]); if (avc1_chunk_type != FOURCC('a', 'v', 'c', '1')) { LOGE("Multiple Non AVC Sample Entries are not supported"); return ERROR_MALFORMED; } uint8_t *buffer = new uint8_t[(ssize_t)avc1_chunk_data_size]; if (mDataSource->readAt(avc1_data_offset, buffer, (ssize_t)avc1_chunk_data_size) < (ssize_t)avc1_chunk_data_size) { return ERROR_IO; } uint16_t data_ref_index = U16_AT(&buffer[6]); uint16_t width = U16_AT(&buffer[6 + 18]); uint16_t height = U16_AT(&buffer[6 + 20]); LOGE("data_ref_index : %d width : %d height: %d", data_ref_index, width, height); /* parse AVCC atom */ uint64_t avcc_chunk_size = U32_AT(&buffer[avcC_offset]); uint32_t avcc_chunk_type = U32_AT(&buffer[avcC_offset+4]);; if((avcc_chunk_size == 0)|| (avcc_chunk_size == 1)) { LOGE("chunk size error while reading avCC atom"); return ERROR_MALFORMED; } LOGV("parsing chunk %c%c%c%c", ((char *)&avcc_chunk_type)[3], ((char *)&avcc_chunk_type)[2], ((char *)&avcc_chunk_type)[1], ((char *)&avcc_chunk_type)[0]); if (avcc_chunk_type != FOURCC('a', 'v', 'c', 'C')) { LOGE("'avcC' atom expected, but not found"); return ERROR_MALFORMED; } off64_t avcc_chunk_data_size = avc1_chunk_data_size - avcC_offset - 8; SampleDescAtom *sda = new SampleDescAtom; uint8_t *avccBuffer = new uint8_t[avcc_chunk_data_size]; memcpy(avccBuffer, buffer+avcC_offset+8,avcc_chunk_data_size); sda->ptr = avccBuffer; sda->size = avcc_chunk_data_size; mSampleDescAtoms.push_back(sda); delete[] buffer; offset += avc1_chunk_size; } return OK; } status_t SampleTable::getSampleDescAtIndex(uint32_t index, uint8_t **ptr, uint32_t *size) { uint32_t i = 1; for (List<SampleDescAtom *>::iterator it = mSampleDescAtoms.begin(); it != mSampleDescAtoms.end(); ++it, ++i) { if(i == index) { SampleDescAtom *sda = *it; *ptr = sda->ptr; *size = sda->size; } } return OK; } status_t SampleTable::getMaxAvccAtomSize(uint32_t *size) { *size = 0; for (List<SampleDescAtom *>::iterator it = mSampleDescAtoms.begin(); it != mSampleDescAtoms.end(); ++it) { SampleDescAtom *sda = *it; if( *size < sda->size) *size = sda->size; } return OK; } } // namespace android
#include "sky.h" #include "planet.h" #include "d_caps.h" #include "g_surfac.h" #include "simResource.h" #include "console.h" #include "gOGLSfc.h" //--------------------------------------------------------------------------- #define DEGRAD (M_PI/180.0) #define RADDEG (180.0/M_PI) //--------------------------------------------------------------------------- IMPLEMENT_PERSISTENT_TAGS(Planet, FOURCC('T','P','L','A'), PlanetPersTag); static Point2F textCoord[4]; const float hexPoints[6][2] = { { -1.0f, 0.0f }, { -0.5f, -0.83f }, { 0.5f, -0.83f }, { 1.0f, 0.0f }, { 0.5f, 0.83f }, {-0.5f, 0.83f } }; //--------------------------------------------------------------------------- const char *Planet::LensFlare::filename = "lensFlare.dml"; //--------------------------------------------------------------------------- float boxPoints[4][2] = { {-1.0f, -1.0f}, {1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f} };
void mpeg_ts_reader_c::identify() { std::vector<std::string> verbose_info; auto mpls_in = dynamic_cast<mm_mpls_multi_file_io_c *>(get_underlying_input_as_multi_file_io()); if (mpls_in) mpls_in->create_verbose_identification_info(verbose_info); id_result_container(verbose_info); size_t i; for (i = 0; i < tracks.size(); i++) { mpeg_ts_track_ptr &track = tracks[i]; if (!track->probed_ok) continue; const char *fourcc = FOURCC('M', 'P', 'G', '1') == track->fourcc ? "MPEG-1" : FOURCC('M', 'P', 'G', '2') == track->fourcc ? "MPEG-2" : FOURCC('A', 'V', 'C', '1') == track->fourcc ? "AVC/h.264" : FOURCC('W', 'V', 'C', '1') == track->fourcc ? "VC1" : FOURCC('M', 'P', '1', ' ') == track->fourcc ? "MPEG-1 layer 1" : FOURCC('M', 'P', '2', ' ') == track->fourcc ? "MPEG-1 layer 2" : FOURCC('M', 'P', '3', ' ') == track->fourcc ? "MPEG-1 layer 3" : FOURCC('A', 'A', 'C', ' ') == track->fourcc ? "AAC" : FOURCC('A', 'C', '3', ' ') == track->fourcc ? "AC3" : FOURCC('D', 'T', 'S', ' ') == track->fourcc ? "DTS" : FOURCC('T', 'R', 'H', 'D') == track->fourcc ? "TrueHD" : FOURCC('P', 'G', 'S', ' ') == track->fourcc ? "HDMV PGS" // : FOURCC('P', 'C', 'M', ' ') == track->fourcc ? "PCM" // : FOURCC('L', 'P', 'C', 'M') == track->fourcc ? "LPCM" : nullptr; if (!fourcc) continue; verbose_info.clear(); if (!track->language.empty()) verbose_info.push_back((boost::format("language:%1%") % escape(track->language)).str()); verbose_info.push_back((boost::format("ts_pid:%1%") % track->pid).str()); std::string type = ES_AUDIO_TYPE == track->type ? ID_RESULT_TRACK_AUDIO : ES_VIDEO_TYPE == track->type ? ID_RESULT_TRACK_VIDEO : ID_RESULT_TRACK_SUBTITLES; id_result_track(i, type, fourcc, verbose_info); } if (!m_chapter_timecodes.empty()) id_result_chapters(m_chapter_timecodes.size()); }
int mpeg_ts_reader_c::parse_pmt(unsigned char *pmt) { if (!pmt) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid parameters!\n"); return -1; } mpeg_ts_pmt_t *pmt_header = (mpeg_ts_pmt_t *)pmt; if (pmt_header->table_id != 0x02) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid PMT table_id!\n"); return -1; } if (pmt_header->get_section_syntax_indicator() != 1 || pmt_header->get_current_next_indicator() == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Invalid PMT section_syntax_indicator/current_next_indicator!\n"); return -1; } if (pmt_header->section_number != 0 || pmt_header->last_section_number != 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Unsupported multiple section PMT!\n"); return -1; } unsigned short pmt_section_length = pmt_header->get_section_length(); uint32_t elapsed_CRC = crc_calc_mpeg2(pmt, 3 + pmt_section_length - 4/*CRC32*/); uint32_t read_CRC = get_uint32_be(pmt + 3 + pmt_section_length - 4); if (elapsed_CRC != read_CRC) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Wrong PMT CRC !!! Elapsed = 0x%|1$08x|, read 0x%|2$08x|\n") % elapsed_CRC % read_CRC); return -1; } if (pmt_section_length < 13 || pmt_section_length > 1021) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Wrong PMT section_length (=%1%)\n") % pmt_section_length); return -1; } mpeg_ts_pmt_descriptor_t *pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)(pmt + sizeof(mpeg_ts_pmt_t)); unsigned short program_info_length = pmt_header->get_program_info_length(); while (pmt_descriptor < (mpeg_ts_pmt_descriptor_t *)(pmt + sizeof(mpeg_ts_pmt_t) + program_info_length)) pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_descriptor + sizeof(mpeg_ts_pmt_descriptor_t) + pmt_descriptor->length); mpeg_ts_pmt_pid_info_t *pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)pmt_descriptor; // Calculate pids_count size_t pids_found = 0; while (pmt_pid_info < (mpeg_ts_pmt_pid_info_t *)(pmt + 3 + pmt_section_length - 4/*CRC32*/)) { pids_found++; pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + pmt_pid_info->get_es_info_length()); } mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: program number (%1%)\n") % pmt_header->get_program_number()); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: pcr pid (%1%)\n") % pmt_header->get_pcr_pid()); if (pids_found == 0) { mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: There's no information about elementary PIDs\n"); return 0; } pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)pmt_descriptor; // Extract pid_info while (pmt_pid_info < (mpeg_ts_pmt_pid_info_t *)(pmt + 3 + pmt_section_length - 4/*CRC32*/)) { mpeg_ts_track_ptr track(new mpeg_ts_track_c(*this)); unsigned short es_info_length = pmt_pid_info->get_es_info_length(); track->type = ES_UNKNOWN; track->set_pid(pmt_pid_info->get_pid()); switch(pmt_pid_info->stream_type) { case ISO_11172_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '1'); break; case ISO_13818_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '2'); break; case ISO_14496_PART2_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('M', 'P', 'G', '4'); break; case ISO_14496_PART10_VIDEO: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('A', 'V', 'C', '1'); break; case STREAM_VIDEO_VC1: track->type = ES_VIDEO_TYPE; track->fourcc = FOURCC('W', 'V', 'C', '1'); break; case ISO_11172_AUDIO: case ISO_13818_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('M', 'P', '2', ' '); break; case ISO_13818_PART7_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'A', 'C', ' '); break; case ISO_14496_PART3_AUDIO: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'A', 'C', ' '); break; case STREAM_AUDIO_AC3: case STREAM_AUDIO_AC3_PLUS: // EAC3 track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); break; case STREAM_AUDIO_AC3_LOSSLESS: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('T', 'R', 'H', 'D'); break; case STREAM_AUDIO_DTS: case STREAM_AUDIO_DTS_HD: case STREAM_AUDIO_DTS_HD_MA: track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('D', 'T', 'S', ' '); break; case STREAM_SUBTITLES_HDMV_PGS: track->type = ES_SUBT_TYPE; track->fourcc = FOURCC('P', 'G', 'S', ' '); track->probed_ok = true; break; case ISO_13818_PES_PRIVATE: break; default: mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: Unknown stream type: %1%\n") % (int)pmt_pid_info->stream_type); track->type = ES_UNKNOWN; break; } pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t)); bool type_known = false; while (pmt_descriptor < (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + es_info_length)) { mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: PMT descriptor tag 0x%|1$02x| length %2%\n") % static_cast<unsigned int>(pmt_descriptor->tag) % static_cast<unsigned int>(pmt_descriptor->length)); switch(pmt_descriptor->tag) { case 0x56: // Teletext descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_UNKNOWN; type_known = true; mxdebug_if(m_debug_pat_pmt, "mpeg_ts:parse_pmt: Teletext found but not handled !!\n"); } break; case 0x59: // Subtitles descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_SUBT_TYPE; track->fourcc = FOURCC('V', 'S', 'U', 'B'); type_known = true; } break; case 0x6A: // AC3 descriptor case 0x7A: // EAC3 descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); type_known = true; } break; case 0x7b: // DTS descriptor if (pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) { // PES containig private data track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('D', 'T', 'S', ' '); type_known = true; } break; case 0x0a: // ISO 639 language descriptor if (3 <= pmt_descriptor->length) { int language_idx = map_to_iso639_2_code(std::string(reinterpret_cast<char *>(pmt_descriptor + 1), 3).c_str()); if (-1 != language_idx) track->language = iso639_languages[language_idx].iso639_2_code; } break; } pmt_descriptor = (mpeg_ts_pmt_descriptor_t *)((unsigned char *)pmt_descriptor + sizeof(mpeg_ts_pmt_descriptor_t) + pmt_descriptor->length); } // Default to AC3 if it's a PES private stream type that's missing // a known/more concrete descriptor tag. if ((pmt_pid_info->stream_type == ISO_13818_PES_PRIVATE) && !type_known) { track->type = ES_AUDIO_TYPE; track->fourcc = FOURCC('A', 'C', '3', ' '); } pmt_pid_info = (mpeg_ts_pmt_pid_info_t *)((unsigned char *)pmt_pid_info + sizeof(mpeg_ts_pmt_pid_info_t) + es_info_length); if (track->type != ES_UNKNOWN) { PMT_found = true; track->pid = track->pid; track->processed = false; track->data_ready = false; tracks.push_back(track); es_to_process++; uint32_t fourcc = get_uint32_be(&track->fourcc); mxdebug_if(m_debug_pat_pmt, boost::format("mpeg_ts:parse_pmt: PID %1% has type: 0x%|2$08x| (%3%)\n") % track->pid % fourcc % std::string(reinterpret_cast<char *>(&fourcc), 4)); } } return 0; }
void exec_sendEvent(Chirp *chirp, uint32_t event) { if (chirp) CRP_SEND_XDATA(chirp, HTYPE(FOURCC('E','V','T','1')), INT32(event)); }
namespace FearGui { static int __cdecl nickNameAscend(const void *a,const void *b) { FGIRCNicknames::NickRep **entry_A = (FGIRCNicknames::NickRep **)(a); FGIRCNicknames::NickRep **entry_B = (FGIRCNicknames::NickRep **)(b); return (stricmp((*entry_A)->nick, (*entry_B)->nick)); } enum { NIName = 0, NICount }; static FGArrayCtrl::ColumnInfo gNicknameInfo[NICount] = { { IDSTR_NICKNAMES, 10, 300, 0, 0, TRUE, 90, nickNameAscend, NULL }, }; static FGArrayCtrl::ColumnInfo *gInfoPtrs[NICount]; IMPLEMENT_PERSISTENT_TAG(FGIRCNicknames, FOURCC('F','G','i','n')); bool FGIRCNicknames::onAdd() { if(!Parent::onAdd()) return false; //reset the fonts hFont = SimResource::loadByTag(manager, IDFNT_9_STANDARD, true); hFontHL = SimResource::loadByTag(manager, IDFNT_9_STATIC, true); hFontNA = SimResource::loadByTag(manager, IDFNT_9_DISABLED, true); hFontMO = SimResource::loadByTag(manager, IDFNT_9_HILITE, true); //load the icons mAwayBMP = SimResource::get(manager)->load("irc_icon_away.bmp"); AssertFatal(mAwayBMP, "Unable to load irc_icon_away.bmp"); mAwayBMP->attribute |= BMA_TRANSPARENT; mIgnoreBMP = SimResource::get(manager)->load("irc_icon_Ignore.bmp"); AssertFatal(mIgnoreBMP, "Unable to load irc_icon_Ignore.bmp"); mIgnoreBMP->attribute |= BMA_TRANSPARENT; mLockBMP = SimResource::get(manager)->load("irc_icon_Lock.bmp"); AssertFatal(mLockBMP, "Unable to load irc_icon_Lock.bmp"); mLockBMP->attribute |= BMA_TRANSPARENT; mMesgBMP = SimResource::get(manager)->load("irc_icon_Mesg.bmp"); AssertFatal(mMesgBMP, "Unable to load irc_icon_Mesg.bmp"); mMesgBMP->attribute |= BMA_TRANSPARENT; mOperBMP = SimResource::get(manager)->load("irc_icon_Oper.bmp"); AssertFatal(mOperBMP, "Unable to load irc_icon_Oper.bmp"); mOperBMP->attribute |= BMA_TRANSPARENT; mSpecBMP = SimResource::get(manager)->load("irc_icon_Spec.bmp"); AssertFatal(mSpecBMP, "Unable to load irc_icon_Spec.bmp"); mSpecBMP->attribute |= BMA_TRANSPARENT; mSpkrBMP = SimResource::get(manager)->load("irc_icon_Spkr.bmp"); AssertFatal(mSpkrBMP, "Unable to load irc_icon_Spkr.bmp"); mSpkrBMP->attribute |= BMA_TRANSPARENT; //other misc vars refresh = TRUE; numColumns = NICount; columnInfo = gInfoPtrs; //set the ptrs table for (int i = 0; i < NICount; i++) { gInfoPtrs[i] = &gNicknameInfo[i]; } //set the cell dimensions int width = 0; for (int k = 0; k < NICount; k++) { width += gInfoPtrs[k]->width; } cellSize.set(width, hFont->getHeight() + 6); prevSelected.set(-1, -1); //find the IRC client mIRCClient = ::IRCClient::find(manager); AssertFatal(mIRCClient, "IRCChatDelegate: unable to locate IRC client"); return true; } void FGIRCNicknames::onWake() { cellSize.set(max(cellSize.x, parent->extent.x), cellSize.y); setSize(Point2I( 1, 0)); refresh = TRUE; } void FGIRCNicknames::onPreRender() { // Keep the cell size up to date cellSize.set(max(cellSize.x, parent->extent.x), cellSize.y); // Build up the list of nicknames entries.clear(); entryPtrs.clear(); // Get the current channel ::IRCClient::Channel *channel = mIRCClient->findChannel(NULL); if (channel) { // Build up the nickname list for (int i = 0; i < channel->members.size(); i ++) { // Add the client to the list NickRep newNick; strcpy(newNick.nick, channel->members[i].person->nick); newNick.status = (channel->members[i].person->flags | channel->members[i].flags); entries.push_back(newNick); } setSize(Point2I(1, entries.size())); // Set up the pointers array for (int j = 0; j < entries.size(); j++) { entryPtrs.push_back(&entries[j]); } } else { setSize(Point2I(1, 0)); } } void FGIRCNicknames::onRenderCell(GFXSurface *sfc, Point2I offset, Point2I cell, bool sel, bool mouseOver) { IRCClient::Channel *channel = mIRCClient->findChannel(NULL); Point2I parentOffset = parent->localToGlobalCoord(Point2I(0, 0)); bool ghosted = FALSE; if (root) { SimGui::Control *topDialog = root->getDialogNumber(1); if ((! active) || (topDialog && (topDialog != getTopMostParent()) && (topDialog->findControlWithTag(IDCTG_DIALOG)))) { ghosted = TRUE; } } //initialize the font GFXFont *font; if (ghosted || (! cellSelectable(cell))) font = hFontNA; else if (sel) font = hFontHL; else if (mouseOver) font = hFontMO; else font = hFont; //initialize the draw offset Point2I drawOffset = offset; drawOffset.x += 2; //first draw the icon int iconWidth = mOperBMP->getWidth() + 3; GFXBitmap *bmp; if (entryPtrs[cell.y]->status & IRCClient::PERSON_IGNORE) { bmp = mIgnoreBMP; } else { if (entryPtrs[cell.y]->status & IRCClient::PERSON_AWAY) { bmp = mAwayBMP; } else if (entryPtrs[cell.y]->status & IRCClient::PERSON_OPERATOR) { bmp = mOperBMP; } else if (entryPtrs[cell.y]->status & IRCClient::PERSON_SPEAKER || (channel && !(channel->flags & IRCClient::CHANNEL_MODERATED))) { bmp = mSpkrBMP; } else { bmp = mSpecBMP; } } if (bmp && (! ghosted)) { sfc->drawBitmap2d(bmp, &Point2I(drawOffset.x, drawOffset.y + 2 + (cellSize.y - bmp->getHeight()) / 2)); } drawOffset.x += iconWidth; char *entryText = entryPtrs[cell.y]->nick; if (entryText) { drawInfoText(sfc, font, entryText, Point2I(drawOffset.x, drawOffset.y - 2), Point2I(columnInfo[0]->width - 4 - iconWidth, cellSize.y), TRUE, FALSE); } drawOffset.x += columnInfo[0]->width; } void FGIRCNicknames::onRender(GFXSurface *sfc, Point2I offset, const Box2I &updateRect) { Grandparent::onRender(sfc, offset, updateRect); } static char buffer[256]; char* FGIRCNicknames::getCellText(GFXSurface *, const Point2I &cell, const Point2I &, const Point2I &) { switch (cell.x) { case NIName: //NAME return entryPtrs[cell.y]->nick; } return NULL; } const char *FGIRCNicknames::getSelectedText() { if (selectedCell.y != -1) { return (entryPtrs[selectedCell.y]->nick); } return (NULL); } void FGIRCNicknames::onRightMouseDown(const Event &event) { onMouseDown(event); } void FGIRCNicknames::onMouseDown(const Event &event) { Parent::onMouseDown(event); if (event.mouseDownCount > 1) { if (selectedCell.y == prevSelected.y) { onMessage(this, IDIRC_MENUOPT_PRIVATE_CHAT); } } prevSelected = selectedCell; } void FGIRCNicknames::onRightMouseUp(const Event &event) { bool fIsMe; IRCClient *objIRCClient; IRCClient::Person *person; IRCClient::PersonInfo *info; IRCClient::Channel *channel = mIRCClient->findChannel(NULL); //find out in which cell the mouse was released Point2I pt = globalToLocalCoord(event.ptMouse); if (pt.x < 0 || pt.x >= extent.x) return; int cell = pt.y / cellSize.y; if (cell < 0 || cell != prevSelected.y) return; // Get our information person = mIRCClient->getMe(); if (person && channel) { info = channel->findPerson(person->nick); if (info && selectedCell.y != -1) { FGPopUpMenu *menu = new FGPopUpMenu; manager->addObject(menu); menu->onWake(); menu->setPos(event.ptMouse); // KICK menu entry is DISABLED if the current user (me) is not // an OPERATOR, or if the selected entry is me menu->appendMenu(MENU_STRING | ((!(info->flags & IRCClient::PERSON_OPERATOR) || !(stricmp(entryPtrs[selectedCell.y]->nick, person->nick))) ? MENU_DISABLED : 0), IDIRC_MENUOPT_KICK, SimTagDictionary::getString(manager, IDSTR_KICK_USER)); // BAN menu entry is DISABLED if the current user (me) is not // an OPERATOR, or if the selected entry is me menu->appendMenu(MENU_STRING | ((!(info->flags & IRCClient::PERSON_OPERATOR) || !(stricmp(entryPtrs[selectedCell.y]->nick, person->nick))) ? MENU_DISABLED : 0), IDIRC_MENUOPT_BAN, SimTagDictionary::getString(manager, IDSTR_BAN_UNBAN_USER)); // Space the entries menu->appendMenu(MENU_SEPARATOR); fIsMe = (stricmp(entryPtrs[selectedCell.y]->nick, person->nick) == 0); menu->appendMenu(MENU_STRING | (fIsMe ? MENU_DISABLED : 0), IDIRC_MENUOPT_PRIVATE_CHAT, SimTagDictionary::getString(manager, IDSTR_PRIVATE_CHAT)); menu->appendMenu(MENU_STRING | (fIsMe ? MENU_DISABLED : 0), IDIRC_MENUOPT_PING_USER, SimTagDictionary::getString(manager, IDSTR_PING_USER)); menu->appendMenu(MENU_STRING | (fIsMe ? MENU_DISABLED : 0), IDIRC_MENUOPT_WHOIS_USER, SimTagDictionary::getString(manager, IDSTR_WHO_IS_THIS)); menu->appendMenu(MENU_SEPARATOR); menu->appendMenu(MENU_STRING | (entryPtrs[selectedCell.y]->status & IRCClient::PERSON_AWAY ? MENU_CHECKED : 0) | (fIsMe ? 0 : MENU_DISABLED), IDIRC_MENUOPT_AWAY, SimTagDictionary::getString(manager, IDSTR_AWAY_FROM_KEYBOARD)); // IGNORE menu entry is CHECKED if we are currently ignoring the // selected entry menu->appendMenu(MENU_STRING | (entryPtrs[selectedCell.y]->status & IRCClient::PERSON_IGNORE ? MENU_CHECKED : 0) | (fIsMe ? MENU_DISABLED : 0), IDIRC_MENUOPT_IGNORE, SimTagDictionary::getString(manager, IDSTR_IGNORE_USER)); // Space the entries menu->appendMenu(MENU_SEPARATOR); // HOST menu entry is CHECKED if the selected entry is an OPERATOR, // and is DISABLED if the current user (me) is not an OPERATOR menu->appendMenu(MENU_STRING | ((entryPtrs[selectedCell.y]->status & IRCClient::PERSON_OPERATOR) ? MENU_CHECKED : 0) | ((info->flags & IRCClient::PERSON_OPERATOR) ? 0 : MENU_DISABLED), IDIRC_MENUOPT_OPER, SimTagDictionary::getString(manager, IDSTR_OPERATOR)); // SPEAKER menu entry is CHECKED if the selected entry is NOT an // OPERATOR and is either explicitly set as a SPEAKER or this // channel is NOT MODERATED. It is DISABLED if the current user // (me) is not an OPERATOR menu->appendMenu(MENU_STRING | ((!(entryPtrs[selectedCell.y]->status & IRCClient::PERSON_OPERATOR) && ((entryPtrs[selectedCell.y]->status & IRCClient::PERSON_SPEAKER) || (!(channel->flags & IRCClient::CHANNEL_MODERATED)))) ? MENU_CHECKED : 0) | ((info->flags & IRCClient::PERSON_OPERATOR) ? 0 : MENU_DISABLED), IDIRC_MENUOPT_SPKR, SimTagDictionary::getString(manager, IDSTR_SPEAKER)); // SPECTATOR menu entry is CHECKED if the selected entry is NOT an // OPERATOR and is NOT a SPEAKER and the channel is MODERATED. It // is DISABLED if the current user (me) is not an OPERATOR menu->appendMenu(MENU_STRING | ((info->flags & IRCClient::PERSON_OPERATOR) && (channel->flags & IRCClient::CHANNEL_MODERATED) ? 0 : MENU_DISABLED) | ((!(entryPtrs[selectedCell.y]->status & IRCClient::PERSON_OPERATOR) && (!(entryPtrs[selectedCell.y]->status & IRCClient::PERSON_SPEAKER)) && (channel->flags & IRCClient::CHANNEL_MODERATED)) ? MENU_CHECKED : 0), IDIRC_MENUOPT_SPEC, SimTagDictionary::getString(manager, IDSTR_SPECTATOR)); // Done, display the menu root->pushDialogControl(menu); } } } };
//----------------------------------------------------------------------------- // _ctmUncompressMesh_MG1() - Uncmpress the mesh from the input stream in the // CTM context, and store the resulting mesh in the CTM context. //----------------------------------------------------------------------------- int _ctmUncompressMesh_MG1(_CTMcontext * self) { CTMuint * indices; _CTMfloatmap * map; CTMuint i; // Allocate memory for the indices indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3); if(!indices) { self->mError = CTM_OUT_OF_MEMORY; return CTM_FALSE; } // Read triangle indices if(_ctmStreamReadUINT(self) != FOURCC("INDX")) { self->mError = CTM_BAD_FORMAT; free(indices); return CTM_FALSE; } if(!_ctmStreamReadPackedInts(self, (CTMint *) indices, self->mTriangleCount, 3, CTM_FALSE)) return CTM_FALSE; // Restore indices _ctmRestoreIndices(self, indices); for(i = 0; i < self->mTriangleCount * 3; ++ i) self->mIndices[i] = indices[i]; // Free temporary resources free(indices); // Read vertices if(_ctmStreamReadUINT(self) != FOURCC("VERT")) { self->mError = CTM_BAD_FORMAT; return CTM_FALSE; } if(!_ctmStreamReadPackedFloats(self, self->mVertices, self->mVertexCount * 3, 1)) return CTM_FALSE; // Read normals if(self->mNormals) { if(_ctmStreamReadUINT(self) != FOURCC("NORM")) { self->mError = CTM_BAD_FORMAT; return CTM_FALSE; } if(!_ctmStreamReadPackedFloats(self, self->mNormals, self->mVertexCount, 3)) return CTM_FALSE; } // Read UV maps map = self->mUVMaps; while(map) { if(_ctmStreamReadUINT(self) != FOURCC("TEXC")) { self->mError = CTM_BAD_FORMAT; return 0; } _ctmStreamReadSTRING(self, &map->mName); _ctmStreamReadSTRING(self, &map->mFileName); if(!_ctmStreamReadPackedFloats(self, map->mValues, self->mVertexCount, 2)) return CTM_FALSE; map = map->mNext; } // Read vertex attribute maps map = self->mAttribMaps; while(map) { if(_ctmStreamReadUINT(self) != FOURCC("ATTR")) { self->mError = CTM_BAD_FORMAT; return 0; } _ctmStreamReadSTRING(self, &map->mName); if(!_ctmStreamReadPackedFloats(self, map->mValues, self->mVertexCount, 4)) return CTM_FALSE; map = map->mNext; } return CTM_TRUE; }
int Interpreter::call(const QStringList &argv, bool interactive) { QMutexLocker locker(&m_chirp->m_mutex); ChirpProc proc; ProcInfo info; int args[20]; int i, j, k, n, base, res; bool ok; uint type; ArgList list; // not allowed if (argv.size()<1) return -1; // a procedure needs extension info (arg info, etc) in order for us to call... if ((proc=m_chirp->getProc(argv[0].toLocal8Bit()))>=0 && m_chirp->getProcInfo(proc, &info)>=0) { memset(args, 0, sizeof(args)); // zero args getArgs(&info, &list); n = strlen((char *)info.argTypes); // if we have fewer args than required... if ((int)list.size()>argv.size()-1) { // if we're interactive, ask for values if (interactive && argv.size()>0) { QStringList cargv = argv; QString pstring, pstring2; for (i=cargv.size()-1; i<(int)list.size(); i++) { if (info.argTypes[i]==CRP_TYPE_HINT) { if (n>i+4) { type = *(uint *)&info.argTypes[i+1]; if (type==FOURCC('R','E','G','1')) { emit videoInput(VideoWidget::REGION); pstring2 = "(select region with mouse)"; } if (type==FOURCC('P','N','T','1')) { emit videoInput(VideoWidget::POINT); pstring2 = "(select point with mouse)"; } emit enableConsole(false); } } k = i; pstring = printArgType(&info.argTypes[i], i) + " " + list[k].first + (list[k].second=="" ? "?" : " (" + list[k].second + ")?") + " " + pstring2; emit prompt(pstring); m_mutexInput.lock(); m_waiting = true; m_waitInput.wait(&m_mutexInput); m_waiting = false; m_mutexInput.unlock(); emit enableConsole(true); if (m_key==Qt::Key_Escape) return -1; cargv << m_command.split(QRegExp("\\s+")); } // call ourselves again, now that we have all the args return call(cargv, true); } else { emit error("too few arguments.\n"); return -1; } } augmentProcInfo(&info); // if we have all the args we need, parse, put in args array for (i=0, j=0; m_argTypes[i]; i++) { if (argv.size()>i+1) { if (m_argTypes[i]==CRP_INT8 || m_argTypes[i]==CRP_INT16 || m_argTypes[i]==CRP_INT32) { args[j++] = m_argTypes[i]; if (argv[i+1].left(2)=="0x") base = 16; else base = 10; args[j++] = argv[i+1].toInt(&ok, base); if (!ok) { emit error("argument didn't parse.\n"); return -1; } } #if 0 else if (m_argTypes[i]==CRP_STRING) { args[j++] = m_argTypes[i]; // string goes where? can't cast pointer to int... } #endif else { // deal with non-integer types return -1; } } } #if 0 // print helpful chirp argument string if (interactive && argv.size()>1) { QString callString = "Chirp arguments for " + argv[0] + " (ChirpProc=" + QString::number(proc) + "): "; for (i=1; i<argv.size(); i++) { if (i>1) callString += ", "; j = i; callString += printArgType(&m_argTypes[i-1], i) + "(" + argv[j] + ")"; } emit textOut(callString + "\n"); } #endif // make chirp call res = m_chirp->callAsync(proc, args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11], args[12], args[13], args[14], args[15], args[16], args[17], args[18], args[19], END_OUT_ARGS); // check for cable disconnect if (res<0 && !m_notified) //res==LIBUSB_ERROR_PIPE) { m_notified = true; emit connected(PIXY, false); return res; } // get response if we're not programming, save text if we are if (m_programming) addProgram(argv); else m_chirp->serviceChirp(); } else { emit error("procedure unsupported.\n"); return -1; } return 0; }
void ProcessThread::own_thread() { enum class Format { UNKNOWN, RAW8, RAW16, MJPEG, YUYV, BGR8 }; Format format = Format::UNKNOWN; int cv_format = CV_MAKETYPE( CV_8U, 1 ); sepia::Stream::image_header_t* hdr = m_input->getHeader( m_id ); switch( hdr->fourcc ) { case 0x00000000: if( hdr->bpp == 8 ) { format = Format::RAW8; cv_format = CV_MAKETYPE( CV_8U, 1 ); } else if( hdr->bpp == 16 ) { format = Format::RAW16; cv_format = CV_MAKETYPE( CV_16U, 1 ); } else if( hdr->bpp == 24 ) { format = Format::BGR8; cv_format = CV_MAKETYPE( CV_8U, 3 ); } break; case FOURCC( 'M', 'J', 'P', 'G'): format = Format::MJPEG; cv_format = CV_MAKETYPE( CV_8U, 3 ); // format after conversion break; default: break; } cv::Mat input_frame( m_input->getHeader( m_id )->height, m_input->getHeader( m_id )->width, cv_format, m_input->getAddress( m_id ) ); cv::Mat converted_frame( m_output->getHeader( m_id )->height, m_output->getHeader( m_id )->width, CV_8UC3 ); if( m_rectifier == NULL ) { converted_frame.data = reinterpret_cast< unsigned char* >( m_output->getAddress( m_id ) ); } cv::Mat rectified_frame( m_output->getHeader( m_id )->height, m_output->getHeader( m_id )->width, CV_8UC3, m_output->getAddress( m_id ) ); JpegDecoder decoder; while( !m_terminate ) { if( format == Format::RAW8 || format == Format::RAW16 ) { cv::demosaicing( input_frame, converted_frame, cv::COLOR_BayerBG2BGR_EA ); } else if( format == Format::MJPEG ) { // perform JPEG decode here decoder.readHeader( reinterpret_cast< unsigned char* >( input_frame.data ), m_input->getHeader( m_id )->size ); decoder.readData( reinterpret_cast< unsigned char* >( converted_frame.data ), m_input->getHeader( m_id )->width * 3, true ); } else { } if( m_rectifier != NULL ) { if( m_id == 0 ) { m_rectifier->remapLeft( &converted_frame, &rectified_frame ); } else if( m_id == 1 ) { m_rectifier->remapRight( &converted_frame, &rectified_frame ); } } m_barrier->wait(); if( m_id == 0 ) { m_output->update(); m_input->update(); } m_barrier->wait(); input_frame.data = reinterpret_cast< unsigned char* >( m_input->getAddress( m_id ) ); if( m_rectifier != NULL ) { rectified_frame.data = reinterpret_cast< unsigned char* >( m_output->getAddress( m_id ) ); } else { converted_frame.data = reinterpret_cast< unsigned char* >( m_output->getAddress( m_id ) ); } } }
int32_t cc_getRLSCCChirp(Chirp *chirp) { int16_t* c_components = new int16_t[MAX_BLOBS*4]; uint32_t numRls, result;//, prebuf; uint32_t *memory = (uint32_t *)RLS_MEMORY; result = cc_getRLSFrame(memory, LUT_MEMORY, &numRls); CBlobAssembler blobber; int32_t row; uint32_t i, startCol, length; uint8_t model; for (i=0, row=-1; i<numRls; i++) { if (memory[i]==0) { row++; continue; } model = memory[i]&0x03; memory[i] >>= 3; startCol = memory[i]&0x1ff; memory[i] >>= 9; length = memory[i]&0x1ff; if(!handleRL(&blobber, model, row, startCol, length)) break; } blobber.EndFrame(); blobber.SortFinished(); // // Take Finished blobs and return with chirp // CBlob *blob, *temp; blob = blobber.finishedBlobs; uint32_t cc_num = 0; temp = blob; while (temp) { int16_t top, right, bottom, left; temp->getBBox(left, top, right, bottom); // Don't want objects with area less than 9... if ((right-left)*(bottom-top) < 9) break; temp = temp->next; cc_num++; } // Remove the rest that we don't care about /*while(temp) { CBlob *next = temp->next; temp->~CBlob(); temp = NULL; temp = next; }*/ cc_num = (cc_num < 15) ? cc_num : MAX_BLOBS; // Populate return w/ result //void* mem = malloc(sizeof(int16_t)*cc_num*4); //if (mem == NULL) // int i = 0; //free(mem); //int16_t* c_components = new int16_t[cc_num*4]; //g_mem += sizeof(int16_t)*cc_num*4; memset((void *)c_components, 0, sizeof(uint16_t)*cc_num*4); for (int i = 0; i < cc_num; i++) { int16_t top, right, bottom, left; blob->getBBox(left, top, right, bottom); c_components[(i*4)+0] = top; c_components[(i*4)+1] = right; c_components[(i*4)+2] = bottom; c_components[(i*4)+3] = left; blob = blob->next; } //CRP_RETURN(chirp, USE_BUFFER(SRAM0_SIZE, SRAM0_LOC), HTYPE(0), UINT16(0), UINT16(0), UINTS8(0, 0), END); //prebuf = chirp->getPreBufLen(); blobber.Reset(); CRP_RETURN(chirp, HTYPE(FOURCC('V','I','S','U')), UINTS16(cc_num*4, c_components), END); delete[] c_components; //g_mem -= sizeof(int16_t)*cc_num*4; return result; }
static int convert_support_fourcc(int fourcc) { switch (fourcc) { case FOURCC('B','A','S','0'): return feature_bas0; case FOURCC('B','A','S','E'): return feature_base; case FOURCC('A','U','T','0'): return feature_auto; case FOURCC('U','C','M','0'): case FOURCC('U','C','M','D'): return feature_ucmd; case FOURCC('Z','L','I','F'): return feature_zlif; case FOURCC('B','B','S','0'): return feature_bbs; case FOURCC('T','I','G','R'): return feature_tiger; case FOURCC('B','L','O','M'): case FOURCC('B','L','O','0'): return feature_bloom; case FOURCC('P','I','N','G'): return feature_ping; case FOURCC('L','I','N','K'): return feature_link; case FOURCC('A','D','C','S'): return feature_adcs; // ignore these extensions, they are not useful for the hub. case FOURCC('D','H','T','0'): return 0; default: LOG_DEBUG("Unknown extension: %x", fourcc); return 0; } }
int main( int argc, char **argv ) { unicap_handle_t handle; unicap_device_t device; unicap_format_t format_spec; unicap_format_t format; unicap_data_buffer_t buffer; unicap_data_buffer_t *returned_buffer; int width, height; int i; SDL_Surface *screen; SDL_Overlay *overlay; int quit=0; int imgcnt = 0; printf( "select video device\n" ); for( i = 0; SUCCESS( unicap_enumerate_devices( NULL, &device, i ) ); i++ ) { printf( "%i: %s\n", i, device.identifier ); } if( --i > 0 ) { printf( "Select video capture device: " ); scanf( "%d", &i ); } if( !SUCCESS( unicap_enumerate_devices( NULL, &device, i ) ) ) { fprintf( stderr, "Failed to get info for device '%s'\n", device.identifier ); exit( 1 ); } /* Acquire a handle to this device */ if( !SUCCESS( unicap_open( &handle, &device ) ) ) { fprintf( stderr, "Failed to open device: %s\n", device.identifier ); exit( 1 ); } printf( "Opened video capture device: %s\n", device.identifier ); /* Create a format specification to limit the list of formats returned by unicap_enumerate_formats to the ones with the color format 'UYVY' */ unicap_void_format( &format_spec ); format_spec.fourcc = FOURCC('U','Y','V','Y'); /* Get the list of video formats of the colorformat UYVY */ for( i = 0; SUCCESS( unicap_enumerate_formats( handle, &format_spec, &format, i ) ); i++ ) { printf( "%d: %s [%dx%d]\n", i, format.identifier, format.size.width, format.size.height ); } if( --i > 0 ) { printf( "Select video format: " ); scanf( "%d", &i ); } if( !SUCCESS( unicap_enumerate_formats( handle, &format_spec, &format, i ) ) ) { fprintf( stderr, "Failed to get video format\n" ); exit( 1 ); } /* If a video format has more than one size, ask for which size to use */ if( format.size_count ) { for( i = 0; i < format.size_count; i++ ) { printf( "%d: %dx%d\n", i, format.sizes[i].width, format.sizes[i].height ); } do { printf( "Select video format size: " ); scanf( "%d", &i ); }while( ( i < 0 ) && ( i > format.size_count ) ); format.size.width = format.sizes[i].width; format.size.height = format.sizes[i].height; } /* Set this video format */ if( !SUCCESS( unicap_set_format( handle, &format ) ) ) { fprintf( stderr, "Failed to set video format\n" ); exit( 1 ); } /* Initialize the image buffer */ memset( &buffer, 0x0, sizeof( unicap_data_buffer_t ) ); /** Init SDL & SDL_Overlay **/ if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "Failed to initialize SDL: %s\n", SDL_GetError()); exit(1); } atexit(SDL_Quit); /* Make sure the video window does not get too big. */ width = MIN( format.size.width, 800 ); height = MIN( format.size.height, 600 ); screen = SDL_SetVideoMode( width, height, 32, SDL_HWSURFACE); if ( screen == NULL ) { fprintf(stderr, "Unable to set video mode: %s\n", SDL_GetError()); exit(1); } overlay = SDL_CreateYUVOverlay( format.size.width, format.size.height, SDL_UYVY_OVERLAY, screen ); if( overlay == NULL ) { fprintf( stderr, "Unable to create overlay: %s\n", SDL_GetError() ); exit( 1 ); } /* Pass the pointer to the overlay to the unicap data buffer. */ buffer.data = overlay->pixels[0]; buffer.buffer_size = format.size.width * format.size.height * format.bpp / 8; /* Start the capture process on the device */ if( !SUCCESS( unicap_start_capture( handle ) ) ) { fprintf( stderr, "Failed to start capture on device: %s\n", device.identifier ); exit( 1 ); } while( !quit ) { SDL_Rect rect; SDL_Event event; rect.x = 0; rect.y = 0; rect.w = width; rect.h = height; /* Queue the buffer The buffer now gets filled with image data by the capture device */ if( !SUCCESS( unicap_queue_buffer( handle, &buffer ) ) ) { fprintf( stderr, "Failed to queue a buffer on device: %s\n", device.identifier ); exit( 1 ); } /* Wait until the image buffer is ready */ if( !SUCCESS( unicap_wait_buffer( handle, &returned_buffer ) ) ) { fprintf( stderr, "Failed to wait for buffer on device: %s\n", device.identifier ); } /* Display the video data */ SDL_UnlockYUVOverlay( overlay ); SDL_DisplayYUVOverlay( overlay, &rect ); while( SDL_PollEvent( &event ) ) { switch( event.type ) { case SDL_QUIT: quit = 1; break; case SDL_MOUSEBUTTONDOWN: { unsigned char *pixels; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; FILE *outfile; JSAMPROW row_pointer[1]; int row_stride; char filename[128]; struct timeval t1, t2; unsigned long long usecs; sprintf( filename, "%04d.jpg", imgcnt++ ); cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); if ((outfile = fopen( filename, "wb" ) ) == NULL ) { fprintf(stderr, "can't open %s\n", "file"); exit(1); } jpeg_stdio_dest(&cinfo, outfile); cinfo.image_width = format.size.width; /* image width and height, in pixels */ cinfo.image_height = format.size.height; cinfo.input_components = 3; /* # of color components per pixel */ cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ jpeg_set_defaults(&cinfo); pixels = malloc( format.size.width * format.size.height * 3 ); uyvy2rgb24( pixels, returned_buffer->data, format.size.width * format.size.height * 3, format.size.width * format.size.height * 2 ); gettimeofday( &t1, NULL ); jpeg_start_compress(&cinfo, TRUE); while( cinfo.next_scanline < cinfo.image_height ) { row_pointer[0] = &pixels[cinfo.next_scanline * format.size.width * 3 ]; (void) jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); gettimeofday( &t2, NULL ); usecs = t2.tv_sec * 1000000LL + t2.tv_usec; usecs -= ( t1.tv_sec * 1000000LL + t1.tv_usec ); printf( "Compression took: %lld usec\n", usecs ); /* After finish_compress, we can close the output file. */ fclose(outfile); jpeg_destroy_compress(&cinfo); free( pixels ); } break; default: break; } } SDL_LockYUVOverlay(overlay); } /* Stop the device */ if( !SUCCESS( unicap_stop_capture( handle ) ) ) { fprintf( stderr, "Failed to stop capture on device: %s\n", device.identifier ); } /* Close the device This invalidates the handle */ if( !SUCCESS( unicap_close( handle ) ) ) { fprintf( stderr, "Failed to close the device: %s\n", device.identifier ); } SDL_Quit(); return 0; }
// To extract box 'tx3g' defined in 3GPP TS 26.245, and store it in a Parcel status_t TextDescriptions::extract3GPPGlobalDescriptions( const uint8_t *data, ssize_t size, Parcel *parcel, int depth) { ssize_t chunkSize = U32_AT(data); uint32_t chunkType = U32_AT(data + 4); const uint8_t *tmpData = data; tmpData += 8; if (size < chunkSize) { return OK; } if (depth == 0) { parcel->writeInt32(KEY_GLOBAL_SETTING); } switch(chunkType) { case FOURCC('t', 'x', '3', 'g'): { tmpData += 8; // skip the first 8 bytes parcel->writeInt32(KEY_DISPLAY_FLAGS); parcel->writeInt32(U32_AT(tmpData)); parcel->writeInt32(KEY_STRUCT_JUSTIFICATION); parcel->writeInt32(tmpData[4]); parcel->writeInt32(tmpData[5]); parcel->writeInt32(KEY_BACKGROUND_COLOR_RGBA); uint32_t rgba = *(tmpData + 6) << 24 | *(tmpData + 7) << 16 | *(tmpData + 8) << 8 | *(tmpData + 9); parcel->writeInt32(rgba); tmpData += 10; parcel->writeInt32(KEY_STRUCT_TEXT_POS); parcel->writeInt32(U16_AT(tmpData)); parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(U16_AT(tmpData + 6)); tmpData += 8; parcel->writeInt32(KEY_STRUCT_STYLE_LIST); parcel->writeInt32(KEY_START_CHAR); parcel->writeInt32(U16_AT(tmpData)); parcel->writeInt32(KEY_END_CHAR); parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(KEY_FONT_ID); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(KEY_STYLE_FLAGS); parcel->writeInt32(*(tmpData + 6)); parcel->writeInt32(KEY_FONT_SIZE); parcel->writeInt32(*(tmpData + 7)); parcel->writeInt32(KEY_TEXT_COLOR_RGBA); rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 | *(tmpData + 10) << 8 | *(tmpData + 11); parcel->writeInt32(rgba); tmpData += 12; parcel->writeInt32(KEY_STRUCT_FONT_LIST); uint16_t count = U16_AT(tmpData); parcel->writeInt32(count); tmpData += 2; for (int i = 0; i < count; i++) { // font ID parcel->writeInt32(U16_AT(tmpData)); // font name length parcel->writeInt32(*(tmpData + 2)); int len = *(tmpData + 2); parcel->write(tmpData + 3, len); tmpData += 3 + len; } break; } default: { break; } } data += chunkSize; size -= chunkSize; if (size > 0) { // continue to extract next 'tx3g' return extract3GPPGlobalDescriptions(data, size, parcel, 1); } return OK; }
status_t SampleTable::setSampleDescParams(uint32_t count, off64_t offset, size_t size) { // avcC atom will start after 78 bytes in avC1 atom const uint32_t avcC_offset = 78; for(uint32_t i = 0; i < count; ++i) { uint32_t hdr[2]; if (mDataSource->readAt(offset, hdr, 8) < 8) { return ERROR_IO; } uint64_t avc1_chunk_size = ntohl(hdr[0]); uint32_t avc1_chunk_type = ntohl(hdr[1]); off64_t avc1_data_offset = offset + 8; if(avc1_chunk_size == 0) return ERROR_MALFORMED; if (avc1_chunk_size == 1) { if (mDataSource->readAt(offset + 8, &avc1_chunk_size, 8) < 8) { return ERROR_IO; } avc1_chunk_size = ntoh64(avc1_chunk_size); if (avc1_chunk_size == 0) return ERROR_MALFORMED; avc1_data_offset += 8; if (avc1_chunk_size < 16) { // The smallest valid chunk is 16 bytes long in this case. return ERROR_MALFORMED; } } else if (avc1_chunk_size < 8) { // The smallest valid chunk is 8 bytes long. return ERROR_MALFORMED; } off64_t avc1_chunk_data_size = offset + avc1_chunk_size - avc1_data_offset; LOGV("parsing chunk %c%c%c%c", ((char *)&avc1_chunk_type)[3], ((char *)&avc1_chunk_type)[2], ((char *)&avc1_chunk_type)[1], ((char *)&avc1_chunk_type)[0]); if (avc1_chunk_type != FOURCC('a', 'v', 'c', '1')) { LOGE("Multiple Non AVC Sample Entries are not supported"); return ERROR_MALFORMED; } uint8_t *buffer = new uint8_t[(ssize_t)avc1_chunk_data_size]; if (mDataSource->readAt(avc1_data_offset, buffer, (ssize_t)avc1_chunk_data_size) < (ssize_t)avc1_chunk_data_size) { return ERROR_IO; } uint16_t data_ref_index = U16_AT(&buffer[6]); uint16_t width = U16_AT(&buffer[6 + 18]); uint16_t height = U16_AT(&buffer[6 + 20]); LOGE("data_ref_index : %d width : %d height: %d", data_ref_index, width, height); /* parse AVCC atom */ uint64_t avcc_chunk_size = U32_AT(&buffer[avcC_offset]); uint32_t avcc_chunk_type = U32_AT(&buffer[avcC_offset+4]);; if((avcc_chunk_size == 0)|| (avcc_chunk_size == 1)) { LOGE("chunk size error while reading avCC atom"); return ERROR_MALFORMED; } LOGV("parsing chunk %c%c%c%c", ((char *)&avcc_chunk_type)[3], ((char *)&avcc_chunk_type)[2], ((char *)&avcc_chunk_type)[1], ((char *)&avcc_chunk_type)[0]); if (avcc_chunk_type != FOURCC('a', 'v', 'c', 'C')) { LOGE("'avcC' atom expected, but not found"); return ERROR_MALFORMED; } off64_t avcc_chunk_data_size = avc1_chunk_data_size - avcC_offset - 8; SampleDescAtom *sda = new SampleDescAtom; uint8_t *avccBuffer = new uint8_t[avcc_chunk_data_size]; memcpy(avccBuffer, buffer+avcC_offset+8,avcc_chunk_data_size); sda->ptr = avccBuffer; sda->size = avcc_chunk_data_size; mSampleDescAtoms.push_back(sda); delete[] buffer; offset += avc1_chunk_size; } return OK; }
#include "internal_includes/tokens.h" #include "internal_includes/structs.h" #include "internal_includes/decode.h" #include "stdlib.h" #include "stdio.h" #include "internal_includes/reflect.h" #include "internal_includes/debug.h" #define FOURCC(a, b, c, d) ((uint32_t)(uint8_t)(a) | ((uint32_t)(uint8_t)(b) << 8) | ((uint32_t)(uint8_t)(c) << 16) | ((uint32_t)(uint8_t)(d) << 24 )) static enum {FOURCC_DXBC = FOURCC('D', 'X', 'B', 'C')}; //DirectX byte code static enum {FOURCC_SHDR = FOURCC('S', 'H', 'D', 'R')}; //Shader model 4 code static enum {FOURCC_SHEX = FOURCC('S', 'H', 'E', 'X')}; //Shader model 5 code static enum {FOURCC_RDEF = FOURCC('R', 'D', 'E', 'F')}; //Resource definition (e.g. constant buffers) static enum {FOURCC_ISGN = FOURCC('I', 'S', 'G', 'N')}; //Input signature static enum {FOURCC_IFCE = FOURCC('I', 'F', 'C', 'E')}; //Interface (for dynamic linking) static enum {FOURCC_OSGN = FOURCC('O', 'S', 'G', 'N')}; //Output signature typedef struct DXBCContainerHeaderTAG { unsigned fourcc; uint32_t unk[4]; uint32_t one; uint32_t totalSize; uint32_t chunkCount; } DXBCContainerHeader; typedef struct DXBCChunkHeaderTAG { unsigned fourcc; unsigned size; } DXBCChunkHeader;
FourCC GetWidgetTypeID() const {return FOURCC('LITE');}
#include <console.h> Door::Door() : MoveableBase() { } Door::~Door() { } int Door::getDatGroup() { return (DataBlockManager::DoorDataType); } IMPLEMENT_PERSISTENT_TAGS(Door, FOURCC('D', 'O', 'O', 'R'), DoorPersTag); Persistent::Base::Error Door::read(StreamIO &sio, int iVer, int iUsr) { return (Parent::read(sio, iVer, iUsr)); } Persistent::Base::Error Door::write(StreamIO &sio, int iVer, int iUsr) { return (Parent::write(sio, iVer, iUsr)); } void Door::onFirst() { if (const char *lpcszScript = scriptName("onClose")) {
int CDVDOverlayCodecTX3G::Decode(DemuxPacket *pPacket) { if (m_pOverlay) SAFE_RELEASE(m_pOverlay); uint8_t *data = pPacket->pData; int size = pPacket->iSize; m_pOverlay = new CDVDOverlayText(); CDVDOverlayCodec::GetAbsoluteTimes(m_pOverlay->iPTSStartTime, m_pOverlay->iPTSStopTime, pPacket, m_pOverlay->replace); // do not move this. READ_XXXX macros modify pos. uint8_t *pos = data; uint8_t *end = pos + size; // Parse the packet as a TX3G TextSample. // Look for a single StyleBox ('styl') and // read all contained StyleRecords. // Ignore all other box types. // NOTE: Buffer overflows on read are not checked. // ALSO: READ_XXXX/SKIP_XXXX macros will modify pos. uint16_t textLength = READ_U16(); uint8_t *text = READ_ARRAY(textLength); int numStyleRecords = 0; uint8_t *bgnStyle = (uint8_t*)calloc(textLength, 1); uint8_t *endStyle = (uint8_t*)calloc(textLength, 1); int bgnColorIndex = 0, endColorIndex = 0; uint32_t textColorRGBA = m_textColor; while (pos < end) { // Read TextSampleModifierBox uint32_t size = READ_U32(); if (size == 0) size = pos - end; // extends to end of packet if (size == 1) { CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported large size" ); break; } uint32_t type = READ_U32(); if (type == FOURCC("uuid")) { CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: TextSampleModifierBox has unsupported extended type" ); break; } if (type == FOURCC("styl")) { // Found a StyleBox. Parse the contained StyleRecords if ( numStyleRecords != 0 ) { CLog::Log(LOGDEBUG, "CDVDOverlayCodecTX3G: found additional StyleBoxes on subtitle; skipping" ); SKIP_ARRAY(size); continue; } numStyleRecords = READ_U16(); for (int i = 0; i < numStyleRecords; i++) { StyleRecord curRecord; curRecord.bgnChar = READ_U16(); curRecord.endChar = READ_U16(); curRecord.fontID = READ_U16(); curRecord.faceStyleFlags = READ_U8(); curRecord.fontSize = READ_U8(); curRecord.textColorRGBA = READ_U32(); bgnStyle[curRecord.bgnChar] |= curRecord.faceStyleFlags; endStyle[curRecord.endChar] |= curRecord.faceStyleFlags; bgnColorIndex = curRecord.bgnChar; endColorIndex = curRecord.endChar; textColorRGBA = curRecord.textColorRGBA; } } else { // Found some other kind of TextSampleModifierBox. Skip it. SKIP_ARRAY(size); } } // Copy text to out and add HTML markup for the style records int charIndex = 0; CStdStringA strUTF8; for (pos = text, end = text + textLength; pos < end; pos++) { if ((*pos & 0xC0) == 0x80) { // Is a non-first byte of a multi-byte UTF-8 character strUTF8.append((const char*)pos, 1); continue; // ...without incrementing 'charIndex' } uint8_t bgnStyles = bgnStyle[charIndex]; uint8_t endStyles = endStyle[charIndex]; // [B] or [/B] -> toggle bold on and off // [I] or [/I] -> toggle italics on and off // [COLOR ffab007f] or [/COLOR] -> toggle color on and off // [CAPS <option>] or [/CAPS] -> toggle capatilization on and off if (endStyles & BOLD) strUTF8.append("[/B]"); if (endStyles & ITALIC) strUTF8.append("[/I]"); // we do not support underline //if (endStyles & UNDERLINE) // strUTF8.append("[/U]"); if (endColorIndex == charIndex && textColorRGBA != m_textColor) strUTF8.append("[/COLOR]"); // invert the order from above so we bracket the text correctly. if (bgnColorIndex == charIndex && textColorRGBA != m_textColor) strUTF8.AppendFormat("[COLOR %8x]", textColorRGBA); // we do not support underline //if (bgnStyles & UNDERLINE) // strUTF8.append("[U]"); if (bgnStyles & ITALIC) strUTF8.append("[I]"); if (bgnStyles & BOLD) strUTF8.append("[B]"); // stuff the UTF8 char strUTF8.append((const char*)pos, 1); // this is a char index, not a byte index. charIndex++; } free(bgnStyle); free(endStyle); if (strUTF8.IsEmpty()) return OC_BUFFER; if (strUTF8[strUTF8.size()-1] == '\n') strUTF8.Delete(strUTF8.size()-1); // add a new text element to our container m_pOverlay->AddElement(new CDVDOverlayText::CElementText(strUTF8.c_str())); return OC_OVERLAY; }
void xtr_alac_c::create_file(xtr_base_c *master, KaxTrackEntry &track) { init_content_decoder(track); auto channels = kt_get_a_channels(track); auto priv = FindChild<KaxCodecPrivate>(&track); if (!priv) mxerror(boost::format(Y("Track %1% with the CodecID '%2%' is missing the \"codec private\" element and cannot be extracted.\n")) % m_tid % m_codec_id); m_priv = decode_codec_private(priv); if (m_priv->get_size() != sizeof(alac::codec_config_t)) mxerror(boost::format(Y("ALAC private data size mismatch\n"))); xtr_base_c::create_file(master, track); m_out->write(std::string{"caff"}); // mFileType m_out->write_uint16_be(1); // mFileVersion m_out->write_uint16_be(0); // mFileFlags m_out->write(std::string{"desc"}); // Audio Description chunk m_out->write_uint64_be(32ULL); // mChunkSize m_out->write_double(static_cast<int>(kt_get_a_sfreq(track))); // mSampleRate m_out->write(std::string{"alac"}); // mFormatID m_out->write_uint32_be(0); // mFormatFlags m_out->write_uint32_be(0); // mBytesPerPacket m_out->write_uint32_be(caf::defs::default_frames_per_packet); // mFramesPerPacket m_out->write_uint32_be(channels); // mChannelsPerFrame m_out->write_uint32_be(0); // mBitsPerChannel auto kuki_size = 12 + 36 + 8 + (2 < channels ? 24 : 0); // add the size of ALACChannelLayoutInfo for more than 2 channels m_out->write(std::string{"kuki"}); m_out->write_uint64_be(kuki_size); m_out->write_uint8('\0'); m_out->write_uint8('\0'); m_out->write_uint8('\0'); m_out->write_uint8('\14'); m_out->write(std::string{"frma"}); m_out->write(std::string{"alac"}); m_out->write_uint32_be(12 + sizeof(alac::codec_config_t)); // ALAC Specific Info size = 36 (12 + sizeof(ALAXSpecificConfig)) m_out->write(std::string{"alac"}); // ALAC Specific Info ID m_out->write_uint32_be(0L); // Version Flags m_out->write(m_priv); // audio specific config auto alo = caf::channel_layout_t(); if (2 < channels) { switch (channels) { case 3: alo.channel_layout_tag = caf::channel_layout_t::mpeg_3_0_b; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center; break; case 4: alo.channel_layout_tag = caf::channel_layout_t::mpeg_4_0_b; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::center_surround; break; case 5: alo.channel_layout_tag = caf::channel_layout_t::mpeg_5_0_d; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround; break; case 6: alo.channel_layout_tag = caf::channel_layout_t::mpeg_5_1_d; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround | caf::channel_layout_t::lfe_screen; break; case 7: alo.channel_layout_tag = caf::channel_layout_t::aac_6_1; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround | caf::channel_layout_t::center_surround | caf::channel_layout_t::lfe_screen; break; case 8: alo.channel_layout_tag = caf::channel_layout_t::mpeg_7_1_b; alo.channel_bitmap = caf::channel_layout_t::left | caf::channel_layout_t::right | caf::channel_layout_t::center | caf::channel_layout_t::left_center | caf::channel_layout_t::right_center | caf::channel_layout_t::left_surround | caf::channel_layout_t::right_surround | caf::channel_layout_t::lfe_screen; break; } auto acli = caf::channel_layout_info_t(); put_uint32_be(&acli.channel_layout_info_size, 24); // = sizeof(ALACChannelLayoutInfo) put_uint32_be(&acli.channel_layout_info_id, FOURCC('c', 'h', 'a', 'n')); // = 'chan' put_uint32_be(&acli.channel_layout_tag, alo.channel_layout_tag); m_out->write(&acli, sizeof(acli)); } // Terminator atom m_out->write_uint32_be(8); // Channel Layout Info Size m_out->write_uint32_be(0); // Channel Layout Info ID if (2 < channels) { m_out->write(std::string{"chan"}); // 'chan' chunk immediately following the kuki m_out->write_uint64_be(12ULL); // = sizeof(ALACAudioChannelLayout) m_out->write_uint32_be(alo.channel_layout_tag); m_out->write_uint32_be(alo.channel_bitmap); m_out->write_uint32_be(alo.number_channel_descriptions); } m_free_chunk_offset = m_out->getFilePointer(); // remember the location of m_free_chunk_size = 16384; auto free_chunk = memory_c::alloc(m_free_chunk_size); memset(free_chunk->get_buffer(), 0, sizeof(m_free_chunk_size)); // the 'free' chunk m_out->write(std::string{"free"}); m_out->write_uint64_be(m_free_chunk_size); m_out->write(free_chunk); m_data_chunk_offset = m_out->getFilePointer(); m_out->write(std::string{"data"}); // Audio Data Chunk m_out->write_uint64_be(-1LL); // mChunkSize (= -1 if unknown) m_out->write_uint32_be(1); // mEditCount }
namespace stagefright { // static const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o'); // static const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4'); // static const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z'); // static const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2'); const uint32_t kAuxTypeCenc = FOURCC('c', 'e', 'n', 'c'); static const uint32_t kMAX_ALLOCATION = (SIZE_MAX < INT32_MAX ? SIZE_MAX : INT32_MAX) - 128; //////////////////////////////////////////////////////////////////////////////// struct SampleTable::CompositionDeltaLookup { CompositionDeltaLookup(); void setEntries( const uint32_t *deltaEntries, size_t numDeltaEntries); uint32_t getCompositionTimeOffset(uint32_t sampleIndex); private: Mutex mLock; const uint32_t *mDeltaEntries; size_t mNumDeltaEntries; size_t mCurrentDeltaEntry; size_t mCurrentEntrySampleIndex; DISALLOW_EVIL_CONSTRUCTORS(CompositionDeltaLookup); }; SampleTable::CompositionDeltaLookup::CompositionDeltaLookup() : mDeltaEntries(NULL), mNumDeltaEntries(0), mCurrentDeltaEntry(0), mCurrentEntrySampleIndex(0) { } void SampleTable::CompositionDeltaLookup::setEntries( const uint32_t *deltaEntries, size_t numDeltaEntries) { Mutex::Autolock autolock(mLock); mDeltaEntries = deltaEntries; mNumDeltaEntries = numDeltaEntries; mCurrentDeltaEntry = 0; mCurrentEntrySampleIndex = 0; } uint32_t SampleTable::CompositionDeltaLookup::getCompositionTimeOffset( uint32_t sampleIndex) { Mutex::Autolock autolock(mLock); if (mDeltaEntries == NULL) { return 0; } if (sampleIndex < mCurrentEntrySampleIndex) { mCurrentDeltaEntry = 0; mCurrentEntrySampleIndex = 0; } while (mCurrentDeltaEntry < mNumDeltaEntries) { uint32_t sampleCount = mDeltaEntries[2 * mCurrentDeltaEntry]; if (sampleIndex < mCurrentEntrySampleIndex + sampleCount) { return mDeltaEntries[2 * mCurrentDeltaEntry + 1]; } mCurrentEntrySampleIndex += sampleCount; ++mCurrentDeltaEntry; } return 0; } //////////////////////////////////////////////////////////////////////////////// SampleTable::SampleTable(const sp<DataSource> &source) : mDataSource(source), mChunkOffsetOffset(-1), mChunkOffsetType(0), mNumChunkOffsets(0), mSampleToChunkOffset(-1), mNumSampleToChunkOffsets(0), mSampleSizeOffset(-1), mSampleSizeFieldSize(0), mDefaultSampleSize(0), mNumSampleSizes(0), mTimeToSampleCount(0), mTimeToSample(NULL), mSampleTimeEntries(NULL), mCompositionTimeDeltaEntries(NULL), mNumCompositionTimeDeltaEntries(0), mCompositionDeltaLookup(new CompositionDeltaLookup), mSyncSampleOffset(-1), mNumSyncSamples(0), mSyncSamples(NULL), mLastSyncSampleIndex(0), mSampleToChunkEntries(NULL), mCencInfo(NULL), mCencInfoCount(0), mCencDefaultSize(0) { mSampleIterator = new SampleIterator(this); } SampleTable::~SampleTable() { delete[] mSampleToChunkEntries; mSampleToChunkEntries = NULL; delete[] mSyncSamples; mSyncSamples = NULL; delete mCompositionDeltaLookup; mCompositionDeltaLookup = NULL; delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; delete[] mSampleTimeEntries; mSampleTimeEntries = NULL; delete[] mTimeToSample; mTimeToSample = NULL; if (mCencInfo) { for (uint32_t i = 0; i < mCencInfoCount; i++) { if (mCencInfo[i].mSubsamples) { delete[] mCencInfo[i].mSubsamples; } } delete[] mCencInfo; } delete mSampleIterator; mSampleIterator = NULL; } bool SampleTable::isValid() const { return mChunkOffsetOffset >= 0 && mSampleToChunkOffset >= 0 && mSampleSizeOffset >= 0 && mTimeToSample != NULL; } status_t SampleTable::setChunkOffsetParams( uint32_t type, off64_t data_offset, size_t data_size) { if (mChunkOffsetOffset >= 0) { return ERROR_MALFORMED; } CHECK(type == kChunkOffsetType32 || type == kChunkOffsetType64); mChunkOffsetOffset = data_offset; mChunkOffsetType = type; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumChunkOffsets = U32_AT(&header[4]); if (mChunkOffsetType == kChunkOffsetType32) { if (data_size < 8 + (uint64_t)mNumChunkOffsets * 4) { return ERROR_MALFORMED; } } else { if (data_size < 8 + (uint64_t)mNumChunkOffsets * 8) { return ERROR_MALFORMED; } } return OK; } status_t SampleTable::setSampleToChunkParams( off64_t data_offset, size_t data_size) { if (mSampleToChunkOffset >= 0) { return ERROR_MALFORMED; } mSampleToChunkOffset = data_offset; if (data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSampleToChunkOffsets = U32_AT(&header[4]); if (data_size < 8 + (uint64_t)mNumSampleToChunkOffsets * 12) { return ERROR_MALFORMED; } mSampleToChunkEntries = new SampleToChunkEntry[mNumSampleToChunkOffsets]; for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) { uint8_t buffer[12]; if (mDataSource->readAt( mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer)) != (ssize_t)sizeof(buffer)) { return ERROR_IO; } if (!U32_AT(buffer)) { ALOGE("error reading sample to chunk table"); return ERROR_MALFORMED; // chunk index is 1 based in the spec. } // We want the chunk index to be 0-based. mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1; mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]); mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]); } return OK; } status_t SampleTable::setSampleSizeParams( uint32_t type, off64_t data_offset, size_t data_size) { if (mSampleSizeOffset >= 0) { return ERROR_MALFORMED; } CHECK(type == kSampleSizeType32 || type == kSampleSizeTypeCompact); mSampleSizeOffset = data_offset; if (data_size < 12) { return ERROR_MALFORMED; } uint8_t header[12]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mDefaultSampleSize = U32_AT(&header[4]); mNumSampleSizes = U32_AT(&header[8]); if (type == kSampleSizeType32) { mSampleSizeFieldSize = 32; if (mDefaultSampleSize != 0) { return OK; } if (data_size < 12 + (uint64_t)mNumSampleSizes * 4) { return ERROR_MALFORMED; } } else { if ((mDefaultSampleSize & 0xffffff00) != 0) { // The high 24 bits are reserved and must be 0. return ERROR_MALFORMED; } mSampleSizeFieldSize = mDefaultSampleSize & 0xff; mDefaultSampleSize = 0; if (mSampleSizeFieldSize != 4 && mSampleSizeFieldSize != 8 && mSampleSizeFieldSize != 16) { return ERROR_MALFORMED; } if (data_size < 12 + ((uint64_t)mNumSampleSizes * mSampleSizeFieldSize + 4) / 8) { return ERROR_MALFORMED; } } return OK; } status_t SampleTable::setTimeToSampleParams( off64_t data_offset, size_t data_size) { if (mTimeToSample != NULL || data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mTimeToSampleCount = U32_AT(&header[4]); if (mTimeToSampleCount > kMAX_ALLOCATION / 2 / sizeof(uint32_t)) { // Avoid later overflow. return ERROR_MALFORMED; } mTimeToSample = new uint32_t[mTimeToSampleCount * 2]; size_t size = sizeof(uint32_t) * mTimeToSampleCount * 2; if (mDataSource->readAt( data_offset + 8, mTimeToSample, size) < (ssize_t)size) { return ERROR_IO; } for (uint32_t i = 0; i < mTimeToSampleCount * 2; ++i) { mTimeToSample[i] = ntohl(mTimeToSample[i]); } return OK; } status_t SampleTable::setCompositionTimeToSampleParams( off64_t data_offset, size_t data_size) { ALOGI("There are reordered frames present."); if (mCompositionTimeDeltaEntries != NULL || data_size < 8) { return ERROR_MALFORMED; } uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } uint32_t numEntries = U32_AT(&header[4]); if (data_size != ((uint64_t)numEntries + 1) * 8) { return ERROR_MALFORMED; } mNumCompositionTimeDeltaEntries = numEntries; mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries]; if (mDataSource->readAt( data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8) < (ssize_t)numEntries * 8) { delete[] mCompositionTimeDeltaEntries; mCompositionTimeDeltaEntries = NULL; return ERROR_IO; } for (size_t i = 0; i < 2 * numEntries; ++i) { mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]); } mCompositionDeltaLookup->setEntries( mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries); return OK; } status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) { if (mSyncSampleOffset >= 0 || data_size < 8) { return ERROR_MALFORMED; } mSyncSampleOffset = data_offset; uint8_t header[8]; if (mDataSource->readAt( data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) { return ERROR_IO; } if (U32_AT(header) != 0) { // Expected version = 0, flags = 0. return ERROR_MALFORMED; } mNumSyncSamples = U32_AT(&header[4]); if (mNumSyncSamples > kMAX_ALLOCATION / sizeof(uint32_t)) { // Avoid later overflow. return ERROR_MALFORMED; } if (mNumSyncSamples < 2) { ALOGV("Table of sync samples is empty or has only a single entry!"); } mSyncSamples = new uint32_t[mNumSyncSamples]; size_t size = mNumSyncSamples * sizeof(uint32_t); if (mDataSource->readAt(mSyncSampleOffset + 8, mSyncSamples, size) != (ssize_t)size) { return ERROR_IO; } for (size_t i = 0; i < mNumSyncSamples; ++i) { mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1; } return OK; } static status_t validateCencBoxHeader( sp<DataSource>& data_source, off64_t& data_offset, uint8_t* out_version, uint32_t* out_aux_type) { *out_aux_type = 0; if (data_source->readAt(data_offset++, out_version, 1) < 1) { ALOGE("error reading sample aux info header"); return ERROR_IO; } uint32_t flags; if (!data_source->getUInt24(data_offset, &flags)) { ALOGE("error reading sample aux info flags"); return ERROR_IO; } data_offset += 3; if (flags & 1) { uint32_t aux_type; uint32_t aux_param; if (!data_source->getUInt32(data_offset, &aux_type) || !data_source->getUInt32(data_offset + 4, &aux_param)) { ALOGE("error reading aux info type"); return ERROR_IO; } data_offset += 8; *out_aux_type = aux_type; } return OK; } status_t SampleTable::setSampleAuxiliaryInformationSizeParams( off64_t data_offset, size_t data_size, uint32_t drm_scheme) { off64_t data_end = data_offset + data_size; uint8_t version; uint32_t aux_type; status_t err = validateCencBoxHeader( mDataSource, data_offset, &version, &aux_type); if (err != OK) { return err; } if (aux_type && aux_type != kAuxTypeCenc && drm_scheme != kAuxTypeCenc) { // Quietly skip aux types we don't care about. return OK; } if (!mCencSizes.isEmpty() || mCencDefaultSize) { ALOGE("duplicate cenc saiz box"); return ERROR_MALFORMED; } if (version) { ALOGV("unsupported cenc saiz version"); return ERROR_UNSUPPORTED; } if (mDataSource->readAt( data_offset++, &mCencDefaultSize, sizeof(mCencDefaultSize)) < sizeof(mCencDefaultSize)) { return ERROR_IO; } if (!mDataSource->getUInt32(data_offset, &mCencInfoCount)) { return ERROR_IO; } data_offset += 4; if (!mCencDefaultSize) { mCencSizes.insertAt(0, 0, mCencInfoCount); if (mDataSource->readAt( data_offset, mCencSizes.editArray(), mCencInfoCount) < mCencInfoCount) { return ERROR_IO; } data_offset += mCencInfoCount; } CHECK(data_offset == data_end); return parseSampleCencInfo(); } status_t SampleTable::setSampleAuxiliaryInformationOffsetParams( off64_t data_offset, size_t data_size, uint32_t drm_scheme) { off64_t data_end = data_offset + data_size; uint8_t version; uint32_t aux_type; status_t err = validateCencBoxHeader(mDataSource, data_offset, &version, &aux_type); if (err != OK) { return err; } if (aux_type && aux_type != kAuxTypeCenc && drm_scheme != kAuxTypeCenc) { // Quietly skip aux types we don't care about. return OK; } if (!mCencOffsets.isEmpty()) { ALOGE("duplicate cenc saio box"); return ERROR_MALFORMED; } uint32_t cencOffsetCount; if (!mDataSource->getUInt32(data_offset, &cencOffsetCount)) { ALOGE("error reading cenc aux info offset count"); return ERROR_IO; } data_offset += 4; mCencOffsets.setCapacity(cencOffsetCount); if (!version) { for (uint32_t i = 0; i < cencOffsetCount; i++) { uint32_t tmp; if (!mDataSource->getUInt32(data_offset, &tmp)) { ALOGE("error reading cenc aux info offsets"); return ERROR_IO; } mCencOffsets.push(tmp); data_offset += 4; } } else { for (uint32_t i = 0; i < cencOffsetCount; i++) { if (!mDataSource->getUInt64(data_offset, &mCencOffsets.editItemAt(i))) { ALOGE("error reading cenc aux info offsets"); return ERROR_IO; } data_offset += 8; } } CHECK(data_offset == data_end); return parseSampleCencInfo(); } status_t SampleTable::parseSampleCencInfo() { if ((!mCencDefaultSize && !mCencInfoCount) || mCencOffsets.isEmpty()) { // We don't have all the cenc information we need yet. Quietly fail and // hope we get the data we need later in the track header. ALOGV("Got half of cenc saio/saiz pair. Deferring parse until we get the other half."); return OK; } if (!mCencSizes.isEmpty() && mCencOffsets.size() > 1 && mCencSizes.size() != mCencOffsets.size()) { return ERROR_MALFORMED; } if (mCencInfoCount > kMAX_ALLOCATION / sizeof(SampleCencInfo)) { // Avoid future OOM. return ERROR_MALFORMED; } mCencInfo = new SampleCencInfo[mCencInfoCount]; for (uint32_t i = 0; i < mCencInfoCount; i++) { mCencInfo[i].mSubsamples = NULL; } uint64_t nextOffset = mCencOffsets[0]; for (uint32_t i = 0; i < mCencInfoCount; i++) { uint8_t size = mCencDefaultSize ? mCencDefaultSize : mCencSizes[i]; uint64_t offset = mCencOffsets.size() == 1 ? nextOffset : mCencOffsets[i]; nextOffset = offset + size; auto& info = mCencInfo[i]; if (size < IV_BYTES) { ALOGE("cenc aux info too small"); return ERROR_MALFORMED; } if (mDataSource->readAt(offset, info.mIV, IV_BYTES) < IV_BYTES) { ALOGE("couldn't read init vector"); return ERROR_IO; } offset += IV_BYTES; if (size == IV_BYTES) { info.mSubsampleCount = 0; continue; } if (size < IV_BYTES + sizeof(info.mSubsampleCount)) { ALOGE("subsample count overflows sample aux info buffer"); return ERROR_MALFORMED; } if (!mDataSource->getUInt16(offset, &info.mSubsampleCount)) { ALOGE("error reading sample cenc info subsample count"); return ERROR_IO; } offset += sizeof(info.mSubsampleCount); if (size < IV_BYTES + sizeof(info.mSubsampleCount) + info.mSubsampleCount * 6) { ALOGE("subsample descriptions overflow sample aux info buffer"); return ERROR_MALFORMED; } info.mSubsamples = new SampleCencInfo::SubsampleSizes[info.mSubsampleCount]; for (uint16_t j = 0; j < info.mSubsampleCount; j++) { auto& subsample = info.mSubsamples[j]; if (!mDataSource->getUInt16(offset, &subsample.mClearBytes) || !mDataSource->getUInt32(offset + sizeof(subsample.mClearBytes), &subsample.mCipherBytes)) { ALOGE("error reading cenc subsample aux info"); return ERROR_IO; } offset += 6; } } return OK; } uint32_t SampleTable::countChunkOffsets() const { return mNumChunkOffsets; } uint32_t SampleTable::countSamples() const { return mNumSampleSizes; } status_t SampleTable::getMaxSampleSize(size_t *max_size) { Mutex::Autolock autoLock(mLock); *max_size = 0; for (uint32_t i = 0; i < mNumSampleSizes; ++i) { size_t sample_size; status_t err = getSampleSize_l(i, &sample_size); if (err != OK) { return err; } if (sample_size > *max_size) { *max_size = sample_size; } } return OK; } uint32_t abs_difference(uint32_t time1, uint32_t time2) { return time1 > time2 ? time1 - time2 : time2 - time1; } // static int SampleTable::CompareIncreasingTime(const void *_a, const void *_b) { const SampleTimeEntry *a = (const SampleTimeEntry *)_a; const SampleTimeEntry *b = (const SampleTimeEntry *)_b; if (a->mCompositionTime < b->mCompositionTime) { return -1; } else if (a->mCompositionTime > b->mCompositionTime) { return 1; } return 0; } void SampleTable::buildSampleEntriesTable() { Mutex::Autolock autoLock(mLock); if (mSampleTimeEntries != NULL) { return; } mSampleTimeEntries = new SampleTimeEntry[mNumSampleSizes]; uint32_t sampleIndex = 0; uint32_t sampleTime = 0; for (uint32_t i = 0; i < mTimeToSampleCount; ++i) { uint32_t n = mTimeToSample[2 * i]; uint32_t delta = mTimeToSample[2 * i + 1]; for (uint32_t j = 0; j < n; ++j) { if (sampleIndex < mNumSampleSizes) { // Technically this should always be the case if the file // is well-formed, but you know... there's (gasp) malformed // content out there. mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex; uint32_t compTimeDelta = mCompositionDeltaLookup->getCompositionTimeOffset( sampleIndex); mSampleTimeEntries[sampleIndex].mCompositionTime = sampleTime + compTimeDelta; } ++sampleIndex; sampleTime += delta; } } qsort(mSampleTimeEntries, mNumSampleSizes, sizeof(SampleTimeEntry), CompareIncreasingTime); } status_t SampleTable::findSampleAtTime( uint32_t req_time, uint32_t *sample_index, uint32_t flags) { buildSampleEntriesTable(); uint32_t left = 0; uint32_t right = mNumSampleSizes; while (left < right) { uint32_t center = (left + right) / 2; uint32_t centerTime = mSampleTimeEntries[center].mCompositionTime; if (req_time < centerTime) { right = center; } else if (req_time > centerTime) { left = center + 1; } else { left = center; break; } } if (left == mNumSampleSizes) { if (flags == kFlagAfter) { return ERROR_OUT_OF_RANGE; } --left; } uint32_t closestIndex = left; switch (flags) { case kFlagBefore: { while (closestIndex > 0 && mSampleTimeEntries[closestIndex].mCompositionTime > req_time) { --closestIndex; } break; } case kFlagAfter: { while (closestIndex + 1 < mNumSampleSizes && mSampleTimeEntries[closestIndex].mCompositionTime < req_time) { ++closestIndex; } break; } default: { CHECK(flags == kFlagClosest); if (closestIndex > 0) { // Check left neighbour and pick closest. uint32_t absdiff1 = abs_difference( mSampleTimeEntries[closestIndex].mCompositionTime, req_time); uint32_t absdiff2 = abs_difference( mSampleTimeEntries[closestIndex - 1].mCompositionTime, req_time); if (absdiff1 > absdiff2) { closestIndex = closestIndex - 1; } } break; } } *sample_index = mSampleTimeEntries[closestIndex].mSampleIndex; return OK; } status_t SampleTable::findSyncSampleNear( uint32_t start_sample_index, uint32_t *sample_index, uint32_t flags) { Mutex::Autolock autoLock(mLock); *sample_index = 0; if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = start_sample_index; return OK; } if (mNumSyncSamples == 0) { *sample_index = 0; return OK; } uint32_t left = 0; uint32_t right = mNumSyncSamples; while (left < right) { uint32_t center = left + (right - left) / 2; uint32_t x = mSyncSamples[center]; if (start_sample_index < x) { right = center; } else if (start_sample_index > x) { left = center + 1; } else { left = center; break; } } if (left == mNumSyncSamples) { if (flags == kFlagAfter) { ALOGE("tried to find a sync frame after the last one: %d", left); return ERROR_OUT_OF_RANGE; } left = left - 1; } // Now ssi[left] is the sync sample index just before (or at) // start_sample_index. // Also start_sample_index < ssi[left + 1], if left + 1 < mNumSyncSamples. uint32_t x = mSyncSamples[left]; if (left + 1 < mNumSyncSamples) { uint32_t y = mSyncSamples[left + 1]; // our sample lies between sync samples x and y. status_t err = mSampleIterator->seekTo(start_sample_index); if (err != OK) { return err; } uint32_t sample_time = mSampleIterator->getSampleTime(); err = mSampleIterator->seekTo(x); if (err != OK) { return err; } uint32_t x_time = mSampleIterator->getSampleTime(); err = mSampleIterator->seekTo(y); if (err != OK) { return err; } uint32_t y_time = mSampleIterator->getSampleTime(); if (abs_difference(x_time, sample_time) > abs_difference(y_time, sample_time)) { // Pick the sync sample closest (timewise) to the start-sample. x = y; ++left; } } switch (flags) { case kFlagBefore: { if (x > start_sample_index) { CHECK(left > 0); x = mSyncSamples[left - 1]; if (x > start_sample_index) { // The table of sync sample indices was not sorted // properly. return ERROR_MALFORMED; } } break; } case kFlagAfter: { if (x < start_sample_index) { if (left + 1 >= mNumSyncSamples) { return ERROR_OUT_OF_RANGE; } x = mSyncSamples[left + 1]; if (x < start_sample_index) { // The table of sync sample indices was not sorted // properly. return ERROR_MALFORMED; } } break; } default: break; } *sample_index = x; return OK; } status_t SampleTable::findThumbnailSample(uint32_t *sample_index) { Mutex::Autolock autoLock(mLock); if (mSyncSampleOffset < 0) { // All samples are sync-samples. *sample_index = 0; return OK; } uint32_t bestSampleIndex = 0; size_t maxSampleSize = 0; static const size_t kMaxNumSyncSamplesToScan = 20; // Consider the first kMaxNumSyncSamplesToScan sync samples and // pick the one with the largest (compressed) size as the thumbnail. size_t numSamplesToScan = mNumSyncSamples; if (numSamplesToScan > kMaxNumSyncSamplesToScan) { numSamplesToScan = kMaxNumSyncSamplesToScan; } for (size_t i = 0; i < numSamplesToScan; ++i) { uint32_t x = mSyncSamples[i]; // Now x is a sample index. size_t sampleSize; status_t err = getSampleSize_l(x, &sampleSize); if (err != OK) { return err; } if (i == 0 || sampleSize > maxSampleSize) { bestSampleIndex = x; maxSampleSize = sampleSize; } } *sample_index = bestSampleIndex; return OK; } status_t SampleTable::getSampleSize_l( uint32_t sampleIndex, size_t *sampleSize) { return mSampleIterator->getSampleSizeDirect( sampleIndex, sampleSize); } status_t SampleTable::getMetaDataForSample( uint32_t sampleIndex, off64_t *offset, size_t *size, uint32_t *compositionTime, uint32_t *duration, bool *isSyncSample, uint32_t *decodeTime) { Mutex::Autolock autoLock(mLock); status_t err; if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) { return err; } if (offset) { *offset = mSampleIterator->getSampleOffset(); } if (size) { *size = mSampleIterator->getSampleSize(); } if (compositionTime) { *compositionTime = mSampleIterator->getSampleTime(); } if (decodeTime) { *decodeTime = mSampleIterator->getSampleDecodeTime(); } if (duration) { *duration = mSampleIterator->getSampleDuration(); } if (isSyncSample) { *isSyncSample = false; if (mSyncSampleOffset < 0) { // Every sample is a sync sample. *isSyncSample = true; } else { size_t i = (mLastSyncSampleIndex < mNumSyncSamples) && (mSyncSamples[mLastSyncSampleIndex] <= sampleIndex) ? mLastSyncSampleIndex : 0; while (i < mNumSyncSamples && mSyncSamples[i] < sampleIndex) { ++i; } if (i < mNumSyncSamples && mSyncSamples[i] == sampleIndex) { *isSyncSample = true; } mLastSyncSampleIndex = i; } } return OK; } uint32_t SampleTable::getCompositionTimeOffset(uint32_t sampleIndex) { return mCompositionDeltaLookup->getCompositionTimeOffset(sampleIndex); } status_t SampleTable::getSampleCencInfo( uint32_t sample_index, Vector<uint16_t>& clear_sizes, Vector<uint32_t>& cipher_sizes, uint8_t iv[]) { CHECK(clear_sizes.isEmpty() && cipher_sizes.isEmpty()); if (sample_index >= mCencInfoCount) { ALOGE("cenc info requested for out of range sample index"); return ERROR_MALFORMED; } auto& info = mCencInfo[sample_index]; clear_sizes.setCapacity(info.mSubsampleCount); cipher_sizes.setCapacity(info.mSubsampleCount); for (uint32_t i = 0; i < info.mSubsampleCount; i++) { clear_sizes.push(info.mSubsamples[i].mClearBytes); cipher_sizes.push(info.mSubsamples[i].mCipherBytes); } memcpy(iv, info.mIV, IV_BYTES); return OK; } } // namespace stagefright
#include <swscale.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> } #define FOURCC(a,b,c,d) (unsigned int)((((unsigned int)a))+(((unsigned int)b)<<8)+(((unsigned int)c)<<16)+(((unsigned int)d)<<24)) typedef struct PixelFormatTag { PixelFormat pix_fmt; unsigned int fourcc; } PixelFormatTag; static const PixelFormatTag pixelFormatTags[] = { /* Planar formats */ { PIX_FMT_YUV420P, FOURCC('I', '4', '2', '0') }, { PIX_FMT_YUV420P, FOURCC('I', 'Y', 'U', 'V') }, { PIX_FMT_YUV420P, FOURCC('Y', 'V', '1', '2') }, { PIX_FMT_YUV410P, FOURCC('Y', 'U', 'V', '9') }, { PIX_FMT_YUV411P, FOURCC('Y', '4', '1', 'B') }, { PIX_FMT_YUV422P, FOURCC('Y', '4', '2', 'B') }, { PIX_FMT_GRAY8, FOURCC('Y', '8', '0', '0') }, { PIX_FMT_GRAY8, FOURCC(' ', ' ', 'Y', '8') }, //v4l { PIX_FMT_GRAY8, FOURCC('G', 'R', 'E', 'Y') }, //{ PIX_FMT_... FOURCC('H', '2', '4', '0') }, //HI420 BT848, seems to not exist in ffmpeg { PIX_FMT_RGB565, FOURCC('R', 'G', 'B', '6') }, //RGB565 { PIX_FMT_RGB555 , FOURCC('R', 'G', 'B', '5') }, //RGB15 { PIX_FMT_RGB32, FOURCC('R', 'G', 'B', '4') }, //RGB32 { PIX_FMT_YUYV422, FOURCC('Y', 'U', 'Y', 'V') },
// Extract the local 3GPP display descriptions. 3GPP local descriptions // are appended to the text sample if any. The descriptions could include // information such as text styles, highlights, karaoke and so on. They // are contained in different boxes, such as 'styl' box contains text // styles, and 'krok' box contains karaoke timing and positions. status_t TextDescriptions::extract3GPPLocalDescriptions( const uint8_t *data, ssize_t size, int timeMs, Parcel *parcel) { parcel->writeInt32(KEY_LOCAL_SETTING); // write start time to display this text sample parcel->writeInt32(KEY_START_TIME); parcel->writeInt32(timeMs); if (size < 2) { return OK; } ssize_t textLen = (*data) << 8 | (*(data + 1)); if (size < textLen + 2) { return OK; } // write text sample length and text sample itself parcel->writeInt32(KEY_STRUCT_TEXT); parcel->writeInt32(textLen); parcel->writeInt32(textLen); parcel->write(data + 2, textLen); if (size > textLen + 2) { data += (textLen + 2); size -= (textLen + 2); } else { return OK; } while (size >= 8) { const uint8_t *tmpData = data; ssize_t chunkSize = U32_AT(tmpData); // size includes size and type uint32_t chunkType = U32_AT(tmpData + 4); if (chunkSize <= 8 || chunkSize > size) { return OK; } size_t remaining = chunkSize - 8; tmpData += 8; switch(chunkType) { // 'styl' box specifies the style of the text. case FOURCC('s', 't', 'y', 'l'): { if (remaining < 2) { return OK; } size_t dataPos = parcel->dataPosition(); uint16_t count = U16_AT(tmpData); tmpData += 2; remaining -= 2; for (int i = 0; i < count; i++) { if (remaining < 12) { // roll back parcel->setDataPosition(dataPos); return OK; } parcel->writeInt32(KEY_STRUCT_STYLE_LIST); parcel->writeInt32(KEY_START_CHAR); parcel->writeInt32(U16_AT(tmpData)); parcel->writeInt32(KEY_END_CHAR); parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(KEY_FONT_ID); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(KEY_STYLE_FLAGS); parcel->writeInt32(*(tmpData + 6)); parcel->writeInt32(KEY_FONT_SIZE); parcel->writeInt32(*(tmpData + 7)); parcel->writeInt32(KEY_TEXT_COLOR_RGBA); uint32_t rgba = *(tmpData + 8) << 24 | *(tmpData + 9) << 16 | *(tmpData + 10) << 8 | *(tmpData + 11); parcel->writeInt32(rgba); tmpData += 12; remaining -= 12; } break; } // 'krok' box. The number of highlight events is specified, and each // event is specified by a starting and ending char offset and an end // time for the event. case FOURCC('k', 'r', 'o', 'k'): { if (remaining < 6) { return OK; } size_t dataPos = parcel->dataPosition(); parcel->writeInt32(KEY_STRUCT_KARAOKE_LIST); int startTime = U32_AT(tmpData); uint16_t count = U16_AT(tmpData + 4); parcel->writeInt32(count); tmpData += 6; remaining -= 6; int lastEndTime = 0; for (int i = 0; i < count; i++) { if (remaining < 8) { // roll back parcel->setDataPosition(dataPos); return OK; } parcel->writeInt32(startTime + lastEndTime); lastEndTime = U32_AT(tmpData); parcel->writeInt32(lastEndTime); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(U16_AT(tmpData + 6)); tmpData += 8; remaining -= 8; } break; } // 'hlit' box specifies highlighted text case FOURCC('h', 'l', 'i', 't'): { if (remaining < 4) { return OK; } parcel->writeInt32(KEY_STRUCT_HIGHLIGHT_LIST); // the start char offset to highlight parcel->writeInt32(U16_AT(tmpData)); // the last char offset to highlight parcel->writeInt32(U16_AT(tmpData + 2)); tmpData += 4; remaining -= 4; break; } // 'hclr' box specifies the RGBA color: 8 bits each of // red, green, blue, and an alpha(transparency) value case FOURCC('h', 'c', 'l', 'r'): { if (remaining < 4) { return OK; } parcel->writeInt32(KEY_HIGHLIGHT_COLOR_RGBA); uint32_t rgba = *(tmpData) << 24 | *(tmpData + 1) << 16 | *(tmpData + 2) << 8 | *(tmpData + 3); parcel->writeInt32(rgba); tmpData += 4; remaining -= 4; break; } // 'dlay' box specifies a delay after a scroll in and/or // before scroll out. case FOURCC('d', 'l', 'a', 'y'): { if (remaining < 4) { return OK; } parcel->writeInt32(KEY_SCROLL_DELAY); uint32_t delay = *(tmpData) << 24 | *(tmpData + 1) << 16 | *(tmpData + 2) << 8 | *(tmpData + 3); parcel->writeInt32(delay); tmpData += 4; remaining -= 4; break; } // 'href' box for hyper text link case FOURCC('h', 'r', 'e', 'f'): { if (remaining < 5) { return OK; } size_t dataPos = parcel->dataPosition(); parcel->writeInt32(KEY_STRUCT_HYPER_TEXT_LIST); // the start offset of the text to be linked parcel->writeInt32(U16_AT(tmpData)); // the end offset of the text parcel->writeInt32(U16_AT(tmpData + 2)); // the number of bytes in the following URL size_t len = *(tmpData + 4); parcel->writeInt32(len); remaining -= 5; if (remaining < len) { parcel->setDataPosition(dataPos); return OK; } // the linked-to URL parcel->writeInt32(len); parcel->write(tmpData + 5, len); tmpData += (5 + len); remaining -= len; if (remaining < 1) { parcel->setDataPosition(dataPos); return OK; } // the number of bytes in the following "alt" string len = *tmpData; parcel->writeInt32(len); tmpData += 1; remaining -= 1; if (remaining < len) { parcel->setDataPosition(dataPos); return OK; } // an "alt" string for user display parcel->writeInt32(len); parcel->write(tmpData, len); tmpData += 1; remaining -= 1; break; } // 'tbox' box to indicate the position of the text with values // of top, left, bottom and right case FOURCC('t', 'b', 'o', 'x'): { if (remaining < 8) { return OK; } parcel->writeInt32(KEY_STRUCT_TEXT_POS); parcel->writeInt32(U16_AT(tmpData)); parcel->writeInt32(U16_AT(tmpData + 2)); parcel->writeInt32(U16_AT(tmpData + 4)); parcel->writeInt32(U16_AT(tmpData + 6)); tmpData += 8; remaining -= 8; break; } // 'blnk' to specify the char range to be blinked case FOURCC('b', 'l', 'n', 'k'): { if (remaining < 4) { return OK; } parcel->writeInt32(KEY_STRUCT_BLINKING_TEXT_LIST); // start char offset parcel->writeInt32(U16_AT(tmpData)); // end char offset parcel->writeInt32(U16_AT(tmpData + 2)); tmpData += 4; remaining -= 4; break; } // 'twrp' box specifies text wrap behavior. If the value if 0x00, // then no wrap. If it's 0x01, then automatic 'soft' wrap is enabled. // 0x02-0xff are reserved. case FOURCC('t', 'w', 'r', 'p'): { if (remaining < 1) { return OK; } parcel->writeInt32(KEY_WRAP_TEXT); parcel->writeInt32(*tmpData); tmpData += 1; remaining -= 1; break; } default: { break; } } data += chunkSize; size -= chunkSize; } return OK; }
} static const ProcModule g_module[] = { { "cc_getRLSFrame", (ProcPtr)cc_getRLSFrameChirp, {END}, "Get a frame of color run-length segments (RLS)" "@r 0 if success, negative if error" "@r CCQ1 formated data, including 8-palette" }, { "cc_setModel", (ProcPtr)cc_setModel, {CRP_UINT8, CRP_HTYPE(FOURCC('R','E','G','1')), END}, "Set model by selecting box in image" "@p model numerical index of model, can be 0-5" "@p pixels user-selected pixels" "@r 0 if success, negative if error" }, { "cc_setMemory", (ProcPtr)cc_setMemory, {CRP_UINT32, CRP_UINTS8, END}, "" }, { "cc_getRLSCC", (ProcPtr)cc_getRLSCCChirp, {END},
extern int output_flv(struct mp4_context_t const* mp4_context, unsigned int* trak_sample_start, unsigned int* trak_sample_end, struct bucket_t** buckets, struct mp4_split_options_t* options) { struct moov_t* moov = mp4_context->moov; unsigned int track = 0; for(track = 0; track != moov->tracks_; ++track) { struct trak_t* trak = moov->traks_[track]; struct stsd_t const* stsd = trak->mdia_->minf_->stbl_->stsd_; struct sample_entry_t const* sample_entry = &stsd->sample_entries_[0]; unsigned int start_sample = trak_sample_start[track]; unsigned int end_sample = trak_sample_end[track]; unsigned int s; if(trak->mdia_->hdlr_->handler_type_ != FOURCC('v', 'i', 'd', 'e')) continue; if(trak->mdia_->hdlr_->handler_type_ == FOURCC('v', 'i', 'd', 'e')) { unsigned char* buffer = (unsigned char*)malloc(1 + 1 + 3 + sample_entry->codec_private_data_length_); unsigned char* p = buffer; p = write_8(p, 0x17); p = write_8(p, RTMP_AVC_SEQUENCE_HEADER); p = write_24(p, 0); memcpy(p, sample_entry->codec_private_data_, sample_entry->codec_private_data_length_); p += sample_entry->codec_private_data_length_; bucket_insert_tail(buckets, bucket_init_memory(buffer, p - buffer)); free(buffer); } else if(trak->mdia_->hdlr_->handler_type_ == FOURCC('s', 'o', 'u', 'n')) { unsigned char* buffer = (unsigned char*)malloc(1 + 1 + sample_entry->codec_private_data_length_); unsigned char* p = buffer; p = write_8(p, 0xaf); p = write_8(p, RTMP_AAC_SEQUENCE_HEADER); memcpy(p, sample_entry->codec_private_data_, sample_entry->codec_private_data_length_); p += sample_entry->codec_private_data_length_; bucket_insert_tail(buckets, bucket_init_memory(buffer, p - buffer)); free(buffer); } else { continue; } for(s = start_sample; s != end_sample; ++s) { uint64_t sample_pos = trak->samples_[s].pos_; unsigned int sample_size = trak->samples_[s].size_; int cto = trak->samples_[s].cto_; // FLV uses a fixed 1000 timescale unsigned int composition_time = (unsigned int) (trak_time_to_moov_time(cto, 1000, trak->mdia_->mdhd_->timescale_)); MP4_INFO( "frame=%u pts=%u offset=%llu size=%u\n", s, composition_time, sample_pos, sample_size); if(trak->mdia_->hdlr_->handler_type_ == FOURCC('v', 'i', 'd', 'e')) { // if(is_avc) { // VIDEODATA unsigned char header[5]; unsigned int is_keyframe = trak->samples_[s].is_ss_; unsigned int codec_id = 7; // AVC write_8(header, ((is_keyframe ? 1 : 2) << 4) + codec_id); write_8(header + 1, RTMP_AVC_NALU); write_24(header + 2, composition_time); bucket_insert_tail(buckets, bucket_init_memory(header, 5)); bucket_insert_tail(buckets, bucket_init_file(sample_pos, sample_size)); } } else { // AUDIODATA unsigned char header[2]; write_8(header, 0xaf); write_8(header + 1, RTMP_AAC_RAW); // AACAUDIODATA bucket_insert_tail(buckets, bucket_init_memory(header, 2)); bucket_insert_tail(buckets, bucket_init_file(sample_pos, sample_size)); } } } return 1; }
FourCC GetWidgetTypeID() const { return FOURCC('SLGP'); }