将rtsp流中的h264视频流在没解码之前获取下来,并保存到本地文件mp4中的h264流中,h264->mp4
网络摄像机rtsp地址详解。

流程图:

源码:

.h
#ifndef RTSPSTREAMMUXTASK_H
#define RTSPSTREAMMUXTASK_H#include <QMainWindow>
#include <QThread>
#include <QImage>
#include <iostream>
#include <stdio.h>extern "C"
{#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libavutil/mathematics.h"
}class RtspStreamMuxTask : public QMainWindow
{Q_OBJECTpublic:explicit RtspStreamMuxTask(QWidget *parent = 0);~RtspStreamMuxTask();void rtsp();
};#endif // RTSPSTREAMMUXTASK_H
.cpp
#include "rtspstreammuxtask.h"
#include <stdio.h>
#include <iostream>
#include <QDebug>
#include <QDateTime>
#include <stdlib.h>RtspStreamMuxTask::RtspStreamMuxTask(QWidget *parent) :QMainWindow(parent)
{rtsp();
}RtspStreamMuxTask::~RtspStreamMuxTask()
{}void RtspStreamMuxTask::rtsp()
{AVFormatContext *inVFmtCtx=NULL,*outFmtCtx=NULL;int frame_index=0;//统计帧数int inVStreamIndex=-1,outVStreamIndex=-1;//输入输出视频流在文件中的索引位置const char *inVFileName = "rtsp://admin:123456@192.168.31.168:554/type=0&id=1";const char *outFileName = "video.mp4";//======================输入部分============================//inVFmtCtx = avformat_alloc_context();//初始化内存//打开输入文件//打开一个文件并解析。可解析的内容包括:视频流、音频流、视频流参数、音频流参数、视频帧索引。//参数一:AVFormatContext **ps, 格式化的上下文(由avformat_alloc_context分配)的指针。//参数二:要打开的流的url,地址最终会存入到AVFormatContext结构体当中。//参数三:指定输入的封装格式。一般传NULL,由FFmpeg自行探测。//参数四:包含AVFormatContext和demuxer私有选项的字典。返回时,此参数将被销毁并替换为包含找不到的选项if(avformat_open_input(&inVFmtCtx,inVFileName,NULL,NULL)<0){printf("Cannot open input file.\n");return ;}//查找输入文件中的流/*avformat_find_stream_info函数*///参数一:媒体文件上下文。//参数二:字典,一些配置选项。      /*媒体句柄*/if(avformat_find_stream_info(inVFmtCtx,NULL)<0){printf("Cannot find stream info in input file.\n");return ;}//查找视频流在文件中的位置for(size_t i=0;i<inVFmtCtx->nb_streams;i++){//nb_streams 视音频流的个数//streams :输入视频的AVStream []数组  codec:该流对应的AVCodecContextif(inVFmtCtx->streams[i]->codecpar->codec_type==AVMEDIA_TYPE_VIDEO){//streams 视音频流inVStreamIndex=(int)i;break;}}     AVCodecParameters *codecPara = inVFmtCtx->streams[inVStreamIndex]->codecpar;//输入视频流的编码参数printf("===============Input information========>\n");av_dump_format(inVFmtCtx, 0, inVFileName, 0); //输出视频信息printf("===============Input information========<\n");//=====================输出部分=========================////打开输出文件并填充格式数据//参数一:函数调用成功之后创建的AVFormatContext结构体。//参数二:指定AVFormatContext中的AVOutputFormat,确定输出格式。指定为NULL,设定后两个参数(format_name或者filename)由FFmpeg猜测输出格式。。//参数三:使用该参数需要自己手动获取AVOutputFormat,相对于使用后两个参数来说要麻烦一些。//参数四:指定输出格式的名称。根据格式名称,FFmpeg会推测输出格式。输出格式可以是“flv”,“mkv”等等。if(avformat_alloc_output_context2(&outFmtCtx,NULL,NULL,outFileName)<0){printf("Cannot alloc output file context.\n");return;}//打开输出文件并填充数据if(avio_open(&outFmtCtx->pb,outFileName,AVIO_FLAG_READ_WRITE)<0){printf("output file open failed.\n");return;}//在输出的mp4文件中创建一条视频流AVStream *outVStream = avformat_new_stream(outFmtCtx,NULL);//记录视频流通道数目。存储视频流通道。if(!outVStream){printf("Failed allocating output stream.\n");return ;}outVStream->time_base.den=25;//AVRational这个结构标识一个分数,num为分数,den为分母(时间的刻度)outVStream->time_base.num=1;outVStreamIndex=outVStream->index;//查找编码器//参数一:id请求的编码器的AVCodecID//参数二:如果找到一个编码器,则为NULL。//H264/H265码流后,再调用avcodec_find_decoder解码后,再写入到/MP4文件中去AVCodec *outCodec = avcodec_find_decoder(codecPara->codec_id);if(outCodec==NULL){printf("Cannot find any encoder.\n");return;}//从输入的h264编码器数据复制一份到输出文件的编码器中AVCodecContext *outCodecCtx=avcodec_alloc_context3(outCodec); //申请AVCodecContext空间。需要传递一个编码器,也可以不传,但不会包含编码器。//AVCodecParameters与AVCodecContext里的参数有很多相同的AVCodecParameters *outCodecPara = outFmtCtx->streams[outVStream->index]->codecpar;//avcodec_parameters_copy()来copyAVCodec的上下文。if(avcodec_parameters_copy(outCodecPara,codecPara)<0){printf("Cannot copy codec para.\n");return;}//基于编解码器提供的编解码参数设置编解码器上下文参数//参数一:要设置参数的编解码器上下文//参数二:媒体流的参数信息 , 包含 码率 , 宽度 , 高度 , 采样率 等参数信息if(avcodec_parameters_to_context(outCodecCtx,outCodecPara)<0){printf("Cannot alloc codec ctx from para.\n");return ;}//设置编码器参数(不同参数对视频编质量或大小的影响)/*outCodecCtx->time_base.den=25;outCodecCtx->time_base.num=1;*/outCodecCtx->bit_rate =0;//目标的码率,即采样的码率;显然,采样码率越大,视频大小越大  比特率outCodecCtx->time_base.num=1;//下面两行:一秒钟25帧outCodecCtx->time_base.den=15;outCodecCtx->frame_number=1;//每包一个视频帧//打开输出文件需要的编码器if(avcodec_open2(outCodecCtx,outCodec,NULL)<0){printf("Cannot open output codec.\n");return ;}printf("============Output Information=============>\n");av_dump_format(outFmtCtx,0,outFileName,1);//输出视频信息printf("============Output Information=============<\n");//写入文件头if(avformat_write_header(outFmtCtx,NULL)<0){printf("Cannot write header to file.\n");return ;}//===============编码部分===============////AVPacket 数据结构 显示时间戳(pts)、解码时间戳(dts)、数据时长,所在媒体流的索引等AVPacket *pkt = av_packet_alloc();//存储每一个视频/音频流信息的结构体AVStream *inVStream = inVFmtCtx->streams[inVStreamIndex];//循环读取每一帧直到读完 从媒体流中读取帧填充到填充到Packet的数据缓存空间while(av_read_frame(inVFmtCtx,pkt)>=0){//循环读取每一帧直到读完pkt->dts = 0;//不加这个时间戳会出问题,时间戳比之前小的话 FFmpeg会选择丢弃视频包,现在给视频包打时间戳可以重0开始依次递增。if(pkt->stream_index==inVStreamIndex){//确保处理的是视频流 stream_index标识该AVPacket所属的视频/音频流。//FIXME:No PTS (Example: Raw H.264)//Simple Write PTS//如果当前处理帧的显示时间戳为0或者没有等等不是正常值if(pkt->pts==AV_NOPTS_VALUE){printf("frame_index:%d\n", frame_index);//Write PTS时间 刻度AVRational time_base1 = inVStream->time_base;//Duration between 2 frames (us) 时长//AV_TIME_BASE 时间基//av_q2d(AVRational);该函数负责把AVRational结构转换成double,通过这个函数可以计算出某一帧在视频中的时间位置//r_frame_rateint64_t calc_duration = (double)AV_TIME_BASE / av_q2d(inVStream->r_frame_rate);//Parameters参数pkt->pts = (double)(frame_index*calc_duration) / (double)(av_q2d(time_base1)*AV_TIME_BASE);pkt->dts = pkt->pts;pkt->duration = (double)calc_duration / (double)(av_q2d(time_base1)*AV_TIME_BASE);frame_index++;}//Convert PTS/DTS//AVPacket// pts 显示时间戳// dts 解码时间戳// duration 数据的时长,以所属媒体流的时间基准为单位// pos 数据在媒体流中的位置,未知则值为-1// 标识该AVPacket所属的视频/音频流。pkt->pts = av_rescale_q_rnd(pkt->pts, inVStream->time_base, outVStream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt->dts = av_rescale_q_rnd(pkt->dts, inVStream->time_base, outVStream->time_base, (enum AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));pkt->duration = av_rescale_q(pkt->duration, inVStream->time_base, outVStream->time_base);pkt->pos = -1;pkt->stream_index = outVStreamIndex;printf("Write 1 Packet. size:%5d\tpts:%ld\n", pkt->size, pkt->pts);//Writeif (av_interleaved_write_frame(outFmtCtx, pkt) < 0) {printf("Error muxing packet\n");break;}//处理完压缩数据之后,并且在进入下一次循环之前,//记得使用 av_packet_unref 来释放已经分配的AVPacket->data缓冲区。av_packet_unref(pkt);}}av_write_trailer(outFmtCtx);//=================释放所有指针=======================av_packet_free(&pkt);//堆栈上数据缓存空间av_free(inVStream);//存储每一个视频/音频流信息的结构体av_free(outVStream);//在输出的mp4文件中创建一条视频流avformat_close_input(&outFmtCtx);//关闭一个AVFormatContextavcodec_close(outCodecCtx);avcodec_free_context(&outCodecCtx);av_free(outCodec);avcodec_parameters_free(&outCodecPara);avcodec_parameters_free(&codecPara);avformat_close_input(&inVFmtCtx);//关闭一个AVFormatContextavformat_free_context(inVFmtCtx);//销毁函数avio_close(outFmtCtx->pb);}

FFMPEG保存视频流数据至本地(rtsp转mp4)相关推荐

  1. 使用wxpy统计微信好友数量及男女数量,并保存好友数据到本地

    使用wxpy统计微信好友数量及男女数量,并保存好友数据到本地,代码如下: from wxpy import * import json class bots:def __init__(self):pa ...

  2. 【开源项目】保存YUV420数据到本地

    void SaveYUV420(AVFrame* Frameyuv) {//********************** 保存YUV数据FILE *yuv_file = fopen("yuv ...

  3. Secure保存串口数据到本地

    有的时候我们需要进行长时间的老化测试,测试过程中需要将串口打印出来的数据进行保存.这时候如果数据可以实时保存到本地的话,就会非常的方便.本文记录了一种使用Secure进行串口数据保存的方式. 本文适用 ...

  4. ffmpeg截取视频流、rtsp录mp4,与海思NVR,内存问题

    一. FFmpeg定时截取rtsp流,60s保存为一个MP4, 我写的ffmpeg的命令为:   ffmpeg -n -rtsp_transport tcp -i rtsp://XXXXXX   -v ...

  5. 使用FFmpeg读取视频流并保存

    使用FFmpeg进行多媒体开发(一)--读取视频流 准备 主函数 总结 最近接触到FFmpeg,需要实现一个将rtsp协议的码流读取并能显示的程序.在网上搬运代码的同时,也写一些对FFmpeg,Qt这 ...

  6. 「Python|音视频处理|场景案例」如何使用ffmpeg下载m3u8视频到本地并保存成mp4

    本文主要介绍如何使用ffmpeg批量下载视频到本地并保存成指定格式. 文章目录 场景说明 解决方案 源代码 场景说明 当我们希望将网页上的视频下载到本地的时候,我们可能获取到的视频地址是指向.m3u8 ...

  7. python保存数据到本地文件_python保存数据到本地文件的方法

    python保存数据到本地文件的方法 1.保存列表为.txt文件 #1/list写入txt ipTable = ['158.59.194.213', '18.9.14.13', '58.59.14.2 ...

  8. 微信小程序-注册登录功能-本地数据保存-页面数据交替

    Title:微信小程序-注册登录功能-本地数据保存-页面数据交替 完美-小程序登录注册功能.rar-- 访问码:yqa5 1.主页面 主页面login.js代码 // pages/login/logi ...

  9. ffmpeg推流摄像头数据至公网服务器

    完整的推流代码已经托管到个人的Gitee,如有需要请自取 https://gitee.com/MonsterAKALei/push_video.git ffmpeg推流摄像头数据 昨天实现用API分别 ...

最新文章

  1. transactionscope 中的异步 处理 异常_协程中的取消和异常 | 异常处理详解
  2. 树莓派 之 Screen
  3. BufferedReader
  4. 第十四章 降维操作-机器学习老师板书-斯坦福吴恩达教授
  5. Lucene4.3.1 拼写检查SpellChecker
  6. 八、Linux 常用 Shell 命令,控制台的快捷键以及 Shell 编程(中)
  7. Vx2Text-多模态任务新进展!哥大Facebook提出VX2TEXT模型,实现了“视频+X”到“文本”的任务...
  8. C#中使用正则表达式验证电话号码、手机号、身份证号、数字和邮编
  9. 渗透测试工程师前景_网络安全工程师教你:Kali Linux之Metasploit渗透测试基础(一)...
  10. 存储图片到第三方云服务器
  11. jest单元测试-匹配器
  12. azw3 netty权威指南_小程序,巧应用(pdf+epub+mobi+txt+azw3)
  13. 图片批量压缩工具免费版-免费的批量图片压缩工具
  14. 偷梁换柱“Windows 11安装包”竟成了恶意程序?
  15. C++实验02(02)华氏温度转换为摄氏温度
  16. 微博、微信,媒体选择何去何从
  17. 【尚硅谷】Vue.js从入门到精通笔记
  18. 计算机一级考试:选择题汇总D(精简版)
  19. RestTemplate技术预研——OkHttp
  20. cgroup架构及控制文件介绍

热门文章

  1. 微信群运营怎么做?一文讲透社群活跃技巧及发展模式
  2. 利用机器学习算法挖掘群控网络黑产设备
  3. outlook服务器拒绝访问文件夹,无法打开共享日历文件夹 - Outlook | Microsoft Docs
  4. 创业者不能盲目的跟风,不然结局很凄凉
  5. 项目实战2 | 基于Swarm+Prometheus实现双VIP可监控Web高可用集群
  6. 网站更换国外服务器,备案被注销替换外国服务器?这样合理吗?
  7. Ubuntu安装Nixnote,解决印象笔记(国服/中国区)登录不能显示输入密码的问题
  8. 开幕在即!众星齐聚八泉峡推介会 为山西加油,为二青助力!
  9. 约他没去玩 他却更爱好跟男共事一伏
  10. 一战封神——提升奇珍提高战力