最简单的音视频解封装器,基于FFmpeg4.1实现(FFMpeg学习笔记一)

最简单的音视频解封装器,基于FFmpeg4.1实现


最近在学习FFmpeg,打算照着FFmpeg官方文档和官方的examples实现一些程序,加深理解,首先先实现一个解封装的程序。代码运行效果如下图:
在这里插入图片描述
代码的注释写的很详细,环境是在vs2019中运行的,下面直接上代码:

#include<iostream>
#include<string.h>
extern "C"
{
#include<libavformat/avformat.h>
}
int main(int argc,char *argv[])
{
	const char* videoname = NULL;
	/*if (argc!=1) {
		std::cout << "when you run ,the video name should be entered!" << std::endl;
		return -1;
	}
	videoname = argv[0];*/
	videoname = "test1.mp4";
	/* 通过avformat_open_input()打开文件并且为acformatcontext分配空间*/
	AVFormatContext* fmt_ctx = NULL;
	/**
		第三个参数,是媒体格式,置空则会自动探测。
		第四个参数, it is not possible to set demuxer private options on a preallocated
		context. Instead, the options should be passed to avformat_open_input()
		wrapped in an AVDictionary:
	*/
	if (avformat_open_input(&fmt_ctx, videoname, NULL, NULL) < 0) {
		std::cout << "could not open soure file :" << videoname << std::endl;
		return -1;
	};
	/**
		Read packets of a media file to get stream information.
		This is useful for file formats with no headers such as MPEG. 
		This function also computes the real framerate in case of MPEG-2 repeat frame mode. 
		The logical file position is not changed by this function; 
		examined packets may be buffered for later processing.
	*/
	if (avformat_find_stream_info(fmt_ctx, NULL) < 0) {
		std::cout << "could not find stream information."<< std::endl;
		return -1;
	}

	//查找码流
	int videostream = -1;
	int audiostream = -1;
	int subtitlestream = -1;
	videostream=av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	if (videostream<0) {
		std::cout << "could not find video stream information." << std::endl;
	}
	audiostream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	if (audiostream<0) {
		std::cout << "could not find audio stream information." << std::endl;
	}
	//字幕流
	subtitlestream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_SUBTITLE, -1, -1, NULL, 0);
	if (subtitlestream<0) {
		std::cout << "could not find subtitle stream information." << std::endl;
	}


	//打印信息
	std::cout << "--------------------------视频流-------------------------" << std::endl;
	std::cout << "索引号:" << videostream << " " << " 解码器ID:" << fmt_ctx->streams[videostream]->codecpar->codec_id
		<< "视频宽*高" << fmt_ctx->streams[videostream]->codecpar->width << "*" << fmt_ctx->streams[videostream]->codecpar->height << std::endl;
	std::cout << "--------------------------音频流-------------------------" << std::endl;
	std::cout << "索引号:" << audiostream << " " << " 解码器ID:" << fmt_ctx->streams[audiostream]->codecpar->codec_id
		<< "音频声道数:" << fmt_ctx->streams[audiostream]->codecpar->channels << std::endl;
	std::cout << "--------------------------字幕流-------------------------" << std::endl;

	AVPacket *pkt=NULL;
	//av_init_packet(pkt);
	pkt = av_packet_alloc();
	for (;;)
	{
		if (av_read_frame(fmt_ctx, pkt) < 0)
		{
			std::cout << "读到文件结尾了!" << std::endl;
			break;
		};
		if (pkt->stream_index == videostream)
		{
			//打印信息
			std::cout << "--------------------------视频流-------------------------" << std::endl;
			std::cout <<
				"duration: " << pkt->duration * (double)((double)fmt_ctx->streams[1]->time_base.num / (double)fmt_ctx->streams[1]->time_base.den)*1000 <<"ms"<< std::endl;;
			std::cout << "size: " << pkt->size << std::endl;
			std::cout << "pts : " << pkt->pts * (double)((double)fmt_ctx->streams[1]->time_base.num / (double)fmt_ctx->streams[1]->time_base.den) * 1000 << "ms" 
				<<"      dts :"<< pkt->dts * (double)((double)fmt_ctx->streams[1]->time_base.num / (double)fmt_ctx->streams[1]->time_base.den) * 1000 << "ms" <<std::endl;
		}
		if (pkt->stream_index == audiostream)
		{
			//打印信息
			std::cout << "--------------------------音频流-------------------------" << std::endl;
			std::cout <<
				"duration: " << pkt->duration * (double)((double)fmt_ctx->streams[1]->time_base.num / (double)fmt_ctx->streams[1]->time_base.den) * 1000 << "ms" << std::endl;;
			std::cout << "size: " << pkt->size << std::endl;
			std::cout << "pts : " << pkt->pts * (double)((double)fmt_ctx->streams[1]->time_base.num / (double)fmt_ctx->streams[1]->time_base.den) * 1000 << "ms"
				<< "      dts :" << pkt->dts * (double)((double)fmt_ctx->streams[1]->time_base.num / (double)fmt_ctx->streams[1]->time_base.den) * 1000 << "ms" << std::endl;
		}
		//每次调用av_read_frame会导致pkt的引用计数加1,要即时清理。
		//否则会导致内存泄漏
		av_packet_unref(pkt);
	}
	av_packet_free(&pkt);
	avformat_close_input(&fmt_ctx);
	return 0;
}

这部分程序可能存在内存泄漏的地方只有一个,就是AVPacket对象在申请完内存后,记得在av_read_frame()循环中对引用技术减1,即av_packet_unref(pkt);

参考:
[1]: 100行代码实现最简单的基于FFMPEG+SDL的视频播放器(SDL1.x)

猜你喜欢

转载自blog.csdn.net/weixin_40840000/article/details/107816244