上文中贴出了av_read_frame()函数的实现,现在更细致地分析一下其内部的实现流程。
av_read_frame()开始后,通常会调用read_frame_internal(s, pkt)函数:
static int read_frame_internal(AVFormatContext *s, AVPacket *pkt) { int ret = 0, i, got_packet = 0; av_init_packet(pkt); while (!got_packet && !s->parse_queue) { AVStream *st; AVPacket cur_pkt; /* read next packet */ ret = ff_read_packet(s, &cur_pkt); if (ret < 0) { if (ret == AVERROR(EAGAIN)) return ret; /* flush the parsers */ for(i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->parser && st->need_parsing) parse_packet(s, NULL, st->index); } /* all remaining packets are now in parse_queue => * really terminate parsing */ break; } ret = 0; st = s->streams[cur_pkt.stream_index]; if (cur_pkt.pts != AV_NOPTS_VALUE && cur_pkt.dts != AV_NOPTS_VALUE && cur_pkt.pts < cur_pkt.dts) { av_log(s, AV_LOG_WARNING, "Invalid timestamps stream=%d, pts=%s, dts=%s, size=%d\n", cur_pkt.stream_index, av_ts2str(cur_pkt.pts), av_ts2str(cur_pkt.dts), cur_pkt.size); } if (s->debug & FF_FDEBUG_TS) av_log(s, AV_LOG_DEBUG, "ff_read_packet stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", cur_pkt.stream_index, av_ts2str(cur_pkt.pts), av_ts2str(cur_pkt.dts), cur_pkt.size, cur_pkt.duration, cur_pkt.flags); if (st->need_parsing && !st->parser && !(s->flags & AVFMT_FLAG_NOPARSE)) { st->parser = av_parser_init(st->codec->codec_id); if (!st->parser) { av_log(s, AV_LOG_VERBOSE, "parser not found for codec " "%s, packets or times may be invalid.\n", avcodec_get_name(st->codec->codec_id)); /* no parser available: just output the raw packets */ st->need_parsing = AVSTREAM_PARSE_NONE; } else if(st->need_parsing == AVSTREAM_PARSE_HEADERS) { st->parser->flags |= PARSER_FLAG_COMPLETE_FRAMES; } else if(st->need_parsing == AVSTREAM_PARSE_FULL_ONCE) { st->parser->flags |= PARSER_FLAG_ONCE; } else if(st->need_parsing == AVSTREAM_PARSE_FULL_RAW) { st->parser->flags |= PARSER_FLAG_USE_CODEC_TS; } } if (!st->need_parsing || !st->parser) { /* no parsing needed: we just output the packet as is */ *pkt = cur_pkt; compute_pkt_fields(s, st, NULL, pkt); if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && (pkt->flags & AV_PKT_FLAG_KEY) && pkt->dts != AV_NOPTS_VALUE) { ff_reduce_index(s, st->index); av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME); } got_packet = 1; } else if (st->discard < AVDISCARD_ALL) { if ((ret = parse_packet(s, &cur_pkt, cur_pkt.stream_index)) < 0) return ret; } else { /* free packet */ av_free_packet(&cur_pkt); } if (pkt->flags & AV_PKT_FLAG_KEY) st->skip_to_keyframe = 0; if (st->skip_to_keyframe) { av_free_packet(&cur_pkt); if (got_packet) { *pkt = cur_pkt; } got_packet = 0; } } if (!got_packet && s->parse_queue) ret = read_from_packet_buffer(&s->parse_queue, &s->parse_queue_end, pkt); if(s->debug & FF_FDEBUG_TS) av_log(s, AV_LOG_DEBUG, "read_frame_internal stream=%d, pts=%s, dts=%s, size=%d, duration=%d, flags=%d\n", pkt->stream_index, av_ts2str(pkt->pts), av_ts2str(pkt->dts), pkt->size, pkt->duration, pkt->flags); return ret; }首先调用av_init_packet(pkt)对pkt进行初始化:
void av_init_packet(AVPacket *pkt) { pkt->pts = AV_NOPTS_VALUE; pkt->dts = AV_NOPTS_VALUE; pkt->pos = -1; pkt->duration = 0; pkt->convergence_duration = 0; pkt->flags = 0; pkt->stream_index = 0; #if FF_API_DESTRUCT_PACKET FF_DISABLE_DEPRECATION_WARNINGS pkt->destruct = NULL; FF_ENABLE_DEPRECATION_WARNINGS #endif pkt->buf = NULL; pkt->side_data = NULL; pkt->side_data_elems = 0; }该函数将pts、dts设为AV_NOPTS_VALUE,将pos初始化为-1,将其他参数设为0或空值;随后在一个while循环中,调用ff_read_packet函数读取数据:
int ff_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, i, err; AVStream *st; for(;;){ AVPacketList *pktl = s->raw_packet_buffer; if (pktl) { *pkt = pktl->pkt; st = s->streams[pkt->stream_index]; if (s->raw_packet_buffer_remaining_size <= 0) { if ((err = probe_codec(s, st, NULL)) < 0) return err; } if(st->request_probe <= 0){ s->raw_packet_buffer = pktl->next; s->raw_packet_buffer_remaining_size += pkt->size; av_free(pktl); return 0; } } pkt->data = NULL; pkt->size = 0; av_init_packet(pkt); ret= s->iformat->read_packet(s, pkt); if (ret < 0) { if (!pktl || ret == AVERROR(EAGAIN)) return ret; for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (st->probe_packets) { if ((err = probe_codec(s, st, NULL)) < 0) return err; } av_assert0(st->request_probe <= 0); } continue; } if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) && (pkt->flags & AV_PKT_FLAG_CORRUPT)) { av_log(s, AV_LOG_WARNING, "Dropped corrupted packet (stream = %d)\n", pkt->stream_index); av_free_packet(pkt); continue; } if(!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) av_packet_merge_side_data(pkt); if(pkt->stream_index >= (unsigned)s->nb_streams){ av_log(s, AV_LOG_ERROR, "Invalid stream index %d\n", pkt->stream_index); continue; } st= s->streams[pkt->stream_index]; pkt->dts = wrap_timestamp(st, pkt->dts); pkt->pts = wrap_timestamp(st, pkt->pts); force_codec_ids(s, st); /* TODO: audio: time filter; video: frame reordering (pts != dts) */ if (s->use_wallclock_as_timestamps) pkt->dts = pkt->pts = av_rescale_q(av_gettime(), AV_TIME_BASE_Q, st->time_base); if(!pktl && st->request_probe <= 0) return ret; add_to_pktbuf(&s->raw_packet_buffer, pkt, &s->raw_packet_buffer_end); s->raw_packet_buffer_remaining_size -= pkt->size; if ((err = probe_codec(s, st, pkt)) < 0) return err; } }该函数从AVFormatContext指针格式的媒体文件句柄中读取待解码数据,并储存于AVPacket实例中。当读取成功时返回0,读取失败则返回AVERROR值。
AVInputFormat ff_mov_demuxer = { .name = "mov,mp4,m4a,3gp,3g2,mj2", .long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"), .priv_data_size = sizeof(MOVContext), .read_probe = mov_probe, .read_header = mov_read_header, .read_packet = mov_read_packet, .read_close = mov_read_close, .read_seek = mov_read_seek, .priv_class = &mov_class, .flags = AVFMT_NO_BYTE_SEEK, };其read_packet指针指向mov_read_packet函数,这个函数的内容也比较长,暂时就不贴了,有时间慢慢分析。