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
- static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st)
- {
- AVIndexEntry *sample = NULL;
- int64_t best_dts = INT64_MAX;
- int i;
- for (i = 0; i < s->nb_streams; i++) {
- AVStream *avst = s->streams[i];
- MOVStreamContext *msc = avst->priv_data;
- if (msc->pb && msc->current_sample < avst->nb_index_entries) {
- AVIndexEntry *current_sample = &avst->index_entries[msc->current_sample];
- int64_t dts = av_rescale(current_sample->timestamp, AV_TIME_BASE, msc->time_scale);
- if (!sample || (!s->pb->seekable && current_sample->pos < sample->pos) ||
- (s->pb->seekable &&
- ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb &&
- ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) ||
- (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) {
- sample = current_sample;
- best_dts = dts;
- *st = avst;
- }
- }
- }
- return sample;
- }
上面函数的作用就是从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
- 从stco中读取出来如下的video与audio的chunk:
- video:
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[0]=0x30
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[1]=0x137d
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[2]=0x253c
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[3]=0x3143
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[4]=0x3ca7
- audio:
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[0]=0x1363
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[1]=0x22ec
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[2]=0x22f5
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[3]=0x22fe
- cong:libavformat/mov.c:mov_read_stco[1693]: chunk_offsets[4]=0x239f
-
- next_sample的顺序就是如下:
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x30,sample->timestamp=0xfffffffffffffc17,size=0x1333
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x1363,sample->timestamp=0x0,size=0x1a
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x137d,sample->timestamp=0x0,size=0xf6f
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x22ec,sample->timestamp=0x400,size=0x9
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x22f5,sample->timestamp=0x800,size=0x9
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x22fe,sample->timestamp=0xc00,size=0xa1
- cong:libavformat/mov.c:mov_read_packet[5026]: sample->pos=0x239f,sample->timestamp=0x1000,size=0xc9
这个函数中计算的dts,只是一个中间的结果,不是真正的dts
- static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
- {
- MOVContext *mov = s->priv_data;
- MOVStreamContext *sc;
- AVIndexEntry *sample;
- AVStream *st = NULL;
- int ret;
- mov->fc = s;
- retry:
- sample = mov_find_next_sample(s, &st); //查找下一个sample
- sc = st->priv_data;
- sc->current_sample++;
-
- if (st->discard != AVDISCARD_ALL) {
- //通过sample中的pos找到媒体文件中的sample起始点与大小,然后根据这个去读取媒体文件的内容
- int64_t ret64 = avio_seek(sc->pb, sample->pos, SEEK_SET);
- ret = av_get_packet(sc->pb, pkt, sample->size); //读取媒体文件的内容,大小是sample->size
- }
- pkt->stream_index = sc->ffindex;
- pkt->dts = sample->timestamp; //dts是计算出来的"start_time+samplduration"
- if (sc->ctts_data && sc->ctts_index < sc->ctts_count) {
- pkt->pts = pkt->dts + sc->dts_shift + sc->ctts_data[sc->ctts_index].duration;
- sc->ctts_sample++;
- if (sc->ctts_index < sc->ctts_count &&
- sc->ctts_data[sc->ctts_index].count == sc->ctts_sample) {
- sc->ctts_index++;
- sc->ctts_sample = 0;
- }
- } else {
- int64_t next_dts = (sc->current_sample < st->nb_index_entries) ?
- st->index_entries[sc->current_sample].timestamp : st->duration;
- pkt->duration = next_dts - pkt->dts;
- pkt->pts = pkt->dts;
- }
- pkt->flags |= sample->flags & AVINDEX_KEYFRAME ? AV_PKT_FLAG_KEY : 0;
- pkt->pos = sample->pos;
- return 0;
- }
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的数据