AVFormatContext、AV_read_frame、av_seek_frame

一、

AVFormatContext 结构体描述了一个媒体文件或媒体流的构成和基本信息
int avformat_open_input(AVFormatContext **ps,
				 const char *url,   //URL of the stream to open
				  AVInputFormat *fmt,
				   AVDictionary **options
				   );
int re=avformat_open_input(&ic, path, 0 ,0);
void avformat_close_input(AVFormatContext **s);
具体的错误描述信息
 av_strerror(re, buf, sizeof (buf)-1);
 av_strerror(re, buf, sizeof (buf)-1);
流的持续时间,以平均时间为单位秒
int64_t duration;
AV_TIME_BASE
#define AV_TIME_BASE            1000000
打印有关输入或输出格式的详细信息,例如持续时间、比特率、流、容器、程序、元数据、边数据,编解码器和tinme base。
void av_dump_format(AVFormatContext *ic,
                    int index,   //streamde 索引
                    const char *url,   //源文件或者目标文件
                    int is_output);  选择上下文是输入(0)还是输出(1av_dump_format(ic,0,path,0);
初始化网络库(可以打开rtsp rtmp http 协议的流媒体视频)
    avformat_network_init();
设置rtsp流使用tcp协议打开
    av_dict_set(&opts, "rtsp_transport", "tcp", 0);
 网络延迟时间
 av_dict_set(&opts,"max_delay", "500", 0);
获取流信息
  re =avformat_find_stream_info(ic,0);
AVCodecParameters结构体描述编码流的属性。

二、获取音视频流信息通畅使用遍历和函数

for (int i = 0; i < ic->nb_streams; i++)
	{
		AVStream *as = ic->streams[i]; //索引大小
		cout << "codec_id = " << as->codecpar->codec_id << endl;
		cout << "format = " << as->codecpar->format << endl;
遍历
		//音频 AVMEDIA_TYPE_AUDIO
		//as->codecpar包含了一些类型数据
		if (as->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
		{
			audioStream = i;
			cout <<i<< "音频信息" << endl;
			cout << "帧率= " << as->codecpar->sample_rate << endl;
			//AVSampleFormat;
			cout << "channels = " << as->codecpar->channels << endl;
			//一帧数据  单通道样本数 
			cout << "frame_size = " << as->codecpar->frame_size << endl;
			//双通道 1024 * 2 * 2 = 4096  fps = sample_rate/frame_size
			
		}
		//视频 AVMEDIA_TYPE_VIDEO
		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<<"video fps = " <<r2d(as->avg_frame_rate)<<endl;
		}
	}
获取视频流函数
	videoStream = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
	///ic->streams[videoStream]

三、AV_read_frame中相关参数及函数

AVPacket:

AVBufferRef *buf 引用通常不用管
pts 显示时间 dts 解码时间
AVPacket *av_Packet_alloc(Void);创建并初始化,只创建对象(堆)
AVPacket *av_Pakcet_clone(const AVPacket *src); //创建并用计数
				同步需要两个队列进行同步,需要克隆
int av_Packet_ref(AvPacket *dst,const AVPacket *src);	//引用增加
int av_Packet_unref(AVPacket *pkt);						//引用减少
void av_packet_free(AVPacket **pkt);			//清空对象并减引用计数
int av_Packet_from_data(AVPacket *pkt,uint8_t *data,int size);  //制作packet
int av_copy_packet();	//老式版本,类似于深拷贝,比较浪费时间。

av_seek_frame 滑动条拖动时需要

int av_seek_frame(AVFormatContext *s, 
				int stream_index,	//-1 default
				int64_t timestamp,	//AVstream,timebase
				int flags);
	其中flag:
	#define AVSEEK_FLAG_BACKWARD	1 //seekbackward
	#define AVSEEK_FLAG_BYTE	    2 
	#define AVSEEK_FLAG_ANY			4 //找最近任一帧
	#define AVSEEK_FLAG_FRAME		8 //找关键帧

示例代码:

#include <thread>
void XSleep(int ms)
{
	//c++ 11  为了支持跨平台
	chrono::milliseconds du(ms);
	this_thread::sleep_for(du);
}
#pragma comment(lib,"avcodec.lib")
static double r2d(AVRational r)
{
	return r.den == 0 ? 0:(double)r.num / (double)r.den;
}
	//malloc AVPacket并初始化
	AVPacket *pkt = av_packet_alloc();
	for (;;)
	{
		int re = av_read_frame(ic, pkt);
		if (re != 0)
		{
			//循环播放
	cout << "==============================end==============================" << endl;
			int ms = 3000; //三秒位置 根据时间基数(分数)转换
			long long pos = (double)ms/ (double)1000*r2d(ic->streams[pkt->stream_index]->time_base);
			av_seek_frame(ic, videoStream, pos, AVSEEK_FLAG_BACKWARD | AVSEEK_FLAG_FRAME);
			continue;
		}
		cout << "pkt->size = "<< pkt->size << endl;
		//显示的时间
		cout << "pkt->pts = " << pkt->pts << endl;
		
		//转换为毫秒,方便做同步
		cout << "pkt->pts ms = " << pkt->pts * (r2d(ic->streams[pkt->stream_index]->time_base) * 1000) << endl;
		//解码时间
		cout << "pkt->dts = " << pkt->dts << endl;
		if (pkt->stream_index == videoStream)
		{
			cout << "图像" << endl;
		}
		if (pkt->stream_index == audioStream)
		{
			cout << "音频" << endl;
		}
		//释放,引用计数-1 为0释放空间
		av_packet_unref(pkt);

		//XSleep(500);
	}

	av_packet_free(&pkt);
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要使用FFmpeg库进行推流和跳转功能,需要按照以下步骤进行操作: 1. 初始化FFmpeg库 在使用FFmpeg库之前,需要先初始化FFmpeg库。可以使用av_register_all()函数进行初始化。 ```c av_register_all(); ``` 2. 打开输入文件 使用avformat_open_input()函数打开输入文件,然后使用avformat_find_stream_info()函数查找文件中的流信息。 ```c AVFormatContext *formatCtx = NULL; avformat_open_input(&formatCtx, inputFile, NULL, NULL); avformat_find_stream_info(formatCtx, NULL); ``` 3. 打开输出文件 使用avformat_alloc_output_context2()函数创建输出文件的AVFormatContext,并使用avio_open()函数打开输出文件。 ```c AVFormatContext *outFormatCtx = NULL; avformat_alloc_output_context2(&outFormatCtx, NULL, NULL, outputFile); AVIOContext *outAVIOContext = NULL; avio_open(&outAVIOContext, outputFile, AVIO_FLAG_WRITE); outFormatCtx->pb = outAVIOContext; ``` 4. 为输出文件添加流 使用avformat_new_stream()函数为输出文件添加音频或视频流,并设置流的编码格式和参数。 ```c AVStream *outStream = avformat_new_stream(outFormatCtx, NULL); outStream->codecpar->codec_id = codecId; outStream->codecpar->codec_type = codecType; outStream->codecpar->width = width; outStream->codecpar->height = height; outStream->codecpar->sample_rate = sampleRate; outStream->codecpar->channels = channels; outStream->codecpar->format = AV_SAMPLE_FMT_FLTP; ``` 5. 打开编码器 使用avcodec_find_encoder()函数查找流的编码器,并使用avcodec_open2()函数打开编码器。 ```c AVCodec *encoder = avcodec_find_encoder(outStream->codecpar->codec_id); AVCodecContext *encoderCtx = avcodec_alloc_context3(encoder); avcodec_parameters_to_context(encoderCtx, outStream->codecpar); avcodec_open2(encoderCtx, encoder, NULL); ``` 6. 写入文件头 使用avformat_write_header()函数写入输出文件的文件头。 ```c avformat_write_header(outFormatCtx, NULL); ``` 7. 读取和写入数据 使用av_read_frame()函数读取输入文件中的数据,并使用av_write_frame()函数将数据写入输出文件。如果需要跳转到指定时间点,可以使用av_seek_frame()函数进行跳转。 ```c while (av_read_frame(formatCtx, &packet) == 0) { if (packet.stream_index == streamIndex) { if (av_seek_frame(formatCtx, streamIndex, timestamp, AVSEEK_FLAG_BACKWARD) >= 0) { avcodec_flush_buffers(decoderCtx); continue; } avcodec_send_packet(decoderCtx, &packet); while (avcodec_receive_frame(decoderCtx, frame) == 0) { // 对音视频数据进行处理 avcodec_send_frame(encoderCtx, frame); while (avcodec_receive_packet(encoderCtx, &outPacket) == 0) { outPacket.stream_index = outStream->index; av_interleaved_write_frame(outFormatCtx, &outPacket); av_packet_unref(&outPacket); } } } av_packet_unref(&packet); } ``` 8. 关闭和释放资源 使用av_write_trailer()函数写入输出文件的文件尾,并使用avformat_close_input()、avformat_close_output()等函数关闭输入输出文件,并释放相应的资源。 ```c av_write_trailer(outFormatCtx); avformat_close_input(&formatCtx); avformat_close_input(&outFormatCtx); avcodec_close(decoderCtx); avcodec_close(encoderCtx); avformat_free_context(formatCtx); avformat_free_context(outFormatCtx); av_frame_free(&frame); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风赤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值