ARTPAssembler::AssemblyStatus AH263Assembler::addPacket( const sp<ARTPSource> &source) { List<sp<ABuffer> > *queue = source->queue(); if (queue->empty()) { return NOT_ENOUGH_DATA; } if (mNextExpectedSeqNoValid) { List<sp<ABuffer> >::iterator it = queue->begin(); while (it != queue->end()) { if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { break; } it = queue->erase(it); } if (queue->empty()) { return NOT_ENOUGH_DATA; } } sp<ABuffer> buffer = *queue->begin(); if (!mNextExpectedSeqNoValid) { mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { #if VERBOSE LOG(VERBOSE) << "Not the sequence number I expected"; #endif return WRONG_SEQUENCE_NUMBER; } uint32_t rtpTime; CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { submitAccessUnit(); } mAccessUnitRTPTime = rtpTime; // hexdump(buffer->data(), buffer->size()); if (buffer->size() < 2) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; return MALFORMED_PACKET; } unsigned payloadHeader = U16_AT(buffer->data()); unsigned P = (payloadHeader >> 10) & 1; unsigned V = (payloadHeader >> 9) & 1; unsigned PLEN = (payloadHeader >> 3) & 0x3f; unsigned PEBIT = payloadHeader & 7; // V=0 if (V != 0u) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; ALOGW("Packet discarded due to VRC (V != 0)"); return MALFORMED_PACKET; } // PLEN=0 if (PLEN != 0u) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; ALOGW("Packet discarded (PLEN != 0)"); return MALFORMED_PACKET; } // PEBIT=0 if (PEBIT != 0u) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; ALOGW("Packet discarded (PEBIT != 0)"); return MALFORMED_PACKET; } size_t skip = V + PLEN + (P ? 0 : 2); buffer->setRange(buffer->offset() + skip, buffer->size() - skip); if (P) { buffer->data()[0] = 0x00; buffer->data()[1] = 0x00; } mPackets.push_back(buffer); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; }
/** * UTF16toUTF8: converts UTF-16 (host byte order) to UTF-8 * * @param src UTF-16 bytes sequence, aligned on a 16-bits boundary * @param len number of uint16_t to convert */ static char * UTF16toUTF8( const uint16_t *in, size_t len, size_t *newlen ) { char *res, *out; /* allocate memory */ out = res = (char *)malloc( 3 * len ); if( res == NULL ) return NULL; while( len > 0 ) { uint32_t uv = *in; in++; len--; if( uv < 0x80 ) { *out++ = uv; continue; } if( uv < 0x800 ) { *out++ = (( uv >> 6) | 0xc0); *out++ = (( uv & 0x3f) | 0x80); continue; } if( (uv >= 0xd800) && (uv < 0xdbff) ) { /* surrogates */ uint16_t low = U16_AT( in ); in++; len--; if( (low < 0xdc00) || (low >= 0xdfff) ) { *out++ = '?'; /* Malformed surrogate */ continue; } else uv = ((uv - 0xd800) << 10) + (low - 0xdc00) + 0x10000; } if( uv < 0x10000 ) { *out++ = (( uv >> 12) | 0xe0); *out++ = (((uv >> 6) & 0x3f) | 0x80); *out++ = (( uv & 0x3f) | 0x80); continue; }
static void DAT12Decode( void *outp, const uint8_t *in, unsigned samples ) { int32_t *out = outp; while( samples >= 2 ) { *(out++) = dat12tos16(U16_AT(in) >> 4); *(out++) = dat12tos16(U16_AT(in + 1) & ~0xF000); in += 3; samples -= 2; } if( samples ) *(out++) = dat12tos16(U16_AT(in) >> 4); }
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); }
size_t AH263Assembler::getOffsetOfHeader(const sp<ABuffer> buffer) { //the final right offset should be 0 or 2, it is //initialized to 1 for checking whether errors happen size_t offset = 1; if (buffer->size() < 2) { ALOGW("Packet size is less than 2 bytes"); return offset; } unsigned payloadHeader = U16_AT(buffer->data()); unsigned P = (payloadHeader >> 10) & 1; unsigned V = (payloadHeader >> 9) & 1; unsigned PLEN = (payloadHeader >> 3) & 0x3f; unsigned PEBIT = payloadHeader & 7; // V=0 if (V != 0u) { ALOGW("Packet discarded due to VRC (V != 0)"); return offset; } // PLEN=0 if (PLEN != 0u) { ALOGW("Packet discarded (PLEN != 0)"); return offset; } // PEBIT=0 if (PEBIT != 0u) { ALOGW("Packet discarded (PEBIT != 0)"); return offset; } offset = V + PLEN + (P ? 0 : 2); return offset; }
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; }
ARTPAssembler::AssemblyStatus AH263Assembler::addPacket( const sp<ARTPSource> &source) { List<sp<ABuffer> > *queue = source->queue(); if (queue->empty()) { return NOT_ENOUGH_DATA; } if (mNextExpectedSeqNoValid) { List<sp<ABuffer> >::iterator it = queue->begin(); while (it != queue->end()) { if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { break; } it = queue->erase(it); } if (queue->empty()) { return NOT_ENOUGH_DATA; } } sp<ABuffer> buffer = *queue->begin(); if (!mNextExpectedSeqNoValid) { mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { #if VERBOSE LOG(VERBOSE) << "Not the sequence number I expected"; #endif return WRONG_SEQUENCE_NUMBER; } uint32_t rtpTime; if (!buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; LOGW("Cannot find rtp-time. Malformed packet."); return MALFORMED_PACKET; } if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { if (!submitAccessUnit()) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; LOGW("Cannot find rtp-time. Malformed packet."); return MALFORMED_PACKET; } } mAccessUnitRTPTime = rtpTime; // hexdump(buffer->data(), buffer->size()); if (buffer->size() < 2) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; return MALFORMED_PACKET; } // RFC 4629, Sec. 5.1 General H.263+ Payload Header. // The H.263+ payload header is structured as follows: // 0 1 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | RR |P|V| PLEN |PEBIT| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // // RR: 5 bits // Reserved bits. It SHALL be zero and MUST be ignored by receivers. // P: 1 bit // Indicates the picture start or a picture segment (GOB/Slice) start or // a video sequence end (EOS or EOSBS). Two bytes of zero bits then have // to be prefixed to the payload of such a packet to compose a complete // picture/GOB/slice/EOS/EOSBS start code. This bit allows the omission // of the two first bytes of the start code, thus improving the // compression ratio. // V: 1 bit // Indicates the presence of an 8-bit field containing information for // Video Redundancy Coding (VRC), which follows immediately after the // initial 16 bits of the payload header. // PLEN: 6 bits // Length, in bytes, of the extra picture header. If no extra picture // header is attached, PLEN is 0. If PLEN>0, the extra picture header is // attached immediately following the rest of the payload header. Note // that the length reflects the omission of the first two bytes of the // picture start code (PSC). // PEBIT: 3 bits // Indicates the number of bits that shall be ignored in the last byte // of the picture header. If PLEN is not zero, the ignored bits shall be // the least significant bits of the byte. If PLEN is zero, then PEBIT // shall also be zero. unsigned payloadHeader = U16_AT(buffer->data()); unsigned P = (payloadHeader >> 10) & 1; unsigned V = (payloadHeader >> 9) & 1; unsigned PLEN = (payloadHeader >> 3) & 0x3f; unsigned PEBIT = payloadHeader & 7; // V = 0 // We do not support VRC header extension for now, so just discard it if // present. if (V != 0u) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; LOGW("Packet discarded due to VRC (V != 0)"); return MALFORMED_PACKET; } // If PLEN is zero, then PEBIT shall also be zero. if (PLEN == 0u && PEBIT != 0u) { queue->erase(queue->begin()); ++mNextExpectedSeqNo; LOGW("Packet discarded (PEBIT != 0)"); return MALFORMED_PACKET; } size_t skip = PLEN + (P ? 0: 2); buffer->setRange(buffer->offset() + skip, buffer->size() - skip); if (P) { buffer->data()[0] = 0x00; buffer->data()[1] = 0x00; } mPackets.push_back(buffer); queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; }
char *stream_ReadLine( stream_t *s ) { stream_priv_t *priv = (stream_priv_t *)s; char *p_line = NULL; int i_line = 0, i_read = 0; /* Let's fail quickly if this is a readdir access */ if( s->pf_read == NULL ) return NULL; for( ;; ) { char *psz_eol; const uint8_t *p_data; int i_data; int64_t i_pos; /* Probe new data */ i_data = stream_Peek( s, &p_data, STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* No more data */ /* BOM detection */ i_pos = stream_Tell( s ); if( i_pos == 0 && i_data >= 2 ) { const char *psz_encoding = NULL; if( !memcmp( p_data, "\xFF\xFE", 2 ) ) { psz_encoding = "UTF-16LE"; priv->text.little_endian = true; } else if( !memcmp( p_data, "\xFE\xFF", 2 ) ) { psz_encoding = "UTF-16BE"; } /* Open the converter if we need it */ if( psz_encoding != NULL ) { msg_Dbg( s, "UTF-16 BOM detected" ); priv->text.char_width = 2; priv->text.conv = vlc_iconv_open( "UTF-8", psz_encoding ); if( priv->text.conv == (vlc_iconv_t)-1 ) msg_Err( s, "iconv_open failed" ); } } if( i_data % priv->text.char_width ) { /* keep i_char_width boundary */ i_data = i_data - ( i_data % priv->text.char_width ); msg_Warn( s, "the read is not i_char_width compatible"); } if( i_data == 0 ) break; /* Check if there is an EOL */ if( priv->text.char_width == 1 ) { /* UTF-8: 0A <LF> */ psz_eol = memchr( p_data, '\n', i_data ); if( psz_eol == NULL ) /* UTF-8: 0D <CR> */ psz_eol = memchr( p_data, '\r', i_data ); } else { const uint8_t *p_last = p_data + i_data - priv->text.char_width; uint16_t eol = priv->text.little_endian ? 0x0A00 : 0x00A0; assert( priv->text.char_width == 2 ); psz_eol = NULL; /* UTF-16: 000A <LF> */ for( const uint8_t *p = p_data; p <= p_last; p += 2 ) { if( U16_AT( p ) == eol ) { psz_eol = (char *)p + 1; break; } } if( psz_eol == NULL ) { /* UTF-16: 000D <CR> */ eol = priv->text.little_endian ? 0x0D00 : 0x00D0; for( const uint8_t *p = p_data; p <= p_last; p += 2 ) { if( U16_AT( p ) == eol ) { psz_eol = (char *)p + 1; break; } } } } if( psz_eol ) { i_data = (psz_eol - (char *)p_data) + 1; p_line = realloc_or_free( p_line, i_line + i_data + priv->text.char_width ); /* add \0 */ if( !p_line ) goto error; i_data = stream_Read( s, &p_line[i_line], i_data ); if( i_data <= 0 ) break; /* Hmmm */ i_line += i_data - priv->text.char_width; /* skip \n */; i_read += i_data; /* We have our line */ break; } /* Read data (+1 for easy \0 append) */ p_line = realloc_or_free( p_line, i_line + STREAM_PROBE_LINE + priv->text.char_width ); if( !p_line ) goto error; i_data = stream_Read( s, &p_line[i_line], STREAM_PROBE_LINE ); if( i_data <= 0 ) break; /* Hmmm */ i_line += i_data; i_read += i_data; if( i_read >= STREAM_LINE_MAX ) goto error; /* line too long */ } if( i_read > 0 ) { memset(p_line + i_line, 0, priv->text.char_width); i_line += priv->text.char_width; /* the added \0 */ if( priv->text.char_width > 1 ) { int i_new_line = 0; size_t i_in = 0, i_out = 0; const char * p_in = NULL; char * p_out = NULL; char * psz_new_line = NULL; /* iconv */ /* UTF-8 needs at most 150% of the buffer as many as UTF-16 */ i_new_line = i_line * 3 / 2; psz_new_line = malloc( i_new_line ); if( psz_new_line == NULL ) goto error; i_in = (size_t)i_line; i_out = (size_t)i_new_line; p_in = p_line; p_out = psz_new_line; if( vlc_iconv( priv->text.conv, &p_in, &i_in, &p_out, &i_out ) == (size_t)-1 ) { msg_Err( s, "iconv failed" ); msg_Dbg( s, "original: %d, in %d, out %d", i_line, (int)i_in, (int)i_out ); } free( p_line ); p_line = psz_new_line; i_line = (size_t)i_new_line - i_out; /* does not include \0 */ } /* Remove trailing LF/CR */ while( i_line >= 2 && ( p_line[i_line-2] == '\r' || p_line[i_line-2] == '\n') ) i_line--; /* Make sure the \0 is there */ p_line[i_line-1] = '\0'; return p_line; } error: /* We failed to read any data, probably EOF */ free( p_line ); /* */ if( priv->text.conv != (vlc_iconv_t)(-1) ) { vlc_iconv_close( priv->text.conv ); priv->text.conv = (vlc_iconv_t)(-1); } return NULL; }
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; }
ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( const sp<ARTPSource> &source) { List<sp<ABuffer> > *queue = source->queue(); if (queue->empty()) { return NOT_ENOUGH_DATA; } if (mNextExpectedSeqNoValid) { List<sp<ABuffer> >::iterator it = queue->begin(); while (it != queue->end()) { if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { break; } it = queue->erase(it); } if (queue->empty()) { return NOT_ENOUGH_DATA; } } sp<ABuffer> buffer = *queue->begin(); if (!mNextExpectedSeqNoValid) { mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { LOGV("Not the sequence number I expected"); return WRONG_SEQUENCE_NUMBER; } uint32_t rtpTime; if (!buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)) { LOGW("Cannot find rtp-time. Malformed packet."); return MALFORMED_PACKET; } if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { if (!submitAccessUnit()) { LOGW("Cannot find rtp-time. Malformed packet."); return MALFORMED_PACKET; } } // If constantDuration and CTSDelta are not present. We should assume the // stream has fixed duration and calculate the mConstantDuration. if (!mConstantDuration && !mCTSDeltaLength && mPreviousAUCount && rtpTime > mAccessUnitRTPTime) { mConstantDuration = (rtpTime - mAccessUnitRTPTime) / mPreviousAUCount; } mAccessUnitRTPTime = rtpTime; if (!mIsGeneric) { mPackets.push_back(buffer); } else { // hexdump(buffer->data(), buffer->size()); if (buffer->size() < 2u) { LOGW("Payload format error. Malformed packet."); return MALFORMED_PACKET; } unsigned AU_headers_length = U16_AT(buffer->data()); // in bits if (buffer->size() < 2 + (AU_headers_length + 7) / 8) { LOGW("Payload format error. Malformed packet."); return MALFORMED_PACKET; } List<AUHeader> headers; ABitReader bits(buffer->data() + 2, buffer->size() - 2); unsigned numBitsLeft = AU_headers_length; unsigned AU_serial = 0; for (;;) { if (numBitsLeft < mSizeLength) { break; } unsigned AU_size = bits.getBits(mSizeLength); numBitsLeft -= mSizeLength; size_t n = headers.empty() ? mIndexLength : mIndexDeltaLength; if (numBitsLeft < n) { break; } unsigned AU_index = bits.getBits(n); numBitsLeft -= n; if (headers.empty()) { AU_serial = AU_index; } else { AU_serial += 1 + AU_index; } if (mCTSDeltaLength > 0) { if (numBitsLeft < 1) { break; } --numBitsLeft; if (bits.getBits(1)) { if (numBitsLeft < mCTSDeltaLength) { break; } bits.skipBits(mCTSDeltaLength); numBitsLeft -= mCTSDeltaLength; } } if (mDTSDeltaLength > 0) { if (numBitsLeft < 1) { break; } --numBitsLeft; if (bits.getBits(1)) { if (numBitsLeft < mDTSDeltaLength) { break; } bits.skipBits(mDTSDeltaLength); numBitsLeft -= mDTSDeltaLength; } } if (mRandomAccessIndication) { if (numBitsLeft < 1) { break; } bits.skipBits(1); --numBitsLeft; } if (mStreamStateIndication > 0) { if (numBitsLeft < mStreamStateIndication) { break; } bits.skipBits(mStreamStateIndication); } AUHeader header; header.mSize = AU_size; header.mSerial = AU_serial; headers.push_back(header); } size_t offset = 2 + (AU_headers_length + 7) / 8; if (mAuxiliaryDataSizeLength > 0) { ABitReader bits(buffer->data() + offset, buffer->size() - offset); unsigned auxSize = bits.getBits(mAuxiliaryDataSizeLength); offset += (mAuxiliaryDataSizeLength + auxSize + 7) / 8; } mPreviousAUCount = 0; for (List<AUHeader>::iterator it = headers.begin(); it != headers.end(); ++it) { mPreviousAUCount++; const AUHeader &header = *it; const AUHeader &first = *headers.begin(); if (offset + header.mSize > buffer->size()) { LOGW("Payload format error. Malformed packet."); return MALFORMED_PACKET; } sp<ABuffer> accessUnit = new ABuffer(header.mSize); memcpy(accessUnit->data(), buffer->data() + offset, header.mSize); offset += header.mSize; int rtpTime = mAccessUnitRTPTime + mConstantDuration * (header.mSerial - first.mSerial); accessUnit->meta()->setInt32("rtp-time", rtpTime); accessUnit->setInt32Data(buffer->int32Data()); mPackets.push_back(accessUnit); } if (offset != buffer->size()) { LOGW("Payload format error. Malformed packet."); return MALFORMED_PACKET; } } queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; }
// 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 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; }
// 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; }
// 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; }
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; }
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; }
ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket( const sp<ARTPSource> &source) { List<sp<ABuffer> > *queue = source->queue(); if (queue->empty()) { return NOT_ENOUGH_DATA; } if (mNextExpectedSeqNoValid) { List<sp<ABuffer> >::iterator it = queue->begin(); while (it != queue->end()) { if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) { break; } it = queue->erase(it); } if (queue->empty()) { return NOT_ENOUGH_DATA; } } sp<ABuffer> buffer = *queue->begin(); if (!mNextExpectedSeqNoValid) { mNextExpectedSeqNoValid = true; mNextExpectedSeqNo = (uint32_t)buffer->int32Data(); } else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) { LOGV("Not the sequence number I expected"); return WRONG_SEQUENCE_NUMBER; } uint32_t rtpTime; CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime)); if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) { submitAccessUnit(); } mAccessUnitRTPTime = rtpTime; if (!mIsGeneric) { mPackets.push_back(buffer); } else { // hexdump(buffer->data(), buffer->size()); CHECK_GE(buffer->size(), 2u); unsigned AU_headers_length = U16_AT(buffer->data()); // in bits CHECK_GE(buffer->size(), 2 + (AU_headers_length + 7) / 8); List<AUHeader> headers; ABitReader bits(buffer->data() + 2, buffer->size() - 2); unsigned numBitsLeft = AU_headers_length; unsigned AU_serial = 0; for (;;) { if (numBitsLeft < mSizeLength) { break; } unsigned AU_size = bits.getBits(mSizeLength); numBitsLeft -= mSizeLength; size_t n = headers.empty() ? mIndexLength : mIndexDeltaLength; if (numBitsLeft < n) { break; } unsigned AU_index = bits.getBits(n); numBitsLeft -= n; if (headers.empty()) { AU_serial = AU_index; } else { AU_serial += 1 + AU_index; } if (mCTSDeltaLength > 0) { if (numBitsLeft < 1) { break; } --numBitsLeft; if (bits.getBits(1)) { if (numBitsLeft < mCTSDeltaLength) { break; } bits.skipBits(mCTSDeltaLength); numBitsLeft -= mCTSDeltaLength; } } if (mDTSDeltaLength > 0) { if (numBitsLeft < 1) { break; } --numBitsLeft; if (bits.getBits(1)) { if (numBitsLeft < mDTSDeltaLength) { break; } bits.skipBits(mDTSDeltaLength); numBitsLeft -= mDTSDeltaLength; } } if (mRandomAccessIndication) { if (numBitsLeft < 1) { break; } bits.skipBits(1); --numBitsLeft; } if (mStreamStateIndication > 0) { if (numBitsLeft < mStreamStateIndication) { break; } bits.skipBits(mStreamStateIndication); } AUHeader header; header.mSize = AU_size; header.mSerial = AU_serial; headers.push_back(header); } size_t offset = 2 + (AU_headers_length + 7) / 8; if (mAuxiliaryDataSizeLength > 0) { ABitReader bits(buffer->data() + offset, buffer->size() - offset); unsigned auxSize = bits.getBits(mAuxiliaryDataSizeLength); offset += (mAuxiliaryDataSizeLength + auxSize + 7) / 8; } for (List<AUHeader>::iterator it = headers.begin(); it != headers.end(); ++it) { const AUHeader &header = *it; CHECK_LE(offset + header.mSize, buffer->size()); sp<ABuffer> accessUnit = new ABuffer(header.mSize); memcpy(accessUnit->data(), buffer->data() + offset, header.mSize); offset += header.mSize; CopyTimes(accessUnit, buffer); mPackets.push_back(accessUnit); } CHECK_EQ(offset, buffer->size()); } queue->erase(queue->begin()); ++mNextExpectedSeqNo; return OK; }
// 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; }