1. 程式人生 > >Android NDK開發 native層獲取Surface並顯示影象 思路過程

Android NDK開發 native層獲取Surface並顯示影象 思路過程


import java.io.File;
import java.io.FileInputStream;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import
 android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MainActivity extends Activity {

    private static final String ACTIVITY_TAG = "displayYUV";
    final String FILE_NAME = "/akiyo_qcif.yuv";
    final int width = 176;
    final int height = 144;
    final int size = (int
) (width * height * 1.5);
    byte[] yuvBuffer = new byte[size];
    // final Builder builder = new AlertDialog.Builder(this);
    private SurfaceHolder holder;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //
 TextView tv = new TextView(this);
        
// tv.setText( stringFromJNI() );
        
// setContentView(tv);
        
// My Code
        Log.v(ACTIVITY_TAG, stringFromJNI());
        SurfaceView surface = (SurfaceView) findViewById(R.id.show);
        // 初始化SurfaceHolder物件        holder = surface.getHolder();
        holder.addCallback(new Callback() {
            @Override
            public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
                    int arg3) {
            }

            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                setVideoSurface(holder.getSurface());
                //test(holder.getSurface());                if (read(yuvBuffer)) {
                    // 設定對話方塊的圖示
                    
// builder.setIcon(R.drawable.tools);
                    
// 設定對話方塊的標題
                    
// builder.setTitle("自定義普通對話方塊");
                    
//// 設定對話方塊顯示的內容
                    
// builder.setMessage("一個簡單的提示對話方塊");
                    
////建立、並顯示對話方塊
                    
// builder.create().show();
                    
// }
                    
// 鎖定整個SurfaceView
//                    Canvas canvas = holder.lockCanvas();
//                    canvas.drawColor(Color.WHITE);
//// 繪製背景
//// Bitmap back = BitmapFactory.decodeResource(
//// SurfaceViewTest.this.getResources(), R.drawable.sun);
//// 繪製背景
//// canvas.drawBitmap(back, 0, 0, null);
//// 繪製完成,釋放畫布,提交修改
//                    holder.unlockCanvasAndPost(canvas);
//                    yourFunction(yuvBuffer, width, height);
                    
////重新鎖一次,"持久化"上次所繪製的內容
                    
// holder.lockCanvas(new Rect(0, 0, 0, 0));
                    
// holder.unlockCanvasAndPost(canvas);                    int[] mIntArray = new int[width * height];

                    // Decode Yuv data to integer array
                    
// decodeYUV420SP(mIntArray, data, mWidth, mHeight);                    convertYUV420_NV21toRGB8888(mIntArray, yuvBuffer, width, height);
                    drawYUV(mIntArray);
                    test(holder.getSurface());
                }
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
            }
        });
    }

    private boolean read(byte[] yuvArray) {
        try {
            // 如果手機插入了SD卡,而且應用程式具有訪問SD的許可權            if (Environment.getExternalStorageState().equals(
                    Environment.MEDIA_MOUNTED)) {
                // 獲取SD卡對應的儲存目錄                File sdCardDir = Environment.getExternalStorageDirectory();
                // 獲取指定檔案對應的輸入流                FileInputStream fis = new FileInputStream(
                        sdCardDir.getCanonicalPath() + FILE_NAME);
                fis.read(yuvArray, 0, size);
                return true;
            } else {
                return false;
            }
        }

        catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    void yourFunction(byte[] data, int mWidth, int mHeight) {

        int[] mIntArray = new int[mWidth * mHeight];

        // Decode Yuv data to integer array
        
// decodeYUV420SP(mIntArray, data, mWidth, mHeight);        convertYUV420_NV21toRGB8888(mIntArray, data, mWidth, mHeight);

        // Initialize the bitmap, with the replaced color        Bitmap bmp = Bitmap.createBitmap(mIntArray, mWidth, mHeight,
                Bitmap.Config.ARGB_8888);

        Canvas canvas = holder.lockCanvas();
        canvas.drawBitmap(bmp, 0, 0, null);
        holder.unlockCanvasAndPost(canvas);
        // Draw the bitmap with the replaced color
        
// iv.setImageBitmap(bmp);
        
// ByteArrayOutputStream out = new ByteArrayOutputStream();
        
// YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width,
        
// height, null);
        
// yuvImage.compressToJpeg(new Rect(0, 0, width, height), 50, out);
        
// byte[] imageBytes = out.toByteArray();
        
// Bitmap bmp = BitmapFactory.decodeByteArray(imageBytes, 0,
        
// imageBytes.length);
        
// Canvas canvas = holder.lockCanvas();
        
// canvas.drawBitmap(bmp, 0, 0, null);
        
// holder.unlockCanvasAndPost(canvas);    }

    static public void decodeYUV420SP(int[] rgba, byte[] yuv420sp, int width,
            int height) {
        final int frameSize = width * height;

        for (int j = 0, yp = 0; j < height; j++) {
            int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
            for (int i = 0; i < width; i++, yp++) {
                int y = (0xff & ((int) yuv420sp[yp])) - 16;
                if (y < 0)
                    y = 0;
                if ((i & 1) == 0) {
                    v = (0xff & yuv420sp[uvp++]) - 128;
                    u = (0xff & yuv420sp[uvp++]) - 128;
                }

                int y1192 = 1192 * y;
                int r = (y1192 + 1634 * v);
                int g = (y1192 - 833 * v - 400 * u);
                int b = (y1192 + 2066 * u);

                if (r < 0)
                    r = 0;
                else if (r > 262143)
                    r = 262143;
                if (g < 0)
                    g = 0;
                else if (g > 262143)
                    g = 262143;
                if (b < 0)
                    b = 0;
                else if (b > 262143)
                    b = 262143;

                // rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &
                
// 0xff00) | ((b >> 10) & 0xff);
                
// rgba, divide 2^10 ( >> 10)                rgba[yp] = ((r << 14) & 0xff000000) | ((g << 6) & 0xff0000)
                        | ((b >> 2) | 0xff00);
            }
        }
    }

    /**
     * Converts YUV420 NV21 to RGB8888
     * 
     * 
@param data
     *            byte array on YUV420 NV21 format.
     * 
@param width
     *            pixels width
     * 
@param height
     *            pixels height
     * 
@return a RGB8888 pixels int array. Where each int is a pixels ARGB.
     
*/
    public static void convertYUV420_NV21toRGB8888(int[] rgba, byte[] data,
            int width, int height) {
        int size = width * height;
        int offset = size;
        // int[] pixels = new int[size];        int u, v, y1, y2, y3, y4;

        // i percorre os Y and the final pixels
        
// k percorre os pixles U e V        for (int i = 0, k = 0; i < size; i += 2, k += 2) {
            y1 = data[i] & 0xff;
            y2 = data[i + 1] & 0xff;
            y3 = data[width + i] & 0xff;
            y4 = data[width + i + 1] & 0xff;

            u = data[offset + k] & 0xff;
            v = data[offset + k + 1] & 0xff;
            u = u - 128;
            v = v - 128;

            rgba[i] = convertYUVtoRGB(y1, u, v);
            rgba[i + 1] = convertYUVtoRGB(y2, u, v);
            rgba[width + i] = convertYUVtoRGB(y3, u, v);
            rgba[width + i + 1] = convertYUVtoRGB(y4, u, v);

            if (i != 0 && (i + 2) % width == 0)
                i += width;
        }

        // return pixels;    }

    private static int convertYUVtoRGB(int y, int u, int v) {
        int r, g, b;

        r = y + (int) 1.402f * v;
        g = y - (int) (0.344f * u + 0.714f * v);
        b = y + (int) 1.772f * u;
        r = r > 255 ? 255 : r < 0 ? 0 : r;
        g = g > 255 ? 255 : g < 0 ? 0 : g;
        b = b > 255 ? 255 : b < 0 ? 0 : b;
        return 0xff000000 | (b << 16) | (g << 8) | r;
    }

    // @Override
    
// public boolean onCreateOptionsMenu(Menu menu) {
    
//// Inflate the menu; this adds items to the action bar if it is present.
    
// getMenuInflater().inflate(R.menu.activity_main, menu);
    
// return true;
    
// }    public native String stringFromJNI();

    private native void setVideoSurface(Surface surface);

    private native void test(Surface surface);

    private native void test2(Surface surface);
    private native void drawYUV(int[] yuvData);
    static {
        System.loadLibrary("drawSurface");
    }
}