parseChunk学习

任意一个MP4文件,它都是由一个个相邻的box组成的,播放MP4文件前需要解析这些box获得视频的数据,主要结构如下:

fytp-----------moov(视频数据结构)---------------------------------mdat(视频数据)
                        |                                                                           |
                        |-----mvhd                                                             |----chunk1
                        |-----trak                                                              |           |
                        |-----trak                                                              |           |--sample1
                                   |                                                                 |           |--sample2
                                   |----tkhd                                                     |           |--samplen
                                   |----mdia                                                     |
                                                                                                  |
                                            |--mdhd                                               |
                                            |--minf                                              |----chunkn
                                                  |                                                            |
                                                  |---stbl                                                 |--samplem
                                                         |
                                                         |---stts
                                                         |---stsd
                                                         |---stsc
                                                         |---stco
                                                         |---....

1:解析FOURCC('s', 't', 'b', 'l')和FOURCC('t', 'r', 'a', 'k')这种容器型的box之后会跟着解析器内部的子box,两者的代码是放在一起的
2:parseChunk主要是解析moov以及其内部的子box,上面这段代码放在判断moov之前,就是为了在确保遇到moov函数返回前,会进行moov内部子box的深入解析。
case FOURCC('m', 'o', 'o', 'v'):
            case FOURCC('t', 'r', 'a', 'k'):
            case FOURCC('m', 'd', 'i', 'a'):
            case FOURCC('m', 'i', 'n', 'f'):
            case FOURCC('d', 'i', 'n', 'f'):
            case FOURCC('s', 't', 'b', 'l'):
            case FOURCC('m', 'v', 'e', 'x'):
            case FOURCC('m', 'o', 'o', 'f'):
            case FOURCC('t', 'r', 'a', 'f'):
            case FOURCC('m', 'f', 'r', 'a'):
            case FOURCC('u', 'd', 't', 'a'):
            case FOURCC('i', 'l', 's', 't'):
            {
                   if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
                        LOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
                        mLastTrack->sampleTable = new SampleTable(mDataSource);
                  }
                  bool isTrack = false;
                   if (chunk_type == FOURCC('t', 'r', 'a', 'k')) {
                        isTrack = true;

                        Track *track = new Track;
                        track->next = NULL;
                        if (mLastTrack) {
                              mLastTrack->next = track;
                        } else {
                              mFirstTrack = track;
                        }
                  }

                   off64_t stop_offset = *offset + chunk_size;
            *offset = data_offset;
            while (*offset < stop_offset) {
                status_t err = parseChunk(offset, depth + 1);
                if (err != OK) {
                    return err;
                }
            }

                  if (*offset != stop_offset) {
                        return ERROR_MALFORMED;
                  }

                  if (isTrack) {
                        if (mLastTrack->skipTrack) {
                              Track *cur = mFirstTrack;

                              if (cur == mLastTrack) {
                                    delete cur;
                                    mFirstTrack = mLastTrack = NULL;
                              }
                   } else if (chunk_type == FOURCC('m', 'o', 'o', 'v')) {
                        mInitCheck = OK;
                        if (!mIsDrm) {
                              return UNKNOWN_ERROR;   // Return a dummy error.
                        } else {
                              return OK;
                        }
                  }
                  break;
            }

3:解析trak的第一个子box,tkhd头box
case FOURCC('t', 'k', 'h', 'd'):
            {
                  status_t err;
                  if (( err = parseTrackHeader(data_offset, chunk_data_size)) != OK) {
                        return err;
                  }
                  *offset += chunk_size;
                  break;
            }
4:解析mdia box中的第一个子box,头box:mdhd,并分别从里面获取版本,timescale,track的时常等信息
            case FOURCC('m', 'd', 'h', 'd'):
            {
                  if (chunk_data_size < 4) {
                        return ERROR_MALFORMED;
                  }

                   uint8_t version;
            if (mDataSource->readAt(
                        data_offset, &version, sizeof(version))
                    < (ssize_t)sizeof(version)) {
                return ERROR_IO;
            }

                   mLastTrack->timescale = ntohl(timescale);

                  int64_t duration;

                   mLastTrack->meta->setInt64(
                    kKeyDuration, (duration * 1000000) / mLastTrack->timescale);

                   mLastTrack->meta->setCString(
                    kKeyMediaLanguage, lang_code);

                  *offset += chunk_size;
                  break;
            }

5:音频相关的box的解析,获取音频相关的信息
case FOURCC('m', 'p', '4', 'a'):
            case FOURCC('s', 'a', 'm', 'r'):
            case FOURCC('s', 'a', 'w', 'b'):
            {
                  uint8_t buffer[8 + 20];
                  if (mDataSource->readAt(
                                    data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
                        return ERROR_IO;
                  }
                  uint16_t data_ref_index = U16_AT(&buffer[6]);
                  uint16_t num_channels = U16_AT(&buffer[16]);
                  uint16_t sample_size = U16_AT(&buffer[18]);
                  uint32_t sample_rate = U32_AT(&buffer[24]) >> 16;
                  if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB,
                                          FourCC2MIME(chunk_type))) {
                        // AMR NB audio is always mono, 8kHz
                        num_channels = 1;
                        sample_rate = 8000;
                  } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB,
                                               FourCC2MIME(chunk_type))) {
                        // AMR WB audio is always mono, 16kHz
                        num_channels = 1;
                        sample_rate = 16000;
                  }
                  mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
                  mLastTrack->meta->setInt32(kKeyChannelCount, num_channels);
                  mLastTrack->meta->setInt32(kKeySampleRate, sample_rate);

                  off64_t stop_offset = *offset + chunk_size;
                  *offset = data_offset + sizeof(buffer);
                  while (*offset < stop_offset) {
                        status_t err = parseChunk(offset, depth + 1);
                        if (err != OK) {
                              return err;
                        }
                  }
                  if (*offset != stop_offset) {
                        return ERROR_MALFORMED;
                  }
                  break;
            }
6:视频box解析,获取视频相关的信息
            case FOURCC('m', 'p', '4', 'v'):
            case FOURCC('s', '2', '6', '3'):
            case FOURCC('H', '2', '6', '3'):
            case FOURCC('h', '2', '6', '3'):
            case FOURCC('a', 'v', 'c', '1'):
            {
                  mHasVideo = true;
                  uint8_t buffer[78];
                  if (mDataSource->readAt(
                                    data_offset, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
                        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]);

                  // The video sample is not stand-compliant if it has invalid dimension.
                  // Use some default width and height value, and
                  // let the decoder figure out the actual width and height (and thus
                  // be prepared for INFO_FOMRAT_CHANGED event).
                  if (width == 0)   width   = 352;
                  if (height == 0) height = 288;

                  mLastTrack->meta->setCString(kKeyMIMEType, FourCC2MIME(chunk_type));
                  mLastTrack->meta->setInt32(kKeyWidth, width);
                  mLastTrack->meta->setInt32(kKeyHeight, height);

                  off64_t stop_offset = *offset + chunk_size;
                  *offset = data_offset + sizeof(buffer);
                  while (*offset < stop_offset) {
                        status_t err = parseChunk(offset, depth + 1);
                        if (err != OK) {
                              return err;
                        }
                  }
                  break;
            }
7:所有stbl box以及其子box相关的解析,解析stbl的时候new了一个SampleTable,随后调用其各个方法完成设置,大部分函数的参数为data_offset,和chunk_data_size。
if (chunk_type == FOURCC('s', 't', 'b', 'l')) {
                        LOGV("sampleTable chunk is %d bytes long.", (size_t)chunk_size);
                         mLastTrack->sampleTable = new SampleTable(mDataSource);
}

case FOURCC('s', 't', 's', 'd'):
            {
                  break;
}

            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;
            }

            case FOURCC('s', 't', 's', 'c'):
            {
                   status_t err =
                mLastTrack->sampleTable->setSampleToChunkParams(
                        data_offset, chunk_data_size);
                  *offset += chunk_size;
                  break;
            }

            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;
            }
            case FOURCC('s', 't', 't', 's'):
            {
                  status_t err =
                         mLastTrack->sampleTable->setTimeToSampleParams(
                        data_offset, chunk_data_size);
                  *offset += chunk_size;
                  break;
            }
            case FOURCC('c', 't', 't', 's'):
            {
                  status_t err =
                         mLastTrack->sampleTable->setCompositionTimeToSampleParams(
                        data_offset, chunk_data_size);
                  *offset += chunk_size;
                  break;
            }
            case FOURCC('s', 't', 's', 's'):
            {
                  status_t err =
                         mLastTrack->sampleTable->setSyncSampleParams(
                        data_offset, chunk_data_size);
                  *offset += chunk_size;
                  break;
            }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值