视频播放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
- 视频播放surfaceView camera,获取预览图像显示setPreviewCallback()
- SurfaceView获取Camera预览界面
- Android 从Camera获取视频数据用SurfaceView显示
- Camera 使用SurfaceView预览图像拉伸
- SurfaceView预览Camera图像,SurfaceView总是位于顶层的问题
- Camera获取的视频流怎么解析然后在SurfaceView上面播放
- Android Camera setPreviewCallback setOneShotPreviewCallback方法返回的预览数据处理问题
- Camera(android图像、视频获取)
- SurfaceView预览Camera+GLSurfaceView绘制
- Camera 预览之SurfaceView、TextureView、GLSurfaceView(一)
- Camera 预览之SurfaceView、TextureView、GLSurfaceView(二)
- Camera 预览之SurfaceView、TextureView、GLSurfaceView(三)
- Camera预览图像拉伸
- Android SurfaceView播放视频有声音无图像问题
- android 调用Camera,获取预览帧中的图像
- Android调用Camera,获取预览帧中的图像
- 同时获取Camera预览和录像视频流
- SurfaceView实现视频播放
- LeetCode | 7. Reverse Integer
- CentOS yum安装mysql
- java Exception异常处理
- 微信小程序开发怎么获取用户输入
- 动态开发基础
- 视频播放surfaceView camera,获取预览图像显示setPreviewCallback()
- spring官网文档
- 欢迎使用CSDN-markdown编辑器
- spark架构原理(一)
- gh0st源码分析与远控的编写(一)
- ARM MMU工作原理剖析
- Springboot + shiro 整合之Url拦截设置
- Spark单机模式下使用mysql和DataFrame API
- URL编码与两次encodeURI分析