Wie sammle ich Kameraszenendaten und pushe den RTMP-Dienst unter Unity3D?

Unity3D-Nutzungsszenarien

Unity3D ist eine sehr beliebte Spieleentwicklungs-Engine, die verschiedene Arten von 3D- und 2D-Spielen oder anderen interaktiven Anwendungen erstellen kann. Häufige Nutzungsszenarien sind wie folgt:

  1. Spieleentwicklung: Unity3D ist eine Umgebung, die häufig für die Spieleentwicklung verwendet wird und sich zum Erstellen verschiedener Arten von Spielen eignet, darunter Actionspiele, Rollenspiele, Strategiespiele, Abenteuerspiele usw.
  2. Virtuelle Realität: Unity3D wird auch häufig für die Entwicklung virtueller Realität (VR) verwendet und bietet Unterstützung für VR-Geräte wie Oculus Rift und HTC Vive.
  3. Interaktive Demonstrationen: Mit Unity3D können verschiedene Arten interaktiver Demonstrationen erstellt werden, z. B. Produktprototypen, Konstruktions- und Designsimulatoren, Bildungsanwendungen usw.
  4. Echtzeit-Rendering: Die Echtzeit-Rendering-Funktionen von Unity3D können zum Erstellen filmischer Spezialeffekte und Animationen sowie für Vorab- und Produktions-Renderings genutzt werden.
  5. Plattformübergreifende Entwicklung: Unity3D unterstützt mehrere Plattformen, darunter PC, Mac, Linux, Android, iOS, Windows usw., was es Entwicklern erleichtert, ihre Anwendungen und Spiele auf verschiedene Plattformen zu portieren.

Unabhängig davon, in welchem ​​Bereich Sie Unity3D verwenden, müssen Sie seine grundlegenden Tools und Funktionen verstehen, einschließlich Szeneneditor, Spielobjekte, Komponenten, Skripte usw. Gleichzeitig müssen Sie einige grundlegende Programmiersprachen wie C# beherrschen, um Spiellogik und Kontrollfluss zu schreiben.

So erhalten Sie Kameraszenendaten

Unity3D verwendet normalerweise die Methoden RenderTexture und RenderTexture.GetPixel, um Kameradaten abzurufen, das erfasste Bildschirmbild in einer Texture2D-Instanz zu speichern und diese Instanz zum Abrufen von RGB-Daten zu verwenden. Beachten Sie, dass Sie ein neues Texturobjekt für die Ausgabetextur erstellen müssen, da sonst möglicherweise ein leerer Bildschirm angezeigt wird. Der Beispielcode lautet wie folgt:

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

So implementieren Sie den RTMP-Push-Dienst

In diesem Artikel wird als Beispiel die von Daniu Live SDK entwickelte Demo der RTMP-Push-Kameraszene der Android-Plattform unter Unity3D verwendet und die Kernimplementierungslogik basierend auf der Interaktion zwischen Unity und nativen Modulen kurz vorgestellt.

Beginnen Sie mit dem Pushen des RTMP-Dienstes:

    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 () vervollständigt die allgemeinen Parametereinstellungen, wie z. B. weiche und harte Codierung, Bildrate, Coderate und andere Parametereinstellungen. Wenn Sie Audio sammeln müssen, können Sie auch das vom Mikrofon gesammelte Audio und die von Audioclip erhaltenen Audiodaten mischen und Ausgabe:

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

Die Logik zur Bereitstellung von Videodaten ist wie folgt implementiert:

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

Wenn Sie den RTMP-Push stoppen müssen:

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

Technische Zusammenfassung

Es ist von großer Bedeutung, Kameraszenen zu sammeln und RTMP unter Unity3D zu pushen, was eine starke Unterstützung für Echtzeitüberwachung, Online-Live-Übertragung, Video-Tutorial-Produktion, Augmented-Reality- und Virtual-Reality-Anwendungen sowie Datenaufzeichnung und -analyse bieten kann. Beispielsweise kann die Erfassung von Kameraszenen in Augmented-Reality- und Virtual-Reality-Anwendungen eingesetzt werden. In AR können virtuelle Elemente in reale Szenen integriert werden, indem Bilder tatsächlicher Szenen gesammelt werden, um das Eintauchen und die Interaktivität zu verbessern.

Guess you like

Origin blog.csdn.net/renhui1112/article/details/132620958