av_write_frame 与 av_interleaved_write_frame

2024-05-04 04:08
文章标签 write frame av interleaved

本文主要是介绍av_write_frame 与 av_interleaved_write_frame,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

https://blog.csdn.net/wishfly/article/details/51783809

 

av_write_frame 与 av_interleaved_write_frame

2016年06月29日 16:14:44 Tianyu-liu 阅读数:2563

1、函数介绍

av_interleaved_write_frame函数介绍:

[cpp] view plain copy

  1. /** 
  2.  * Write a packet to an output media file ensuring correct interleaving. 
  3.  * 
  4.  * This function will buffer the packets internally as needed to make sure the 
  5.  * packets in the output file are properly interleaved in the order of 
  6.  * increasing dts. Callers doing their own interleaving should call 
  7.  * av_write_frame() instead of this function. 
  8.  * 
  9.  * @param s media file handle 
  10.  * @param pkt The packet containing the data to be written. 
  11.  *            <br> 
  12.  *            If the packet is reference-counted, this function will take 
  13.  *            ownership of this reference and unreference it later when it sees 
  14.  *            fit. 
  15.  *            The caller must not access the data through this reference after 
  16.  *            this function returns. If the packet is not reference-counted, 
  17.  *            libavformat will make a copy. 
  18.  *            <br> 
  19.  *            This parameter can be NULL (at any time, not just at the end), to 
  20.  *            flush the interleaving queues. 
  21.  *            <br> 
  22.  *            Packet's @ref AVPacket.stream_index "stream_index" field must be 
  23.  *            set to the index of the corresponding stream in @ref 
  24.  *            AVFormatContext.streams "s->streams". It is very strongly 
  25.  *            recommended that timing information (@ref AVPacket.pts "pts", @ref 
  26.  *            AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to 
  27.  *            correct values. 
  28.  * 
  29.  * @return 0 on success, a negative AVERROR on error. Libavformat will always 
  30.  *         take care of freeing the packet, even if this function fails. 
  31.  * 
  32.  * @see av_write_frame(), AVFormatContext.max_interleave_delta 
  33.  */  
  34. int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt);  

av_write_frame函数介绍:

[cpp] view plain copy

  1. /** 
  2.  * Write a packet to an output media file. 
  3.  * 
  4.  * This function passes the packet directly to the muxer, without any buffering 
  5.  * or reordering. The caller is responsible for correctly interleaving the 
  6.  * packets if the format requires it. Callers that want libavformat to handle 
  7.  * the interleaving should call av_interleaved_write_frame() instead of this 
  8.  * function. 
  9.  * 
  10.  * @param s media file handle 
  11.  * @param pkt The packet containing the data to be written. Note that unlike 
  12.  *            av_interleaved_write_frame(), this function does not take 
  13.  *            ownership of the packet passed to it (though some muxers may make 
  14.  *            an internal reference to the input packet). 
  15.  *            <br> 
  16.  *            This parameter can be NULL (at any time, not just at the end), in 
  17.  *            order to immediately flush data buffered within the muxer, for 
  18.  *            muxers that buffer up data internally before writing it to the 
  19.  *            output. 
  20.  *            <br> 
  21.  *            Packet's @ref AVPacket.stream_index "stream_index" field must be 
  22.  *            set to the index of the corresponding stream in @ref 
  23.  *            AVFormatContext.streams "s->streams". It is very strongly 
  24.  *            recommended that timing information (@ref AVPacket.pts "pts", @ref 
  25.  *            AVPacket.dts "dts", @ref AVPacket.duration "duration") is set to 
  26.  *            correct values. 
  27.  * @return < 0 on error, = 0 if OK, 1 if flushed and there is no more data to flush 
  28.  * 
  29.  * @see av_interleaved_write_frame() 
  30.  */  
  31. int av_write_frame(AVFormatContext *s, AVPacket *pkt);  

2、函数调用图

av_interleaved_write_frame函数调用图:

av_write_frame函数调用图:

 

3、函数代码

av_interleaved_write_frame函数代码:

[cpp] view plain copy

  1. int av_interleaved_write_frame(AVFormatContext *s, AVPacket *pkt)  
  2. {  
  3.     int ret, flush = 0;  
  4.     //检查pkt是否合法  
  5.     ret = check_packet(s, pkt);  
  6.     if (ret < 0)  
  7.         goto fail;  
  8.   
  9.     if (pkt) {  
  10.         AVStream *st = s->streams[pkt->stream_index];  
  11.   
  12.         av_dlog(s, "av_interleaved_write_frame size:%d dts:%s pts:%s\n",  
  13.                 pkt->size, av_ts2str(pkt->dts), av_ts2str(pkt->pts));  
  14.         if ((ret = compute_pkt_fields2(s, st, pkt)) < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))//计算和检查pts、dts、duration  
  15.             goto fail;  
  16.   
  17.         if (pkt->dts == AV_NOPTS_VALUE && !(s->oformat->flags & AVFMT_NOTIMESTAMPS)) {  
  18.             ret = AVERROR(EINVAL);  
  19.             goto fail;  
  20.         }  
  21.     } else {  
  22.         av_dlog(s, "av_interleaved_write_frame FLUSH\n");  
  23.         flush = 1;  
  24.     }  
  25.   
  26.     for (;; ) {  
  27.         AVPacket opkt;  
  28.         int ret = interleave_packet(s, &opkt, pkt, flush);  
  29.         if (pkt) {  
  30.             memset(pkt, 0, sizeof(*pkt));  
  31.             av_init_packet(pkt);  
  32.             pkt = NULL;  
  33.         }  
  34.         if (ret <= 0) //FIXME cleanup needed for ret<0 ?  
  35.             return ret;  
  36.   
  37.         ret = write_packet(s, &opkt);  
  38.         if (ret >= 0)  
  39.             s->streams[opkt.stream_index]->nb_frames++;  
  40.   
  41.         av_free_packet(&opkt);  
  42.   
  43.         if (ret < 0)  
  44.             return ret;  
  45.         if(s->pb && s->pb->error)  
  46.             return s->pb->error;  
  47.     }  
  48. fail:  
  49.     av_packet_unref(pkt);  
  50.     return ret;  
  51. }  

av_write_frame函数代码:

[cpp] view plain copy

  1. int av_write_frame(AVFormatContext *s, AVPacket *pkt)  
  2. {  
  3.     int ret;  
  4.   
  5.     ret = check_packet(s, pkt);  
  6.     if (ret < 0)  
  7.         return ret;  
  8.   
  9.     if (!pkt) {  
  10.         if (s->oformat->flags & AVFMT_ALLOW_FLUSH) {  
  11.             ret = s->oformat->write_packet(s, NULL);  
  12.             if (s->flush_packets && s->pb && s->pb->error >= 0 && s->flags & AVFMT_FLAG_FLUSH_PACKETS)  
  13.                 avio_flush(s->pb);  
  14.             if (ret >= 0 && s->pb && s->pb->error < 0)  
  15.                 ret = s->pb->error;  
  16.             return ret;  
  17.         }  
  18.         return 1;  
  19.     }  
  20.   
  21.     ret = compute_pkt_fields2(s, s->streams[pkt->stream_index], pkt);  
  22.   
  23.     if (ret < 0 && !(s->oformat->flags & AVFMT_NOTIMESTAMPS))  
  24.         return ret;  
  25.   
  26.     ret = write_packet(s, pkt);  
  27.     if (ret >= 0 && s->pb && s->pb->error < 0)  
  28.         ret = s->pb->error;  
  29.   
  30.     if (ret >= 0)  
  31.         s->streams[pkt->stream_index]->nb_frames++;  
  32.     return ret;  
  33. }  

4、解释

可以看出2个函数的区别在于av_interleaved_write_frame调用了interleave_packet,而av_write_frame没有调用,看看interleave_packet的代码:

[cpp] view plain copy

  1. static int interleave_packet(AVFormatContext *s, AVPacket *out, AVPacket *in, int flush)  
  2. {  
  3.     if (s->oformat->interleave_packet) {  
  4.         int ret = s->oformat->interleave_packet(s, out, in, flush);  
  5.         if (in)  
  6.             av_free_packet(in);  
  7.         return ret;  
  8.     } else  
  9.         return ff_interleave_packet_per_dts(s, out, in, flush);  
  10. }  

代码非常简单,如果AVOutputFormat有interleave_packet函数指针,则调用,如果没有则调用ff_interleave_packet_per_dts,看看ff_interleave_packet_per_dts的代码:
[cpp] view plain copy

  1. int ff_interleave_packet_per_dts(AVFormatContext *s, AVPacket *out,  
  2.                                  AVPacket *pkt, int flush)  
  3. {  
  4.     AVPacketList *pktl;  
  5.     int stream_count = 0;  
  6.     int noninterleaved_count = 0;  
  7.     int i, ret;  
  8.   
  9.     if (pkt) {//把pkt加入到AVPacketList中去  
  10.         if ((ret = ff_interleave_add_packet(s, pkt, interleave_compare_dts)) < 0)  
  11.             return ret;  
  12.     }  
  13.   
  14.     for (i = 0; i < s->nb_streams; i++) {  
  15.         if (s->streams[i]->last_in_packet_buffer) {  
  16.             ++stream_count;  
  17.         } else if (s->streams[i]->codec->codec_type != AVMEDIA_TYPE_ATTACHMENT &&  
  18.                    s->streams[i]->codec->codec_id != AV_CODEC_ID_VP8 &&  
  19.                    s->streams[i]->codec->codec_id != AV_CODEC_ID_VP9) {  
  20.             ++noninterleaved_count;  
  21.         }  
  22.     }  
  23.   
  24.     if (s->internal->nb_interleaved_streams == stream_count)  
  25.         flush = 1;  
  26.   
  27.     if (s->max_interleave_delta > 0 &&  
  28.         s->internal->packet_buffer &&  
  29.         !flush &&  
  30.         s->internal->nb_interleaved_streams == stream_count+noninterleaved_count  
  31.     ) {  
  32.         AVPacket *top_pkt = &s->internal->packet_buffer->pkt;  
  33.         int64_t delta_dts = INT64_MIN;  
  34.         int64_t top_dts = av_rescale_q(top_pkt->dts,  
  35.                                        s->streams[top_pkt->stream_index]->time_base,  
  36.                                        AV_TIME_BASE_Q);  
  37.   
  38.         for (i = 0; i < s->nb_streams; i++) {  
  39.             int64_t last_dts;  
  40.             const AVPacketList *last = s->streams[i]->last_in_packet_buffer;  
  41.   
  42.             if (!last)  
  43.                 continue;  
  44.   
  45.             last_dts = av_rescale_q(last->pkt.dts,  
  46.                                     s->streams[i]->time_base,  
  47.                                     AV_TIME_BASE_Q);  
  48.             delta_dts = FFMAX(delta_dts, last_dts - top_dts);  
  49.         }  
  50.   
  51.         if (delta_dts > s->max_interleave_delta) {  
  52.             av_log(s, AV_LOG_DEBUG,  
  53.                    "Delay between the first packet and last packet in the "  
  54.                    "muxing queue is %"PRId64" > %"PRId64": forcing output\n",  
  55.                    delta_dts, s->max_interleave_delta);  
  56.             flush = 1;  
  57.         }  
  58.     }  
  59.   
  60.     if (stream_count && flush) {  
  61.         AVStream *st;  
  62.         pktl = s->internal->packet_buffer;  
  63.         *out = pktl->pkt;  
  64.         st   = s->streams[out->stream_index];  
  65.   
  66.         s->internal->packet_buffer = pktl->next;  
  67.         if (!s->internal->packet_buffer)  
  68.             s->internal->packet_buffer_end = NULL;  
  69.   
  70.         if (st->last_in_packet_buffer == pktl)  
  71.             st->last_in_packet_buffer = NULL;  
  72.         av_freep(&pktl);  
  73.   
  74.         return 1;  
  75.     } else {  
  76.         av_init_packet(out);  
  77.         return 0;  
  78.     }  
  79. }  

从代码中看到,函数ff_interleave_packet_per_dts调用ff_interleave_add_packet把pkt加入缓存,然后再从缓存中取出第一个pkt返回。
看看ff_interleave_add_packet的代码:[cpp] view plain copy

  1. int ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,  
  2.                              int (*compare)(AVFormatContext *, AVPacket *, AVPacket *))  
  3. {  
  4.     int ret;  
  5.     AVPacketList **next_point, *this_pktl;  
  6.     AVStream *st   = s->streams[pkt->stream_index];  
  7.     int chunked    = s->max_chunk_size || s->max_chunk_duration;  
  8.   
  9.     this_pktl      = av_mallocz(sizeof(AVPacketList));  
  10.     if (!this_pktl)  
  11.         return AVERROR(ENOMEM);  
  12.     this_pktl->pkt = *pkt;  
  13. #if FF_API_DESTRUCT_PACKET  
  14. FF_DISABLE_DEPRECATION_WARNINGS  
  15.     pkt->destruct  = NULL;           // do not free original but only the copy  
  16. FF_ENABLE_DEPRECATION_WARNINGS  
  17. #endif  
  18.     pkt->buf       = NULL;  
  19.     pkt->side_data = NULL;  
  20.     pkt->side_data_elems = 0;  
  21.     if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) {  
  22.         av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE);  
  23.         av_assert0(((AVFrame *)pkt->data)->buf);  
  24.     } else {  
  25.         // Duplicate the packet if it uses non-allocated memory  
  26.         if ((ret = av_dup_packet(&this_pktl->pkt)) < 0) {  
  27.             av_free(this_pktl);  
  28.             return ret;  
  29.         }  
  30.     }  
  31.   
  32.     if (s->streams[pkt->stream_index]->last_in_packet_buffer) {  
  33.         next_point = &(st->last_in_packet_buffer->next);  
  34.     } else {  
  35.         next_point = &s->internal->packet_buffer;  
  36.     }  
  37.   
  38.     if (chunked) {  
  39.         uint64_t max= av_rescale_q_rnd(s->max_chunk_duration, AV_TIME_BASE_Q, st->time_base, AV_ROUND_UP);  
  40.         st->interleaver_chunk_size     += pkt->size;  
  41.         st->interleaver_chunk_duration += pkt->duration;  
  42.         if (   (s->max_chunk_size && st->interleaver_chunk_size > s->max_chunk_size)  
  43.             || (max && st->interleaver_chunk_duration           > max)) {  
  44.             st->interleaver_chunk_size      = 0;  
  45.             this_pktl->pkt.flags |= CHUNK_START;  
  46.             if (max && st->interleaver_chunk_duration > max) {  
  47.                 int64_t syncoffset = (st->codec->codec_type == AVMEDIA_TYPE_VIDEO)*max/2;  
  48.                 int64_t syncto = av_rescale(pkt->dts + syncoffset, 1, max)*max - syncoffset;  
  49.   
  50.                 st->interleaver_chunk_duration += (pkt->dts - syncto)/8 - max;  
  51.             } else  
  52.                 st->interleaver_chunk_duration = 0;  
  53.         }  
  54.     }  
  55.     if (*next_point) {  
  56.         if (chunked && !(this_pktl->pkt.flags & CHUNK_START))  
  57.             goto next_non_null;  
  58.   
  59.         if (compare(s, &s->internal->packet_buffer_end->pkt, pkt)) {  
  60.             while (   *next_point  
  61.                    && ((chunked && !((*next_point)->pkt.flags&CHUNK_START))  
  62.                        || !compare(s, &(*next_point)->pkt, pkt)))  
  63.                 next_point = &(*next_point)->next;  
  64.             if (*next_point)  
  65.                 goto next_non_null;  
  66.         } else {  
  67.             next_point = &(s->internal->packet_buffer_end->next);  
  68.         }  
  69.     }  
  70.     av_assert1(!*next_point);  
  71.   
  72.     s->internal->packet_buffer_end = this_pktl;  
  73. next_non_null:  
  74.   
  75.     this_pktl->next = *next_point;  
  76.   
  77.     s->streams[pkt->stream_index]->last_in_packet_buffer =  
  78.         *next_point                                      = this_pktl;  
  79.   
  80.     return 0;  
  81. }  

代码中可以看到,函数ff_interleave_add_packet把pkt经过排序(如果缓存中有pkt的话)加入到缓存中,这个排序是根据ff_interleave_packet_per_dts函数传入的compare(其实就是函数interleave_compare_dts)指针做的,来看看interleave_compare_dts函数的代码:[cpp] view plain copy

  1. static int interleave_compare_dts(AVFormatContext *s, AVPacket *next,  
  2.                                   AVPacket *pkt)  
  3. {  
  4.     AVStream *st  = s->streams[pkt->stream_index];  
  5.     AVStream *st2 = s->streams[next->stream_index];  
  6.     int comp      = av_compare_ts(next->dts, st2->time_base, pkt->dts,  
  7.                                   st->time_base);  
  8.     if (s->audio_preload && ((st->codec->codec_type == AVMEDIA_TYPE_AUDIO) != (st2->codec->codec_type == AVMEDIA_TYPE_AUDIO))) {  
  9.         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);  
  10.         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);  
  11.         if (ts == ts2) {  
  12.             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  
  13.                -( 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;  
  14.             ts2=0;  
  15.         }  
  16.         comp= (ts>ts2) - (ts<ts2);  
  17.     }  
  18.   
  19.     if (comp == 0)  
  20.         return pkt->stream_index < next->stream_index;  
  21.     return comp > 0;  
  22. }  

从代码中可以看到interleave_compare_dts函数其实就是在比较传入的2个pkt的dts值,其实就是比那个的dts更早,如果有音频还有audio_preload(音频预加载时间)的话,还需要把音频包的预加载时间算进去。

 

好了,现在整体逻辑就清晰了,得出的结论是:在有多个流的情况下要用av_interleaved_write_frame,只有单一流2个函数都可以用。

 

 

http://blog.csdn.net/dancing_night/article/details/46469865

这篇关于av_write_frame 与 av_interleaved_write_frame的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/958315

相关文章

Qt中window frame的影响

window frame 在创建图形化界面的时候,会创建窗口主体,上面会多出一条,周围多次一圈细边,这就叫window frame窗口框架,这是操作系统自带的。 这个对geometry的一些属性有一定影响,主要体现在Qt坐标系体系: 窗口当中包含一个按钮,这个按钮的坐标系是以父元素为参考,那么这个参考是widget本体作为参考,还是window frame作为参考,这两种参考体系都存在

Unstructured cannot write mode RGBA as JPEG 错误解决

Unstructured cannot write mode RGBA as JPEG 错误解决 0. 错误详细1. 解决方法 0. 错误详细 Image Extraction Error: Skipping the failed imageTraceback (most recent call last):File "/root/miniconda3/envs/learn-y

70-java write类应用场景

在Java中,我们可以使用java.io包中的FileWriter和BufferedWriter类来写入数据到文件。以下是一个简单的例子,展示了如何使用FileWriter和BufferedWriter来写入数据到文件: import java.io.BufferedWriter;import java.io.FileWriter;import java.io.IOException;pub

SylixOS write 0 字节问题

1 问题描述 在移植中间件过程中,在SylixOS调用write函数写入0字节的数据到文件中时,会导致对应的中间件测试用例失败,失败的原因是文件系统中的write函数在Linux系统和SylixOS有区别,两种实现的差别如下。 2 write函数的实现机制 2.1 SylixOS实现机制 在SylixOS下通过write 函数写数据到普通文件中时,第一步会判断写入的数据是否为0,如果是0直

Java 入门指南:Java 并发编程 —— Copy-On-Write 写时复制技术

文章目录 Copy-On-Write使用场景特点缺点CopyOnWrite 和 读写锁相同点之处不同之处 CopyOnWriteArrayList适用场景主要特性方法构造方法CopyOnWriteArrayList 使用示例 CopyOnWriteArraySet适用场景主要特性方法构造方法使用注意事项CopyOnWriteArraySet 使用示例 Copy-On-Writ

df.write.csv

# 将 DataFrame 写入 CSV 文件# 拆分 ArrayType 列df_exploded = df.withColumn("interests", explode("interests"))print("\nExploded DataFrame:")df_exploded.show(truncate=False)# 写入 CSV 文件df_exploded.write.csv

iOS——frame和bounds的区别

把frame理解为占用区域,把bounds理解为边界。View在旋转过程中,其实自己的坐标系统并没有发生改变,bounds中的origin只能通过setBounds方法修改。 frame 定义了视图在其父视图坐标系统中的位置和大小。其坐标系是相对于俯视图的坐标系。 bounds 定义了视图自身坐标系统中的位置和大小。其坐标系是相对于自己本身视图的坐标系。 UIView.h中的注释: // 如

IOS界面开发基础——Frame与Bounds

参考资料:http://blog.csdn.net/hherima/article/details/39501857 在IOS的UI开发中,经常需要对view进行定位。比较常用的概念就是Frame和Bound,通过view这两个属性,就可以任意的“摆弄”我们的view了。 这两个属性都可以定义view的位置和大小,但这两个属性之间有什么区别和联系呢?经过资料查找,记录如下: Frame

redis被攻击redis READONLY You can‘t write against a read only slave.

redis 日志路径 /var/log/redis 拿下来后发现有这种错误 Operation now in progress 可能是网络断开导致, 查找redis whereis redis 修改 vim /etc/redis.conf 大概在300行 下面代码yes改no slave-read-only no 重启redis sudo systemctl restart

FFmpeg源码:compute_frame_duration函数分析

一、compute_frame_duration函数的定义 compute_frame_duration函数定义在FFmpeg源码(本文演示用的FFmpeg源码版本为7.0.1)的源文件libavformat/demux.c中: /*** Return the frame duration in seconds. Return 0 if not available.*/static void