Android 录制音视频

打开camera

private void openCamera(int position) {if (mCamera == null) {mCamera = Camera.open(position);int degree = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 0 : 90;mCamera.setDisplayOrientation(degree);}}

camera默认是横屏的,所以我们要使用竖屏录制要旋转90度

int degree = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 0 : 90;mCamera.setDisplayOrientation(degree);

camera预览

我们要选择一个与我们要显示的SurfaceView大小比例最接近的一个camera预览大小,这里要特别注意camera支持的宽高都是宽大于高。

所以就有了下面这段选择代码

private Size getBestCameraResolution(Camera.Parameters parameters, Size screenResolution) {float tmp = 0f;float mindiff = 100f;Log.e("yuanVideo", "screen width=" + screenResolution.getWidth() + " height=" + screenResolution.getHeight());float width_d_height;if (screenResolution.getWidth() > screenResolution.getHeight()) {width_d_height = (float) screenResolution.getWidth() / (float) screenResolution.getHeight();} else {width_d_height = (float) screenResolution.getHeight() / (float) screenResolution.getWidth();}Log.e("yuanVideo", "width_d_height=" + width_d_height);Camera.Size best = null;List supportedPreviewSizes = parameters.getSupportedPreviewSizes();for (Camera.Size s : supportedPreviewSizes) {tmp = Math.abs(((float) s.width / (float) s.height) - width_d_height);Log.e("yuanVideo", "support width=" + s.width + " height=" + s.height + " ratio=" + tmp);if (tmp < mindiff) {mindiff = tmp;best = s;}}Log.e("yuanVideo", "best width=" + best.width + " height=" + best.height);return new Size(best.width, best.height);}

初始化MediaRecorder

private boolean prepareMediaRecorder() {// 创建MediaPlayer对象mCamera.unlock();mRecorder = new MediaRecorder();mRecorder.reset();mRecorder.setCamera(mCamera);// 设置从麦克风采集声音(或来自录像机的声音AudioSource.CAMCORDER)mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置从摄像头采集图像mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);Log.e("yuanProfile", "QUALITY_LOW=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_LOW));Log.e("yuanProfile", "QUALITY_HIGH=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH));Log.e("yuanProfile", "QUALITY_QCIF=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QCIF));Log.e("yuanProfile", "QUALITY_480P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P));Log.e("yuanProfile", "QUALITY_720P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P));Log.e("yuanProfile", "QUALITY_1080P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P));Log.e("yuanProfile", "QUALITY_QVGA=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA));Log.e("yuanProfile", "QUALITY_2160P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P));Log.e("yuanProfile", "QUALITY_VGA=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_VGA));Log.e("yuanProfile", "QUALITY_4KDCI=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_4KDCI));Log.e("yuanProfile", "QUALITY_QHD=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QHD));Log.e("yuanProfile", "QUALITY_2K=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2K));if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_1080P));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_LOW)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));} else {return false;}// mTempList.add(mCurrentTempRecordData);mRecorder.setOutputFile(mCurPath);mRecorder.setPreviewDisplay(activtityVideoRecordBinding.sView.getHolder().getSurface()); // ①int degree;if(getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){int degree ;if (cameraPosition == Camera.CameraInfo.CAMERA_FACING_FRONT) {degree = 270;} else {degree = 90;}mRecorder.setOrientationHint(degree);}try {mRecorder.prepare();} catch (Exception e) {e.printStackTrace();return false;}return true;}

这里也要设置视频的旋转参数

if(getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){int degree ;if (cameraPosition == Camera.CameraInfo.CAMERA_FACING_FRONT) {degree = 270;} else {degree = 90;}mRecorder.setOrientationHint(degree);}

 

下面是完整的代码

package com.yuanxuzhen.ffmpeg;import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Size;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;import com.yuanxuzhen.ffmpeg.databinding.ActivtityVideoRecordBinding;import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class VideoRecordActivity extends Activity {ActivtityVideoRecordBinding activtityVideoRecordBinding;MediaRecorder mRecorder;private boolean isRecording = false;private int cameraPosition = Camera.CameraInfo.CAMERA_FACING_FRONT;//0代表前置摄像头,1代表后置摄像头private Camera mCamera;private Camera.Parameters mParameters;private String mCurPath = null;private VideoTempRecordData mCurrentTempRecordData = null;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);getWindow().setFormat(PixelFormat.TRANSLUCENT);mCurPath = DirUtil.getCacheDir(this) + File.separator + "out.mp4";activtityVideoRecordBinding = ActivtityVideoRecordBinding.inflate(getLayoutInflater());setContentView(activtityVideoRecordBinding.getRoot());activtityVideoRecordBinding.sView.getHolder().setKeepScreenOn(true);activtityVideoRecordBinding.sView.getHolder().addCallback(new SurfaceHolder.Callback() {@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {openPreView();}@Overridepublic void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {Log.e("yuanVideo", "surfaceChanged width=" + width + " height=" + height);}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {}});activtityVideoRecordBinding.recordOrStop.setText("开始");activtityVideoRecordBinding.recordOrStop.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (isRecording) {Log.d("TAG", "停止录像");stopRecord();} else {startRecord();}}});activtityVideoRecordBinding.change.setOnClickListener(new View.OnClickListener() {@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)@Overridepublic void onClick(View v) {if(isRecording){return;}releaseCamera();cameraPosition = cameraPosition == Camera.CameraInfo.CAMERA_FACING_FRONT ? Camera.CameraInfo.CAMERA_FACING_BACK : Camera.CameraInfo.CAMERA_FACING_FRONT;openCamera(cameraPosition);openPreView();}});}/*** 1.打开相机*/private void openCamera(int position) {if (mCamera == null) {mCamera = Camera.open(position);int degree = getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE ? 0 : 90;mCamera.setDisplayOrientation(degree);}}/*** initCameraAndSurfaceViewHolder初始化hoder后* 2.设置预览功能*/@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)private void openPreView() {try {if (mCamera != null) {mParameters = mCamera.getParameters();mCamera.setPreviewDisplay(activtityVideoRecordBinding.sView.getHolder());Size screenPoint = getScreenMetrics(VideoRecordActivity.this);Size bestPreviewSize = getBestCameraResolution(mCamera.getParameters(), screenPoint);mParameters.setPreviewSize(bestPreviewSize.getWidth(), bestPreviewSize.getHeight());mCamera.setParameters(mParameters);mCamera.startPreview();mCamera.autoFocus(new Camera.AutoFocusCallback() {@Overridepublic void onAutoFocus(boolean success, Camera camera) {Log.e("yuanVideo", "autoFocus success=" + success);}});mCamera.setPreviewCallback(new Camera.PreviewCallback() {@Overridepublic void onPreviewFrame(byte[] data, Camera camera) {Log.i("TAG", "获取预览帧...");Log.d("TAG", "预览帧大小:" + String.valueOf(data.length));}});}} catch (IOException e) {e.printStackTrace();}}private boolean prepareMediaRecorder() {// 创建MediaPlayer对象mCamera.unlock();mRecorder = new MediaRecorder();mRecorder.reset();mRecorder.setCamera(mCamera);// 设置从麦克风采集声音(或来自录像机的声音AudioSource.CAMCORDER)mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);// 设置从摄像头采集图像mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);Log.e("yuanProfile", "QUALITY_LOW=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_LOW));Log.e("yuanProfile", "QUALITY_HIGH=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH));Log.e("yuanProfile", "QUALITY_QCIF=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QCIF));Log.e("yuanProfile", "QUALITY_480P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P));Log.e("yuanProfile", "QUALITY_720P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P));Log.e("yuanProfile", "QUALITY_1080P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P));Log.e("yuanProfile", "QUALITY_QVGA=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA));Log.e("yuanProfile", "QUALITY_2160P=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2160P));Log.e("yuanProfile", "QUALITY_VGA=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_VGA));Log.e("yuanProfile", "QUALITY_4KDCI=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_4KDCI));Log.e("yuanProfile", "QUALITY_QHD=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QHD));Log.e("yuanProfile", "QUALITY_2K=" + CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_2K));if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_720P));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_1080P));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_480P));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_LOW)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH)) {mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));} else {return false;}
//        mTempList.add(mCurrentTempRecordData);mRecorder.setOutputFile(mCurPath);mRecorder.setPreviewDisplay(activtityVideoRecordBinding.sView.getHolder().getSurface()); // ①if(getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE){int degree ;if (cameraPosition == Camera.CameraInfo.CAMERA_FACING_FRONT) {degree = 270;} else {degree = 90;}mRecorder.setOrientationHint(degree);}try {mRecorder.prepare();} catch (Exception e) {e.printStackTrace();return false;}return true;}private void startRecord() {if (prepareMediaRecorder()) {mRecorder.start();isRecording = true;activtityVideoRecordBinding.recordOrStop.setText("停止");} else {releaseMediaRecorder();isRecording = false;activtityVideoRecordBinding.recordOrStop.setText("开始");}}private void stopRecord() {if (mRecorder == null) {return;}mRecorder.stop();releaseMediaRecorder();isRecording = false;activtityVideoRecordBinding.recordOrStop.setText("开始");}@Nullable@Overridepublic CharSequence onCreateDescription() {return super.onCreateDescription();}@Overrideprotected void onDestroy() {releaseCamera();releaseMediaRecorder();super.onDestroy();}/*** 释放相机资源*/private void releaseCamera() {if (mCamera != null) {mCamera.setPreviewCallback(null);mCamera.stopPreview();mCamera.release();mCamera = null;}}private void releaseMediaRecorder() {if (mRecorder != null) {mRecorder.reset();mRecorder.release();mRecorder = null;mCamera.lock();}}@Overrideprotected void onResume() {super.onResume();openCamera(cameraPosition);}@Overrideprotected void onPause() {super.onPause();releaseMediaRecorder();releaseCamera();}/*** 获取最佳预览大小** @param parameters       相机参数* @param screenResolution 屏幕宽高* @return*/@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)private Size getBestCameraResolution(Camera.Parameters parameters, Size screenResolution) {float tmp = 0f;float mindiff = 100f;Log.e("yuanVideo", "screen width=" + screenResolution.getWidth() + " height=" + screenResolution.getHeight());float width_d_height;if (screenResolution.getWidth() > screenResolution.getHeight()) {width_d_height = (float) screenResolution.getWidth() / (float) screenResolution.getHeight();} else {width_d_height = (float) screenResolution.getHeight() / (float) screenResolution.getWidth();}Log.e("yuanVideo", "width_d_height=" + width_d_height);Camera.Size best = null;List supportedPreviewSizes = parameters.getSupportedPreviewSizes();for (Camera.Size s : supportedPreviewSizes) {tmp = Math.abs(((float) s.width / (float) s.height) - width_d_height);Log.e("yuanVideo", "support width=" + s.width + " height=" + s.height + " ratio=" + tmp);if (tmp < mindiff) {mindiff = tmp;best = s;}}Log.e("yuanVideo", "best width=" + best.width + " height=" + best.height);return new Size(best.width, best.height);}/*** 获取屏幕宽度和高度,单位为px** @param context* @return*/@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)public static Size getScreenMetrics(Context context) {DisplayMetrics dm = context.getResources().getDisplayMetrics();int w_screen = dm.widthPixels;int h_screen = dm.heightPixels;return new Size(w_screen, h_screen);}}

布局



 

package com.yuanxuzhen.ffmpeg;import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceView;public class ResizeAbleSurfaceView extends SurfaceView {private int mWidth = -1;private int mHeight = -1;public ResizeAbleSurfaceView(Context context) {super(context);}public ResizeAbleSurfaceView(Context context, AttributeSet attrs) {super(context, attrs);}public ResizeAbleSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {if (-1 == mWidth || -1 == mHeight) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}else {setMeasuredDimension(mWidth, mHeight);}}public void resize(int width, int height) {mWidth = width;mHeight = height;getHolder().setFixedSize(width, height);requestLayout();invalidate();}}
package com.yuanxuzhen.ffmpeg;import android.content.Context;
import android.os.Environment;import java.io.File;public class DirUtil {public static final String WEBVIEW_CACHE = ".webviewCache";public static final String IMAGE_PATH = "image";public static final String DOWNLOAD_PATH = "download";public static final String VIDEO_PATH = ".video";public static final String NET_PATH = ".net";//imagepublic static String getImageDir(Context context) {return getCacheDir(context) + File.separator + IMAGE_PATH;}//webviewpublic static String getWebviewCache(Context context) {return getCacheDir(context) + File.separator + WEBVIEW_CACHE;}//downloadpublic static String getDownloadDir(Context context) {return getCacheDir(context) + File.separator + DOWNLOAD_PATH;}//videopublic static String getVideoPath(Context context) {return getCacheDir(context) + File.separator + VIDEO_PATH;}//netpublic static String getNetPath(Context context) {return getCacheDir(context) + File.separator + NET_PATH;}public static String getCacheDir(Context context) {if (context == null) {return "";}String path = null;if (context.getExternalCacheDir() != null&& (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())|| !Environment.isExternalStorageRemovable())) {//外部存储可用path = context.getExternalCacheDir().getPath();} else {//内部存储不可用path = context.getCacheDir().getPath();}return path;}}

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部