Created
December 8, 2016 09:53
-
-
Save xinfushe/49a0ae6456ab9ce0c43cdf7a3577c1ce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.gangneux.dev.jrmgxlibview; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.util.AttributeSet; | |
import android.util.Log; | |
import android.view.Surface; | |
import android.view.ViewGroup; | |
import android.webkit.WebChromeClient; | |
import android.webkit.WebView; | |
import android.webkit.WebViewClient; | |
/** | |
* Created by jerome on 30/10/2016. | |
*/ | |
public class JrmgxWebView extends WebView { | |
private Surface surface = null; | |
// Inherit | |
public JrmgxWebView(Context context) { | |
super(context); | |
Log.i("JrmgxWebView.java", "Constructor with context"); | |
} | |
public JrmgxWebView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
Log.i("JrmgxWebView.java", "Constructor with context + attrs"); | |
} | |
public JrmgxWebView(Context context, AttributeSet attrs, int defStyleAttr) { | |
super(context, attrs, defStyleAttr); | |
Log.i("JrmgxWebView.java", "Constructor with context + attrs + styleAttr"); | |
} | |
// Custom | |
public long lastUpdateTime = 0; | |
public int width = 512; | |
public int height = 512; | |
public boolean hasUpdate = false; | |
public JrmgxWebView(Context context, int width, int height) { | |
super(context); | |
this.width = width; | |
this.height = height; | |
Log.i("JrmgxWebView.java", "Constructor with context + width + height = " + width + " + " + height); | |
//setWebChromeClient( new WebChromeClient(){} ); | |
//setWebViewClient( new WebViewClient() ); | |
/* | |
setWebChromeClient(new WebChromeClient()); | |
getSettings().setJavaScriptEnabled(true); | |
getSettings().setDomStorageEnabled(true); | |
setWebViewClient(new WebViewClient() { | |
public boolean shouldOverrideUrlLoading(WebView view,String url) { | |
return false; | |
} | |
}); | |
*/ | |
setLayoutParams(new ViewGroup.LayoutParams(width, height)); | |
} | |
void setSurface(Surface surface) { | |
Log.i("JrmgxWebView.java", "setSurface"); | |
this.surface = surface; | |
} | |
@Override | |
public void loadUrl(String url) { | |
Log.i("JrmgxWebView.java", "load url " + url); | |
super.loadUrl(url); | |
} | |
@Override | |
public void loadData(String data, String mimeType, String encoding) { | |
super.loadData(data, mimeType, encoding); | |
} | |
public void loadData(String data) { | |
Log.i("JrmgxWebView.java", "load data with: " + data); | |
super.loadData(data, "text/html; charset=utf-8", "UTF-8"); | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
Log.i("JrmgxWebView.java", "onDraw"); | |
/*if (lastUpdateTime == 0) { | |
lastUpdateTime = System.currentTimeMillis(); | |
} | |
if (System.currentTimeMillis() - lastUpdateTime < 33) { | |
return; // Skip frame-rate | |
} | |
lastUpdateTime = System.currentTimeMillis(); | |
hasUpdate = true;*/ | |
if (surface != null) { | |
try { | |
final Canvas surfaceCanvas = surface.lockCanvas(null); | |
//surfaceCanvas.save(); | |
//surfaceCanvas.translate(0, 0); // TODO scrolling | |
super.onDraw(surfaceCanvas); | |
//surfaceCanvas.restore(); | |
surface.unlockCanvasAndPost(surfaceCanvas); | |
Log.i("JrmgxWebView.java", "onDraw not null + success"); | |
} | |
catch (Exception e) { | |
Log.e("JrmgxWebView.java", "onDraw exception " + e.getMessage()); | |
} | |
} | |
//super.onDraw(canvas); | |
/* GVR (samsung) | |
Canvas attachedCanvas = mSceneObject.lockCanvas(); | |
// translate canvas to reflect view scrolling | |
attachedCanvas.scale(attachedCanvas.getWidth() / (float) canvas.getWidth(), | |
attachedCanvas.getHeight() / (float) canvas.getHeight()); | |
attachedCanvas.translate(-getScrollX(), -getScrollY()); | |
// draw the view to provided canvas | |
super.draw(attachedCanvas); | |
*/ | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************************ | |
Filename : MediaSurface.cpp | |
Content : Interface to copy/mip a SurfaceTexture stream onto a normal GL texture | |
Created : July 14, 2014 | |
Authors : John Carmack | |
Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. | |
*************************************************************************************/ | |
#include "MediaSurface.h" | |
#include "Kernel/OVR_LogUtils.h" | |
#include "GlStateSave.h" | |
namespace OVR | |
{ | |
MediaSurface::MediaSurface() : | |
jni( NULL ), | |
AndroidSurfaceTexture( NULL ), | |
SurfaceObject( NULL ), | |
LastSurfaceTexNanoTimeStamp( 0 ), | |
TexIdWidth( -1 ), | |
TexIdHeight( -1 ), | |
BoundWidth( -1 ), | |
BoundHeight( -1 ), | |
TexId( 0 ), | |
Fbo( 0 ), | |
ExternalTexture( false ) | |
{ | |
} | |
void MediaSurface::Init( JNIEnv * jni_ ) | |
{ | |
LOG( "MediaSurface - Init()" ); | |
jni = jni_; | |
LastSurfaceTexNanoTimeStamp = 0; | |
TexId = 0; | |
Fbo = 0; | |
// Setup a surface for playing movies in Unity | |
AndroidSurfaceTexture = new SurfaceTexture( jni ); | |
static const char * className = "android/view/Surface"; | |
const jclass surfaceClass = jni->FindClass( className ); | |
if ( surfaceClass == 0 ) | |
{ | |
FAIL( "MediaSurface - FindClass( %s ) failed", className ); | |
} | |
// find the constructor that takes a surfaceTexture object | |
const jmethodID constructor = jni->GetMethodID( surfaceClass, "<init>", "(Landroid/graphics/SurfaceTexture;)V" ); | |
if ( constructor == 0 ) | |
{ | |
FAIL( "MediaSurface - GetMethodID( <init> ) failed" ); | |
} | |
jobject obj = jni->NewObject( surfaceClass, constructor, AndroidSurfaceTexture->GetJavaObject() ); | |
if ( obj == 0 ) | |
{ | |
FAIL( "MediaSurface - NewObject() failed" ); | |
} | |
SurfaceObject = jni->NewGlobalRef( obj ); | |
if ( SurfaceObject == 0 ) | |
{ | |
FAIL( "MediaSurface - NewGlobalRef() failed" ); | |
} | |
// Now that we have a globalRef, we can free the localRef | |
jni->DeleteLocalRef( obj ); | |
// The class is also a localRef that we can delete | |
jni->DeleteLocalRef( surfaceClass ); | |
} | |
void MediaSurface::Shutdown() | |
{ | |
LOG( "MediaSurface - Shutdown()" ); | |
DeleteProgram( CopyMovieProgram ); | |
UnitSquare.Free(); | |
delete AndroidSurfaceTexture; | |
AndroidSurfaceTexture = NULL; | |
if ( Fbo != 0 ) | |
{ | |
glDeleteFramebuffers( 1, &Fbo ); | |
Fbo = 0; | |
} | |
if ( !ExternalTexture && TexId != 0 ) | |
{ | |
glDeleteTextures( 1, &TexId ); | |
} | |
if ( jni != NULL ) | |
{ | |
if ( SurfaceObject != NULL ) | |
{ | |
jni->DeleteGlobalRef( SurfaceObject ); | |
SurfaceObject = NULL; | |
} | |
} | |
} | |
jobject MediaSurface::GetSurfaceObject() | |
{ | |
if ( SurfaceObject == NULL ) | |
{ | |
LOG( "MediaSurface - SurfaceObject == NULL" ); | |
abort(); | |
} | |
return SurfaceObject; | |
} | |
int MediaSurface::GetNativeTextureId() | |
{ | |
LOG ("MediaSurface - GetNativeTextureId = %i", TexId); | |
return TexId; | |
} | |
void MediaSurface::SetExternalTexId_DEPRECATED( const int texId_ ) | |
{ | |
LOG ("MediaSurface - SetExternalTexId_DEPRECATED DANGER"); | |
TexId = texId_; | |
ExternalTexture = true; | |
} | |
// TODO: Format, mips, etc | |
void MediaSurface::SetTextureParms( const int texWidth_, const int texHeight_ ) | |
{ | |
BoundWidth = texWidth_; | |
BoundHeight = texHeight_; | |
} | |
void MediaSurface::Update() | |
{ | |
LOG ("MediaSurface - Update"); | |
if ( AndroidSurfaceTexture == NULL ) | |
{ | |
LOG( "MediaSurface - AndroidSurfaceTexture == NULL" ); | |
return; | |
} | |
if ( ExternalTexture && TexId <= 0 ) | |
{ | |
LOG( "MediaSurface - TexId <= 0" ); | |
return; | |
} | |
AndroidSurfaceTexture->Update(); | |
long long currentTimeStamp = AndroidSurfaceTexture->GetNanoTimeStamp(); | |
LOG ("MediaSurface - %d =? %d", currentTimeStamp, LastSurfaceTexNanoTimeStamp); | |
if ( currentTimeStamp == LastSurfaceTexNanoTimeStamp ) | |
{ | |
LOG( "MediaSurface - No new surface!" ); | |
// HARDCORE return; | |
return; | |
} | |
LastSurfaceTexNanoTimeStamp = AndroidSurfaceTexture->GetNanoTimeStamp(); | |
// don't mess up Unity state | |
GLStateSave stateSave; | |
// If we haven't allocated our GL objects yet, do it now. | |
// This isn't done at Init, because GL may not be current then. | |
if ( UnitSquare.vertexArrayObject == 0 ) | |
{ | |
LOG( "MediaSurface - Allocating GL objects" ); | |
UnitSquare = BuildTesselatedQuad( 1, 1 ); | |
CopyMovieProgram = BuildProgram( | |
NULL, | |
"attribute vec4 Position;\n" | |
"attribute vec2 TexCoord;\n" | |
"varying highp vec2 oTexCoord;\n" | |
"void main()\n" | |
"{\n" | |
" gl_Position = Position;\n" | |
" oTexCoord = TexCoord;\n" | |
"}\n" | |
, | |
"#extension GL_OES_EGL_image_external : enable\n" | |
"#extension GL_OES_EGL_image_external_essl3 : enable\n" | |
, | |
"uniform samplerExternalOES Texture0;\n" | |
"varying highp vec2 oTexCoord;\n" | |
"void main()\n" | |
"{\n" | |
" gl_FragColor = texture2D( Texture0, oTexCoord );\n" | |
"}\n" | |
); | |
} | |
// If the SurfaceTexture has changed dimensions, we need to | |
// reallocate the texture and FBO. | |
if ( ( !ExternalTexture && ( TexId == 0 ) ) || TexIdWidth != BoundWidth || TexIdHeight != BoundHeight ) | |
{ | |
LOG( "MediaSurface - New surface size: %ix%i", BoundWidth, BoundHeight ); | |
TexIdWidth = BoundWidth; | |
TexIdHeight = BoundHeight; | |
if ( Fbo != 0 ) | |
{ | |
glDeleteFramebuffers( 1, &Fbo ); | |
} | |
if ( !ExternalTexture ) | |
{ | |
if ( TexId != 0 ) | |
{ | |
glDeleteTextures( 1, &TexId ); | |
} | |
glGenTextures( 1, &TexId ); | |
} | |
glActiveTexture( GL_TEXTURE1 ); | |
glBindTexture( GL_TEXTURE_2D, TexId ); | |
// TODO: Switch to glTexStorage2D when we're no longer having to support deprecated external image interface. | |
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 ); | |
} | |
if ( Fbo != 0 ) | |
{ | |
LOG ("MediaSurface - Fbo != 0"); | |
glActiveTexture( GL_TEXTURE0 ); | |
glBindTexture( GL_TEXTURE_EXTERNAL_OES, AndroidSurfaceTexture->GetTextureId() ); | |
glBindFramebuffer( GL_FRAMEBUFFER, Fbo ); | |
glDisable( GL_DEPTH_TEST ); | |
glDisable( GL_SCISSOR_TEST ); | |
glDisable( GL_STENCIL_TEST ); | |
glDisable( GL_CULL_FACE ); | |
glDisable( GL_BLEND ); | |
const GLenum fboAttachments[1] = { GL_COLOR_ATTACHMENT0 }; | |
glInvalidateFramebuffer( GL_FRAMEBUFFER, 1, fboAttachments ); | |
glViewport( 0, 0, TexIdWidth, TexIdHeight ); | |
glUseProgram( CopyMovieProgram.Program ); | |
UnitSquare.Draw(); | |
glUseProgram( 0 ); | |
glBindTexture( GL_TEXTURE_EXTERNAL_OES, 0 ); | |
glBindFramebuffer( GL_FRAMEBUFFER, 0 ); | |
glBindTexture( GL_TEXTURE_2D, TexId ); | |
glGenerateMipmap( GL_TEXTURE_2D ); | |
glBindTexture( GL_TEXTURE_2D, 0 ); | |
} | |
} | |
} // namespace OVR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************************ | |
Filename : MediaSurfacePlugin.cpp | |
Content : | |
Created : July 1, 2015 | |
Authors : | |
Copyright : Copyright 2015 Oculus VR, LLC. All Rights reserved. | |
*************************************************************************************/ | |
#include <jni.h> | |
#include "Kernel/OVR_Allocator.h" | |
#include "Kernel/OVR_Types.h" | |
#include "Kernel/OVR_System.h" | |
#include "Android/JniUtils.h" | |
#include "Kernel/OVR_GlUtils.h" | |
#include "Kernel/OVR_LogUtils.h" | |
#include "MediaSurface.h" | |
#include "GlStateSave.h" | |
#define OCULUS_EXPORT | |
using namespace OVR; | |
static struct InitShutdown | |
{ | |
InitShutdown() | |
{ | |
OVR::System::Init( OVR::Log::ConfigureDefaultLog( OVR::LogMask_All ) ); | |
} | |
~InitShutdown() | |
{ | |
OVR::System::Destroy(); | |
} | |
} GlobalInitShutdown; | |
class MediaSurfacePlugin | |
{ | |
public: | |
MediaSurfacePlugin() : | |
initialized( false ), | |
eventBase( 0 ), | |
jniEnv( NULL ) | |
{ | |
} | |
bool initialized; | |
int eventBase; | |
JNIEnv * jniEnv; | |
// Media surface for video player support in Unity | |
MediaSurface mediaSurface; | |
}; | |
MediaSurfacePlugin mediaSurfacePlugin; | |
extern "C" | |
{ | |
static JavaVM * UnityJavaVM; | |
JNIEXPORT jint JNI_OnLoad( JavaVM * vm, void * reserved ) | |
{ | |
LOG( "MediaSurfacePlugin - JNI_OnLoad" ); | |
UnityJavaVM = vm; | |
return JNI_VERSION_1_6; | |
} | |
// Call this as early as possible to load the plugin. | |
OCULUS_EXPORT void OVR_Media_Surface_Init() | |
{ | |
LOG( "MediaSurfacePlugin - OVR_Media_Surface_Init()" ); | |
} | |
OCULUS_EXPORT void OVR_Media_Surface_SetEventBase( int eventBase ) | |
{ | |
//LOG( "OVR_Media_Surface_SetEventBase() = %d", eventBase ); | |
mediaSurfacePlugin.eventBase = eventBase; | |
} | |
OCULUS_EXPORT jobject OVR_Media_Surface_GetObject() | |
{ | |
return mediaSurfacePlugin.mediaSurface.GetSurfaceObject(); | |
} | |
OCULUS_EXPORT intptr_t OVR_Media_Surface_GetNativeTexture() | |
{ | |
return mediaSurfacePlugin.mediaSurface.GetNativeTextureId(); | |
} | |
OCULUS_EXPORT void OVR_Media_Surface_SetTextureId_DEPRECATED( void * texPtr ) | |
{ | |
GLuint texId = (GLuint)(size_t)(texPtr); | |
LOG( "MediaSurfacePlugin - OVR_Media_Surface_SetTextureId(%i)", texId ); | |
return mediaSurfacePlugin.mediaSurface.SetExternalTexId_DEPRECATED( texId ); | |
} | |
OCULUS_EXPORT void OVR_Media_Surface_SetTextureParms( int const width, int const height ) | |
{ | |
LOG( "MediaSurfacePlugin - OVR_Media_Surface_SetTextureParms(%i, %i)", width, height ); | |
return mediaSurfacePlugin.mediaSurface.SetTextureParms( width, height ); | |
} | |
void OVR_InitMediaSurface() | |
{ | |
if ( mediaSurfacePlugin.initialized ) | |
{ | |
return; | |
} | |
LOG( "MediaSurfacePlugin - OVR_InitMediaSurface()" ); | |
#if defined( OVR_HAS_OPENGL_LOADER ) | |
if ( !GLES3::LoadGLFunctions() ) | |
{ | |
FAIL( "MediaSurfacePlugin - Failed to load GLES3 core entry points!" ); | |
} | |
#endif | |
// We should have a javaVM from the .so loadupdateTexImage | |
if ( UnityJavaVM == NULL ) | |
{ | |
FAIL( "MediaSurfacePlugin - JNI_OnLoad() not called yet" ); | |
} | |
UnityJavaVM->AttachCurrentThread( &mediaSurfacePlugin.jniEnv, 0 ); | |
// Look up extensions | |
GL_InitExtensions(); | |
mediaSurfacePlugin.initialized = true; | |
mediaSurfacePlugin.mediaSurface.Init( mediaSurfacePlugin.jniEnv ); | |
} | |
void OVR_ShutdownMediaSurface() | |
{ | |
if ( !mediaSurfacePlugin.initialized ) | |
{ | |
return; | |
} | |
LOG( "MediaSurfacePlugin - OVR_ShutdownMediaSurface()" ); | |
mediaSurfacePlugin.mediaSurface.Shutdown(); | |
mediaSurfacePlugin.initialized = false; | |
} | |
enum MediaSurfaceEventType | |
{ | |
MS_EVENT_INIT = 0, | |
MS_EVENT_SHUTDOWN = 1, | |
MS_EVENT_UPDATE = 2 | |
}; | |
// When Unity's multi-threaded renderer is enabled, the GL context is never current for | |
// the script execution thread, so the only way for a plugin to execute GL code is to | |
// have it done through the GL.IssuePluginEvent( int ) call, which calls this function. | |
OCULUS_EXPORT void UnityRenderEvent( int eventID ) | |
{ | |
const int remappedID = eventID - mediaSurfacePlugin.eventBase; | |
//LOG( "MediaSurface:: UnityRenderEvent %d %d", eventID, remappedID ); | |
switch( remappedID ) | |
{ | |
case MS_EVENT_INIT: | |
{ | |
OVR_InitMediaSurface(); | |
break; | |
} | |
case MS_EVENT_SHUTDOWN: | |
{ | |
OVR_ShutdownMediaSurface(); | |
break; | |
} | |
case MS_EVENT_UPDATE: | |
{ | |
// Update the movie surface, if active. | |
mediaSurfacePlugin.mediaSurface.Update(); | |
break; | |
} | |
default: | |
break; | |
} | |
} | |
} // extern "C" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************************ | |
Filename : SurfaceTexture.cpp | |
Content : Interface to Android SurfaceTexture objects | |
Created : September 17, 2013 | |
Authors : John Carmack | |
Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. | |
*************************************************************************************/ | |
#include "SurfaceTexture.h" | |
#include <stdlib.h> | |
#include "Kernel/OVR_GlUtils.h" | |
#include "Kernel/OVR_LogUtils.h" | |
namespace OVR { | |
SurfaceTexture::SurfaceTexture( JNIEnv * jni_ ) : | |
textureId( 0 ), | |
javaObject( NULL ), | |
jni( NULL ), | |
nanoTimeStamp( 0 ), | |
updateTexImageMethodId( NULL ), | |
getTimestampMethodId( NULL ), | |
setDefaultBufferSizeMethodId( NULL ) | |
{ | |
LOG ("SurfaceTexture - init"); | |
#if defined( OVR_OS_ANDROID ) | |
jni = jni_; | |
// Gen a gl texture id for the java SurfaceTexture to use. | |
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 ); | |
static const char * className = "android/graphics/SurfaceTexture"; | |
const jclass surfaceTextureClass = jni->FindClass(className); | |
if ( surfaceTextureClass == 0 ) { | |
FAIL( "SurfaceTexture - FindClass( %s ) failed", className ); | |
} | |
// find the constructor that takes an int | |
const jmethodID constructor = jni->GetMethodID( surfaceTextureClass, "<init>", "(I)V" ); | |
if ( constructor == 0 ) { | |
FAIL( "SurfaceTexture - GetMethodID( <init> ) failed" ); | |
} | |
jobject obj = jni->NewObject( surfaceTextureClass, constructor, textureId ); | |
if ( obj == 0 ) { | |
FAIL( "SurfaceTexture - NewObject() failed" ); | |
} | |
javaObject = jni->NewGlobalRef( obj ); | |
if ( javaObject == 0 ) { | |
FAIL( "SurfaceTexture - 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( "SurfaceTexture - couldn't get updateTexImageMethodId" ); | |
} | |
getTimestampMethodId = jni->GetMethodID( surfaceTextureClass, "getTimestamp", "()J" ); | |
if ( !getTimestampMethodId ) { | |
FAIL( "SurfaceTexture - couldn't get getTimestampMethodId" ); | |
} | |
setDefaultBufferSizeMethodId = jni->GetMethodID( surfaceTextureClass, "setDefaultBufferSize", "(II)V" ); | |
if ( !setDefaultBufferSizeMethodId ) { | |
FAIL( "SurfaceTexture - couldn't get setDefaultBufferSize" ); | |
} | |
// jclass objects are localRefs that need to be freed | |
jni->DeleteLocalRef( surfaceTextureClass ); | |
LOG ("SurfaceTexture - init with success"); | |
#endif | |
LOG ("SurfaceTexture - init has success ^^ ? and textureId = %i", textureId); | |
} | |
SurfaceTexture::~SurfaceTexture() | |
{ | |
#if defined( OVR_OS_ANDROID ) | |
if ( textureId ) { | |
glDeleteTextures( 1, &textureId ); | |
textureId = 0; | |
} | |
if ( javaObject ) { | |
jni->DeleteGlobalRef( javaObject ); | |
javaObject = 0; | |
} | |
#endif | |
} | |
void SurfaceTexture::SetDefaultBufferSize( const int width, const int height ) | |
{ | |
#if defined( OVR_OS_ANDROID ) | |
jni->CallVoidMethod( javaObject, setDefaultBufferSizeMethodId, width, height ); | |
#else | |
OVR_UNUSED( width ); | |
OVR_UNUSED( height ); | |
#endif | |
} | |
void SurfaceTexture::Update() | |
{ | |
#if defined( OVR_OS_ANDROID ) | |
// latch the latest movie frame to the texture | |
if ( !javaObject ) { | |
return; | |
} | |
jni->CallVoidMethod( javaObject, updateTexImageMethodId ); | |
nanoTimeStamp = jni->CallLongMethod( javaObject, getTimestampMethodId ); | |
LOG ("SurfaceTexture - last nanoTimeStamp is %i", nanoTimeStamp); | |
#endif | |
} | |
unsigned SurfaceTexture::GetTextureId() | |
{ | |
return textureId; | |
} | |
jobject SurfaceTexture::GetJavaObject() | |
{ | |
return javaObject; | |
} | |
long long SurfaceTexture::GetNanoTimeStamp() | |
{ | |
return nanoTimeStamp; | |
} | |
} // namespace OVR |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************************ | |
Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. | |
Licensed under the Oculus VR Rift SDK License Version 3.3 (the "License"); | |
you may not use the Oculus VR Rift SDK except in compliance with the License, | |
which is provided at the time of installation or download, or which | |
otherwise accompanies this software in either electronic or hard copy form. | |
You may obtain a copy of the License at | |
http://www.oculus.com/licenses/LICENSE-3.3 | |
Unless required by applicable law or agreed to in writing, the Oculus VR SDK | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
************************************************************************************/ | |
using UnityEngine; | |
using System.Collections; // required for Coroutines | |
using System.Runtime.InteropServices; // required for DllImport | |
using System; // requred for IntPtr | |
using System.IO; // required for File | |
/************************************************************************************ | |
Usage: | |
Place a simple textured quad surface with the correct aspect ratio in your scene. | |
Add the WebviewPlayerSample.cs script to the surface object. | |
Supply the name of the media file to play: | |
This sample assumes the media file is placed in "Assets/StreamingAssets", ie | |
"ProjectName/Assets/StreamingAssets/url.mp4". | |
On Desktop, Unity MovieTexture functionality is used. Note: the media file | |
is loaded at runtime, and therefore expected to be converted to Ogg Theora | |
beforehand. | |
Implementation: | |
In the WebviewPlayerSample Awake() call, GetNativeTexturePtr() is called on | |
renderer.material.mainTexture. | |
When the MediaSurface plugin gets the initialization event on the render thread, | |
it creates a new Android SurfaceTexture and Surface object in preparation | |
for receiving media. | |
When the game wants to start the video playing, it calls the StartWebViewOnTextureId() | |
script call, which creates an Android webView java object, issues a | |
native plugin call to tell the native code to set up the target texture to | |
render the video to and return the Android Surface object to pass to webView, | |
then sets up the media stream and starts it. | |
Every frame, the SurfaceTexture object is checked for updates. If there | |
is one, the target texId is re-created at the correct dimensions and format | |
if it is the first frame, then the video image is rendered to it and mipmapped. | |
The following frame, instead of Unity drawing the image that was placed | |
on the surface in the Unity editor, it will draw the current video frame. | |
************************************************************************************/ | |
public class WebviewPlayerSampleWeb : MonoBehaviour { | |
public string url = string.Empty; | |
public int textureWidth = 512; | |
public int textureHeight = 512; | |
#if (UNITY_ANDROID && !UNITY_EDITOR) | |
// Internals | |
private bool started = false; | |
private Renderer currentRenderer = null; | |
private Texture2D nativeTexture = null; | |
private IntPtr nativeTexId = IntPtr.Zero; | |
private AndroidJavaObject webView = null; | |
private int frameCpt = 0; | |
private enum MediaSurfaceEventType { | |
Initialize = 0, | |
Shutdown = 1, | |
Update = 2, | |
Max_EventType | |
}; | |
/// The start of the numeric range used by event IDs. | |
/// If multiple native rundering plugins are in use, the Oculus Media Surface plugin's event IDs | |
/// can be re-mapped to avoid conflicts. | |
/// | |
/// Set this value so that it is higher than the highest event ID number used by your plugin. | |
/// Oculus Media Surface plugin event IDs start at eventBase and end at eventBase plus the highest | |
/// value in MediaSurfaceEventType. | |
public static int eventBase { | |
get { return _eventBase; } | |
set { | |
_eventBase = value; | |
OVR_Media_Surface_SetEventBase(_eventBase); | |
} | |
} | |
private static int _eventBase = 0; | |
private static void IssuePluginEvent(MediaSurfaceEventType eventType) { | |
GL.IssuePluginEvent((int) eventType + eventBase); | |
} | |
// GameObject | |
void log(string message) { | |
print("WebviewPlayerSampleWeb: LOG " + message); | |
} | |
void error(string message) { | |
print("WebviewPlayerSampleWeb: ERROR " + message); | |
} | |
void Awake() { | |
log("Awake"); | |
OVR_Media_Surface_Init(); | |
currentRenderer = GetComponent<Renderer>(); | |
if (currentRenderer.material == null) { | |
error("No material for web surface"); | |
if (currentRenderer.material.mainTexture == null) { | |
error ("No mainTexture"); | |
} | |
} | |
if (url == string.Empty) { | |
error("No url provided"); | |
} | |
nativeTexture = Texture2D.CreateExternalTexture(textureWidth, textureHeight, TextureFormat.RGBA32, true, false, IntPtr.Zero); | |
IssuePluginEvent(MediaSurfaceEventType.Initialize); | |
} | |
void Start() { | |
log("Start"); | |
StartCoroutine(DelayedRetrieveWebPage()); | |
} | |
void Update() { | |
log ("Update"); | |
IntPtr currTexId = OVR_Media_Surface_GetNativeTexture(); | |
log ("texId = " + currTexId); | |
if (currTexId != nativeTexId) { | |
log ("Update + tex is diff"); | |
nativeTexId = currTexId; | |
nativeTexture.UpdateExternalTexture(currTexId); | |
} | |
IssuePluginEvent(MediaSurfaceEventType.Update); | |
if (webView != null) { | |
frameCpt++; | |
if (frameCpt % 100 == 0) { | |
webView.Call("loadData", "<h1>HELLO WORLD: " + frameCpt); | |
webView.Call("postInvalidate"); | |
} | |
} | |
} | |
/// Pauses when the app loses or gains focus | |
void OnApplicationPause(bool wasPaused) { | |
log("OnApplicationPause: " + wasPaused); | |
} | |
private void OnApplicationQuit() { | |
log("OnApplicationQuit"); | |
// This will trigger the shutdown on the render thread | |
IssuePluginEvent(MediaSurfaceEventType.Shutdown); | |
} | |
/// Auto-starts loading | |
IEnumerator DelayedRetrieveWebPage() { | |
log ("DelayedRetrieveWebPage NOT STARTED"); | |
yield return null; // delay 1 frame to allow MediaSurfaceInit from the render thread. | |
if (!started) { | |
log ("DelayedRetrieveWebPage STARTED"); | |
started = true; | |
webView = StartOnTextureId(textureWidth, textureHeight, url); | |
webView.Call("loadData", "<h1>HELLO WORLD!"); | |
currentRenderer.material.mainTexture = nativeTexture; | |
} | |
} | |
/// Set up the web view with surface texture id. | |
AndroidJavaObject StartOnTextureId(int texWidth, int texHeight, string url) { | |
log("StartOnTextureId"); | |
OVR_Media_Surface_SetTextureParms(textureWidth, textureHeight); | |
IntPtr androidSurface = OVR_Media_Surface_GetObject(); | |
//AndroidJavaObject webView = new AndroidJavaObject("android/webkit/WebView"); | |
AndroidJavaClass unityJavaClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer"); | |
AndroidJavaObject unityJavaContext = unityJavaClass.GetStatic<AndroidJavaObject>("currentActivity"); | |
AndroidJavaObject webView = new AndroidJavaObject("net.gangneux.dev.jrmgxlibview.JrmgxWebView", unityJavaContext, texWidth, texHeight); | |
// Can't use AndroidJavaObject.Call() with a jobject, must use low level interface | |
//webView.Call("setSurface", androidSurface); | |
IntPtr setSurfaceMethodId = AndroidJNI.GetMethodID(webView.GetRawClass(), "setSurface", "(Landroid/view/Surface;)V"); | |
jvalue[] parms = new jvalue[1]; | |
parms[0] = new jvalue(); | |
parms[0].l = androidSurface; | |
AndroidJNI.CallVoidMethod(webView.GetRawObject(), setSurfaceMethodId, parms); | |
try { | |
webView.Call("loadUrl", url); | |
//webView.Call("prepare"); | |
//webView.Call("setLooping", true); | |
//webView.Call("start"); | |
} | |
catch (Exception e) { | |
error("Failed to start webView with message " + e.Message); | |
} | |
return webView; | |
} | |
[DllImport("OculusMediaSurface")] | |
private static extern void OVR_Media_Surface_Init(); | |
[DllImport("OculusMediaSurface")] | |
private static extern void OVR_Media_Surface_SetEventBase(int eventBase); | |
// This function returns an Android Surface object that is | |
// bound to a SurfaceTexture object on an independent OpenGL texture id. | |
// Each frame, before the TimeWarp processing, the SurfaceTexture is checked | |
// for updates, and if one is present, the contents of the SurfaceTexture | |
// will be copied over to the provided surfaceTexId and mipmaps will be | |
// generated so normal Unity rendering can use it. | |
[DllImport("OculusMediaSurface")] | |
private static extern IntPtr OVR_Media_Surface_GetObject(); | |
[DllImport("OculusMediaSurface")] | |
private static extern IntPtr OVR_Media_Surface_GetNativeTexture(); | |
[DllImport("OculusMediaSurface")] | |
private static extern void OVR_Media_Surface_SetTextureParms(int texWidth, int texHeight); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment