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();
}
}