上节介绍了如何打开音视频文件并将输出流进行配置,这节分享一下如何读取音视频帧,将读取的帧让rtmp进行推流。
首先用int avio_open(AVIOContext **s, const char *url, int flags);打开文件io流,
第一个参数是io上下文,在输出流上下文结构体中的有存放该结构体
第二个参数是输出的视频地址
第三个参数是打开方式,这里传入AVIO_FLAG_WRITE,意思就是写入的意思
然后利用int avformat_write_header(AVFormatContext *s, AVDictionary **options);写入头信息
最后再利用死循环读取每一帧
利用int av_read_frame(AVFormatContext *s, AVPacket *pkt);函数将读取到的每一帧放入AVPacket包中,本节先打印pkt中的显示时间戳,最后是源码分享
extern "C"
{
#include "libavformat/avformat.h"
}
#include <iostream>
using namespace std;
#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"avcodec.lib")
int XError(int errNum)
{
char buf[1024] = { 0 };
av_strerror(errNum, buf, sizeof(buf));
std::cout << buf << endl;
getchar();
return -1;
}
int main(int argc, char *argv[])
{
char *inUrl = "test.flv";
char *outUrl = "rtmp://192.168.198.128/live";
//初始化所有封装和解封装 flv mp4 mov mp3
av_register_all();
//初始化网络库
avformat_network_init();
//1 打开文件,解封装
//输入封装上下文
AVFormatContext *ictx = NULL;
//打开文件,解封文件头
int re=avformat_open_input(&ictx,inUrl,NULL,NULL);
if (re != 0)
{
return XError(re);
}
std::cout << "open file" << inUrl << "Success" << endl;
//获取音视频流信息,h264 flv
re=avformat_find_stream_info(ictx,0);
if (re != 0)
{
return XError(re);
}
av_dump_format(ictx,0,inUrl,0);
/
//输出流
//创建输出流上下文
AVFormatContext *octx = NULL;
re=avformat_alloc_output_context2(&octx,0,"flv",outUrl);
if (!octx)
{
return XError(re);
}
std::cout << "octx create success!" << endl;
//配置输出流
//遍历输入的AVStream
for (int i = 0;i < ictx->nb_streams;i++)
{
//创建输出流
AVStream *out= avformat_new_stream(octx,ictx->streams[i]->codec->codec);
if (!out)
{
return XError(0);
}
//复制配置信息,用于MP4
//re=avcodec_copy_context(out->codec, ictx->streams[i]->codec);
re = avcodec_parameters_copy(out->codecpar, ictx->streams[i]->codecpar);
out->codec->codec_tag = 0;
}
av_dump_format(octx, 0, outUrl, 1);
//
//rtmp推流
//打开io
re=avio_open(&octx->pb,outUrl,AVIO_FLAG_WRITE);
if (!octx->pb)
{
return XError(re);
}
//写入头信息
re=avformat_write_header(octx,0);
if (re < 0)
{
return XError(re);
}
cout << "avformat_writr_header" << re << endl;
//推流每一帧数据
AVPacket pkt;
for (;;)
{
re=av_read_frame(ictx,&pkt);
if (re != 0)
{
break;
}
cout << pkt.pts <<" "<<flush;
//清除空间
av_packet_unref(&pkt);
}
std::cout << "file to rtmp test" << endl;
getchar();
return 0;
}