Unity3D下如何采集camera场景数据并推送RTMP服务?

简介: Unity3D是非常流行的游戏开发引擎,可以创建各种类型的3D和2D游戏或其他互动应用程序。常见使用场景如下:

Unity3D使用场景

Unity3D是非常流行的游戏开发引擎,可以创建各种类型的3D和2D游戏或其他互动应用程序。常见使用场景如下:


  1. 游戏开发:Unity3D是一个广泛用于游戏开发的环境,适用于创建各种类型的游戏,包括动作游戏、角色扮演游戏、策略游戏、冒险游戏等。
  2. 虚拟现实:Unity3D也常用于虚拟现实(VR)开发,它提供了对VR设备的支持,如Oculus Rift和HTC Vive。
  3. 交互式演示:Unity3D可以用于创建各种类型的交互式演示,如产品原型、建筑和设计模拟器、教育应用程序等。
  4. 实时渲染:Unity3D的实时渲染功能可以用于创建电影级的特效和动画,以及用于视觉预览和产品渲染。
  5. 跨平台开发:Unity3D支持多个平台,包括PC、Mac、Linux、Android、iOS、Windows等,这使得开发者可以更容易地将他们的应用程序和游戏移植到不同的平台。


无论你是在哪个领域使用Unity3D,都需要了解其基本的工具和功能,包括场景编辑器、游戏对象、组件、脚本等。同时,还需要掌握一些基本的编程语言,如C#,以编写游戏逻辑和控制流程。

如何获取Camera场景数据

Unity3D获取摄像机数据通常用RenderTexture和RenderTexture.GetPixel方法来获取数据,把捕获屏幕的图像,存储在一个Texture2D实例中,用这个实例获取RGB数据。需要注意的是,需要为输出纹理创建一个新的纹理对象,否则可能会在屏幕上看到一片空白。示例代码如下:

using UnityEngine;  
public class GetCameraData : MonoBehaviour  
{  
    public Texture2D outputTexture; // 输出纹理,用于存储RGB数据  
    public RenderTexture renderTexture; // RenderTexture实例,用于捕获屏幕图像  
    void Start()  
    {  
        // 创建一个RenderTexture实例  
        renderTexture = new RenderTexture(Screen.width, Screen.height, 24);  
        // 获取当前摄像机  
        Camera camera = GetComponent<Camera>();  
        // 将当前摄像机的屏幕输出设置为刚刚创建的RenderTexture实例  
        camera.targetTexture = renderTexture;  
        // 创建一个空的Texture2D实例,用于存储从RenderTexture读取的RGB数据  
        outputTexture = new Texture2D(Screen.width, Screen.height);  
    }  
    void Update()  
    {  
        // 从RenderTexture中读取RGB数据,并存储到outputTexture中  
        RenderTexture.active = renderTexture;  
        outputTexture.ReadPixels(new Rect(0, 0, Screen.width, Screen.height), 0, 0);  
        outputTexture.Apply();  
    }  
}

如何实现RTMP推送服务

本文以大牛直播SDK开发的Unity3D下Android平台的RTMP推送camera场景的demo为例,结合Unity和原生模块交互,大概介绍下核心实现逻辑。

02765e904c8a4d859a090f75f0d42c8a.jpg

开始推送RTMP服务:

    public bool StartRtmpPusher()
    {
        if (is_pushing_rtmp_)
        {
            Debug.Log("已推送..");   
            return false;
        }
        if(!is_rtsp_publisher_running_)
        {
            InitAndSetConfig();
        }
        if (pusher_handle_ == 0) {
             Debug.LogError("StartRtmpPusher, publisherHandle is null..");
            return false;
        }
        NT_PB_U3D_SetPushUrl(pusher_handle_, rtmp_push_url_);
        int is_suc = NT_PB_U3D_StartPublisher(pusher_handle_);
        if (is_suc  == DANIULIVE_RETURN_OK)
        {
            Debug.Log("StartPublisher success..");          
            is_pushing_rtmp_ = true;
        }
        else
        {
            Debug.LogError("StartPublisher failed..");
            return false;
        }
        return true;
    }


InitAndSetConfig()完成常规参数设置,比如软硬编码、帧率、码率等参数设置,如果需要采集audio,还可以把麦克风采集到的audio和audioclip获取到的audio数据mix后输出:

    private void InitAndSetConfig()
    {
        if ( java_obj_cur_activity_ == null )
        {
            Debug.LogError("getApplicationContext is null");
            return;
        }
        int audio_opt = 1;
        int video_opt = 3;
        video_width_ = camera_.pixelWidth;
        video_height_ = camera_.pixelHeight;
        pusher_handle_ = NT_PB_U3D_Open(audio_opt, video_opt, video_width_, video_height_);
        if (pusher_handle_ != 0){
            Debug.Log("NT_PB_U3D_Open success");
            NT_PB_U3D_Set_Game_Object(pusher_handle_, game_object_);
        }
        else
        {
            Debug.LogError("NT_PB_U3D_Open failed!");
            return;
        }
        int fps = 30;
        int gop = fps * 2;
        if(video_encoder_type_ == (int)PB_VIDEO_ENCODER_TYPE.VIDEO_ENCODER_HARDWARE_AVC)
        {
            int h264HWKbps = setHardwareEncoderKbps(true, video_width_, video_height_);
            h264HWKbps = h264HWKbps * fps / 25;
            Debug.Log("h264HWKbps: " + h264HWKbps);
            int isSupportH264HWEncoder = NT_PB_U3D_SetVideoHWEncoder(pusher_handle_, h264HWKbps);
            if (isSupportH264HWEncoder == 0) {
                NT_PB_U3D_SetNativeMediaNDK(pusher_handle_, 0);
                NT_PB_U3D_SetVideoHWEncoderBitrateMode(pusher_handle_, 1); // 0:CQ, 1:VBR, 2:CBR
                NT_PB_U3D_SetVideoHWEncoderQuality(pusher_handle_, 39);
                NT_PB_U3D_SetAVCHWEncoderProfile(pusher_handle_, 0x08); // 0x01: Baseline, 0x02: Main, 0x08: High
                // NT_PB_U3D_SetAVCHWEncoderLevel(pusher_handle_, 0x200); // Level 3.1
                // NT_PB_U3D_SetAVCHWEncoderLevel(pusher_handle_, 0x400); // Level 3.2
                // NT_PB_U3D_SetAVCHWEncoderLevel(pusher_handle_, 0x800); // Level 4
                NT_PB_U3D_SetAVCHWEncoderLevel(pusher_handle_, 0x1000); // Level 4.1 多数情况下,这个够用了
                //NT_PB_U3D_SetAVCHWEncoderLevel(pusher_handle_, 0x2000); // Level 4.2
                // NT_PB_U3D_SetVideoHWEncoderMaxBitrate(pusher_handle_, ((long)h264HWKbps)*1300);
                Debug.Log("Great, it supports h.264 hardware encoder!");
            }
        }
        else if(video_encoder_type_ == (int)PB_VIDEO_ENCODER_TYPE.VIDEO_ENCODER_HARDWARE_HEVC)
        {
            int hevcHWKbps = setHardwareEncoderKbps(false, video_width_, video_height_);
            hevcHWKbps = hevcHWKbps*fps/25;
            Debug.Log("hevcHWKbps: " + hevcHWKbps);
            int isSupportHevcHWEncoder = NT_PB_U3D_SetVideoHevcHWEncoder(pusher_handle_, hevcHWKbps);
            if (isSupportHevcHWEncoder == 0) {
                NT_PB_U3D_SetNativeMediaNDK(pusher_handle_, 0);
                NT_PB_U3D_SetVideoHWEncoderBitrateMode(pusher_handle_, 0); // 0:CQ, 1:VBR, 2:CBR
                NT_PB_U3D_SetVideoHWEncoderQuality(pusher_handle_, 39);
                // NT_PB_U3D_SetVideoHWEncoderMaxBitrate(pusher_handle_, ((long)hevcHWKbps)*1200);
                Debug.Log("Great, it supports hevc hardware encoder!");
            }
        }
        else 
        {
            if (is_sw_vbr_mode_) //H.264 software encoder
            {
                int is_enable_vbr = 1;
                int video_quality = CalVideoQuality(video_width_, video_height_, true);
                int vbr_max_bitrate = CalVbrMaxKBitRate(video_width_, video_height_);
                vbr_max_bitrate = vbr_max_bitrate * fps / 25;
                NT_PB_U3D_SetSwVBRMode(pusher_handle_, is_enable_vbr, video_quality, vbr_max_bitrate);
                //NT_PB_U3D_SetSWVideoEncoderSpeed(pusher_handle_, 2);
            }
        }
        NT_PB_U3D_SetAudioCodecType(pusher_handle_, 1);
        NT_PB_U3D_SetFPS(pusher_handle_, fps);
        NT_PB_U3D_SetGopInterval(pusher_handle_, gop);
        if (audio_push_type_ == (int)PB_AUDIO_OPTION.AUDIO_OPTION_MIC_EXTERNAL_PCM_MIXER
            || audio_push_type_ == (int)PB_AUDIO_OPTION.AUDIO_OPTION_TWO_EXTERNAL_PCM_MIXER)
        {
            NT_PB_U3D_SetAudioMix(pusher_handle_, 1);
        }
        else
        {
            NT_PB_U3D_SetAudioMix(pusher_handle_, 0);
        }
    }


投递video数据的逻辑实现如下:

    void PostVideoData() {
        if(pusher_handle_ == 0)
            return;
        if(!is_pushing_rtmp_ && !is_rtsp_publisher_running_)
            return;
        if (textures_poll_ == null)
           return;
        int w = camera_.pixelWidth;
        int h = camera_.pixelHeight;
       if (w != video_width_ || h != video_height_) {
           Debug.Log("PostVideoData resolution changed++ width: " + w + " height: " + h);
           if(render_texture_ != null) {
               render_texture_.Release();
               render_texture_ = null;
           }
           video_width_  = w;
           video_height_ = h;
       }
       if (null == render_texture_ ) {
           render_texture_ = new RenderTexture(video_width_, video_height_, 16);
           render_texture_.Create();
       }
       Texture2D image_texture = textures_poll_.get(video_width_, video_height_);
        if (null == image_texture)
           return;
         ...
        image_texture.ReadPixels(new Rect(0, 0, video_width_, video_height_), 0, 0, false);
         ...
        post_image_worker_.post(image_texture, is_vertical_flip_, is_horizontal_flip_, scale_width_, scale_height_);
    }


如果需要停止RTMP推送:

    private void StopRtmpPusher()
    {
        if(!is_pushing_rtmp_)
            return;
        NT_PB_U3D_StopPublisher(pusher_handle_);
        if(!is_rtsp_publisher_running_)
        {
            NT_PB_U3D_Close(pusher_handle_);
            pusher_handle_ = 0;
            NT_PB_U3D_UnInit();
        }
        is_pushing_rtmp_ = false;
    }

技术总结

Unity3D下采集camera场景并推送RTMP具有重要的意义,可以为实时监控、在线直播、视频教程制作、增强现实和虚拟现实应用以及数据记录和分析等领域提供有力的支持。比如,采集camera场景可以用于增强现实和虚拟现实应用。在AR中,可以通过采集实际场景的画面,将虚拟元素与现实场景进行融合,增强沉浸感和互动性。

相关文章
|
4月前
|
数据采集 编解码 图形学
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
Android平台Unity下如何通过WebCamTexture采集摄像头数据并推送至RTMP服务器或轻量级RTSP服务
108 0
|
5月前
|
图形学
Unity重置场景
Unity重置场景
|
8月前
|
编解码 数据处理 vr&ar
VR头显Unity下如何实现毫秒级延迟的RTMP或RTSP播放?
VR头显Unity下如何实现毫秒级延迟的RTMP或RTSP播放?
182 1
|
8月前
|
Linux 开发工具 图形学
Unity下如何实现RTMP或RTSP播放端录像?
Unity下如何实现RTMP或RTSP播放端录像?
230 0
|
8月前
|
编解码 开发工具 图形学
Unity环境下RTMP推流+RTMP播放低延迟解决方案
在本文之前,我们发布了Unity环境下的RTMP推流(Windows平台+Android平台)和RTMP|RTSP拉流(Windows平台+Android平台+iOS平台)低延迟的解决方案,今天做个整体汇总,权当抛砖引玉。
446 0
|
8月前
|
编解码 监控 图形学
Windows平台Unity下播放RTSP或RTMP如何开启硬解码?
我们在做Windows平台Unity播放RTMP或RTSP的时候,遇到这样的问题,比如展会、安防监控等场景下,需要同时播放多路RTMP或RTSP流,这样对设备性能,提出来更高的要求。
|
8月前
|
图形学 开发者 Windows
Unity平台如何实现RTSP转RTMP推送?
Unity平台下,RTSP、RTMP播放和RTMP推送,甚至包括轻量级RTSP服务这块都不再赘述,今天探讨的一位开发者提到的问题,如果在Unity下,实现RTSP播放的同时,随时转RTMP推送出去?
|
8月前
|
Linux 图形学 Android开发
Unity3D下如何实现跨平台低延迟的RTMP、RTSP播放
好多开发者,希望我们能探讨下Unity平台RTMP或RTSP直播流数据播放和录制相关的模块,实际上,这块流程我们已经聊过多次,无非就是通过原生的RTMP或者RTSP模块,先从协议层拉取到数据,并解包解码,回调YUV或RGB数据,然后,在Unity创建响应的shader,获取图像数据填充纹理即可,说起来流程很简单,但是每个环节,如果做到极致体验,都非常难。简单来说,多一次拷贝,都会增大性能瓶颈或延迟。
|
8月前
|
数据采集 vr&ar 图形学
Windows平台Unity Camera场景实现轻量级RTSP服务和RTMP推送
随着VR技术在医疗、军事、农业、学校、景区、消防、公共安全、研学机构、展厅展馆,商场等场所普及,开发者对Unity平台下的直播体验提出了更高的要求。
|
8月前
|
Linux 开发工具 图形学
Unity下如何实现RTMP或RTSP流播放和录制
在探讨Unity平台RTMP或RTSP直播流数据播放和录制之前,我们先简单回顾下RTSP或RTMP直播流数据在Unity平台的播放流程: 1. 通过Native RTSP或RTSP直播播放SDK回调RGB/YUV420/NV12等其中的一种未压缩的图像格式; 2. Unity下创建相应的RGB/YUV420等Shader; 1. Unity从各个平台获取图像数据来填充纹理即可。
180 0