通过ffmpeg实时读取宇视摄像头的高清帧流数据,并保存4张图片进行4合一照片的生成。
FFmpeg视频解码过程
通常来说,FFmpeg的视频解码过程有以下几个步骤:
注册所支持的所有的文件(容器)格式及其对应的CODEC av_register_all()
打开文件 avformat_open_input()
从文件中提取流信息 avformat_find_stream_info()
在多个数据流中找到视频流 video stream(类型为MEDIA_TYPE_VIDEO)
查找video stream 相对应的解码器 avcodec_find_decoder
打开解码器 avcodec_open2()
为解码帧分配内存 av_frame_alloc()
从流中读取读取数据到Packet中 av_read_frame()
对video 帧进行解码,调用 avcodec_decode_video2()
SaveAsJPEG(); 函数
1.分配AVFormatContext对象 AVFormatContext* pFormatCtx = avformat_alloc_context();
2.设置输出文件格式 pFormatCtx->oformat = av_guess_format("mjpeg", NULL, NULL);
3.建并初始化一个和该url相关的AVIOContext
4.// 构建一个新stream
5.// 设置该stream的信息
6.查找编码器
7.设置pCodecCtx的解码器为pCodec
8.给AVPacket分配足够大的空间
代码如下:
//通过ffmpeg实时读取宇视摄像头的高清帧流数据,并保存一张图片进行4合一照片的生成。
#include <iostream>
#include <stdio.h>
#include <opencv2/opencv.hpp>
//#include <Windows.h>
using namespace std;
using namespace cv;
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswscale/swscale.h"
#include "libavdevice/avdevice.h"
#include "libavutil/pixfmt.h"
}
//由于我们建立的是C++的工程 编译的时候使用的C++的编译器编译
//而FFMPEG是C的库 因此这里需要加上extern "C"
//否则会提示各种未定义
//void SaveAsBMP(AVFrame *pFrameRGB, int width, int height, int index, int bpp);
int SaveAsJPEG(AVFrame* pFrame, int width, int height, int index);
void FourToOne(int x,int y);//生成4合1照片合成图
Mat image_1;
Mat image_2;
Mat image_3;
Mat image_4;
int main()
{
cout << "Hello FFmpeg!" << endl;
av_register_all(); //初始化FFMPEG 调用了这个才能正常适用编码器和解码器
// 初始化网络模块
avformat_network_init();
//=========================== 创建AVFormatContext结构体 ===============================//
//分配一个AVFormatContext,FFMPEG所有的操作都要通过这个AVFormatContext来进行
AVFormatContext *pFormatCtx = avformat_alloc_context();
//==================================== 打开文件 ======================================//
char file_path[] = "rtsp://admin:admin@192.168.1.13:554/video2";
AVDictionary* options = NULL;
av_dict_set(&options, "buffer_size", "102400", 0); //设置缓存大小,1080p可将值调大
av_dict_set(&options, "rtsp_transport", "tcp", 0); //以udp方式打开,如果以tcp方式打开将udp替换为tcp
av_dict_set(&options, "stimeout", "2000000", 0); //设置超时断开连接时间,单位微秒
av_dict_set(&options, "max_delay", "500000", 0); //设置最大时延
// packet = (AVPacket *)av_malloc(sizeof(AVPacket));
//打开网络流或文件流
if (avformat_open_input(&pFormatCtx, file_path, NULL, &options) != 0)
{
printf("Couldn't open input stream.\n");
return -1;
}
//循环查找视频中包含的流信息,直到找到视频类型的流
//便将其记录下来 保存到videoStream变量中
int i;
int videoStream;
//=================================== 获取视频流信息 ===================================//
if (avformat_find_stream_info(pFormatCtx, NULL)