好久没更新博客了,最近在交毕设的材料耽搁了学习的时间,今天继续开始进行音视频学习的记录,上次利用rtmp进行推流完成了一个基本的流媒体直播,这次要利用本地的摄像头采集视频帧然后利用rtmp将采集到的视频上传到服务器进行直播,这次需要利用opencv和ffmpeg的库进行,所以在编写代码之前需要对项目进行配置。
文件夹的目录还是与之前的一致,bin文件夹存放生成的文件,include文件夹存放头文件,lib文件夹存放库文件,src文件夹存放源代码。
配置的方法还是和之前的一致,在属性中的常规将生成的路径修改成bin文件夹。
头文件目录
库文件目录
配置好以后就可以进行编写代码了。
利用opencv的VideoCapture类中的open函数打开摄像头,我这边由于打开的是电脑的摄像头,所以直接使用下标0。
然后这边使用c++的异常机制,try-catch函数,当出现打开摄像头异常的时候,直接抛出错误,如果没有这么处理的话,打开摄像头失败还进行读帧的话程序会卡掉。
然后利用opencv中的grab函数读取视频帧并进行解码,再利用retrieve函数将读取到yuv格式转化rgb格式。
然后就可以利用opencv的nameWindow创建一个窗口,然后利用imshow将读取的视频帧显示出来。
由于将视频帧推流到服务器上需要.h264的视频,所以需要将rgb格式的图片转化成yuv格式的才可以进行编码,这时候就需要用到ffmpeg的sws_getCachedContext()函数进行转化,该函数的参数如下所示。
struct SwsContext *context,
int srcW, int srcH, 原宽高
enum AVPixelFormat srcFormat,原像素格式
int dstW, int dstH, 目标宽高
enum AVPixelFormat dstFormat,目标格式
int flags, 算法标签(性能差异 效果差异 针对尺寸变化)
SwsFilter *srcFilter,过滤器
SwsFilter *dstFilter,过滤器
const double *param 算法中默认值的设定 可以默认);
两个函数的差别是第一个参数:SwsContext
sws_getContext 会创建一个上下文空间,sws_getCachedContext会去缓冲中找,前后两次参数没变时返回同一个。
这次只是分享如何初始化像素格式上下文,下面是具体代码的分享。
#include <opencv2/highgui.hpp>
#include <iostream>
extern "C"
{
#include <libswscale/swscale.h>
}
using namespace std;
using namespace cv;
#pragma comment(lib,"opencv_world320.lib")
#pragma comment(lib,"swscale.lib")
int main(int argc,char *argv[])
{
//nginx-rtmp 直播服务器rtmp推流URL
char *outUrl = "rtmp://192.168.198.128/live";
VideoCapture cam;
Mat frame;
namedWindow("video");
//像素格式转换上下文
SwsContext *vsc = NULL;
try
{
//使用opencv打开本地相机
cam.open(0);
///1.打开摄像头
if (!cam.isOpened())
{
throw exception("cam open failed!");
}
cout << "cam open success" << endl;
int inWidth = cam.get(CAP_PROP_FRAME_WIDTH);
int inHeight = cam.get(CAP_PROP_FRAME_HEIGHT);
///2 初始化格式转换上下文
vsc = sws_getCachedContext(vsc,
//源宽、高、像素格式
inWidth,inHeight, AV_PIX_FMT_BGR24,
//目标宽、高、像素格式
inWidth, inHeight,AV_PIX_FMT_YUV420P,
SWS_BICUBIC, //尺寸变化使用的算法
0,0,0
);
if (!vsc)
{
throw exception("sws_getCachedContext failed!");
}
//读取帧
for (;;)
{
//只做解码,读取视频帧,解码视频帧
if (!cam.grab())
{
continue;
}
//yuv转化为rgb
if (!cam.retrieve(frame))
{
continue;
}
imshow("video", frame);
waitKey(1);
//rgb to yuv
//h264编码
//推流
}
}
catch (exception &ex)
{
if (cam.isOpened())
cam.release();
if (vsc)
{
sws_freeContext(vsc);
vsc = NULL;
}
cerr << ex.what() << endl;
}
getchar();
return 0;
}