转自:http://blog.csdn.net/shaqoneal/article/details/16960927
AVPacket结构用于保存压缩编码过的数据。在解码时,该结构的实例通常作为解复用器(demuxer)的输出并输入到解码器中;在编码时,通常是编码器的输出,并输入到复用器(muxer)中。该结构体的定义如下:
- typedef struct AVPacket {
- /**
- * A reference to the reference-counted buffer where the packet data is
- * stored.
- * May be NULL, then the packet data is not reference-counted.
- */
- AVBufferRef *buf;
- /**
- * Presentation timestamp in AVStream->time_base units; the time at which
- * the decompressed packet will be presented to the user.
- * Can be AV_NOPTS_VALUE if it is not stored in the file.
- * pts MUST be larger or equal to dts as presentation cannot happen before
- * decompression, unless one wants to view hex dumps. Some formats misuse
- * the terms dts and pts/cts to mean something different. Such timestamps
- * must be converted to true pts/dts before they are stored in AVPacket.
- */
- int64_t pts;//显示时间戳
- /**
- * Decompression timestamp in AVStream->time_base units; the time at which
- * the packet is decompressed.
- * Can be AV_NOPTS_VALUE if it is not stored in the file.
- */
- int64_t dts;//解码时间戳
- uint8_t *data;//实例所包含的压缩数据,直接获取该指针指向缓存的数据可以得到压缩过的码流;
- int size;//原始压缩数据的大小
- int stream_index;//标识当前AVPacket所从属的码流
- /**
- * A combination of AV_PKT_FLAG values
- */
- int flags;
- /**
- * Additional packet data that can be provided by the container.
- * Packet can contain several types of side information.
- */
- struct {
- uint8_t *data;
- int size;
- enum AVPacketSideDataType type;
- } *side_data;
- int side_data_elems;
- /**
- * Duration of this packet in AVStream->time_base units, 0 if unknown.
- * Equals next_pts - this_pts in presentation order.
- */
- int duration;
- #if FF_API_DESTRUCT_PACKET
- attribute_deprecated
- void (*destruct)(struct AVPacket *);
- attribute_deprecated
- void *priv;
- #endif
- int64_t pos; ///< byte position in stream, -1 if unknown
- /**
- * Time difference in AVStream->time_base units from the pts of this
- * packet to the point at which the output from the decoder has converged
- * independent from the availability of previous frames. That is, the
- * frames are virtually identical no matter if decoding started from
- * the very first frame or from this keyframe.
- * Is AV_NOPTS_VALUE if unknown.
- * This field is not the display duration of the current packet.
- * This field has no meaning if the packet does not have AV_PKT_FLAG_KEY
- * set.
- *
- * The purpose of this field is to allow seeking in streams that have no
- * keyframes in the conventional sense. It corresponds to the
- * recovery point SEI in H.264 and match_time_delta in NUT. It is also
- * essential for some types of subtitle streams to ensure that all
- * subtitles are correctly displayed after seeking.
- */
- int64_t convergence_duration;
- } AVPacket;
- 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;
- // last dts seen for this stream. if any of packets following
- // current one had no dts, we will set this to AV_NOPTS_VALUE.
- 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))) { //not b frame
- next_pkt->pts = pktl->pkt.dts;
- }
- if (last_dts != AV_NOPTS_VALUE) {
- // Once last dts was set to AV_NOPTS_VALUE, we don't change it.
- last_dts = pktl->pkt.dts;
- }
- }
- pktl = pktl->next;
- }
- if (eof && next_pkt->pts == AV_NOPTS_VALUE && last_dts != AV_NOPTS_VALUE) {
- // Fixing the last reference frame had none pts issue (For MXF etc).
- // We only do this when
- // 1. eof.
- // 2. we are not able to resolve a pts value for current packet.
- // 3. the packets for this stream at the end of the files had valid dts.
- next_pkt->pts = last_dts + next_pkt->duration;
- }
- pktl = s->packet_buffer;
- }
- /* read packet from packet buffer, if there is data */
- 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;
- /* 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;
- }
- 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;
- }
- 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;
- }
- }
该函数调用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,
- };