FFmpeg解复用器(解封装)简单测试【2】

解复用器(解封装)的相关函数

avformat_alloc_context();负责申请一个AVFormatContext结构的内存,并进行简单初始化

avformat_free_context();释放该结构里的所有东西以及该结构本身

avformat_close_input();关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放。

avformat_open_input();打开输入视频文件

avformat_find_stream_info();获取视频文件信息

av_read_frame(); 读取音视频包

avformat_seek_file(); 定位文件

av_seek_frame():定位帧

流程

测试

cpp 复制代码
#include <iostream>
#include <thread>
using namespace std;

extern "C"
{
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
}
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")


static double r2d(AVRational r)
{
	return r.den == 0 ? 0 : (double)r.num / (double)r.den;
}

void XSleep(int ms)
{
	//C++ 11 
	chrono::milliseconds du(ms);//延迟ms
	this_thread::sleep_for(du);
}

int main(int argc, char* argv[])
{
//解封装
cout << " test Demux FFmpeg club" << endl;

	const char* path = "1.mp4";

	//1、初始化封装库
	av_register_all();

	//初始化网络库(可以打开rtsp rtmp http 协议的流媒体视频)
	//avformat_network_init();

	//参数设置
	AVDictionary* opts = NULL;

	//设置rtsp流已tcp协议打开
	//av_dict_set(&opts, "rtsp_transport", "tcp", 0);
	//设置网络延迟时间
	//av_dict_set(&opts, "max_delay", "500", 0);

	//解封装上下文
	AVFormatContext* ic = NULL;

	int re = avformat_open_input(
				&ic, //上下文结构体:保存音视频的构成和基本信息
				path, //音视频文件路径
				0, //自动选择解封器
				&opts//参数设置,比如rtsp的延迟设置
				);
	if (re != 0)//0为成功打开文件
	{
		char buf[1024] = {0};
		av_strerror(re, buf, sizeof(buf) - 1);//打印错误原因
		cout << " open--" << path << "--failed! : " << buf << endl;
		getchar();
		return -1;
	}
	cout << "open--" << path << "--success! : " << endl;


	//获取音视频流信息,包含了视频和音频 
	//mp4在这里flv有所不同
	re = avformat_find_stream_info(ic, 0);

	//AV_TIME_BASE是时间的计数百万, ic->duration / AV_TIME_BASE是秒。
	//打印总时长 ms
	int total_time = ic->duration / (AV_TIME_BASE/1000);
	cout << "total time : " << total_time << " ms" << endl;

	//打印视频流的详细信息
	av_dump_format(ic,0,path,0);

	//音视频索引
	int videoStream = 0;
	int audioStream = 1;

	//获取音视频流信息(遍历,函数获取),ic->nb_streams是媒体流的数量
	for (int i = 0; i < ic->nb_streams; i++)
	{
		AVStream* as = ic->streams[i];
		//as->codecpar->codec_type 中保存流的类别
		//音频
		if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			audioStream = i;
			cout << i << " : 音频信息" << endl;
			cout << "sample_rate = " << as->codecpar->sample_rate << endl;
			//cout << "format = " << as->codecpar->format << endl;//AVSampleFormat
			cout << "channnels = " << as->codecpar->channels << endl;
			//cout << "codec_id = " << as->codecpar->codec_id << endl;//AVCodecID
			cout << "audio fps = " << r2d(as->avg_frame_rate) << endl;//存储浮点数是按照分子分母保存的
			//音频一帧数据 是 一定量的样本数 单通道
			cout<< "frame_size = " << as->codecpar->frame_size << endl;
			//fps = sample_rate/frame_size
		}
		//视频
		else if (as->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
		{
			videoStream = i;
			cout << i <<" : 视频信息" << endl;
			cout << "width = " << as->codecpar->width << endl;
			cout << "height = " << as->codecpar->height << endl;
			//帧率 fps 分数转换
			cout << "vedio fps = " << r2d(as->avg_frame_rate) << endl;
			//打印时长
			int as_duration =  (as->duration) * av_q2d(as->time_base);
			cout << "视频的总时长为: " << as_duration / 3600 << ":" << as_duration % 3600 / 60 << ":" << as_duration % 60 << endl;
			//av_q2d;

		}
	}

	//获取视频流 另一种方法
	//videoStream = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	//ic->streams[videoStream];

	//获取一个包的数据
	AVPacket* pkt = av_packet_alloc();//分配包的内存(堆上),需要手动释放
	int pkt_count = 0;
	int print_max_count = 10;//打印10个包
	cout << "*****av_read_frame start*****" << endl;

	while (1)
	{
		int ret = av_read_frame(ic, pkt);
		if (ret < 0)
		{
			cout << "******av_read_frame end*****" << endl;
			break;//开辟空间失败,就不需要再释放,即减少引用计数

			//循环播放,跳转帧的位置
			//int ms = 100;//根据时间基数转换位置
			//long long pos = (double)ms / 1000 * r2d(ic->streams[pkt->stream_index]->time_base);
			//av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);//往后找一帧,且找到关键帧
			//getchar();
			//continue;
		}
		if (pkt_count++ < print_max_count)
		{
			if (pkt->stream_index == audioStream)
			{
				//显示时间
				cout << "******audio pts :"<< pkt->pts << endl;
				//显示为ms,方便同步
				cout << pkt->pts * r2d(ic->streams[pkt->stream_index]->time_base) * 1000 << endl;
				//解码时间
				cout << "******audio dts :" << pkt->dts << endl;
				cout << "******audio size :" << pkt->size << endl;
				cout << "******audio pos :" << pkt->pos << endl;
				cout << endl;
			}
			else if (pkt->stream_index == videoStream)
			{
				cout << "******video pts :" << pkt->pts << endl;
				//显示为ms
				cout << pkt->pts * r2d(ic->streams[pkt->stream_index]->time_base) * 1000 << endl;
				cout << "******video dts :" << pkt->dts << endl;
				cout << "******video size :" << pkt->size << endl;
				cout << "******video pos :" << pkt->pos << endl;
				cout << endl;
			}
			else
				cout << "unknow stream_index" << pkt->stream_index << endl;
		}
		//每次拿到包的数据后减少引用计数
		av_packet_unref(pkt);
	}
	//最后释放包的内存
	av_packet_free(&pkt);
	
	if (ic)
	{
		//释放封装上下文,并且把ic置为0
		avformat_close_input(&ic);
	}

	getchar();
	return 0;
}
相关推荐
cuijiecheng20182 小时前
音视频入门基础:FLV专题(13)——FFmpeg源码中,解析任意Type值的SCRIPTDATAVALUE类型的实现
ffmpeg·音视频
小神.Chen1 天前
YouTube音视频合并批处理基于 FFmpeg的
ffmpeg·音视频
昱禹2 天前
记一次因视频编码无法在浏览器播放、编码视频报错问题
linux·python·opencv·ffmpeg·音视频
寻找09之夏3 天前
【FFmpeg 深度解析】:全方位视频合成
ffmpeg·音视频
zanglengyu3 天前
ffmpeg取rtsp流音频数据保存声音为wav文件
ffmpeg·音视频
cuijiecheng20183 天前
音视频入门基础:FLV专题(11)——FFmpeg源码中,解析SCRIPTDATASTRING类型的ScriptDataValue的实现
ffmpeg·音视频
汪子熙3 天前
什么是 LDAC、SBC 和 AAC 音频编码技术
ffmpeg·音视频·aac
cpp_learners3 天前
Windows环境 源码编译 FFmpeg
windows·ffmpeg·源码编译·ffmpeg源码编译
cuijiecheng20183 天前
音视频入门基础:FLV专题(8)——FFmpeg源码中,解码Tag header的实现
ffmpeg·音视频
职场人参4 天前
如何改变音频声音大小?关于改变音频大小的方法介绍
android·ffmpeg