当前位置: 首页 > news >正文

超分服务的分量保存

分量说明

    分量的概念主要是对于显卡解码,编码和网络传输而言,显卡可以同时进行几个线程,多个显卡可以分布式计算,对分量进行AI识别,比如我们有cuda的显卡,cuda的核心量可以分给不同的分片视频,第一步先将视频减小,第二部分割视频。对于小视频片而言,不同的智能盒子也可以接收网络传输来进行接收数据,进行并行识别服务。这就是我说的分量服务的概念。

采样

    在超分服务中,上采样和下采样是两个重要的操作,分别用于增加和减少图像的分辨率。我们在下采样后存储文件和传输,可以显著减少存储的量,同时减少网络的传输量,而接收端收到以后再进行上采样放大,同时进行AI 分析

超分服务说明

    实现超分服务,将实时视频能够缩小并且传输和保存,同时需要将文件分成片,同时保证每个文件的最后一帧和下一个文件的第一帧相同,还需要解决两个问题
文件切片是问了能够分布式传输出去,同时本地如果有多个显卡,可以同时进行文件的搜索,比如再多个文件中同时启动AI服务,搜索同一个人脸。

    采用rtsp,rtmp服务器接收,rtmp服务器在接收文件时保存为flv文件,为了不污染任何代码,不采用开源的各种服务,使用c++20 去写rtmp和rtsp服务器,这个花了两天时间,协议没啥问题,结果反而时卡在了文件保存上面,下面具体说几个问题,主要体现在时间戳上面。

    以下为flv文件保存的要素,首先时flv 头部,在头部中查找0x17 和 0x00 0x01
*/
//0x17 key 00(AVCPacketType ) 00 表示 是AVCDecoderConfigurationRecord
//0x17 key 01(AVCPacketType ) 01 表示 raw data ->nalu
//0x27 not key 01 01 表示 raw data ->nalu

//FLV head 9 bytes
//4 bytes previous tag
//tag data —>11 bytes head -> 5 bytes video head -> nalu data
//4 bytes previous tag
//tag data
熟悉flv文件格式的人一看就懂,无需多言。

1 关键帧问题
2 时间戳问题

关键帧问题

    必须保证一个文件第一帧一定为关键帧,所以在分割视频的时候必须能够拿到关键帧的时候才能分割,为了能够保证未丢失文件,上一个文件的最后一帧为下一个文件的第一帧,否则会有很多依靠关键帧解码的p帧b帧无法解码,变成比较难受的绿色,也有可能为绿加黑。

分量保存的时间戳

看下图,
在这里插入图片描述

    显然除了第一个文件是正确的,但除了第一个分量文件,其他文件第一帧的时间戳是不对的,这是因为AVC sequence header 总是零,vlc播放的时候计算的时间就不正确了,那么就有两个方法:

1 是修改 sequence header的时间戳,
2 是修改每一帧时间戳,

    这里有一个问题要说明,就是整体直播出去的时候关键帧的时间戳肯定是对的,为了让文件比较正常,采取修改每一帧时间戳。

    总结一下flv头部, 11 个字节头部后,如果是视频,加5个字节的扩展,后面就是nalu数据,如果是音频,加2个字节的扩展,视频5个字节里面第一个就是判别是关键帧和非关键帧的紧要,这里简单一点先用0x17 0x27来判别,注意实际上不是这样,只有h264才是这个值,先找定时间戳,假定我们从协议里面获取的时间戳是正确的,看下面的代码


//11 个字节头部
static void pack_tag_header(uint8_t *buf, uint8_t type, uint32_t data_size, uint32_t timestamp) {//8 audio ; 9 video ; 18 script//8 is the most if (type == 8 || type == 9 || type == 18){*buf++ = type;//one bytesbuf = write_be_ui24(buf, data_size); //three bytesbuf = write_be_ui24(buf, timestamp & 0xffffff);//three bytes*buf++ = timestamp >> 24; //one bytesbuf = write_be_ui24(buf, 0); //three bytes}
}//flv header length is 11
//type 8:audio,  9:video,  18:script meta
static void pack_tag(uint8_t* header, ptr_s_memory mem, uint8_t type, uint32_t timestamp) {pack_tag_header(header, type, (uint32_t)mem->v_len, timestamp);uint8_t* p = mem->v_data_r + mem->v_len;//last write the frame length ,it must include the header lengthwrite_be_ui32(p, FLV_TAG_HEADER_LEN + (uint32_t)mem->v_len);
}

1 2 3 4 5 6 7 8 9 10 11
09 xx xx xx 00 7c 79 00 00 00 00
11 个flv字节头部里面有四个字节包含了时间戳,第5个字节到第8,也是我们自己的代码写入的,我们要做的就是重写时间戳,但是不能修改传入的tag数组,这是外面传输出去要用的

0 和 1 之间无缝衔接,同时每个文件的时间长度和时间戳都保证正确
在这里插入图片描述

在这里插入图片描述
开头和结尾衔接
在这里插入图片描述
相邻两个文件开头和结尾为同一帧

code

主要就是需要重新改写时间戳,直接看代码

#pragma once
#include <stdint.h>
#include <stdio.h>
#include <string>#include "c_hub.h"
#include "util_flv_pack.h"
//flv 文件读写
class c_flv_writer
{FILE* v_fp = NULL;int64_t v_num = 0;uint32_t v_hash = 0;std::string v_deviceurl;uint32_t v_record_timestamp = 0;
public:ptr_s_memory v_head_video = nullptr;ptr_s_memory v_head_audio = nullptr;int v_frame_count = 2000;int v_frame_record = 0;int v_inited = 0;protected:std::string GetFileName(){//判断v_deviceurl是否"/"结尾std::string name = v_deviceurl + std::to_string(v_hash);name +="_" + std::to_string(v_num);name += ".flv";v_num++;return name;}
public:void initStart(std::string deviceurl, uint32_t hash, ptr_s_memory v, ptr_s_memory a){v_hash = hash;v_deviceurl = deviceurl;v_head_video = v;v_head_audio = a;v_inited = 1;}static void modify_timestamp(uint8_t* buf, uint32_t timestamp) {buf = buf + 4; // write_be_ui24(buf, data_size); //three bytesbuf = write_be_ui24(buf, timestamp & 0xffffff);//three bytes*buf++ = timestamp >> 24; //one bytes}int writeStart(uint32_t ts){if (v_fp == NULL){v_frame_record = 0;std::string name = GetFileName();v_fp = fopen(name.c_str(), "wb+");if (v_fp == NULL)return -1;fwrite(FLV_HEADER_BUF_13, 13, 1, v_fp);//video headif (v_head_video != nullptr){uint8_t* data_v = v_head_video->v_data_h; //flvhub->v_cache_hv->v_data_h;size_t len_v = v_head_video->v_len + 11 + 4;fwrite(data_v, len_v, 1, v_fp);}//audio headif (v_head_audio != nullptr){uint8_t* data_a = v_head_audio->v_data_h;size_t len_a = v_head_audio->v_len + 11 + 4;fwrite(data_a, len_a, 1, v_fp);}}v_record_timestamp = ts;return 0;}void writeData(uint8_t* tag, int taglen, uint8_t* data, size_t len, uint32_t ts){if (v_fp == NULL)writeStart(ts);//遇到关键帧才能重新开始if (v_fp != NULL /*&& v_frame_record < v_frame_count*/){uint8_t a = *data;uint8_t b = *(data + 1);if (v_frame_record > v_frame_count && ((a == 0x17) && (b == 0x01))){//需要重复最后一帧放开uint8_t newtag[11];memcpy(newtag, tag, 11);uint32_t nowts = ts - v_record_timestamp;modify_timestamp(newtag, nowts);fwrite(newtag, taglen, 1, v_fp);fwrite(data, len, 1, v_fp);fclose(v_fp);v_fp = NULL;std::cout << "close the file now" << std::endl;writeStart(ts);}uint8_t newtag[11];memcpy(newtag, tag, 11);uint32_t nowts = ts - v_record_timestamp;modify_timestamp(newtag, nowts);fwrite(newtag, taglen, 1, v_fp);fwrite(data, len, 1, v_fp);v_frame_record++;std::cout << "write the number " << v_frame_record << std::endl;}}
};

调用

调用的时候放在音视频接收以后并且下采样结束的地方

if (flvhub->v_flv_w.v_inited == 0)
{flvhub->v_flv_w.initStart("./", hash, flvhub->v_cache_hv, flvhub->v_cache_ha);flvhub->v_flv_w.v_inited = 1;
}
flvhub->v_flv_w.writeData(tag,taglen, mem->v_data_r ,len, mem->v_ts);

其他编码

    由于rtmp协议已经加入enhanced 扩展,rtmp/flv已经有统一支持H265的国际版本,我后面会修改rtmp server,加入对h265的支持,那么这边存储flv 也必须进行修改,适应编码

相关文章:

超分服务的分量保存

分量说明 分量的概念主要是对于显卡解码&#xff0c;编码和网络传输而言&#xff0c;显卡可以同时进行几个线程&#xff0c;多个显卡可以分布式计算&#xff0c;对分量进行AI识别&#xff0c;比如我们有cuda的显卡&#xff0c;cuda的核心量可以分给不同的分片视频&#xff0c;第…...

Windows11系统下SkyWalking环境搭建教程

目录 前言SkyWalking简介SkyWalking下载Agent监控实现启动配置SkyWalking启动Java应用程序启动Elasticsearch安装总结 前言 本文为博主在项目环境搭建时记录的SkyWalking安装流程&#xff0c;希望对大家能够有所帮助&#xff0c;不足之处欢迎批评指正&#x1f91d;&#x1f91…...

前端BOM常用操作

BOM操作常用命令详解及代码案例 BOM&#xff08;Browser Object Model&#xff09;是浏览器对象模型&#xff0c;是浏览器提供的JavaScript操作浏览器的API。BOM提供了与网页无关的浏览器的功能对象&#xff0c;虽然没有正式的标准&#xff0c;但现代浏览器已经几乎实现了Java…...

【Go】-viper库的使用

目录 viper简介 viper使用 通过viper.Set设置值 读取配置文件说明 读取配置文件 读取多个配置文件 读取配置项的值 读取命令行的值 io.Reader中读取值 写配置文件 WriteConfig() 和 SafeWriteConfig() 区别: viper简介 配置管理解析库&#xff0c;是由大神 Steve Fr…...

JavaWeb酒店管理系统(详细版)

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…...

C++ | 定长内存池 | 对象池

文章目录 C | 定长内存池 | 对象池一、内存池的引入二、代码中的内存池实现 - ObjectPool类&#xff08;一&#xff09;整体结构&#xff08;二&#xff09;内存分配 - New函数&#xff08;三&#xff09;内存回收 - Delete函数 三、内存池在TreeNode示例中的性能测试演示四、脱…...

python画图|自制渐变柱状图

在前述学习过程中&#xff0c;我们已经通过官网学习了如何绘制渐变的柱状图及其背景。 掌握一门技能的最佳检验方式就是通过实战&#xff0c;因此&#xff0c;本文尝试做一些渐变设计。 前述学习记录可查看链接&#xff1a; Python画图|渐变背景-CSDN博客 【1】柱状图渐变 …...

基于RPA+BERT的文档辅助“悦读”系统 | OPENAIGC开发者大赛高校组AI创作力奖

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给…...

K8S部署流程

一、war打包镜像(survey,analytics,trac系统) 代码打包成war准备tomcat的server.xml文件&#xff0c;修改connector中8080端口为项目的端口 修改前&#xff1a; <Connector port"8080" protocol"HTTP/1.1"connectionTimeout"20000"redirect…...

DevExpress WinForms中文教程:Data Grid - 如何添加或删除行?

本教程介绍DevExpress WinForm的Data Grid控件UI元素和API&#xff0c;它们使您和最终用户能够添加或删除数据行。您将首选学习如何启用内置的数据导航器&#xff0c;然后学习如何使用Microsoft Outlook启发的New Item行添加新记录。最后教程将向您展示基本的API&#xff0c;它…...

u盘格式化后数据能恢复吗?2024年Top4恢复神器来帮忙

在这个电脑和手机满天飞的时代&#xff0c;U盘是我们用来存东西和传文件的得力助手&#xff0c;特别重要。但是&#xff0c;有时候U盘可能会不小心被格式化了&#xff0c;里面的重要文件就不见了。那么&#xff0c;U盘格式化后的数据还能恢复吗&#xff1f;当然可以。今天会告诉…...

深度学习·Argparse

Argparse 命令行选项、参数和子命令解析器 ArgumentParser 命令行传参数->解析参数->获得对应参数 初始化&#xff1a;parser argparse.ArgumentParser(descriptionxxx)添加命令行参数&#xff1a; parser.add_argument("--training_filepath", typestr, he…...

制造企业为何需要PLM系统?PLM系统解决方案对制造业重要性分析

制造企业为何需要PLM系统&#xff1f;PLM系统解决方案对制造业重要性分析 新华社9月23日消息&#xff0c;据全国组织机构统一社会信用代码数据服务中心统计&#xff0c;我国制造业企业总量突破600万家。数据显示&#xff0c;2024年1至8月&#xff0c;我国制造业企业数量呈现稳…...

http协议中的header详细讲解

http协议中的header详细讲解 HTTP 协议和 TCP/IP 协议族内的其他众多的协议相同&#xff0c;用于客户端和服务器之间的通信。 请求访问文本或图像等资源的一端称为客户端&#xff0c;而提供资源响应的一端称为服务器端。 HTTP 协议规定&#xff0c;请求从客户端发出&#xf…...

探索后量子安全:基于格加密技术的未来密码学展望

在信息技术日新月异的今天&#xff0c;量子计算作为下一代计算技术的代表&#xff0c;正逐步从理论走向实践。量子计算的出现对现有的加密体系构成了严重威胁&#xff0c;尤其是基于大数分解和离散对数难题的传统密码学&#xff08;如RSA和Diffie-Hellman协议&#xff09;。为了…...

WPF之UI进阶--完整了解wpf的控件和布局容器及应用

前面三篇有关WPF的基础介绍&#xff0c;分别介绍了wpf与winform的异同&#xff0c;wpf的事件生成和使用以及数据绑定。但我们还缺乏一副好的“皮囊”&#xff0c;所以从这篇开始我们来开始学习wpf的UI相关的内容&#xff0c;首当其冲的就是布局容器。 其实我们知道&#xff0c;…...

unity一键注释日志和反注释日志

开发背景&#xff1a;游戏中日志也是很大的开销&#xff0c;虽然有些日志不打印但是毕竟有字符串的开销&#xff0c;甚至有字符串拼接的开销&#xff0c;有些还有装箱和拆箱的开销&#xff0c;比如Debug.Log(1) 这种 因此需要注释掉&#xff0c;当然还需要提供反注释的功能&am…...

VBA数据库解决方案第十五讲:Recordset集合中单个数据的精确处理

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...

甄选范文“论软件需求管理”,软考高级论文,系统架构设计师论文

论文真题 软件需求管理是一个对系统需求变更了解和控制的过程。需求管理过程与需求开发过程相互关联,初始需求导出的同时就要形成需求管理规划,一旦启动了软件开发过程,需求管理活动就紧密相伴。 需求管理过程中主要包含变更控制、版本控制、需求跟踪和需求状态跟踪等4项活…...

Android Studio Dolphin 中Gradle下载慢的解决方法

我用的版本Android Studio Dolphin | 2021.3.1 Patch 1 1.Gradle自身的版本下载慢 解决办法&#xff1a;修改gradle\wrapper\gradle-wrapper.properties中的distributionUrl 将https\://services.gradle.org/distributions为https\://mirrors.cloud.tencent.com/gradle dis…...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建

制造业采购供应链管理是企业运营的核心环节&#xff0c;供应链协同管理在供应链上下游企业之间建立紧密的合作关系&#xff0c;通过信息共享、资源整合、业务协同等方式&#xff0c;实现供应链的全面管理和优化&#xff0c;提高供应链的效率和透明度&#xff0c;降低供应链的成…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

基于PHP的连锁酒店管理系统

有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发&#xff0c;数据库mysql&#xff0c;前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...

Qt的学习(一)

1.什么是Qt Qt特指用来进行桌面应用开发&#xff08;电脑上写的程序&#xff09;涉及到的一套技术Qt无法开发网页前端&#xff0c;也不能开发移动应用。 客户端开发的重要任务&#xff1a;编写和用户交互的界面。一般来说和用户交互的界面&#xff0c;有两种典型风格&…...