返回首页 |

合作共赢、快速高效、优质的网站建设提供商

更多精品源码-尽在织梦模板-www.moke8.com

记载一个Unity播放器插件的开发

时间:2017-10-26 编辑:admin

布景

公司最近在做VR直播渠道,VR开发我们用到了Unity,而在Unity中播映视频就需求一款视频插件,我们调研了几个视频插件,记载两个,如下:

Unity视频插件调研

网上搜了搜,最盛行的有以下两款Unity插件:

AVPro 这个在Unity商铺价格150$,最新release版别为1.6.15,功用包含:

Powerful cross-platform video playback solution for Unity.

Native video playback on Android, iOS, macOS and tvOS (Apple TV), WebGL, Windows, Windows Phone and UWP.

Features include:

New Unity 2017 supported New New iOS video playback path that uses less memory One API for video playback on all supported platforms Unity 4.6 - 5.x supported 8K video (on supported hardware) VR Support (mono, stereo, equirectangular and cubemap) Transparency support (native and packed) Subtitles support (external SRT) Fast flexible video playback In-editor playback support for Windows and macOS Free watermarked trial version available Components for IMGUI, uGUI and NGUI Over 64 PlayMaker actions included Easy to use drag and drop components Linear and Gamma colour spaces supported Fast native Direct3D, OpenGL and Metal texture updates Desktop support for Hap, Hap Alpha, Hap Q and Hap Q Alpha Streaming video from URL (when supported by platform)

此插件支撑HLS视频播映,运用文档很具体,可是此插件没有源码,不适合做今后的个性化开发。

鼎鼎大名的EasyMovieTexture.价格65$,支撑功用如下:

Supported resolutions:

Android: General devices support up to 1920 * 1080.
The latest device supports up to 4k. iOS: General devices support up to 1920 * 1080.
The latest device is support up to 2560 * 1440.
iPhone 6s Plus supports up to 4k. It also supports StreamingAsset*****ternal storage, and streaming services. Android streaming support list: http, HLS (http live streaming),rtsp iOS streaming support list: http,HLS (http live streaming) EasyMovieTexture requires Android 4.0 or above. EasyMovieTexture requires iOS 6.0 or Above. Unity 4.X requires an iOS Pro. In Unity 5.X it does not require a Pro. Supports multithreaded rendering options. (Only supports Unity 5.X.)

这个插件貌似是个人开发的,没有阐明文档,有部分java源码,native code并没有给出。我们需求有源码的插件便利今后的个性化开发。

自己着手,风衣足食

归纳以上调研成果,我们决议自己着手完成一个简略能满意我们要求的Unity播映器插件,有两个难点要打破:

一个是找一个适宜的开源播映器。 另一个就是怎么把播映视频画面映射到Unity中的物体外表,这个是最要害的。

寻觅材料

从下面这个帖子中,找到了一些能够参阅的材料。

unity 3d 中怎么完成以物体的外表作为播映视频的方位,比如在墙面播映视频?

寻觅开源播映器

正本计划运用VLC播映器的,可是搭档发现有一个商用的开源播映器,而且运用的人数也不少,B站的ijkplayer。正好在上面的帖子中回复人也提到了这个播映器,我们决议运用这个播映器。

怎么做视频画面映射

没有一点Unity开发经历,只能从头一点点学起,知乎的帖子里边,有个人回复能够参阅OVR里边的比如。阅读了里边的代码,一起也参阅了easyMovieTexture中的源码(easyMovie中只要java代码,要害的native code并没有给)。看的有些似懂非懂,尝试了之后,竟然成功了。

最要害的一点我描绘成下面的话:

将Ijkplayer的AndroidSurfaceTexture纹路ID和Unity中Texture2D的纹路ID别离一起绑定到不同的方针上。AndroidSurfaceTexture绑定到GL_TEXTURE_EXTERNAL_OES,Unity的纹路ID绑定到GL_TEXTURE_2D

自始至终整理一遍流程

初始化

Unity

Unity端初始化一个Texture2D纹路ID用于显现视频帧。

m_VideoTexture = new Texture2D (Call_GetVideoWidth (), Call_GetVideoHeight (), TextureFormat.RGB565, false);
OVR

这儿运用了OVR里边的native code,OVR中初始化AndroidSurfaceTexture和相关的函数:

static const char * className = "android/graphics/SurfaceTexture";
    const jclass surfaceTextureClass = jni->FindClass(className);
    if ( surfaceTextureClass == 0 ) {
        FAIL( "FindClass( %s ) failed", className );
    }

    // find the constructor that takes an int
    const jmethodID constructor = jni->GetMethodID( surfaceTextureClass, "<init>", "(I)V" );
    if ( constructor == 0 ) {
        FAIL( "GetMethodID( <init> ) failed" );
    }

    jobject obj = jni->NewObject( surfaceTextureClass, constructor, textureId );
    if ( obj == 0 ) {
        FAIL( "NewObject() failed" );
    }

    javaObject = jni->NewGlobalRef( obj );
    if ( javaObject == 0 ) {
        FAIL( "NewGlobalRef() failed" );
    }

    // Now that we have a globalRef, we can free the localRef
    jni->DeleteLocalRef( obj );

    updateTexImageMethodId = jni->GetMethodID( surfaceTextureClass, "updateTexImage", "()V" );
    if ( !updateTexImageMethodId ) {
        FAIL( "couldn't get updateTexImageMethodId" );
    }

    getTimestampMethodId = jni->GetMethodID( surfaceTextureClass, "getTimestamp", "()J" );
    if ( !getTimestampMethodId ) {
        FAIL( "couldn't get getTimestampMethodId" );
    }

    setDefaultBufferSizeMethodId = jni->GetMethodID( surfaceTextureClass, "setDefaultBufferSize", "(II)V" );
    if ( !setDefaultBufferSizeMethodId ) {
        FAIL( "couldn't get setDefaultBufferSize" );
    }

    // jclass objects are localRefs that need to be freed
    jni->DeleteLocalRef( surfaceTextureClass );

初始化纹路ID,并将其绑定到方针GL_TEXTURE_2D上:

glGenTextures( 1, &textureId );
    glBindTexture( GL_TEXTURE_EXTERNAL_OES, textureId );
    glTexParameterf( GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
    glTexParameterf( GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
    glBindTexture( GL_TEXTURE_EXTERNAL_OES, 0 );

将Unity的纹路ID传递到OVR中,用于绑定到方针GL_TEXTURE_EXTERNAL_OES上:


jobject OVR_Media_Surface( void * texPtr, int const width, int const height )
{
    GLuint texId = (GLuint)(size_t)(texPtr);
    LOG( "OVR_Media_Surface(%i, %i, %i)", texId, width, height );
    return _msp.VideoSurface.Bind( texId, width, height );
}
Ijkplayer

创立一个播映器,留意这儿我们运用OVR中现已实例化的AndroidMovieTexture来初始化播映器。

 m_IjkMediaPlayer.setSurface(m_Surface);

改写

改写操作由Unity中的Update函数触发,终究在OVR中履行,首要调用AndroidMovieTexture中的Update函数,接下来就是绑定纹路操作,Ijkplayer的纹路ID每改写一次绑定一次。而Unity的纹路ID只要在视频图画长度或许宽度发生变化才会绑定。

void MediaSurface::Update()
{
    if ( !AndroidSurfaceTexture )
    {
        LOG( "!AndroidSurfaceTexture" );
        return;
    }
    if ( TexId <= 0 )
    {
        //LOG( "TexId <= 0" );
        return;
    }
    AndroidSurfaceTexture->Update();
    if ( AndroidSurfaceTexture->GetNanoTimeStamp() == LastSurfaceTexNanoTimeStamp )
    {
        //LOG( "No new surface!" );
        return;
    }
    LastSurfaceTexNanoTimeStamp = AndroidSurfaceTexture->GetNanoTimeStamp()

   // If the SurfaceTexture has changed dimensions, we need to
    // reallocate the texture and FBO.
    glActiveTexture( GL_TEXTURE0 );
    glBindTexture( GL_TEXTURE_EXTERNAL_OES, AndroidSurfaceTexture->GetTextureId() );
    if ( TexIdWidth != BoundWidth || TexIdHeight != BoundHeight )
    {
        LOG( "New surface size: %ix%i", BoundWidth, BoundHeight );

        TexIdWidth = BoundWidth;
        TexIdHeight = BoundHeight;

        if ( Fbo )
        {
            glDeleteFramebuffers( 1, &Fbo );
        }

        glActiveTexture( GL_TEXTURE1 );
        glBindTexture( GL_TEXTURE_2D, TexId );
        glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
                TexIdWidth, TexIdHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

        glBindTexture( GL_TEXTURE_2D, 0 );
        glActiveTexture( GL_TEXTURE0 );

        glGenFramebuffers( 1, &Fbo );
        glBindFramebuffer( GL_FRAMEBUFFER, Fbo );
        glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
                TexId, 0 );
        glBindFramebuffer( GL_FRAMEBUFFER, 0 );
    }
}

终究的成果可能是这个姿态的:Ijkplayer担任推进视频不断向前播映,播映器的纹路也会不断改写,这会带动Unity纹路跟着改写,终究显现在Unity的Material上。


浏览:

网站建设

流程

    网站建设流程