Android实现Unity3D下RTMP推送的示例

目录
  • 数据采集推送
  • 简单调用流程
  • 完成接口初始化后,调用Push()接口
  • 调用OpenPusher()
  • InitAndSetConfig()
  • ClosePusher()
  • 相关Event处理
  • 总结

关于屏幕采集,有两种方案:

1. 直接封装Android原生的屏幕采集工程,在unity提供接口,拿到屏幕权限后,获取屏幕数据并推送;

2. 如果只需要拿到Unity的窗体或摄像机数据推出去,可在Unity下获取到需要推送的原始数据,然后封装原生的RTMP推流接口,调用原生SDK实现数据推送,这种做法的好处是,可以自定义需要采集的数据内容,只要按照原生SDK提供的接口,完成数据对接即可,具体实现参看本文。

本文以Android平台为例,介绍下Unity环境下的Android平台RTMP推流,数据采集在Unity完成,数据编码推送,调用大牛直播SDK(官方)Android平台RTMP直播推送SDK原生库对外二次封装的接口,高效率的实现RTMP推送。废话多说,先上图看效果。

下图系Android平台Unity环境下采集屏幕,编码推送到RTMP服务器,然后Windows平台播放器拉取RTMP流播放,为了方便看到延迟效果,特地在Android端的Unity窗口显示了当前时间,可以看到,整体延迟在毫秒级:

数据采集推送

unity数据采集相对简单,可以很轻松的拿到RGB24的数据:

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

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

texture_.Apply();

然后通过调用texture_.GetRawTextureData(); 获取到数据即可。

拿到数据后,调用原生SDK封装的NT_PB_U3D_OnCaptureVideoRGB24PtrData()接口,完成数据投递。

简单调用流程

    private void Start()
    {
        game_object_ = this.gameObject.name;

        AndroidJavaClass android_class = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
        java_obj_cur_activity_ = android_class.GetStatic<AndroidJavaObject>("currentActivity");
        pusher_obj_ = new AndroidJavaObject("com.daniulive.smartpublisher.SmartPublisherUnity3d");

        NT_PB_U3D_Init();

        //NT_U3D_SetSDKClientKey("", "", 0);

        btn_encode_mode_.onClick.AddListener(OnEncodeModeBtnClicked);

        btn_pusher_.onClick.AddListener(OnPusherBtnClicked);

        btn_mute_.onClick.AddListener(OnMuteBtnClicked);
    }

完成接口初始化后,调用Push()接口

    public void Push()
    {
        if (is_running)
        {
            Debug.Log("已推送..");
            return;
        }

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

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

        scale_width_ = (video_width_ + 1) / 2;
        scale_height_ = (video_height_ + 1) / 2;

        if (scale_width_ % 2 != 0)
        {
            scale_width_ = scale_width_ + 1;
        }

        if (scale_height_ % 2 != 0)
        {
            scale_height_ = scale_height_ + 1;
        }

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

        //获取输入框的url
        string url = input_url_.text.Trim();

        if (!url.StartsWith("rtmp://"))
        {
            push_url_ = "rtmp://192.168.0.199:1935/hls/stream1";
        }
        else
        {
            push_url_ = url;
        }

        OpenPusher();

        if (pusher_handle_ == 0)
            return;

        NT_PB_U3D_Set_Game_Object(pusher_handle_, game_object_);

        /* ++ 推送前参数配置可加在此处 ++ */

        InitAndSetConfig();

        NT_PB_U3D_SetPushUrl(pusher_handle_, push_url_);
        /* -- 推送前参数配置可加在此处 -- */

        int flag = NT_PB_U3D_StartPublisher(pusher_handle_);

        if (flag  == DANIULIVE_RETURN_OK)
        {
            Debug.Log("推送成功..");
        }
        else
        {
            Debug.LogError("推送失败..");
        }

        is_running = true;
    }

调用OpenPusher()

    private void OpenPusher()
    {
        if ( java_obj_cur_activity_ == null )
        {
            Debug.LogError("getApplicationContext is null");
            return;
        }

        int audio_opt = 1;
        int video_opt = 1;

        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");
        else
            Debug.LogError("NT_PB_U3D_Open fail");
    }

InitAndSetConfig()

    private void InitAndSetConfig()
    {
        if (is_hw_encode_)
        {
            int h264HWKbps = setHardwareEncoderKbps(true, video_width_, video_height_);

            Debug.Log("h264HWKbps: " + h264HWKbps);

            int isSupportH264HWEncoder = NT_PB_U3D_SetVideoHWEncoder(pusher_handle_, h264HWKbps);

            if (isSupportH264HWEncoder == 0)
            {
                Debug.Log("Great, it supports h.264 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_);

                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_, 25);

        NT_PB_U3D_SetGopInterval(pusher_handle_, 25*2);

        //NT_PB_U3D_SetSWVideoBitRate(pusher_handle_, 600, 1200);
    }

ClosePusher()

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

        int flag = NT_PB_U3D_StopPublisher(pusher_handle_);

        if (flag == DANIULIVE_RETURN_OK)
        {
            Debug.Log("停止成功..");
        }
        else
        {
            Debug.LogError("停止失败..");
        }

        flag = NT_PB_U3D_Close(pusher_handle_);

        if (flag == DANIULIVE_RETURN_OK)
        {
            Debug.Log("关闭成功..");
        }
        else
        {
            Debug.LogError("关闭失败..");
        }

        pusher_handle_ = 0;

        NT_PB_U3D_UnInit();

        is_running = false;
    }

为了便于测试,Update()刷新下当前时间:

    private void Update()
    {
        //获取当前时间
        hour = DateTime.Now.Hour;
        minute = DateTime.Now.Minute;
        millisecond = DateTime.Now.Millisecond;
        second = DateTime.Now.Second;
        year = DateTime.Now.Year;
        month = DateTime.Now.Month;
        day = DateTime.Now.Day;

        GameObject.Find("Canvas/Panel/LableText").GetComponent<Text>().text = string.Format("{0:D2}:{1:D2}:{2:D2}:{3:D2} " + "{4:D4}/{5:D2}/{6:D2}", hour, minute, second, millisecond, year, month, day);
    }

相关Event处理

 public void onNTSmartEvent(string param)
    {
        if (!param.Contains(","))
        {
            Debug.Log("[onNTSmartEvent] android传递参数错误");
            return;
        }

       string[] strs = param.Split(',');

       string player_handle =strs[0];
       string code = strs[1];
       string param1 = strs[2];
       string param2 = strs[3];
       string param3 = strs[4];
       string param4 = strs[5];

       Debug.Log("[onNTSmartEvent] code: 0x" + Convert.ToString(Convert.ToInt32(code), 16));

        String publisher_event = "";

        switch (Convert.ToInt32(code))
        {
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_STARTED:
                publisher_event = "开始..";
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_CONNECTING:
                publisher_event = "连接中..";
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_CONNECTION_FAILED:
                publisher_event = "连接失败..";
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_CONNECTED:
                publisher_event = "连接成功..";
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_DISCONNECTED:
                publisher_event = "连接断开..";
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_STOP:
                publisher_event = "关闭..";
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_RECORDER_START_NEW_FILE:
                publisher_event = "开始一个新的录像文件 : " + param3;
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_ONE_RECORDER_FILE_FINISHED:
                publisher_event = "已生成一个录像文件 : " + param3;
                break;

            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_SEND_DELAY:
                publisher_event = "发送时延: " + param1 + " 帧数:" + param2;
                break;

            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_CAPTURE_IMAGE:
                publisher_event = "快照: " + param1 + " 路径:" + param3;

                if (Convert.ToInt32(param1) == 0)
                {
                    publisher_event = publisher_event + "截取快照成功..";
                }
                else
                {
                    publisher_event = publisher_event + "截取快照失败..";
                }
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUBLISHER_RTSP_URL:
                publisher_event = "RTSP服务URL: " + param3;
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUSH_RTSP_SERVER_RESPONSE_STATUS_CODE:
                publisher_event = "RTSP status code received, codeID: " + param1 + ", RTSP URL: " + param3;
                break;
            case EVENTID.EVENT_DANIULIVE_ERC_PUSH_RTSP_SERVER_NOT_SUPPORT:
                publisher_event = "服务器不支持RTSP推送, 推送的RTSP URL: " + param3;
                break;
        }

        Debug.Log(publisher_event);

    }

总结

通过以上流程,可以实现Unity环境下屏幕或摄像机数据,毫秒级体验的RTMP推送和播放,感兴趣的开发者可酌情参考。

以上就是Android实现Unity3D下RTMP推送的示例的详细内容,更多关于Android实现Unity3D下RTMP推送的资料请关注我们其它相关文章!

(0)

相关推荐

  • nginx使用nginx-rtmp-module模块实现直播间功能

    系统环境 wujianjun@wujianjun-work ~ $ uname -a Linux wujianjun-work 4.10.0-37-generic #41~16.04.1-Ubuntu SMP Fri Oct 6 22:42:59 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux 软件环境 OBS(Open Broadcaster Software) v20.0.1 (Linux) nginx version: nginx/1.13.6 built

  • unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk)

    unity3d发布apk在android虚拟机中运行的详细步骤(unity3d导出android apk),总的流程分为以下6个步骤: 1.安装java_jdk 2.配置java环境变量 3.更新android的sdk 4.从Unity3d中发布出apk文件 5.创建android虚拟机并运行 6.将apk文件安装到android虚拟机中 (为方便新手,在下面对每个步骤的具体操作及可能遇到的问题详细提一下) 1.安装java_jdk 官网(www.java.com),免费,我安装的文件的名字是j

  • 在linux系统下安装python librtmp包的实现方法

    安装librtmp包需要依赖环境较多,机器上已经安装了python2.7版本,安装librtmp包之前需要先安装依赖环境. 1.安装gcc和依赖包 yum install gcc* python-devel libffi-dev* -y 2.安装librtmp 从git上下载源码: git clone git://git.ffmpeg.org/rtmpdump cd rtmpdump/librtmp/ make && make install 3.安装setuptools wget -S

  • Nginx搭建rtmp直播服务器实现代码

    1.到nginx源码目录新建个rtmp目录 ,进入 git clone https://github.com/arut/nginx-rtmp-module.git 2.重编译nginx 代码如下 ./configure --prefix=/usr/local/nginx-1.2.9/ --add-module=./rtmp/nginx-rtmp-module --with-http_ssl_module --with-pcre=/lamp_source/pcre-8.38; make;make

  • Unity3D游戏引擎实现在Android中打开WebView的实例

    本文讲述了如何在Unity中调用Android中的WebView组件,实现内部浏览器样式的页面切换.首先打开Eclipse创建一个Android的工程: UnityTestActivity.java 入口Activity ,Unity中会调用这个Activity中的方法从而打开网页. package com.xys; import android.content.Context; import android.content.Intent; import android.os.Bundle; i

  • 树莓派使用python-librtmp实现rtmp推流h264的方法

    目的是能使用Python进行rtmp推流,方便在h264帧里加入弹幕等操作. librtmp使用的是0.3.0,使用树莓派noir官方摄像头适配的. 通过wireshark抓ffmpeg的包一点点改动,最终可以在red5和斗鱼上推流了. 没怎么写过python,有不恰当的地方请包涵. 上代码: # -- coding: utf-8 -- # http://blog.csdn.net/luhanglei import picamera import time import traceback im

  • 在Ubuntu 14 上安装 Nginx-RTMP 流媒体服务器的教程

    一:RTMP RTMP流媒体协议是 一套 Adobe 开发的音频视频实时传输协议: 二:Nginx-rtmp nginx-rtmp 是一个基于nginx的 RTMP服务模块,开源,免费 https://github.com/arut/nginx-rtmp-module 三:在 ubuntu server 14 安装流程 1.先下载安装 nginx 和 nginx-rtmp 编译依赖工具 sudo apt-get install build-essential libpcre3 libpcre3-

  • vue-video-player实现实时视频播放方式(监控设备-rtmp流)

    监控设备播放效果如下 1.vue项目安装vue-video-player npm install vue-video-player --save 2.编写视频播放组件(放上完整的组件例子,父组件调用时给videoSrc和playerOptions.sources[0].src赋值就可以播放了,具体操作有注释) 注:style样式部分用了lang=scss,如果自己的项目没用他请用自己的方式改一下样式部分避免报错 <template> <div class="video-js&q

  • 详解Ubuntu18.04下配置Nginx+RTMP+HLS+HTTPFLV服务器实现点播/直播/录制功能

    2019.9.4更新 继续玩又发现个好玩的东西,nginx-http-flv-module模块,集成了之前的RTMP模块,又有httpflv模块,还是咱们国内程序员大神开发维护,真是开心,国内的大神如此出色,为他们这些愿意分享技术的人点32个赞,具体的编译和安装方式与RTMP模块基本一样,配置readme中也说得很详细,就不赘述了,需要注意的一点是,httpflv方式客户端想看也是需要服务设置cors的,这点readme中没有提到好像. 2019.6.27更新 再更新个windows版本的搭建方

  • Mac上搭建nginx+rtmp直播服务器的步骤详解

    前言 相信大家都知道nginx是非常优秀的开源服务器,用它来做hls或者rtmp流媒体服务器是非常不错的选择,所以小编在网上整理了安装流程,现在分享给大家并且作备忘.有需要的朋友们可以参考学习,下面来一起看看吧. 一.安装Homebrow 已经安装了brow的可以直接跳过这一步. 执行命令 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" 如果已经安装过,而

  • vue项目中播放rtmp视频文件流的方法

    想要播放rtmp视频文件流用H5的video标签是不可行的,所以这里我引用了一款插件 vue-video-player ,当然想要流畅的运用 vue-video-player 播放视频还必须安装辅助插件 videojs-flash.最后还要特别注意的是必须使用npm安装,当然我在安装过程中也遇到了一个问题,就是在选择使用 vue-video-player前还安装了videojs插件,卸载从新安装 vue-video-player时由于项目中有以前安装的其他视频组件影响,一直运行不起来,后面我把n

  • Nginx-rtmp实现直播媒体实时流效果

    0. 前言 这段时间在搭建一个IPCamera项目服务器.视频点对点通话,客户端会查看设备端的音视频实时流.为了省流量,是通过P2P进行穿透.但是由于NAT设备的原因和IPV4的枯竭.有些设备是无法进行点对点传输实时流.所以需要进行服务器转发.这里为了快速实现原型,同时参考现在主流的流媒体协议.发现很多使用的是RTMP协议. 下图是总体设计图,为了整合多平台,会自建RTMP流媒体服务器和使用云厂商SaaS的RTMP流媒体服务.但是由于有时候会传输一些非流媒体数据,需要传输一些二进制文件,所以会需

随机推荐