转自:http://blog.csdn.net/shaqoneal/article/details/16960927
AVPacket结构用于保存压缩编码过的数据。在解码时,该结构的实例通常作为解复用器(demuxer)的输出并输入到解码器中;在编码时,通常是编码器的输出,并输入到复用器(muxer)中。该结构体的定义如下:
- typedef struct AVPacket {
-
-
-
-
-
- AVBufferRef *buf;
-
-
-
-
-
-
-
-
-
- int64_t pts;
-
-
-
-
-
- int64_t dts;
- uint8_t *data;
- int size;
- int stream_index;
-
-
-
- int flags;
-
-
-
-
- struct {
- uint8_t *data;
- int size;
- enum AVPacketSideDataType type;
- } *side_data;
- int side_data_elems;
-
-
-
-
-
- int duration;
- #if FF_API_DESTRUCT_PACKET
- attribute_deprecated
- void (*destruct)(struct AVPacket *);
- attribute_deprecated
- void *priv;
- #endif
- int64_t pos;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- int64_t convergence_duration;
- } AVPacket;
在demo中,调用了av_read_frame(pFormatCtx, &packet)函数从pFormatCtx所指向的环境的文件中读取压缩码流数据,保存到AVPacket实例packet中。av_read_frame()函数实现如下所示:
- int av_read_frame(AVFormatContext *s, AVPacket *pkt)
- {
- const int genpts = s->flags & AVFMT_FLAG_GENPTS;
- int eof = 0;
- int ret;
- AVStream *st;
-
- if (!genpts) {
- ret = s->packet_buffer ?
- read_from_packet_buffer(&s->packet_buffer, &s->packet_buffer_end, pkt) :
- read_frame_internal(s, pkt);
- if (ret < 0)
- return ret;
- goto return_packet;
- }
-
- for (;;) {
- AVPacketList *pktl = s->packet_buffer;
-
- if (pktl) {
- AVPacket *next_pkt = &pktl->pkt;
-
- if (next_pkt->dts != AV_NOPTS_VALUE) {
- int wrap_bits = s->streams[next_pkt->stream_index]->pts_wrap_bits;
-
-
- int64_t last_dts = next_pkt->dts;
- while (pktl && next_pkt->pts == AV_NOPTS_VALUE) {
- if (pktl->pkt.stream_index == next_pkt->stream_index &&
- (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) {
- if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) {
- next_pkt->pts = pktl->pkt.dts;
- }
- if (last_dts != AV_NOPTS_VALUE) {
-
- last_dts = pktl->pkt.dts;
- }
- }
- pktl = pktl->next;
- }
- if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
-
-
-
-
-
- next_pkt->pts = last_dts + next_pkt->duration;
- }
- pktl = s->packet_buffer;
- }
-
-
- if (!(next_pkt->pts == AV_NOPTS_VALUE &&
- next_pkt->dts != AV_NOPTS_VALUE && !eof)) {
- ret = read_from_packet_buffer(&s->packet_buffer,
- &s->packet_buffer_end, pkt);
- goto return_packet;
- }
- }
-
- ret = read_frame_internal(s, pkt);
- if (ret < 0) {
- if (pktl && ret != AVERROR(EAGAIN)) {
- eof = 1;
- continue;
- } else
- return ret;
- }
-
- if (av_dup_packet(add_to_pktbuf(&s->packet_buffer, pkt,
- &s->packet_buffer_end)) < 0)
- return AVERROR(ENOMEM);
- }
-
- return_packet:
-
- st = s->streams[pkt->stream_index];
- if (st->skip_samples) {
- uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10);
- if (p) {
- AV_WL32(p, st->skip_samples);
- av_log(s, AV_LOG_DEBUG, "demuxer injecting skip %d\n", st->skip_samples);
- }
- st->skip_samples = 0;
- }
-
- if ((s->iformat->flags & AVFMT_GENERIC_INDEX) && pkt->flags & AV_PKT_FLAG_KEY) {
- ff_reduce_index(s, st->index);
- av_add_index_entry(st, pkt->pos, pkt->dts, 0, 0, AVINDEX_KEYFRAME);
- }
-
- if (is_relative(pkt->dts))
- pkt->dts -= RELATIVE_TS_BASE;
- if (is_relative(pkt->pts))
- pkt->pts -= RELATIVE_TS_BASE;
-
- return ret;
- }
上文中贴出了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;
-
-
- ret = ff_read_packet(s, &cur_pkt);
- if (ret < 0) {
- if (ret == AVERROR(EAGAIN))
- return ret;
-
- for(i = 0; i < s->nb_streams; i++) {
- st = s->streams[i];
- if (st->parser && st->need_parsing)
- parse_packet(s, NULL, st->index);
- }
-
-
- 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));
-
- 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) {
-
- *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 {
-
- 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);
-
-
- 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值。
该函数调用av_init_packet对参数pkg初始化,并调用iformat的方法read_packet读取数据。在本demo中,AVFormatContext实例中iformat成员为ff_mov_demuxer,如下所示:
- 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函数,这个函数的内容也比较长,暂时就不贴了,有时间慢慢分析。