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;
-
}
在"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
-
从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
mov_find_next_sample按照chunk_offset的值从小到大依次排列
这个函数中计算的dts,只是一个中间的结果,不是真正的dts
3.mov_read_packet
-
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;
-
}
到此,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的数据
阅读(2336) | 评论(0) | 转发(0) |