Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2150709
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2016-05-12 19:08:48

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 (i = 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的数据



阅读(2308) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~