1. 程式人生 > >錄影功能簡單實現&字幕srt儲存

錄影功能簡單實現&字幕srt儲存

介面效果

這裡寫圖片描述

功能介紹

照相機預覽

  • 窗體的onCreate中新增
SurfaceHolder holder = surfaceView.getHolder();
holder.addCallback(this);
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
surfaceView.setKeepScreenOn(true);//保持螢幕高亮
  • surfaceCreated
@Override
public void surfaceCreated(SurfaceHolder holder) {
    surfaceHolder = holder;
    //初始化相機
initCamera(); }
  • surfaceChanged
@Override
public void surfaceChanged(SurfaceHolder holder, int i, int i1, int i2) {
    surfaceHolder = holder;
    //開啟相機預覽
    cameraPreview();
}
  • surfaceDestroyed
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    surfaceView = null;
    surfaceHolder = null
; //釋放MediaRecorder及相機 stopRecord(); //釋放MediaPlayer stopPlay(); }
  • initCamera:初始化相機
private void initCamera() {
    if (camera != null) {
        camera.release();
        camera = null;
    }
    try {
        //開啟後置攝像頭(此文未涉及前置攝像頭)
        camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        if
(camera != null) { cameraPara = camera.getParameters(); //可通過camera.getParameters().getSupportedVideoSizes()獲取支援的大小 cameraPara.setPreviewSize(600, 480); cameraPara.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); camera.cancelAutoFocus();//連續自動對焦 camera.setParameters(cameraPara); } } catch (Exception e) { e.printStackTrace(); if (camera != null) { camera.release(); camera = null; } } }
  • cameraPreview:相機預覽
private void cameraPreview() {
    if (camera != null) {
        try {
            camera.setPreviewDisplay(surfaceView.getHolder());
            camera.setDisplayOrientation(90);
            camera.startPreview();
            //設定閃光燈
            cameraPara.setFlashMode(isFlashOn ? Parameters.FLASH_MODE_TORCH : Parameters.FLASH_MODE_OFF);
            camera.setParameters(cameraPara);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

錄影

  • startRecord:開始錄製
private static final int RECORDER_MAX_LENGTH = 30 * 60 * 1000;//錄影最大時長
private Handler handler = new Handler();
private long srtInterval = 1000;//字幕輸出的時間間隔

private void startRecord() {
    //錄影過程中顯示時間
    hour = minute = second = 0;
    startRecordTime = new Date().getTime();
    handler.postDelayed(updateTimeRunnable, 1000);
    //錄影過程中儲存字幕檔案
    lastSrtTime = "00:00:00,000";//上次輸出srt的時間
    srtRowNum = 1;//字幕輸出的行號
    handler.postDelayed(recordSrtRunnable, srtInterval);    

    //開始錄製
    if (mediaRecorder == null) {
        mediaRecorder = new MediaRecorder();
    }
    if (camera == null) {
        initCamera();
        camera.setDisplayOrientation(90);
    }
    camera.unlock();
    mediaRecorder.setCamera(camera);
    try {
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);

        //設定輸出的檔案格式 
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);

        //與camera的previewSize需設定為一樣
        mediaRecorder.setVideoSize(640, 480);
        mediaRecorder.setVideoFrameRate(30);
        mediaRecorder.setVideoEncodingBitRate(3 * 1024 * 1024);
        mediaRecorder.setOrientationHint(90);

        //設定記錄會話的最大持續時間(毫秒)
        mediaRecorder.setMaxDuration(RECORDER_MAX_LENGTH);
        mediaRecorder.setPreviewDisplay(surfaceHolder.getSurface());

        mediaRecorder.setOutputFile(path);
        mediaRecorder.prepare();
        mediaRecorder.start();
    } catch (Exception e) {
        e.printStackTrace();
        stopRecord();
    }
}

//顯示錄影時長
private Runnable updateTimeRunnable = new Runnable() {
    @Override
    public void run() {
        if (second >= 59) {
            if (minute >= 59) {
                hour++;
                minute = 0;
            } else {
                minute++;
            }
            second = 0;
        } else {
            second++;
        }
        if (hour > 0) {
            tvTime.setText(String.format("%02d:%02d:%02d", hour, minute, second));
        } else {
            tvTime.setText(String.format("%02d:%02d", minute, second));
        }
        //錄製超過最大時長
        if (new Date().getTime() - startRecordTime >= RECORDER_MAX_LENGTH) {
            stopRecord();
            return;
        }

        handler.postDelayed(this, 1000);
    }
}

//將位置資訊寫入字幕檔案
private Runnable recordSrtRunnable = new Runnable() {
    @Override
    public void run() {
        StringBuilder srtBuilder = new StringBuilder();
        String srtTime = String.format("%02d:%02d:%02d,000", hour, minute, second);
        srtBuilder.append(srtRowNum++ + "\n");
        srtBuilder.append(String.format("%s --> %s\n", lastSrtTime, srtTime));
        srtBuilder.append(String.format("%s%.2f\n", "高程:", altitude));
        srtBuilder.append("\n");
        srtBuilder.append(srtRowNum++ + "\n");
        srtBuilder.append(String.format("%s --> %s\n", lastSrtTime, srtTime));
        srtBuilder.append(String.format("%s%s %s%s\n", "緯度:", latitude, "經度:", longitude));
        srtBuilder.append("\n");
        lastSrtTime = srtTime;

        File srtFile = new File(srtPath);
        try {
            FileOutputStream fs = new FileOutputStream(srtFile.getAbsolutePath(), true);
            fs.write(srtBuilder.toString().getBytes());
            fs.close();
        } catch (Exception e) {
            e.printStackTrack();
        }

        handler.postDelayed(this, srtInterval);
    }
}
  • stopRecord:停止錄製,釋放資源
private void stopRecord() {
    try {
        if (mediaRecorder != null) {
            handler.removeCallbacks(recordSrtRunnable);
            handler.removeCallbacks(updateTimeRunnable);
            mediaRecorder.stop();
            mediaRecorder.reset();
            mediaRecorder.release();
            mediaRecorder = null;
        }   
        if (camera != null) {
            camera.release();
            camera = null;
        }    
    } catch (Exception e) {
        e.printStackTrace();
    }
}

播放

  • startPlay:開始播放
private void startPlay() {
    if (mediaPlayer == null) {
        mediaPlayer = new MediaPlayer();
    }
    mediaPlayer.reset();
    Uri uri = Uri.parse(path);
    mediaPlayer = MediaPlayer.create(MainActivity.this, uri);
    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    mediaPlayer.setDisplay(surfaceHolder);
    mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
        @Override
        public void onCompletion(MediaPlayer mediaPlayer) {
            stopPlay();
        }
    });
    try {
        mediaPlayer.prepare();
    } catch (Exception e) {
        e.printStackTrace();
    }
    mediaPlayer.start();
}
  • stopPlay:停止播放,釋放資源
private void stopPlay() {
    if (mediaPlayer != null){
        mediaPlayer.stop();
        mediaPlayer.reset();
        mediaPlayer.release();
        mediaPlayer = null;
    }
}

其他

  • 判斷閃光燈是否可用
getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH);
  • 開關閃光燈
btnFlash.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (isFlashOn) {
            btnFlash.setImageResource(R.drawable.video_flash_close);
            isFlashOn = false;
        } else {
            btnFlash.setImageResource(R.drawable.video_flash_on);
            isFlashOn = true;
        }
        cameraPara.setFlashMode(isFlashOn ? Parameters.FLASH_MODE_TORCH : Parameters.FLASH_MODE_OFF);
        camera.setParameters(cameraPara);
    }
});
  • AndroidManifest.xml新增許可權
<uses-feature android:name="android.hardware.camera"/>
<uses-feature android:name="android.hardware.camera.autofocus"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
  • 字幕檔案srt的格式
1
00:00:00,000 --> 00:00:01,000
高程:150.60

2
00:00:00,000 --> 00:00:01,000
緯度:22.982481666666665 經度:113.36807833333333

3
00:00:01,000 --> 00:00:02,000
高程:150.60

4
00:00:01,000 --> 00:00:02,000
緯度:22.982481666666665 經度:113.36807833333333
  • 錄製結果

這裡寫圖片描述