Camera基础

 

Camera可以选择两种拍照和视频方式,第一种是使用广播告知系统帮助拍照,第二种是自己实行预览拍照和拍摄视频

权限:

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-feature android:name="android.hardware.camera" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-feature android:name="android.hardware.camera.autofocus" />
    <uses-feature android:name="android.hardware.camera.flash" />


一、广播拍照/拍摄视频 创建Intent,指定拍照类型

MediaStore.ACTION_IMAGE_CAPTURE 拍摄照片;

MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频;

Intent intent = new Intent(MediaStore.ACTION_IMAGE/VIDEO_CAPTURE);

intent.putExtra(MediaStore.EXTRA_OUTPUT, “保存路径”);

startActivityForResult(intent, 0); 在重写onActivityResult后,返回intent会携带照片uri,Uri uri = data.getData(),然后根据返回的uri在数据库中查找相关信息

有部分手机在获取到uri后无法获取实际尺寸的照片,解决方法如下:

扫描二维码关注公众号,回复: 2761359 查看本文章

String filename = "xxx.jpg";

cameraFile = new File(Environment.getExternalStorageDirectory()+"/"+"自己文件夹名称"+filename);

Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(cameraFile));

startActivityForResult(intent, REQUEST_CODE_CAPTURE_CAMEIA);

在重写onActivityResult后FileInputStream fis = new FileInputStream(cameraFile);bitmap = BitmapFactory.decodeStream(fis);再根据bitmap获取图片

二、使用camera.takePicture()获取照片

package com.zzr.takepicture;

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

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class MainActivity extends Activity implements SurfaceHolder.Callback{
	private Button btTakePic;
	private Camera camera;
	private LayoutInflater inflater;
	private SurfaceView surfaceView;
	private SurfaceHolder holder;
	private View view;
	private ShutterCallback mshutter = new ShutterCallback(){
		@Override
		public void onShutter() {
		}
	};
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setType(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		inflater = LayoutInflater.from(this);
		view = inflater.inflate(R.layout.activity_main, null);
		setContentView(view);
		surfaceView = (SurfaceView) view.findViewById(R.id.movView);
		btTakePic = (Button) view.findViewById(R.id.take_pic);
		holder =surfaceView.getHolder();
		holder.addCallback(this);
		btTakePic.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				camera.takePicture(null, null, picCallback);
			}
		});
	}


	private Camera.PictureCallback picCallback = new PictureCallback(){
		@Override
		public void onPictureTaken(byte[] data, Camera camera1) {
			camera.startPreview();
			try {
				String path1 = "/sdcard/pic";
				File file1 = new File(path1);
				if(!file1.exists()) {
					file1.mkdir();
				}
				String path = path1+File.separator+System.currentTimeMillis()+".jpg";
				File file = new File(path);
				if(!file.exists()) {
					file.createNewFile();
				} 
				FileOutputStream fos = new FileOutputStream(file);
				Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
				bitmap.compress(CompressFormat.JPEG, 100, fos);
			}catch (IOException e) {
				e.printStackTrace();
			}
		}
	};

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		Log.i("zhangziran", "surfaceCreated");
		//打开摄像头,获得Camera对象
		camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
		try {
			//设置显示
			camera.setPreviewDisplay(holder);
			camera.setDisplayOrientation(90);
		} catch (IOException exception) {
			camera.release();
			camera = null;
		}
		
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		Log.i("zhangziran", "surfaceChanged");
		//已经获得Surface的width和height,设置Camera的参数
		Camera.Parameters parameters = camera.getParameters();
		parameters.setPreviewSize(height, width);
		//设置白平衡
		parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
		//设置场景模式
		parameters.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
		//设置对焦模式
		parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);//连续对焦
		//设置闪光灯模式
		parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
		camera.setParameters(parameters);
		//开始预览
		camera.startPreview();
		camera.cancelAutoFocus();//如果要是实现自动连续对焦,就要把这句话加上
	}



	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		Log.i("zhangziran", "destroyed");
		camera.stopPreview();
		//释放Camera
		camera.release();
		camera = null;
		
	}
}
三、使用MediaCodec实现H264编码,并使用MediaMuxer合成视屏

package com.zzr.takeaudio;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PreviewCallback;
import android.hardware.Camera.Size;
import android.media.CamcorderProfile;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnInfoListener;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class MainActivity extends Activity implements SurfaceHolder.Callback,OnClickListener,PreviewCallback, OnInfoListener{
	private String tag = "zhangziran";
	private SurfaceView surfaceView;
	private SurfaceHolder surfaceHolder;
	private Camera camera;
	private MediaRecorder recorder;
	private File file;
	private Button btnStart,btnStop; 
	private boolean isRecorder =false;
	private byte[] btf =null;
	private Handler handler = new Handler();
	private boolean isChange = false;
	private int width = 1280;
	private int height = 720;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.activity_main);
		btnStart = (Button) findViewById(R.id.start_recorder);
		btnStop = (Button) findViewById(R.id.stop_recorder);
		btnStart.setOnClickListener(this);
		btnStop.setOnClickListener(this);
		surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
		surfaceHolder = surfaceView.getHolder();
		surfaceHolder.addCallback(this);
		String path = Environment.getExternalStorageDirectory().getAbsolutePath()+File.separator+"audio";
		file = new File(path);
		if(!file.exists()) {
			file.mkdir();
		}
	}
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		try {
			camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
			camera.setPreviewDisplay(holder);
			camera.setDisplayOrientation(90);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
		Log.i("zhangziran", "width*height="+width+"*"+height);
		Parameters params = camera.getParameters();
		//camera默认是横屏,也就是意味着界面高就是预览的宽,界面的高就是预览的宽,
		//对于我自己的手机分辨率是1920*1080(高*宽),而本手机也支持1920*1080的预览
		//所以将手机的宽高反向位置放进去
		//params.setPreviewSize(height, width);
		params.setPreviewSize(1280, 720);
		params.setPictureSize(1280, 720);
		params.setPreviewFormat(ImageFormat.YV12);
		//设置白平衡
		params.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
		//设置场景模式
		params.setSceneMode(Camera.Parameters.SCENE_MODE_AUTO);
		//设置对焦模式
		params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
		//设置闪光灯模式
		params.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
		camera.setParameters(params);
		createfile();
		camera.setPreviewCallback(this);
		prepareMediaCodec();
		camera.startPreview();
		camera.cancelAutoFocus();
	}
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		try {
			mediaMuxer.stop();
			mediaMuxer.release();
			mediaCodec.stop();
			mediaCodec.release();
			outputStream.flush();
			outputStream.close();
			camera.setPreviewCallback(null);
			camera.stopPreview();
			camera.unlock();
			camera.release();
			camera=null;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private boolean prepareViewRecorder() {
		//创建工具
		recorder = new MediaRecorder();
		//释放摄像机,为MediaRecorder设置摄像机
		camera.unlock();
		recorder.setCamera(camera);
		//设置声音和视频来源
		recorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
		recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		//设置视频输出格式和编码
		recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
		//设置比特率
		recorder.setVideoEncodingBitRate(5*1024*1024);
		//设置输出文件夹
		recorder.setOutputFile(getSaveFile().toString());
		//设置最大录制时间
		recorder.setMaxDuration(10*1000);
		//设置预览窗口
		recorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
		recorder.setOnInfoListener(this);
		//准备拍摄
		try {
			recorder.prepare();
		} catch (IllegalStateException e) {
			e.printStackTrace();
			return false;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	int i=0;
	private File getSaveFile() {
		String path = file.getAbsolutePath()+File.separator+System.currentTimeMillis()+".mp4";
		File file1= new File(path);
		if(!file1.exists()) {
			try {
				file1.createNewFile();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return file1;
	}
	@Override
	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.start_recorder:
			if(isRecorder) return;
			if(prepareViewRecorder()) {
				recorder.start();
				isRecorder = true;
			}
			break;
		case R.id.stop_recorder:
			if(isRecorder) {
				recorder.stop();
				recorder.release();
			}
			mediaMuxer.stop();
			mediaMuxer.release();
			mediaCodec.stop();
			mediaCodec.release();
			break;
		}
	}


	/**
	 * 初始化编码器
	 */
	private MediaCodec mediaCodec;
	private int frameRate =15;
	private MediaMuxer mediaMuxer;
	@SuppressLint("NewApi")
	private void prepareMediaCodec() {
		mediaCodec = MediaCodec.createEncoderByType("video/avc");
		MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
		//设置比特率/码流
		mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE,125000);
		//设置帧数
		mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE,frameRate);
		//颜色格式
		mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar);
		//关键帧时间间隔:单位秒
		mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,5);
		//设置声道数量
		mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT,1);
		mediaFormat.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER,1000000/frameRate);
		mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
		mediaCodec.start();
		try {
			mediaMuxer = new MediaMuxer(getSaveFile().toString(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	@Override
	public void onPreviewFrame(byte[] data, Camera camera) {
		onFrame(data);
	}
	//I420: YYYYYYYY UU VV    =>YUV420P 
	//YV12: YYYYYYYY VV UU    =>YUV420P
	//NV12: YYYYYYYY UVUV     =>YUV420SP
	//NV21: YYYYYYYY VUVU     =>YUV420SP
	public void swapYV12toI420(byte[] yv12bytes, byte[] i420bytes, int width,
			int height) {
		System.arraycopy(yv12bytes, 0, i420bytes, 0, width * height);
		System.arraycopy(yv12bytes, width * height + width * height / 4,
				i420bytes, width * height, width * height / 4);
		System.arraycopy(yv12bytes, width * height, 
				i420bytes, width * height+ width * height / 4, width * height / 4);
	}
	private int index=-1;
	public byte[] configbyte; 
	@SuppressLint("NewApi")
	private void onFrame(byte[] data1) {
		// 以720×488大小图象YUV420 planar为例,其存储格式是: 共大小为(720×480×3>>1)
		//YUV420是4:2:0,Y=720*480*8bit,U=V=720*480*8bit/4,
		byte[] data = new byte[width*height*3/2];
		swapYV12toI420(data1, data, width, height);
		Log.i(tag, "data1="+data1.length);
		Log.i(tag, " data="+data.length);
		//取出输出流和输入流数组
		ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
		ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
		int inputBufferIndex = mediaCodec.dequeueInputBuffer(0);
		long audioAbsolutePtsUs = System.nanoTime() / 1000;
		if(inputBufferIndex >=0){
			ByteBuffer inputByteBuffer = inputBuffers[inputBufferIndex];
			inputByteBuffer.clear();
			inputByteBuffer.put(data);
			mediaCodec.queueInputBuffer(inputBufferIndex, 0, data.length, audioAbsolutePtsUs, 0);
		}
		MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
		while(true){
			int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
			//outputBufferIndex经常性值为-1,因为数据是断断续续过来的,并不是一直有
			//在else中一定要释放output缓存空间,否则缓存空间满了outputBufferIndex也会返回-1
			if(outputBufferIndex==MediaCodec.INFO_TRY_AGAIN_LATER){
				break;
			}else if(outputBufferIndex==MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED){
				outputBuffers = mediaCodec.getOutputBuffers();
			}else if(outputBufferIndex==MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){
				MediaFormat format = mediaCodec.getOutputFormat();
				index=mediaMuxer.addTrack(format);
				mediaMuxer.start();
			}else if (outputBufferIndex<0){
				break;
			}else {
				/*try {
					ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
					byte[] outData = new byte[bufferInfo.size];
					outputBuffer.get(outData);
					if(bufferInfo.flags == 2){
						configbyte = new byte[bufferInfo.size];
						configbyte = outData;
					}else if(bufferInfo.flags == 1){
						byte[] keyframe = new byte[bufferInfo.size + configbyte.length];
						System.arraycopy(configbyte, 0, keyframe, 0, configbyte.length);
						System.arraycopy(outData, 0, keyframe, configbyte.length, outData.length);
						outputStream.write(keyframe, 0, keyframe.length);
					}else{
						outputStream.write(outData, 0, outData.length);
					}
				} catch (Exception e) {
				}*/

				ByteBuffer outpurByteBuffer = outputBuffers[outputBufferIndex];
				if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
					bufferInfo.size = 0;
				}
				if(bufferInfo.size!=0){
					outpurByteBuffer.position(bufferInfo.offset);
					outpurByteBuffer.limit(bufferInfo.offset+bufferInfo.size);
					mediaMuxer.writeSampleData(index, outpurByteBuffer, bufferInfo);
				}
				mediaCodec.releaseOutputBuffer(outputBufferIndex,false);
			}
		}
	}


	private static String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/test1.h264";
	private BufferedOutputStream outputStream;
	FileOutputStream outStream;
	private void createfile(){
		File file = new File(path);
		if(file.exists()){
			file.delete();
		}
		try {
			outputStream = new BufferedOutputStream(new FileOutputStream(file));
		} catch (Exception e){ 
			e.printStackTrace();
		}
	}
	@Override
	public void onInfo(MediaRecorder mr, int what, int extra) {

	}

	@Override
	protected void onDestroy() {
		mediaCodec.stop();
		mediaCodec.release();
		mediaMuxer.stop();
		mediaMuxer.release();
		if(camera!=null) {
			camera.stopPreview();
			camera.setPreviewCallback(null);
			camera.unlock();
			camera.release();
			camera=null;
		}
		super.onDestroy();
	}
}

另:添加水印

private int index=-1;
public byte[] configbyte;
@SuppressLint("NewApi")
private void onFrame(byte[] data1) {
      //对数据做处理:yv12(YUV420P)转RGB
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      YuvImage yuvImage = new YuvImage(data1, ImageFormat.NV21, 1920, 1080, null);
      yuvImage.compressToJpeg(new Rect(0, 0, 1920, 1080), 100, out);
      byte[] imageByte = out.toByteArray();
      //把每一帧数据转换成Bitmap
      Bitmap image = BitmapFactory.decodeByteArray(imageByte, 0, imageByte.length).copy(Bitmap.Config.ARGB_8888, true);
      //渲染图片
      Canvas canvas = new Canvas(image);
      Bitmap shuiyin = BitmapFactory.decodeResource(getResources(), R.drawable.shuiying);
      Paint paint = new Paint();
      canvas.drawBitmap(shuiyin,0,0,paint);
      //再将bitmap转nv21
      byte[] data2 = getNV21(1920, 1080, image);
      // 以720×488大小图象YUV420 planar为例,其存储格式是: 共大小为(720×480×3>>1)
      //YUV420是4:2:0,Y=720*480*8bit,U=V=720*480*8bit/4,
      byte[] data = new byte[width*height*3/2];
      nv21ToI420(data2, data, width, height);
      //swapYV12toI420(data1, data, width, height);
      Log.i(tag, "data1="+data1.length);
      Log.i(tag, " data="+data.length);
      //取出输出流和输入流数组
      ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
      ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
      int inputBufferIndex = mediaCodec.dequeueInputBuffer(0);

接三

相关资料:

注:I420: YYYYYYYY UU VV    =>YUV420P
YV12: YYYYYYYY VV UU    =>YUV420P
NV12: YYYYYYYY UVUV     =>YUV420SP
NV21: YYYYYYYY VUVU     =>YUV420SP

Android常用的几种格式:NV21/NV12/YV12/YUV420P的区别:http://www.cnblogs.com/raomengyang/p/4924787.html

图文详解YUV420数据格式:http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.htm






猜你喜欢

转载自blog.csdn.net/zzr1114969538/article/details/77895504
今日推荐