当前位置:网站首页>搭建极简GB28181 网守和网关服务器,建立AI推理和3d服务场景,然后开源代码(一)
搭建极简GB28181 网守和网关服务器,建立AI推理和3d服务场景,然后开源代码(一)
2022-06-25 14:35:00 【qianbo_insist】
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 项目自由人
这样的团队建立起来以后,需要一个比较有经验的人来处理问题,我们把这个叫做项目跟随自由人,往往有这样的一个人,会减少百分之五十的团队人员。这个人需要有足够的经验。
边栏推荐
- Kubernetes 理解kubectl/调试
- Is qiniu regular? Is it safe to open a stock account?
- China has made major breakthroughs in battery technology. Japan, South Korea and the United States are lagging behind. China has consolidated its leading edge
- 移除区间(贪心)
- Shell string variable
- It's not easy to understand the data consistency of the microservice architecture for the first time after six years as a programmer
- 【HBZ分享】LockSupport的使用
- 【世界历史】第一集——石器时代的人们
- Deeply understand the mathematics behind deep neural networks (mysteries of neural networks Part I)
- Renix perf: detailed explanation of IP network performance test tools and test case parameters
猜你喜欢

使用sphinx根据py源文件自动生成API文档

Complete and detailed compilation of experimental reports

shell 数组

Page 112 machine learning - review of fundamentals of mathematics pptx

重磅!国产 IDE 发布,由阿里研发,完全开源!(高性能+高定制性)

‘nvidia-smi‘ 不是内部或外部命令,也不是可运行的程序或批处理文件

JVM uses tools to analyze classic cases of OOM

JS floating point multiplication and division method can not accurately calculate the problem

当了六年程序员第一次搞懂微服务架构的数据一致性,真不容易

"Mobile cloud Cup" computing power network application innovation competition is in hot registration!
随机推荐
Where is it safe to open an account for buying funds? Ask for guidance
Solving error: creating window glfw error: glew initialization error: missing GL version
Stream竟然还有应用进阶学习?作为程序员的你知道吗
启牛是正规的吗?股票开户安全吗?
Add the resources directory under test in idea
Getting started with numpy Library
Beego--- notes
【世界历史】第一集——石器时代的人们
合宙Air32F103CBT6开发板上手报告
About the problem of kicad stuck in win10 version, version 6 x
‘nvidia-smi‘ 不是内部或外部命令,也不是可运行的程序或批处理文件
分饼干问题
Garbage collection mechanism
Pourquoi les programmeurs devraient - ils être plus doux?
JGG | 河北大学杜会龙组综述植物泛基因组学研究
laravel8实现图片验证码
Add a string at the input and textarea cursors
从0到1完全掌握 XSS
shell 运算符
Is it safe for tongdaxin to open a stock account