FFMPEG通过管道将图片推送流媒体

2023-05-16

         最近遇到个需求,将私有协议的码流,就是比较老的视频设备啦,新设备都支持标准H264,H265了,或者私有平台协议的视频,将这些私有协议视频通过转码推送到标准的流媒体服务器,然后通过网页不使用插件进行。目前无插件播放的播放器很多比如video.js啦,一般只支持H264的flv格式,HLS等,当然也有支持H265的,不过这些都不是重点,今天的重点是怎么通过FFMPEG将私有协议的码流转化为标准的H264然后通过FFMPEG推送到流媒体服务器,从而通过网页直接播放。

        这个需求嘛,做的方式也很多,比如先对接私有SDK,然后通过私有解码库解码为YVU然后在编码转发,这是一个比较普遍的做法,也很常规。不过其实比较麻烦, 需要对编解码有一定基础。下面我介绍的方法较为简单,也很通用,只需要私有SDK支持抓图功能即可,一般私有SDK抓图的接口基本都有。

      主要思路就是使用私有SDK的抓图接口,不停的抓图,然后将图片数据输送到FFMPEG的管道,这样就可以源源不断的推送了。

     首先是FFMPEG的管道命令使用方法 

      ffmpeg.exe -f image2pipe -i \\.\\pipe\MyPipe -pix_fmt yuv420p -vcodec libx264 -f rtsp -rtsp_transport tcp "rtsp://127.0.0.1:8554/1234/1"

     调用这个命令后,FFMPEG就会连接\\.\\pipe\MyPipe的命名管道,如果没有打开命名管道,FFMPEG会退出,如果有,则会等待管道数据,我们就是利用此功能进行推送

     好了,废话不多说,上干货,也就是代码,这里以windows为例,linux大同小异就是管道的使用方法不同而已,大家学会举一反三

 

long StartProgress()//调用FFMPEG命令推流
{
    char sProcessID[32] = {0};
    sprintf_s(sProcessID,sizeof(sProcessID),"%d",GetCurrentProcessId());

    char sparam[1024];
    //调用FFMPEG命令通过管道数据推流,这里想推什么流改后面的推流地址即可,FFMPEG很强大的
    sprintf(sparam,"ffmpeg.exe -f image2pipe -i \\\\.\\pipe\\MyPipe -pix_fmt yuv420p -vcodec libx264 -f rtsp -rtsp_transport tcp \"rtsp://127.0.0.1:8554/1234/1\"");

    PROCESS_INFORMATION pi;
    STARTUPINFO    si;
    memset(&si, 0, sizeof(si));
    si.cb = sizeof(STARTUPINFO);
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.lpTitle = "";
    si.wShowWindow = SW_SHOWNORMAL;

    DWORD dwExitCode =0;
    BOOL ret = ::CreateProcess(NULL,(char*)sparam, NULL, NULL, FALSE,CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
    if (ret)
    {
        
        //m_lpid = pi.dwProcessId;

        //GF_AddProcessToJobObject(pi.hProcess);
        //关闭子进程的主线程句柄
        
        //等待子进程的退出
        //WaitForSingleObject(pi.hProcess,INFINITE);
        //获取子进程的退出码
        //GetExitCodeProcess(pi.hProcess, &dwExitCode);

        //::CloseHandle((HANDLE)pi.dwProcessId); 
        ::CloseHandle((HANDLE)pi.hThread);
        //关闭子进程句柄
        //CloseHandle(pi.hProcess);
    }else
    {
        //LOGE << "idx:" << m_lidx << " Start Progress Failed.error:" << GetLastError();
    }
    return 0;

}

    

int cappic()//抓图函数
{
    CString str;
    CString strDIR;
    int num = 1;
    int nDir = 0;

    SECURITY_ATTRIBUTES sa;
    SECURITY_DESCRIPTOR sd;
    if( InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) )
    {
        // add a NULL disc. ACL to the security descriptor.
        if (SetSecurityDescriptorDacl(&sd, TRUE, (PACL) NULL, FALSE))
        {
            sa.nLength = sizeof(sa);
            sa.lpSecurityDescriptor =&sd;
            sa.bInheritHandle = TRUE;
            //创建一个命名管道,在windows中\代表zhuan'yi两个\\代表一个\ 
            HANDLE hNamedPipe = CreateNamedPipeA("\\\\.\\pipe\\MyPipe", 
                PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 
                PIPE_TYPE_BYTE, 1, 1024, 1024,0 , &sa); 
            //检查是否创建成功 
            if (hNamedPipe == INVALID_HANDLE_VALUE) 
            { 
                printf("create named pipe failed!\n"); 
            } 
            else 
            { 
                printf("create named pipe success!\n"); 
            } 

            //异步IO结构 
            OVERLAPPED op; 
            ZeroMemory(&op, sizeof(OVERLAPPED)); 
            //创建一个事件内核对象 
            op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); 
            //等待一个客户端进行连接 
            BOOL b = ConnectNamedPipe(hNamedPipe, &op); 
            //开启FFMPEG,并调用命令
            StartProgress();
            //当有客户端进行连接时,事件变成有信号的状态 
            if (WaitForSingleObject(op.hEvent, INFINITE) == 0) 
            { 
                printf("client connect success!\n"); 
            } 
            else 
            { 
                printf("client connect failed!\n"); 
            } 

            unsigned char*  buff = new unsigned char[1024*1024*100]; 
            memset(buff,0,1024*1024*100);
            CFile file;
            
            while(TRUE)
            {
                if(m_lPlayBackHandle == -1)
                    return -1;

                //下面的函数就是私有SDK抓图函数,自己改为自己的抓图接口即可

                str.Format("G:\\test\\conver\\bin\\1234\\1.bmp",num);
                GF_CreateDir(str);
                int nRes = EX_NET_CapturePicture(0,m_lPlayBackHandle,(char*)(LPCTSTR)str);

                //--------抓图接口抓图完成后,读取图像数据,通过管道输入到FFMPEG
                if(file.Open(str,CFile::modeReadWrite))
                {    
                    memset(buff,0,1024*1024*100);
                    int nLen = file.Read(buff,1024*1024*100);
                    DWORD cbWrite; 
                    WriteFile(hNamedPipe, buff, nLen, &cbWrite, NULL); 
                    file.Close();
                }
                Sleep(10);
            }
        }
    }
    return 0xFFFF;
}

 

效果图上个

说明推流成功啦

VLC播放效果

CPU占用略高,FFMPEG转码占用CPU本身比较高

我I5的CPU大概解码15%,编码15%左右

此文仅用来抛砖引玉,给出个思路,具体应用到项目中,还需很多工作

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FFMPEG通过管道将图片推送流媒体 的相关文章

随机推荐

  • 获取安卓位置信息

    别忘了添加权限 xff1a lt uses permission android name 61 34 android permission INTERNET 34 gt lt uses permission android name 61
  • 安卓与html混合开发之原生与js相互调用

    原生和html的优缺点就不多说了 xff0c 有些特定条件下用html页面可以很方便 xff0c 也很容易更新和维护 xff0c 那么这就涉及到html与安卓原生的交互和通信 接下来我要分享的是html调用原生的弹窗和位置信息 xff0c
  • 应用保活--杀死进程也能收到推送消息

    我选取的是极光推送 xff0c 当把进程杀死时候就接受不到推送过来的消息 这是因为我使用的是小米手机 xff0c 小米和华为手机属于那种深度定制安卓系统 xff0c 需要用户的操作才能够实现应用 保活 的目的 小米 MIUI 自启动管理 x
  • 安卓原生与vue前段相互调用

    之前写过一个博客是安卓原生与JS交互的博客 xff1a http blog csdn net jhl122 article details 53406623 那是正常情况下的交互 xff0c 但是如果前段人员使用vue开发就会产生一个问题
  • CMake 编译时报错 ninja: error: ......missing and no known rule to make it

    Build command failed Error while executing process F Android sdk cmake 3 6 4111459 bin cmake exe with arguments build E
  • 数据类型和Json格式

    1 前几天 xff0c 我才知道有一种简化的数据交换格式 xff0c 叫做yaml 我翻了一遍它的文档 xff0c 看懂的地方不多 xff0c 但是有一句话令我茅塞顿开 它说 xff0c 从结构上看 xff0c 所有的数据最终都可以分成三种
  • golang语言rsa加解密及签名验签

    golang语言rsa加解密及签名验签 96 rsa 96 算法概述 96 Rsa 96 结构体封装封装的优点使用案例 rsa算法 概述 rsa是一种非对称的可逆的加密算法 xff0c 对加密数据长度有限制 xff0c 同时rsa也提供了数
  • 异常与错误处理

    异常与错误处理 PHP的异常与错误是分开的 xff0c 当程序出现异常时会throw一个 Exception 或子类 对象 xff0c 但是当出现错误时会触发一个错误 1 异常处理 1 1 通过try catch主动处理异常 span cl
  • 设计模式

    1 什么是模式 设计模式是对某些典型易变问题的特定解决方案 xff0c 这些问题和解决方案经过分类总结 xff0c 并且为了方便交流给每个解决方案都起了特定的名字 模式是为了解决变化的问题 xff0c 将变化的问题进行封装 xff0c 让变
  • 最新完美解决Python第三方库安装出现Microsoft Visual C++ 14.0 is required的问题

    安装库出现报错 xff1a Microsoft Visual 14 0 or greater is required 怎么办 xff1f 使用Python下载第三方库 xff0c pip也更新了 xff0c 镜像也使用了 xff0c 网络也
  • pdo-mysql

    pdo mysql PHP连接数据库推荐使用PDO xff0c PDO扩展为PHP访问数据库定义了一个轻量级接口 我们可以通过实现PDO接口的每个数据库驱动来访问数据库服务 访问mysql数据库服务 xff0c 我们使用PDO MYSQL驱
  • db封装

    db封装 以下Connection类封装支持以下几个特性 1 参数绑定防止sql注入2 读写分离3 多主多从 xff0c 多节点负载均衡4 故障自动摘除及自动恢复 代码实现 span class token delimiter import
  • 数据结构

    1 数据结构 提到算法不能不提数据结构 xff0c 数据结构就是数据元素按照一种或多种关系的集合 xff0c 按照逻辑结构划分 xff0c 可以分为 xff1a 1 1 集合 集合是由一堆无序的 相关联的 xff0c 且不重复的数据元素组成
  • 数据切分——Atlas介绍

    Atlas是由 Qihoo 360公司Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目 它在MySQL官方推出的MySQL Proxy 0 8 2版本的基础上 xff0c 修改了大量bug xff0c 添加了很多功能
  • Nginx负载均衡:分布式/热备Web Server的搭建

    Nginx是一款轻量级的Web 服务器 反向代理服务器 及电子邮件 xff08 IMAP POP3 xff09 代理服务器 xff0c 并在一个BSD like 协议下发行 由俄罗斯的程序设计师Igor Sysoev所开发 xff0c 供俄
  • 数据切分——Atlas读写分离Mysql集群的搭建

    关于数据切分的原理可以参见博客 xff1a http blog csdn net jhq0113 article details 44226789 关于Atlas的介绍可以参见博客 xff1a http blog csdn net jhq0
  • 数据切分——Mysql分区表的建立及性能分析

    Mysql的安装方法可以参考 xff1a http blog csdn net jhq0113 article details 43812895 Mysql分区表的介绍可以参考 xff1a http blog csdn net jhq011
  • 利用C++求解一元二次方程

    题目 xff1a 求解一元二次方程 xff1a ax 43 bx 43 c 61 0 的解 xff0c 其中a 61 1 b 61 3 c 61 2 分析 xff1a 大家都知道一元二次方程的解有三种情况 xff0c 即考虑 61 xff0
  • windows server 2016 中users组用户权限实探

    users 组用户不可删除他人创的文件和文件夹 但可在他人创建的文件夹中创文件夹 xff08 系统文件夹除外 xff09 并在创建的文件夹中创建文件 users 组用户不可以在磁盘根目前下创建文件 users 组用户不可在c盘windows
  • FFMPEG通过管道将图片推送流媒体

    最近遇到个需求 xff0c 将私有协议的码流 xff0c 就是比较老的视频设备啦 xff0c 新设备都支持标准H264 H265了 xff0c 或者私有平台协议的视频 xff0c 将这些私有协议视频通过转码推送到标准的流媒体服务器 xff0