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后无法获取实际尺寸的照片,解决方法如下:
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();
}
}
另:添加水印
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