用jni实现基于opengl的yuv格式的视频渲染

由于项目需要,需要在android上面实现视频流的解码显示,综合考虑决定使用ffmpeg解码,opengl渲染视频。

技术选型确定以后,开始写demo,不做不知道,一做才发现网上的东西太不靠谱了,基于jni实现的opengl不是直接渲染yuv格式的数据,都是yuv转rgb以后在显示的,有实现的资料都是在java层做的,我不是java出生,所以对那个不感冒,综合考虑之后决定自己通过jni来实现,由于以前基于webrtc开发了一款产品,用的是webrtc的c++接口开发(现在的webrtc都基于浏览器开发了,更加成熟了,接口也更加简单,^_^我觉得还是挖c++代码出来自己实现接口层有意思,我那个项目就是这样搞的),废话不多说,开始讲述实现步骤。


注意:android2.3.3版本才开始支持opengl。

写jni的时候需要在Android.mk里面加上opengl的库连接,这里我发一个我的Android.mk出来供大家参考一下:

[cpp]  view plain copy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. MY_LIBS_PATH := /Users/chenjianjun/Documents/work/ffmpeg-android/build/lib  
  4. MY_INCLUDE_PATH := /Users/chenjianjun/Documents/work/ffmpeg-android/build/include  
  5.   
  6.   
  7. include $(CLEAR_VARS)  
  8. LOCAL_MODULE := libavcodec  
  9. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libavcodec.a  
  10. include $(PREBUILT_STATIC_LIBRARY)  
  11.   
  12. include $(CLEAR_VARS)  
  13. LOCAL_MODULE := libavfilter  
  14. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libavfilter.a  
  15. include $(PREBUILT_STATIC_LIBRARY)  
  16.   
  17. include $(CLEAR_VARS)  
  18. LOCAL_MODULE := libavformat  
  19. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libavformat.a  
  20. include $(PREBUILT_STATIC_LIBRARY)  
  21.   
  22. include $(CLEAR_VARS)  
  23. LOCAL_MODULE := libavresample  
  24. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libavresample.a  
  25. include $(PREBUILT_STATIC_LIBRARY)  
  26.   
  27. include $(CLEAR_VARS)  
  28. LOCAL_MODULE := libavutil  
  29. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libavutil.a  
  30. include $(PREBUILT_STATIC_LIBRARY)  
  31.   
  32. include $(CLEAR_VARS)  
  33. LOCAL_MODULE := libpostproc  
  34. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libpostproc.a  
  35. include $(PREBUILT_STATIC_LIBRARY)  
  36.   
  37. include $(CLEAR_VARS)  
  38. LOCAL_MODULE := libswresample  
  39. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libswresample.a  
  40. include $(PREBUILT_STATIC_LIBRARY)  
  41.   
  42. include $(CLEAR_VARS)  
  43. LOCAL_MODULE := libswscale  
  44. LOCAL_SRC_FILES :=  $(MY_LIBS_PATH)/libswscale.a  
  45. include $(PREBUILT_STATIC_LIBRARY)  
  46.   
  47.   
  48. include $(CLEAR_VARS)  
  49. LOCAL_MODULE_TAGS := MICloudPub  
  50. LOCAL_MODULE := libMICloudPub  
  51.   
  52. LOCAL_SRC_FILES := H264Decoder.cpp \              #我的H264基于ffmpeg的解码接口代码  
  53.                    render_opengles20.cpp \        #opengl的渲染代码  
  54.                    test.cpp                       #测试接口代码  
  55. LOCAL_CFLAGS :=  
  56.   
  57. LOCAL_C_INCLUDES := $(MY_INCLUDE_PATH)  
  58. LOCAL_CPP_INCLUDES := $(MY_INCLUDE_PATH)  
  59.   
  60. LOCAL_LDLIBS := \  
  61.     -llog \  
  62.     -lgcc \  
  63.     <span style="font-size:32px;color:#FF0000;">-lGLESv2 \</span>  
  64.     -lz  
  65.       
  66. LOCAL_WHOLE_STATIC_LIBRARIES := \  
  67.     libavcodec \  
  68.     libavfilter \  
  69.     libavformat \  
  70.     libavresample \  
  71.     libavutil \  
  72.     libpostproc \  
  73.     libswresample \  
  74.     libswscale  
  75.   
  76. include $(BUILD_SHARED_LIBRARY)  
  77.    
上面红色的是opengl的库,我是mac电脑上面编译的,其他系统的不知道是不是叫这个名字哈(不过这么弱智的应该不会变哈).


第一步:

写java代码(主要是为了jni里面的代码回调java的代码实现,其中的妙用大家后面便知)

我把webrtc里面的代码拿出来改动了一下,就没自己去写了(不用重复造轮子)

ViEAndroidGLES20.java

[java]  view plain copy
  1. package hzcw.opengl;  
  2.   
  3. import java.util.concurrent.locks.ReentrantLock;  
  4.   
  5. import javax.microedition.khronos.egl.EGL10;  
  6. import javax.microedition.khronos.egl.EGLConfig;  
  7. import javax.microedition.khronos.egl.EGLContext;  
  8. import javax.microedition.khronos.egl.EGLDisplay;  
  9. import javax.microedition.khronos.opengles.GL10;  
  10.   
  11. import android.app.ActivityManager;  
  12. import android.content.Context;  
  13. import android.content.pm.ConfigurationInfo;  
  14. import android.graphics.PixelFormat;  
  15. import android.opengl.GLSurfaceView;  
  16. import android.util.Log;  
  17.   
  18. public class ViEAndroidGLES20 extends GLSurfaceView implements GLSurfaceView.Renderer  
  19. {  
  20.     private static String TAG = "MICloudPub";  
  21.     private static final boolean DEBUG = false;  
  22.     // True if onSurfaceCreated has been called.  
  23.     private boolean surfaceCreated = false;  
  24.     private boolean openGLCreated = false;  
  25.     // True if NativeFunctionsRegistered has been called.  
  26.     private boolean nativeFunctionsRegisted = false;  
  27.     private ReentrantLock nativeFunctionLock = new ReentrantLock();  
  28.     // Address of Native object that will do the drawing.  
  29.     private long nativeObject = 0;  
  30.     private int viewWidth = 0;  
  31.     private int viewHeight = 0;  
  32.   
  33.     public static boolean UseOpenGL2(Object renderWindow) {  
  34.         return ViEAndroidGLES20.class.isInstance(renderWindow);  
  35.     }  
  36.   
  37.     public ViEAndroidGLES20(Context context) {  
  38.         super(context);  
  39.         init(false00);  
  40.     }  
  41.   
  42.     public ViEAndroidGLES20(Context context, boolean translucent,  
  43.             int depth, int stencil) {  
  44.         super(context);  
  45.         init(translucent, depth, stencil);  
  46.     }  
  47.   
  48.     private void init(boolean translucent, int depth, int stencil) {  
  49.   
  50.         // By default, GLSurfaceView() creates a RGB_565 opaque surface.  
  51.         // If we want a translucent one, we should change the surface's  
  52.         // format here, using PixelFormat.TRANSLUCENT for GL Surfaces  
  53.         // is interpreted as any 32-bit surface with alpha by SurfaceFlinger.  
  54.         if (translucent) {  
  55.             this.getHolder().setFormat(PixelFormat.TRANSLUCENT);  
  56.         }  
  57.   
  58.         // Setup the context factory for 2.0 rendering.  
  59.         // See ContextFactory class definition below  
  60.         setEGLContextFactory(new ContextFactory());  
  61.   
  62.         // We need to choose an EGLConfig that matches the format of  
  63.         // our surface exactly. This is going to be done in our  
  64.         // custom config chooser. See ConfigChooser class definition  
  65.         // below.  
  66.         setEGLConfigChooser( translucent ?  
  67.                              new ConfigChooser(8888, depth, stencil) :  
  68.                              new ConfigChooser(5650, depth, stencil) );  
  69.   
  70.         // Set the renderer responsible for frame rendering  
  71.         this.setRenderer(this);  
  72.         this.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);  
  73.     }  
  74.   
  75.     private static class ContextFactory implements GLSurfaceView.EGLContextFactory {  
  76.         private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;  
  77.         public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {  
  78.             Log.w(TAG, "creating OpenGL ES 2.0 context");  
  79.             checkEglError("Before eglCreateContext", egl);  
  80.             int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };  
  81.             EGLContext context = egl.eglCreateContext(display, eglConfig,  
  82.                     EGL10.EGL_NO_CONTEXT, attrib_list);  
  83.             checkEglError("After eglCreateContext", egl);  
  84.             return context;  
  85.         }  
  86.   
  87.         public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {  
  88.             egl.eglDestroyContext(display, context);  
  89.         }  
  90.     }  
  91.   
  92.     private static void checkEglError(String prompt, EGL10 egl) {  
  93.         int error;  
  94.         while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {  
  95.             Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));  
  96.         }  
  97.     }  
  98.   
  99.     private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {  
  100.   
  101.         public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {  
  102.             mRedSize = r;  
  103.             mGreenSize = g;  
  104.             mBlueSize = b;  
  105.             mAlphaSize = a;  
  106.             mDepthSize = depth;  
  107.             mStencilSize = stencil;  
  108.         }  
  109.   
  110.         // This EGL config specification is used to specify 2.0 rendering.  
  111.         // We use a minimum size of 4 bits for red/green/blue, but will  
  112.         // perform actual matching in chooseConfig() below.  
  113.         private static int EGL_OPENGL_ES2_BIT = 4;  
  114.         private static int[] s_configAttribs2 =  
  115.         {  
  116.             EGL10.EGL_RED_SIZE, 4,  
  117.             EGL10.EGL_GREEN_SIZE, 4,  
  118.             EGL10.EGL_BLUE_SIZE, 4,  
  119.             EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,  
  120.             EGL10.EGL_NONE  
  121.         };  
  122.   
  123.         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {  
  124.   
  125.             // Get the number of minimally matching EGL configurations  
  126.             int[] num_config = new int[1];  
  127.             egl.eglChooseConfig(display, s_configAttribs2, null0, num_config);  
  128.   
  129.             int numConfigs = num_config[0];  
  130.   
  131.             if (numConfigs <= 0) {  
  132.                 throw new IllegalArgumentException("No configs match configSpec");  
  133.             }  
  134.   
  135.             // Allocate then read the array of minimally matching EGL configs  
  136.             EGLConfig[] configs = new EGLConfig[numConfigs];  
  137.             egl.eglChooseConfig(display, s_configAttribs2, configs, numConfigs, num_config);  
  138.   
  139.             if (DEBUG) {  
  140.                 printConfigs(egl, display, configs);  
  141.             }  
  142.             // Now return the "best" one  
  143.             return chooseConfig(egl, display, configs);  
  144.         }  
  145.   
  146.         public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,  
  147.                 EGLConfig[] configs) {  
  148.             for(EGLConfig config : configs) {  
  149.                 int d = findConfigAttrib(egl, display, config,  
  150.                         EGL10.EGL_DEPTH_SIZE, 0);  
  151.                 int s = findConfigAttrib(egl, display, config,  
  152.                         EGL10.EGL_STENCIL_SIZE, 0);  
  153.   
  154.                 // We need at least mDepthSize and mStencilSize bits  
  155.                 if (d < mDepthSize || s < mStencilSize)  
  156.                     continue;  
  157.   
  158.                 // We want an *exact* match for red/green/blue/alpha  
  159.                 int r = findConfigAttrib(egl, display, config,  
  160.                         EGL10.EGL_RED_SIZE, 0);  
  161.                 int g = findConfigAttrib(egl, display, config,  
  162.                             EGL10.EGL_GREEN_SIZE, 0);  
  163.                 int b = findConfigAttrib(egl, display, config,  
  164.                             EGL10.EGL_BLUE_SIZE, 0);  
  165.                 int a = findConfigAttrib(egl, display, config,  
  166.                         EGL10.EGL_ALPHA_SIZE, 0);  
  167.   
  168.                 if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)  
  169.                     return config;  
  170.             }  
  171.             return null;  
  172.         }  
  173.   
  174.         private int findConfigAttrib(EGL10 egl, EGLDisplay display,  
  175.                 EGLConfig config, int attribute, int defaultValue) {  
  176.   
  177.             if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {  
  178.                 return mValue[0];  
  179.             }  
  180.             return defaultValue;  
  181.         }  
  182.   
  183.         private void printConfigs(EGL10 egl, EGLDisplay display,  
  184.             EGLConfig[] configs) {  
  185.             int numConfigs = configs.length;  
  186.             Log.w(TAG, String.format("%d configurations", numConfigs));  
  187.             for (int i = 0; i < numConfigs; i++) {  
  188.                 Log.w(TAG, String.format("Configuration %d:\n", i));  
  189.                 printConfig(egl, display, configs[i]);  
  190.             }  
  191.         }  
  192.   
  193.         private void printConfig(EGL10 egl, EGLDisplay display,  
  194.                 EGLConfig config) {  
  195.             int[] attributes = {  
  196.                     EGL10.EGL_BUFFER_SIZE,  
  197.                     EGL10.EGL_ALPHA_SIZE,  
  198.                     EGL10.EGL_BLUE_SIZE,  
  199.                     EGL10.EGL_GREEN_SIZE,  
  200.                     EGL10.EGL_RED_SIZE,  
  201.                     EGL10.EGL_DEPTH_SIZE,  
  202.                     EGL10.EGL_STENCIL_SIZE,  
  203.                     EGL10.EGL_CONFIG_CAVEAT,  
  204.                     EGL10.EGL_CONFIG_ID,  
  205.                     EGL10.EGL_LEVEL,  
  206.                     EGL10.EGL_MAX_PBUFFER_HEIGHT,  
  207.                     EGL10.EGL_MAX_PBUFFER_PIXELS,  
  208.                     EGL10.EGL_MAX_PBUFFER_WIDTH,  
  209.                     EGL10.EGL_NATIVE_RENDERABLE,  
  210.                     EGL10.EGL_NATIVE_VISUAL_ID,  
  211.                     EGL10.EGL_NATIVE_VISUAL_TYPE,  
  212.                     0x3030// EGL10.EGL_PRESERVED_RESOURCES,  
  213.                     EGL10.EGL_SAMPLES,  
  214.                     EGL10.EGL_SAMPLE_BUFFERS,  
  215.                     EGL10.EGL_SURFACE_TYPE,  
  216.                     EGL10.EGL_TRANSPARENT_TYPE,  
  217.                     EGL10.EGL_TRANSPARENT_RED_VALUE,  
  218.                     EGL10.EGL_TRANSPARENT_GREEN_VALUE,  
  219.                     EGL10.EGL_TRANSPARENT_BLUE_VALUE,  
  220.                     0x3039// EGL10.EGL_BIND_TO_TEXTURE_RGB,  
  221.                     0x303A// EGL10.EGL_BIND_TO_TEXTURE_RGBA,  
  222.                     0x303B// EGL10.EGL_MIN_SWAP_INTERVAL,  
  223.                     0x303C// EGL10.EGL_MAX_SWAP_INTERVAL,  
  224.                     EGL10.EGL_LUMINANCE_SIZE,  
  225.                     EGL10.EGL_ALPHA_MASK_SIZE,  
  226.                     EGL10.EGL_COLOR_BUFFER_TYPE,  
  227.                     EGL10.EGL_RENDERABLE_TYPE,  
  228.                     0x3042 // EGL10.EGL_CONFORMANT  
  229.             };  
  230.             String[] names = {  
  231.                     "EGL_BUFFER_SIZE",  
  232.                     "EGL_ALPHA_SIZE",  
  233.                     "EGL_BLUE_SIZE",  
  234.                     "EGL_GREEN_SIZE",  
  235.                     "EGL_RED_SIZE",  
  236.                     "EGL_DEPTH_SIZE",  
  237.                     "EGL_STENCIL_SIZE",  
  238.                     "EGL_CONFIG_CAVEAT",  
  239.                     "EGL_CONFIG_ID",  
  240.                     "EGL_LEVEL",  
  241.                     "EGL_MAX_PBUFFER_HEIGHT",  
  242.                     "EGL_MAX_PBUFFER_PIXELS",  
  243.                     "EGL_MAX_PBUFFER_WIDTH",  
  244.                     "EGL_NATIVE_RENDERABLE",  
  245.                     "EGL_NATIVE_VISUAL_ID",  
  246.                     "EGL_NATIVE_VISUAL_TYPE",  
  247.                     "EGL_PRESERVED_RESOURCES",  
  248.                     "EGL_SAMPLES",  
  249.                     "EGL_SAMPLE_BUFFERS",  
  250.                     "EGL_SURFACE_TYPE",  
  251.                     "EGL_TRANSPARENT_TYPE",  
  252.                     "EGL_TRANSPARENT_RED_VALUE",  
  253.                     "EGL_TRANSPARENT_GREEN_VALUE",  
  254.                     "EGL_TRANSPARENT_BLUE_VALUE",  
  255.                     "EGL_BIND_TO_TEXTURE_RGB",  
  256.                     "EGL_BIND_TO_TEXTURE_RGBA",  
  257.                     "EGL_MIN_SWAP_INTERVAL",  
  258.                     "EGL_MAX_SWAP_INTERVAL",  
  259.                     "EGL_LUMINANCE_SIZE",  
  260.                     "EGL_ALPHA_MASK_SIZE",  
  261.                     "EGL_COLOR_BUFFER_TYPE",  
  262.                     "EGL_RENDERABLE_TYPE",  
  263.                     "EGL_CONFORMANT"  
  264.             };  
  265.             int[] value = new int[1];  
  266.             for (int i = 0; i < attributes.length; i++) {  
  267.                 int attribute = attributes[i];  
  268.                 String name = names[i];  
  269.                 if (egl.eglGetConfigAttrib(display, config, attribute, value)) {  
  270.                     Log.w(TAG, String.format("  %s: %d\n", name, value[0]));  
  271.                 } else {  
  272.                     // Log.w(TAG, String.format("  %s: failed\n", name));  
  273.                     while (egl.eglGetError() != EGL10.EGL_SUCCESS);  
  274.                 }  
  275.             }  
  276.         }  
  277.   
  278.         // Subclasses can adjust these values:  
  279.         protected int mRedSize;  
  280.         protected int mGreenSize;  
  281.         protected int mBlueSize;  
  282.         protected int mAlphaSize;  
  283.         protected int mDepthSize;  
  284.         protected int mStencilSize;  
  285.         private int[] mValue = new int[1];  
  286.     }  
  287.   
  288.     // IsSupported  
  289.     // Return true if this device support Open GL ES 2.0 rendering.  
  290.     public static boolean IsSupported(Context context) {  
  291.         ActivityManager am =  
  292.                 (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);  
  293.         ConfigurationInfo info = am.getDeviceConfigurationInfo();  
  294.         if(info.reqGlEsVersion >= 0x20000) {  
  295.             // Open GL ES 2.0 is supported.  
  296.             return true;  
  297.         }  
  298.         return false;  
  299.     }  
  300.   
  301.     public void onDrawFrame(GL10 gl) {  
  302.         nativeFunctionLock.lock();  
  303.         if(!nativeFunctionsRegisted || !surfaceCreated) {  
  304.             nativeFunctionLock.unlock();  
  305.             return;  
  306.         }  
  307.   
  308.         if(!openGLCreated) {  
  309.             if(0 != CreateOpenGLNative(nativeObject, viewWidth, viewHeight)) {  
  310.                 return// Failed to create OpenGL  
  311.             }  
  312.             openGLCreated = true// Created OpenGL successfully  
  313.         }  
  314.         DrawNative(nativeObject); // Draw the new frame  
  315.         nativeFunctionLock.unlock();  
  316.     }  
  317.   
  318.     public void onSurfaceChanged(GL10 gl, int width, int height) {  
  319.         surfaceCreated = true;  
  320.         viewWidth = width;  
  321.         viewHeight = height;  
  322.   
  323.         nativeFunctionLock.lock();  
  324.         if(nativeFunctionsRegisted) {  
  325.             if(CreateOpenGLNative(nativeObject,width,height) == 0)  
  326.                 openGLCreated = true;  
  327.         }  
  328.         nativeFunctionLock.unlock();  
  329.     }  
  330.   
  331.     public void onSurfaceCreated(GL10 gl, EGLConfig config) {  
  332.     }  
  333.   
  334.     public void RegisterNativeObject(long nativeObject) {  
  335.         nativeFunctionLock.lock();  
  336.         this.nativeObject = nativeObject;  
  337.         nativeFunctionsRegisted = true;  
  338.         nativeFunctionLock.unlock();  
  339.     }  
  340.   
  341.     public void DeRegisterNativeObject() {  
  342.         nativeFunctionLock.lock();  
  343.         nativeFunctionsRegisted = false;  
  344.         openGLCreated = false;  
  345.         this.nativeObject = 0;  
  346.         nativeFunctionLock.unlock();  
  347.     }  
  348.   
  349.     public void ReDraw() {// jni层解码以后的数据回调,然后由系统调用onDrawFrame显示  
  350.         if(surfaceCreated) {  
  351.             // Request the renderer to redraw using the render thread context.  
  352.             this.requestRender();  
  353.         }  
  354.     }  
  355.   
  356.     private native int CreateOpenGLNative(long nativeObject, int width, int height);  
  357.     private native void DrawNative(long nativeObject);  
  358. }  
ViERenderer.java
[java]  view plain copy
  1. package hzcw.opengl;  
  2.   
  3. import android.content.Context;  
  4. import android.view.SurfaceView;  
  5.   
  6. public class ViERenderer  
  7. {  
  8.     public static SurfaceView CreateRenderer(Context context) {  
  9.         return CreateRenderer(context, false);  
  10.     }  
  11.   
  12.     public static SurfaceView CreateRenderer(Context context,  
  13.             boolean useOpenGLES2) {  
  14.         if(useOpenGLES2 == true && ViEAndroidGLES20.IsSupported(context))  
  15.             return new ViEAndroidGLES20(context);  
  16.         else  
  17.             return null;  
  18.     }  
  19. }  

GL2JNILib.java (native接口代码)

[java]  view plain copy
  1. package com.example.filltriangle;  
  2.   
  3. public class GL2JNILib {    
  4.         
  5.       static {    
  6.           System.loadLibrary("MICloudPub");  
  7.       }    
  8.         
  9.      /**  
  10.       */    
  11.       public static native void init(Object glSurface);  
  12.       public static native void step(String filepath);  
  13. }  

第二步:写jni代码

com_example_filltriangle_GL2JNILib.h (javah自动生成的)

[cpp]  view plain copy
  1. /* DO NOT EDIT THIS FILE - it is machine generated */  
  2. #include <jni.h>  
  3. /* Header for class com_example_filltriangle_GL2JNILib */  
  4.   
  5. #ifndef _Included_com_example_filltriangle_GL2JNILib  
  6. #define _Included_com_example_filltriangle_GL2JNILib  
  7. #ifdef __cplusplus  
  8. extern "C" {  
  9. #endif  
  10. /* 
  11.  * Class:     com_example_filltriangle_GL2JNILib 
  12.  * Method:    init 
  13.  * Signature: (II)V 
  14.  */  
  15. JNIEXPORT void JNICALL Java_com_example_filltriangle_GL2JNILib_init  
  16.   (JNIEnv *, jclass, jobject);  
  17.   
  18. /* 
  19.  * Class:     com_example_filltriangle_GL2JNILib 
  20.  * Method:    step 
  21.  * Signature: ()V 
  22.  */  
  23. JNIEXPORT void JNICALL Java_com_example_filltriangle_GL2JNILib_step  
  24.     (JNIEnv *, jclass, jstring);  
  25.   
  26. #ifdef __cplusplus  
  27. }  
  28. #endif  
  29. #endif  

test.cpp

[cpp]  view plain copy
  1. #include <jni.h>  
  2. #include <stdlib.h>  
  3. #include <stdio.h>  
  4.   
  5. #include "render_opengles20.h"  
  6. #include "com_example_filltriangle_GL2JNILib.h"  
  7. #include "H264Decoder.h"  
  8.   
  9. class AndroidNativeOpenGl2Channel  
  10. {  
  11. public:  
  12.     AndroidNativeOpenGl2Channel(JavaVM* jvm,  
  13.                                 void* window)  
  14.     {  
  15.         _jvm = jvm;  
  16.         _ptrWindow = window;  
  17.         _buffer = (uint8_t*)malloc(1024000);  
  18.     }  
  19.       
  20.     ~AndroidNativeOpenGl2Channel()  
  21.     {  
  22.         if (_jvm)  
  23.         {  
  24.             bool isAttached = false;  
  25.             JNIEnv* env = NULL;  
  26.             if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  27.                 // try to attach the thread and get the env  
  28.                 // Attach this thread to JVM  
  29.                 jint res = _jvm->AttachCurrentThread(&env, NULL);  
  30.                   
  31.                 // Get the JNI env for this thread  
  32.                 if ((res < 0) || !env) {  
  33.                     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  34.                                  "%s: Could not attach thread to JVM (%d, %p)",  
  35.                                  __FUNCTION__, res, env);  
  36.                     env = NULL;  
  37.                 } else {  
  38.                     isAttached = true;  
  39.                 }  
  40.             }  
  41.               
  42.             if (env && _deRegisterNativeCID) {  
  43.                 env->CallVoidMethod(_javaRenderObj, _deRegisterNativeCID);  
  44.             }  
  45.               
  46.             env->DeleteGlobalRef(_javaRenderObj);  
  47.             env->DeleteGlobalRef(_javaRenderClass);  
  48.               
  49.             if (isAttached) {  
  50.                 if (_jvm->DetachCurrentThread() < 0) {  
  51.                     WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,  
  52.                                  "%s: Could not detach thread from JVM",  
  53.                                  __FUNCTION__);  
  54.                 }  
  55.             }  
  56.         }  
  57.           
  58.         free(_buffer);  
  59.     }  
  60.       
  61.     int32_t Init()  
  62.     {  
  63.         if (!_ptrWindow)  
  64.         {  
  65.             WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,  
  66.                          "(%s): No window have been provided.", __FUNCTION__);  
  67.             return -1;  
  68.         }  
  69.           
  70.         if (!_jvm)  
  71.         {  
  72.             WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,  
  73.                          "(%s): No JavaVM have been provided.", __FUNCTION__);  
  74.             return -1;  
  75.         }  
  76.           
  77.         // get the JNI env for this thread  
  78.         bool isAttached = false;  
  79.         JNIEnv* env = NULL;  
  80.         if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  81.             // try to attach the thread and get the env  
  82.             // Attach this thread to JVM  
  83.             jint res = _jvm->AttachCurrentThread(&env, NULL);  
  84.               
  85.             // Get the JNI env for this thread  
  86.             if ((res < 0) || !env) {  
  87.                 WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  88.                              "%s: Could not attach thread to JVM (%d, %p)",  
  89.                              __FUNCTION__, res, env);  
  90.                 return -1;  
  91.             }  
  92.             isAttached = true;  
  93.         }  
  94.           
  95.         // get the ViEAndroidGLES20 class  
  96.         jclass javaRenderClassLocal = reinterpret_cast<jclass> (env->FindClass("hzcw/opengl/ViEAndroidGLES20"));  
  97.         if (!javaRenderClassLocal) {  
  98.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  99.                          "%s: could not find ViEAndroidGLES20", __FUNCTION__);  
  100.             return -1;  
  101.         }  
  102.           
  103.         _javaRenderClass = reinterpret_cast<jclass> (env->NewGlobalRef(javaRenderClassLocal));  
  104.         if (!_javaRenderClass) {  
  105.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  106.                          "%s: could not create Java SurfaceHolder class reference",  
  107.                          __FUNCTION__);  
  108.             return -1;  
  109.         }  
  110.   
  111.         // Delete local class ref, we only use the global ref  
  112.         env->DeleteLocalRef(javaRenderClassLocal);  
  113.         jmethodID cidUseOpenGL = env->GetStaticMethodID(_javaRenderClass,  
  114.                                                         "UseOpenGL2",  
  115.                                                         "(Ljava/lang/Object;)Z");  
  116.         if (cidUseOpenGL == NULL) {  
  117.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,  
  118.                          "%s: could not get UseOpenGL ID", __FUNCTION__);  
  119.             return false;  
  120.         }  
  121.         jboolean res = env->CallStaticBooleanMethod(_javaRenderClass,  
  122.                                                     cidUseOpenGL, (jobject) _ptrWindow);  
  123.           
  124.         // create a reference to the object (to tell JNI that we are referencing it  
  125.         // after this function has returned)  
  126.         _javaRenderObj = reinterpret_cast<jobject> (env->NewGlobalRef((jobject)_ptrWindow));  
  127.         if (!_javaRenderObj)  
  128.         {  
  129.             WEBRTC_TRACE(  
  130.                          kTraceError,  
  131.                          kTraceVideoRenderer,  
  132.                          _id,  
  133.                          "%s: could not create Java SurfaceRender object reference",  
  134.                          __FUNCTION__);  
  135.             return -1;  
  136.         }  
  137.           
  138.         // get the method ID for the ReDraw function  
  139.         _redrawCid = env->GetMethodID(_javaRenderClass, "ReDraw""()V");  
  140.         if (_redrawCid == NULL) {  
  141.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  142.                          "%s: could not get ReDraw ID", __FUNCTION__);  
  143.             return -1;  
  144.         }  
  145.           
  146.         _registerNativeCID = env->GetMethodID(_javaRenderClass,  
  147.                                               "RegisterNativeObject""(J)V");  
  148.         if (_registerNativeCID == NULL) {  
  149.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  150.                          "%s: could not get RegisterNativeObject ID", __FUNCTION__);  
  151.             return -1;  
  152.         }  
  153.           
  154.         _deRegisterNativeCID = env->GetMethodID(_javaRenderClass,  
  155.                                                 "DeRegisterNativeObject""()V");  
  156.         if (_deRegisterNativeCID == NULL) {  
  157.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  158.                          "%s: could not get DeRegisterNativeObject ID",  
  159.                          __FUNCTION__);  
  160.             return -1;  
  161.         }  
  162.           
  163.         JNINativeMethod nativeFunctions[2] = {  
  164.             { "DrawNative",  
  165.                 "(J)V",  
  166.                 (void*) &AndroidNativeOpenGl2Channel::DrawNativeStatic, },  
  167.             { "CreateOpenGLNative",  
  168.                 "(JII)I",  
  169.                 (void*) &AndroidNativeOpenGl2Channel::CreateOpenGLNativeStatic },  
  170.         };  
  171.         if (env->RegisterNatives(_javaRenderClass, nativeFunctions, 2) == 0) {  
  172.             WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, -1,  
  173.                          "%s: Registered native functions", __FUNCTION__);  
  174.         }  
  175.         else {  
  176.             WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, -1,  
  177.                          "%s: Failed to register native functions", __FUNCTION__);  
  178.             return -1;  
  179.         }  
  180.           
  181.         env->CallVoidMethod(_javaRenderObj, _registerNativeCID, (jlong) this);  
  182.           
  183.         if (isAttached) {  
  184.             if (_jvm->DetachCurrentThread() < 0) {  
  185.                 WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,  
  186.                              "%s: Could not detach thread from JVM", __FUNCTION__);  
  187.             }  
  188.         }  
  189.           
  190.         WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s done",  
  191.                      __FUNCTION__);  
  192.           
  193. //        if (_openGLRenderer.SetCoordinates(zOrder, left, top, right, bottom) != 0) {  
  194. //            return -1;  
  195. //        }  
  196.           
  197.         return 0;  
  198.     }  
  199.       
  200.     void DeliverFrame(int32_t widht, int32_t height)  
  201.     {  
  202.         if (_jvm)  
  203.         {  
  204.             bool isAttached = false;  
  205.             JNIEnv* env = NULL;  
  206.             if (_jvm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  207.                 // try to attach the thread and get the env  
  208.                 // Attach this thread to JVM  
  209.                 jint res = _jvm->AttachCurrentThread(&env, NULL);  
  210.                   
  211.                 // Get the JNI env for this thread  
  212.                 if ((res < 0) || !env) {  
  213.                     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  214.                                  "%s: Could not attach thread to JVM (%d, %p)",  
  215.                                  __FUNCTION__, res, env);  
  216.                     env = NULL;  
  217.                 } else {  
  218.                     isAttached = true;  
  219.                 }  
  220.             }  
  221.               
  222.             if (env && _redrawCid)  
  223.             {  
  224.                 _widht = widht;  
  225.                 _height = height;  
  226.                   
  227.                 env->CallVoidMethod(_javaRenderObj, _redrawCid);  
  228.             }  
  229.               
  230.             if (isAttached) {  
  231.                 if (_jvm->DetachCurrentThread() < 0) {  
  232.                     WEBRTC_TRACE(kTraceWarning, kTraceVideoRenderer, _id,  
  233.                                  "%s: Could not detach thread from JVM",  
  234.                                  __FUNCTION__);  
  235.                 }  
  236.             }  
  237.         }  
  238.     }  
  239.       
  240.     void GetDataBuf(uint8_t*& pbuf, int32_t& isize)  
  241.     {  
  242.         pbuf = _buffer;  
  243.         isize = 1024000;  
  244.     }  
  245.       
  246.     static jint CreateOpenGLNativeStatic(JNIEnv * env,  
  247.                                         jobject,  
  248.                                         jlong context,  
  249.                                         jint width,  
  250.                                         jint height)  
  251.     {  
  252.         AndroidNativeOpenGl2Channel* renderChannel =  
  253.         reinterpret_cast<AndroidNativeOpenGl2Channel*> (context);  
  254.           
  255.         WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "%s:", __FUNCTION__);  
  256.           
  257.         return renderChannel->CreateOpenGLNative(width, height);  
  258.     }  
  259.       
  260.     static void DrawNativeStatic(JNIEnv * env,jobject, jlong context)  
  261.     {  
  262.         AndroidNativeOpenGl2Channel* renderChannel =  
  263.         reinterpret_cast<AndroidNativeOpenGl2Channel*>(context);  
  264.         renderChannel->DrawNative();  
  265.     }  
  266.       
  267.     jint CreateOpenGLNative(int width, int height)  
  268.     {  
  269.         return _openGLRenderer.Setup(width, height);  
  270.     }  
  271.       
  272.     void DrawNative()  
  273.     {  
  274.         _openGLRenderer.Render(_buffer, _widht, _height);  
  275.     }  
  276.       
  277. private:  
  278.     JavaVM*     _jvm;  
  279.     void* _ptrWindow;  
  280.       
  281.     jobject _javaRenderObj;  
  282.     jclass _javaRenderClass;  
  283.     JNIEnv* _javaRenderJniEnv;  
  284.       
  285.     jmethodID      _redrawCid;  
  286.     jmethodID      _registerNativeCID;  
  287.     jmethodID      _deRegisterNativeCID;  
  288.       
  289.     RenderOpenGles20 _openGLRenderer;  
  290.       
  291.     uint8_t* _buffer;  
  292.     int32_t _widht;  
  293.     int32_t _height;  
  294. };  
  295.   
  296. static JavaVM* g_jvm = NULL;  
  297. static AndroidNativeOpenGl2Channel* p_opengl_channel = NULL;  
  298.   
  299. extern "C"  
  300. {  
  301.     JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void *reserved)  
  302.     {  
  303.         JNIEnv* env = NULL;  
  304.         jint result = -1;  
  305.           
  306.         if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)  
  307.             return -1;  
  308.           
  309.         g_jvm = vm;  
  310.           
  311.         return JNI_VERSION_1_4;  
  312.     }  
  313. }  
  314.   
  315. extern "C"  
  316. {  
  317.     int mTrans = 0x0F0F0F0F;  
  318.     int MergeBuffer(uint8_t *NalBuf, int NalBufUsed, uint8_t *SockBuf, int SockBufUsed, int SockRemain)  
  319.     {  
  320.         //把读取的数剧分割成NAL块  
  321.         int i = 0;  
  322.         char Temp;  
  323.           
  324.         for (i = 0; i < SockRemain; i++) {  
  325.             Temp = SockBuf[i + SockBufUsed];  
  326.             NalBuf[i + NalBufUsed] = Temp;  
  327.               
  328.             mTrans <<= 8;  
  329.             mTrans |= Temp;  
  330.               
  331.             if (mTrans == 1) // 找到一个开始字  
  332.             {  
  333.                 i++;  
  334.                 break;  
  335.             }  
  336.         }  
  337.           
  338.         return i;  
  339.     }  
  340.       
  341.     JNIEXPORT void JNICALL Java_com_example_filltriangle_GL2JNILib_init  
  342.     (JNIEnv *env, jclass oclass, jobject glSurface)  
  343.     {  
  344.         if (p_opengl_channel)  
  345.         {  
  346.             WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "初期化失败[%d].", __LINE__);  
  347.             return;  
  348.         }  
  349.           
  350.         p_opengl_channel = new AndroidNativeOpenGl2Channel(g_jvm, glSurface);  
  351.         if (p_opengl_channel->Init() != 0)  
  352.         {  
  353.             WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "初期化失败[%d].", __LINE__);  
  354.             return;  
  355.         }  
  356.     }  
  357.       
  358.     JNIEXPORT void JNICALL Java_com_example_filltriangle_GL2JNILib_step(JNIEnv* env, jclass tis, jstring filepath)  
  359.     {  
  360.         const char *filename = env->GetStringUTFChars(filepath, NULL);  
  361.           
  362.         WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "step[%d].", __LINE__);  
  363.           
  364.         FILE *_imgFileHandle =  fopen(filename, "rb");  
  365.         if (_imgFileHandle == NULL)  
  366.         {  
  367.             WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "File No Exist[%s][%d].", filename, __LINE__);  
  368.             return;  
  369.         }  
  370.           
  371.         H264Decoder* pMyH264 = new H264Decoder();  
  372.         X264_DECODER_H handle = pMyH264->X264Decoder_Init();  
  373.         if (handle <= 0)  
  374.         {  
  375.             WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "X264Decoder_Init Error[%d].", __LINE__);  
  376.             return;  
  377.         }  
  378.           
  379.         int iTemp = 0;  
  380.         int nalLen;  
  381.         int bytesRead = 0;  
  382.         int NalBufUsed = 0;  
  383.         int SockBufUsed = 0;  
  384.           
  385.         bool bFirst = true;  
  386.         bool bFindPPS = true;  
  387.           
  388.         uint8_t *SockBuf = (uint8_t *)malloc(204800);  
  389.         uint8_t *NalBuf = (uint8_t *)malloc(4098000);  
  390.           
  391.           
  392.         int nWidth, nHeight;  
  393.         memset(SockBuf, 0, 204800);  
  394.           
  395.         uint8_t *buffOut = NULL;  
  396.         int outSize = 0;  
  397.         p_opengl_channel->GetDataBuf(buffOut, outSize);  
  398.           
  399.           
  400.         uint8_t *IIBuf = (uint8_t *)malloc(204800);  
  401.         int IILen = 0;  
  402.           
  403.           
  404.         do {  
  405.             bytesRead = fread(SockBuf, 1, 204800, _imgFileHandle);  
  406.             WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "bytesRead  = %d", bytesRead);  
  407.             if (bytesRead <= 0) {  
  408.                 break;  
  409.             }  
  410.               
  411.             SockBufUsed = 0;  
  412.             while (bytesRead - SockBufUsed > 0) {  
  413.                 nalLen = MergeBuffer(NalBuf, NalBufUsed, SockBuf, SockBufUsed,  
  414.                                      bytesRead - SockBufUsed);  
  415.                 NalBufUsed += nalLen;  
  416.                 SockBufUsed += nalLen;  
  417.                   
  418.                 while (mTrans == 1) {  
  419.                     mTrans = 0xFFFFFFFF;  
  420.                     if (bFirst == true// the first start flag  
  421.                     {  
  422.                         bFirst = false;  
  423.                     }  
  424.                     else // a complete NAL data, include 0x00000001 trail.  
  425.                     {  
  426.                         if (bFindPPS == true// true  
  427.                         {  
  428.                             if ((NalBuf[4] & 0x1F) == 7 || (NalBuf[4] & 0x1F) == 8)  
  429.                             {  
  430.                                 bFindPPS = false;  
  431.                             }  
  432.                             else  
  433.                             {  
  434.                                 NalBuf[0] = 0;  
  435.                                 NalBuf[1] = 0;  
  436.                                 NalBuf[2] = 0;  
  437.                                 NalBuf[3] = 1;  
  438.                                   
  439.                                 NalBufUsed = 4;  
  440.                                   
  441.                                 break;  
  442.                             }  
  443.                         }  
  444.   
  445.                         if (NalBufUsed == 16 || NalBufUsed == 10 || NalBufUsed == 54 || NalBufUsed == 12 || NalBufUsed == 20) {  
  446.                             memcpy(IIBuf + IILen, NalBuf, NalBufUsed);  
  447.                             IILen += NalBufUsed;  
  448.                         }  
  449.                         else  
  450.                         {  
  451.                             memcpy(IIBuf + IILen, NalBuf, NalBufUsed);  
  452.                             IILen += NalBufUsed;  
  453.                               
  454.                             //  decode nal  
  455.                             iTemp = pMyH264->X264Decoder_Decode(handle, (uint8_t *)IIBuf,  
  456.                                                                 IILen, (uint8_t *)buffOut,  
  457.                                                                 outSize, &nWidth, &nHeight);  
  458.                             if (iTemp == 0) {  
  459.                                 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "解码成功,宽度:%d高度:%d,解码数据长度:%d.", nWidth, nHeight, iTemp);  
  460. //                                [self.glView setVideoSize:nWidth height:nHeight];  
  461. //                                [self.glView displayYUV420pData:buffOut  
  462. //                                                          width:nWidth  
  463. //                                                         height:nHeight];  
  464.                                 p_opengl_channel->DeliverFrame(nWidth, nHeight);  
  465.                             }  
  466.                             else  
  467.                             {  
  468.                                 WEBRTC_TRACE(kTraceInfo, kTraceVideoRenderer, -1, "解码失败.");  
  469.                             }  
  470.                               
  471.                             IILen = 0;  
  472.                         }  
  473.                     }  
  474.                       
  475.                     NalBuf[0]=0;  
  476.                     NalBuf[1]=0;  
  477.                     NalBuf[2]=0;  
  478.                     NalBuf[3]=1;  
  479.                       
  480.                     NalBufUsed=4;  
  481.                 }  
  482.             }  
  483.         }while (bytesRead>0);  
  484.           
  485.           
  486.         fclose(_imgFileHandle);  
  487.         pMyH264->X264Decoder_UnInit(handle);  
  488.           
  489.         free(SockBuf);  
  490.         free(NalBuf);  
  491.         delete pMyH264;  
  492.           
  493.         env->ReleaseStringUTFChars(filepath, filename);  
  494.     }  
  495. }  

render_opengles20.cpp

[cpp]  view plain copy
  1. #include <GLES2/gl2.h>  
  2. #include <GLES2/gl2ext.h>  
  3. #include <stdio.h>  
  4. #include <stdlib.h>  
  5. #include <stdio.h>  
  6.   
  7. #include "render_opengles20.h"  
  8.   
  9.   
  10. const char RenderOpenGles20::g_indices[] = { 0, 3, 2, 0, 2, 1 };  
  11.   
  12. const char RenderOpenGles20::g_vertextShader[] = {  
  13.     "attribute vec4 aPosition;\n"  
  14.     "attribute vec2 aTextureCoord;\n"  
  15.     "varying vec2 vTextureCoord;\n"  
  16.     "void main() {\n"  
  17.     "  gl_Position = aPosition;\n"  
  18.     "  vTextureCoord = aTextureCoord;\n"  
  19.     "}\n" };  
  20.   
  21. // The fragment shader.  
  22. // Do YUV to RGB565 conversion.  
  23. const char RenderOpenGles20::g_fragmentShader[] = {  
  24.     "precision mediump float;\n"  
  25.     "uniform sampler2D Ytex;\n"  
  26.     "uniform sampler2D Utex,Vtex;\n"  
  27.     "varying vec2 vTextureCoord;\n"  
  28.     "void main(void) {\n"  
  29.     "  float nx,ny,r,g,b,y,u,v;\n"  
  30.     "  mediump vec4 txl,ux,vx;"  
  31.     "  nx=vTextureCoord[0];\n"  
  32.     "  ny=vTextureCoord[1];\n"  
  33.     "  y=texture2D(Ytex,vec2(nx,ny)).r;\n"  
  34.     "  u=texture2D(Utex,vec2(nx,ny)).r;\n"  
  35.     "  v=texture2D(Vtex,vec2(nx,ny)).r;\n"  
  36.       
  37.     //"  y = v;\n"+  
  38.     "  y=1.1643*(y-0.0625);\n"  
  39.     "  u=u-0.5;\n"  
  40.     "  v=v-0.5;\n"  
  41.       
  42.     "  r=y+1.5958*v;\n"  
  43.     "  g=y-0.39173*u-0.81290*v;\n"  
  44.     "  b=y+2.017*u;\n"  
  45.     "  gl_FragColor=vec4(r,g,b,1.0);\n"  
  46.     "}\n" };  
  47.   
  48. RenderOpenGles20::RenderOpenGles20() :  
  49. _id(0),  
  50. _textureWidth(-1),  
  51. _textureHeight(-1)  
  52. {  
  53.     WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s: id %d",  
  54.                  __FUNCTION__, (int) _id);  
  55.       
  56.     const GLfloat vertices[20] = {  
  57.         // X, Y, Z, U, V  
  58.         -1, -1, 0, 1, 0, // Bottom Left  
  59.         1, -1, 0, 0, 0, //Bottom Right  
  60.         1, 1, 0, 0, 1, //Top Right  
  61.         -1, 1, 0, 1, 1 }; //Top Left  
  62.       
  63.     memcpy(_vertices, vertices, sizeof(_vertices));  
  64. }  
  65.   
  66. RenderOpenGles20::~RenderOpenGles20() {  
  67.     glDeleteTextures(3, _textureIds);  
  68. }  
  69.   
  70. int32_t RenderOpenGles20::Setup(int32_t width, int32_t height) {  
  71.     WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,  
  72.                  "%s: width %d, height %d", __FUNCTION__, (int) width,  
  73.                  (int) height);  
  74.       
  75.     printGLString("Version", GL_VERSION);  
  76.     printGLString("Vendor", GL_VENDOR);  
  77.     printGLString("Renderer", GL_RENDERER);  
  78.     printGLString("Extensions", GL_EXTENSIONS);  
  79.       
  80.     int maxTextureImageUnits[2];  
  81.     int maxTextureSize[2];  
  82.     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, maxTextureImageUnits);  
  83.     glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxTextureSize);  
  84.       
  85.     WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id,  
  86.                  "%s: number of textures %d, size %d", __FUNCTION__,  
  87.                  (int) maxTextureImageUnits[0], (int) maxTextureSize[0]);  
  88.       
  89.     _program = createProgram(g_vertextShader, g_fragmentShader);  
  90.     if (!_program) {  
  91.         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  92.                      "%s: Could not create program", __FUNCTION__);  
  93.         return -1;  
  94.     }  
  95.       
  96.     int positionHandle = glGetAttribLocation(_program, "aPosition");  
  97.     checkGlError("glGetAttribLocation aPosition");  
  98.     if (positionHandle == -1) {  
  99.         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  100.                      "%s: Could not get aPosition handle", __FUNCTION__);  
  101.         return -1;  
  102.     }  
  103.       
  104.     int textureHandle = glGetAttribLocation(_program, "aTextureCoord");  
  105.     checkGlError("glGetAttribLocation aTextureCoord");  
  106.     if (textureHandle == -1) {  
  107.         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  108.                      "%s: Could not get aTextureCoord handle", __FUNCTION__);  
  109.         return -1;  
  110.     }  
  111.       
  112.     // set the vertices array in the shader  
  113.     // _vertices contains 4 vertices with 5 coordinates.  
  114.     // 3 for (xyz) for the vertices and 2 for the texture  
  115.     glVertexAttribPointer(positionHandle, 3, GL_FLOAT, false,  
  116.                           5 * sizeof(GLfloat), _vertices);  
  117.     checkGlError("glVertexAttribPointer aPosition");  
  118.       
  119.     glEnableVertexAttribArray(positionHandle);  
  120.     checkGlError("glEnableVertexAttribArray positionHandle");  
  121.       
  122.     // set the texture coordinate array in the shader  
  123.     // _vertices contains 4 vertices with 5 coordinates.  
  124.     // 3 for (xyz) for the vertices and 2 for the texture  
  125.     glVertexAttribPointer(textureHandle, 2, GL_FLOAT, false, 5  
  126.                           * sizeof(GLfloat), &_vertices[3]);  
  127.     checkGlError("glVertexAttribPointer maTextureHandle");  
  128.     glEnableVertexAttribArray(textureHandle);  
  129.     checkGlError("glEnableVertexAttribArray textureHandle");  
  130.       
  131.     glUseProgram(_program);  
  132.     int i = glGetUniformLocation(_program, "Ytex");  
  133.     checkGlError("glGetUniformLocation");  
  134.     glUniform1i(i, 0); /* Bind Ytex to texture unit 0 */  
  135.     checkGlError("glUniform1i Ytex");  
  136.       
  137.     i = glGetUniformLocation(_program, "Utex");  
  138.     checkGlError("glGetUniformLocation Utex");  
  139.     glUniform1i(i, 1); /* Bind Utex to texture unit 1 */  
  140.     checkGlError("glUniform1i Utex");  
  141.       
  142.     i = glGetUniformLocation(_program, "Vtex");  
  143.     checkGlError("glGetUniformLocation");  
  144.     glUniform1i(i, 2); /* Bind Vtex to texture unit 2 */  
  145.     checkGlError("glUniform1i");  
  146.       
  147.     glViewport(0, 0, width, height);  
  148.     checkGlError("glViewport");  
  149.     return 0;  
  150. }  
  151.   
  152. // SetCoordinates  
  153. // Sets the coordinates where the stream shall be rendered.  
  154. // Values must be between 0 and 1.  
  155. int32_t RenderOpenGles20::SetCoordinates(int32_t zOrder,  
  156.                                          const float left,  
  157.                                          const float top,  
  158.                                          const float right,  
  159.                                          const float bottom) {  
  160.     if ((top > 1 || top < 0) || (right > 1 || right < 0) ||  
  161.         (bottom > 1 || bottom < 0) || (left > 1 || left < 0)) {  
  162.         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  163.                      "%s: Wrong coordinates", __FUNCTION__);  
  164.         return -1;  
  165.     }  
  166.       
  167.     //  X, Y, Z, U, V  
  168.     // -1, -1, 0, 0, 1, // Bottom Left  
  169.     //  1, -1, 0, 1, 1, //Bottom Right  
  170.     //  1,  1, 0, 1, 0, //Top Right  
  171.     // -1,  1, 0, 0, 0  //Top Left  
  172.       
  173.     // Bottom Left  
  174.     _vertices[0] = (left * 2) - 1;  
  175.     _vertices[1] = -1 * (2 * bottom) + 1;  
  176.     _vertices[2] = zOrder;  
  177.       
  178.     //Bottom Right  
  179.     _vertices[5] = (right * 2) - 1;  
  180.     _vertices[6] = -1 * (2 * bottom) + 1;  
  181.     _vertices[7] = zOrder;  
  182.       
  183.     //Top Right  
  184.     _vertices[10] = (right * 2) - 1;  
  185.     _vertices[11] = -1 * (2 * top) + 1;  
  186.     _vertices[12] = zOrder;  
  187.       
  188.     //Top Left  
  189.     _vertices[15] = (left * 2) - 1;  
  190.     _vertices[16] = -1 * (2 * top) + 1;  
  191.     _vertices[17] = zOrder;  
  192.       
  193.     return 0;  
  194. }  
  195.   
  196. GLuint RenderOpenGles20::loadShader(GLenum shaderType, const char* pSource)  
  197. {  
  198.     GLuint shader = glCreateShader(shaderType);  
  199.     if (shader) {  
  200.         glShaderSource(shader, 1, &pSource, NULL);  
  201.         glCompileShader(shader);  
  202.         GLint compiled = 0;  
  203.         glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);  
  204.         if (!compiled) {  
  205.             GLint infoLen = 0;  
  206.             glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);  
  207.             if (infoLen) {  
  208.                 char* buf = (char*) malloc(infoLen);  
  209.                 if (buf) {  
  210.                     glGetShaderInfoLog(shader, infoLen, NULL, buf);  
  211.                     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  212.                                  "%s: Could not compile shader %d: %s",  
  213.                                  __FUNCTION__, shaderType, buf);  
  214.                     free(buf);  
  215.                 }  
  216.                 glDeleteShader(shader);  
  217.                 shader = 0;  
  218.             }  
  219.         }  
  220.     }  
  221.     return shader;  
  222. }  
  223.   
  224. GLuint RenderOpenGles20::createProgram(const char* pVertexSource,  
  225.                                        const char* pFragmentSource) {  
  226.     GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);  
  227.     if (!vertexShader) {  
  228.         return 0;  
  229.     }  
  230.       
  231.     GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);  
  232.     if (!pixelShader) {  
  233.         return 0;  
  234.     }  
  235.       
  236.     GLuint program = glCreateProgram();  
  237.     if (program) {  
  238.         glAttachShader(program, vertexShader);  
  239.         checkGlError("glAttachShader");  
  240.         glAttachShader(program, pixelShader);  
  241.         checkGlError("glAttachShader");  
  242.         glLinkProgram(program);  
  243.         GLint linkStatus = GL_FALSE;  
  244.         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);  
  245.         if (linkStatus != GL_TRUE) {  
  246.             GLint bufLength = 0;  
  247.             glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);  
  248.             if (bufLength) {  
  249.                 char* buf = (char*) malloc(bufLength);  
  250.                 if (buf) {  
  251.                     glGetProgramInfoLog(program, bufLength, NULL, buf);  
  252.                     WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  253.                                  "%s: Could not link program: %s",  
  254.                                  __FUNCTION__, buf);  
  255.                     free(buf);  
  256.                 }  
  257.             }  
  258.             glDeleteProgram(program);  
  259.             program = 0;  
  260.         }  
  261.     }  
  262.     return program;  
  263. }  
  264.   
  265. void RenderOpenGles20::printGLString(const char *name, GLenum s) {  
  266.     const char *v = (const char *) glGetString(s);  
  267.     WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "GL %s = %s\n",  
  268.                  name, v);  
  269. }  
  270.   
  271. void RenderOpenGles20::checkGlError(const char* op) {  
  272. #ifdef ANDROID_LOG  
  273.     for (GLint error = glGetError(); error; error = glGetError()) {  
  274.         WEBRTC_TRACE(kTraceError, kTraceVideoRenderer, _id,  
  275.                      "after %s() glError (0x%x)\n", op, error);  
  276.     }  
  277. #else  
  278.     return;  
  279. #endif  
  280. }  
  281.   
  282. static void InitializeTexture(int name, int id, int width, int height) {  
  283.     glActiveTexture(name);  
  284.     glBindTexture(GL_TEXTURE_2D, id);  
  285.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);  
  286.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  
  287.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);  
  288.     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);  
  289.     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, width, height, 0,  
  290.                  GL_LUMINANCE, GL_UNSIGNED_BYTE, NULL);  
  291. }  
  292.   
  293. // Uploads a plane of pixel data, accounting for stride != width*bpp.  
  294. static void GlTexSubImage2D(GLsizei width, GLsizei height, int stride,  
  295.                             const uint8_t* plane) {  
  296.     if (stride == width) {  
  297.         // Yay!  We can upload the entire plane in a single GL call.  
  298.         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE,  
  299.                         GL_UNSIGNED_BYTE,  
  300.                         static_cast<const GLvoid*>(plane));  
  301.     } else {  
  302.         // Boo!  Since GLES2 doesn't have GL_UNPACK_ROW_LENGTH and Android doesn't  
  303.         // have GL_EXT_unpack_subimage we have to upload a row at a time.  Ick.  
  304.         for (int row = 0; row < height; ++row) {  
  305.             glTexSubImage2D(GL_TEXTURE_2D, 0, 0, row, width, 1, GL_LUMINANCE,  
  306.                             GL_UNSIGNED_BYTE,  
  307.                             static_cast<const GLvoid*>(plane + (row * stride)));  
  308.         }  
  309.     }  
  310. }  
  311.   
  312. int32_t RenderOpenGles20::Render(void * data, int32_t widht, int32_t height)  
  313. {  
  314.     WEBRTC_TRACE(kTraceDebug, kTraceVideoRenderer, _id, "%s: id %d",  
  315.                  __FUNCTION__, (int) _id);  
  316.       
  317.     glUseProgram(_program);  
  318.     checkGlError("glUseProgram");  
  319.       
  320.     if (_textureWidth != (GLsizei) widht || _textureHeight != (GLsizei) height) {  
  321.         SetupTextures(widht, height);  
  322.     }  
  323.     UpdateTextures(data, widht, height);  
  324.       
  325.     glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, g_indices);  
  326.     checkGlError("glDrawArrays");  
  327.       
  328.     return 0;  
  329. }  
  330.   
  331. void RenderOpenGles20::SetupTextures(int32_t width, int32_t height)  
  332. {  
  333.     glDeleteTextures(3, _textureIds);  
  334.     glGenTextures(3, _textureIds); //Generate  the Y, U and V texture  
  335.     InitializeTexture(GL_TEXTURE0, _textureIds[0], width, height);  
  336.     InitializeTexture(GL_TEXTURE1, _textureIds[1], width / 2, height / 2);  
  337.     InitializeTexture(GL_TEXTURE2, _textureIds[2], width / 2, height / 2);  
  338.       
  339.     checkGlError("SetupTextures");  
  340.       
  341.     _textureWidth = width;  
  342.     _textureHeight = height;  
  343. }  
  344.   
  345. void RenderOpenGles20::UpdateTextures(void* data, int32_t widht, int32_t height)  
  346. {  
  347.     glActiveTexture(GL_TEXTURE0);  
  348.     glBindTexture(GL_TEXTURE_2D, _textureIds[0]);  
  349.     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widht, height, GL_LUMINANCE, GL_UNSIGNED_BYTE,  
  350.                     data);  
  351.       
  352.     glActiveTexture(GL_TEXTURE1);  
  353.     glBindTexture(GL_TEXTURE_2D, _textureIds[1]);  
  354.     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widht / 2, height / 2, GL_LUMINANCE,  
  355.                     GL_UNSIGNED_BYTE, (char *)data + widht * height);  
  356.       
  357.     glActiveTexture(GL_TEXTURE2);  
  358.     glBindTexture(GL_TEXTURE_2D, _textureIds[2]);  
  359.     glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, widht / 2, height / 2, GL_LUMINANCE,  
  360.                     GL_UNSIGNED_BYTE, (char *)data + widht * height * 5 / 4);  
  361.       
  362.     checkGlError("UpdateTextures");  
  363. }  

H264Decoder.cpp (解码代码,前面的博客贴过代码,这里就不贴了)


第三步:编译jni,生成so文件

第四步:把生成的so文件拷贝到android工程里面去,这里贴一下我的Activity代码,如下:

[java]  view plain copy
  1. package com.example.filltriangle;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.InputStream;  
  5.   
  6. import hzcw.opengl.ViERenderer;  
  7. import android.app.Activity;    
  8. import android.os.Bundle;     
  9. import android.os.Environment;  
  10. import android.util.Log;  
  11. import android.view.SurfaceView;  
  12.     
  13. public class FillTriangle extends Activity {    
  14.     
  15.     private SurfaceView mView = null;  
  16.       
  17.     static {    
  18.           System.loadLibrary("MICloudPub");  
  19.     }  
  20.     
  21.     @Override protected void onCreate(Bundle icicle) {    
  22.         super.onCreate(icicle);    
  23.         mView = ViERenderer.CreateRenderer(thistrue);  
  24.         if (mView == null) {  
  25.             Log.i("test""mView is null");  
  26.         }  
  27.         setContentView(mView);  
  28.           
  29.         GL2JNILib.init(mView);  
  30.           
  31.         new MyThread().start();  
  32.     }  
  33.       
  34.       
  35.       
  36.     public class MyThread extends Thread {    
  37.         public void run() {  
  38.             GL2JNILib.step("/sdcard/test.264");  
  39.         }    
  40.     }  
  41. }  

这个demo就是读一个视频文件,解码以后在界面显示出来。便于运行,最后上效果图哈,免得有人怀疑项目真实性。



这里打一个小广告,希望大家支持一下:

1.寻找android开发团队或者个人,有兴趣一起创业的朋友,(最好是成都本地的朋友,也欢迎有激情的应届毕业生加入)联系QQ:276775937。

2.承接ios,android应用系统开发,我们有很多成熟的案例。


原文:http://blog.csdn.net/cjj198561/article/details/34136187

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值