zoukankan      html  css  js  c++  java
  • FFmpeg4.0笔记:rtsp2rtmp

    Github

    https://github.com/gongluck/FFmpeg4.0-study.git

    #include <iostream>
    using namespace std;
    
    extern "C"
    {
    #include "libavformat/avformat.h"
    #include "libavutil/time.h"
    }
    #pragma comment(lib, "avformat.lib")
    #pragma comment(lib, "avutil.lib")
    #pragma comment(lib, "avcodec.lib")
    
    char av_error[AV_ERROR_MAX_STRING_SIZE] = { 0 };
    #define av_err2str(errnum) 
        av_make_error_string(av_error, AV_ERROR_MAX_STRING_SIZE, errnum)
    
    #define INFILE	"in.flv"
    #define RTMP	"rtmp://192.168.140.128/live/test"
    #define RTSP	"rtsp://184.72.239.149/vod/mp4://BigBuckBunny_175k.mov"
    
    int file2rtmp()
    {
    	int ret = 0;
    	//封装上下文
    	AVFormatContext* ictx = nullptr;
    	AVFormatContext* octx = nullptr;
    	const char* iurl = INFILE;
    	const char* ourl = RTMP;
    	int64_t starttime;
    
    	ret = avformat_network_init();
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//打开文件,解封文件头
    	ret = avformat_open_input(&ictx, iurl, nullptr, nullptr);
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    	cerr << "open file " << iurl << " success." << endl;
    
    	//获取音视频流信息,h264 flv
    	ret = avformat_find_stream_info(ictx, nullptr);
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//打印媒体信息
    	av_dump_format(ictx, 0, iurl, 0);
    
    	//////////////////////////////
    
    	//输出流
    	ret = avformat_alloc_output_context2(&octx, av_guess_format(nullptr, INFILE, nullptr), nullptr, ourl);
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    	cout << "octx create success." << endl;
    
    	//配置输出流
    	for (int i = 0; i < ictx->nb_streams; ++i)
    	{
    		//创建流
    		AVStream* ostream = avformat_new_stream(octx, avcodec_find_encoder(ictx->streams[i]->codecpar->codec_id));
    		if (ostream == nullptr)
    			goto END;
    		//复制配置信息
    		ret = avcodec_parameters_copy(ostream->codecpar, ictx->streams[i]->codecpar);
    		if (ret != 0)
    		{
    			cout << av_err2str(ret) << endl;
    			goto END;
    		}
    		ostream->codecpar->codec_tag = 0;//标记不需要重新编解码
    	}
    	av_dump_format(octx, 0, ourl, 1);
    
    	//////////////////////////////
    
    	//推流
    	ret = avio_open2(&octx->pb, ourl, AVIO_FLAG_WRITE, nullptr, nullptr);
    	if (ret < 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//写入头信息
    	ret = avformat_write_header(octx, nullptr);
    	if (ret < 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//推流每一帧数据
    	AVPacket pkt;
    	starttime = av_gettime();
    	while (av_read_frame(ictx, &pkt) == 0)
    	{
    		//计算转换pts dts
    		AVRational itime = ictx->streams[pkt.stream_index]->time_base;
    		AVRational otime = octx->streams[pkt.stream_index]->time_base;
    		pkt.pts = av_rescale_q_rnd(pkt.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    		pkt.dts = av_rescale_q_rnd(pkt.dts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    		pkt.duration = av_rescale_q_rnd(pkt.duration, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    		pkt.pos = -1;
    
    		if (ictx->streams[pkt.stream_index]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
    		{
    			int64_t nowtime = av_gettime() - starttime;
    			int64_t dts = pkt.dts * av_q2d(octx->streams[pkt.stream_index]->time_base) * 1000 * 1000;
    			if(dts > nowtime)
    				/*av_usleep(dts- nowtime)*/;
    		}
    		
    		ret = av_interleaved_write_frame(octx, &pkt);
    		av_packet_unref(&pkt);
    		if (ret < 0)
    		{
    			cout << av_err2str(ret) << endl;
    			goto END;
    		}
    	}
    	ret = av_write_trailer(octx);//写文件尾
    	if (ret < 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    END:
    	if (ictx != nullptr)
    		avformat_close_input(&ictx);
    	if (octx != nullptr)
    	{
    		avio_close(octx->pb);
    		avformat_free_context(octx);
    	}
    	ret = avformat_network_deinit();
    	if (ret != 0)
    		cout << av_err2str(ret) << endl;
    	return 0;
    }
    
    int rtsp2rtmp()
    {
    	int ret = 0;
    	//封装上下文
    	AVFormatContext* ictx = nullptr;
    	AVFormatContext* octx = nullptr;
    	const char* iurl = RTSP;
    	const char* ourl = RTMP;
    	int64_t starttime;
    
    	ret = avformat_network_init();
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//打开文件,解封文件头
    	ret = avformat_open_input(&ictx, iurl, nullptr, nullptr);
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    	cerr << "open file " << iurl << " success." << endl;
    
    	//获取音视频流信息,h264 flv
    	ret = avformat_find_stream_info(ictx, nullptr);
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//打印媒体信息
    	av_dump_format(ictx, 0, iurl, 0);
    
    	//////////////////////////////
    
    	//输出流
    	ret = avformat_alloc_output_context2(&octx, av_guess_format(nullptr, INFILE, nullptr), nullptr, ourl);
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    	cerr << "octx create success." << endl;
    
    	//配置输出流
    	for (int i = 0; i < ictx->nb_streams; ++i)
    	{
    		//创建流
    		AVStream* ostream = avformat_new_stream(octx, avcodec_find_encoder(ictx->streams[i]->codecpar->codec_id));
    		if (ostream == nullptr)
    			return -1;
    		//复制配置信息
    		ret = avcodec_parameters_copy(ostream->codecpar, ictx->streams[i]->codecpar);
    		if (ret != 0)
    		{
    			cout << av_err2str(ret) << endl;
    			goto END;
    		}
    		ostream->codecpar->codec_tag = 0;//标记不需要重新编解码
    	}
    	av_dump_format(octx, 0, ourl, 1);
    
    	//////////////////////////////
    
    	//推流
    	if (ret != 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	ret = avio_open(&octx->pb, ourl, AVIO_FLAG_WRITE);
    	if (ret < 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//写入头信息
    	ret = avformat_write_header(octx, nullptr);
    	if (ret < 0)
    	{
    		cout << av_err2str(ret) << endl;
    		goto END;
    	}
    
    	//推流每一帧数据
    	AVPacket pkt;
    	starttime = av_gettime();
    	while (av_read_frame(ictx, &pkt) == 0)
    	{
    		//计算转换pts dts
    		AVRational itime = ictx->streams[pkt.stream_index]->time_base;
    		AVRational otime = octx->streams[pkt.stream_index]->time_base;
    		pkt.pts = av_rescale_q_rnd(pkt.pts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    		pkt.dts = av_rescale_q_rnd(pkt.dts, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    		pkt.duration = av_rescale_q_rnd(pkt.duration, itime, otime, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
    		pkt.pos = -1;
    
    		ret = av_interleaved_write_frame(octx, &pkt);
    		av_packet_unref(&pkt);
    		if (ret < 0)
    			cout << av_err2str(ret) << endl;//不用退出
    	}
    
    END:
    	if (ictx != nullptr)
    		avformat_close_input(&ictx);
    	if (octx != nullptr)
    	{
    		avio_close(octx->pb);
    		avformat_free_context(octx);
    	}
    	ret = avformat_network_deinit();
    	if (ret != 0)
    		cout << av_err2str(ret) << endl;
    	return 0;
    }
    
    int main()
    {
    	//file2rtmp();
    	rtsp2rtmp();
    	system("pause");
    	return 0;
    }
    
  • 相关阅读:
    ActiveMQ的作用总结(应用场景及优势)
    深入剖析ThreadLocal实现原理以及内存泄漏问题
    Java ThreadLocal 原理分析
    关于iview ui的"Page分页"组件的使用
    使用TortoiseGit操作分支的创建与合并
    乐观锁与悲观锁的区别
    Linux下如何安装MongoDB及配置
    centos8安装图解(超详细教程)
    SpringBoot整合MongoDB
    PPT学习---醍醐灌顶!你对PPT的理解过时了!
  • 原文地址:https://www.cnblogs.com/gongluck/p/9028504.html
Copyright © 2011-2022 走看看