同事找我做一个视频预览复制,实现屏幕一分为二,同时显示相同画面。这里写个demo版
本篇的重点是
camera.setPreviewCallback()
其中要注意的是返回的数组图像格式为YUV,并不支持直接BitmapFactory.decodeByteArray()方法,需要通过格式转换。但这也导致运行计算所化时间较长,第二个界面卡顿。目前没有很好的解决方案,想到的两种解决方式,通过开启线程池,处理数据;或者通过native提高运算效率。
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//处理data
previewSize = camera.getParameters().getPreviewSize();//获取尺寸,格式转换的时候要用到
YuvImage yuvimage = new YuvImage(
data,
ImageFormat.NV21,
previewSize.width,
previewSize.height,
null);
baos = new ByteArrayOutputStream();
yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);// 80--JPG图片的质量[0-100],100最高
rawImage = baos.toByteArray();
//将rawImage转换成bitmap
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.RGB_565;
bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);
// idx++;
// text.setText(idx+"");
// bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
icon.setImageBitmap(bitmap);
}
});
首先是对ui初始化,然后关联camera和surfaceview即可
package com.example.administrator.carmavideoapplication;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
SurfaceViewJereh surfaceView;
ImageView icon;
private Button button, button2;
private TextView text;
private MediaRecorder mediaRecorder;
private String path;
private Camera camera;
private SurfaceHolder.Callback callback;
private int idx;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
initSurfaceView();
}
private void initSurfaceView() {
surfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setKeepScreenOn(true);
callback = new SurfaceHolder.Callback() {
//在控件创建的时候,进行相应的初始化工作
public void surfaceCreated(SurfaceHolder holder) {
//打开相机,同时进行各种控件的初始化mediaRecord等
camera = Camera.open();
mediaRecorder = new MediaRecorder();
}
//当控件发生变化的时候调用,进行surfaceView和camera进行绑定,可以进行画面的显示
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
doChange(holder);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
camera.setPreviewCallback(null);
camera.stopPreview();
}
};
//为SurfaceView设置回调函数
surfaceView.getHolder().addCallback(callback);
}
ByteArrayOutputStream baos;
byte[] rawImage;
Bitmap bitmap;
Camera.Size previewSize;
BitmapFactory.Options newOpts = new BitmapFactory.Options();
//当我们的程序开始运行,即使我们没有开始录制视频,我们的surFaceView中也要显示当前摄像头显示的内容
private void doChange(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(holder);
//设置surfaceView旋转的角度,系统默认的录制是横向的画面,把这句话注释掉运行你就会发现这行代码的作用
// camera.setDisplayOrientation(getDegree());
if (camera != null )
{
try
{
Camera.Parameters parameters = camera.getParameters(); //获取摄像头参数
// parameters.setZoom(); //镜头缩放
// 设置预览照片的大小
// parameters.setPreviewSize(200, 200);
// 设置预览照片时每秒显示多少帧的最小值和最大值
// parameters.setPreviewFpsRange(4, 10);
// 设置图片格式
// parameters.setPictureFormat(ImageFormat.JPEG);
// 设置JPG照片的质量
// parameters.set("jpeg-quality", 85);
// 设置照片的大小
// parameters.setPictureSize(200, 200);
camera.setParameters(parameters);
}
catch (Exception e) {
e.printStackTrace();
}
}
newOpts.inJustDecodeBounds = true;
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] data, Camera camera) {
//处理data
// previewSize = camera.getParameters().getPreviewSize();//获取尺寸,格式转换的时候要用到
// YuvImage yuvimage = new YuvImage(
// data,
// ImageFormat.NV21,
// previewSize.width,
// previewSize.height,
// null);
// baos = new ByteArrayOutputStream();
// yuvimage.compressToJpeg(new Rect(0, 0, previewSize.width, previewSize.height), 100, baos);// 80--JPG图片的质量[0-100],100最高
// rawImage = baos.toByteArray();
// //将rawImage转换成bitmap
// BitmapFactory.Options options = new BitmapFactory.Options();
// options.inPreferredConfig = Bitmap.Config.RGB_565;
// bitmap = BitmapFactory.decodeByteArray(rawImage, 0, rawImage.length, options);
//// idx++;
//// text.setText(idx+"");
//// bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
// icon.setImageBitmap(bitmap);
}
});
camera.startPreview();//开始预览
} catch (IOException e) {
e.printStackTrace();
}
}
public int getDegree() {
//获取当前屏幕旋转的角度
int rotating = this.getWindowManager().getDefaultDisplay().getRotation();
int degree = 0;
//根据手机旋转的角度,来设置surfaceView的显示的角度
switch (rotating) {
case Surface.ROTATION_0:
degree = 90;
break;
case Surface.ROTATION_90:
degree = 0;
break;
case Surface.ROTATION_180:
degree = 270;
break;
case Surface.ROTATION_270:
degree = 180;
break;
}
return degree;
}
private void init() {
button = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);
surfaceView = (SurfaceViewJereh)findViewById(R.id.surfaceview);
icon = (ImageView)findViewById(R.id.icon);
text = (TextView) findViewById(R.id.text);
button.setOnClickListener(this);
button2.setOnClickListener(this);
path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/hello.3gp";
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.button1:
startRecord();
break;
case R.id.button2:
stopRecord();
break;
}
}
private void stopRecord() {
//当结束录制之后,就将当前的资源都释放
mediaRecorder.release();
camera.release();
mediaRecorder = null;
//然后再重新初始化所有的必须的控件和对象
camera = Camera.open();
mediaRecorder = new MediaRecorder();
doChange(surfaceView.getHolder());
}
private void startRecord() {
//先释放被占用的camera,在将其设置为mediaRecorder所用的camera
camera.unlock();
mediaRecorder.setCamera(camera);
mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
//设置音频的来源 麦克风
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置视频的来源
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//设置视频的输出格式 3gp
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//设置视频中的声音和视频的编码格式
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
//设置保存的路径
mediaRecorder.setOutputFile(path);
//开始录制
try {
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if(camera!=null)
camera.release();//释放相机资源
}
}