FFmpeg实现视频流多平台分发技术方案

  • 概述

应用QT 和C++技术,采集视频设备的数据流,通过分发技术方案,可以使多个终端设备接收该视频流;视频器材可以是任何基于IP网络的视频设备,如视频眼镜、摄像机等。接收分发视频流的终端基本支持所有设备,如PC机、IOS手机、Android手机等;该技术方案主要用来解决两个问题:视频安全可控【防止视频数据泄露】;大幅度节约视频应用成本【目前使用视频云服务的成本相当高昂】。

 

  • 技术方案总览图框架图

总体分三层结构,视频采集层、数据源管理层和终端接收层,如下图所示:

 

  • 视频源采集技术

可以通过如下步骤采集视频流(本例以广播包形式说明),视频采集设备可以是PC或者手机终端【本例以Android手机端作为视频采集端,如何编译FFMPEG Android,请参考:https://www.apps121.com/2019/03/11/ffmpeg4-1-androidlibwindows_compile_successfully/】

  • 启动采集设备上的视频采集程序,搜素网络中的视频设备:
  • 捕获搜索到视频设备中的视频流;

代码说明如下:

  • 创建QudpSocket 对象,使用bind绑定端口
  • 定时发送网络广播包
  • 解析出RTSP 视频流的地址
  • 拉取设备视频流数据
    1. 循环使用函数 av_read_frame 读取视频流中的数据到AVPacket ,AVPacket结构特别重要【可以作为未解码的原始数据包直接转发到服务端;根据需求再次编码;直接在设备采集端解码并播放视频;可以进行视频的数据的录制等】;
    2. 需要设置关键帧信息 : AVCodecContext中的两个参数分别为time_base.num 和time_base.den
  • 分发的数据流采集

设备采集端需要制作两路视频,一路视频用于采集端播放;另一路用于传到服务端,用于分发使用;

采集端播放代码比较简单:

首先avcodec_decode_video2解码视频流数据,使用sws_scale适配出合适的帧数据,最后创建Qimage对象显示就可以的

注释:Android 显示帧数据使用Image对象就可以的,通过QquickImageProvider格式化显示的帧数据

 

用于服务端分发流主要有三种方式:

  1. 直接使用解码之后的帧数据

首先把帧数据写入QbyteArray对象,再压缩,最后通过网络传输到服务端

QImage image;

this->OpQueue(image,1);

QByteArray byte;

QBuffer buffer(&byte);

buffer.open(QIODevice::WriteOnly);

image.save(&buffer, “JPG”, g_nFrameLevelTmp);

byte = qCompress(byte);

  1. 使用未解码的原始数据

把通过函数av_read_frame读取原始数据流AVPacket做个数据拷贝,再把数据写入QbyteArray中同时进行压缩,最后通过网络传输到服务器。

  1. 重新编码视频流数据【Android系统FFMPEG编译的时候需要添加H264支持的,默认只支持解码的,不支持编码的,需要特别主要】

创建H264编码器,主要是如下三个函数

avcodec_find_decoder(AV_CODEC_ID_H264)

avcodec_alloc_context3

avcodec_open2

 

解码器主要参数设置如下:

m_pVideoEnCtx->codec_id = AV_CODEC_ID_H264;

m_pVideoEnCtx->codec_type = AVMEDIA_TYPE_VIDEO;

m_pVideoEnCtx->pix_fmt = AV_PIX_FMT_YUV420P;

m_pVideoEnCtx->width = 1280;

m_pVideoEnCtx->height = 720;

m_pVideoEnCtx->bit_rate = 400000;

m_pVideoEnCtx->gop_size = 75 ;

m_pVideoEnCtx->time_base.num = 1;

m_pVideoEnCtx->time_base.den = 25;

m_pVideoEnCtx->max_b_frames = 0;

m_pVideoEnCtx->has_b_frames = 0;

m_pVideoEnCtx->i_quant_factor = 2;

av_opt_set(m_pVideoEnCtx->priv_data, “preset”, “slow”, 0);

av_opt_set(m_pVideoEnCtx->priv_data, “tune”, “zerolatency”, 0);

 

重新编码视频流数据,这一步可以设置码率、大小等定制化参数;编码之序列化数据到QbyteArray中并且压缩,最后通过网络传输到服务端

 

  1. 三种方式的比较

直接传输视频帧数据,逻辑简单,针对小分辨率和局域网网比较实用;

传输未解码的视频包,逻辑相当复杂点,但是数据压缩率极高,能很好的满足公网传输

重新编码方式,主要应用于多功能定制用途,灵活性特别好,满足不同的视频质量和网络带宽要求

  • 服务端分发技术

服务端主要用户账号管理,提供访问视频数据权限;视频源数据管理,数据存档、过滤以及 以及视频数据下发给各个终端设备。

服务端流程示意图:

 

  • 接收视频流的终端设备

视频终端设备,连接服务端并接收视频数据,视频终端设备有可能需要处理视频数据,如未解码的原始视频数据,需要终端解码并显示;针对Android视频库的的编译方式,请参照:https://www.apps121.com/2019/03/11/ffmpeg4-1-androidlibwindows_compile_successfully/

 

  • 结束语

Qt&C++ 基于FFMPEG库的视频流分发技术方案可以有效的节约成本,保证对视频数据的绝对控制和处理;

 

详细的代码细节,如有兴趣,可以私聊沟通,谢谢!