freed.cam.apis.camera2.modules.VideoModuleApi2.java Source code

Java tutorial

Introduction

Here is the source code for freed.cam.apis.camera2.modules.VideoModuleApi2.java

Source

/*
 *
 *     Copyright (C) 2015 Ingo Fuchs
 *     This program is free software; you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation; either version 2 of the License, or
 *     (at your option) any later version.
 *
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 *
 *     You should have received a copy of the GNU General Public License along
 *     with this program; if not, write to the Free Software Foundation, Inc.,
 *     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 * /
 */

package freed.cam.apis.camera2.modules;

import android.annotation.TargetApi;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCaptureSession.StateCallback;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CaptureRequest;
import android.location.Location;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OutputFormat;
import android.media.MediaRecorder.VideoSource;
import android.net.Uri;
import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.support.v4.provider.DocumentFile;
import android.util.Log;
import android.util.Range;
import android.util.Size;
import android.view.Surface;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import freed.cam.apis.KEYS;
import freed.cam.apis.basecamera.CameraWrapperInterface;
import freed.cam.apis.basecamera.modules.I_RecorderStateChanged;
import freed.cam.apis.basecamera.modules.ModuleHandlerAbstract;
import freed.cam.apis.basecamera.modules.VideoMediaProfile;
import freed.cam.apis.camera2.parameters.modes.VideoProfilesApi2;
import freed.utils.AppSettingsManager;

/**
 * Created by troop on 26.11.2015.
 */
@TargetApi(VERSION_CODES.LOLLIPOP)
public class VideoModuleApi2 extends AbstractModuleApi2 {
    private final String TAG = VideoModuleApi2.class.getSimpleName();
    private boolean isRecording;
    private Size previewSize;
    private VideoMediaProfile currentVideoProfile;
    private Surface previewsurface;
    private Surface recorderSurface;
    private File recordingFile;

    private MediaRecorder mediaRecorder;

    public VideoModuleApi2(CameraWrapperInterface cameraUiWrapper, Handler mBackgroundHandler) {
        super(cameraUiWrapper, mBackgroundHandler);
        name = KEYS.MODULE_VIDEO;
    }

    @Override
    public String ModuleName() {
        return name;
    }

    @Override
    public void DoWork() {
        if (isRecording)
            stopRecording();
        else
            startRecording();
    }

    @Override
    public void InitModule() {
        Log.d(TAG, "InitModule");
        super.InitModule();
        VideoProfilesApi2 profilesApi2 = (VideoProfilesApi2) parameterHandler.VideoProfiles;
        currentVideoProfile = profilesApi2
                .GetCameraProfile(appSettingsManager.getApiString(AppSettingsManager.VIDEOPROFILE));
        startPreview();
    }

    @TargetApi(VERSION_CODES.LOLLIPOP)
    @Override
    public void DestroyModule() {
        if (isRecording)
            stopRecording();
        Log.d(TAG, "DestroyModule");
        cameraHolder.CaptureSessionH.CloseCaptureSession();
        previewsurface = null;
        super.DestroyModule();
    }

    @Override
    public String LongName() {
        return "Video";
    }

    @Override
    public String ShortName() {
        return "Vid";
    }

    private void startRecording() {
        changeCaptureState(ModuleHandlerAbstract.CaptureStates.video_recording_start);
        Log.d(TAG, "startRecording");
        startPreviewVideo();
    }

    private void stopRecording() {
        Log.d(TAG, "stopRecording");
        mediaRecorder.stop();
        mediaRecorder.reset();
        cameraHolder.CaptureSessionH.RemoveSurface(recorderSurface);
        recorderSurface = null;
        isRecording = false;

        cameraUiWrapper.GetModuleHandler().onRecorderstateChanged(I_RecorderStateChanged.STATUS_RECORDING_STOP);
        changeCaptureState(ModuleHandlerAbstract.CaptureStates.video_recording_stop);
        cameraHolder.CaptureSessionH.CreateCaptureSession();
        cameraUiWrapper.getActivityInterface().ScanFile(recordingFile);
    }

    @TargetApi(VERSION_CODES.LOLLIPOP)
    @Override
    public void startPreview() {
        previewSize = new Size(currentVideoProfile.videoFrameWidth, currentVideoProfile.videoFrameHeight);
        int sensorOrientation = cameraHolder.characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
        int orientation = 0;
        switch (sensorOrientation) {
        case 90:
            orientation = 270;
            break;
        case 180:
            orientation = 0;
            break;
        case 270:
            orientation = 90;
            break;
        case 0:
            orientation = 180;
            break;
        }
        cameraHolder.CaptureSessionH.SetTextureViewSize(previewSize.getWidth(), previewSize.getHeight(),
                orientation, orientation + 180, true);
        SurfaceTexture texture = cameraHolder.CaptureSessionH.getSurfaceTexture();
        texture.setDefaultBufferSize(currentVideoProfile.videoFrameWidth, currentVideoProfile.videoFrameHeight);
        previewsurface = new Surface(texture);
        cameraHolder.CaptureSessionH.AddSurface(previewsurface, true);
        cameraHolder.CaptureSessionH.CreateCaptureSession();
    }

    @Override
    public void stopPreview() {
        DestroyModule();
    }

    @TargetApi(VERSION_CODES.LOLLIPOP)
    private void startPreviewVideo() {
        recordingFile = new File(cameraUiWrapper.getActivityInterface().getStorageHandler()
                .getNewFilePath(appSettingsManager.GetWriteExternal(), ".mp4"));
        mediaRecorder = new MediaRecorder();
        mediaRecorder.reset();
        mediaRecorder.setMaxFileSize(3037822976L); //~2.8 gigabyte
        mediaRecorder.setMaxDuration(7200000); //2hours
        mediaRecorder.setOnErrorListener(new OnErrorListener() {
            @Override
            public void onError(MediaRecorder mr, int what, int extra) {
                Log.d(TAG, "error MediaRecorder:" + what + "extra:" + extra);
                cameraUiWrapper.GetModuleHandler()
                        .onRecorderstateChanged(I_RecorderStateChanged.STATUS_RECORDING_STOP);
                changeCaptureState(ModuleHandlerAbstract.CaptureStates.video_recording_stop);
            }
        });

        mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
            @Override
            public void onInfo(MediaRecorder mr, int what, int extra) {
                if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
                    recordnextFile(mr);
                } else if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_FILESIZE_REACHED) {
                    recordnextFile(mr);
                }
            }
        });

        if (cameraUiWrapper.GetAppSettingsManager().getApiString(AppSettingsManager.SETTING_LOCATION)
                .equals(KEYS.ON)) {
            Location location = cameraUiWrapper.getActivityInterface().getLocationHandler().getCurrentLocation();
            if (location != null)
                mediaRecorder.setLocation((float) location.getLatitude(), (float) location.getLongitude());
        }
        switch (currentVideoProfile.Mode) {

        case Normal:
        case Highspeed:
            if (currentVideoProfile.isAudioActive)
                mediaRecorder.setAudioSource(AudioSource.CAMCORDER);
            break;
        case Timelapse:
            break;
        }
        mediaRecorder.setVideoSource(VideoSource.SURFACE);

        mediaRecorder.setOutputFormat(OutputFormat.MPEG_4);
        setRecorderFilePath();

        mediaRecorder.setVideoEncodingBitRate(currentVideoProfile.videoBitRate);

        try {
            cameraHolder.SetParameterRepeating(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
                    new Range<>(currentVideoProfile.videoFrameRate, currentVideoProfile.videoFrameRate));
        } catch (Exception e) {
            e.printStackTrace();
        }

        //  if(currentVideoProfile.Mode == VideoMediaProfile.VideoMode.SlowMO)
        //     int SlowFactor = currentVideoProfile.videoFrameRate /30;

        if (currentVideoProfile.videoFrameRate == 120 && currentVideoProfile.videoFrameWidth == 1920)
            mediaRecorder.setVideoFrameRate(60);
        else
            mediaRecorder.setVideoFrameRate(currentVideoProfile.videoFrameRate);

        /*setCaptureRate
            
        Added in API level 11
        void setCaptureRate (double fps)
        Set video frame capture rate. This can be used to set a different video frame capture rate than the recorded video's playback rate.
        !!!!!! This method also sets the recording mode to time lapse.!!!!!
        In time lapse video recording, only video is recorded.
        Audio related parameters are ignored when a time lapse recording session starts, if an application sets them.*/
        //mediaRecorder.setCaptureRate((double)currentVideoProfile.videoFrameRate);
        mediaRecorder.setVideoSize(currentVideoProfile.videoFrameWidth, currentVideoProfile.videoFrameHeight);
        try {
            mediaRecorder.setVideoEncoder(currentVideoProfile.videoCodec);
        } catch (IllegalArgumentException ex) {
            mediaRecorder.reset();
            cameraUiWrapper.GetCameraHolder().SendUIMessage("VideoCodec not Supported");
        }

        switch (currentVideoProfile.Mode) {
        case Normal:
        case Highspeed:
            if (currentVideoProfile.isAudioActive) {
                try {
                    mediaRecorder.setAudioEncoder(currentVideoProfile.audioCodec);
                } catch (IllegalArgumentException ex) {
                    mediaRecorder.reset();
                    cameraUiWrapper.GetCameraHolder().SendUIMessage("AudioCodec not Supported");
                }
                mediaRecorder.setAudioChannels(currentVideoProfile.audioChannels);
                mediaRecorder.setAudioEncodingBitRate(currentVideoProfile.audioBitRate);
                mediaRecorder.setAudioSamplingRate(currentVideoProfile.audioSampleRate);
            }
            break;
        case Timelapse:
            float frame = 30;
            if (!appSettingsManager.getApiString(AppSettingsManager.TIMELAPSEFRAME).equals(""))
                frame = Float.parseFloat(
                        appSettingsManager.getApiString(AppSettingsManager.TIMELAPSEFRAME).replace(",", "."));
            else
                appSettingsManager.setApiString(AppSettingsManager.TIMELAPSEFRAME, "" + frame);
            mediaRecorder.setCaptureRate(frame);
            break;
        }
        try {
            mediaRecorder.prepare();
        } catch (IOException ex) {
            ex.printStackTrace();
            cameraUiWrapper.GetModuleHandler().onRecorderstateChanged(I_RecorderStateChanged.STATUS_RECORDING_STOP);
            changeCaptureState(ModuleHandlerAbstract.CaptureStates.video_recording_stop);
            return;
        }
        recorderSurface = mediaRecorder.getSurface();
        cameraHolder.CaptureSessionH.AddSurface(recorderSurface, true);

        if (currentVideoProfile.Mode != VideoMediaProfile.VideoMode.Highspeed)
            cameraHolder.CaptureSessionH.CreateCaptureSession(previewrdy);
        else
            cameraHolder.CaptureSessionH.CreateHighSpeedCaptureSession(previewrdy);
    }

    private void setRecorderFilePath() {
        if (!appSettingsManager.GetWriteExternal()) {
            mediaRecorder.setOutputFile(recordingFile.getAbsolutePath());
        } else {
            Uri uri = Uri.parse(appSettingsManager.GetBaseFolder());
            DocumentFile df = cameraUiWrapper.getActivityInterface().getFreeDcamDocumentFolder();
            DocumentFile wr = df.createFile("*/*", recordingFile.getName());
            ParcelFileDescriptor fileDescriptor = null;
            try {
                fileDescriptor = cameraUiWrapper.getContext().getContentResolver().openFileDescriptor(wr.getUri(),
                        "rw");
                mediaRecorder.setOutputFile(fileDescriptor.getFileDescriptor());
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                try {
                    fileDescriptor.close();
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        }
    }

    private void recordnextFile(MediaRecorder mr) {
        stopRecording();
        startRecording();
    }

    private final StateCallback previewrdy = new StateCallback() {

        @Override
        public void onConfigured(CameraCaptureSession cameraCaptureSession) {
            if (currentVideoProfile.Mode != VideoMediaProfile.VideoMode.Highspeed) {
                cameraHolder.CaptureSessionH.SetCaptureSession(cameraCaptureSession);
                cameraHolder.CaptureSessionH.StartRepeatingCaptureSession();
            } else {
                cameraHolder.CaptureSessionH.SetHighSpeedCaptureSession(cameraCaptureSession);
                cameraHolder.CaptureSessionH.StartHighspeedCaptureSession();
            }
            mediaRecorder.start();
            isRecording = true;
            cameraUiWrapper.GetModuleHandler()
                    .onRecorderstateChanged(I_RecorderStateChanged.STATUS_RECORDING_START);

        }

        @Override
        public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
            Log.d(TAG, "Failed to Config CaptureSession");
        }
    };
}