SampleTable和SampleIterator的初始化和设置

SampleTable和SampleIterator的初始化和设置 (2012-12-31 22:41:16)
===================================================================
http://www.52rd.com/blog/Detail_RD.Blog_wqyuwss_7918.html
包含转化媒体时间到实际的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),
    mCompositionTimeDeltaEnt ries(NULL),
    mNumCompositionTimeDelta Entries(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->setCompositionTimeToSamp leParams(
                      data_offset, chunk_data_size);
          *offset += chunk_size;
          break;
      }
status_t SampleTable::setCompositionTimeToSamp leParams(
      off64_t data_offset, size_t data_size) {
  ALOGI("There are reordered frames present.");
  if (mCompositionTimeDeltaEnt ries != 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;
  }
  mNumCompositionTimeDelta Entries = numEntries;
  mCompositionTimeDeltaEnt ries = new uint32_t[2 * numEntries];
  if (mDataSource->readAt(
              data_offset + 8, mCompositionTimeDeltaEnt ries, numEntries * 8)
          < (ssize_t)numEntries * 8) {
      delete[] mCompositionTimeDeltaEnt ries;
      mCompositionTimeDeltaEnt ries = NULL;
      return ERROR_IO;
  }
  for (size_t i = 0; i < 2 * numEntries; ++i) {
      mCompositionTimeDeltaEnt ries[i] = ntohl(mCompositionTimeDeltaEnt ries[i]);
  }
  mCompositionDeltaLookup->setEntries(
          mCompositionTimeDeltaEnt ries, mNumCompositionTimeDelta Entries);
  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;
}

最后网友一片博文:讲述的MP4解析流程
http://www.360doc.com/content/10/0802/15/474846_43156144.shtml
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值