包含转化媒体时间到实际的sample的信息,是一个容器,包含下面的所有的表
if (chunk_type ==
FOURCC('s', 't', 'b', 'l')) {
ALOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
mLastTrack->sampleTable =
new SampleTable(mDataSource);
}
初始化所有变量的值,主要是各个boxer数据部分的偏移地址,以便于调用readAt函数读取解析
SampleTable::SampleTable(const sp &source)
: mDataSource(source),
mChunkOffsetOffset(-1),
mChunkOffsetType(0),
mNumChunkOffsets(0),
mSampleToChunkOffset(-1),
mNumSampleToChunkOffsets(0),
mSampleSizeOffset(-1),
mSampleSizeFieldSize(0),
mDefaultSampleSize(0),
mNumSampleSizes(0),
mTimeToSampleCount(0),
mTimeToSample(NULL),
mSampleTimeEntries(NULL),
mCompositionTimeDeltaEntries(NULL),
mNumCompositionTimeDeltaEntries(0),
mCompositionDeltaLookup(new CompositionDeltaLookup),
mSyncSampleOffset(-1),
mNumSyncSamples(0),
mSyncSamples(NULL),
mLastSyncSampleIndex(0),
mSampleToChunkEntries(NULL) {
mSampleIterator = new SampleIterator(this);
}
SampleIterator::SampleIterator(SampleTable *table)
: mTable(table),
mInitialized(false),
mTimeToSampleIndex(0),
mTTSSampleIndex(0),
mTTSSampleTime(0),
mTTSCount(0),
mTTSDuration(0) {
reset();
}
void SampleIterator::reset() {
mSampleToChunkIndex = 0;
mFirstChunk = 0;
mFirstChunkSampleIndex = 0;
mStopChunk = 0;
mStopChunkSampleIndex = 0;
mSamplesPerChunk = 0;
mChunkDesc = 0;
}
==============================================================
http://www.52rd.com/Blog/Detail_RD.Blog_wqyuwss_7925.html
每个chunk的相对于文件起始位置的偏移
case FOURCC('s', 't', 'c', 'o'):
case FOURCC('c', 'o', '6', '4'):
{
status_t err =
mLastTrack->
sampleTable->setChunkOffsetParams(
chunk_type, data_offset, chunk_data_size);
*offset += chunk_size;
break;
}
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);
stco boxer数据部分的偏移位置
mChunkOffsetOffset = data_offset;
mChunkOffsetType = type;
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]);
chunk的数目,每个chunk具体文件开始的便宜用4个字节或者八个字节来记录,
以四个字节为例子:
第一个chunk的便宜位置:U32_AT(&header[mChunkOffsetOffset+
8+0*4]);
第二个chunk的便宜位置:U32_AT(&header[mChunkOffsetOffset+
8+1*4]);
第三个chunk的便宜位置:U32_AT(&header[mChunkOffsetOffset+
8+2*4]);
第四个chunk的便宜位置:U32_AT(&header[mChunkOffsetOffset+
8+3*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;
}
===========================================================
http://www.52rd.com/Blog/Detail_RD.Blog_wqyuwss_7922.html
sample to chunk,也即是当前这个sample在哪一个chunk
case FOURCC('s', 't', 's', 'c'):
{
status_t err =
mLastTrack->sampleTable->
setSampleToChunkParams(
data_offset, chunk_data_size);
*offset += chunk_size;
break;
}
status_t SampleTable::setSampleToChunkParams(
off64_t data_offset, size_t data_size) {
mSampleToChunkOffset = 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;
}
mNumSampleToChunkOffsets = U32_AT(&header[4]);
if (data_size < 8 +
mNumSampleToChunkOffsets * 12) {
return ERROR_MALFORMED;
}
mSampleToChunkEntries =
new SampleToChunkEntry[mNumSampleToChunkOffsets];
for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
uint8_t buffer[12];
if (mDataSource->readAt(
mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
!= (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
// We want the chunk index to be 0-based.
mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
}
每个sampleToChunk占12个字节:每四个字节表示不同的含义
偏移地址计算公式:mSampleToChunkOffset + 8 + i * 12
每四字节的含义:
1:这个table使用的第一个chunk序号
2:当前trunk内的sample数目
3:与这些sample关联的sample description的序号
return OK;
}
===================================================
http://www.52rd.com/Blog/Detail_RD.Blog_wqyuwss_7924.html
stsz 记录了每个sample的大小以及全部sample的数目
case FOURCC('s', 't', 's', 'z'):
case FOURCC('s', 't', 'z', '2'):
{
status_t err =
mLastTrack->sampleTable->
setSampleSizeParams(
chunk_type, data_offset, chunk_data_size);
size_t max_size;
err =
mLastTrack->sampleTable->getMaxSampleSize(&max_size);
// Assume that a given buffer only contains at most 10 fragments,
// each fragment originally prefixed with a 2 byte length will
// have a 4 byte header (0x00 0x00 0x00 0x01) after conversion,
// and thus will grow by 2 bytes per fragment.
mLastTrack->meta->setInt32(kKeyMaxInputSize, max_size + 10 * 2);
*offset += chunk_size;
// Calculate average frame rate.
计算公式看起来非常简单: 总时长/总的帧数
const char *mime;
CHECK(mLastTrack->meta->findCString(kKeyMIMEType, &mime));
if (!strncasecmp("video/", mime, 6)) {
size_t nSamples = mLastTrack->sampleTable->countSamples();
int64_t durationUs;
if (mLastTrack->meta->findInt64(kKeyDuration, &durationUs)) {
if (durationUs > 0) {
int32_t frameRate = (nSamples * 1000000LL +
(durationUs >> 1)) / durationUs;
mLastTrack->meta->setInt32(kKeyFrameRate, frameRate);
}
}
}
break;
}
status_t SampleTable::setSampleSizeParams(
uint32_t type, off64_t data_offset, size_t data_size) {
mSampleSizeOffset = data_offset;
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]); 默认的每一个sample的大小,如果大于0,则表示所有的sample大小一致,即为
mDefaultSampleSize
mNumSampleSizes = U32_AT(&header[8]); sample的数目
if (type == kSampleSizeType32) {
mSampleSizeFieldSize = 32;用四个字节来表示每一个sample的大小,所以数据去总长度不能小于12 + mNumSampleSizes * 4
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;用来表示sample大小的字节数
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;
}
下面的各个函数是计算每一个sample的大小,然后选择大小最大的那个,就是四字节四字节的读取
status_t SampleTable::getMaxSampleSize(size_t *max_size) {
Mutex::Autolock autoLock(mLock);
*max_size = 0;
for (
uint32_t i = 0; i < mNumSampleSizes; ++i) { 循环获取每个sample的大小
size_t sample_size;
status_t err = getSampleSize_l(i, &sample_size);
if (sample_size > *max_size) {
*max_size = sample_size;
}
}
return OK;
}
status_t SampleTable::getSampleSize_l(
uint32_t sampleIndex, size_t *sampleSize) {
return mSampleIterator->getSampleSizeDirect(
sampleIndex, sampleSize);
}
status_t SampleIterator::getSampleSizeDirect(
uint32_t sampleIndex, size_t *size) {
*size = 0;
if (sampleIndex >= mTable->mNumSampleSizes) {
return ERROR_OUT_OF_RANGE;
}
if (mTable->mDefaultSampleSize > 0) {
*size = mTable->mDefaultSampleSize;
return OK;
}
switch (mTable->mSampleSizeFieldSize) {
case 32:
{
红色部分为每一个sample的偏移位置
if (mTable->mDataSource->readAt(
mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
size, sizeof(*size)) < (ssize_t)sizeof(*size)) {
return ERROR_IO;
}
*size = ntohl(*size);
break;
}
case 16:
{
uint16_t x;
if (mTable->mDataSource->readAt(
mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
&x, sizeof(x)) < (ssize_t)sizeof(x)) {
return ERROR_IO;
}
*size = ntohs(x);
break;
}
case 8:
{
uint8_t x;
if (mTable->mDataSource->readAt(
mTable->mSampleSizeOffset + 12 + sampleIndex,
&x, sizeof(x)) < (ssize_t)sizeof(x)) {
return ERROR_IO;
}
*size = x;
break;
}
default:
{
CHECK_EQ(mTable->mSampleSizeFieldSize, 4);
uint8_t x;
if (mTable->mDataSource->readAt(
mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
&x, sizeof(x)) < (ssize_t)sizeof(x)) {
return ERROR_IO;
}
*size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
break;
}
}
return OK;
}
===================================================
http://www.52rd.com/blog/Detail_RD.Blog_wqyuwss_7920.html
每一个时间点映射到具体的sample上,Time-to-sample atoms存储了media sample的duration信息,提供了时间对具体data sample的映射方法,通过这个atom,你可以找到任何时间的sample
case FOURCC('s', 't', 't', 's'):
{
status_t err =
mLastTrack->sampleTable->
setTimeToSampleParams(
data_offset, chunk_data_size);
*offset += chunk_size;
break;
}
status_t SampleTable::setTimeToSampleParams(
off64_t data_offset, size_t data_size) {
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];
这里为什么要乘2呢???
size_t size = sizeof(uint32_t) *
mTimeToSampleCount * 2;
mTimeToSample每个元素占四个字节,最后得到mTimeToSample这张表
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;
}
========================================================
case FOURCC('c', 't', 't', 's'):
{
status_t err =
mLastTrack->sampleTable->setCompositionTimeToSampleParams(
data_offset, chunk_data_size);
*offset += chunk_size;
break;
}
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;
mCompositionTimeDeltaEntries = new uint32_t[2 * numEntries];
if (mDataSource->readAt(
data_offset + 8, mCompositionTimeDeltaEntries, numEntries * 8)
< (ssize_t)numEntries * 8) {
delete[] mCompositionTimeDeltaEntries;
mCompositionTimeDeltaEntries = NULL;
return ERROR_IO;
}
for (size_t i = 0; i < 2 * numEntries; ++i) {
mCompositionTimeDeltaEntries[i] = ntohl(mCompositionTimeDeltaEntries[i]);
}
mCompositionDeltaLookup->setEntries(
mCompositionTimeDeltaEntries, mNumCompositionTimeDeltaEntries);
return OK;
}
==================================================
http://www.cnblogs.com/haibindev/archive/2011/10/17/2214518.html
可随机访问的sample列表,关键帧列表
case FOURCC('s', 't', 's', 's'):
{
status_t err =
mLastTrack->sampleTable->setSyncSampleParams(
data_offset, chunk_data_size);
*offset += chunk_size;
break;
}
status_t SampleTable::setSyncSampleParams(off64_t data_offset, size_t data_size) {
mSyncSampleOffset = data_offset;
uint8_t header[8];
if (mDataSource->readAt(
data_offset, header, sizeof(header)) < (ssize_t)sizeof(header)) {
return ERROR_IO;
}
if (
U32_AT(header) != 0) {
// Expected version = 0, flags = 0.
return ERROR_MALFORMED;
}
mNumSyncSamples = U32_AT(&header[4]);
if (mNumSyncSamples < 2) {
ALOGV("Table of sync samples is empty or has only a single entry!");
}
mSyncSamples = new uint32_t[mNumSyncSamples]; 用四个字节来记录关键帧的
size_t size = mNumSyncSamples * sizeof(uint32_t);
if (mDataSource->readAt(
mSyncSampleOffset + 8, mSyncSamples, size)
!= (ssize_t)size) {
return ERROR_IO;
}
for (size_t i = 0; i < mNumSyncSamples; ++i) {
mSyncSamples[i] = ntohl(mSyncSamples[i]) - 1;
}
return OK;
}