1、功能:将RTSP流保存为本地TS文件

2、存在问题:
保存mp4文件播放不了,还未解决…希望路过的大佬帮忙瞅瞅 _

3、流程:
0)初始化:并注册所有的解封装器、封装器和协议,初始化网络库;
1)打开输入的解封装上下文;
2)打开输出的封装上下文;
3)为输出的封装上下文分别新建音频流、视频流stream;
4)根据输入编码类型获取输出编码器codec;
5)为输出流的编码器参数字段codecpar设置参数(从输入编码器参数字段拷贝);
6)创建输出的编码器上下文,并通过输出编码器参数字段设置编码器上下文;
7)打开输出的编码器上下文;
8)通过输出封装上下文写文件头;
9)读取输入解封装上下文的包packet
10)根据输入的解封装上下文和输出的封装上下文的时间基准time_base,转换时间戳pts、dts,以及设置整个时间duration;
11)将音视频包以正确交织方式写入输出的封装上下文

4、代码:

/*
功能:将RTSP保存为本地ts文件
存在问题:保存mp4文件播放不了,还未解决...
*/#include <iostream>
#include <string>
extern "C"{#include <libavformat/avformat.h>#include <libavcodec/avcodec.h>
}
using namespace std;
AVFormatContext *inputContext = NULL;
AVFormatContext *outputContext = NULL;// 打开输入rtsp,获得输入封装上下文
bool openInput(string& inputUrl)
{// 输入的解封装上下文int ret = avformat_open_input(&inputContext,inputUrl.c_str(),0,  // 0表示自动选择解封器0 //参数设置,比如rtsp的延时时间);if (ret != 0){char buf[1024] = { 0 };av_strerror(ret, buf, sizeof(buf) - 1);cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "open " << inputUrl << " failed! :" << buf << endl;return false;}ret = avformat_find_stream_info(inputContext, 0);if (ret < 0){char buf[1024] = { 0 };av_strerror(ret, buf, sizeof(buf) - 1);cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avformat_find_stream_info failed! " << buf << endl;return false;}return true;
}// 读取输入封装上下文的packet
AVPacket * readPacketFromSource()
{AVPacket* pkt = av_packet_alloc();int ret = av_read_frame(inputContext, pkt);if (ret != 0){av_packet_free(&pkt);cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "av_read_frame failed!" << endl;return NULL;}return pkt;
}// 修改时间戳
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb)
{if(NULL == pkt){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "input err!" << endl;return;}if(pkt->pts != AV_NOPTS_VALUE)pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);if(pkt->dts != AV_NOPTS_VALUE)pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
//    if(pkt->pts != AV_NOPTS_VALUE)
//        pkt->pts = av_rescale_q_rnd(pkt->pts, src_tb, dst_tb, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
//    if(pkt->dts != AV_NOPTS_VALUE)
//        pkt->dts = av_rescale_q_rnd(pkt->dts, src_tb, dst_tb, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));if(pkt->duration > 0)pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);//    pkt->pts = pkt->pts < pkt->dts ? pkt->dts:pkt->pts;pkt->pos = -1;
}// 将packt写入新的封装上下文,并释放packet
bool writePacket(AVPacket *pkt)
{if(NULL == pkt || NULL == inputContext || NULL == outputContext){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "input err!" << endl;return false;}auto inputStream  = inputContext->streams[pkt->stream_index];auto outputStream = outputContext->streams[pkt->stream_index];av_packet_rescale_ts(pkt, inputStream->time_base, outputStream->time_base);// 将音视频包以正确交织方式写入封装上下文int ret = av_interleaved_write_frame(outputContext, pkt);// 释放!av_packet_free(&pkt);if(ret != 0){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "av_interleaved_write_frame failed!" << endl;char buf[1024] = { 0 };av_strerror(ret, buf, sizeof(buf) - 1);cout << "avcodec_open2  failed! :" << buf << endl;return false;}return true;
}// 打开输出文件,并获取输出封装上下文
bool openOutput(string& url)
{// 根据输出封装格式,创建输出上下文int ret = avformat_alloc_output_context2(&outputContext, NULL, NULL, url.c_str());if(ret < 0){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avformat_alloc_output_context2 failed!" << endl;return false;}// 打开输出文件ret = avio_open2(&outputContext->pb, url.c_str(), AVIO_FLAG_READ_WRITE, NULL, NULL);if(ret < 0){avformat_free_context(outputContext);outputContext = NULL;cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avio_open failed!" << endl;return false;}unsigned int i = 0;for(i = 0; i < inputContext->nb_streams; i++){#if 0 // 旧版本,使用streams[i]->codec,不建议使用AVStream *stream = avformat_new_stream(outputContext,inputContext->streams[i]->codec->codec);ret = avcodec_copy_context(stream->codec, inputContext->streams[i]->codec);if(ret != 0){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avcodec_copy_context failed!" << endl;break;}
#else // 新版本,弃用streams[i]->codecAVCodecParameters *inCodecPara = inputContext->streams[i]->codecpar;// 为封装上下文创建新的流AVStream *outStream = avformat_new_stream(outputContext, avcodec_find_decoder(inCodecPara->codec_id));if(NULL == outStream){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avformat_new_stream failed!" << endl;break;}outStream->time_base.den=25;//AVRational这个结构标识一个分数,num为分数,den为分母(时间的刻度)outStream->time_base.num=1;// 找到和输入一样的编码器AVCodec* outCodec = avcodec_find_decoder(inCodecPara->codec_id);if (!outCodec){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "can't find the codec id " << inCodecPara->codec_id << endl;break;}// 创建输出编码器上下文AVCodecContext *outCodecContext = avcodec_alloc_context3(outCodec);if(NULL == outCodecContext){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avcodec_alloc_context3 failed!" << endl;break;}// 输入编码器参数 拷贝到 输出编码器参数AVCodecParameters *outCodecPara = outStream->codecpar;ret = avcodec_parameters_copy(outCodecPara, inCodecPara);if(ret < 0){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avcodec_parameters_copy failed!" << endl;break;}// 不加这个,有的流保存为mp4会报错,[mp4 @ 031be9c0] Tag [27][0][0][0] incompatible with output codec id '27' (avc1)// 但是加了这个,保存成Mmp4还是播放不了...outCodecPara->codec_tag = 0;// 输出编码器参数 拷贝到 输出编码器上下文ret = avcodec_parameters_to_context(outCodecContext, outCodecPara);if(ret < 0){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avcodec_parameters_copy failed!" << endl;break;}//        outCodecContext->bit_rate =0;//目标的码率,即采样的码率;显然,采样码率越大,视频大小越大  比特率
//        outCodecContext->time_base.num=1;//下面两行:一秒钟25帧
//        outCodecContext->time_base.den=15;
//        outCodecContext->frame_number=1;//每包一个视频帧// 打开编码器输出上下文ret = avcodec_open2(outCodecContext, outCodec, 0);if(ret != 0){cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avcodec_open2 failed!" << endl;break;}av_free(outCodec);outCodec = NULL;
#endif}// 判断音视频流stream是否全部创建成功if(i != outputContext->nb_streams){avio_close(outputContext->pb);avformat_free_context(outputContext);outputContext = NULL;cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "failed!" << endl;return false;}av_dump_format(outputContext, 0, url.c_str(), 1);//输出视频信息// 写入文件头ret = avformat_write_header(outputContext, NULL);if(ret < 0){avio_close(outputContext->pb);avformat_free_context(outputContext);outputContext = NULL;cout << "[" << __FILE__ << "|" << __LINE__ << "]" << "avformat_write_header failed!" << endl;char buf[1024] = { 0 };av_strerror(ret, buf, sizeof(buf) - 1);cout << "avformat_write_header  failed! :" << buf << endl;return false;}return true;
}void init()
{av_register_all();avformat_network_init();
}
void deinit()
{avformat_network_deinit();
}
int main()
{cout << "Hello World!" << endl;init();string inUrl = "http://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear2/prog_index.m3u8";
//    inUrl = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mp4";int ret = openInput(inUrl);if(true != ret)return -1;string outUrl = "./test1.mp4";ret =openOutput(outUrl);if(true != ret)return -1;while(1){auto pkt = readPacketFromSource();if(pkt){ret = writePacket(pkt);if(ret)cout << "write success!" << endl;elsecout << "write fail!" << endl;}}if(outputContext){avio_close(outputContext->pb);avformat_free_context(outputContext);}if(inputContext){avformat_free_context(inputContext);}deinit();return 0;
}

将RTSP流保存为本地TS文件相关推荐

  1. python怎么保存文件视频教程_python3将视频流保存为本地视频文件

    使用python3+opencv3.3.1环境将视频流保存为本地视频文件,具体内容如下 1.利用opencv中的VideoCapture类获取视频流的链接,通过cv2的方法得到该视频流的帧数和每帧大小 ...

  2. python 保存视频流_python3将视频流保存为本地视频文件

    使用python3+opencv3.3.1环境将视频流保存为本地视频文件,具体内容如下 1.利用opencv中的VideoCapture类获取视频流的链接,通过cv2的方法得到该视频流的帧数和每帧大小 ...

  3. 将Chrome调试器里的JavaScript变量保存成本地JSON文件

    我们在Chrome开发者工具的Console标签页里,可以输入JavaScript变量然后回车,查看这些变量的值. 比如我用类jQuery选择器的语法 var button = $('button') ...

  4. JS 变量保存为本地json文件,读取本地json文件为变量

    一.变量保存为本地json文件: 第一步:把返回的数据转成json格式 var content = json.stringify(data); 第二步:把转成blob这种格式             ...

  5. Python数据分析实战-将一维列表和二维列表内容保存到本地excel文件(附源码和实现效果)

    前面我介绍了可视化的一些方法以及机器学习在预测方面的应用,分为分类问题(预测值是离散型)和回归问题(预测值是连续型).同时做了关于图像识别的系列文章,让读者理解python进行图像识别的过程.原理和方 ...

  6. 爬虫豆瓣读书top250,保存为本地csv文件

    爬虫豆瓣读书top250,保存为本地csv文件 目的 将豆瓣读书top250排名保存到本地excel,包括书名,作者,评分,评论数,简评,网址.用到了requests,res,BeautifulSou ...

  7. vue文件下载:把文件流保存到本地

    开发vue项目时经常碰到文件下载的需求,分两种情况: 一种是:后台给文件路径,前端拼地址去下载文件 另一种是:后台直接返回文件流,前端去处理 第一种很简单这里就不赘述了,直接给出第二种接受文件流并下载 ...

  8. python如何将数据保存到本地json文件

    之前做了dict字典的合并,这一篇会将dict数据转换成json格式的数据保存在本地,并在需要的时候读取显示. 将数据保存成.json文件: @app.route('/', methods=['GET ...

  9. 爬虫豆瓣读书top250,保存为本地csv文件,可用excel查看(具体步骤和容易遇到的坑)

    1.目的 将豆瓣读书top250排名保存到本地excel,包括书名,作者,评分,评论数,简评,网址.用到了requests,res,BeautifulSoup,csv库. 2.分析网址 打开豆瓣读书网 ...

最新文章

  1. CF1385E Directing Edges (拓扑排序判断环)
  2. yii mysql 事务处理_Yii2中事务的使用实例代码详解
  3. Python Flask出现No module named ‘markupsafe._compat
  4. Tomcat的安装与配置(新手向)
  5. python的Web编程
  6. BOM--window对象
  7. freecodecamp_如何充分利用freeCodeCamp
  8. Python刷题-2
  9. 吴恩达深度学习2.1练习_Improving Deep Neural Networks_Regularization
  10. 【BZOJ】1497: [NOI2006]最大获利 最大权闭合子图或最小割
  11. Help with arrayCollection.additem()
  12. C++:标准程序库-STL迭代器Iterator
  13. DataTable转为JSON数据格式代码
  14. CAD制图初学入门:CAD图案填充之图案加洞
  15. 【Week7 作业B】TT的旅行日记
  16. mysql order by 原理及优化详解
  17. 多光谱高光谱图像算法面经
  18. 武汉新时标文化传媒有限公司短视频创作者实现突围?
  19. DeepMind 最新发文:AlphaZero 的黑箱打开了
  20. ElasticSearch(2)

热门文章

  1. No servers available for service: renren…。 Gateway 网关报503错误 ,已解决
  2. BP 供应商创建与修改
  3. 操作操作操作操作操作操作
  4. NORDIC Thingy:52 蓝牙 BLE 服务 SoC 程序调用流程分析之八, 网盘分享 PPT
  5. 入门【必学】20个SEO优化术语
  6. Mysql 2003错误 10038 1045 (推荐第七次解决方案)
  7. qq令牌64位密钥提取_QQ令牌工具 活令牌查询动态密码(大哥牌)
  8. 和利时scada系统服务器参数,MACS-SCADA综合监控系统
  9. RFID不是一个赚快钱的行业,需要沉下心来
  10. 电脑广告弹窗怎么解决?