Android用surface直接显示yuv数据(三)

来源:互联网 发布:java把网址生成二维码 编辑:程序博客网 时间:2024/05/16 11:39

    本文用Java创建UI并联合JNI层操作surface来直接显示yuv数据(yv12),开发环境为Android 4.4,全志A23平台。

[java] view plain copy
  1. package com.example.myyuvviewer;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import android.app.Activity;  
  6. import android.os.Bundle;  
  7. import android.os.Environment;  
  8. import android.util.Log;  
  9. import android.view.Surface;  
  10. import android.view.SurfaceHolder;  
  11. import android.view.SurfaceHolder.Callback;  
  12. import android.view.SurfaceView;  
  13.   
  14. public class MainActivity extends Activity {  
  15.   
  16.     final private String TAG = "MyYUVViewer";  
  17.     final private String FILE_NAME = "yuv_320_240.yuv";  
  18.     private int width = 320;  
  19.     private int height = 240;  
  20.     private int size = width * height * 3/2;  
  21.       
  22.     @Override  
  23.     protected void onCreate(Bundle savedInstanceState) {  
  24.         super.onCreate(savedInstanceState);  
  25.         setContentView(R.layout.activity_main);  
  26.         nativeTest();  
  27.         SurfaceView surfaceview = (SurfaceView) findViewById(R.id.surfaceView);  
  28.         SurfaceHolder holder = surfaceview.getHolder();  
  29.         holder.addCallback(new Callback(){  
  30.   
  31.             @Override  
  32.             public void surfaceCreated(SurfaceHolder holder) {  
  33.                 // TODO Auto-generated method stub  
  34.                 Log.d(TAG,"surfaceCreated");  
  35.                 byte[]yuvArray = new byte[size];  
  36.                 readYUVFile(yuvArray, FILE_NAME);  
  37.                 nativeSetVideoSurface(holder.getSurface());  
  38.                 nativeShowYUV(yuvArray,width,height);  
  39.             }  
  40.   
  41.             @Override  
  42.             public void surfaceChanged(SurfaceHolder holder, int format,  
  43.                     int width, int height) {  
  44.                 // TODO Auto-generated method stub  
  45.                   
  46.             }  
  47.   
  48.             @Override  
  49.             public void surfaceDestroyed(SurfaceHolder holder) {  
  50.                 // TODO Auto-generated method stub  
  51.                   
  52.             }});  
  53.     }  
  54.       
  55.     private boolean readYUVFile(byte[] yuvArray,String filename){  
  56.         try {  
  57.             // 如果手机插入了SD卡,而且应用程序具有访问SD的权限  
  58.             if (Environment.getExternalStorageState().equals(  
  59.                     Environment.MEDIA_MOUNTED)) {  
  60.                 // 获取SD卡对应的存储目录  
  61.                 File sdCardDir = Environment.getExternalStorageDirectory();  
  62.                 // 获取指定文件对应的输入流  
  63.                 FileInputStream fis = new FileInputStream(  
  64.                         sdCardDir.getCanonicalPath() +"/" + filename);  
  65.                 fis.read(yuvArray, 0, size);  
  66.                 fis.close();  
  67.                 return true;  
  68.             } else {  
  69.                 return false;  
  70.             }  
  71.         }catch (Exception e) {  
  72.             e.printStackTrace();  
  73.             return false;  
  74.         }  
  75.     }  
  76.     private native void nativeTest();  
  77.     private native boolean nativeSetVideoSurface(Surface surface);  
  78.     private native void nativeShowYUV(byte[] yuvArray,int width,int height);  
  79.     static {  
  80.         System.loadLibrary("showYUV");  
  81.     }  
  82. }  
activity_main.xml
[html] view plain copy
  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
  2.     android:layout_width="fill_parent"    
  3.     android:layout_height="fill_parent"    
  4.     android:orientation="vertical" >    
  5.     
  6.     <SurfaceView    
  7.         android:id="@+id/surfaceView"    
  8.         android:layout_width="fill_parent"    
  9.         android:layout_height="360dp" />   
  10.           
  11. </LinearLayout>  

JNI层,showYUV.cpp(libshowyuv.so)采用动态注册JNI函数的方法.

[cpp] view plain copy
  1. #include <jni.h>  
  2. #include <android_runtime/AndroidRuntime.h>  
  3. #include <android_runtime/android_view_Surface.h>  
  4. #include <gui/Surface.h>  
  5. #include <assert.h>  
  6. #include <utils/Log.h>  
  7. #include <JNIHelp.h>  
  8. #include <media/stagefright/foundation/ADebug.h>  
  9. #include <ui/GraphicBufferMapper.h>  
  10. #include <cutils/properties.h>  
  11. using namespace android;  
  12.   
  13. static sp<Surface> surface;  
  14.   
  15. static int ALIGN(int x, int y) {  
  16.     // y must be a power of 2.  
  17.     return (x + y - 1) & ~(y - 1);  
  18. }  
  19.   
  20. static void render(  
  21.         const void *data, size_t size, const sp<ANativeWindow> &nativeWindow,int width,int height) {  
  22.     ALOGE("[%s]%d",__FILE__,__LINE__);  
  23.     sp<ANativeWindow> mNativeWindow = nativeWindow;  
  24.     int err;  
  25.     int mCropWidth = width;  
  26.     int mCropHeight = height;  
  27.       
  28.     int halFormat = HAL_PIXEL_FORMAT_YV12;//颜色空间  
  29.     int bufWidth = (mCropWidth + 1) & ~1;//按2对齐  
  30.     int bufHeight = (mCropHeight + 1) & ~1;  
  31.       
  32.     CHECK_EQ(0,  
  33.             native_window_set_usage(  
  34.             mNativeWindow.get(),  
  35.             GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN  
  36.             | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP));  
  37.   
  38.     CHECK_EQ(0,  
  39.             native_window_set_scaling_mode(  
  40.             mNativeWindow.get(),  
  41.             NATIVE_WINDOW_SCALING_MODE_SCALE_CROP));  
  42.   
  43.     // Width must be multiple of 32???  
  44.     //很重要,配置宽高和和指定颜色空间yuv420  
  45.     //如果这里不配置好,下面deque_buffer只能去申请一个默认宽高的图形缓冲区  
  46.     CHECK_EQ(0, native_window_set_buffers_geometry(  
  47.                 mNativeWindow.get(),  
  48.                 bufWidth,  
  49.                 bufHeight,  
  50.                 halFormat));  
  51.       
  52.       
  53.     ANativeWindowBuffer *buf;//描述buffer  
  54.     //申请一块空闲的图形缓冲区  
  55.     if ((err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(),  
  56.             &buf)) != 0) {  
  57.         ALOGW("Surface::dequeueBuffer returned error %d", err);  
  58.         return;  
  59.     }  
  60.   
  61.     GraphicBufferMapper &mapper = GraphicBufferMapper::get();  
  62.   
  63.     Rect bounds(mCropWidth, mCropHeight);  
  64.   
  65.     void *dst;  
  66.     CHECK_EQ(0, mapper.lock(//用来锁定一个图形缓冲区并将缓冲区映射到用户进程  
  67.                 buf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst));//dst就指向图形缓冲区首地址  
  68.   
  69.     if (true){  
  70.         size_t dst_y_size = buf->stride * buf->height;  
  71.         size_t dst_c_stride = ALIGN(buf->stride / 2, 16);//1行v/u的大小  
  72.         size_t dst_c_size = dst_c_stride * buf->height / 2;//u/v的大小  
  73.           
  74.         memcpy(dst, data, dst_y_size + dst_c_size*2);//将yuv数据copy到图形缓冲区  
  75.     }  
  76.   
  77.     CHECK_EQ(0, mapper.unlock(buf->handle));  
  78.   
  79.     if ((err = mNativeWindow->queueBuffer(mNativeWindow.get(), buf,  
  80.             -1)) != 0) {  
  81.         ALOGW("Surface::queueBuffer returned error %d", err);  
  82.     }  
  83.     buf = NULL;  
  84. }  
  85.   
  86. static void nativeTest(){  
  87.     ALOGE("[%s]%d",__FILE__,__LINE__);  
  88. }  
  89.   
  90. static jboolean  
  91. nativeSetVideoSurface(JNIEnv *env, jobject thiz, jobject jsurface){  
  92.     ALOGE("[%s]%d",__FILE__,__LINE__);  
  93.     surface = android_view_Surface_getSurface(env, jsurface);  
  94.     if(android::Surface::isValid(surface)){  
  95.         ALOGE("surface is valid ");  
  96.     }else {  
  97.         ALOGE("surface is invalid ");  
  98.         return false;  
  99.     }  
  100.     ALOGE("[%s][%d]\n",__FILE__,__LINE__);  
  101.     return true;  
  102. }  
  103. static void  
  104. nativeShowYUV(JNIEnv *env, jobject thiz,jbyteArray yuvData,jint width,jint height){  
  105.     ALOGE("width = %d,height = %d",width,height);  
  106.     jint len = env->GetArrayLength(yuvData);  
  107.     ALOGE("len = %d",len);  
  108.     jbyte *byteBuf = env->GetByteArrayElements(yuvData, 0);  
  109.     render(byteBuf,len,surface,width,height);  
  110. }  
  111. static JNINativeMethod gMethods[] = {  
  112.     {"nativeTest",                  "()V",                              (void *)nativeTest},  
  113.     {"nativeSetVideoSurface",       "(Landroid/view/Surface;)Z",        (void *)nativeSetVideoSurface},  
  114.     {"nativeShowYUV",               "([BII)V",                          (void *)nativeShowYUV},  
  115. };  
  116.   
  117. static const charconst kClassPathName = "com/example/myyuvviewer/MainActivity";  
  118.   
  119. // This function only registers the native methods  
  120. static int register_com_example_myyuvviewer(JNIEnv *env)  
  121. {  
  122.     ALOGE("[%s]%d",__FILE__,__LINE__);  
  123.     return AndroidRuntime::registerNativeMethods(env,  
  124.                 kClassPathName, gMethods, NELEM(gMethods));  
  125. }  
  126.   
  127. jint JNI_OnLoad(JavaVM* vm, void* reserved)  
  128. {  
  129.     ALOGE("[%s]%d",__FILE__,__LINE__);  
  130.     JNIEnv* env = NULL;  
  131.     jint result = -1;  
  132.   
  133.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {  
  134.         ALOGE("ERROR: GetEnv failed\n");  
  135.         goto bail;  
  136.     }  
  137.     assert(env != NULL);  
  138.     ALOGE("[%s]%d",__FILE__,__LINE__);  
  139.    if (register_com_example_myyuvviewer(env) < 0) {  
  140.         ALOGE("ERROR: MediaPlayer native registration failed\n");  
  141.         goto bail;  
  142.     }  
  143.   
  144.     /* success -- return valid version number */  
  145.     result = JNI_VERSION_1_4;  
  146.   
  147. bail:  
  148.     return result;  
  149. }  

Android.mk

[plain] view plain copy
  1. LOCAL_PATH:= $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3.   
  4. LOCAL_SRC_FILES:= \  
  5.     showYUV.cpp  
  6.       
  7. LOCAL_SHARED_LIBRARIES := \  
  8.     libcutils \  
  9.     libutils \  
  10.     libbinder \  
  11.     libui \  
  12.     libgui \  
  13.     libandroid_runtime \  
  14.     libstagefright_foundation  
  15.       
  16. LOCAL_MODULE:= libshowYUV  
  17.   
  18. LOCAL_MODULE_TAGS := tests  
  19.   
  20. include $(BUILD_SHARED_LIBRARY)  

生成的so文件复制到Java项目里 与src并列的libs/armeabi目录下,没有就手动创建目录,

这样Eclipse会自动把so库打包进apk。

转载请注明出处:http://blog.csdn.net/tung214/article/details/37762487

yuvdata下载地址:点击打开链接

0 0
原创粉丝点击