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::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::setCompositionTimeToSampleParams( off64_t data_offset, size_t data_size) { #endif 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; } size_t numEntries = U32_AT(&header[4]); #ifdef ANDROID_DEFAULT_CODE // skip box might be included if (data_size != (numEntries + 1) * 8) { return ERROR_MALFORMED; } #else if (data_size < (numEntries + 1) * 8) { //data_size not enough return ERROR_MALFORMED; } #endif 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]); #ifndef ANDROID_DEFAULT_CODE if (i%2 == 1 && timescaleFactor != 0) { mCompositionTimeDeltaEntries[i] /= timescaleFactor; } #endif } mCompositionDeltaLookup->setEntries( mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries); 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; } size_t numEntries = U32_AT(&header[4]); if (data_size != (numEntries + 1) * 8) { return ERROR_MALFORMED; } mNumCompositionTimeDeltaEntries = numEntries; uint64_t allocSize = (uint64_t)numEntries * 2 * sizeof(uint32_t); if (allocSize > UINT32_MAX) { return ERROR_OUT_OF_RANGE; } mCompositionTimeDeltaEntries = new (std::nothrow) uint32_t[2 * numEntries]; if (!mCompositionTimeDeltaEntries) return ERROR_OUT_OF_RANGE; 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::setTimeToSampleParams( off64_t data_offset, size_t data_size) #endif { 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]); #ifdef MTK_AOSP_ENHANCEMENT uint64_t allocSize = ((uint64_t)mTimeToSampleCount)* 2 * sizeof(uint32_t); #else uint64_t allocSize = mTimeToSampleCount * 2 * sizeof(uint32_t); #endif if (allocSize > SIZE_MAX) { return ERROR_OUT_OF_RANGE; } 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]); #ifdef MTK_AOSP_ENHANCEMENT if (i%2 == 1 && timescaleFactor != 0) { mTimeToSample[i] /= timescaleFactor; } #endif } return OK; }
status_t SampleTable::setTimeToSampleParams( off64_t data_offset, size_t data_size) { if (mHasTimeToSample || 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 ((uint64_t)mTimeToSampleCount > (uint64_t)UINT32_MAX / (2 * sizeof(uint32_t))) { // Choose this bound because // 1) 2 * sizeof(uint32_t) is the amount of memory needed for one // time-to-sample entry in the time-to-sample table. // 2) mTimeToSampleCount is the number of entries of the time-to-sample // table. // 3) We hope that the table size does not exceed UINT32_MAX. ALOGE(" Error: Time-to-sample table size too large."); return ERROR_OUT_OF_RANGE; } // Note: At this point, we know that mTimeToSampleCount * 2 will not // overflow because of the above condition. if (!mDataSource->getVector(data_offset + 8, &mTimeToSample, mTimeToSampleCount * 2)) { ALOGE(" Error: Incomplete data read for time-to-sample table."); return ERROR_IO; } for (size_t i = 0; i < mTimeToSample.size(); ++i) { mTimeToSample.editItemAt(i) = ntohl(mTimeToSample[i]); } mHasTimeToSample = true; 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!"); } uint64_t allocSize = mNumSyncSamples * (uint64_t)sizeof(uint32_t); if (allocSize > SIZE_MAX) { return ERROR_OUT_OF_RANGE; } mSyncSamples = new (std::nothrow) uint32_t[mNumSyncSamples]; if (!mSyncSamples) return ERROR_OUT_OF_RANGE; 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; }
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; }
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; } #ifndef ANDROID_DEFAULT_CODE if (U32_AT(buffer) < 1) { ALOGE("Chunk index is less than 1 in stsc"); return ERROR_MALFORMED; } #else CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec. #endif // 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::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 ESDS::parseDecoderConfigDescriptor(size_t offset, size_t size) { if (size < 13) { return ERROR_MALFORMED; } mObjectTypeIndication = mData[offset]; mBitRateMax = U32_AT(mData + offset + 5); mBitRateAvg = U32_AT(mData + offset + 9); offset += 13; size -= 13; if (size == 0) { mDecoderSpecificOffset = 0; mDecoderSpecificLength = 0; return OK; } uint8_t tag; size_t sub_offset, sub_size; status_t err = skipDescriptorHeader( offset, size, &tag, &sub_offset, &sub_size); if (err != OK) { return err; } if (tag != kTag_DecoderSpecificInfo) { return ERROR_MALFORMED; } mDecoderSpecificOffset = sub_offset; mDecoderSpecificLength = sub_size; 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; } if (SIZE_MAX / sizeof(SampleToChunkEntry) <= (size_t)mNumSampleToChunkOffsets) return ERROR_OUT_OF_RANGE; mSampleToChunkEntries = new (std::nothrow) SampleToChunkEntry[mNumSampleToChunkOffsets]; if (!mSampleToChunkEntries) return ERROR_OUT_OF_RANGE; 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::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; }
static void S20BDecode( void *outp, const uint8_t *in, unsigned samples ) { int32_t *out = outp; while( samples >= 2 ) { uint32_t dw = U32_AT(in); in += 4; *(out++) = dw & ~0xFFF; *(out++) = (dw << 20) | (*in << 12); in++; samples -= 2; } /* No U32_AT() for the last odd sample: avoid off-by-one overflow! */ if( samples ) *(out++) = (U16_AT(in) << 16) | ((in[2] & 0xF0) << 8); }
status_t MP3Source::getNextFramePos(off_t *curPos, off_t *pNextPos,int64_t * frameTsUs) { uint8_t mp3header[4]; size_t frame_size; int samplerate=0; int num_sample =0; for(;;) { ssize_t n = mDataSource->readAt(*curPos, mp3header, 4); if (n < 4) { MP3_EXTR_DBG("For Seek Talbe :ERROR_END_OF_STREAM"); return ERROR_END_OF_STREAM; } // MP3_EXTR_DBG("mp3header[0]=%0x,mp3header[1]=%0x,mp3header[2]=%0x,mp3header[3]=%0x",mp3header[0],mp3header[1],mp3header[2],mp3header[3]); uint32_t header = U32_AT((const uint8_t *)mp3header); if ((header & kMask) == (mFixedHeader & kMask) && GetMPEGAudioFrameSize(header, &frame_size, &samplerate, NULL,NULL,&num_sample)) { break; } // Lost sync. //MP3_EXTR_DBG("getNextFramePos::lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader); off64_t pos = *curPos; if (!Resync(mDataSource, mFixedHeader, &pos, NULL,NULL)) { //MP3_EXTR_DBG("getNextFramePos---Unable to resync. Signalling end of stream."); return ERROR_END_OF_STREAM; } *curPos = pos; // Try again with the new position. } *pNextPos=*curPos+frame_size; *frameTsUs = 1000000ll * num_sample/samplerate; return OK; }
// 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; }
/* * fill a signature_packet_v4_t from signature packet data * verify that it was used with a DSA or RSA public key */ static size_t parse_signature_v4_packet( signature_packet_t *p_sig, const uint8_t *p_buf, size_t i_sig_len ) { size_t i_read = 1; /* we already read the version byte */ if( i_sig_len < 10 ) /* signature is at least 10 bytes + the 2 MPIs */ return 0; p_sig->type = *p_buf++; i_read++; p_sig->public_key_algo = *p_buf++; i_read++; if (p_sig->public_key_algo != GCRY_PK_DSA && p_sig->public_key_algo != GCRY_PK_RSA ) return 0; p_sig->digest_algo = *p_buf++; i_read++; memcpy( p_sig->specific.v4.hashed_data_len, p_buf, 2 ); p_buf += 2; i_read += 2; size_t i_hashed_data_len = scalar_number( p_sig->specific.v4.hashed_data_len, 2 ); i_read += i_hashed_data_len; if( i_read + 4 > i_sig_len ) return 0; p_sig->specific.v4.hashed_data = (uint8_t*) malloc( i_hashed_data_len ); if( !p_sig->specific.v4.hashed_data ) return 0; memcpy( p_sig->specific.v4.hashed_data, p_buf, i_hashed_data_len ); p_buf += i_hashed_data_len; memcpy( p_sig->specific.v4.unhashed_data_len, p_buf, 2 ); p_buf += 2; i_read += 2; size_t i_unhashed_data_len = scalar_number( p_sig->specific.v4.unhashed_data_len, 2 ); i_read += i_unhashed_data_len; if( i_read + 2 > i_sig_len ) return 0; p_sig->specific.v4.unhashed_data = (uint8_t*) malloc( i_unhashed_data_len ); if( !p_sig->specific.v4.unhashed_data ) return 0; memcpy( p_sig->specific.v4.unhashed_data, p_buf, i_unhashed_data_len ); p_buf += i_unhashed_data_len; memcpy( p_sig->hash_verification, p_buf, 2 ); p_buf += 2; i_read += 2; uint8_t *p, *max_pos; p = p_sig->specific.v4.unhashed_data; max_pos = p + scalar_number( p_sig->specific.v4.unhashed_data_len, 2 ); for( ;; ) { if( p > max_pos ) return 0; size_t i_subpacket_len; if( *p < 192 ) { if( p + 1 > max_pos ) return 0; i_subpacket_len = *p++; } else if( *p < 255 ) { if( p + 2 > max_pos ) return 0; i_subpacket_len = (*p++ - 192) << 8; i_subpacket_len += *p++ + 192; } else { if( ++p + 4 > max_pos ) return 0; i_subpacket_len = U32_AT(p); p += 4; } if( *p == ISSUER_SUBPACKET ) { if( p + 9 > max_pos ) return 0; memcpy( &p_sig->issuer_longid, p+1, 8 ); return i_read; } p += i_subpacket_len; } }
static uint64_t U64_AT(const uint8_t *ptr) { return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4); }
bool ID3::removeUnsynchronizationV2_4(bool iTunesHack) { size_t oldSize = mSize; size_t offset = 0; while (offset + 10 <= mSize) { if (!memcmp(&mData[offset], "\0\0\0\0", 4)) { break; } size_t dataSize; if (iTunesHack) { dataSize = U32_AT(&mData[offset + 4]); } else if (!ParseSyncsafeInteger(&mData[offset + 4], &dataSize)) { return false; } if (offset + dataSize + 10 > mSize) { return false; } uint16_t flags = U16_AT(&mData[offset + 8]); uint16_t prevFlags = flags; if (flags & 1) { // Strip data length indicator memmove(&mData[offset + 10], &mData[offset + 14], mSize - offset - 14); mSize -= 4; dataSize -= 4; flags &= ~1; } if (flags & 2) { // This file has "unsynchronization", so we have to replace occurrences // of 0xff 0x00 with just 0xff in order to get the real data. size_t readOffset = offset + 11; size_t writeOffset = offset + 11; for (size_t i = 0; i + 1 < dataSize; ++i) { if (mData[readOffset - 1] == 0xff && mData[readOffset] == 0x00) { ++readOffset; --mSize; --dataSize; } mData[writeOffset++] = mData[readOffset++]; } // move the remaining data following this frame memmove(&mData[writeOffset], &mData[readOffset], oldSize - readOffset); flags &= ~2; } if (flags != prevFlags || iTunesHack) { WriteSyncsafeInteger(&mData[offset + 4], dataSize); mData[offset + 8] = flags >> 8; mData[offset + 9] = flags & 0xff; } offset += 10 + dataSize; }
bool ID3::parseV2(const sp<DataSource> &source) { struct id3_header { char id[3]; uint8_t version_major; uint8_t version_minor; uint8_t flags; uint8_t enc_size[4]; }; id3_header header; if (source->readAt( 0, &header, sizeof(header)) != (ssize_t)sizeof(header)) { return false; } if (memcmp(header.id, "ID3", 3)) { return false; } if (header.version_major == 0xff || header.version_minor == 0xff) { return false; } if (header.version_major == 2) { if (header.flags & 0x3f) { // We only support the 2 high bits, if any of the lower bits are // set, we cannot guarantee to understand the tag format. return false; } if (header.flags & 0x40) { // No compression scheme has been decided yet, ignore the // tag if compression is indicated. return false; } } else if (header.version_major == 3) { if (header.flags & 0x1f) { // We only support the 3 high bits, if any of the lower bits are // set, we cannot guarantee to understand the tag format. return false; } } else if (header.version_major == 4) { if (header.flags & 0x0f) { // The lower 4 bits are undefined in this spec. return false; } } else { return false; } size_t size; if (!ParseSyncsafeInteger(header.enc_size, &size)) { return false; } if (size > kMaxMetadataSize) { ALOGE("skipping huge ID3 metadata of size %d", size); return false; } mData = (uint8_t *)malloc(size); if (mData == NULL) { return false; } mSize = size; mRawSize = mSize + sizeof(header); if (source->readAt(sizeof(header), mData, mSize) != (ssize_t)mSize) { free(mData); mData = NULL; return false; } if (header.version_major == 4) { void *copy = malloc(size); memcpy(copy, mData, size); bool success = removeUnsynchronizationV2_4(false /* iTunesHack */); if (!success) { memcpy(mData, copy, size); mSize = size; success = removeUnsynchronizationV2_4(true /* iTunesHack */); if (success) { ALOGV("Had to apply the iTunes hack to parse this ID3 tag"); } } free(copy); copy = NULL; if (!success) { free(mData); mData = NULL; return false; } } else if (header.flags & 0x80) { ALOGV("removing unsynchronization"); removeUnsynchronization(); } mFirstFrameOffset = 0; if (header.version_major == 3 && (header.flags & 0x40)) { // Version 2.3 has an optional extended header. if (mSize < 4) { free(mData); mData = NULL; return false; } size_t extendedHeaderSize = U32_AT(&mData[0]) + 4; if (extendedHeaderSize > mSize) { free(mData); mData = NULL; return false; } mFirstFrameOffset = extendedHeaderSize; uint16_t extendedFlags = 0; if (extendedHeaderSize >= 6) { extendedFlags = U16_AT(&mData[4]); if (extendedHeaderSize >= 10) { size_t paddingSize = U32_AT(&mData[6]); if (mFirstFrameOffset + paddingSize > mSize) { free(mData); mData = NULL; return false; } mSize -= paddingSize; } if (extendedFlags & 0x8000) { ALOGV("have crc"); } } } else if (header.version_major == 4 && (header.flags & 0x40)) { // Version 2.4 has an optional extended header, that's different // from Version 2.3's... if (mSize < 4) { free(mData); mData = NULL; return false; } size_t ext_size; if (!ParseSyncsafeInteger(mData, &ext_size)) { free(mData); mData = NULL; return false; } if (ext_size < 6 || ext_size > mSize) { free(mData); mData = NULL; return false; } mFirstFrameOffset = ext_size; } if (header.version_major == 2) { mVersion = ID3_V2_2; } else if (header.version_major == 3) { mVersion = ID3_V2_3; } else { CHECK_EQ(header.version_major, 4); mVersion = ID3_V2_4; } return true; }
status_t MP3Source::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; int64_t seekTimeUs; ReadOptions::SeekMode mode; bool seekCBR = false; if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) { int64_t actualSeekTimeUs = seekTimeUs; #ifndef ANDROID_DEFAULT_CODE if(!mEnableTOC){ #endif if (mSeeker == NULL || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) { int32_t bitrate; if (!mMeta->findInt32(kKeyBitRate, &bitrate)) { // bitrate is in bits/sec. ALOGI("no bitrate"); return ERROR_UNSUPPORTED; } mCurrentTimeUs = seekTimeUs; mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000; seekCBR = true; } else { mCurrentTimeUs = actualSeekTimeUs; } #ifndef ANDROID_DEFAULT_CODE }else{ MP3_EXTR_DBG("before getFramePos seekTimeUs=%lld",seekTimeUs); off_t ActualPos=0; status_t stat=getFramePos(seekTimeUs, &mCurrentTimeUs, &ActualPos, true); if(stat==BAD_VALUE){ int32_t bitrate; if (!mMeta->findInt32(kKeyBitRate, &bitrate)) { // bitrate is in bits/sec. MP3_EXTR_WARN("no bitrate"); return ERROR_UNSUPPORTED; } mCurrentTimeUs = seekTimeUs; mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000; if (mSeeker == NULL || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) { int32_t bitrate; if (!mMeta->findInt32(kKeyBitRate, &bitrate)) { // bitrate is in bits/sec. ALOGI("no bitrate"); return ERROR_UNSUPPORTED; } mCurrentTimeUs = seekTimeUs; mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000; seekCBR = true; } else { mCurrentTimeUs = actualSeekTimeUs; } }else if(stat == ERROR_END_OF_STREAM){ return stat; }else{ mCurrentPos= ActualPos; MP3_EXTR_DBG("after seek mCurrentTimeUs=%lld,pActualPos=%ld",mCurrentTimeUs,ActualPos); } } #endif mBasisTimeUs = mCurrentTimeUs; mSamplesRead = 0; } MediaBuffer *buffer; status_t err = mGroup->acquire_buffer(&buffer); if (err != OK) { return err; } size_t frame_size; int bitrate; int num_samples; int sample_rate; for (;;) { ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), 4); if (n < 4) { buffer->release(); buffer = NULL; return ERROR_END_OF_STREAM; } uint32_t header = U32_AT((const uint8_t *)buffer->data()); if ((header & kMask) == (mFixedHeader & kMask) && GetMPEGAudioFrameSize( header, &frame_size, &sample_rate, NULL, &bitrate, &num_samples)) { // re-calculate mCurrentTimeUs because we might have called Resync() if (seekCBR) { mCurrentTimeUs = (mCurrentPos - mFirstFramePos) * 8000 / bitrate; mBasisTimeUs = mCurrentTimeUs; } break; } // Lost sync. ALOGV("lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader); off64_t pos = mCurrentPos; if (!Resync(mDataSource, mFixedHeader, &pos, NULL, NULL)) { ALOGE("Unable to resync. Signalling end of stream."); buffer->release(); buffer = NULL; return ERROR_END_OF_STREAM; } mCurrentPos = pos; // Try again with the new position. } CHECK(frame_size <= buffer->size()); ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), frame_size); if (n < (ssize_t)frame_size) { buffer->release(); buffer = NULL; return ERROR_END_OF_STREAM; } buffer->set_range(0, frame_size); buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs); buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1); mCurrentPos += frame_size; mSamplesRead += num_samples; mCurrentTimeUs = mBasisTimeUs + ((mSamplesRead * 1000000) / sample_rate); *out = buffer; return OK; }
/** * Add a SAP announce */ int SAP_Add (sap_handler_t *p_sap, session_descriptor_t *p_session) { int i; char psz_addr[NI_MAXNUMERICHOST]; bool b_ipv6 = false, b_ssm = false; sap_session_t *p_sap_session; mtime_t i_hash; union { struct sockaddr a; struct sockaddr_in in; struct sockaddr_in6 in6; } addr; socklen_t addrlen; addrlen = p_session->addrlen; if ((addrlen == 0) || (addrlen > sizeof (addr))) { msg_Err( p_sap, "No/invalid address specified for SAP announce" ); return VLC_EGENERIC; } /* Determine SAP multicast address automatically */ memcpy (&addr, &p_session->addr, addrlen); switch (addr.a.sa_family) { #if defined (HAVE_INET_PTON) || defined (WIN32) case AF_INET6: { /* See RFC3513 for list of valid IPv6 scopes */ struct in6_addr *a6 = &addr.in6.sin6_addr; memcpy( a6->s6_addr + 2, "\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x02\x7f\xfe", 14 ); if( IN6_IS_ADDR_MULTICAST( a6 ) ) { /* SSM <=> ff3x::/32 */ b_ssm = (U32_AT (a6->s6_addr) & 0xfff0ffff) == 0xff300000; /* force flags to zero, preserve scope */ a6->s6_addr[1] &= 0xf; } else /* Unicast IPv6 - assume global scope */ memcpy( a6->s6_addr, "\xff\x0e", 2 ); b_ipv6 = true; break; } #endif case AF_INET: { /* See RFC2365 for IPv4 scopes */ uint32_t ipv4 = addr.in.sin_addr.s_addr; /* 224.0.0.0/24 => 224.0.0.255 */ if ((ipv4 & htonl (0xffffff00)) == htonl (0xe0000000)) ipv4 = htonl (0xe00000ff); else /* 239.255.0.0/16 => 239.255.255.255 */ if ((ipv4 & htonl (0xffff0000)) == htonl (0xefff0000)) ipv4 = htonl (0xefffffff); else /* 239.192.0.0/14 => 239.195.255.255 */ if ((ipv4 & htonl (0xfffc0000)) == htonl (0xefc00000)) ipv4 = htonl (0xefc3ffff); else if ((ipv4 & htonl (0xff000000)) == htonl (0xef000000)) ipv4 = 0; else /* other addresses => 224.2.127.254 */ { /* SSM: 232.0.0.0/8 */ b_ssm = (ipv4 & htonl (255 << 24)) == htonl (232 << 24); ipv4 = htonl (0xe0027ffe); } if( ipv4 == 0 ) { msg_Err( p_sap, "Out-of-scope multicast address " "not supported by SAP" ); return VLC_EGENERIC; } addr.in.sin_addr.s_addr = ipv4; break; } default: msg_Err( p_sap, "Address family %d not supported by SAP", addr.a.sa_family ); return VLC_EGENERIC; } i = vlc_getnameinfo( &addr.a, addrlen, psz_addr, sizeof( psz_addr ), NULL, NI_NUMERICHOST ); if( i ) { msg_Err( p_sap, "%s", gai_strerror( i ) ); return VLC_EGENERIC; } /* Find/create SAP address thread */ msg_Dbg( p_sap, "using SAP address: %s", psz_addr); vlc_mutex_lock (&p_sap->lock); sap_address_t *sap_addr; for (sap_addr = p_sap->first; sap_addr; sap_addr = sap_addr->next) if (!strcmp (psz_addr, sap_addr->group)) break; if (sap_addr == NULL) { sap_addr = AddressCreate (VLC_OBJECT(p_sap), psz_addr); if (sap_addr == NULL) { vlc_mutex_unlock (&p_sap->lock); return VLC_EGENERIC; } sap_addr->next = p_sap->first; p_sap->first = sap_addr; } /* Switch locks. * NEVER take the global SAP lock when holding a SAP thread lock! */ vlc_mutex_lock (&sap_addr->lock); vlc_mutex_unlock (&p_sap->lock); memcpy (&p_session->orig, &sap_addr->orig, sap_addr->origlen); p_session->origlen = sap_addr->origlen; size_t headsize = 20, length; switch (p_session->orig.ss_family) { #ifdef AF_INET6 case AF_INET6: headsize += 16; break; #endif case AF_INET: headsize += 4; break; default: assert (0); } /* XXX: Check for dupes */ length = headsize + strlen (p_session->psz_sdp); p_sap_session = malloc (sizeof (*p_sap_session) + length + 1); if (p_sap_session == NULL) { vlc_mutex_unlock (&sap_addr->lock); return VLC_EGENERIC; /* NOTE: we should destroy the thread if left unused */ } p_sap_session->next = sap_addr->first; sap_addr->first = p_sap_session; p_sap_session->p_sd = p_session; p_sap_session->length = length; /* Build the SAP Headers */ uint8_t *psz_head = p_sap_session->data; /* SAPv1, not encrypted, not compressed */ psz_head[0] = 0x20; psz_head[1] = 0x00; /* No authentication length */ i_hash = mdate(); psz_head[2] = i_hash >> 8; /* Msg id hash */ psz_head[3] = i_hash; /* Msg id hash 2 */ headsize = 4; switch (p_session->orig.ss_family) { #ifdef AF_INET6 case AF_INET6: { struct in6_addr *a6 = &((struct sockaddr_in6 *)&p_session->orig)->sin6_addr; memcpy (psz_head + headsize, a6, 16); psz_head[0] |= 0x10; /* IPv6 flag */ headsize += 16; break; } #endif case AF_INET: { uint32_t ipv4 = (((struct sockaddr_in *)&p_session->orig)->sin_addr.s_addr); memcpy (psz_head + headsize, &ipv4, 4); headsize += 4; break; } } memcpy (psz_head + headsize, "application/sdp", 16); headsize += 16; /* Build the final message */ strcpy( (char *)psz_head + headsize, p_session->psz_sdp); sap_addr->session_count++; vlc_cond_signal (&sap_addr->wait); vlc_mutex_unlock (&sap_addr->lock); return VLC_SUCCESS; }
bool FastSniffMP3( const sp<DataSource> &source, String8 *mimeType, float *confidence, sp<AMessage> *meta) { off64_t inout_pos = 0; off64_t post_id3_pos; uint32_t header; if (inout_pos == 0) { // Skip an optional ID3 header if syncing at the very beginning // of the datasource. for (;;) { uint8_t id3header[10]; if (source->readAt(inout_pos, id3header, sizeof(id3header)) < (ssize_t)sizeof(id3header)) { ALOGV("Read no enough data"); return false; } if (memcmp("ID3", id3header, 3)) { break; } size_t len = ((id3header[6] & 0x7f) << 21) | ((id3header[7] & 0x7f) << 14) | ((id3header[8] & 0x7f) << 7) | (id3header[9] & 0x7f); len += 10; inout_pos += len; } post_id3_pos = inout_pos; } off64_t pos = inout_pos; bool valid = true; uint32_t test_header = 0; for (int j = 0; j < 4; ++j) { uint8_t tmp[4]; if (source->readAt(pos, tmp, 4) < 4) { valid = false; break; } test_header = U32_AT(tmp); size_t test_frame_size; if (!GetMPEGAudioFrameSize( test_header, &test_frame_size)) { valid = false; break; } ALOGV("found subsequent frame #%d at %lld", j + 2, pos); pos += test_frame_size; } if (false == valid) { ALOGV("no dice, no valid sequence of frames found."); return false; } else header = test_header; *meta = new AMessage; (*meta)->setInt64("offset", inout_pos); (*meta)->setInt32("header", header); (*meta)->setInt64("post-id3-offset", inout_pos); *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG; *confidence = 0.2f; return true; }
// static sp<VBRISeeker> VBRISeeker::CreateFromSource( const sp<DataSource> &source, off64_t post_id3_pos) { off64_t pos = post_id3_pos; uint8_t header[4]; ssize_t n = source->readAt(pos, header, sizeof(header)); if (n < (ssize_t)sizeof(header)) { return NULL; } uint32_t tmp = U32_AT(&header[0]); size_t frameSize; int sampleRate; if (!GetMPEGAudioFrameSize(tmp, &frameSize, &sampleRate)) { return NULL; } // VBRI header follows 32 bytes after the header _ends_. pos += sizeof(header) + 32; uint8_t vbriHeader[26]; n = source->readAt(pos, vbriHeader, sizeof(vbriHeader)); if (n < (ssize_t)sizeof(vbriHeader)) { return NULL; } if (memcmp(vbriHeader, "VBRI", 4)) { return NULL; } size_t numFrames = U32_AT(&vbriHeader[14]); int64_t durationUs = numFrames * 1000000ll * (sampleRate >= 32000 ? 1152 : 576) / sampleRate; ALOGV("duration = %.2f secs", durationUs / 1E6); size_t numEntries = U16_AT(&vbriHeader[18]); size_t entrySize = U16_AT(&vbriHeader[22]); size_t scale = U16_AT(&vbriHeader[20]); ALOGV("%zu entries, scale=%zu, size_per_entry=%zu", numEntries, scale, entrySize); size_t totalEntrySize = numEntries * entrySize; uint8_t *buffer = new uint8_t[totalEntrySize]; n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize); if (n < (ssize_t)totalEntrySize) { delete[] buffer; buffer = NULL; return NULL; } sp<VBRISeeker> seeker = new VBRISeeker; seeker->mBasePos = post_id3_pos + frameSize; // only update mDurationUs if the calculated duration is valid (non zero) // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime() // return false when called, to indicate that this vbri tag does not have the // requested information if (durationUs) { seeker->mDurationUs = durationUs; } off64_t offset = post_id3_pos; for (size_t i = 0; i < numEntries; ++i) { uint32_t numBytes; switch (entrySize) { case 1: numBytes = buffer[i]; break; case 2: numBytes = U16_AT(buffer + 2 * i); break; case 3: numBytes = U24_AT(buffer + 3 * i); break; default: { CHECK_EQ(entrySize, 4u); numBytes = U32_AT(buffer + 4 * i); break; } } numBytes *= scale; seeker->mSegments.push(numBytes); ALOGV("entry #%zu: %u offset 0x%016llx", i, numBytes, offset); offset += numBytes; } delete[] buffer; buffer = NULL; ALOGI("Found VBRI header."); return seeker; }
static uint64_t TO_U64(uint64_t v) { uint8_t* ptr = (uint8_t*)&v; return ((uint64_t)U32_AT(ptr)) << 32 | U32_AT(ptr + 4); }
int main(int argc, char* argv[]) { int retval = 1; int fdout = -1; uint8_t* pIn = NULL; uint8_t* pOut = NULL; if (argc < 3 || argc > 3) { fprintf(stderr, "Usage: mfrafix infile outfile\n"); return 1; } int fdin = open(argv[1], O_RDONLY); if (fdin < 0) { fprintf(stderr, "Error: failed to open '%s' for reading\n", argv[1]); goto cleanup; } off_t length = lseek(fdin, 0, SEEK_END); lseek(fdin, 0, SEEK_SET); debug("Length of in file: %d\n", (int)length); pIn = mmap(NULL, length, PROT_READ, MAP_SHARED, fdin, 0); if (pIn == NULL) { fprintf(stderr, "Error: mmap failed with error %d - '%s'\n", errno, strerror(errno)); goto cleanup; } // Look for the mfra by checking the last four bytes in the mfro // For now we assume that the mfra is at the end of the file... uint32_t mfro = U32_AT(pIn + length - sizeof(uint32_t)); uint8_t* pMFRA = pIn + length - mfro; uint32_t mfraSize = U32_AT(pMFRA); uint8_t* pMFRAEnd = pMFRA + mfraSize; SKIP(pMFRA, 4); // Size processed debug("mfro offset %x\n", mfro); debug("MFRA size %x\n", mfraSize); debug("MFRA box '%08x'\n", U32_AT(pMFRA)); if (FOURCC('m', 'f', 'r', 'a') != U32_AT(pMFRA)) { fprintf(stderr, "Error: The mfra box was not found\n"); goto cleanup; } SKIP(pMFRA, 4); // Type processed debug("Found mfra\n"); TFRAEntry* tfraEntries = NULL; int numTFRAEntries = 0; while (pMFRA < pMFRAEnd) { uint32_t boxSize = U32_AT(pMFRA); SKIP(pMFRA, 4); // Size read debug("Box size %x\n", boxSize); debug("Box type '%08x'\n", U32_AT(pMFRA)); switch (U32_AT(pMFRA)) { case FOURCC('t', 'f', 'r', 'a'): debug("Found tfra\n"); SKIP(pMFRA, 4); // Type processed SKIP(pMFRA, 4); // Ignore version and flags uint32_t trackId = U32_AT(pMFRA); SKIP(pMFRA, 4); // trackId processed uint32_t tmp = U32LE_AT(pMFRA); int trafNum = (tmp >> 4) & 0x3; int trunNum = (tmp >> 2) & 0x3; int sampleNum = (tmp >> 0) & 0x3; SKIP(pMFRA, 4); // Traf, trun and samples processed debug("trackId %d\ntraf %d trun %d sample %d\n", trackId, trafNum, trunNum, sampleNum); uint32_t numEntry = U32_AT(pMFRA); SKIP(pMFRA, 4); // numEntry processed debug("numEntry: %d\n", numEntry); tfraEntries = realloc(tfraEntries, sizeof(TFRAEntry) * (numEntry + numTFRAEntries)); if (tfraEntries == NULL) { fprintf(stderr, "Error: Failed to allocate memory for tfra entries\n"); goto cleanup; } for (int i = numTFRAEntries; i < (numEntry + numTFRAEntries); ++i) { tfraEntries[i].trackId = trackId; debug("time: %lx\n", U64_AT(pMFRA)); tfraEntries[i].time = U64_AT(pMFRA); SKIP(pMFRA, 8); // Skip uint64, time debug("moof: %lx\n", U64_AT(pMFRA)); tfraEntries[i].moof = U64_AT(pMFRA); tfraEntries[i].moofOffset = (pMFRA - pIn); SKIP(pMFRA, 8); // Skip uint64, moof offset int skip = trafNum + 1 + trunNum + 1 + sampleNum + 1; pMFRA = pMFRA + skip; } // Update here as we use numTFRAEntries as offset when indexing the array numTFRAEntries += numEntry; break; case FOURCC('m', 'f', 'r', 'o'): debug("found mfro box\n"); pMFRA = pMFRA + boxSize - sizeof(uint32_t); break; default: fprintf(stderr, "Error: Unknown box found '%08x'\n", U32_AT(pMFRA)); goto cleanup; } } if (numTFRAEntries == 0) { fprintf(stderr, "Error: No TFRA entries found.\n"); goto cleanup; } // Start by checking if the first entry points to a moof uint8_t* p1 = pIn + tfraEntries[0].moof; if (FOURCC('m', 'o', 'o', 'f') != U32_AT(p1 + 4)) { uint32_t offset = U32_AT(p1); fprintf(stdout, "We found '%08x' instead of moof, try to correct with offset %x\n", U32_AT(p1 + 4), offset); for (int i = 0; i < numTFRAEntries; ++i) { debug("p = %x\n", tfraEntries[i].moof); uint8_t *p = pIn + tfraEntries[i].moof + offset; if (U32_AT(p + 4) == FOURCC('m', 'o', 'o', 'f')) debug("Found moof\n"); else { debug("Found '%08x'\n", U32_AT(p + 4)); goto cleanup; } } debug("Open output file\n"); fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC); if (fdout < 0) { fprintf(stderr, "Error: failed to open '%s' for writing\n", argv[2]); goto cleanup; } debug("Set size of out file\n"); lseek(fdout, length - 1, SEEK_SET); write(fdout, "", 1); debug("Call mmap for output file\n"); pOut = mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fdout, 0); if (pOut == NULL) { fprintf(stderr, "Error: mmap failed with error %d - '%s'\n", errno, strerror(errno)); goto cleanup; } debug("Do memcpy\n"); memcpy(pOut, pIn, length); debug("Update moof references\n"); for (int i = 0; i < numTFRAEntries; ++i) { debug("p = %x\n", tfraEntries[i].moof); debug("offset = %x\n", offset); debug("out = %x\n", tfraEntries[i].moof + offset); uint64_t *p = (uint64_t*)(pOut + tfraEntries[i].moofOffset); (*p) = TO_U64(tfraEntries[i].moof + offset); } debug("Do msync\n"); msync(pOut, length, MS_SYNC); fprintf(stdout, "Fixed all entries...\n"); } else { fprintf(stdout, "The first moof reference is correct, assume the rest are as well and exit\n"); } retval = 0; cleanup: if (tfraEntries != NULL) free(tfraEntries); if (fdout >= 0) close(fdout); if (pOut != NULL) munmap(pOut, length); if (pIn != NULL) munmap(pIn, length); if (fdin >= 0) close(fdin); return retval; }
static bool Resync( const sp<DataSource> &source, uint32_t match_header, off64_t *inout_pos, off64_t *post_id3_pos, uint32_t *out_header) { if (post_id3_pos != NULL) { *post_id3_pos = 0; } if (*inout_pos == 0) { // Skip an optional ID3 header if syncing at the very beginning // of the datasource. for (;;) { uint8_t id3header[10]; if (source->readAt(*inout_pos, id3header, sizeof(id3header)) < (ssize_t)sizeof(id3header)) { // If we can't even read these 10 bytes, we might as well bail // out, even if there _were_ 10 bytes of valid mp3 audio data... return false; } if (memcmp("ID3", id3header, 3)) { break; } // Skip the ID3v2 header. size_t len = ((id3header[6] & 0x7f) << 21) | ((id3header[7] & 0x7f) << 14) | ((id3header[8] & 0x7f) << 7) | (id3header[9] & 0x7f); len += 10; *inout_pos += len; LOGV("skipped ID3 tag, new starting offset is %lld (0x%016llx)", *inout_pos, *inout_pos); } if (post_id3_pos != NULL) { *post_id3_pos = *inout_pos; } } off64_t pos = *inout_pos; bool valid = false; const size_t kMaxReadBytes = 1024; const size_t kMaxBytesChecked = 128 * 1024; uint8_t buf[kMaxReadBytes]; ssize_t bytesToRead = kMaxReadBytes; ssize_t totalBytesRead = 0; ssize_t remainingBytes = 0; bool reachEOS = false; uint8_t *tmp = buf; do { if (pos >= *inout_pos + kMaxBytesChecked) { // Don't scan forever. LOGV("giving up at offset %lld", pos); break; } if (remainingBytes < 4) { if (reachEOS) { break; } else { memcpy(buf, tmp, remainingBytes); bytesToRead = kMaxReadBytes - remainingBytes; /* * The next read position should start from the end of * the last buffer, and thus should include the remaining * bytes in the buffer. */ totalBytesRead = source->readAt(pos + remainingBytes, buf + remainingBytes, bytesToRead); if (totalBytesRead <= 0) { break; } reachEOS = (totalBytesRead != bytesToRead); totalBytesRead += remainingBytes; remainingBytes = totalBytesRead; tmp = buf; continue; } } uint32_t header = U32_AT(tmp); if (match_header != 0 && (header & kMask) != (match_header & kMask)) { ++pos; ++tmp; --remainingBytes; continue; } size_t frame_size; int sample_rate, num_channels, bitrate; if (!GetMPEGAudioFrameSize( header, &frame_size, &sample_rate, &num_channels, &bitrate)) { ++pos; ++tmp; --remainingBytes; continue; } LOGV("found possible 1st frame at %lld (header = 0x%08x)", pos, header); // We found what looks like a valid frame, // now find its successors. off64_t test_pos = pos + frame_size; valid = true; for (int j = 0; j < 3; ++j) { uint8_t tmp[4]; if (source->readAt(test_pos, tmp, 4) < 4) { valid = false; break; } uint32_t test_header = U32_AT(tmp); LOGV("subsequent header is %08x", test_header); if ((test_header & kMask) != (header & kMask)) { valid = false; break; } size_t test_frame_size; if (!GetMPEGAudioFrameSize( test_header, &test_frame_size)) { valid = false; break; } LOGV("found subsequent frame #%d at %lld", j + 2, test_pos); test_pos += test_frame_size; } if (valid) { *inout_pos = pos; if (out_header != NULL) { *out_header = header; } } else { LOGV("no dice, no valid sequence of frames found."); } ++pos; ++tmp; --remainingBytes; } while (!valid); return valid; }
status_t MatroskaSource::read( MediaBuffer **out, const ReadOptions *options) { *out = NULL; int64_t targetSampleTimeUs = -1ll; int64_t seekTimeUs; ReadOptions::SeekMode mode; if (options && options->getSeekTo(&seekTimeUs, &mode) && !mExtractor->isLiveStreaming()) { clearPendingFrames(); // The audio we want is located by using the Cues to seek the video // stream to find the target Cluster then iterating to finalize for // audio. int64_t actualFrameTimeUs; mBlockIter.seek(seekTimeUs, mIsAudio, &actualFrameTimeUs); if (mode == ReadOptions::SEEK_CLOSEST) { targetSampleTimeUs = actualFrameTimeUs; } } while (mPendingFrames.empty()) { status_t err = readBlock(); if (err != OK) { clearPendingFrames(); return err; } } MediaBuffer *frame = *mPendingFrames.begin(); mPendingFrames.erase(mPendingFrames.begin()); if (mType != AVC || mNALSizeLen == 0) { if (targetSampleTimeUs >= 0ll) { frame->meta_data()->setInt64( kKeyTargetTime, targetSampleTimeUs); } *out = frame; return OK; } // Each input frame contains one or more NAL fragments, each fragment // is prefixed by mNALSizeLen bytes giving the fragment length, // followed by a corresponding number of bytes containing the fragment. // We output all these fragments into a single large buffer separated // by startcodes (0x00 0x00 0x00 0x01). // // When mNALSizeLen is 0, we assume the data is already in the format // desired. const uint8_t *srcPtr = (const uint8_t *)frame->data() + frame->range_offset(); size_t srcSize = frame->range_length(); size_t dstSize = 0; MediaBuffer *buffer = NULL; uint8_t *dstPtr = NULL; for (int32_t pass = 0; pass < 2; ++pass) { size_t srcOffset = 0; size_t dstOffset = 0; while (srcOffset + mNALSizeLen <= srcSize) { size_t NALsize; switch (mNALSizeLen) { case 1: NALsize = srcPtr[srcOffset]; break; case 2: NALsize = U16_AT(srcPtr + srcOffset); break; case 3: NALsize = U24_AT(srcPtr + srcOffset); break; case 4: NALsize = U32_AT(srcPtr + srcOffset); break; default: TRESPASS(); } if (srcOffset + mNALSizeLen + NALsize <= srcOffset + mNALSizeLen) { frame->release(); frame = NULL; return ERROR_MALFORMED; } else if (srcOffset + mNALSizeLen + NALsize > srcSize) { break; } if (pass == 1) { memcpy(&dstPtr[dstOffset], "\x00\x00\x00\x01", 4); if (frame != buffer) { memcpy(&dstPtr[dstOffset + 4], &srcPtr[srcOffset + mNALSizeLen], NALsize); } } dstOffset += 4; // 0x00 00 00 01 dstOffset += NALsize; srcOffset += mNALSizeLen + NALsize; } if (srcOffset < srcSize) { // There were trailing bytes or not enough data to complete // a fragment. frame->release(); frame = NULL; return ERROR_MALFORMED; } if (pass == 0) { dstSize = dstOffset; if (dstSize == srcSize && mNALSizeLen == 4) { // In this special case we can re-use the input buffer by substituting // each 4-byte nal size with a 4-byte start code buffer = frame; } else { buffer = new MediaBuffer(dstSize); } int64_t timeUs; CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs)); int32_t isSync; CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync)); buffer->meta_data()->setInt64(kKeyTime, timeUs); buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync); dstPtr = (uint8_t *)buffer->data(); } } if (frame != buffer) { frame->release(); frame = NULL; } if (targetSampleTimeUs >= 0ll) { buffer->meta_data()->setInt64( kKeyTargetTime, targetSampleTimeUs); } *out = buffer; return OK; }
status_t DRMSource::read(MediaBuffer **buffer, const ReadOptions *options) { Mutex::Autolock autoLock(mDRMLock); status_t err; if ((err = mOriginalMediaSource->read(buffer, options)) != OK) { return err; } size_t len = (*buffer)->range_length(); char *src = (char *)(*buffer)->data() + (*buffer)->range_offset(); DrmBuffer encryptedDrmBuffer(src, len); DrmBuffer decryptedDrmBuffer; decryptedDrmBuffer.length = len; decryptedDrmBuffer.data = new char[len]; DrmBuffer *pDecryptedDrmBuffer = &decryptedDrmBuffer; if ((err = mDrmManagerClient->decrypt(mDecryptHandle, mTrackId, &encryptedDrmBuffer, &pDecryptedDrmBuffer)) != NO_ERROR) { if (decryptedDrmBuffer.data) { delete [] decryptedDrmBuffer.data; decryptedDrmBuffer.data = NULL; } return err; } CHECK(pDecryptedDrmBuffer == &decryptedDrmBuffer); const char *mime; CHECK(getFormat()->findCString(kKeyMIMEType, &mime)); if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC) && !mWantsNALFragments) { uint8_t *dstData = (uint8_t*)src; size_t srcOffset = 0; size_t dstOffset = 0; len = decryptedDrmBuffer.length; while (srcOffset < len) { CHECK(srcOffset + mNALLengthSize <= len); size_t nalLength = 0; const uint8_t* data = (const uint8_t*)(&decryptedDrmBuffer.data[srcOffset]); switch (mNALLengthSize) { case 1: nalLength = *data; break; case 2: nalLength = U16_AT(data); break; case 3: nalLength = ((size_t)data[0] << 16) | U16_AT(&data[1]); break; case 4: nalLength = U32_AT(data); break; default: CHECK(!"Should not be here."); break; } srcOffset += mNALLengthSize; if (srcOffset + nalLength > len) { if (decryptedDrmBuffer.data) { delete [] decryptedDrmBuffer.data; decryptedDrmBuffer.data = NULL; } return ERROR_MALFORMED; } if (nalLength == 0) { continue; } CHECK(dstOffset + 4 <= (*buffer)->size()); dstData[dstOffset++] = 0; dstData[dstOffset++] = 0; dstData[dstOffset++] = 0; dstData[dstOffset++] = 1; memcpy(&dstData[dstOffset], &decryptedDrmBuffer.data[srcOffset], nalLength); srcOffset += nalLength; dstOffset += nalLength; } CHECK_EQ(srcOffset, len); (*buffer)->set_range((*buffer)->range_offset(), dstOffset); } else { memcpy(src, decryptedDrmBuffer.data, decryptedDrmBuffer.length); (*buffer)->set_range((*buffer)->range_offset(), decryptedDrmBuffer.length); } if (decryptedDrmBuffer.data) { delete [] decryptedDrmBuffer.data; decryptedDrmBuffer.data = NULL; } return OK; }
// Use here only C linkage and POD types as this function is a cancelation point. extern "C" int recvPacket(sout_stream_t *p_stream, bool &b_msgReceived, uint32_t &i_payloadSize, int i_sock_fd, vlc_tls_t *p_tls, unsigned *pi_received, uint8_t *p_data, bool *pb_pingTimeout, int *pi_wait_delay, int *pi_wait_retries) { struct pollfd ufd[1]; ufd[0].fd = i_sock_fd; ufd[0].events = POLLIN; /* The Chromecast normally sends a PING command every 5 seconds or so. * If we do not receive one after 6 seconds, we send a PING. * If after this PING, we do not receive a PONG, then we consider the * connection as dead. */ if (poll(ufd, 1, *pi_wait_delay) == 0) { if (*pb_pingTimeout) { if (!*pi_wait_retries) { msg_Err(p_stream, "No PONG answer received from the Chromecast"); return 0; // Connection died } (*pi_wait_retries)--; } else { /* now expect a pong */ *pi_wait_delay = PONG_WAIT_TIME; *pi_wait_retries = PONG_WAIT_RETRIES; msg_Warn(p_stream, "No PING received from the Chromecast, sending a PING"); } *pb_pingTimeout = true; } else { *pb_pingTimeout = false; /* reset to default ping waiting */ *pi_wait_delay = PING_WAIT_TIME; *pi_wait_retries = PING_WAIT_RETRIES; } int i_ret; /* Packet structure: * +------------------------------------+------------------------------+ * | Payload size (uint32_t big endian) | Payload data | * +------------------------------------+------------------------------+ */ while (*pi_received < PACKET_HEADER_LEN) { // We receive the header. i_ret = tls_Recv(p_tls, p_data + *pi_received, PACKET_HEADER_LEN - *pi_received); if (i_ret <= 0) return i_ret; *pi_received += i_ret; } // We receive the payload. // Get the size of the payload i_payloadSize = U32_AT( p_data ); const uint32_t i_maxPayloadSize = PACKET_MAX_LEN - PACKET_HEADER_LEN; if (i_payloadSize > i_maxPayloadSize) { // Error case: the packet sent by the Chromecast is too long: we drop it. msg_Err(p_stream, "Packet too long: droping its data"); uint32_t i_size = i_payloadSize - (*pi_received - PACKET_HEADER_LEN); if (i_size > i_maxPayloadSize) i_size = i_maxPayloadSize; i_ret = tls_Recv(p_tls, p_data + PACKET_HEADER_LEN, i_size); if (i_ret <= 0) return i_ret; *pi_received += i_ret; if (*pi_received < i_payloadSize + PACKET_HEADER_LEN) return i_ret; *pi_received = 0; return -1; } // Normal case i_ret = tls_Recv(p_tls, p_data + *pi_received, i_payloadSize - (*pi_received - PACKET_HEADER_LEN)); if (i_ret <= 0) return i_ret; *pi_received += i_ret; if (*pi_received < i_payloadSize + PACKET_HEADER_LEN) return i_ret; assert(*pi_received == i_payloadSize + PACKET_HEADER_LEN); *pi_received = 0; b_msgReceived = true; return i_ret; }