Android切换前后置摄像头并录制视频

时间:2022-09-18 22:36:22

效果图:

Android切换前后置摄像头并录制视频

java代码:

 

package com.cayden.videorecord;

import java.io.IOException;
import java.util.List;

import com.cayden.videorecord.util.LogsUtil;
import com.cayden.videorecord.util.SupportedSizesReflect;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.CameraInfo;
import android.hardware.Camera.Size;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
/**
* TODO
*
* @author zhujiabin
* @version 1.0.0
*/
public class RecordActivity extends Activity implements Callback,
MediaPlayer.OnPreparedListener, OnBufferingUpdateListener,
OnCompletionListener {
private static final String TAG = "RecordActivity";

private String videoPath = "/sdcard/love.3gp";

private MediaRecorder mediarecorder;// 录制视频的类
private MediaPlayer mediaPlayer;// 播放视频的类
private SurfaceView surfaceview;// 显示视频的控件
private Camera camera;

private SurfaceHolder surfaceHolder;// 实现这个接口的Callback接口
private boolean isRecord = false; // 是否正在录制true录制中 false未录制
public boolean isCameraBack = true;

private ImageView recordIv;
private ImageView recordPlayIv;

private int cameraPosition = 1;// 0代表前置摄像头,1代表后置摄像头
private int mVideoWidth;
private int mVideoHeight;
int cameraCount = 0;

public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.video_record);
setTitleStr(
"");
getWindow().setFormat(PixelFormat.TRANSLUCENT);
// 选择支持半透明模式,在有surfaceview的activity中使用。
initView();
}

private void initView() {

surfaceview
= (SurfaceView) this.findViewById(R.id.surfaceview);
recordIv
= (ImageView) findViewById(R.id.recordIv);
recordPlayIv
= (ImageView) findViewById(R.id.recordPlayIv);

SurfaceHolder holder
= surfaceview.getHolder();// 取得holder
holder.addCallback(this);// holder加入回调接口
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置,要不出错.
recordIv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
recordVideo(v);
}
});

}

public void playVideo(View v) {
// 播放视频
recordPlayIv.setVisibility(View.GONE);
try {
mediaPlayer
= new MediaPlayer();
mediaPlayer.setDataSource(videoPath);
mediaPlayer.setDisplay(surfaceHolder);
mediaPlayer.prepareAsync();

}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

mediaPlayer.setOnBufferingUpdateListener(
this);
mediaPlayer.setOnCompletionListener(
this);
mediaPlayer.setOnPreparedListener(
this);
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);

}

public void recordVideo(View v) {
// 开始录制/停止录制
if (isRecord) {
isRecord
= false;
recordIv.setImageResource(R.drawable.video_recorder_start_btn_nor);
recordPlayIv.setVisibility(View.VISIBLE);
if (mediarecorder != null) {
// 停止录制
mediarecorder.stop();
// 释放资源
mediarecorder.release();
mediarecorder
= null;
}
if (camera != null) {
camera.release();
}
}
else {
isRecord
= true;
recordIv.setImageResource(R.drawable.video_recorder_recording_btn);
recordPlayIv.setVisibility(View.GONE);
if (camera != null) {
camera.release();
}

if (cameraPosition == 1) {
camera
= Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);//打开摄像头

camera
= deal(camera);
//视频旋转90度
mediarecorder.setOrientationHint(90);

}
else {
camera
= Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);//打开摄像头
Camera.Parameters parameters = camera.getParameters();
camera.setDisplayOrientation(
90);
camera.setParameters(parameters);
//视频旋转90度
mediarecorder.setOrientationHint(270);
}

camera.unlock();

mediarecorder.setCamera(camera);

// 设置录制视频源为Camera(相机)
mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 设置录制完成后视频的封装格式THREE_GPP为3gp.MPEG_4为mp4
mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// 设置录制的视频编码h263 h264
mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
// 设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错
mediarecorder.setVideoSize(176, 144);
// 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错
mediarecorder.setVideoFrameRate(20);

mediarecorder.setPreviewDisplay(surfaceHolder.getSurface());
// 设置视频文件输出的路径
mediarecorder.setOutputFile(videoPath);
try {
// 准备录制
mediarecorder.prepare();
mediarecorder.start();
}
catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {

e.printStackTrace();
}

}
}

protected void setTitleStr(String str) {
TextView titleText
= (TextView) findViewById(R.id.common_title_text);
titleText.setText(str.trim());

Button left_button
= (Button) findViewById(R.id.left_button);
left_button.setVisibility(View.GONE);

Button right_button
= (Button) findViewById(R.id.right_button);
right_button.setVisibility(View.VISIBLE);
right_button.setText(
"");
right_button.setBackgroundResource(R.drawable.btn_video_switch_bg);
right_button.setOnClickListener(
new View.OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
cameraCount = Camera.getNumberOfCameras();
if (isCameraBack) {
isCameraBack
= false;
}
else {
isCameraBack
= true;
}


int cameraCount = 0;
CameraInfo cameraInfo
= new CameraInfo();
cameraCount
= Camera.getNumberOfCameras();

for (int i = 0; i < cameraCount; i++) {

Camera.getCameraInfo(i, cameraInfo);
//得到每一个摄像头的信息
if (cameraPosition == 1) {
//现在是后置,变更为前置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置

camera.stopPreview();
//停掉原来摄像头的预览
camera.release();//释放资源
camera = null;//取消原来摄像头
camera = Camera.open(i);//打开当前选中的摄像头
try {
deal(camera);
camera.setPreviewDisplay(surfaceHolder);
//通过surfaceview显示取景画面
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();
//开始预览
cameraPosition = 0;
break;
}
}
else {
//现在是前置, 变更为后置
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {// 代表摄像头的方位,CAMERA_FACING_FRONT前置
// CAMERA_FACING_BACK后置

camera.stopPreview();
// 停掉原来摄像头的预览
camera.release();// 停掉原来摄像头的预览
camera = null;// 释放资源
camera = Camera.open(i);// 取消原来摄像头
try {
deal(camera);
camera.setPreviewDisplay(surfaceHolder);
// 通过surfaceview显示取景画面
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
camera.startPreview();
// 开始预览
cameraPosition = 1;
break;
}
}

}

}
});

}

public void back() {
// 返回
finish();

}

public Camera deal(Camera camera) {
// 设置camera预览的角度,因为默认图片是倾斜90度的
camera.setDisplayOrientation(90);

Size pictureSize
= null;
Size previewSize
= null;
Camera.Parameters parameters
= camera.getParameters();
parameters.setPreviewFrameRate(
5);
// 设置旋转代码
parameters.setRotation(90);
List
<Size> supportedPictureSizes = SupportedSizesReflect
.getSupportedPictureSizes(parameters);
List
<Size> supportedPreviewSizes = SupportedSizesReflect
.getSupportedPreviewSizes(parameters);

if (supportedPictureSizes != null && supportedPreviewSizes != null
&& supportedPictureSizes.size() > 0
&& supportedPreviewSizes.size() > 0) {
// 2.x
pictureSize = supportedPictureSizes.get(0);

int maxSize = 1280;
if (maxSize > 0) {
for (Size size : supportedPictureSizes) {
if (maxSize >= Math.max(size.width, size.height)) {
pictureSize
= size;
break;
}
}
}

WindowManager windowManager
= (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display
= windowManager.getDefaultDisplay();
DisplayMetrics displayMetrics
= new DisplayMetrics();
display.getMetrics(displayMetrics);

previewSize
= getOptimalPreviewSize(supportedPreviewSizes,
display.getWidth(), display.getHeight());

parameters.setPictureSize(pictureSize.width, pictureSize.height);
parameters.setPreviewSize(previewSize.width, previewSize.height);

}
camera.setParameters(parameters);
return camera;
}

@Override
public void surfaceChanged(SurfaceHolder holder, int arg1, int arg2,
int arg3) {
// 将holder,这个holder为开始在oncreat里面取得的holder,将它赋给surfaceHolder
surfaceHolder = holder;
}

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) {
final
double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null)
return null;

Size optimalSize
= null;
double minDiff = Double.MAX_VALUE;

int targetHeight = h;

// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize
= size;
minDiff
= Math.abs(size.height - targetHeight);
}
}

// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff
= Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize
= size;
minDiff
= Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
surfaceHolder = holder;

try {
if (isCameraBack) {
camera
= Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);// 鎵撳紑鎽勫儚澶�

}
else {
camera
= Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);// 鎵撳紑鎽勫儚澶�

}

// 设置camera预览的角度,因为默认图片是倾斜90度的
camera.setDisplayOrientation(90);

Size pictureSize
= null;
Size previewSize
= null;
Camera.Parameters parameters
= camera.getParameters();
parameters.setPreviewFrameRate(
5);
// 设置旋转代码
parameters.setRotation(90);

List
<Size> supportedPictureSizes = SupportedSizesReflect
.getSupportedPictureSizes(parameters);
List
<Size> supportedPreviewSizes = SupportedSizesReflect
.getSupportedPreviewSizes(parameters);

if (supportedPictureSizes != null && supportedPreviewSizes != null
&& supportedPictureSizes.size() > 0
&& supportedPreviewSizes.size() > 0) {

// 2.x
pictureSize = supportedPictureSizes.get(0);

int maxSize = 1280;
if (maxSize > 0) {
for (Size size : supportedPictureSizes) {
if (maxSize >= Math.max(size.width, size.height)) {
pictureSize
= size;
break;
}
}
}

WindowManager windowManager
= (WindowManager) getSystemService(Context.WINDOW_SERVICE);
Display display
= windowManager.getDefaultDisplay();
DisplayMetrics displayMetrics
= new DisplayMetrics();
display.getMetrics(displayMetrics);

previewSize
= getOptimalPreviewSize(supportedPreviewSizes,
display.getWidth(), display.getHeight());

parameters
.setPictureSize(pictureSize.width, pictureSize.height);
parameters
.setPreviewSize(previewSize.width, previewSize.height);

}
camera.setParameters(parameters);
camera.setPreviewDisplay(holder);
camera.startPreview();
}
catch (Exception e) {
e.printStackTrace();
}

}

@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
if (camera != null) {
camera.release();
}
surfaceview
= null;
surfaceHolder
= null;
if (surfaceHolder != null) {
surfaceHolder
= null;
}
if (mediarecorder != null) {
mediarecorder
= null;
}
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer
= null;
}

}

@Override
public void onCompletion(MediaPlayer arg0) {
// TODO Auto-generated method stub
LogsUtil.i(TAG, "onCompletion");
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer
= null;
}
recordPlayIv.setVisibility(View.VISIBLE);
}

@Override
public void onPrepared(MediaPlayer arg0) {
// TODO Auto-generated method stub
mVideoWidth = mediaPlayer.getVideoWidth();
mVideoHeight
= mediaPlayer.getVideoHeight();
if (mVideoWidth != 0 && mVideoHeight != 0) {
surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);
// 设置视频的宽度和高度
mediaPlayer.start();// 开始播放
}
}

@Override
public void onBufferingUpdate(MediaPlayer player, int arg1) {
// TODO Auto-generated method stub

}

}

 

 

 

布局文件代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:orientation="vertical"
android:layout_width
="fill_parent" android:background="@drawable/login_bj"
android:layout_height
="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android">

<include android:id="@+id/Title"
android:layout_alignParentTop
="true"
android:layout_width
="fill_parent"
android:layout_height
="wrap_content"
layout
="@layout/layout_common_title"/>


<LinearLayout
android:layout_below
="@+id/Title"
android:layout_above
="@+id/recordBtn"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent"
android:padding
="30dp"
>
<SurfaceView
android:id
="@+id/surfaceview"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent" />


</LinearLayout>

<RelativeLayout
android:id
="@+id/videoPlay"
android:layout_width
="fill_parent"
android:layout_height
="fill_parent"
android:gravity
="center"
>
<ImageView
android:src
="@drawable/btn_video_play_bg"
android:id
="@+id/recordPlayIv"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:clickable
="true"
android:onClick
="playVideo"
android:visibility
="gone"
/>
</RelativeLayout>

<RelativeLayout
android:id
="@+id/recordBtn"
android:layout_width
="fill_parent"
android:layout_height
="wrap_content"
android:gravity
="center"
android:layout_alignParentBottom
="true">
<ImageView
android:src
="@drawable/video_recorder_start_btn_nor"
android:id
="@+id/recordIv"
android:layout_width
="wrap_content"
android:layout_height
="wrap_content"
android:clickable
="true"
android:onClick
="recordVideo"
/>
</RelativeLayout>


</RelativeLayout>

这里还有一些地方需要完善,在录制完成后切换会出现问题。由于时间关系这边还没去处理,在后续会进行处理,

此代码采用的sdk是17,由于在android 2.2上录制视频是横着,所以采用了高点的sdk

代码:这里