如何使用OpenCV+MMPEAG打开摄像头,显示的同时推送RTMP流。
1、 char* outUrl = "rtmp://localhost/live/livestream";
这个地址,是AMS(Adeobe Media Server)的默认地址。
2、
//注册所有的编解码器
avcodec_register_all();
//注册所有的封装器
av_register_all();
//注册所有网络协议
avformat_network_init();
//打开摄像头
VideoCapture cam;
namedWindow("video");
Mat frame; //像素格式转换上下文
SwsContext* vsc = NULL;
//输出的数据结构
AVFrame* yuv = NULL;
//编码器上下文
AVCodecContext* vc = NULL;
//rtmp flv 封装器
AVFormatContext* ic = NULL;
声明好多变量,是OpenCV & MMPEAG 正常运行所需要的。
3、
try {
/// 1. Open Cam
// 这里默认打开的是摄像头0,并获得摄像头参数
cam.open(0);
if (!cam.isOpened()) {
throw exception("cam open failed");
}
cout << "cam open sucess"<< endl; int inWidth = cam.get(CAP_PROP_FRAME_WIDTH);
int inHeight = cam.get(CAP_PROP_FRAME_HEIGHT);
int fps = cam.get(CAP_PROP_FPS);
if (fps == 0) {
fps = 25;
}
cout << fps<< endl; /// 2. 初始化 SwsContext(转换格式上下文)
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");
} ///3.初始化输出的数据结构
yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P;
yuv->width = inWidth;
yuv->height = inHeight;
yuv->pts = 0;
//分配 YUV 空间
int ret = av_frame_get_buffer(yuv, 32);
if (ret != 0) {
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
} ///4. 初始化编码器上下文
//a. 找到编码器,这里全部基于MMPEAG
AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec) {
throw exception("Can't find H.264 encoder");
}
//b. 创建编码器上下文
vc = avcodec_alloc_context3(codec);
if (!vc) {
throw exception("avcodec_alloc_context3 failed");
}
//c. 配置编码器参数
vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
vc->codec_id = codec->id;
vc->thread_count = 8;
vc->bit_rate = 50 * 1024 * 8; //video size(bits) per second: 50kByte
vc->width = inWidth;
vc->height = inHeight; vc->time_base = { 1,fps };//used to calculate pts: pts*time_base = second
vc->framerate = { fps,1 }; vc->gop_size = 50;// for how many frames there is a I frame(关键帧)
vc->max_b_frames = 0;//if these is no B frames, the orders of both decoding and presentation will be the same
vc->pix_fmt = AV_PIX_FMT_YUV420P; //d. 打开编码器上下文(Open encodder context)
ret = avcodec_open2(vc, 0, 0);
if (ret != 0) {
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
}
cout << "avcodec_open2 successed!"<< endl; ///5. 输出封装器和频流配置
//a. Create context for MUX
ret = avformat_alloc_output_context2(&ic, 0, "flv", outUrl);
if (ret != 0) {
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
}
//b. Add video stream
AVStream* vs = avformat_new_stream(ic, NULL);
if (!vs) {
throw exception("avformat_new_stream failed");
}
vs->codecpar->codec_tag = 0;
// copy parameter from Encoder to MUX
avcodec_parameters_from_context(vs->codecpar, vc);
av_dump_format(ic, 0, outUrl, 1); ///6. Open rtmp output IO(打开输出IO)
ret = avio_open(&ic->pb, outUrl, AVIO_FLAG_WRITE);
if (ret != 0) {
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
}
//write mux header
ret = avformat_write_header(ic, NULL); // after this operation the stream's time_base will also be changed, not vc->time_base anymore
if (ret != 0) {
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
} AVPacket pack;
memset(&pack, 0, sizeof(pack));
int vpts = 0; //住循环,读入->显示->转码
for (;;) {
///从cam中读取书
if (!cam.grab()) {
continue;
}
if (!cam.retrieve(frame)) {
continue;
}
imshow("video", frame);
waitKey(1); /// convert RGB to YUV
// Input data structure--RGB
uint8_t* indata[AV_NUM_DATA_POINTERS] = { 0 };//srcStride
indata[0] = frame.data;
int inlinesize[AV_NUM_DATA_POINTERS] = { 0 };//srcSlice
//一行(宽)数据的字节数
inlinesize[0] = frame.cols * frame.elemSize(); int h = sws_scale(vsc, indata, inlinesize, 0, frame.rows,
yuv->data, yuv->linesize);
if (h <= 0) {
continue;
} ///Mux YUV to flv h.264
yuv->pts = vpts;
vpts++;
ret = avcodec_send_frame(vc, yuv);
if (ret != 0) {
continue;
}
ret = avcodec_receive_packet(vc, &pack);
if (ret != 0 || pack.size > 0) {
cout << '*' <<pack.size<< flush;
}
else {
continue;
} ///推流
pack.pts = av_rescale_q(pack.pts, vc->time_base, vs->time_base);
pack.dts = av_rescale_q(pack.dts, vc->time_base, vs->time_base);
ret = av_interleaved_write_frame(ic, &pack);
if (ret == 0) {
cout << '#'<< flush;
} }
}
catch (exception &ex) { if (cam.isOpened())
cam.release();
if (vsc) {
sws_freeContext(vsc);
vsc = NULL;
}
if (vc) {
avio_closep(&ic->pb);
avcodec_free_context(&vc);
}
cerr << ex.what() << endl;
}
getchar();
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <iostream>
#include "XMediaEncode.h"
#include "XRtmp.h"
extern "C"
{
#include <libswscale/swscale.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
}
using namespace cv;
using namespace std; //初始化像素格式上下文
void test004()
{
//相机的rtsp url
char *inUrl = "rtsp://admin:@192.168.10.30:554/ch0_0.264";
VideoCapture cam;
namedWindow("video"); //像素格式转换上下文
SwsContext *vsc = NULL; try
{
////////////////////////////////////////////////////////////////
/// 1 使用opencv打开rtsp相机
cam.open(inUrl);
if (!cam.isOpened())
{
throw exception("cam open failed!");
}
cout << inUrl << " cam open success" << endl;
int inWidth = (int)cam.get(CAP_PROP_FRAME_WIDTH);
int inHeight = (int)cam.get(CAP_PROP_FRAME_HEIGHT);
int fps = (int)cam.get(CAP_PROP_FPS); ///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!");
}
Mat frame;
for (;;)
{
///读取rtsp视频帧,解码视频帧
if (!cam.grab())
{
continue;
}
///yuv转换为rgb
if (!cam.retrieve(frame))
{
continue;
}
imshow("video", frame);
waitKey(1);
}
}
catch (exception &ex)
{
if (cam.isOpened())
cam.release();
if (vsc)
{
sws_freeContext(vsc);
vsc = NULL;
}
cerr << ex.what() << endl;
}
getchar();
} //rtsp数据源到rtmp推流 要重点复习
void test005()
{
cout << "void test005()!" << endl;
//相机的rtsp url
char *inUrl = "rtsp://admin:@192.168.10.30:554/ch0_0.264";
//nginx-rtmp 直播服务器rtmp推流URL
char *outUrl = "rtmp://192.168.10.181/live"; //注册所有的编解码器
avcodec_register_all(); //注册所有的封装器
av_register_all(); //注册所有网络协议
avformat_network_init(); VideoCapture cam;
Mat frame;
namedWindow("video"); //像素格式转换上下文
SwsContext *vsc = NULL; //输出的数据结构
AVFrame *yuv = NULL; //编码器上下文
AVCodecContext *vc = NULL; //rtmp flv 封装器
AVFormatContext *ic = NULL; try
{ ////////////////////////////////////////////////////////////////
/// 1 使用opencv打开rtsp相机
cam.open(inUrl);
if (!cam.isOpened())
{
throw exception("cam open failed!");
}
cout << inUrl << " cam open success" << endl;
int inWidth = (int)cam.get(CAP_PROP_FRAME_WIDTH);
int inHeight = (int)cam.get(CAP_PROP_FRAME_HEIGHT);
int fps = (int)cam.get(CAP_PROP_FPS); ///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!");
} ///3 初始化输出的数据结构
yuv = av_frame_alloc();
yuv->format = AV_PIX_FMT_YUV420P;
yuv->width = inWidth;
yuv->height = inHeight;
yuv->pts = 0;
//分配yuv空间
int ret = av_frame_get_buffer(yuv, 32);
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
} ///4 初始化编码上下文,分为以下三步
//a 找到编码器
AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_H264);
if (!codec)
{
throw exception("Can`t find h264 encoder!");
}
//b 创建编码器上下文
vc = avcodec_alloc_context3(codec);
if (!vc)
{
throw exception("avcodec_alloc_context3 failed!");
}
//c 配置编码器参数
vc->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; //全局参数
vc->codec_id = codec->id;
vc->thread_count = 8; vc->bit_rate = 50 * 1024 * 8;//压缩后每秒视频的bit位大小 50kB
vc->width = inWidth;
vc->height = inHeight;
vc->time_base = { 1,fps };
vc->framerate = { fps,1 }; //画面组的大小,多少帧一个关键帧
vc->gop_size = 50;
vc->max_b_frames = 0;
vc->pix_fmt = AV_PIX_FMT_YUV420P;
//d 打开编码器上下文
ret = avcodec_open2(vc, 0, 0); if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
}
cout << "avcodec_open2 success!" << endl; ///5 输出封装器和视频流配置
//a 创建输出封装器上下文
ret = avformat_alloc_output_context2(&ic, 0, "flv", outUrl);
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
} //b 添加视频流
AVStream *vs = avformat_new_stream(ic, NULL);
if (!vs)
{
throw exception("avformat_new_stream failed");
}
vs->codecpar->codec_tag = 0;
//从编码器复制参数
avcodec_parameters_from_context(vs->codecpar, vc);
av_dump_format(ic, 0, outUrl, 1); ///打开rtmp 的网络输出IO
ret = avio_open(&ic->pb, outUrl, AVIO_FLAG_WRITE);
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
} //写入封装头
ret = avformat_write_header(ic, NULL);
if (ret != 0)
{
char buf[1024] = { 0 };
av_strerror(ret, buf, sizeof(buf) - 1);
throw exception(buf);
} AVPacket pack;
memset(&pack, 0, sizeof(pack));
int vpts = 0; //死循环
for (;;)
{
///读取rtsp视频帧,解码视频帧
if (!cam.grab())
{
continue;
}
///yuv转换为rgb
if (!cam.retrieve(frame))
{
continue;
}
imshow("video", frame);
waitKey(1); ///rgb to yuv
//输入的数据结构
uint8_t *indata[AV_NUM_DATA_POINTERS] = { 0 };
//indata[0] bgrbgrbgr
//plane indata[0] bbbbb indata[1]ggggg indata[2]rrrrr
indata[0] = frame.data;
int insize[AV_NUM_DATA_POINTERS] = { 0 };
//一行(宽)数据的字节数
insize[0] = frame.cols * frame.elemSize();
int h = sws_scale(vsc, indata, insize, 0, frame.rows, //源数据
yuv->data, yuv->linesize);
if (h <= 0)
{
continue;
}
cout << h << " " << flush; ///h264编码
yuv->pts = vpts;
vpts++;
ret = avcodec_send_frame(vc, yuv);
if (ret != 0)
continue; ret = avcodec_receive_packet(vc, &pack);
if (ret != 0 || pack.size > 0)
{
cout << "*" << pack.size << flush;
}
else
{
continue;
}
//推流
pack.pts = av_rescale_q(pack.pts, vc->time_base, vs->time_base);
pack.dts = av_rescale_q(pack.dts, vc->time_base, vs->time_base);
pack.duration = av_rescale_q(pack.duration, vc->time_base, vs->time_base);
ret = av_interleaved_write_frame(ic, &pack);
if (ret == 0)
{
cout << "#" << flush;
}
} }
catch (exception &ex)
{
if (cam.isOpened())
cam.release();
if (vsc)
{
sws_freeContext(vsc);
vsc = NULL;
} if (vc)
{
avio_closep(&ic->pb);
avcodec_free_context(&vc);
} cerr << ex.what() << endl;
}
getchar();
} //opencv_rtsp_to_rtmp_class封装重构代码 要重点复习
void test006()
{
cout << "void test006()!" << endl;
//相机的rtsp url
char *inUrl = "rtsp://admin:@192.168.10.30:554/ch0_0.264";
//nginx-rtmp 直播服务器rtmp推流URL
char *outUrl = "rtmp://192.168.10.181/live"; //编码器和像素格式转换
XMediaEncode *me = XMediaEncode::Get(0); //封装和推流对象
XRtmp *xr = XRtmp::Get(0); VideoCapture cam;
Mat frame;
namedWindow("video"); int ret = 0;
try
{ ////////////////////////////////////////////////////////////////
/// 1 使用opencv打开rtsp相机
cam.open(inUrl);
if (!cam.isOpened())
{
throw exception("cam open failed!");
}
cout << inUrl << " cam open success" << endl;
int inWidth = (int)cam.get(CAP_PROP_FRAME_WIDTH);
int inHeight = (int)cam.get(CAP_PROP_FRAME_HEIGHT);
int fps = (int)cam.get(CAP_PROP_FPS); ///2 初始化格式转换上下文
///3 初始化输出的数据结构
me->inWidth = inWidth;
me->inHeight = inHeight;
me->outWidth = inWidth;
me->outHeight = inHeight;
me->InitScale(); ///4 初始化编码上下文
//a 找到编码器
if (!me->InitVideoCodec())
{
throw exception("InitVideoCodec failed!");
} ///5 输出封装器和视频流配置
xr->Init(outUrl); //添加视频流
xr->AddStream(me->vc);
xr->SendHead(); for (;;)
{
///读取rtsp视频帧,解码视频帧
if (!cam.grab())
{
continue;
}
///yuv转换为rgb
if (!cam.retrieve(frame))
{
continue;
}
//imshow("video", frame);
//waitKey(1); ///rgb to yuv
me->inPixSize = frame.elemSize();
AVFrame *yuv = me->RGBToYUV((char*)frame.data);
if (!yuv) continue; ///h264编码
AVPacket *pack = me->EncodeVideo(yuv);
if (!pack) continue; xr->SendFrame(pack); } }
catch (exception &ex)
{
if (cam.isOpened())
cam.release();
cerr << ex.what() << endl;
}
getchar();
} int main(int argc, char *argv[])
{
//test000();
//test001();
//test002();
//test003();
//test004();
//test005();
test006();
return 0;
}
https://files.cnblogs.com/files/blogs/758212/opencv_rtsp2rtmp-master.rar
https://files.cnblogs.com/files/blogs/758212/main.js
如何使用OpenCV+MMPEAG打开摄像头,显示的同时推送RTMP流。的更多相关文章
- iOS8自定义推送显示按钮及推送优化
http://www.jianshu.com/p/803bfaae989e iOS8自定义推送显示按钮及推送优化 字数1435 阅读473 评论0 喜欢2 导语 在iOS8中,推送消息不再只是简单地点 ...
- JavaCV 采集摄像头和麦克风数据推送到流媒体服务器
越来越觉得放弃JavaCV FFmpeg native API,直接使用JavaCV二次封装的API开发是很明智的选择,使用JavaCV二次封装的API开发避免了各种内存操作不当引起的crash. 上 ...
- opencv学习---打开摄像头检测个人头像
opencv中具有检测人体各部分的级联分类器,在opencv文件夹里面的sources/data/haarcascades里面. 这里要选择的是能够检测人体头像的还有检测眼睛的级联分类器的文件. 它们 ...
- 基于OpenCV 的美颜相机推送直播流
程序流程: 1.图像采集 先从opencv(2.4.10版本)采集回来摄像头的图像,是一帧一帧的 每一帧图像是一个矩阵,opencv中的mat 数据结构. 2.人脸的美化 人脸美化,我们用的皮肤检测, ...
- Android实现点击通知栏后,先启动应用再打开目标Activity ,极光推送等推送的也可以参考一下(转)
我因为项目中集成了极光推送,推送的通知栏点开需要确定进入哪个界面就参考了这边文章,感谢作者的无私. 标签: 情况简述 在开发Android app的过程中,遇到这样一个需求:app中启动一个Servi ...
- C# ASP.NET MVC 之 SignalR 学习 实时数据推送显示 配合 Echarts 推送实时图表
本文主要是我在刚开始学习 SignalR 的技术总结,网上找的学习方法和例子大多只是翻译了官方给的一个例子,并没有给出其他一些经典情况的示例,所以才有了本文总结,我在实现推送简单的数据后,就想到了如何 ...
- uniapp云打包之后华为手机推送角标不显示(有推送没角标)
小米手机上有角标,华为和OPPO没有角标 解决方法: 华为手机添加权限(可通过反编译或者离线打包添加) < uses - permission android:name="com.hu ...
- 如何使用 OpenCV 打开摄像头获取图像数据?
OpenCV 如何打开摄像头获取图像数据? 代码运行环境:Qt 5.9.1 msvc2015 32bit OpenCV 3.3.0 #include "include/opencv2/ope ...
- EasyPusher进行Android UVC外接摄像头直播推送实现方法
最近EasyPusher针对UVC摄像头做了适配.我们结合了UVCCamera与EasyPusher,支持将UVC摄像头的视频推送到RTSP服务器上.在此特别感谢UVCCamera这个牛逼的项目! 来 ...
- OpenCV Open Camera 打开摄像头
这是一个用OpenCV2.4.10打开摄像头的一个例子,参见代码如下: #include <iostream> #include <stdio.h> #include < ...
随机推荐
- 【前端必会】tapable、hook,webpack的灵魂
背景 什么是tapable.hook,平时做vue开发时的webpack 配置一直都没弄懂,你也有这种情况吗? 还是看源码,闲来无聊又看一下webpack的源码,看看能否找到一些宝藏 tapable和 ...
- 220403 考试爆炸记 (T1T2)
T1 最大约数和 先放一下我考时的代码.(没想到能A过洛谷的数据,可能是洛谷的数据有点弱) #include<bits/stdc++.h> using namespace std; int ...
- How to get the return value of the setTimeout inner function in js All In One
How to get the return value of the setTimeout inner function in js All In One 在 js 中如何获取 setTimeout ...
- eDP接口简介
1. eDP背景介绍 随着显示分辨率的越来越高,传统的VGA.DVI等接口逐渐不能满足人们的视觉需求. 随后就产生了以HDMI.DisplayPort为代表的新型数字接口,外部接口方面HDMI占据 ...
- 2.签名&初始化&提交
Git设置签名 签名的作用是区分不同操作者的身份,用户的签名信息在每一个版本的提交信息中能够看到, 以此确认本次提交是谁做的,git首次安装必须设置用户签名,否则无法提交代码 这里设置的用户签名和 ...
- AIR32F103(四) 27倍频216MHz,CoreMark跑分测试
目录 AIR32F103(一) 合宙AIR32F103CBT6开发板上手报告 AIR32F103(二) Linux环境和LibOpenCM3项目模板 AIR32F103(三) Linux环境基于标准外 ...
- Mysql InnoDB Buffer Pool
参考书籍<mysql是怎样运行的> 系列文章目录和关于我 一丶为什么需要Buffer Pool 对于InnoDB存储引擎的表来说,无论是用于存储用户数据的索引,还是各种系统数据,都是以页的 ...
- redux中间件
Redux 中间件 什么是中间件? 中间件本质上就是一个函数,Redux允许我们通过中间件的方式,扩展和增强Redux应用程序,增强体现在对action处理能力上,之前的计数器与弹出框案例中.acti ...
- git 进阶篇
在git使用时,有时需要在公司内部搭建自己的git服务器,用于内部的版本控制. 从远程服务器到本地 先创建服务器端的空git库,将其clone到本地,再将本地的修改push到服务器端 # step1: ...
- 从0到1搭建redis6.0.7续更~
"心有所向,日复一日,必有精进" 前言: 想必大家看完我之前写的搭建redis服务器,大家都已经把redis搭建起来了吧如果没有搭建起来的小可爱请移步这里哦从0到1搭建redis6 ...