视频播放surfaceView camera,获取预览图像显示setPreviewCallback()

来源:互联网 发布:c语言输出buffer内容 编辑:程序博客网 时间:2024/05/18 23:57

同事找我做一个视频预览复制,实现屏幕一分为二,同时显示相同画面。这里写个demo版


本篇的重点是

camera.setPreviewCallback()

在视频预览过程中,每一帧的图像数据均会通过这个callback返回,在这里面我们可以处理返回的字节数组,转换为bitmap,然后显示出来

其中要注意的是返回的数组图像格式为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);                }            });

界面布局

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="com.example.administrator.carmavideoapplication.MainActivity">    <Button        android:id="@+id/button1"        android:layout_width="match_parent"        android:visibility="gone"        android:layout_height="48dp"        android:text="button1"/>    <Button        android:id="@+id/button2"        android:visibility="gone"        android:layout_width="match_parent"        android:layout_height="48dp"        android:text="button2"/>    <TextView        android:id="@+id/text"        android:layout_width="match_parent"        android:layout_height="48dp" />    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical">        <com.example.administrator.carmavideoapplication.SurfaceViewJereh            android:id="@+id/surfaceview"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_weight="1">        </com.example.administrator.carmavideoapplication.SurfaceViewJereh>        <ImageView            android:id="@+id/icon"            android:layout_weight="1"            android:layout_width="match_parent"            android:layout_height="match_parent" />    </LinearLayout></LinearLayout>


activity初始化

首先是对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();//释放相机资源    }}

阅读全文
0 0
原创粉丝点击