关于 setPreviewDisplay(null) 无法正常显示的问题

    在 “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()); //null
mCamera.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 preview
			Log.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);
		}
	}
}

    注意

















                
Android 中,可以通过设置 Camera.Parameters 中的 setPreviewSize 和 setPreviewFormat 方法来实现相机预览的翻转。 首先,需要获取当前设备支持的预览尺寸和格式。可以使用 Camera.Parameters 中的 getSupportedPreviewSizes 和 getSupportedPreviewFormats 方法来获取支持的预览尺寸和格式列表。 然后,可以通过 setPreviewSize 和 setPreviewFormat 方法来设置预览尺寸和格式。在设置预览尺寸时,需要根据设备的旋转角度进行调整,以保证预览画面正常显示。可以使用 CameraInfo 中的 orientation 字段来获取设备的旋转角度。 最后,可以使用 SurfaceView 或 TextureView 来显示相机预览画面,并使用 Camera.setPreviewDisplay 方法将预览画面与相机绑定起来。 下面是一个简单的示例代码,可以实现相机预览翻转: ``` public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private Camera mCamera; private int mRotation; public CameraPreview(Context context) { super(context); getHolder().addCallback(this); } public void surfaceCreated(SurfaceHolder holder) { try { mCamera = Camera.open(); mCamera.setPreviewDisplay(holder); // 获取支持的预览尺寸和格式 Camera.Parameters params = mCamera.getParameters(); List<Camera.Size> sizes = params.getSupportedPreviewSizes(); int format = params.getPreviewFormat(); // 根据设备旋转角度调整预览尺寸 Camera.CameraInfo info = new Camera.CameraInfo(); Camera.getCameraInfo(0, info); int rotation = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation(); int degrees = 0; switch (rotation) { case Surface.ROTATION_0: degrees = 0; break; case Surface.ROTATION_90: degrees = 90; break; case Surface.ROTATION_180: degrees = 180; break; case Surface.ROTATION_270: degrees = 270; break; } if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { mRotation = (info.orientation + degrees) % 360; mRotation = (360 - mRotation) % 360; } else { mRotation = (info.orientation - degrees + 360) % 360; } for (Camera.Size size : sizes) { if (size.width * 3 == size.height * 4) { params.setPreviewSize(size.width, size.height); break; } } // 设置预览格式和旋转角度 params.setPreviewFormat(format); mCamera.setDisplayOrientation(mRotation); mCamera.setParameters(params); // 开始预览 mCamera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 暂时不需要处理 } public void surfaceDestroyed(SurfaceHolder holder) { mCamera.stopPreview(); mCamera.release(); mCamera = null; } } ``` 这个示例代码可以实现在相机预览时根据设备的旋转角度进行调整,保证预览画面正常显示。如果需要实现更复杂的功能,比如相机拍照、录制视频等,可以参考 Android 官方文档中的 Camera 相关章节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值