c# - Rendering SurfaceTexture to Unity Texture2D -
i came simillar questions earlier, weren't clarified , right take advice what's wrong i'm doing in code.
so i'm trying rendering surfacetexture android plugin unity texture2d.
here's unity code:
public class androidhandler : monobehaviour { [serializefield] private rawimage _rawimage; private texture2d _inputtexture; private androidjavaobject androidstreamerobj; private system.intptr _nativeptr; void start () { _rawimage.material.settexturescale("_maintex", new vector2(-1, -1)); initandroidstreamerobject(); } private void initandroidstreamerobject() { androidstreamerobj = new androidjavaobject("makeitbetter.figazzz.com.vitamiousing7.androidstreamer"); int32 texptr = androidstreamerobj.call <int32> ("gettextureptr"); debug.log("texture pointer? " + texptr); texture2d nativetexture = texture2d.createexternaltexture (128, 128, textureformat.rgba32 , false, false, new system.intptr(texptr)); _rawimage.texture = nativetexture; } public void startstream() { string streamlink = "rtmp://live.hkstv.hk.lxdns.com/live/hks"; //"rtsp://wowzaec2demo.streamlock.net/vod/mp4:bigbuckbunny_115k.mov"; //"rtmp://live.hkstv.hk.lxdns.com/live/hks"; androidstreamerobj.call("launchstream", streamlink); } void update() { androidstreamerobj.call("drawframe"); } }
as can see it's pretty basic. i'm asking android plugin create opengltexture , i'm using pointer of brand-new texture allocate texture2d in unity.
then android plugin code:
public class androidstreamer { private final int float_size_bytes = 4; private final int triangle_vertices_data_stride_bytes = 5 * float_size_bytes; private final int triangle_vertices_data_pos_offset = 0; private final int triangle_vertices_data_uv_offset = 3; private activity _curractivity; private videoview _streamconnection; private surface _cachedsurface; private surfacetexture _cachedsurfacetexture; private boolean isnewframe = false; //open gl private int texwidth = 128; private int texheight = 128; private float[] mmvpmatrix = new float[16]; private float[] mstmatrix = new float[16]; private int glprogram; private int mumvpmatrixhandle; private int mustmatrixhandle; private int mapositionhandle; private int matexturehandle; private int unitytextureid = -1; private int mtextureid = -1; //surface texture id private int idfbo = -1; private int idrbo = -1; private final float[] mtriangleverticesdata = { // x, y, z, u, v -1.0f, -1.0f, 0, 0.f, 0.f, 1.0f, -1.0f, 0, 1.f, 0.f, -1.0f, 1.0f, 0, 0.f, 1.f, 1.0f, 1.0f, 0, 1.f, 1.f, }; private floatbuffer mtrianglevertices; private final string vertexshadercode = "uniform mat4 umvpmatrix;\n" + "uniform mat4 ustmatrix;\n" + "attribute vec4 aposition;\n" + "attribute vec4 atexturecoord;\n" + "varying vec2 vtexturecoord;\n" + "void main() {\n" + " gl_position = umvpmatrix * aposition;\n" + " vtexturecoord = (ustmatrix * atexturecoord).xy;\n" + "}\n"; private final string fragmentshadercode = "#extension gl_oes_egl_image_external : require\n" + "precision mediump float;\n" + // highp here doesn't seem matter "varying vec2 vtexturecoord;\n" + "uniform samplerexternaloes stexture;\n" + "void main() {\n" + " gl_fragcolor = texture2d(stexture, vtexturecoord);\n" + "}\n"; public androidstreamer() { log.d("unity", "androidstreamer initialized"); _curractivity = unityplayer.currentactivity; vitamio.isinitialized(_curractivity); _curractivity.runonuithread(new runnable() { @override public void run() { _streamconnection = new videoview(_curractivity); _curractivity.addcontentview(_streamconnection, new framelayout.layoutparams(100, 100)); } }); mtrianglevertices = bytebuffer.allocatedirect( mtriangleverticesdata.length * float_size_bytes) .order(byteorder.nativeorder()).asfloatbuffer(); mtrianglevertices.put(mtriangleverticesdata).position(0); matrix.setidentitym(mstmatrix, 0); initshaderprogram(); } private void initshaderprogram() { log.d("unity", "initshaderprogram"); int vertexshader = loadshader(gles20.gl_vertex_shader, vertexshadercode); int fragmentshader = loadshader(gles20.gl_fragment_shader, fragmentshadercode); glprogram = gles20.glcreateprogram(); gles20.glattachshader(glprogram, vertexshader); checkglerror("glattachvertexshader"); gles20.glattachshader(glprogram, fragmentshader); checkglerror("glattachfragmentshader"); gles20.gllinkprogram(glprogram); checkglerror("gllinkprogram"); mapositionhandle = gles20.glgetattriblocation(glprogram, "aposition"); checklocation(mapositionhandle, "aposition"); matexturehandle = gles20.glgetattriblocation(glprogram, "atexturecoord"); checklocation(matexturehandle, "atexturecoord"); mumvpmatrixhandle = gles20.glgetuniformlocation(glprogram, "umvpmatrix"); checklocation(mumvpmatrixhandle, "uvmpmatrix"); mustmatrixhandle = gles20.glgetuniformlocation(glprogram, "ustmatrix"); checklocation(mustmatrixhandle, "ustmatrix"); } private int loadshader(int shadertype, string source) { int shader = gles20.glcreateshader(shadertype); if (shader != 0) { gles20.glshadersource(shader, source); gles20.glcompileshader(shader); int[] compiled = new int[1]; gles20.glgetshaderiv(shader, gles20.gl_compile_status, compiled, 0); if (compiled[0] == 0) { log.e("unity", "could not compile shader " + shadertype + ":"); log.e("unity", gles20.glgetshaderinfolog(shader)); gles20.gldeleteshader(shader); shader = 0; } } return shader; } private void checklocation(int location, string label) { if (location < 0) { throw new runtimeexception("unable locate '" + label + "' in program"); } } private void checkglerror(string op) { int error; while ((error = gles20.glgeterror()) != gles20.gl_no_error) { log.e("unity", op + ": glerror " + error); throw new runtimeexception(op + ": glerror " + error); } } private void checkframebufferstatus() { int status = gles20.glcheckframebufferstatus(gles20.gl_framebuffer); checkglerror("glcheckframebufferstatus"); switch (status) { case gles20.gl_framebuffer_complete: log.d("unity", "complete"); break; case gles20.gl_framebuffer_incomplete_attachment: log.e("unity", "incomplete attachment"); break; case gles20.gl_framebuffer_incomplete_missing_attachment: log.e("unity", "incomplete missing attachment"); break; case gles20.gl_framebuffer_incomplete_dimensions: log.e("unity", "incomplete dimensions"); break; case gles20.gl_framebuffer_unsupported: log.e("unity", "framebuffer unsupported"); break; default : log.d("unity", "default"); } } private void initgltexture() { log.d("unity", "initgltexture"); int textures[] = new int[1]; gles20.glgentextures(1, textures, 0); checkglerror("glgentextures initgltexture"); mtextureid = textures[0]; gles20.glactivetexture(gles20.gl_texture0); checkglerror("glactivetexture initgltexture"); gles20.glbindtexture(gles11ext.gl_texture_external_oes, mtextureid); checkglerror("glbindtexture initgltexture"); gles20.gltexparameterf(gles11ext.gl_texture_external_oes, gles20.gl_texture_min_filter, gles20.gl_nearest); checkglerror("gltexparameterf initgltexture"); gles20.gltexparameterf(gles11ext.gl_texture_external_oes, gles20.gl_texture_mag_filter, gles20.gl_linear); checkglerror("gltexparameterf initgltexture"); } public int gettextureptr() { bitmap bitmap = bitmap.createbitmap(texwidth, texheight, bitmap.config.argb_8888); for(int x = 0; x < texwidth; x++) { (int y = 0; y < texheight; y++) { bitmap.setpixel(x, y, color.argb(155, 255, 50, 255)); } } log.d("unity", "bitmap is: " + bitmap); bytebuffer buffer = bytebuffer.allocate(bitmap.getbytecount()); bitmap.copypixelstobuffer(buffer); //gles20.glenable(gles11ext.gl_texture_external_oes); //checkglerror("glenable gettextureptr"); int textures[] = new int[1]; gles20.glgentextures(1, textures, 0); checkglerror("0"); unitytextureid = textures[0]; gles20.glactivetexture(gles20.gl_texture0); checkglerror("1"); gles20.glbindtexture(gles20.gl_texture_2d, unitytextureid); checkglerror("2"); gles20.glteximage2d(gles20.gl_texture_2d, 0, gles20.gl_rgba, texwidth, texheight, 0, gles20.gl_rgba, gles20.gl_unsigned_byte, null); checkglerror("12"); //glutils.teximage2d(gles20.gl_texture_2d, 0, bitmap, 0); //checkglerror("3"); gles20.gltexparameterf(gles20.gl_texture_2d, gles20.gl_texture_min_filter, gles20.gl_nearest); checkglerror("4"); gles20.gltexparameterf(gles20.gl_texture_2d, gles20.gl_texture_mag_filter, gles20.gl_linear); checkglerror("5"); gles20.gltexparameteri(gles20.gl_texture_2d, gles20.gl_texture_wrap_s, gles20.gl_clamp_to_edge); checkglerror("6"); gles20.gltexparameteri(gles20.gl_texture_2d, gles20.gl_texture_wrap_t, gles20.gl_clamp_to_edge); checkglerror("7"); gles20.glbindtexture(gles20.gl_texture_2d, 0); checkglerror("8"); setupbuffers(); log.d("unity", "texture id returned: " + unitytextureid); return unitytextureid; } private void setupbuffers() { log.d("unity", "setupbuffers"); //framebuffer int buffers[] = new int[1]; gles20.glgenframebuffers(1, buffers, 0); checkglerror("9"); idfbo = buffers[0]; gles20.glbindframebuffer(gles20.gl_framebuffer, idfbo); checkglerror("10"); //render buffer int rbuffers[] = new int[1]; gles20.glgenrenderbuffers(1, rbuffers, 0); checkglerror("glgenrenderbuffers setupbuffers"); idrbo = rbuffers[0]; gles20.glbindrenderbuffer(gles20.gl_renderbuffer, idrbo); checkglerror("glbindrenderbuffer setupbuffers"); gles20.glrenderbufferstorage(gles20.gl_renderbuffer, gles20.gl_rgba4, texwidth, texheight); checkglerror("glrenderbufferstorage setupbuffers"); gles20.glframebufferrenderbuffer(gles20.gl_framebuffer, gles20.gl_color_attachment0, gles20.gl_renderbuffer, idrbo); checkglerror("glframebufferrenderbuffer setupbuffers"); gles20.glframebuffertexture2d(gles20.gl_framebuffer, gles20.gl_color_attachment0, gles20.gl_texture_2d, unitytextureid, 0); checkglerror("glframebuffertexture2d"); checkframebufferstatus(); gles20.glclearcolor(1.0f, 0.5f, 0.0f, 1.0f); checkglerror("glclearcolor setupbuffers"); gles20.glclear(gles20.gl_color_buffer_bit); checkglerror("glclear setupbuffers"); } public void drawframe() { if(isnewframe && mstmatrix != null) { int[] testbuffer = new int[1]; gles20.glgetintegerv(gles20.gl_framebuffer_binding, testbuffer, 0); log.d("unity", "drawframe binded = " + testbuffer[0] + " idfbo = " + idfbo); gles20.glbindframebuffer(gles20.gl_framebuffer, idfbo); checkglerror("glbindframebuffer drawframe"); gles20.glclearcolor(0.0f, 1.0f, 0.2f, 1.0f); checkglerror("glclearcolor drawframe"); gles20.glclear(gles20.gl_color_buffer_bit); checkglerror("glclear drawframe"); gles20.gluseprogram(glprogram); checkglerror("gluseprogram drawframe"); gles20.glactivetexture(gles20.gl_texture0); checkglerror("glactivetexture drawframe"); gles20.glbindtexture(gles11ext.gl_texture_external_oes, mtextureid); checkglerror("glbindtexture drawframe"); mtrianglevertices.position(triangle_vertices_data_pos_offset); gles20.glvertexattribpointer(matexturehandle, 2, gles20.gl_float, false, triangle_vertices_data_stride_bytes, mtrianglevertices); checkglerror("glvertexattribpointer drawframe"); gles20.glenablevertexattribarray(matexturehandle); checkglerror("glenablevertexattribarray drawframe"); matrix.setidentitym(mmvpmatrix, 0); gles20.gluniformmatrix4fv(mumvpmatrixhandle, 1, false, mmvpmatrix, 0); checkglerror("gluniformmatrix4fv mvp onframeavailable"); gles20.gluniformmatrix4fv(mustmatrixhandle, 1, false, mstmatrix, 0); checkglerror("gluniformmatrix4fv st onframeavailable"); gles20.gldrawarrays(gles20.gl_triangle_strip, 0, 4); checkglerror("gldrawarrays onframeavailable"); gles20.glbindframebuffer(gles20.gl_framebuffer, 0); checkglerror("glbindframebuffer 0 onframeavailable"); gles20.glbindtexture(gles11ext.gl_texture_external_oes, 0); checkglerror("glbindtexture onframeavailable"); isnewframe = false; } } public void launchstream(string streamlink) { final string path = streamlink; //"http://dlqncdn.miaopai.com/stream/mvaux41a4lkuwlobbgugaq__.mp4"; //"rtmp://live.hkstv.hk.lxdns.com/live/hks"; log.i("unity", "hop hop1 = " + path); _curractivity.runonuithread(new runnable() { @override public void run() { _streamconnection.setvideopath(path); _streamconnection.setmediacontroller(new mediacontroller(_curractivity)); _streamconnection.requestfocus(); _streamconnection.setonerrorlistener(new mediaplayer.onerrorlistener() { @override public boolean onerror(mediaplayer mp, int what, int extra) { log.i("unity", "some error, don't know. = " + + " = " + extra); return false; } }); _streamconnection.setonpreparedlistener(new mediaplayer.onpreparedlistener() { @override public void onprepared(mediaplayer mediaplayer) { // optional need vitamio 4.0 log.i("unity", "hop hop5"); mediaplayer.setplaybackspeed(1.0f); } }); initgltexture(); _cachedsurfacetexture = new surfacetexture(mtextureid); _cachedsurfacetexture.setdefaultbuffersize(texwidth, texheight); _cachedsurfacetexture.setonframeavailablelistener(new surfacetexture.onframeavailablelistener() { @override public void onframeavailable(surfacetexture surfacetexture) { synchronized (this) { surfacetexture.updateteximage(); mstmatrix = new float[16]; surfacetexture.gettransformmatrix(mstmatrix); isnewframe = true; } } }); _cachedsurface = new surface(_cachedsurfacetexture); _streamconnection.setsurfacetoplayer(_cachedsurface); log.i("unity", "you're best around!"); } }); } }
i decided provide code of android plugin in order give clear understanding of situation i'm having. basically, i'm trying do: 1) call method "gettextureptr
" unity side, creates gl_texture_2d
texture apply unity texture2d. in android side setup frame , render buffers changing color of texture. works fine because fills color perfectly. 2) call method "launchstream", creates gl_texture_external_oes
texture (in "initgltexture()
" method) , texture applies surfacetexture. 3) in unity update()
method call android method "drawframe()
" should update unity texture according surfacetexture changes.
right i'm having glerror 1282 on gles20.glbindtexture(gles11ext.gl_texture_external_oes, mtextureid);
, of course texture fills green color here
gles20.glclearcolor(0.0f, 1.0f, 0.2f, 1.0f); checkglerror("glclearcolor drawframe");
what i'm doing wrong?
you can't call surfacetexture.updateteximage(); in onframeavailable, call in drawframe() .
and in unity3d:
void update() { androidstreamerobj.call("drawframe"); gl.invalidatestate(); // add }
Comments
Post a Comment