1、函数介绍
av_interleaved_write_frame函数介绍:
- /**
- * Write a packet to an output media file ensuring correct interleaving.
- *
- * This function will buffer the packets internally as needed to make sure the
- * packets in the output file are properly interleaved in the order of
- * increasing dts. Callers doing their own interleaving should call
- * av_write_frame() instead of this function.
- *
- * @param s media file handle
- * @param pkt The packet containing the data to be written.
- * <br>
- * If the packet is reference-counted, this function will take
- * ownership of this reference and unreference it later when it sees
- * fit.
- * The caller must not access the data through this reference after
- * this function returns. If the packet is not reference-counted,
- * libavformat will make a copy.
- * <br>
- * This parameter can be NULL (at any time, not just at the end), to
- * flush the interleaving queues.
- * <br>
- * Packet's @ref AVPacket.stream_index "stream_index" field must be
- * set to the index of the corresponding stream in @ref
- * AVFormatContext.streams "s->streams". It is very strongly
- * recommended that timing information (@ref AVPacket.pts "pts", @ref
- * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to
- * correct values.
- *
- * @return 0 on success, a negative AVERROR on error. Libavformat will always
- * take care of freeing the packet, even if this function fails.
- *
- * @see av_write_frame(), AVFormatContext.max_interleave_delta
- */
- int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);
av_write_frame函数介绍:
- /**
- * Write a packet to an output media file.
- *
- * This function passes the packet directly to the muxer, without any buffering
- * or reordering. The caller is responsible for correctly interleaving the
- * packets if the format requires it. Callers that want libavformat to handle
- * the interleaving should call av_interleaved_write_frame() instead of this
- * function.
- *
- * @param s media file handle
- * @param pkt The packet containing the data to be written. Note that unlike
- * av_interleaved_write_frame(), this function does not take
- * ownership of the packet passed to it (though some muxers may make
- * an internal reference to the input packet).
- * <br>
- * This parameter can be NULL (at any time, not just at the end), in
- * order to immediately flush data buffered within the muxer, for
- * muxers that buffer up data internally before writing it to the
- * output.
- * <br>
- * Packet's @ref AVPacket.stream_index "stream_index" field must be
- * set to the index of the corresponding stream in @ref
- * AVFormatContext.streams "s->streams". It is very strongly
- * recommended that timing information (@ref AVPacket.pts "pts", @ref
- * AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to
- * correct values.
- * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush
- *
- * @see av_interleaved_write_frame()
- */
- int av_write_frame(AVFormatContext *s, AVPacket *pkt);
2、函数调用图
av_interleaved_write_frame函数调用图:
av_write_frame函数调用图:
3、函数代码
av_interleaved_write_frame函数代码:
- int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)
- {
- int ret, flush = 0;
- //检查pkt是否合法
- ret = check_packet(s, pkt);
- if (ret < 0)
- goto fail;
- if (pkt) {
- AVStream *st = s->streams[pkt->stream_index];
- av_dlog(s, "av_interleaved_write_frame size:%d dts:%s pts:%s\n",
- pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts));
- if ((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))//计算和检查pts、dts、duration
- goto fail;
- if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {
- ret = AVERROR(EINVAL);
- goto fail;
- }
- } else {
- av_dlog(s, "av_interleaved_write_frame FLUSH\n");
- flush = 1;
- }
- for (;; ) {
- AVPacket opkt;
- int ret = interleave_packet(s, &opkt, pkt, flush);
- if (pkt) {
- memset(pkt, 0, sizeof(*pkt));
- av_init_packet(pkt);
- pkt = NULL;
- }
- if (ret <= 0) //FIXME cleanup needed for ret<0 ?
- return ret;
- ret = write_packet(s, &opkt);
- if (ret >= 0)
- s->streams[opkt.stream_index]->nb_frames++;
- av_free_packet(&opkt);
- if (ret < 0)
- return ret;
- if(s->pb && s->pb->error)
- return s->pb->error;
- }
- fail:
- av_packet_unref(pkt);
- return ret;
- }
av_write_frame函数代码:
- int av_write_frame(AVFormatContext *s, AVPacket *pkt)
- {
- int ret;
- ret = check_packet(s, pkt);
- if (ret < 0)
- return ret;
- if (!pkt) {
- if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {
- ret = s->oformat->write_packet(s, NULL);
- if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)
- avio_flush(s->pb);
- if (ret >= 0 && s->pb && s->pb->error < 0)
- ret = s->pb->error;
- return ret;
- }
- return 1;
- }
- ret = compute_pkt_fields2(s, s->streams[pkt->stream_index], pkt);
- if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))
- return ret;
- ret = write_packet(s, pkt);
- if (ret >= 0 && s->pb && s->pb->error < 0)
- ret = s->pb->error;
- if (ret >= 0)
- s->streams[pkt->stream_index]->nb_frames++;
- return ret;
- }
4、解释
可以看出2个函数的区别在于av_interleaved_write_frame调用了interleave_packet,而av_write_frame没有调用,看看interleave_packet的代码:
- static int interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush)
- {
- if (s->oformat->interleave_packet) {
- int ret = s->oformat->interleave_packet(s, out, in, flush);
- if (in)
- av_free_packet(in);
- return ret;
- } else
- return ff_interleave_packet_per_dts(s, out, in, flush);
- }
- int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,
- AVPacket *pkt, int flush)
- {
- AVPacketList *pktl;
- int stream_count = 0;
- int noninterleaved_count = 0;
- int i, ret;
- if (pkt) {//把pkt加入到AVPacketList中去
- if ((ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts)) < 0)
- return ret;
- }
- for (i = 0; i < s->nb_streams; i++) {
- if (s->streams[i]->last_in_packet_buffer) {
- ++stream_count;
- } else if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_ATTACHMENT &&
- s->streams[i]->codec->codec_id != AV_CODEC_ID_VP8 &&
- s->streams[i]->codec->codec_id != AV_CODEC_ID_VP9) {
- ++noninterleaved_count;
- }
- }
- if (s->internal->nb_interleaved_streams == stream_count)
- flush = 1;
- if (s->max_interleave_delta > 0 &&
- s->internal->packet_buffer &&
- !flush &&
- s->internal->nb_interleaved_streams == stream_count+noninterleaved_count
- ) {
- AVPacket *top_pkt = &s->internal->packet_buffer->pkt;
- int64_t delta_dts = INT64_MIN;
- int64_t top_dts = av_rescale_q(top_pkt->dts,
- s->streams[top_pkt->stream_index]->time_base,
- AV_TIME_BASE_Q);
- for (i = 0; i < s->nb_streams; i++) {
- int64_t last_dts;
- const AVPacketList *last = s->streams[i]->last_in_packet_buffer;
- if (!last)
- continue;
- last_dts = av_rescale_q(last->pkt.dts,
- s->streams[i]->time_base,
- AV_TIME_BASE_Q);
- delta_dts = FFMAX(delta_dts, last_dts - top_dts);
- }
- if (delta_dts > s->max_interleave_delta) {
- av_log(s, AV_LOG_DEBUG,
- "Delay between the first packet and last packet in the "
- "muxing queue is %"PRId64" > %"PRId64": forcing output\n",
- delta_dts, s->max_interleave_delta);
- flush = 1;
- }
- }
- if (stream_count && flush) {
- AVStream *st;
- pktl = s->internal->packet_buffer;
- *out = pktl->pkt;
- st = s->streams[out->stream_index];
- s->internal->packet_buffer = pktl->next;
- if (!s->internal->packet_buffer)
- s->internal->packet_buffer_end = NULL;
- if (st->last_in_packet_buffer == pktl)
- st->last_in_packet_buffer = NULL;
- av_freep(&pktl);
- return 1;
- } else {
- av_init_packet(out);
- return 0;
- }
- }
看看ff_interleave_add_packet的代码:
- int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
- int (*compare)(AVFormatContext *, AVPacket *, AVPacket *))
- {
- int ret;
- AVPacketList **next_point, *this_pktl;
- AVStream *st = s->streams[pkt->stream_index];
- int chunked = s->max_chunk_size || s->max_chunk_duration;
- this_pktl = av_mallocz(sizeof(AVPacketList));
- if (!this_pktl)
- return AVERROR(ENOMEM);
- this_pktl->pkt = *pkt;
- #if FF_API_DESTRUCT_PACKET
- FF_DISABLE_DEPRECATION_WARNINGS
- pkt->destruct = NULL; // do not free original but only the copy
- FF_ENABLE_DEPRECATION_WARNINGS
- #endif
- pkt->buf = NULL;
- pkt->side_data = NULL;
- pkt->side_data_elems = 0;
- if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {
- av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);
- av_assert0(((AVFrame *)pkt->data)->buf);
- } else {
- // Duplicate the packet if it uses non-allocated memory
- if ((ret = av_dup_packet(&this_pktl->pkt)) < 0) {
- av_free(this_pktl);
- return ret;
- }
- }
- if (s->streams[pkt->stream_index]->last_in_packet_buffer) {
- next_point = &(st->last_in_packet_buffer->next);
- } else {
- next_point = &s->internal->packet_buffer;
- }
- if (chunked) {
- uint64_t max= av_rescale_q_rnd(s->max_chunk_duration, AV_TIME_BASE_Q, st->time_base, AV_ROUND_UP);
- st->interleaver_chunk_size += pkt->size;
- st->interleaver_chunk_duration += pkt->duration;
- if ( (s->max_chunk_size && st->interleaver_chunk_size > s->max_chunk_size)
- || (max && st->interleaver_chunk_duration > max)) {
- st->interleaver_chunk_size = 0;
- this_pktl->pkt.flags |= CHUNK_START;
- if (max && st->interleaver_chunk_duration > max) {
- int64_t syncoffset = (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)*max/2;
- int64_t syncto = av_rescale(pkt->dts + syncoffset, 1, max)*max - syncoffset;
- st->interleaver_chunk_duration += (pkt->dts - syncto)/8 - max;
- } else
- st->interleaver_chunk_duration = 0;
- }
- }
- if (*next_point) {
- if (chunked && !(this_pktl->pkt.flags & CHUNK_START))
- goto next_non_null;
- if (compare(s, &s->internal->packet_buffer_end->pkt, pkt)) {
- while ( *next_point
- && ((chunked && !((*next_point)->pkt.flags&CHUNK_START))
- || !compare(s, &(*next_point)->pkt, pkt)))
- next_point = &(*next_point)->next;
- if (*next_point)
- goto next_non_null;
- } else {
- next_point = &(s->internal->packet_buffer_end->next);
- }
- }
- av_assert1(!*next_point);
- s->internal->packet_buffer_end = this_pktl;
- next_non_null:
- this_pktl->next = *next_point;
- s->streams[pkt->stream_index]->last_in_packet_buffer =
- *next_point = this_pktl;
- return 0;
- }
- static int interleave_compare_dts(AVFormatContext *s, AVPacket *next,
- AVPacket *pkt)
- {
- AVStream *st = s->streams[pkt->stream_index];
- AVStream *st2 = s->streams[next->stream_index];
- int comp = av_compare_ts(next->dts, st2->time_base, pkt->dts,
- st->time_base);
- if (s->audio_preload && ((st->codec->codec_type == AVMEDIA_TYPE_AUDIO) != (st2->codec->codec_type == AVMEDIA_TYPE_AUDIO))) {
- int64_t ts = av_rescale_q(pkt ->dts, st ->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st ->codec->codec_type == AVMEDIA_TYPE_AUDIO);
- int64_t ts2= av_rescale_q(next->dts, st2->time_base, AV_TIME_BASE_Q) - s->audio_preload*(st2->codec->codec_type == AVMEDIA_TYPE_AUDIO);
- if (ts == ts2) {
- ts= ( pkt ->dts* st->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st ->codec->codec_type == AVMEDIA_TYPE_AUDIO)* st->time_base.den)*st2->time_base.den
- -( next->dts*st2->time_base.num*AV_TIME_BASE - s->audio_preload*(int64_t)(st2->codec->codec_type == AVMEDIA_TYPE_AUDIO)*st2->time_base.den)* st->time_base.den;
- ts2=0;
- }
- comp= (ts>ts2) - (ts<ts2);
- }
- if (comp == 0)
- return pkt->stream_index < next->stream_index;
- return comp > 0;
- }
好了,现在整体逻辑就清晰了,得出的结论是:在有多个流的情况下要用av_interleaved_write_frame,只有单一流2个函数都可以用。
http://blog.csdn.net/dancing_night/article/details/46469865