搭建极简GB28181 网守和网关服务器,建立AI推理和3d服务场景,然后开源代码
Posted qianbo_insist
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搭建极简GB28181 网守和网关服务器,建立AI推理和3d服务场景,然后开源代码相关的知识,希望对你有一定的参考价值。
1 目的
这里说的开源并非使用开源现有的系统,而是自己写个系统去开源。
为何要搭建极简GB服务,我们在公司里公司先后使用了nodejs ,go ,c# ,c++ 等等搭建了不同类型的GB服务,这个使用很多都可以搭建起来,也不像很多人说的那样,一定要tcp 才能通,udp 一样可以通,但是GB服务容易,难道网关就不能非常简单的搭建起来,满足我们的简单需求?
首先是为了视频分析,使用GB28181 接入视频以后,后接AI服务来满足简单需求
2、分析ps流
最简单的分析ps流方法是使用ffmpeg直接解析出流,流媒体服务器自己做,做了一个基本的流媒体服务器,开源在gitee,目前是第一版,需要读者自己优化,地址在下方
https://gitee.com/guanzhi0319/mediaserver
以上建立服务器是一种选择,另外在网关里面我们再可以有更简单的方式
分析ps流方法
struct buffer_data
uint8_t* ptr;
size_t size;
;
static int read_packet(void* opaque, uint8_t* buf, int buf_size)
struct buffer_data* bd = (struct buffer_data*)opaque;
buf_size = FFMIN(buf_size, bd->size);
if (!buf_size)
return AVERROR_EOF;
printf("ptr:%p size:%zu\\n", bd->ptr, bd->size);
memcpy(buf, bd->ptr, buf_size);
bd->ptr += buf_size;
bd->size -= buf_size;
return buf_size;
int main(int argc, char* argv[])
AVFormatContext* fmt_ctx = NULL;
AVIOContext* avio_ctx = NULL;
uint8_t* buffer = NULL, * avio_ctx_buffer = NULL;
size_t buffer_size, avio_ctx_buffer_size = 4096;
char* input_filename = NULL;
int ret = 0;
struct buffer_data bd = 0 ;
input_filename =(char*)"D:/ps file/ps0.264";
/* slurp file content into buffer */
ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
if (ret < 0)
return -1;
/* fill opaque structure used by the AVIOContext read callback */
bd.ptr = buffer;
bd.size = buffer_size;
if (!(fmt_ctx = avformat_alloc_context()))
ret = AVERROR(ENOMEM);
return -1;
avio_ctx_buffer = (uint8_t*)av_malloc(avio_ctx_buffer_size);
if (!avio_ctx_buffer)
ret = AVERROR(ENOMEM);
return -1;
avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
0, &bd, &read_packet, NULL, NULL);
if (!avio_ctx)
ret = AVERROR(ENOMEM);
return -1;
fmt_ctx->pb = avio_ctx;
ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
if (ret < 0)
std::cout << "Could not open input" << std::endl;
return -1;
ret = avformat_find_stream_info(fmt_ctx, NULL);
if (ret < 0)
std::cout << "Could not find stream information" << std::endl;
return -1;
av_dump_format(fmt_ctx, 0, input_filename, 0);
AVPacket pkt;
av_read_frame(fmt_ctx, &pkt);
avformat_close_input(&fmt_ctx);
/* note: the internal buffer could have changed, and be != avio_ctx_buffer */
if (avio_ctx)
av_freep(&avio_ctx->buffer);
av_freep(&avio_ctx);
av_file_unmap(buffer, buffer_size);
if (ret < 0)
std::cout << "Error occurred!" << std::endl;
return 1;
return 0;
以上代码输入一个ps文件,是可以输出一帧的,如果ps流是标准的,则没有问题。
2 建立简单网关
我们把它叫做simple gateway,其实是mediaserver,上面的开源地址已经有了, 视频流拉取到以后,我们只是用来上云,并且在服务端接到流以后,发送到AI 推理端进行视频推理,并且在3d数字孪生场景中插入我们的视频服务。
mediaserver 既然负责转协议,那在网络里面就是 网关,也是路由器。
3 如何足够简单?
这个问题比较复杂了,因为设计一个产品,我们往往会陷入死胡同,往复杂里面设计。
1 建立一个足够简单的GB服务
有多简单,只有一个c++程序,却能够承受10k的并发,能做到吗,当然,必须要有足够的带宽支持。
2 GB服务和媒体网管合成。
如果在云上,我们是可以直接合成的,那么就需要把两者合成,直接使用c++程序,我测试了以下,使用最简单及其简化的c++ 程序写完最基础的代码,编译完就一个几百k的可执行文件,不依赖其他任何动态库。这个后面也会开源出来。
4、播放rtsp
建立rtsp链接当然有很多方法,我们可以自己写rtsp客户端,这是一种方式,既然这里要求最简单,那就是使用ffmpeg直接拉流,以下代码是例子。
int ffmpeg_rtsp_client()
// Allocate an AVFormatContext
AVFormatContext* format_ctx = avformat_alloc_context();
// open rtsp: Open an input stream and read the header. The codecs are not opened
const char* url = "rtsp://127.0.0.1/out.264";
int ret = -1;
AVDictionary* opts = NULL;
av_dict_set(&opts, "rtsp_transport","tcp", 0);
av_dict_set(&opts, "buffer_size", "1048576", 0);
av_dict_set(&opts, "fpsprobesize", "2", 0);
av_dict_set(&opts, "analyzeduration", "5000000", 0);
//设置 最大延迟
av_dict_set(&opts, "max_delay", "500", 0);
//rtmp、rtsp延迟控制到最小
av_dict_set(&opts, "fflags", "nobuffer", 0);
//设置 阻塞超时,否则可能在流断开时连接发生阻塞
av_dict_set(&opts, "stimeout", "3000000", 0);
ret = avformat_open_input(&format_ctx, url, nullptr, &opts);
if (ret != 0)
fprintf(stderr, "fail to open url: %s, return value: %d\\n", url, ret);
return -1;
// Read packets of a media file to get stream information
ret = avformat_find_stream_info(format_ctx, nullptr);
if (ret < 0)
fprintf(stderr, "fail to get stream information: %d\\n", ret);
return -1;
// audio/video stream index
int video_stream_index = -1;
int audio_stream_index = -1;
fprintf(stdout, "Number of elements in AVFormatContext.streams: %d\\n", format_ctx->nb_streams);
for (int i = 0; i < format_ctx->nb_streams; ++i)
const AVStream* stream = format_ctx->streams[i];
fprintf(stdout, "type of the encoded data: %d\\n", stream->codecpar->codec_id);
if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
video_stream_index = i;
fprintf(stdout, "dimensions of the video frame in pixels: width: %d, height: %d, pixel format: %d\\n",
stream->codecpar->width, stream->codecpar->height, stream->codecpar->format);
else if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
audio_stream_index = i;
fprintf(stdout, "audio sample format: %d\\n", stream->codecpar->format);
if (video_stream_index == -1)
fprintf(stderr, "no video stream\\n");
return -1;
if (audio_stream_index == -1)
fprintf(stderr, "no audio stream\\n");
int cnt = 0;
AVPacket pkt;
while (1)
if (++cnt > 100) break;
ret = av_read_frame(format_ctx, &pkt);
if (ret < 0)
fprintf(stderr, "error or end of file: %d\\n", ret);
continue;
if (pkt.stream_index == video_stream_index)
fprintf(stdout, "video stream, packet size: %d\\n", pkt.size);
if (pkt.stream_index == audio_stream_index)
fprintf(stdout, "audio stream, packet size: %d\\n", pkt.size);
av_packet_unref(&pkt);
avformat_free_context(format_ctx);
return 0;
5 3d 场景
使用threejs 搭建,threejs足够简单,例子繁多,具体在下一章节里写了。
6 c# 或者nodejs建立网守
使用nodejs 和 c# 的好处依然是足够简单,使用java也是可以,但没有以上两种语言简单。建立http服务的时候,如果使用nodejs express,是非常快速方便的。使用c# 来做的时候,也是够简单快速,并且跨平台,也可以直接在平台上直接编译另外一个平台的可执行文件,这一点和go语言类似,语法又和java类似,以下是在gb28181 建立服务的时候,需要使用本地IP地址,代码如下所示。上云的时候我们需要使用本地的IP地址而不是外网的IP地址。不要奇怪,是真的,外网的地址只是在摄像头或者nvr里面使用。
class IPUtil
public static string IPV4()
string ipv4 = GetLocalIPv4(NetworkInterfaceType.Wireless80211);
if (ipv4 == "")
ipv4 = GetLocalIPv4(NetworkInterfaceType.Ethernet);
if (ipv4 == "")
ipv4 = GetLoacalIPMaybeVirtualNetwork();
return ipv4;
private static string GetLoacalIPMaybeVirtualNetwork()
string name = Dns.GetHostName();
IPAddress[] ipadrlist = Dns.GetHostAddresses(name);
foreach (IPAddress ipa in ipadrlist)
if (ipa.AddressFamily == AddressFamily.InterNetwork)
return ipa.ToString();
return "没有连接网络,请链接网络后重试!";
public static string GetLocalIPv4(NetworkInterfaceType _type)
string output = "";
foreach (NetworkInterface item in NetworkInterface.GetAllNetworkInterfaces())
//Console.WriteLine(item.NetworkInterfaceType.ToString());
if (item.NetworkInterfaceType == _type && item.OperationalStatus == OperationalStatus.Up)
foreach (UnicastIPAddressInformation ip in item.GetIPProperties().UnicastAddresses)
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
output = ip.Address.ToString();
return output;
7、播放器
这个下一章节说了
8 产品化
需要一个
1 产品经理
2 一个前端
3 一个后端
4 一个c++
5 一个nodejs 或者c# 人员
6 项目自由人
这样的团队建立起来以后,需要一个比较有经验的人来处理问题,我们把这个叫做项目跟随自由人,往往有这样的一个人,会减少百分之五十的团队人员。这个人需要有足够的经验。
以上是关于搭建极简GB28181 网守和网关服务器,建立AI推理和3d服务场景,然后开源代码的主要内容,如果未能解决你的问题,请参考以下文章
ZLMediaKit + wvp-GB28181-pro 流媒体服务搭建