Windows平台实现Unity下窗体

2023-11-03

技术背景

随着Unity3D的应用范围越来越广,越来越多的行业开始基于Unity3D开发产品,如传统行业中虚拟仿真教育、航空工业、室内设计、城市规划、工业仿真等领域。

基于此,好多开发者苦于在Unity环境下,没有低延迟的推拉流解决方案,前几年,我们在Unity环境下推出了跨平台低延迟的RTMP|RTSP直播播放器,很好的解决了好多对延迟要求苛刻的使用场景。

随着时间的推移,越来越多的开发者联系我们,希望我们能推出Unity环境下的RTMP推送模块,获取到unity的实时数据,更低延迟更高效率的实现数据传输推送,基于此,我们发布了Unity环境下的RTMP推送模块。

本文以Windows平台为例,数据源分别为Unity的窗口、摄像头或整个屏幕,编码传输模块,还是调用大牛直播SDK(官方)的原生接口,简单界面先睹为快:

技术实现

1. 基础初始化


        private bool InitSDK()
        {
            if (!is_pusher_sdk_init_)
            {
                // 设置日志路径(请确保目录存在)
                String log_path = "D:\\pulisherlog";
                NTSmartLog.NT_SL_SetPath(log_path);

                UInt32 isInited = NTSmartPublisherSDK.NT_PB_Init(0, IntPtr.Zero);

                if (isInited != 0)
                {
                    Debug.Log("调用NT_PB_Init失败..");
                    return false;
                }

                is_pusher_sdk_init_ = true;
            }

            return true;
        }

2. 调用Open()接口,获取推送实例

       public bool OpenPublisherHandle(uint video_option, uint audio_option)
        {
            if (publisher_handle_ != IntPtr.Zero)
            {
                return true;
            }

            publisher_handle_count_ = 0;

            if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_Open(out publisher_handle_,
                video_option, audio_option, 0, IntPtr.Zero))
            {
                return false;
            }

            if (publisher_handle_ != IntPtr.Zero)
            {
                pb_event_call_back_ = new NT_PB_SDKEventCallBack(PbEventCallBack);

                NTSmartPublisherSDK.NT_PB_SetEventCallBack(publisher_handle_, IntPtr.Zero, pb_event_call_back_);

                return true;
            }
            else
            {
                return false;
            }
        }

3. 初始化参数配置

这里需要注意下,如果要采集unity窗口,需要设置图层模式,先填充一层RGBA黑色背景,然后再添加一层,用于叠加外部数据。

       private void SetCommonOptionToPublisherSDK()
        {
            if (!IsPublisherHandleAvailable())
            {
                Debug.Log("SetCommonOptionToPublisherSDK, publisher handle with null..");
                return;
            }

            NTSmartPublisherSDK.NT_PB_ClearLayersConfig(publisher_handle_, 0,
                            0, IntPtr.Zero);

            if (video_option == NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_LAYER)
            {
                // 第0层填充RGBA矩形, 目的是保证帧率, 颜色就填充全黑
                int red = 0;
                int green = 0;
                int blue = 0;
                int alpha = 255;

                NT_PB_RGBARectangleLayerConfig rgba_layer_c0 = new NT_PB_RGBARectangleLayerConfig();

                rgba_layer_c0.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE;
                rgba_layer_c0.base_.index_ = 0;
                rgba_layer_c0.base_.enable_ = 1;
                rgba_layer_c0.base_.region_.x_ = 0;
                rgba_layer_c0.base_.region_.y_ = 0;
                rgba_layer_c0.base_.region_.width_ = video_width_;
                rgba_layer_c0.base_.region_.height_ = video_height_;

                rgba_layer_c0.base_.offset_ = Marshal.OffsetOf(rgba_layer_c0.GetType(), "base_").ToInt32();
                rgba_layer_c0.base_.cb_size_ = (uint)Marshal.SizeOf(rgba_layer_c0);

                rgba_layer_c0.red_ = System.BitConverter.GetBytes(red)[0];
                rgba_layer_c0.green_ = System.BitConverter.GetBytes(green)[0];
                rgba_layer_c0.blue_ = System.BitConverter.GetBytes(blue)[0];
                rgba_layer_c0.alpha_ = System.BitConverter.GetBytes(alpha)[0];

                IntPtr rgba_conf = Marshal.AllocHGlobal(Marshal.SizeOf(rgba_layer_c0));

                Marshal.StructureToPtr(rgba_layer_c0, rgba_conf, true);

                UInt32 rgba_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                rgba_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_RGBA_RECTANGLE,
                                0, IntPtr.Zero);

                Marshal.FreeHGlobal(rgba_conf);

                NT_PB_ExternalVideoFrameLayerConfig external_layer_c1 = new NT_PB_ExternalVideoFrameLayerConfig();

                external_layer_c1.base_.type_ = (Int32)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_EXTERNAL_VIDEO_FRAME;
                external_layer_c1.base_.index_ = 1;
                external_layer_c1.base_.enable_ = 1;
                external_layer_c1.base_.region_.x_ = 0;
                external_layer_c1.base_.region_.y_ = 0;
                external_layer_c1.base_.region_.width_ = video_width_;
                external_layer_c1.base_.region_.height_ = video_height_;

                external_layer_c1.base_.offset_ = Marshal.OffsetOf(external_layer_c1.GetType(), "base_").ToInt32();
                external_layer_c1.base_.cb_size_ = (uint)Marshal.SizeOf(external_layer_c1);

                IntPtr external_layer_conf = Marshal.AllocHGlobal(Marshal.SizeOf(external_layer_c1));

                Marshal.StructureToPtr(external_layer_c1, external_layer_conf, true);

                UInt32 external_r = NTSmartPublisherSDK.NT_PB_AddLayerConfig(publisher_handle_, 0,
                                external_layer_conf, (int)NTSmartPublisherDefine.NT_PB_E_LAYER_TYPE.NT_PB_E_LAYER_TYPE_EXTERNAL_VIDEO_FRAME,
                                0, IntPtr.Zero);

                Marshal.FreeHGlobal(external_layer_conf);

            }
            else if (video_option == NTSmartPublisherDefine.NT_PB_E_VIDEO_OPTION.NT_PB_E_VIDEO_OPTION_CAMERA)
            {
                CameraInfo camera = cameras_[cur_sel_camera_index_];
                NT_PB_VideoCaptureCapability cap = camera.capabilities_[cur_sel_camera_resolutions_index_];

                SetVideoCaptureDeviceBaseParameter(camera.id_.ToString(), (UInt32)cap.width_, (UInt32)cap.height_);
            }

            SetFrameRate((UInt32)CalBitRate(edit_key_frame_, video_width_, video_height_));

            Int32 type = 0;   //软编码
            Int32 encoder_id = 1;
            UInt32 codec_id = (UInt32)NTCommonMediaDefine.NT_MEDIA_CODEC_ID.NT_MEDIA_CODEC_ID_H264;
            Int32 param1 = 0;

            SetVideoEncoder(type, encoder_id, codec_id, param1);

            SetVideoQualityV2(CalVideoQuality(video_width_, video_height_, is_h264_encoder));

            SetVideoMaxBitRate((CalMaxKBitRate(edit_key_frame_, video_width_, video_height_, false)));

            SetVideoKeyFrameInterval((edit_key_frame_));

            if (is_h264_encoder)
            {
                SetVideoEncoderProfile(1);
            }

            SetVideoEncoderSpeed(CalVideoEncoderSpeed(video_width_, video_height_, is_h264_encoder));

            // 音频相关设置

            SetAuidoInputDeviceId(0);
            SetPublisherAudioCodecType(1);
            SetPublisherMute(is_mute);
            SetEchoCancellation(0, 0);
            SetNoiseSuppression(0);
            SetAGC(0);
            SetVAD(0);
            SetInputAudioVolume(Convert.ToSingle(edit_audio_input_volume_));
        }

4. 数据采集

摄像头和屏幕的数据采集,还是调用原生的SDK接口,本文不再赘述,如果需要采集Unity窗体的数据,可以用参考以下代码:

        if ( texture_ == null || video_width_ != Screen.width || video_height_ != Screen.height)
        {
            Debug.Log("OnPostRender screen changed++ scr_width: " + Screen.width + " scr_height: " + Screen.height);

            if (screen_image_ != IntPtr.Zero)
            {
                Marshal.FreeHGlobal(screen_image_);
                screen_image_ = IntPtr.Zero;
            }

            if (texture_ !=  null)
            {
                UnityEngine.Object.Destroy(texture_);
                texture_ = null;
            }

            video_width_ = Screen.width;
            video_height_ = Screen.height;

            texture_ = new Texture2D(video_width_, video_height_, TextureFormat.BGRA32, false);

            screen_image_ = Marshal.AllocHGlobal(video_width_ * 4 * video_height_);

            Debug.Log("OnPostRender screen changed--");

            return;
        }

        texture_.ReadPixels(new Rect(0, 0, video_width_, video_height_), 0, 0, false);
        texture_.Apply();

从 texture里面,通过调用 GetRawTextureData(),获取到原始数据。

5. 数据对接

获取到数据后,通过调用 OnPostRGBAData()接口,传递给SDK层。

6. 本地数据预览

        public bool StartPreview()
        {
            if(CheckPublisherHandleAvailable() == false)
                return false;

            video_preview_image_callback_ = new NT_PB_SDKVideoPreviewImageCallBack(SDKVideoPreviewImageCallBack);

            NTSmartPublisherSDK.NT_PB_SetVideoPreviewImageCallBack(publisher_handle_, (int)NTSmartPublisherDefine.NT_PB_E_IMAGE_FORMAT.NT_PB_E_IMAGE_FORMAT_RGB32, IntPtr.Zero, video_preview_image_callback_);

            if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_StartPreview(publisher_handle_, 0, IntPtr.Zero))
            {
                if (0 == publisher_handle_count_)
                {
                    NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                    publisher_handle_ = IntPtr.Zero;
                }

                return false;
            }

            publisher_handle_count_++;

            is_previewing_ = true;

            return true;
        }

设置preview后,处理preview的数据回调

        //预览数据回调
        public void SDKVideoPreviewImageCallBack(IntPtr handle, IntPtr user_data, IntPtr image)
        {
            NT_PB_Image pb_image = (NT_PB_Image)Marshal.PtrToStructure(image, typeof(NT_PB_Image));

            NT_VideoFrame pVideoFrame = new NT_VideoFrame();

            pVideoFrame.width_ = pb_image.width_;
            pVideoFrame.height_ = pb_image.height_;

            pVideoFrame.stride_ = pb_image.stride_[0];

            Int32 argb_size = pb_image.stride_[0] * pb_image.height_;

            pVideoFrame.plane_data_ = new byte[argb_size];
            
            if (argb_size > 0)
            {
                Marshal.Copy(pb_image.plane_[0],pVideoFrame.plane_data_,0, argb_size);
            }

            {
                cur_image_ = pVideoFrame;
            }
        }      

7. 相关event回调处理

        private void PbEventCallBack(IntPtr handle, IntPtr user_data, 
            UInt32 event_id,
            Int64 param1,
            Int64 param2,
            UInt64 param3,
            UInt64 param4,
            [MarshalAs(UnmanagedType.LPStr)] String param5,
            [MarshalAs(UnmanagedType.LPStr)] String param6,
            IntPtr param7)
        {
            String event_log = "";

            switch (event_id)
            {
                case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CONNECTING:
                    event_log = "连接中";
                    if (!String.IsNullOrEmpty(param5))
                    {
                        event_log = event_log + " url:" + param5;
                    }
                    break;

                case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CONNECTION_FAILED:
                    event_log = "连接失败";
                    if (!String.IsNullOrEmpty(param5))
                    {
                        event_log = event_log + " url:" + param5;
                    }
                    break;

                case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_CONNECTED:
                    event_log = "已连接";
                    if (!String.IsNullOrEmpty(param5))
                    {
                        event_log = event_log + " url:" + param5;
                    }
                    break;

                case (uint)NTSmartPublisherDefine.NT_PB_E_EVENT_ID.NT_PB_E_EVENT_ID_DISCONNECTED:
                    event_log = "断开连接";
                    if (!String.IsNullOrEmpty(param5))
                    {
                        event_log = event_log + " url:" + param5;
                    }
                    break;

                default:
                    break;
            }

            if(OnLogEventMsg != null) OnLogEventMsg.Invoke(event_id, event_log);
        }

8. 开始推送、停止推送

       public bool StartPublisher(String url)
        {
            if (CheckPublisherHandleAvailable() == false) return false;

            if (publisher_handle_ == IntPtr.Zero)
            {
                return false;
            }
            if (!String.IsNullOrEmpty(url))
            {
                NTSmartPublisherSDK.NT_PB_SetURL(publisher_handle_, url, IntPtr.Zero);
            }

            if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_StartPublisher(publisher_handle_, IntPtr.Zero))
            {
                if (0 == publisher_handle_count_)
                {
                    NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                    publisher_handle_ = IntPtr.Zero;
                }

                is_publishing_ = false;

                return false;
            }

            publisher_handle_count_++;

            is_publishing_ = true;

            return true;
        }

        public void StopPublisher()
        {
            if (is_publishing_ == false) return;

            publisher_handle_count_--;
            NTSmartPublisherSDK.NT_PB_StopPublisher(publisher_handle_);

            if (0 == publisher_handle_count_)
            {
                NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                publisher_handle_ = IntPtr.Zero;
            }

            is_publishing_ = false;
        }

9. 关闭实例

        public void Close()
        {
            if (0 == publisher_handle_count_)
            {
                NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
                publisher_handle_ = IntPtr.Zero;
            }
        }

总结

经测试,Unity环境下,通过高效率的数据采集、编码和推送,配合SmartPlayer播放器播放,整体延迟可控制在毫秒级,可适用于大多数Unity环境下对延迟和稳定性要求苛刻的场景。

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

Windows平台实现Unity下窗体 的相关文章

  • GB28181-2022相对2016版“基于TCP协议的视音频媒体传输要求“调整

    规范解读 GB28181 2022针对 基于TCP协议的视音频媒体传输 实时点播 历史视频回放与下载中 TCP媒体传输重连机制 做了说明 修改后的 基于TCP协议的视音频媒体传输要求 如下 实时视频点播 历史视频回放与下载的TCP媒体传输应
  • 可用的公开 RTSP/ RTMP 在线视频流资源地址(亲测可行)

    可用的公开 RTSP RTMP 在线视频流资源地址 亲测可行 时间节点 2023 01 23 rtsp rtsp wowzaec2demo streamlock net vod mp4 BigBuckBunny 115k mp4 rtmp
  • Android GB28181设备接入端语音广播和语音对讲技术实现探究

    上篇文章提到Android端GB28181接入端的语音广播和语音对讲的实现 从spec角度大概介绍了下流程和简单的接口设计 好多开发者私信我 希望展开说一下 其实这块难度不大 只是广播和对讲涉及到双向实现 如果之前没有相关的积累 从头实现麻
  • GB/T28181-2022协议版本标识X-GB-Ver解读

    GB28181 2022相对2016 其中有个变化是 报文中携带协议版本标识 X GB Ver 3 0 3 0 2022 2 0 2016 为便于联网设备或服务器之间互相识别对方支持的协议版本 在SIP注册及其响应消息 无论是成功或失败 头
  • 国网B接口资源上报(Push_Resourse)接口描述和消息示例

    上篇blog 梳理了国网B接口的REGISTER接口描述和消息示例 前端系统加电启动并初次注册成功后 向平台上报前端系统的设备资源信息 包括 视频服务器 DVR DVS 摄像机 告警设备 环境量采集设备等模拟或数字信号采集设备信息 前端系统
  • 音视频绕不开的话题之WebRTC

    什么是WebRTC 闲来无事 我们今天探讨下音视频绕不开的一个话题 WebRTC WebRTC之于音视频行业 无异于FFMpeg 可以说WebRTC的开源 让音视频行业大跨步进入发展快车道 WebRTC是一个支持实时音视频通信的开源项目 它
  • Windows平台实现Unity下窗体

    技术背景 随着Unity3D的应用范围越来越广 越来越多的行业开始基于Unity3D开发产品 如传统行业中虚拟仿真教育 航空工业 室内设计 城市规划 工业仿真等领域 基于此 好多开发者苦于在Unity环境下 没有低延迟的推拉流解决方案 前几
  • Android平台GB28181设备接入端如何实现本地录像?

    实现Android平台GB28181设备接入的时候 有个功能点不可避免 那就是本地录像 实际上 在实现GB28181设备接入模块之前 我们前些年做RTMP推送和轻量级RTSP服务的时候 早已经实现了本地录像功能 本地录像功能 我们实现的主要
  • librtmp ssl 1.0.0 到 ssl 1.1.1

    openssl 版本更新了 导致 librtmp 库不能使用 于是查查资料 Compiler errors dereferencing pointer to incomplete type DH aka struct dh st 根据上面的
  • Red5应用开发(二)直播串流与录制

    环境 操作系统 win10 1803 Eclipse版本 4 7 3a Oxygen J2EE版本 Red5 Server版本 1 0 8 Release 环境搭建参考前一篇文章 Red5应用开发 一 开发环境搭建 后续不再涉及red5 f
  • 国家开源软件资源库

    http yp oss org cn software show cat php cat id 5 基本信息 成熟度 Dimdim 2009 05 19 1 2 3 4 5 6 7
  • GB28181媒体保活机制探究与实现

    规范解读 GB28181 2016和GB28181 2022关于媒体保活机制这块 并无调整 平台 设备媒体流保活机制规定如下 a 链路建立后 码流经过的各级平台应具备媒体流丢失监测能力 若监测到媒体流丢失 应释放该条媒体链路 并通过会话内B
  • FFmpeg学习(11)——视频转码之-crf参数详解

    什么是固定码率因子crf Constant Rate Factor 固定码率因子 CRF 是 x264 和 x265 编码器的默认质量 和码率控制 设置 取值范围是 0 到 51 这其中越低的值 结果质量越好 同时输出文件越大 越高的值意味
  • Android平台GB28181设备接入端如何调节实时音量?

    我们在对接Android平台GB28181设备接入端的时候 有开发者提出这样的疑惑 如何调整设备接入端的实时音量 实际上 这块我们前几年在做RTMP直播推送模块的时候 已经发布了相关的接口 这里再回顾下 SmartPublisherJniV
  • RTP时间戳概念

    RTP协议不依赖于底层协议 由于UDP包的快速 时实性高的特点 它通常和UDP结合在一起 作为UDP的上层载体数据的形式传播 typedef struct rtp header t uint32 t v 2 protocol version
  • GB/T28181-2022图像抓拍规范解读及技术实现

    规范解读 GB28181 2022相对2016 增加了设备软件升级 图像抓拍信令流程和协议接口 我们先回顾下规范说明 图像抓拍基本要求 源设备向目标设备发送图像抓拍配置命令 携带传输路径 会话ID等信息 目标设备完成图像传输后 发送图像抓拍
  • 视频编码格式发展史

    1 编码标准之战 想预测未来 就回顾历史 先来看看H 264这些编码的从标准化到现在普及的过程 人们一直在想尽办法提高视频编码的效率 让它在尽可能小的体积内提供最好的画面质量 从而满足人们对于视频传输 存储的需求 长期以来 视频编码标准主要
  • GB28181控制、传输流程和协议接口之注册

    注册和注销基本要求 SIP客户端 网关 SIP设备 联网系统等 SIP代理 SIP UA 使用IETFRFC3261中定义的方法 15 GB T28181 2016Register进行注册和注销 注册和注销时应进行认证 认证方式应支持数字摘
  • RTP/RTCP/RTSP负载H264的一些问题小结

    以下内容都是基于rfc3984 RTP负载H264时的参数配置 1 在TCP传输时 Transport头中的interleaved参数必须设置 比如0 1 或者2 3 海康的流中出现了4 但是没有配置 所以wireshark也无法解析cha
  • 深入理解Google Cast(一)基本概念

    什么是google cast google cast允许用户将手机上的内容投影到TV上 然后用户可以将手机作为遥控器来控制TV上的媒体播放 Google cast SDK用于扩展你的app 使其支持google cast功能 一个Cast

随机推荐

  • 测试人员掌握基本Linux命令——查看日志(实时日志)

    很多初级测试人员 在进行执行测试用例这个步骤时 发现bug 不能更加的准确去定位bug 在这样的情况下就可以打开Linux服务器 敲命令查看操作进行中的实时日志 当系统报错时 可以截图日志在缺陷管理系统中 开发人员就知道什么地方错了 操作步
  • rocksdb原理_ceph性能调优历程-rocksdb篇(1)

    最近调优及其他工作实在太忙 没有太多时间写心得 今天抽空来总结一下阶段性成果吧 从一开始的ceph调研 系统调优开始 ceph集群存储大规模数据之后 集群文件数超过2亿 rgw并发写性能下降的问题一直困扰我们 终于在最近找到了原因及相关解决
  • C++primer Plus 第七章复习题

    1 使用函数的3个步骤是什么 定义函数 提供原型 调用函数 2 请创建与下面的描述匹配的函数原型 igor 没有参数 且没有返回值 void igor tofu 接受一个int参数 并返回一个float float tofu int mpg
  • 去除discuz手机版链接&mobile=2后缀

    discuz手机版链接自动添加 mobile 2 导致百度收录的手机版链接无法打开 解决思路 1 打开 source class helper helper mobile php文件搜索下面代码 约在22行 content preg rep
  • malloc的底层实现(ptmalloc)

    前言 本文主要介绍了ptmalloc对于内存分配的管理 结合网上的一些文章和个人的理解 对ptmalloc的实现原理做一些总结 内存布局 介绍ptmalloc之前 我们先了解一下内存布局 以x86的32位系统为例 从上图可以看到 栈至顶向下
  • 【深度学习】_amax() got an unexpected keyword argument ‘dim‘ 解决方案

    在定义一个点云数据pc后 想使用pc max dim 0 然后出现了 amax got an unexpected keyword argument dim 这个是因为对于tensor类型的数据和ndarray类型的数据都有一个max mi
  • 彻底搞懂字符编码ASCII,GB2312,UNICODE,UTF-8

    文章目录 基础 什么是字符编码 正文 ASCII ASCII扩展码 GB2312 GBK DBCS UNICODE UTF 8 UTF 16 USC 2 UTF 32 USC 4 编程语言对字符编码的支持 阅读了一篇关于编码的博客 点击打开
  • Matlab实现PSO算法(附上10个完整仿真源码)

    PSO Particle Swarm Optimization 是一种优化算法 它模拟了鸟群或鱼群等动物的集体行为 通过群体智能的方式来解决优化问题 PSO算法最初由Kennedy和Eberhart在1995年提出 近年来得到了广泛的应用
  • 区块链上的订阅

    为分散式应用程式 以太坊 实施订阅模型 Luca Bravo在Unsplash上拍摄的背景照片 以太坊徽标 火种金标志 介绍 您可能已经听说过 去中心化的应用程序将成为互联网的未来 为了使这个分散的生态系统蓬勃发展并可持续发展 我们将需要许
  • 人工智能数学基础---定积分2:定积分的性质

    一 引言 在 人工智能数学基础 定积分1 定积分的概念以及近似计算 介绍了定积分的概念 几何意义 用定义来求定积分的案例以及使用矩形法 梯形法和抛物线法求定积分近似值的方法和案例等基础知识 根据上文的介绍 结合相关知识补充如下2条规则 可以
  • #pragma once 与#ifndef 的区别解析

    原文地址 http blog csdn net hkx1n article details 4313303 作用 为了避免同一个文件被include多次 C C 中有两种方式 一种是 ifndef方式 一种是 pragma once方式 在
  • linux 查看文件的inode使用情况

    linux 查看文件的inode使用情况 查看文件的空间使用情况 root racdb01 df h Filesystem Size Used Avail Use Mounted on dev mapper vg lgoracle lv r
  • Hutool工具BeanUtil.copyProperties实现自定义类型转换器之字符串转时间格式化

    hutool工具BeanUtil copyProperties在字符串转LocalDateTime时默认用的格式为yyyy MM ddTHH mm ss 所以需要自定义转换器才行 在转换时会优先使用自定义的 在项目启动时执行一次此段代码即可
  • Vue-cli 与Vite 环境搭建与项目构建

    Vue cli 与Vite 环境搭建与项目构建 在之前的语法演示中 我们直接使用 script 引入 Vue 3 从而在浏览器里实现了所有调试功能 但是在实际的项目中 我们会使用专门的调试工具 在项目上线之前 代码也需要打包压缩 并且考虑到
  • $.extend插件的开发与代码的编写

    extend插件的开发与代码的编写 extend item 该方法是将item合并到Jquery的全局对象中去 相当于为Jquery全局对象添加了一个静态方法 extend SayHello function value alert hel
  • Golang(Go语言)内置函数之append

    append主要用于给某个切片 slice 追加元素 如果该切片存储空间 cap 足够 就直接追加 长度 len 变长 如果空间不足 就会重新开辟内存 并将之前的元素和新的元素一同拷贝进去 第一个参数为切片 后面是该切片存储元素类型的可变参
  • TCP超时编程

    2018 2 12http blog csdn net NK test article details 49050379 这个是超时相关的设置 不过比较麻烦的就是 还有很多错误的设置比较难 C的却是太底层的底层的东西 http blog c
  • gcc 编译小笔记

    最近在测试编译个程序的时候发现无论如何都没法正常编译 命令行是这样的 gcc I include L lib lVU lfftw3f lvsip lfftw lfftw3f lrfftw conv1dEx c 一直报链接错误 但是库文件名字
  • python数据库框架_Python六大框架对比,Web2py略胜一筹

    Python是一门动态 面向对象语言 其最初就是作为一门面向对象语言设计的 并且在后期又加入了一些更高级的特性 除了语言本身的设计目的之外 Python标准库也是值得大家称赞的 Python甚至还自带服务器 其它方面 Python拥有足够多
  • Windows平台实现Unity下窗体

    技术背景 随着Unity3D的应用范围越来越广 越来越多的行业开始基于Unity3D开发产品 如传统行业中虚拟仿真教育 航空工业 室内设计 城市规划 工业仿真等领域 基于此 好多开发者苦于在Unity环境下 没有低延迟的推拉流解决方案 前几