m4a音频无法seek

m4a音频无法seek

(2013-10-07 20:44:33)
测试发现一首歌曲无法seek,每次拖动到任意位置,都弹回到最开始处然后播放。

问题分析过程:
1:首先确定seek到的时间有没有传递到底层去,因为是本地纯音频播放,所以直接到AudioPlayer中加个log看看
status_t AudioPlayer::seekTo(int64_t time_us) {
  Mutex::Autolock autoLock(mLock);
  mSeeking = true;
  mPositionTimeRealUs = mPositionTimeMediaUs = -1;
  mReachedEOS = false;
  mSeekTimeUs = time_us;

  // Flush resets the number of played frames
  mNumFramesPlayed = 0;
  mNumFramesPlayedSysTimeU s = ALooper::GetNowUs();
  ......
  return OK;
}
通过打log,seek的时间正常传递了过来,并且更新了蓝色部分的两个值。

2:然后就分析buffer的读取了,buffer的读取是在fillBuffer里面循环读取的,当然做了seek操作和没有seek操作会有一点区别:
size_t AudioPlayer::fillBuffer(void *data, size_t size) {
  while (size_remaining > 0) {
      MediaSource::ReadOptions options;
      {
          Mutex::Autolock autoLock(mLock);

          if (mSeeking) {
              options.setSeekTo(mSeekTimeUs);
              mSeeking = false;
          }
      }
      err = mSource->read(&mInputBuffer, &options);
   
}
如果发生seek的话,options会携带要seek到的位置,加seek的模式传递到mSource的read函数中,我们知道每一种流都会对应一种流,我们这里的音频文件的mime是video/m4a格式的,其选择的解析器是MPEG4Extractor以及流是MPEG4Source,看其read部分的部分代码:
  ReadOptions::SeekMode mode;
  if (options && options->getSeekTo(&seekTimeUs, &mode)) {
      uint32_t findFlags = 0;
      switch (mode) {
          case ReadOptions::SEEK_PREVIOUS_SYNC:
              findFlags = SampleTable::kFlagBefore;
              break;
          case ReadOptions::SEEK_NEXT_SYNC:
              findFlags = SampleTable::kFlagAfter;
              break;
          case ReadOptions::SEEK_CLOSEST_SYNC:
          case ReadOptions::SEEK_CLOSEST:
              findFlags = SampleTable::kFlagClosest;
              break;
          default:
              CHECK(!"Should not be here.");
              break;
      }

      uint32_t sampleIndex;
      status_t err = mSampleTable->findSampleAtTime(
              seekTimeUs * mTimescale / 1000000,
              &sampleIndex, findFlags);

      uint32_t syncSampleIndex;
      if (err == OK) {
          err = mSampleTable->findSyncSampleNear(
                  sampleIndex, & syncSampleIndex, findFlags);
      }

      uint32_t sampleTime;
      if (err == OK) {
          err = mSampleTable->getMetaDataForSample(
                  sampleIndex, NULL, NULL, &sampleTime);
      }
      mCurrentSampleIndex = syncSampleIndex;
     
      status_t err =
          mSampleTable->getMetaDataForSample(
                  mCurrentSampleIndex, &offset, &size, &cts, &isSyncSample);
通过分析这段代码问题找到了

seek的情况处理如下:
1:取出options里面的seekTimeUs和mode;
2:根据seekTimeUs找到对应的sample的sampleIndex,打log发现这块是没有问题的,index找对了;
3:通过sampleIndex找syncSampleIndex,打log发现,这块有问题,syncSampleIndex每次都是0;
4:将syncSampleIndex赋给mCurrentSampleIndex;
5:通过mCurrentSampleIndex得到对应的sample的size,offset等信息

由于syncSampleIndex获取每次都是0,mCurrentSampleIndex也就是0,也就是第一帧,所以每次都是从0开始播放,至于为什么是零,在SampleTable中打log发现,这首歌曲关键帧列表是空的,也就是没有关键帧。对于avc格式的音视频资源来说,播放都要从附近的关键帧开始播放,没有关键帧就乱套了。


对于视频流,会分配很多关键帧;
对于音频流,默认所有的帧都是关键帧。

解决方法
加判断,对于这种没有关键帧的audio,特殊处理,略。

以前还分析过,由于码率不对,导致无法seek的情况,正常高品质MP3文件对应的码率是320,但是由于编码导致的问题,文件中读取出来的码率却是32,导致通过码率计算出来的时间戳都不对,导致seek失败。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值