1. 程式人生 > >FFmpeg中呼叫av_read_frame函式導致的記憶體洩漏問題

FFmpeg中呼叫av_read_frame函式導致的記憶體洩漏問題

  使用FFmpeg的av_read_frame函式後,每讀完一個packet,必須呼叫av_packet_unref函式進行記憶體釋放,否則會導致記憶體釋洩漏。

  在vs(博主所用的ffmpeg版本是3.4.2,vs版本是vs2015)中編譯執行如下程式碼:

#include <stdio.h>
#include <iostream>
#include <windows.h>

extern "C" {
#include "libavformat/avformat.h"
}

int main()
{
	const char *path = "video1.mp4"; //需要讀取的本地媒體檔案相對路徑為video1.mp4
	av_register_all();               //初始化所有元件,只有呼叫了該函式,才能使用複用器和編解碼器。否則,呼叫函式avformat_open_input會失敗,無法獲取媒體檔案的資訊
	avformat_network_init();         //開啟網路流。這裡如果只需要讀取本地媒體檔案,不需要用到網路功能,可以不用加上這一句
	AVDictionary *opts = NULL;
	AVFormatContext *ic = NULL;
	int re = avformat_open_input(&ic, path, NULL, &opts); //媒體開啟函式,呼叫該函式可以獲得路徑為path的媒體檔案的資訊,並把這些資訊儲存到指標ic指向的空間中(呼叫該函式後會分配一個空間,讓指標ic指向該空間)
	if (re != 0) //如果開啟媒體檔案失敗,列印失敗原因
	{
		char buf[1024] = { 0 };
		av_strerror(re, buf, sizeof(buf) - 1);
		printf("open %s failed!:%s", path, buf);
	}
	else  //開啟媒體檔案成功
	{
		printf("open %s success!\n", path);
		avformat_find_stream_info(ic, NULL); //呼叫該函式可以進一步讀取一部分視音訊資料並且獲得一些相關的資訊
		av_dump_format(ic, 0, path, 0);      //輸出媒體檔案的資訊到控制檯上

		AVPacket *pkt = av_packet_alloc();
		while (1)
		{
			int ret = av_read_frame(ic, pkt);
			if (ret != 0)
			{
				printf("\n--------------------------end--------------------------");
				break;
			}
			//av_packet_unref(pkt);
			Sleep(2);  //睡眠2ms,避免程式執行過快影響觀察效果。
		}
		av_packet_free(&pkt);
	}
	
	if (ic)
	{
		avformat_close_input(&ic);
	}
	getchar();
	return 0;
}

可以看到上述程式碼的第38行將av_packet_unref(pkt);這一行註釋掉了,所以會導致記憶體洩漏。執行效果如下圖所示。可以在vs2015的診斷工具裡面觀察到程序執行的過程中(在控制檯列印"--------------------------end--------------------------"之前)佔用的記憶體越來越大。在工作管理員中觀察到該程序記憶體佔用也是越來大。

我們把上述程式碼的第38行的av_packet_unref(pkt);加入到程式碼中,再次編譯執行。執行效果如下圖所示,可以觀察到,程序執行過程中,記憶體基本上是不變的。

綜上所述:使用FFmpeg要注意記憶體洩漏的問題,av_read_frame中會申請記憶體,需要在外面進行釋放,所以每讀完一個packet,需要呼叫av_packet_unref進行記憶體釋放。