系统录制
Intent intent=new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
intent.putExtra(MediaStore.EXTRA_VIDEO_QUALITY,0);
intent.putExtra(MediaStore.EXTRA_SIZE_LIMIT,10485760L);
intent.putExtra(MediaStore.EXTRA_DURATION_LIMIT,10);
startActivityForResult(intent,VIDEO_CAPTURE);
本篇介绍MediaRecorder 和 SurfaceView 录制方法
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.lifecycle.Observer;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Point;
import android.hardware.Camera;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;
private ImageView recorderBtn;
private ImageView recorder_btn_car;
private ImageView recorder_btn_s;
private ImageView iv_confirm;
private ImageView iv_relase;
private VideoFullScreen video_view;
private RelativeLayout rl_bottom;
private TextView tv_time;
private MediaRecorder recorder;
private boolean isStart = false;
private boolean recorded = false;
private Camera camera;
private SurfaceHolder holder;
private String path;
private Camera.Size size;
private int facingBack = Camera.CameraInfo.CAMERA_FACING_BACK;
private boolean isBack = true;
private boolean isSource = true;
private String mCurrentPath;
private int mWidth = 1280;
private int mHeight = 720;
private static final int REQUEST_PERMISSION = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
Display display = getWindowManager().getDefaultDisplay();
mWidth = display.getHeight();
mHeight= display.getWidth();
recorderBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!isStart) {
startTimer(16);
recorderBtn.setSelected(true);
recorder_btn_car.setVisibility(View.GONE);
recorder_btn_s.setVisibility(View.GONE);
startRecorder();
isStart = true;
} else {
recorderBtn.setSelected(false);
recorder_btn_car.setVisibility(View.VISIBLE);
recorder_btn_s.setVisibility(View.GONE);
if (mDisposable !=null) {
mDisposable.cancel();
mDisposable = null;
}
stopRecorder();
startVideo();
isStart = false;
}
}
});
recorder_btn_car.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
isBack = !isBack;
if (isBack) {
facingBack = Camera.CameraInfo.CAMERA_FACING_BACK;
}else {
facingBack = Camera.CameraInfo.CAMERA_FACING_FRONT;
}
releaseCamera();
initPreview();
}
});
recorder_btn_s.setSelected(true);
recorder_btn_s.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
isSource = !isSource;
if (isSource) {
recorder_btn_s.setSelected(true);
}else {
recorder_btn_s.setSelected(false);
}
}
});
iv_relase.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
video_view.stopPlayback();
video_view.setVisibility(View.GONE);
recorder_btn_car.setVisibility(View.VISIBLE);
recorder_btn_s.setVisibility(View.GONE);
recorderBtn.setSelected(false);
isStart = false;
recorderBtn.setVisibility(View.VISIBLE);
rl_bottom.setVisibility(View.GONE);
updataTimeFormat(tv_time,0);
initPreview();
}
});
iv_confirm.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent();
intent.putExtra("data",mCurrentPath);
setResult(-1,intent);
finish();
}
});
}
private void init() {
surfaceView = findViewById(R.id.surface_view);
recorderBtn = findViewById(R.id.recorder_btn_container);
recorder_btn_car = findViewById(R.id.recorder_btn_car);
recorder_btn_s = findViewById(R.id.recorder_btn_s);
iv_confirm = findViewById(R.id.iv_confirm);
iv_relase = findViewById(R.id.iv_relase);
tv_time = findViewById(R.id.tv_time);
rl_bottom = findViewById(R.id.rl_bottom);
video_view = findViewById(R.id.video_view);
holder = surfaceView.getHolder();
holder.setFixedSize(640,480);
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void permissionRead(){
boolean permission = isPermission(Manifest.permission.CAMERA);
boolean permissionRead = isPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
boolean permissionWrite = isPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
boolean permissionAudio = isPermission(Manifest.permission.RECORD_AUDIO);
if (!permissionRead){
initPermission(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE});
}else if(!permissionWrite) {
initPermission(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE});
}else if(!permission) {
initPermission(new String[]{Manifest.permission.CAMERA});
}else if (!permissionAudio){
initPermission(new String[]{Manifest.permission.RECORD_AUDIO});
}else {
initPreview();
}
}
public void initPermission(String[] permissionArr) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
boolean isGranted = true;
for (String permission : permissionArr) {
int result = ActivityCompat.checkSelfPermission(this, permission);
if (result != PackageManager.PERMISSION_GRANTED) {
isGranted = false;
break;
}
}
if (!isGranted) {
ActivityCompat.requestPermissions(this, permissionArr, REQUEST_PERMISSION);
}
}
}
public boolean isPermission(String permission) {
boolean isGranted = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
int result = ActivityCompat.checkSelfPermission(this, permission);
if (result != PackageManager.PERMISSION_GRANTED) {
isGranted = false;
}
}
return isGranted;
}
private void openCamera(int in) {
Log.e("VideoRecorderActivity", "openCamera()");
camera = Camera.open(in);
if (camera != null) {
setCameraParameters();
camera.unlock();
}
}
private void setCameraParameters() {
if (camera == null) {
return;
}
Camera.Parameters parameters = camera.getParameters();
camera.setDisplayOrientation(90);
List<String> focusModesList = parameters.getSupportedFocusModes();
if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
} else if (focusModesList.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
parameters.setRecordingHint(true);
camera.setParameters(parameters);
if (size == null) {
List<Camera.Size> mSupportedPreviewSizes = parameters.getSupportedPreviewSizes();
Collections.sort(mSupportedPreviewSizes, new Comparator<Camera.Size>() {
@Override
public int compare(Camera.Size o1, Camera.Size o2) {
if (o1.width == o2.width) {
return 0;
} else if (o1.width > o2.width) {
return 1;
} else {
return -1;
}
}
});
for (int num = 0; num < mSupportedPreviewSizes.size(); num++) {
Camera.Size size1 = mSupportedPreviewSizes.get(num);
if (size1.width >= 1000 && size1.height >= 800) {
size = size1;
break;
}
}
}
if (facingBack == Camera.CameraInfo.CAMERA_FACING_FRONT) {
Point point = CameraPreviewUtils.getBestPreview(parameters, new Point(mWidth, mHeight));
parameters.setPreviewSize(point.x, point.y);
camera.setParameters(parameters);
}else {
parameters.setPreviewSize(640, 480);
}
}
private void releaseCamera() {
Log.e("VideoRecorderActivity", "releaseCamera()");
if (camera != null) {
camera.setPreviewCallback(null);
camera.stopPreview();
camera.lock();
camera.release();
camera = null;
}
}
private void startRecorder() {
Log.e("VideoRecorderActivity", "initRecorder()");
if (recorder == null) {
recorder = new MediaRecorder();
}
recorderBtn.setVisibility(View.VISIBLE);
openCamera(facingBack);
recorder.setCamera(camera);
recorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
@Override
public void onError(MediaRecorder mr, int what, int extra) {
Log.e("VideoRecorderActivity","onError what = " +what +",extra = "+ extra );
stopRecorder();
}
});
recorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
@Override
public void onInfo(MediaRecorder mediaRecorder, int i, int i1) {
}
});
if (isSource) {
recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
}
recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
if (isSource) {
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
}
recorder.setVideoEncodingBitRate(2* 1024 * 1024);
recorder.setVideoFrameRate(30);
if (facingBack == Camera.CameraInfo.CAMERA_FACING_BACK) {
recorder.setOrientationHint(displayOrientation(this));
}else {
recorder.setOrientationHint(360 - displayOrientation(this));
}
recorder.setMaxDuration(15*1000);
Log.d("生成的分辨率:","width="+size.width+" height="+size.height);
Display display = getWindowManager().getDefaultDisplay();
int Height = display.getHeight();
int Width = display.getWidth();
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {
recorder.setVideoSize(1920, 1080);
}else {
recorder.setVideoSize( Height,Width);
}
recorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
try {
mCurrentPath = createRecordPath();
recorder.setOutputFile(mCurrentPath);
recorder.prepare();
recorder.start();
} catch (Exception e) {
e.printStackTrace();
Log.e("VideoRecorderActivity", "recorder.prepare()异常" );
stopRecorder();
}
}
private int displayOrientation(Context context) {
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
int rotation = windowManager.getDefaultDisplay().getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
default:
degrees = 0;
break;
}
int result = (0 - degrees + 360) % 360;
if (APIUtils.hasGingerbread()) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(facingBack, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360;
} else {
result = (info.orientation - degrees + 360) % 360;
}
}
return result;
}
private void stopRecorder() {
if (recorder != null) {
recorder.stop();
recorder.reset();
recorder.release();
recorder = null;
recorded = true;
recorderBtn.setVisibility(View.GONE);
rl_bottom.setVisibility(View.VISIBLE);
}
releaseCamera();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e("VideoRecorderActivity", "surfaceCreated");
permissionRead();
}
private void initPreview(){
if (camera == null) {
camera = Camera.open(facingBack);
}
try {
setCameraParameters();
camera.setPreviewDisplay(holder);
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(this, "打开相机失败", Toast.LENGTH_SHORT).show();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.e("VideoRecorderActivity", "surfaceChanged width =" + width);
Log.e("VideoRecorderActivity", "surfaceChanged height = " + height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e("VideoRecorderActivity", "surfaceDestroyed");
releaseCamera();
}
private String createRecordPath() throws IOException {
File sdDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
if (sdDir != null) {
File dir = new File(sdDir.getAbsolutePath());
if (!dir.exists()) {
dir.mkdirs();
}
String path = dir.getAbsolutePath() + "/" + System.currentTimeMillis() + ".mp4";
return path;
}
return null;
}
private Timer mDisposable = null;
private int number = 0;
private Handler handler = null;
public void startTimer(int second){
if (mDisposable !=null) {
return;
}
if (handler == null) {
handler = new Handler(getMainLooper());
}
mDisposable = new Timer();
mDisposable.schedule(new TimerTask() {
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
number ++;
if (number >= second) {
updataTimeFormat(tv_time,Math.round(number * 1000));
stopRecorder();
startVideo();
}else {
updataTimeFormat(tv_time,Math.round(number * 1000));
}
}
});
}
},1000,1000);
}
private void startVideo(){
if (video_view.isPlaying())
return;
video_view.setVisibility(View.VISIBLE);
video_view.setVideoPath(mCurrentPath);
video_view.start();
video_view.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
video_view.setVideoPath(mCurrentPath);
video_view.start();
}
});
}
private void updataTimeFormat(TextView textView, int millisecond) {
int second = millisecond / 1000;
int hh = second / 3600;
int mm = second % 3600 / 60;
int ss = second % 60;
String str = null;
if (hh != 0) {
str = String.format("%02d:%02d:%02d", hh, mm, ss);
} else {
str = String.format("%02d:%02d", mm, ss);
}
textView.setText(str);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionRead();
}
}
xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"></SurfaceView>
</FrameLayout>
<TextView
android:id="@+id/tv_time"
android:text="0:00"
android:padding="@dimen/dp_10"
android:textSize="18dp"
android:layout_marginTop="@dimen/dp_10"
android:textColor="@color/white"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></TextView>
<ImageView
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="30dp"
android:background="@drawable/collect_play_selector"
android:src="@drawable/collect_play_selector"
android:id="@+id/recorder_btn_container"
android:layout_width="80dp"
android:layout_height="80dp"></ImageView>
<ImageView
android:text="声音"
android:visibility="gone"
android:layout_marginTop="@dimen/dp_10"
android:src="@drawable/collect_image_voice_selector"
android:layout_toLeftOf="@+id/recorder_btn_car"
android:id="@+id/recorder_btn_s"
android:layout_marginRight="10dp"
android:padding="@dimen/dp_10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> </ImageView>
<ImageView
android:text="切换"
android:padding="@dimen/dp_10"
android:src="@drawable/collect_image_ca_selector"
android:layout_alignParentRight="true"
android:layout_marginTop="@dimen/dp_10"
android:id="@+id/recorder_btn_car"
android:layout_marginRight="10dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"> </ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
<com.hdketang.camera.VideoFullScreen
android:id="@+id/video_view"
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.hdketang.camera.VideoFullScreen>
<RelativeLayout
android:id="@+id/rl_bottom"
android:visibility="gone"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_marginBottom="30dp"
android:paddingLeft="@dimen/dp_20"
android:paddingRight="@dimen/dp_20"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/iv_relase"
android:layout_alignParentBottom="true"
android:src="@mipmap/ic_relese"
android:layout_width="40dp"
android:layout_height="wrap_content">
</ImageView>
<ImageView
android:id="@+id/iv_confirm"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:src="@mipmap/ic_config"
android:layout_width="40dp"
android:layout_height="wrap_content">
</ImageView>
</RelativeLayout>
</RelativeLayout>
源码路径 https://gitee.com/zqmyself/CameraDemo
|