在 “Android NDK Beginner Guide”中第4章有段例程展示在Java中调用JNI的C代码,使用了CameraView类演示了用JNI C代码自己转换YUV420到RGB888的过程,但是实际这段代码在模拟器上倒是没问题,在很多实机上却无法显示。
在国外网站上一般就说是 Android3.0后的版本中CAmera对象的setPreviewDisplay不能使用null作为参数,否则 onPreviewFrame 回调函数不会被调用。按这个提示修改后,将在界面上看到两个预览图案,类似画中画效果,小的画面是通过 onPreviewFrame -> OnDraw调用的。大的是setPreviewDisplay绑定当前SurfaceView自动刷新的。不知道大家还有没有更好的解决办法。
public class CameraView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback { static { System.loadLibrary("livaCamera"); } public static final String TAG = "CameraView"; public native void decode(Bitmap pTarget, byte[] pSource); private Camera mCamera; private byte[] mVideoSource; private Bitmap mBackBuffer; private Paint mPaint; public CameraView(Context context) { super(context); getHolder().addCallback(this); setWillNotDraw(false); } public void surfaceCreated(SurfaceHolder holder) { Log.v(TAG, "surfaceCreated()"); try { mCamera = Camera.open(); mCamera.setDisplayOrientation(0);// mCamera.setPreviewDisplay(null); // 使用空的SurfaceHolder参数无法显示mCamera.setPreviewDisplay(this.getHolder()); //nullmCamera.setPreviewCallbackWithBuffer(this);Log.d(TAG, "surfaceCreated() startPreview Success "); } catch (Exception e) { mCamera.release(); mCamera = null; throw new IllegalStateException(); } } public void surfaceChanged(SurfaceHolder pHolder, int pFormat, int pWidth, int pHeight) { Log.v(TAG, "surfaceChanged()");try {mCamera.stopPreview();Log.d(TAG, "surfaceChanged() stopPreview Success ");} catch (Exception e){// ignore: tried to stop a non-existent previewLog.d(TAG, "surfaceChanged() stopPreview Failed ");} Size lSize = findBestResolution(pWidth, pHeight); PixelFormat lPixelFormat = new PixelFormat(); PixelFormat.getPixelFormatInfo( mCamera.getParameters().getPreviewFormat(), lPixelFormat); int lSourceSize = lSize.width * lSize.height * lPixelFormat.bitsPerPixel / 8; if( mVideoSource == null ) { mVideoSource = new byte[lSourceSize]; } if( mBackBuffer == null ) { mBackBuffer = Bitmap.createBitmap(lSize.width, lSize.height,Bitmap.Config.ARGB_8888); } Camera.Parameters lParameters = mCamera.getParameters(); lParameters.setPreviewSize(lSize.width, lSize.height); lParameters.setPreviewFormat(ImageFormat.NV21); // PixelFormat.YCbCr_422_I deprecated in API level 8. mCamera.setParameters(lParameters); mCamera.addCallbackBuffer(mVideoSource); try { //mCamera.setPreviewDisplay(null); mCamera.startPreview(); Log.d(TAG, "surfaceChanged() startPreview Success "); } catch (Exception e){ // ignore: tried to stop a non-existent preview Log.d(TAG, "surfaceChanged() startPreview Failed "); } } private Size findBestResolution(int pWidth, int pHeight) { List<Size> lSizes = mCamera.getParameters().getSupportedPreviewSizes(); Size lSelectedSize = mCamera.new Size(0, 0);for (Size lSize : lSizes) { if ((lSize.width <= pWidth) && (lSize.height <= pHeight) && (lSize.width >= lSelectedSize.width) && (lSize.height >= lSelectedSize.height)) { lSelectedSize = lSize; } } if ((lSelectedSize.width == 0) || (lSelectedSize.height == 0)) { lSelectedSize = lSizes.get(0); } return lSelectedSize; } public void surfaceDestroyed(SurfaceHolder holder) { Log.v(TAG, "surfaceDestroyed()"); if (mCamera != null) { mCamera.stopPreview(); try { mCamera.reconnect(); } catch (IOException e) { e.printStackTrace(); } mCamera.release(); mCamera = null; mVideoSource = null; mBackBuffer = null; } } public void onPreviewFrame(byte[] pData, Camera pCamera) { int[] px = new int[100]; Log.v(TAG, "onPreviewFrame()"); decode(mBackBuffer, pData); mFrameCnt++; invalidate(); } @Override protected void onDraw(Canvas pCanvas) { Log.v(TAG, "onDraw()"); if (mCamera != null) { pCanvas.drawBitmap(mBackBuffer, 0, 0, mPaint); mCamera.addCallbackBuffer(mVideoSource); } } }注意