ffmpeg源码分析--12.mov的mov_read_packet


1. mov_read_packet的 调用过程
av_read_frame
 -->read_frame_internal
   --> ff_read_packet
      --> mov_read_packet

"stsz"定义了每个video_sample与每个sound_sample的sample_sizes大小
"stco"定义了每个video_chunk与每个sound_chunk在san.mp4这个文件内的offset
所以从san.mp4这个文件的offset处读取sample_sizes就是音视频的数据.
2.  mov_find_next_sample说明
mov_read_packet
-->mov_find_next_sample
  1. static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st)
  2. {
  3.     AVIndexEntry *sample = NULL;
  4.     int64_t best_dts = INT64_MAX;
  5.     int i;
  6.     for (= 0; i < s->nb_streams; i++) {
  7.         AVStream *avst = s->streams[i];
  8.         MOVStreamContext *msc = avst->priv_data;
  9.         if (msc->pb && msc->current_sample < avst->nb_index_entries) {
  10.             AVIndexEntry *current_sample = &avst->index_entries[msc->current_sample];
  11.             int64_t dts = av_rescale(current_sample->timestamp, AV_TIME_BASE, msc->time_scale);
  12.             if (!sample || (!s->pb->seekable && current_sample->pos < sample->pos) ||
  13.                 (s->pb->seekable &&
  14.                  ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb &&
  15.                  ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) ||
  16.                   (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) {
  17.                 sample = current_sample;
  18.                 best_dts = dts;
  19.                 *st = avst;
  20.             }
  21.         }
  22.     }
  23.     return sample;
  24. }
在"stco"中有一系列的chunk_offsets,既包含video的也包含sound的chunk_offsets
上面函数的作用就是从avst->index_entries中分离出所有的chunk_offsets
AV_TIME_BASE=1000000
mov_read_mdhd[1156]: sc->time_scale=0x5dc2=24002  -->视频的time_scale
mov_read_mdhd[1156]: sc->time_scale=0xac44=44100  -->音频的time_scale
  1. 从stco中读取出来如下的video与audio的chunk:
  2. video:
  3. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[0]=0x30
  4. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[1]=0x137d
  5. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[2]=0x253c
  6. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[3]=0x3143
  7. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[4]=0x3ca7
  8. audio:
  9. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[0]=0x1363
  10. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[1]=0x22ec
  11. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[2]=0x22f5
  12. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[3]=0x22fe
  13. cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[4]=0x239f

  14. next_sample的顺序就是如下:
  15. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x30,sample->timestamp=0xfffffffffffffc17,size=0x1333
  16. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x1363,sample->timestamp=0x0,size=0x1a
  17. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x137d,sample->timestamp=0x0,size=0xf6f
  18. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x22ec,sample->timestamp=0x400,size=0x9
  19. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x22f5,sample->timestamp=0x800,size=0x9
  20. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x22fe,sample->timestamp=0xc00,size=0xa1
  21. cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x239f,sample->timestamp=0x1000,size=0xc9
mov_find_next_sample按照chunk_offset的值从小到大依次排列
这个函数中计算的dts,只是一个中间的结果,不是真正的dts

3.mov_read_packet
  1. static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
  2. {
  3.     MOVContext *mov = s->priv_data;
  4.     MOVStreamContext *sc;
  5.     AVIndexEntry *sample;
  6.     AVStream *st = NULL;
  7.     int ret;
  8.     mov->fc = s;
  9.  retry:
  10.     sample = mov_find_next_sample(s, &st);   //查找下一个sample
  11.     sc = st->priv_data;
  12.     sc->current_sample++;

  13.     if (st->discard != AVDISCARD_ALL) {
  14.         //通过sample中的pos找到媒体文件中的sample起始点与大小,然后根据这个去读取媒体文件的内容
  15.         int64_t ret64 = avio_seek(sc->pb, sample->pos, SEEK_SET);
  16.         ret = av_get_packet(sc->pb, pkt, sample->size);  //读取媒体文件的内容,大小是sample->size
  17.     }
  18.     pkt->stream_index = sc->ffindex;
  19.     pkt->dts = sample->timestamp;                            //dts是计算出来的"start_time+samplduration"
  20.     if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
  21.         pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration;
  22.         sc->ctts_sample++;
  23.         if (sc->ctts_index < sc->ctts_count &&
  24.             sc->ctts_data[sc->ctts_index].count == sc->ctts_sample) {
  25.             sc->ctts_index++;
  26.             sc->ctts_sample = 0;
  27.         }
  28.     } else {
  29.         int64_t next_dts = (sc->current_sample < st->nb_index_entries) ?
  30.             st->index_entries[sc->current_sample].timestamp : st->duration;
  31.         pkt->duration = next_dts - pkt->dts;
  32.         pkt->pts = pkt->dts;
  33.     }
  34.     pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
  35.     pkt->pos = sample->pos;
  36.     
  37.     return 0;
  38. }
到此,mov_read_packet己经很明确了
a. mov_find_next_sample找到要读取的文件的偏移 + size
b. avio_seek(sc->pb, sample->pos, SEEK_SET); 将文件的指针定位到文件的偏移处
c. av_get_packet(sc->pb, pkt, sample->size); 从文件的偏移读取size的数据
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值