视频播放surfaceView camera,获取预览图像显示setPreviewCallback()
2017-06-15 11:04
489 查看
同事找我做一个视频预览复制,实现屏幕一分为二,同时显示相同画面。这里写个demo版
本篇的重点是
在视频预览过程中,每一帧的图像数据均会通过这个callback返回,在这里面我们可以处理返回的字节数组,转换为bitmap,然后显示出来
其中要注意的是返回的数组图像格式为YUV,并不支持直接BitmapFactory.decodeByteArray()方法,需要通过格式转换。但这也导致运行计算所化时间较长,第二个界面卡顿。目前没有很好的解决方案,想到的两种解决方式,通过开启线程池,处理数据;或者通过native提高运算效率。
本篇的重点是
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();//释放相机资源 } }
相关文章推荐
- Android 从Camera获取视频数据用SurfaceView显示
- Camera获取的视频流怎么解析然后在SurfaceView上面播放
- SurfaceView预览Camera图像,SurfaceView总是位于顶层的问题
- 调整surfaceView播放视频时的显示比例
- MediaPlayer 播放视频文件并通过SurfaceView显示
- Android Camera setPreviewCallback setOneShotPreviewCallback方法返回的预览数据处理问题
- Camera 使用SurfaceView预览图像拉伸
- 使用SurfaceView播放视频,调节进度,滑动屏幕调节音量并显示音量。
- 09-15 Camera (摄像机),SoundPool(播放提示音等小音频),VideoView(播放视频),SurfaceView(播放视频),MediaRecorder(录制音频)
- 使用SurfaceView播放视频,调节进度,滑动屏幕调节音量并显示音量。
- Android SurfaceView播放视频有声音无图像问题
- SurfaceView获取Camera预览界面
- Android Camera设置setPreviewCallback实现onPreviewFrame接口实时截取每一帧视频流数据
- 使用SurfaceView 播放视频
- 从头学Android之多媒体--使用MediaPlayer和SurfaceView播放视频
- Android之SurfaceView实现视频播放
- SurfaceView显示Camera摄像(之二设置参数、变焦)
- Android之SurfaceView实现视频播放
- OpenCV学习笔记(9)利用MFC的Picture控件显示图像+播放视频和捕获摄像头画面
- 调用 Camera.setPreviewCallback 失效