Windows平台Unity Camera场景实现轻量级RTSP服务和RTMP推送

简介: 随着VR技术在医疗、军事、农业、学校、景区、消防、公共安全、研学机构、展厅展馆,商场等场所普及,开发者对Unity平台下的直播体验提出了更高的要求。

技术背景

随着VR技术在医疗、军事、农业、学校、景区、消防、公共安全、研学机构、展厅展馆,商场等场所普及,开发者对Unity平台下的直播体验提出了更高的要求。

技术实现

Unity平台下的RTMP推流、RTMP、RTSP播放前几年已经覆盖了Windows、Linux、Android、iOS平台。本文主要介绍Windows平台Unity环境下的轻量级RTSP服务。通过对外提供RTSP拉流URL的形式,供内网其他终端调用。


RTMP的技术方案,我们之前有探讨过,这里先说轻量级RTSP服务,轻量级RTSP服务,我们的设计是,可以启动一个RTSP Service,然后发布多个RTSP流实例,这个在多实例的设计,非常有价值,简单来说,一个RTSP Service下面挂载多个RTSP Stream,对外提供RTSP拉流的URL,整体设计方案如下:

1cc44f3c31eba835635e8b2568ad47bd.png

我们看看支持的音视频采集选项,其中视频这块,除了Unity下的Camera场景覆盖,还有Windows摄像头、屏幕数据,音频采集覆盖了Unity声音、扬声器、麦克风,还有混音数据。


音视频原始数据采集到后,编码注入RTSP服务和RTMP推送模块。二者可以单独使用,也可同时使用。其中轻量级RTSP服务,可实时查看链接的RTSP会话数。

ce8e02caaf4397c353508b7f70841d34.png

首先看启动RTSP service封装:

/*
 * PublisherWrapper.cs
 * Author: daniusdk.com
 */
public bool StartRtspService()
{
    if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_OpenRtspServer(ref rtsp_handle_, 0))
    {
        Debug.LogError("创建rtsp server实例失败! 请检查sdk有效性.");
        return false;
    }
    if (IntPtr.Zero == rtsp_handle_)
    {
        Debug.LogError("创建rtsp server实例失败! 请检查sdk有效性.");
        return false;
    }
    int port = 28554;
    if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_SetRtspServerPort(rtsp_handle_, port))
    {
        NTSmartPublisherSDK.NT_PB_CloseRtspServer(rtsp_handle_);
        rtsp_handle_ = IntPtr.Zero;
        Debug.LogError("设置rtsp server端口失败,请检查端口是否重复或者端口不在范围内!");
        return false;
    }
    //String user_name = "admin";
    //String password = "123456";
    //NTSmartPublisherSDK.NT_PB_SetRtspServerUserNamePassword(rtsp_handle, user_name, password);
    if (NTBaseCodeDefine.NT_ERC_OK == NTSmartPublisherSDK.NT_PB_StartRtspServer(rtsp_handle_, 0))
    {
        Debug.Log("StartRtspServer suc..");
    }
    else
    {
        NTSmartPublisherSDK.NT_PB_CloseRtspServer(rtsp_handle_);
        rtsp_handle_ = IntPtr.Zero;
        Debug.LogError("启动rtsp server失败, 请检查设置的端口是否被占用!");
        return false;
    }
    is_rtsp_service_running_ = true;
    return true;
}

停止RTSP Service:

public void StopRtspService()
{
    if (is_rtsp_service_running_ == false) return;
    NTSmartPublisherSDK.NT_PB_StopRtspServer(rtsp_handle_);
    NTSmartPublisherSDK.NT_PB_CloseRtspServer(rtsp_handle_);
    rtsp_handle_ = IntPtr.Zero;
    is_rtsp_service_running_ = false;
}

服务启动后,可以发布或停止RTSP流:

public bool StartRtspStream()
{
    if (CheckPublisherHandleAvailable() == false) return false;
    if (publisher_handle_ == IntPtr.Zero)
    {
        return false;
    }
    if (publisher_handle_count_ < 1)
    {
        SetCommonOptionToPublisherSDK();
    }
    String rtsp_stream_name = "stream1";
    NTSmartPublisherSDK.NT_PB_SetRtspStreamName(publisher_handle_, rtsp_stream_name);
    NTSmartPublisherSDK.NT_PB_ClearRtspStreamServer(publisher_handle_);
    NTSmartPublisherSDK.NT_PB_AddRtspStreamServer(publisher_handle_, rtsp_handle_, 0);
    if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_StartRtspStream(publisher_handle_, 0))
    {
        if (0 == publisher_handle_count_)
        {
            NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
            publisher_handle_ = IntPtr.Zero;
        }
        Debug.LogError("调用发布rtsp流接口失败");
        return false;
    }
    publisher_handle_count_++;
    is_rtsp_publisher_running_ = true;
    return true;
}

停止RTSP流:

public void StopRtspStream()
{
    publisher_handle_count_--;
    NTSmartPublisherSDK.NT_PB_StopRtspStream(publisher_handle_);
    if (0 == publisher_handle_count_)
    {
        NTSmartPublisherSDK.NT_PB_Close(publisher_handle_);
        publisher_handle_ = IntPtr.Zero;
    }
    is_rtsp_publisher_running_ = false;
}

获取RTSP session连接数:

public int GetRtspSessionNumbers()
{
    int num = 0;
    if (rtsp_handle_!=IntPtr.Zero)
    {
        if (NTBaseCodeDefine.NT_ERC_OK != NTSmartPublisherSDK.NT_PB_GetRtspServerClientSessionNumbers(rtsp_handle_, ref num))
        {
            Debug.LogError("Call NT_PB_GetRtspServerClientSessionNumbers failed..");
        }
    }
    return num;
}

封装部分看过后,我们看看我们Unity下调用示例:


启动、停止RTSP服务:

public void btn_rtsp_service_Click()
{
    if (publisher_wrapper_.IsRtspServiceRunning())
    {
        publisher_wrapper_.StopRtspService();
        btn_rtsp_service_.GetComponentInChildren<Text>().text = "启动RTSP服务";
        btn_rtsp_publisher_.interactable = false;
        return;
    }
    if (!publisher_wrapper_.StartRtspService())
    {
        Debug.LogError("调用StartRtspService失败..");
        return;
    }
    btn_rtsp_publisher_.interactable = true;
    btn_rtsp_service_.GetComponentInChildren<Text>().text = "停止RTSP服务";
}

发布、停止RTSP流:

public void btn_rtsp_publisher_Click()
{
    if (publisher_wrapper_.IsRtspPublisherRunning())
    {
        publisher_wrapper_.StopRtspStream();
        if (!publisher_wrapper_.IsPreviewing() && !publisher_wrapper_.IsPushingRtmp())
        {
            StopCaptureAvData();
            if (coroutine_ != null)
            {
                StopCoroutine(coroutine_);
                coroutine_ = null;
            }
        }
        btn_rtsp_service_.interactable = true;
        btn_rtsp_publisher_.GetComponentInChildren<Text>().text = "发布RTSP";
    }
    else
    {
        if (!publisher_wrapper_.IsRtspServiceRunning())
        {
            Debug.LogError("RTSP service is not running..");
            return;
        }
        if (!publisher_wrapper_.IsPreviewing() && !publisher_wrapper_.IsPushingRtmp())
        {
            publisher_wrapper_.SetVideoPushType(video_push_type_);
            publisher_wrapper_.SetAudioPushType(audio_push_type_);
        }
        publisher_wrapper_.StartRtspStream();
        if (!publisher_wrapper_.IsPreviewing() && !publisher_wrapper_.IsPushingRtmp())
        {
            StartCaptureAvData();
            coroutine_ = StartCoroutine(OnPostVideo());
        }
        btn_rtsp_publisher_.GetComponentInChildren<Text>().text = "停止RTSP";
        btn_rtsp_service_.interactable = false;
    }
}

获取RTSP Session链接数:

public void btn_get_rtsp_session_numbers_Click()
{
    if (publisher_wrapper_.IsRtspServiceRunning())
    {
        btn_get_rtsp_session_numbers_.GetComponentInChildren<Text>().text = "RTSP会话数:" + publisher_wrapper_.GetRtspSessionNumbers();
    }
}

RTMP推送、停止推送:

public void btn_start_rtmp_pusher_Click()
{
    if (publisher_wrapper_.IsPushingRtmp())
    {
        StopPushRTMP();
        btn_rtmp_pusher_.GetComponentInChildren<Text>().text = "推送RTMP";
        return;
    }
    String url = rtmp_pusher_url_.text;
    if (url.Length < 8)
    {
        publisher_wrapper_.Close();
        Debug.LogError("请输入RTMP推送地址");
        return;
    }
    if (!publisher_wrapper_.IsPreviewing() && !publisher_wrapper_.IsRtspPublisherRunning())
    {
        publisher_wrapper_.SetVideoPushType(video_push_type_);
        publisher_wrapper_.SetAudioPushType(audio_push_type_);
    }
    if (!publisher_wrapper_.StartRtmpPusher(url))
    {
        Debug.LogError("调用StartPublisher失败..");
        return;
    }
    btn_rtmp_pusher_.GetComponentInChildren<Text>().text = "停止推送";
    if (!publisher_wrapper_.IsPreviewing() && !publisher_wrapper_.IsRtspPublisherRunning())
    {
        StartCaptureAvData();
        coroutine_ = StartCoroutine(OnPostVideo());
    }
}

总结

轻量级RTSP服务和RTMP推送的区别在于,轻量级RTSP服务不需要单独部署流媒体服务器(类似于网络摄像头),在内网小并发场景下,使用起来非常方便,如果需要上公网,还是需要用RTMP推送,感兴趣的开发者可酌情参考。

相关文章
|
4月前
|
编解码 vr&ar 图形学
Unity下如何实现低延迟的全景RTMP|RTSP流渲染
随着虚拟现实技术的发展,全景视频成为新的媒体形式。本文详细介绍了如何在Unity中实现低延迟的全景RTMP或RTSP流渲染,包括环境准备、引入依赖、初始化客户端、解码与渲染、优化低延迟等步骤,并提供了具体的代码示例。适用于远程教育、虚拟旅游等实时交互场景。
122 5
|
9天前
|
API C# 图形学
Unity调用Windows弹出确认框
在 Unity 中调用 Windows 弹出确认框,可通过 Windows API 或 .NET 框架实现。使用 Windows API 的方式是通过 P/Invoke 技术调用 MessageBox 函数,创建模态对话框。代码示例展示了如何在应用退出时弹出确认框,用户选择“确定”则退出游戏。此方法也适用于 ALT+F4 触发的退出确认。
|
5月前
|
监控 Windows
Windows平台RTSP|RTMP播放器如何实时调节音量
我们在做Windows平台RTSP、RTMP播放器的时候,有这样的技术需求,特别是多路监控的时候,并不是每一路audio都需要播放出来的,所以,这时候,需要有针对音量调节的设计
|
3月前
|
编解码 vr&ar 图形学
Unity下如何实现低延迟的全景RTMP|RTSP流渲染
随着虚拟现实技术的发展,全景视频逐渐成为新的媒体形式。本文详细介绍了如何在Unity中实现低延迟的全景RTMP或RTSP流渲染,包括环境准备、引入依赖、初始化客户端、解码与渲染、优化低延迟等步骤,并提供了具体的代码示例。适用于远程教育、虚拟旅游等实时交互场景。
64 2
|
5月前
|
监控 C# 块存储
Windows平台RTSP|RTMP播放器如何叠加OSD文字
做Windows平台RTSP|RTMP播放器的时候,特别是多路播放场景下,开发者希望可以给每一路RTSP或RTMP流添加个额外的OSD台标,以区分不同的设备信息(比如添加摄像头所在位置),本文主要探讨,如何动态添加OSD台标。
Windows平台RTSP|RTMP播放器如何叠加OSD文字
|
5月前
|
Linux Android开发 iOS开发
Windows平台RTSP|RTMP播放器如何实现实时录像功能
Windows平台RTSP、RTMP播放器实时录像接口设计,实际上,除了Windows平台,我们Linux、Android、iOS平台也是一样的设计,单纯的录像模块,如果做的全面,也不是一两个接口可以搞定的
134 1
|
6月前
|
图形学 Android开发 iOS开发
穿越数字洪流,揭秘Unity3d中的视频魔法!Windows、Android和iOS如何征服RTSP与RTMP的终极指南!
【8月更文挑战第15天】在数字媒体的海洋中,实时视频流是连接世界的桥梁。对于那些渴望在Unity3d中搭建这座桥梁的开发者来说,本文将揭示如何在Windows、Android和iOS平台上征服RTSP与RTMP的秘密。我们将深入探讨这两种协议的特性,以及在不同平台上实现流畅播放的技巧。无论你是追求稳定性的RTSP拥趸,还是低延迟的RTMP忠实粉丝,这里都有你需要的答案。让我们一起穿越数字洪流,探索Unity3d中视频魔法的世界吧!
115 2
|
6月前
|
编解码 开发工具 数据安全/隐私保护
如何快速实现Windows平台屏幕摄像头采集并推送RTMP|轻量级RTSP服务能力?
一个好的推送模块,除了实现高效率的编码传输外,还要有好的音视频采集机制和灵活的架构支持,便于后期功能扩展,比如实时快照、预览、实时录像等。除此之外,还要有好的交互机制(比如envent callback)、低延迟和长期运行稳定的性能。
103 0
|
6月前
|
图形学 C#
超实用!深度解析Unity引擎,手把手教你从零开始构建精美的2D平面冒险游戏,涵盖资源导入、角色控制与动画、碰撞检测等核心技巧,打造沉浸式游戏体验完全指南
【8月更文挑战第31天】本文是 Unity 2D 游戏开发的全面指南,手把手教你从零开始构建精美的平面冒险游戏。首先,通过 Unity Hub 创建 2D 项目并导入游戏资源。接着,编写 `PlayerController` 脚本来实现角色移动,并添加动画以增强视觉效果。最后,通过 Collider 2D 组件实现碰撞检测等游戏机制。每一步均展示 Unity 在 2D 游戏开发中的强大功能。
328 6
|
6月前
|
图形学 缓存 算法
掌握这五大绝招,让您的Unity游戏瞬间加载完毕,从此告别漫长等待,大幅提升玩家首次体验的满意度与留存率!
【8月更文挑战第31天】游戏的加载时间是影响玩家初次体验的关键因素,特别是在移动设备上。本文介绍了几种常见的Unity游戏加载优化方法,包括资源的预加载与异步加载、使用AssetBundles管理动态资源、纹理和模型优化、合理利用缓存系统以及脚本优化。通过具体示例代码展示了如何实现异步加载场景,并提出了针对不同资源的优化策略。综合运用这些技术可以显著缩短加载时间,提升玩家满意度。
538 5