完整的推流代码已经托管到个人的Gitee,如有需要请自取

https://gitee.com/MonsterAKALei/push_video.git


ffmpeg推流摄像头数据

昨天实现用API分别实现了读取摄像头数据并保存将本地文件推流到公网两个功能,所以想着是否可以将这两个功能合并一下,读取摄像头数据后不保存而直接推流到公网

FFmpeg采集摄像头图像并推流(RTSP/RTMP)—开发总结

我的一篇博文《如何用FFmpeg API采集摄像头视频和麦克风音频。。。》已经介绍了如何从视音频采集设备获取数据,并且编码、保存文件到本地。但是,**有些应用并不是把流保存成文件,而是需要发送到网络**的,比如现在很典型的一种应用场景:把流推送到RTSP、RTMP、HLS服务器,由服务器转发给其他用户观看。很多开发者也是调用FFmpeg API来实现推流的,用FFmpeg 做一个推流器很简单,调用流程跟输出文件的基本相同,基于前面博文的例子稍微修改就可以做出一个采集+编码+推流的软件。这里,我先假设读者已经会用FFmpeg API保存或录制文件,但没有实现过推流功能,我将给大家说一下做推流跟录制文件的区别,还有说一下要注意的几个问题,希望能帮助大家在开发推流功能时减少一些问题的出现

上面这个博客里提到了我目前的需求,如红字突出部分,但是其内容讲的是如何将已有文件推流到公网,还是有区别的

注意到对于RTMPAVOutputFormatflv,这对后面的操作有很大的影响

我先将昨天的两个cpp文件做了简单的拼接

transmit_test.cpp

#include <iostream>
#include <string>extern "C"
{#include "libavformat/avformat.h"
#include "libavutil/time.h"
#include "libavutil/avutil.h"
#include "libavdevice/avdevice.h"
#include "libavcodec/avcodec.h"
}using namespace std;#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avdevic.lib")int ff_Error(int errNum)
{char buf[1024] = {0};av_strerror(errNum, buf, sizeof(buf));cout << buf << endl;return -1;
}static AVFormatContext *open_dev(const string &devicename)
{int ret = 0;// ctxAVFormatContext *ictx = NULL;AVDictionary *options = NULL;// register audio deviceavdevice_register_all();// get formatAVInputFormat *iformat = av_find_input_format("video4linux2");av_dict_set(&options, "video_size", "640x480", 0);av_dict_set(&options, "framerate", "30", 0);av_dict_set(&options, "pixel_format", "yuyv422", 0);// open deviceif ((ret = avformat_open_input(&ictx, devicename.data(), iformat, &options)) < 0){ff_Error(ret);}else{cout << "相机打开成功!" << endl;}return ictx;
}int main(int argc, char *argv[])
{string outUrl = "rtmp://centos:7788/videotest";av_register_all();//初始化网络库avformat_network_init();AVFormatContext *ictx = NULL;int ret = 0;string devicename = "/dev/video2";//打开设备ictx = open_dev(devicename);ret = avformat_find_stream_info(ictx, 0);if (ret != 0){return ff_Error(ret);}cout << "打印输入流信息:" << endl;av_dump_format(ictx, 0, devicename.data(), 0);//输出流//创建输出流上下文AVFormatContext *octx = NULL;ret = avformat_alloc_output_context2(&octx, 0, "flv", outUrl.data());if (!octx){return ff_Error(ret);}cout << "输出上下文创建成功" << endl;//配置输出流// 遍历输入的AVStreamcout << "ictx->nb_streams:" << ictx->nb_streams << endl;for (int i = 0; i < ictx->nb_streams; i++){//创建输出流AVStream *out = avformat_new_stream(octx, ictx->streams[i]->codec->codec);if (!out){return ff_Error(0);}//复制配置信息ret = avcodec_parameters_copy(out->codecpar, ictx->streams[i]->codecpar);out->codec->codec_tag = 0;}cout << "打印输出流信息:" << endl;av_dump_format(octx, 0, outUrl.data(), 1);// rtmp推流//打开iocout << "准备RTMP推流..." << endl;ret = avio_open(&octx->pb, outUrl.data(), AVIO_FLAG_WRITE);if (!octx->pb){cout << "准备推流失败!" << endl;return ff_Error(ret);}//写入头信息ret = avformat_write_header(octx, 0);if (ret < 0){cout << "写入头信息失败!" << endl;return ff_Error(ret);}// packetAVPacket pkt;while (true){cout << "开始RTMP推流..." << endl;ret = av_read_frame(ictx, &pkt);if (ret != 0){return ff_Error(ret);break;}//推送帧数据ret = av_interleaved_write_frame(octx, &pkt);if (ret < 0){return ff_Error(ret);}}cout << "rtmp 推流结束" << endl;return 0;
}

运行输出如下信息

redwall@redwall-G3-3500:~/Test/video_transmit/bin$ ./transmit_test
相机打开成功!
打印输入流信息:
Input #0, video4linux2,v4l2, from '/dev/video2':Duration: N/A, start: 21117.813711, bitrate: 147456 kb/sStream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 640x480, 147456 kb/s, 30 fps, 30 tbr, 1000k tbn, 1000k tbc
输出上下文创建成功
ictx->nb_streams:1
打印输出流信息:
Output #0, flv, to 'rtmp://centos:7788/videotest':Stream #0:0: Video: rawvideo (YUY2 / 0x32595559), yuyv422, 640x480, q=2-31, 147456 kb/s
准备RTMP推流...
[flv @ 0x5603fbb236c0] Video codec rawvideo not compatible with flv
写入头信息失败!
Function not implemented

提示Video codec rawvideo not compatible with flv,也就是视频编解码器rawvideo不兼容flv ,于是我又去查了yuy2 以及flv是什么

谈谈RGB、YUY2、YUYV、YVYU、UYVY、AYUV

常用视频像素格式NV12、NV21、I420、YV12、YUYV

音视频基础:FLV封装格式介绍及解析

  • 像素格式描述了像素数据存储所用的格式,定义了像素在内存中的编码方式,RGB和YUV是两种经常使用的像素格式
  • RGB:较为熟悉,具有3个通道R G B,分别对应红 绿 蓝三个分量,由三个分量的值决定颜色;通常,会给RGB图像加一个通道alpha,即透明度,于是共有四个分量共同控制颜色(常用的opencv库默认将图片以BGR的方式进行存储,只是通道顺序不一样而已)
  • YUV:(YCrCb)是指将亮度参量Y和色度参量U/V分开表示的像素格式,主要用于优化彩色视频信号的传输
  • YUV像素格式来源于RGB像素格式,通过公式运算,YUV三分量可以还原出RGB
  • FLV(Flash Video)是Adobe公司推出的一种流媒体格式,由于其封装后的音视频文件体积小、封装简单等特点,非常适合于互联网上使用。目前主流的视频网站基本都支持FLV。采用FLV格式封装的文件后缀为.flv

所以报错就很正常了,一种是像素格式一种是流媒体格式,怎么可能读出来就直接推流呢

查看ffmpeg支持的所有视频或音频文件类型

ffmpeg所支持的所有视频或音频文件类型

ffmpeg -formatsredwall@redwall-G3-3500:~$ ffmpeg -formats|grep yu
ffmpeg version 3.4.11-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developersD  pgmyuv_pipe     piped pgmyuv sequenceDE yuv4mpegpipe    YUV4MPEG piperedwall@redwall-G3-3500:~$ ffmpeg -formats|grep h264
ffmpeg version 3.4.11-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developersDE h264            raw H.264 videoredwall@redwall-G3-3500:~$ ffmpeg -formats|grep flv
ffmpeg version 3.4.11-0ubuntu0.1 Copyright (c) 2000-2022 the FFmpeg developersDE flv             FLV (Flash Video)

可以看到yuv4、h264、flv都是不同的编码格式,所以我就想能不能解决codec not compatible的问题

linux下使用ffmpeg采集摄像头数据并编码成h264文件

上面的博客确实做到了将原始摄像头yuyv422格式的数据转换为h264格式的数据并写入文件,但存在两个问题:

1、仅写入文件,但并未实现推流

2、h264格式的数据适用于RTSP,并不适用于RTMP,这一点是从下面的博客发现的

FFmpeg4入门27:捕获摄像头编码h264并推流

我下载并阅读了文中的代码,确实是推流到RTSP服务

//编码器部分开始/
const char *outFile = "rtsp://192.168.1.31/test"; //输出URL
const char *ofmtName = "rtsp";                    //输出格式;if (avformat_alloc_output_context2(&outFmtCtx, NULL, ofmtName, outFile) < 0)
{printf("Cannot alloc output file context.\n");return -1;
}
outFmt = outFmtCtx->oformat;

所以没办法拿来稍微改改就能用,但还是有借鉴意义的,我看有300行代码和好多陌生的API,就没花时间去研究,后面看看有需要还是得研究下

关于ffmpeg的结构体API,可以看网上的一些博客,也可以直接看官方文档,官方的比较简略,学习起来还是有一定的时间成本的

ffmpeg重要函数和结构体整理

ffmpeg官方文档


但是下面的博客又给了我一些新的思路

linux FFMPEG 摄像头采集数据推流

博客中使用ffmpeg命令进行本地摄像头的推流,而拉流则是通过ffmpeg的API函数编程实现的

然后我去看陆辉东robot_remote_control中的imagetransfer代码,发现也是只有拉流的实现

void ImgTrancefer::transImg(){av_register_all();avformat_network_init();iCtx = avformat_alloc_context();int ret;ret = avformat_open_input(&iCtx, rtmp_url.data(), NULL, NULL);if(ret != 0){emit TransIMGLog(QString("open input faild!"));qDebug() << "open input faild!";return;}if(avformat_find_stream_info(iCtx, NULL) < 0){emit TransIMGLog(QString("find stream faild!"));qDebug() << "find stream faild!";return;}for(int i =0;i < iCtx->nb_streams;i++){if(iCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO){videoStream = i;break;}}

后面则是一些解码和转码输出的内容,所以是不是只要有拉流输出的代码实现就可以呢,这是个问题


中午吃饭的时候问了陆辉东,说是推流也是通过API实现,但在车上

是我自己的疏忽,应该想到推流代码应该在车上才对,还是要多思考

推流的代码在redwallbot-2中的transfer_img包中,确实给我提供了一些思路,最重要的是打破了我的认知误区,H264格式也可以进行RTMP推流

产生这样的认知误区主要还是因为自己盲目自信以及过于相信网络博客中的内容,其实随便检索一下

第一条就说明RTMP可以推H264格式,所以要时刻保持怀疑的态度,对不熟悉的事物要多查多看

陆辉东代码里是订阅摄像头话题,转OpenCV图像格式,然后再编码为H264,最后封装为FLV进行RTMP推流,最重要的有3步

  1. 获取摄像头数据,转换为OpenCV图像格式(BGR/BGRA)
  2. 通过ffmpeg编码器将OpenCV图像格式编码为H264格式
  3. 将H264格式封装为FLV格式进行RTMP推流

其实弄清了分为几个步骤,分别去查相应的解决方法,逐个击破即可

第一步最简单,几乎不用什么新知识,几个参考博客

cv_bridge用于ROS图像和OpenCV图像的转换

第二步也有一些博客,但比较杂,用C++实现的不多,还没有深入研究

OpenCV采集的视频流转化成H264格式裸码流

cv::Mat编码H264

第三步涉及到对H264、FLV等格式的解析,难度较大,代码上也少有较清晰的实现

RTMP 两种方式推流:推H.264、ACC和推FLV封装格式

RTMP推流H.264

H264 推流到RTMP服务器

但是踏破铁鞋无觅处,这样一篇博客从天而降

流媒体解码及H.264编码推流



有一说一真的顶,简直量身定制,我看时间是17年的博客,陆辉东的代码感觉就是在他的基础上改为类实现而已,我再简单优化一下即可


完整的推流代码已经托管到个人的Gitee,如有需要请自取

https://gitee.com/MonsterAKALei/push_video.git

ffmpeg推流摄像头数据至公网服务器相关推荐

  1. 海思A182-Hi3516DV300推流摄像头数据

    思A182-Hi3516DV300推流摄像头数据 如果已经按照上一篇文章移植成功了opendump说明你已经成功了一大半,但是下面的一半也不是随随便便成功的,在你想要把librtmp库移植到你的开发板 ...

  2. 6. 毕业设计温湿度监控系统(ESP8266 + DHT11 +OLED 实时上传温湿度数据给公网服务器并在OLED显示屏上显示实时温湿度)

    文章目录 硬件环境 软件环境 1. WiFi联网和HttpPost配置 2. DHT11温湿度读取和OLED显示配置 3. Web服务器配置(用于接收HTTP数据请求) 实验过程 1. ESP8266 ...

  3. linux下使用ffmpeg采集摄像头数据并编码成h264文件

    本文讲述如何在linux下,使用ffmpeg采集视频数据,并编码成h264文件. 打算分成3部分讲解: 需要具备的软硬件环境 ffmpeg命令采集摄像头数据并编码成h264文件 ffmpeg代码采集摄 ...

  4. sdl2和ffmpeg显示摄像头数据

    当我们按下空格键的时候,视频可以暂停. ffmpeg 封装摄像头 extern "C" {#include <libavcodec/avcodec.h> #includ ...

  5. Gstreamer推送摄像头数据到RTMP服务器的方法(SRS成功示例)

    最近在研究如何将Linux中的视频数据推送到流媒体服务器,看到gstreamer还比较不错,于是试了一下 服务端用的SRS,RTMP推流,搭建非常简单,教程可参考:https://blog.csdn. ...

  6. ffmpeg 采集摄像头yuv数据

    本文讲述在linux下,如何使用ffmpeg采集摄像头yuv数据,并保存为文件. 分为4个部分进行讲解 需要的软硬件环境 使用ffmpeg命令采集yuv数据. 使用ffmpeg代码采集yuv数据. 查 ...

  7. Android 音视频深入 十六 FFmpeg 推流手机摄像头,实现直播 (附源码下载)

    源码地址 https://github.com/979451341/RtmpCamera/tree/master 配置RMTP服务器,虽然之前说了,这里就直接粘贴过来吧 1.配置RTMP服务器 这个我 ...

  8. ffmpeg推流时与服务器断开后的自动重连功能的实现

    当我们使用ffmpeg进行视频推流的时候,流媒体服务器与推流终端一直连接的时候,推流是成功的,但是如果服务器重启,就会出现推流一直失败的问题,av_interleaved_write_frame返回值 ...

  9. 手把手教你搭建Nginx-rtmp流媒体服务器+使用ffmpeg推流

    手把手教你搭建Nginx-rtmp流媒体服务器+使用ffmpeg推流 转载自:https://www.jianshu.com/p/06c2025edcd3 by – paperfish 最近尝试着搭建 ...

最新文章

  1. 关于智能车竞赛,你需要知道什么?
  2. rabbitmq的基本使用
  3. MessagePack 学习笔记
  4. html5列表标签代码,HTML5列表标签和表格标签(示例代码)
  5. 我的嵌入式开发之路(.Net Micro Framework)
  6. 球球大作战测试服android版,球球大作战10.0体验服
  7. 研讨会 | 知识工程与问答技术研讨会 (KEQA2018)
  8. DOMJavaScript示例练习
  9. Odoo12中删除无效项目
  10. javascript中new url()属性,轻松解析url地址
  11. 页面滚动图片等元素动态加载实现本质
  12. C# 全局唯一标识符 (GUID)
  13. FISCO BCOS(十二)——— 区块链关键概念
  14. Python学习笔记之 高级变量类型 列表,元组,字典,字符串的相关常用 操作
  15. 微信红包惊人秘密:谁最容易抢到大红包?
  16. 伦敦艺术大学创意计算机学院,伦敦艺术大学专业详细设置
  17. 【Watir Webdriver】自动化上传照片到百度相册
  18. Guitar Pro教程之记谱法简介
  19. ios动态效果实现翻页_iOS实现翻页效果动画
  20. Windows系统近年漏洞概况及攻击教程防御

热门文章

  1. django的优缺点
  2. xxl-job任务调度中心
  3. 基于小波Elman神经网络的短期风电功率预测
  4. 485通信原理_上位机开发之单片机通信实践(一)
  5. sanic教程-开始
  6. 为什么您的WordPress网站会容易被黑客攻击
  7. 大学计算机专业论文提纲范文,毕业论文提纲范文
  8. 电脑无限重启 服务器,Windows10系统开机提示无法连接到sens服务无限重启如何解决...
  9. 马云像火,马化腾像水:8000字深度拆解互联网二马的不同人生
  10. web前端性能优化指南