Android camera、surfaceview、mediarecorder播放、抓拍与录制、前后置切换

本文介绍如何使用Android平台的SurfaceView组件实现手机摄像头的预览、拍照及录制视频功能。重点讨论了参数设置顺序、预览尺寸调整、图像旋转处理及视频格式配置等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用手机自带照相camera,显示在surfaceview上,然后就进行抓怕和录制

一、在surfaceview上显示与拍照、录制,需要考虑以下几点

        1、参数设置顺序(特别是录制时,如果参数设置的顺序有误,无法正常录制)

        2、手机支持的预览、拍照、录制像素设置(图像模糊、录像花屏)

        3、其他参数设置必须符合当前手机

        4、摄像头显示时的旋转角度

        5、手机支持的格式设置

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical" >
    
    <SurfaceView 
        android:id="@+id/surfaceView"
        android:layout_width="300dp"
        android:layout_height="300dp" />
    <Button 
        android:id="@+id/changge"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="后置摄像头" />
    <Button 
        android:id="@+id/preview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="预览" />
    <Button 
        android:id="@+id/capture"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="抓拍" />
    <Button 
        android:id="@+id/record"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="开始录制" />

</LinearLayout>

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" /> 
    <uses-permission android:name="android.permission.CAMERA" />
    

package com.chenhan.cameratest;

import java.io.File;
import java.io.FileOutputStream;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Environment;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class LocalMedia implements Callback, PreviewCallback
{
	private Camera.Parameters mParameters = null;
	@SuppressLint("InlinedApi")
	private int mCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
	private Camera camera;
	private SurfaceHolder surfaceHolder;
	private int width = 1280;
	private int height = 720;
	private Activity activity;
	private MediaRecorder mediaRecorder;

	@SuppressLint("NewApi")
	@SuppressWarnings("deprecation")
	public LocalMedia(Activity activity, SurfaceView surfaceView, int cameraId)
	{
		this.activity = activity;
		this.mCameraId = cameraId;
		surfaceHolder = surfaceView.getHolder();
		surfaceHolder.setFixedSize(width, height);
		surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		surfaceHolder.addCallback(this);
		//startPreview();
	}

	public Camera getCamera()
	{
		return camera;
	}

	public int getCameraId()
	{
		return mCameraId;
	}

	public void startPreview()
	{
		System.out.println("hhhh");
		if (camera != null)
		{
			camera.startPreview();
			System.out.println("cccc");
		}
	}

	public void stopPreview()
	{
		if (camera != null)
		{
			camera.stopPreview();
			camera.setPreviewCallback(null);
			camera.release();
			camera = null;
		}
	}

	@SuppressLint("NewApi")
	@Override
	public void surfaceCreated(SurfaceHolder holder)
	{
		try
		{
			//if (mCameraId == Camera.CameraInfo.CAMERA_FACING_BACK)
			//{
				//camera = Camera.open();
			//}
			//else
			//{
				camera = Camera.open(mCameraId);
			//}
			if (camera != null)
			{
				/*
				 * List<Size> sizes =
				 * camera.getParameters().getSupportedPreviewSizes(); for(int i
				 * = 0; i < sizes.size(); i++) { Log.e("Preview", "w = " +
				 * sizes.get(i).width + ";h = " + sizes.get(i).height); }
				 */
				/*
				 * List<Size> sizes2 =
				 * camera.getParameters().getSupportedPictureSizes(); for(int i
				 * = 0; i < sizes2.size(); i++) { Log.e("Picture", "w = " +
				 * sizes2.get(i).width + ";h = " + sizes2.get(i).height); }
				 */
				camera.setPreviewDisplay(surfaceHolder);
				camera.setDisplayOrientation(getDispalyOritation(activity,
						mCameraId));
				mParameters = camera.getParameters();
				mParameters.setPreviewSize(1280, 720);
				mParameters.setPictureSize(640, 480);
				mParameters.setPreviewFormat(ImageFormat.YV12);
				camera.setParameters(mParameters);
				camera.setPreviewCallback(this);
				//startPreview();
				System.out.println("bbbb");
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	@SuppressLint("NewApi") 
	public void setCameraId(int camreaId)
	{
		
		try
		{
			camera = Camera.open(camreaId);
			if (camera != null) 
			{
				camera.setPreviewDisplay(surfaceHolder);
				camera.setDisplayOrientation(getDispalyOritation(activity,
						mCameraId));
				mParameters = camera.getParameters();
				mParameters.setPreviewSize(1280, 720);
				mParameters.setPictureSize(640, 480);
				mParameters.setPreviewFormat(ImageFormat.YV12);
				camera.setParameters(mParameters);
				camera.setPreviewCallback(this);
				startPreview();
			}
		}
		catch (Exception e)
		{
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height)
	{

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder)
	{
		if (camera != null)
		{
			camera.setPreviewCallback(null);
			camera.stopPreview();
			camera.release();
			camera = null;
		}
	}

	@Override
	public void onPreviewFrame(byte[] data, Camera camera)
	{

	}

	public void takePicture()
	{
		camera.takePicture(mshutter, null, MJpeg);
	}

	public Camera.PictureCallback MJpeg = new Camera.PictureCallback()
	{
		@SuppressLint("InlinedApi")
		@Override
		public void onPictureTaken(byte[] data, Camera camera)
		{
			try
			{
				Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length);
				Matrix matrix = new Matrix();
				matrix.postRotate(getDispalyOritation(activity, mCameraId));
				mParameters.setPreviewFormat(ImageFormat.YV12);
				bm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(),
						bm.getHeight(), matrix, true);
				String jpgFile = Environment.getExternalStorageDirectory()
						.getAbsolutePath() + "/a.jpg";
				File file = new File(jpgFile);
				FileOutputStream fos = new FileOutputStream(file);
				bm.compress(Bitmap.CompressFormat.JPEG, 100, fos);
				if (camera != null)
				{
					camera.startPreview();
				}
				fos.close();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
	};

	public Camera.ShutterCallback mshutter = new Camera.ShutterCallback()
	{
		@Override
		public void onShutter()
		{

		}
	};

	@SuppressLint("NewApi") public void startRecord()
	{
		mediaRecorder = new MediaRecorder();
		if (camera != null)
		{
			mediaRecorder.setCamera(camera);

			mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

			// mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);

			mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
			mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
			// 选择当前终端适合的预览size
			/*
			 * List<Size> sizes1 =
			 * camera.getParameters().getSupportedVideoSizes(); for(int i = 0; i
			 * < sizes1.size(); i++) { Log.e("Video", "w = " +
			 * sizes1.get(i).width + ";h = " + sizes1.get(i).height); }
			 */
			mediaRecorder.setVideoSize(width, height);// 设置分辨率 防止录制的视频出现花屏

			// mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);

			mediaRecorder.setOrientationHint(getDispalyOritation(activity,
					mCameraId));
			mediaRecorder.setOutputFile(Environment.getExternalStorageDirectory()
					.getAbsolutePath() + "/b.mkv");
			/*
			 * mediaRecorder
			 * .setOutputFile(Environment.getExternalStorageDirectory()
			 * .getAbsolutePath() + "/b.mkv");
			 */
			try
			{
				camera.setDisplayOrientation(getDispalyOritation(activity,
						mCameraId));
				camera.unlock();
				mediaRecorder.prepare();
				mediaRecorder.start();
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}

		}

	}

	public void stopRecord()
	{
		if (mediaRecorder != null)
		{
			try
			{
				mediaRecorder.stop();
				mediaRecorder.release();
				mediaRecorder = null;
			}
			catch (Exception e)
			{
				e.printStackTrace();
			}
		}
	}

	@TargetApi(Build.VERSION_CODES.GINGERBREAD)
	@SuppressLint("NewApi")
	private int getDispalyOritation(Activity activity, int cameraId)
	{
		int degrees = activity.getWindowManager().getDefaultDisplay()
				.getRotation();
		Camera.CameraInfo info = new Camera.CameraInfo();
		Camera.getCameraInfo(cameraId, info);
		int result;
		if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
		{
			degrees = getDisplayFrontRotation(degrees);
			result = (info.orientation + degrees) % 360;
			result = (360 - result) % 360;
		}
		else
		{
			degrees = getDisplayBackRotation(degrees);
			result = (info.orientation - degrees + 360) % 360;
		}
		return result;
	}

	private int getDisplayBackRotation(int degrees)
	{
		switch (degrees)
		{
		case Surface.ROTATION_0:
			return 0;
		case Surface.ROTATION_90:
			return 90;
		case Surface.ROTATION_180:
			return 180;
		case Surface.ROTATION_270:
			return 190;
		default:
			break;
		}
		return 0;
	}

	private int getDisplayFrontRotation(int degrees)
	{
		switch (degrees)
		{
		case Surface.ROTATION_0:
			return 180;
		case Surface.ROTATION_90:
			return 270;
		case Surface.ROTATION_180:
			return 0;
		case Surface.ROTATION_270:
			return 90;
		default:
			break;
		}
		return 0;
	}
}

package com.chenhan.cameratest;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener
{

	private SurfaceView surfaceView;
	private Button changge, preview, capture, record;
	private LocalMedia surfaceCallback;
	private boolean startPreview = false;
	private boolean recordPreview = false;
	private boolean isBack = true;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initView();
		initSurface();
	}

	private void initView()
	{
		surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
		surfaceView.setOnClickListener(this);
		changge = (Button) findViewById(R.id.changge);
		changge.setOnClickListener(this);
		preview = (Button) findViewById(R.id.preview);
		preview.setOnClickListener(this);
		capture = (Button) findViewById(R.id.capture);
		capture.setOnClickListener(this);
		record = (Button) findViewById(R.id.record);
		record.setOnClickListener(this);
	}

	@SuppressLint("InlinedApi") 
	private void initSurface()
	{
		surfaceCallback = new LocalMedia(this, surfaceView, Camera.CameraInfo.CAMERA_FACING_BACK);
	}

	@TargetApi(Build.VERSION_CODES.GINGERBREAD) @SuppressLint("InlinedApi") 
	@Override
	public void onClick(View v)
	{
		// TODO 自动生成的方法存根
		switch (v.getId())
		{
		case R.id.changge:
			if (startPreview)
			{
				if (isBack)
				{
					changge.setText("前置摄像头");
					surfaceCallback.stopPreview();
					surfaceCallback.setCameraId(Camera.CameraInfo.CAMERA_FACING_FRONT);
				}
				else
				{
					changge.setText("后置摄像头");
					surfaceCallback.stopPreview();
					surfaceCallback.setCameraId(Camera.CameraInfo.CAMERA_FACING_BACK);
					
				}
				isBack = !isBack;
			}
			else
			{
				Toast.makeText(this, "请先预览", Toast.LENGTH_SHORT).show();
			}
			break;
		case R.id.preview:
			Log.e("aaaaaaaaa", "aaaaaaa");
			if (!startPreview)
			{
				
				//surfaceCallback = new LocalMedia(this, surfaceView, Camera.CameraInfo.CAMERA_FACING_BACK);
				surfaceCallback.startPreview();
				preview.setText("停止");
			}
			else
			{
				surfaceCallback.stopPreview();
				preview.setText("播放");
			}
			startPreview = !startPreview;
			break;
		case R.id.capture:
			surfaceCallback.getCamera().takePicture(surfaceCallback.mshutter,
					null, surfaceCallback.MJpeg);
			break;
		case R.id.record:
			if (!recordPreview)
			{
				record.setText("录制中");
				surfaceCallback.startRecord();
			}
			else
			{
				record.setText("录制结束");
				Toast.makeText(this, "停止录制", Toast.LENGTH_SHORT).show();
				surfaceCallback.stopRecord();
			}
			recordPreview = !recordPreview;
			break;
		default:
			break;
		}
	}

}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值