如何在Unity3d下实现RTMP推送摄像头/屏幕数据到RTMP服务器

简介:

一直以来,好多开发者苦于很难在unity3d下实现RTMP直播推送,本次以大牛直播SDK(Github)的Windows平台RTMP推送模块(以推摄像头为例,如需推屏幕数据,设置相关参数即可)为例,介绍下unity3d的RTMP推送集成。

简单来说,Unity3D环境下,可以直接调用C#的接口封装,针对此,我们先做了一层封装 (nt_publisher_wrapper.cs),核心代码如下:

初始化和基础参数设置:

   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;
    }

    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;
        }
    }
    private void SetCommonOptionToPublisherSDK()
    {
        if (!IsPublisherHandleAvailable())
        {
            Debug.Log("SetCommonOptionToPublisherSDK, publisher handle with null..");
            return;
        }

        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_, cap.width_, cap.height_));

        SetVideoEncoderType(is_h264_encoder ? 1 : 2);

        SetVideoQualityV2(CalVideoQuality(cap.width_, cap.height_, is_h264_encoder));

        SetVideoMaxBitRate((CalMaxKBitRate(edit_key_frame_, cap.width_, cap.height_, false)));

        SetVideoKeyFrameInterval((edit_key_frame_));

        if (is_h264_encoder)
        {
            SetVideoEncoderProfile(1);

        }

        SetVideoEncoderSpeed(CalVideoEncoderSpeed(cap.width_, cap.height_, is_h264_encoder));

        // 音频相关设置

        SetAuidoInputDeviceId(0);

        SetPublisherAudioCodecType(1);

        SetPublisherMute(is_mute);

        SetInputAudioVolume(Convert.ToSingle(edit_audio_input_volume_));
    }

预览、停止预览:

   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;
    }

    public void StopPreview()
    {
        if (is_previewing_ == false) return;

        is_previewing_ = false;

        publisher_handle_count_--;
        NTSmartPublisherSDK.NT_PB_StopPreview(publisher_handle_);

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

开始推送、停止推送:

    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;
    }

相关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);
    }

SmartPublishWinMono.cs 调用上述封装的代码即可,本地预览的话,拿到回调的RGB数据,在unity3d上层刷下即可,如下图:

win_unity_publisher

经测试,unity3d下,RTMP推送,配合RTMP播放端,依然可以实现毫秒级延迟的推拉流体验。

目录
相关文章
|
2月前
|
编解码 vr&ar 图形学
Unity下如何实现低延迟的全景RTMP|RTSP流渲染
随着虚拟现实技术的发展,全景视频成为新的媒体形式。本文详细介绍了如何在Unity中实现低延迟的全景RTMP或RTSP流渲染,包括环境准备、引入依赖、初始化客户端、解码与渲染、优化低延迟等步骤,并提供了具体的代码示例。适用于远程教育、虚拟旅游等实时交互场景。
78 5
|
1月前
|
XML 前端开发 JavaScript
PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑
本文深入探讨了PHP与Ajax在Web开发中的交互技术。PHP作为服务器端脚本语言,处理数据和业务逻辑;Ajax则通过异步请求实现页面无刷新更新。文中详细介绍了两者的工作原理、数据传输格式选择、具体实现方法及实际应用案例,如实时数据更新、表单验证与提交、动态加载内容等。同时,针对跨域问题、数据安全与性能优化提出了建议。总结指出,PHP与Ajax的结合能显著提升Web应用的效率和用户体验。
46 3
|
1月前
|
编解码 vr&ar 图形学
Unity下如何实现低延迟的全景RTMP|RTSP流渲染
随着虚拟现实技术的发展,全景视频逐渐成为新的媒体形式。本文详细介绍了如何在Unity中实现低延迟的全景RTMP或RTSP流渲染,包括环境准备、引入依赖、初始化客户端、解码与渲染、优化低延迟等步骤,并提供了具体的代码示例。适用于远程教育、虚拟旅游等实时交互场景。
33 2
|
24天前
|
存储 运维 算法
服务器数据恢复—raid6阵列硬盘重组raid5阵列如何恢复raid6阵列数据?
服务器存储数据恢复环境: 存储中有一组由12块硬盘组建的RAID6阵列,上层linux操作系统+EXT3文件系统,该存储划分3个LUN。 服务器存储故障&分析: 存储中RAID6阵列不可用。为了抢救数据,运维人员使用原始RAID中的部分硬盘重新组建RAID并进行了初始化。 初始化开始一段时间后,运维人员察觉到情况有异后强制终止初始化,这个时候初始化已经完成一半以上。数据部分已被不可逆的破坏。
|
2月前
|
存储 数据挖掘
服务器数据恢复—用RAID5阵列中部分盘重建RAID5如何恢复原raid5阵列数据?
服务器数据恢复环境: 一台服务器挂接一台存储,该存储中有一组由5块硬盘组建的RAID5阵列。 服务器故障: 存储raid5阵列中有一块硬盘掉线。由于RAID5的特性,阵列并没有出现问题。工作一段时间后,服务器出现故障,用户方请人维修。维修人员在没有了解故障磁盘阵列环境的情况下,用另外4块硬盘(除去掉线的硬盘)重新创建了一组全新的RAID5阵列并完成数据同步,导致原raid5阵列数据全部丢失。
|
3月前
|
存储 弹性计算 缓存
阿里云服务器ECS通用型实例规格族特点、适用场景、指标数据解析
阿里云服务器ECS提供了多种通用型实例规格族,每种规格族都针对不同的计算需求、存储性能、网络吞吐量和安全特性进行了优化。以下是对存储增强通用型实例规格族g8ise、通用型实例规格族g8a、通用型实例规格族g8y、存储增强通用型实例规格族g7se、通用型实例规格族g7等所有通用型实例规格族的详细解析,包括它们的核心特点、适用场景、实例规格及具体指标数据,以供参考。
阿里云服务器ECS通用型实例规格族特点、适用场景、指标数据解析
|
3月前
|
存储 弹性计算 安全
阿里云服务器ECS计算型实例规格族特点、适用场景、指标数据参考
阿里云服务器ECS提供了丰富的计算型实例规格族,专为满足不同场景下的高性能计算需求而设计。包括计算型实例规格族c8y、计算型实例规格族c7、计算型实例规格族c8i等热门计算型实例规格,以及网络增强型的c7nex、密集计算型的ic5等其他计算型实例规格,每一种规格族都经过精心优化,确保在计算性能、存储效率、网络吞吐和安全特性等方面达到最佳平衡。本文将详细解析阿里云服务器ECS中的多个计算型实例规格族,包括它们的核心特点、适用场景、实例规格及具体指标数据,为用户在云计算资源选型时提供全面参考。
阿里云服务器ECS计算型实例规格族特点、适用场景、指标数据参考
|
2月前
|
Python
Flask学习笔记(三):基于Flask框架上传特征值(相关数据)到服务器端并保存为txt文件
这篇博客文章是关于如何使用Flask框架上传特征值数据到服务器端,并将其保存为txt文件的教程。
34 0
Flask学习笔记(三):基于Flask框架上传特征值(相关数据)到服务器端并保存为txt文件
|
2月前
|
SQL 分布式计算 关系型数据库
Hadoop-21 Sqoop 数据迁移工具 简介与环境配置 云服务器 ETL工具 MySQL与Hive数据互相迁移 导入导出
Hadoop-21 Sqoop 数据迁移工具 简介与环境配置 云服务器 ETL工具 MySQL与Hive数据互相迁移 导入导出
90 3
|
2月前
|
弹性计算 Linux 数据库
阿里云国际版如何迁移Linux云服务器系统盘中的数据
阿里云国际版如何迁移Linux云服务器系统盘中的数据