通过MediaRecorder实现Android后台循环录像

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.media.MediaRecorder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class RoadRecordService extends Service {
    private static final String TAG = "RoadRecordService";
    //    adb shell am startservice -n .RoadRecordService --ei duration 20000 --ei id 0 --ei height 1080 --ei width 1920
    //    adb shell am stopservice -n .RoadRecordService
    private int video_duration = 10000;
    private int camera_id = 0;
    private int camera_w = 1920;
    private int camera_h = 1080;
    private MediaRecorder mMediaRecorder;
    private WindowManager windowManager;
    private CameraManager cameraManager;
    private CameraDevice cameraDevice;
    private CameraCaptureSession mPreviewSession;
    private CaptureRequest.Builder mPreviewBuilder;
    private CameraDevice.StateCallback mCameraDeviceStateCallback;
    private CameraCaptureSession.StateCallback mSessionStateCallback;
    private CameraCaptureSession.CaptureCallback mSessionCaptureCallback;
    private Handler mChildHandler;
    private int i = 0;
    private boolean isClick = true;
    private Thread clickThread;
    private String root_path;
    private boolean isRecord = false;
    private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");;
    private Handler handler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            if (msg.what == 0){
                if (mMediaRecorder!=null){
                    mMediaRecorder.stop();
                    mMediaRecorder.release();
                    mMediaRecorder = null;
                }
                if (mPreviewSession!=null){
                    mPreviewSession.close();
                }
                if (cameraDevice!=null){
                    cameraDevice.close();
                }
                initCamera();
            }
        }
    };
    public RoadRecordService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG,"onCreate");
        root_path = getExternalFilesDir("")+"/video";
        initSurface();
        HandlerThread handlerThread = new HandlerThread("Camera2Demo");
        handlerThread.start();
        mChildHandler = new Handler(handlerThread.getLooper());
        initSessionCaptureCallback();
        initSessionStateCallback();
    }

    @SuppressLint("MissingPermission")
    private void initCamera() {
        cameraManager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        try {
            if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                // TODO: Consider calling
                //    ActivityCompat#requestPermissions
                // here to request the missing permissions, and then overriding
                //   public void onRequestPermissionsResult(int requestCode, String[] permissions,
                //                                          int[] grantResults)
                // to handle the case where the user grants the permission. See the documentation
                // for ActivityCompat#requestPermissions for more details.
                return;
            }
            cameraManager.openCamera(camera_id + "", new CameraDevice.StateCallback() {
                @Override
                public void onOpened(@NonNull CameraDevice camera) {
                    cameraDevice = camera;
                    createBuild();
                }

                @Override
                public void onDisconnected(@NonNull CameraDevice camera) {
                    stopSelf();
                }

                @Override
                public void onError(@NonNull CameraDevice camera, int error) {
                    stopSelf();
                }
            }, null);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void initSurface(){
        windowManager = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        TextView textView = new TextView(this);
        WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
                150, 70,
                WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY,
                WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH,
                PixelFormat.TRANSLUCENT
        );
        textView.setText("开始录制");
        textView.setBackgroundColor(Color.RED);
        textView.setGravity(Gravity.CENTER);
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.i(TAG,"onClick=====");
                if (isRecord){
                    isRecord = false;
                    stopRecord();
                    textView.setText("开始录制");
                }else {
                    isRecord = true;
                    initCamera();
                    textView.setText("结束录制");
                }
            }
        });
        layoutParams.gravity = Gravity.RIGHT | Gravity.TOP;
        windowManager.addView(textView, layoutParams);
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        video_duration = intent.getIntExtra("duration",10000);
        camera_id = intent.getIntExtra("id",0);
        camera_w = intent.getIntExtra("width",1280);
        camera_h = intent.getIntExtra("height",720);
        Log.i(TAG,"onStartCommand = "+video_duration+";"+camera_id+";"+camera_w+";"+camera_h);
        initCamera();
        startThread();
        return super.onStartCommand(intent, flags, startId);
    }
    private void startThread(){
        clickThread = new Thread(new Runnable() {
            @Override
            public void run() {
                int j = 0;
                while (isClick){
                    Log.i(TAG,"thread = "+j);
                    j++;
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        clickThread.start();
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }
    private void setUpMediaRecorder() {
        mMediaRecorder = new MediaRecorder();
        //设置用于录制的音源
//        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        //开始捕捉和编码数据到setOutputFile(指定的文件)
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
        //设置在录制过程中产生的输出文件的格式
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        //设置输出文件的路径
        mMediaRecorder.setOutputFile(getVideoPath());
        //设置录制的视频编码比特率
        mMediaRecorder.setVideoEncodingBitRate(10000000);
        //设置要捕获的视频帧速率
        mMediaRecorder.setVideoFrameRate(25);
        //设置要捕获的视频的宽度和高度
        mMediaRecorder.setVideoSize(camera_w,camera_h);
        //设置视频编码器,用于录制
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        //设置audio的编码格式
//        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
        try {
            mMediaRecorder.prepare();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    private String getVideoPath(){
        File pathFile = new File(root_path);
        if (!pathFile.exists()){
            pathFile.mkdirs();
        }
        String videoPath = root_path+"/"+simpleDateFormat.format(new Date())+".mp4";
        Log.i(TAG,"videoPath = "+videoPath);
        File videoFile = new File(videoPath);
        try {
            videoFile.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return videoPath;
    }
    private void createBuild(){
        setUpMediaRecorder();
        try {
            mPreviewBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
            List<Surface> surfaces = new ArrayList<>();
            Surface recorderSurface = mMediaRecorder.getSurface();
            surfaces.add(recorderSurface);
            mPreviewBuilder.addTarget(recorderSurface);
            // 一旦会话开始,我们就可以更新UI并开始录制
            cameraDevice.createCaptureSession(surfaces, mSessionStateCallback, mChildHandler);
            startRecord();
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void startRecord(){
        Log.i(TAG,"startRecord = "+i);
        i++;
        mMediaRecorder.start();
        deleteFile();
        handler.sendEmptyMessageDelayed(0,video_duration);
    }
    private void initSessionStateCallback(){
        mSessionStateCallback = new CameraCaptureSession.StateCallback() {
            @Override
            public void onConfigured(@NonNull CameraCaptureSession session) {
                mPreviewSession = session;
                try {
                    //执行重复获取数据请求,等于一直获取数据呈现预览画面,mSessionCaptureCallback会返回此次操作的信息回调
                    mPreviewSession.setRepeatingRequest(mPreviewBuilder.build(),mSessionCaptureCallback,mChildHandler);
                } catch (CameraAccessException e) {
                    e.printStackTrace();
                }

            }

            @Override
            public void onConfigureFailed(@NonNull CameraCaptureSession session) {

            }
        };
    }

    private void initSessionCaptureCallback(){
        mSessionCaptureCallback = new CameraCaptureSession.CaptureCallback() {
            @Override
            public void onCaptureStarted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, long timestamp, long frameNumber) {
                super.onCaptureStarted(session, request, timestamp, frameNumber);
            }

            @Override
            public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
                super.onCaptureProgressed(session, request, partialResult);
            }

            @Override
            public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                super.onCaptureCompleted(session, request, result);
            }

            @Override
            public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
                super.onCaptureFailed(session, request, failure);
            }
        };
    }
    private void deleteFile(){
        File rootFile = new File(root_path);
        File[] childFiles = rootFile.listFiles();
        if (childFiles.length > 10){
            long time = 0;
            File delFile = null;
            for (int j = 0; j < childFiles.length; j++) {
                File childFile = childFiles[j];
                String name = childFile.getName();
                String timeStr = name.substring(0,name.lastIndexOf("."));
                Log.i(TAG,"child name = "+timeStr);
                try {
                    long t = simpleDateFormat.parse(timeStr).getTime();
                    if (time == 0){
                        time = t;
                        delFile = childFile;
                    }
                    if (t<time){
                        time = t;
                        delFile = childFile;
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }
            }
            if (delFile!=null){
                Log.i(TAG,"delFile = "+delFile.getPath());
                delFile.delete();
            }
        }else {
            Log.i(TAG,"file length = "+childFiles.length);
        }
    }
    private void stopRecord(){
        if (mMediaRecorder!=null){
            mMediaRecorder.stop();
            mMediaRecorder.release();
        }
        if (mPreviewSession!=null){
            mPreviewSession.close();
        }
        if (cameraDevice!=null){
            cameraDevice.close();
        }
    }
    public void onDestroy() {
        Log.i(TAG,"onDestroy");
        stopRecord();
        if (clickThread != null){
            isClick = false;
        }
        super.onDestroy();
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,实现后台录像可以通过使用Service和MediaRecorder类来实现。 首先,需要创建一个后台Service,在Service的onCreate()方法中进行初始化工作,例如创建一个MediaRecorder实例并设置相关参数,例如录制视频的分辨率、帧率、编码格式等。同时,还要在onCreate()方法中获取相机权限,并在onDestroy()方法中对MediaRecorder进行释放。 接下来,在Service的onStartCommand()方法中实现具体的录像逻辑。可以先通过Camera类获取到相机实例,并使用相机的setPreviewDisplay()方法将相机预览界面与MediaRecorder绑定,然后调用MediaRecorder的start()方法开始录制视频。 为了实现后台录像,可以将Service设置为前台服务,即使用startForeground()方法将Service置于前台,同时显示一个通知。这样可以避免Android系统在资源有限时终止后台录像服务。 最后,可以在Service的onDestroy()方法中调用MediaRecorder的stop()方法停止录像,并进行资源释放和一些清理工作。 需要注意的是,由于安卓系统的限制,从Android 10开始,应用在后台录像的时长受到了限制,最多只能录制5分钟。为了延长后台录像的时间,可以将应用设置为前台服务,并在通知中显示一个进度条,模拟长时间录像的效果。 综上所述,通过在Service中使用MediaRecorder类,结合前台服务的设置,可以在Android实现后台录像功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值