背景
-
基于ffmpeg实现录像功能,性能不理想,分析现有流程发现:写每一帧数据都需要生成一个AVPacket变量传递给av_write_frame,流程如下:
-
av_new_packet函数申请一定大小的内存空间存储媒体数据,av_write_frame执行完后,需要使用av_packet_free释放AVPacket内存空间,在行车记录仪产品大码率(16Mbps),较高帧率(25fps ~ 30fps),长时间持续不断录制的环境下,该循环操作对性能的影响不容忽视,生成AVPacket实测耗时如下:
01-01 08:02:13.393 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [0] ms
01-01 08:02:13.460 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [52] ms
01-01 08:02:13.494 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [2] ms
01-01 08:02:13.503 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [3] ms
01-01 08:02:13.533 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [0] ms
01-01 08:02:13.564 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [2] ms
01-01 08:02:13.571 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [2] ms
01-01 08:02:13.608 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [18] ms
01-01 08:02:13.648 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [8] ms
01-01 08:02:13.978 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [0] ms
01-01 08:02:14.014 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [15] ms
01-01 08:02:14.045 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [12] ms
01-01 08:02:14.060 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [6] ms
01-01 08:02:14.085 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [0] ms
01-01 08:02:14.111 230 478 I get_packet@CviMuxer.cpp:294 [/mnt/sd/CARDV/MOVIE/1970_01_01_080135_00.MOV]: get_packet take [15] ms
- 实测耗时波动较大,最多时耗时200~300ms,优化措施:AVPacket 复用。
AVPacket 复用
-
先通过av_packet_alloc创建一个AVPacket,后续重复使用该AVPacket,写每一帧数据流程:
-
AVPacket操作相关接口实现在:libavcodec/avpacket.c中,AVPacket所需内存空间的申请和扩大都封装在相关函数中,APP只需将size传递进去就可以了。
-
修改后实测耗时几乎所有都是1ms以下,只有非常小概率会超出1ms,如下:
01-01 08:00:36.497 237 462 I get_packet@CviMuxer.cpp:308 [/mnt/sd/CARDV/MOVIE/1970_01_01_080022_00.MOV]: get_packet take [0] ms
....
data内存复用
- AVPacket变量以及内存空间可以复用,但是写每一帧都需要将数据memcpy到AVPacket变量的data内存空间中,当数据量较大时memcpy的耗时也会比较明显,可以通过以下函数减少memcpy的使用次数:
int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size)
- av_packet_from_data函数将参数data指针直接赋值给AVPacket的data指针,不需要做内存拷贝,但是释放AVPacket时av_buffer_unref会释放data指向的内存空间,因此存在一些约束。