同时录像拍照

边录像边拍照 ,Android怎样实现录制视频时拍照(或连续取录制的实时这一帧),就是同时录像时可以连续保存图片到本地,录像也同时保存

/**
 * @author: Jeff <[email protected]>
 * @date: 2018-03-05 15:08
 * @description: PLRecordStateListener注册录制状态监听器 , PLVideoSaveListener注册保存视频的监听器
 */
public class VideoActivity extends AppCompatActivity implements PLRecordStateListener, PLVideoSaveListener {


    //captureIV 拍照,deleteIV 删除视频,recordIV 录像,concatIV 保存
    Button captureIV, deleteIV, recordIV, concatIV;

    private void setClickListener() {
        recordIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //  newFilepath(true);
                // 开始一段视频
                mShortVideoRecorder.beginSection();
                newFilepath(true);
            }
        });
        deleteIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 回删上一段视频
                mShortVideoRecorder.deleteLastSection();
            }
        });
        concatIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //先结束视频再保存
                mShortVideoRecorder.endSection();
                // 合成和保存所有的视频片段
                mShortVideoRecorder.concatSections(VideoActivity.this);
            }
        });
        captureIV.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //拍照
                newFilepath(false);
            }
        });
    }

    String VIDEO_STORAGE_DIR = Environment.getExternalStorageDirectory() + "/ShortVideo/";
    String VIDEO_FILE_PATH = "";
    String JPEG_FILE_PATH = "";

    private void newFilepath(boolean path) {
        //创建一个地址,保存图片和视频为时间戳地址
        if (path) {//视频
            //如果是true那就设置  视频
            VIDEO_FILE_PATH = VIDEO_STORAGE_DIR + "video" + System.currentTimeMillis() + ".mp4";
            mRecordSetting.setVideoFilepath(VIDEO_FILE_PATH);

        } else {
            //如果是false那就设置  图片
            JPEG_FILE_PATH = VIDEO_STORAGE_DIR + "img" + System.currentTimeMillis() + ".jpg";
            onCaptureFrame();
        }
    }

    public void onCaptureFrame() {

        //获得视频帧,并做保存
        mShortVideoRecorder.captureFrame(new PLCaptureFrameListener() {
            @Override
            public void onFrameCaptured(PLVideoFrame capturedFrame) {
                if (capturedFrame == null) {
                    Log.d("VideoActivity", "capture frame failed");
                    return;
                }
                //获取帧数据 byte[] getData()
                //将帧数据转换为   Bitmap toBitmap();
                //  Bitmap bitmap = capturedFrame.toBitmap();
                FileOutputStream fos = null;
                try {
                    fos = new FileOutputStream(JPEG_FILE_PATH);
                    capturedFrame.toBitmap().compress(Bitmap.CompressFormat.JPEG, 100, fos);
                    fos.flush();
                    fos.close();
//                    runOnUiThread(new Runnable() {
//                        @Override
//                        public void run() {
//                          //  ToastUtils.s(VideoRecordActivity.this, "截帧已保存到路径:" + Config.CAPTURED_FRAME_FILE_PATH);
//                        }
//                    });
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    if (fos != null) {
                        try {
                            fos.flush();
                            fos.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //设置屏幕常亮
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_video_record);
        //captureIV 拍照,deleteIV 删除视频,recordIV 录像,concatIV 保存
        captureIV = (Button) findViewById(R.id.capture_frame_button);
        recordIV = (Button) findViewById(R.id.record);
        deleteIV = (Button) findViewById(R.id.delete);
        concatIV = (Button) findViewById(R.id.concat);
        glSurfaceView = (GLSurfaceView) findViewById(R.id.preview);
        intioVideo();
        setClickListener();

    }


    //拍摄视频需要的预览窗口为 GLSurfaceView
    GLSurfaceView glSurfaceView;
    //创建录制对象
    PLShortVideoRecorder mShortVideoRecorder;
    //摄像头采集选项
    PLCameraSetting mCameraSetting;
    // 麦克风采集选项
    PLMicrophoneSetting mMicrophoneSetting;
    // 视频编码选项
    PLVideoEncodeSetting mVideoEncodeSetting;
    //// 音频编码选项
    PLAudioEncodeSetting mAudioEncodeSetting;
    // 美颜选项
    PLFaceBeautySetting mFaceBeautySetting;
    // 录制选项  //配置拍摄参数   缓存目录,拍摄时长等
    PLRecordSetting mRecordSetting;

    //视频对象初始化
    private void intioVideo() {
        // 创建录制对象
        mShortVideoRecorder = new PLShortVideoRecorder();
        mShortVideoRecorder.setRecordStateListener(this);
        //  mShortVideoRecorder.setPLVideoSaveListener()
        //mShortVideoRecorder.setVideoFilterListener();

        // 摄像头采集选项
        mCameraSetting = new PLCameraSetting();
        mCameraSetting.setCameraId(chooseCameraFacingId());
        mCameraSetting.setCameraPreviewSizeRatio(PLCameraSetting.CAMERA_PREVIEW_SIZE_RATIO.RATIO_4_3);
        mCameraSetting.setCameraPreviewSizeLevel(PLCameraSetting.CAMERA_PREVIEW_SIZE_LEVEL.PREVIEW_SIZE_LEVEL_1080P);
        // 麦克风采集选项
        mMicrophoneSetting = new PLMicrophoneSetting();
        //  AudioFormat.CHANNEL_IN_MONO 16 : AudioFormat.CHANNEL_IN_STEREO 12
        mMicrophoneSetting.setChannelConfig(AudioFormat.CHANNEL_IN_MONO);
        // 视频编码选项
        mVideoEncodeSetting = new PLVideoEncodeSetting(this);
        mVideoEncodeSetting.setEncodingSizeLevel(PLVideoEncodeSetting.VIDEO_ENCODING_SIZE_LEVEL.VIDEO_ENCODING_SIZE_LEVEL_480P_1); // 480x480
        mVideoEncodeSetting.setEncodingBitrate(1000 * 1000); // 1000kbps
        mVideoEncodeSetting.setEncodingFps(24);
        mVideoEncodeSetting.setHWCodecEnabled(true); // true:硬编 false:软编
        // 音频编码选项
        mAudioEncodeSetting = new PLAudioEncodeSetting();
        mAudioEncodeSetting.setHWCodecEnabled(true); // true:硬编 false:软编
        mAudioEncodeSetting.setChannels(1);
        // mAudioEncodeSetting.setChannels(RecordSettings.AUDIO_CHANNEL_NUM_ARRAY[audioChannelNumPos]);
        // 美颜选项
        mFaceBeautySetting = new PLFaceBeautySetting(1.0f, 0.5f, 0.5f);
        //配置拍摄参数    缓存目录,拍摄时长等
        mRecordSetting = new PLRecordSetting();
        //// 60s  慢   mRecordSpeed = RECORD_SPEED_ARRAY[1]; 正常 mRecordSpeed = RECORD_SPEED_ARRAY[2];
        mRecordSetting.setMaxRecordDuration((long) (10 * 1000 * 6 * 1));
        mRecordSetting.setVideoCacheDir(VIDEO_STORAGE_DIR);
//        mRecordSetting.setVideoFilepath(VIDEO_FILE_PATH);
//        //通过 prepare 把拍摄所选择的参数配置到 SDK 中
//        mShortVideoRecorder.prepare(glSurfaceView, mCameraSetting, mMicrophoneSetting,
//                mVideoEncodeSetting, mAudioEncodeSetting, mFaceBeautySetting, mRecordSetting);
        newFilepath(true);
        //通过 prepare 把拍摄所选择的参数配置到 SDK 中
        mShortVideoRecorder.prepare(glSurfaceView, mCameraSetting, mMicrophoneSetting,
                mVideoEncodeSetting, mAudioEncodeSetting, mFaceBeautySetting, mRecordSetting);
    }

    private PLCameraSetting.CAMERA_FACING_ID chooseCameraFacingId() {
        if (PLCameraSetting.hasCameraFacing(PLCameraSetting.CAMERA_FACING_ID.CAMERA_FACING_3RD)) {
            return PLCameraSetting.CAMERA_FACING_ID.CAMERA_FACING_3RD;
        } else if (PLCameraSetting.hasCameraFacing(PLCameraSetting.CAMERA_FACING_ID.CAMERA_FACING_FRONT)) {
            return PLCameraSetting.CAMERA_FACING_ID.CAMERA_FACING_FRONT;
        } else {
            return PLCameraSetting.CAMERA_FACING_ID.CAMERA_FACING_BACK;
        }
    }


    //在 Activity 的各个生命周期的回调中,分别调用 PLShortVideoRecorder 对应的方法*************
    @Override
    protected void onResume() {
        super.onResume();
        mShortVideoRecorder.resume();
    }

    @Override
    protected void onPause() {
        super.onPause();
        mShortVideoRecorder.pause();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mShortVideoRecorder.destroy();
    }


    //PLRecordStateListener注册录制状态监听器********************************************
    @Override
    public void onReady() {
        // 当准备完毕可以进行录制时触发
        //  ToastUtils.s(VideoActivity.this, "可以开始拍摄咯");
        Log.d("VideoActivity", "onReady()");
    }

    @Override
    public void onError(int i) {
        //当有异常发生时触发\
        Log.d("VideoActivity", "onError(int i)---= " + i);
    }

    @Override
    public void onDurationTooShort() {
        //当录制的片段过短时触发
        Log.d("VideoActivity", "onDurationTooShort()");
    }

    @Override
    public void onRecordStarted() {
        //录制开始
        Log.d("VideoActivity", "onRecordStarted() ");
    }

    @Override
    public void onRecordStopped() {
        //录制结束
        Log.d("VideoActivity", "onRecordStopped()");
    }

    @Override
    public void onSectionIncreased(long incDuration, long totalDuration, int sectionCount) {
        /**
         * 当有新片段录制完成时触发
         * @param incDuration   增加的时长
         * @param totalDuration 总时长
         * @param sectionCount  当前的片段总数
         */
        Log.d("VideoActivity",
                "onSectionIncreased(long incDuration, long totalDuration, int sectionCount)==incDuration"
                        + incDuration + "---totalDuration=" + totalDuration + "----sectionCount=" + sectionCount
        );
    }

    @Override
    public void onSectionDecreased(long decDuration, long totalDuration, int sectionCount) {
        /**
         * 当有片段被删除时触发
         * @param decDuration   减少的时长
         * @param totalDuration 总时长
         * @param sectionCount  当前的片段总数
         */
        Log.d("VideoActivity",
                "onSectionDecreased(long decDuration, long totalDuration, int sectionCount)==sectionCount="
                        + decDuration + "---totalDuration=" + totalDuration + "---sectionCount=" + sectionCount);
    }

    @Override
    public void onRecordCompleted() {
        //当录制全部完成时触发
        Log.d("VideoActivity", "onRecordCompleted()");
    }

    //**************PLVideoSaveListener注册保存视频的监听器***************************************
    @Override
    public void onSaveVideoSuccess(String s) {
        //保存成功时触发
        //在这里可以上传文件
        Log.d("VideoActivity", " onSaveVideoSuccess(String s)===" + s);
        //compressVideoResouce(s);
    }

    @Override
    public void onSaveVideoFailed(int i) {
        //保存失败时触发
        Log.d("VideoActivity", "nSaveVideoFailed(int i)==" + i);
    }

    @Override
    public void onSaveVideoCanceled() {
        //保存取消时触发
        Log.d("VideoActivity", "onSaveVideoCanceled()");
    }

    @Override
    public void onProgressUpdate(float v) {
        //保存进度更新时触发
        Log.d("VideoActivity", "onProgressUpdate(float v)==" + v);
    }

    /**
     * 压缩视频
     *
     * @param filepath
     */
    public void compressVideoResouce(String filepath) {
        if (TextUtils.isEmpty(filepath)) {
            //ToastUtils.s(VideoActivity.this, "请先选择转码文件!");
            return;
        }
        //PLShortVideoTranscoder初始化,三个参数,第一个context,第二个要压缩文件的路径,第三个视频压缩后输出的路径
//        PLShortVideoTranscoder mShortVideoTranscoder = new PLShortVideoTranscoder(this, filepath,
//                APPConstant.LOCAL_PATH + "compress/transcoded.mp4");
        PLShortVideoTranscoder mShortVideoTranscoder = new PLShortVideoTranscoder(this, filepath,
                VIDEO_STORAGE_DIR + "newVideo" + System.currentTimeMillis() + ".mp4");

        MediaMetadataRetriever retr = new MediaMetadataRetriever();
        retr.setDataSource(filepath);
        String height = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT); // 视频高度
        String width = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH); // 视频宽度
        //String rotation = retr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION); // 视频旋转方向
        int transcodingBitrateLevel = 6;//我这里选择的2500*1000压缩,这里可以自己选择合适的压缩比例
        mShortVideoTranscoder.transcode(Integer.parseInt(width), Integer.parseInt(height), getEncodingBitrateLevel(transcodingBitrateLevel),
                false, new PLVideoSaveListener() {
                    @Override
                    public void onSaveVideoSuccess(String s) {
                        //保存成功时触发
                        //在这里可以上传文件
                        Log.d("VideoActivity", " onSaveVideoSuccess(String s)===" + s);
                    }

                    @Override
                    public void onSaveVideoFailed(final int errorCode) {

                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                switch (errorCode) {
                                    case PLErrorCode.ERROR_NO_VIDEO_TRACK:
                                        // ToastUtils.s(VideoActivity.this, "该文件没有视频信息!");
                                        break;
                                    case PLErrorCode.ERROR_SRC_DST_SAME_FILE_PATH:
                                        // ToastUtils.s(VideoActivity.this, "源文件路径和目标路径不能相同!");
                                        break;
                                    case PLErrorCode.ERROR_LOW_MEMORY:
                                        // ToastUtils.s(VideoActivity.this, "手机内存不足,无法对该视频进行时光倒流!");
                                        break;
                                    default:
                                        // ToastUtils.s(VideoActivity.this, "transcode failed: " + errorCode);
                                }
                            }
                        });
                    }

                    @Override
                    public void onSaveVideoCanceled() {
//                LogUtil.e("onSaveVideoCanceled");
                    }

                    @Override
                    public void onProgressUpdate(float percentage) {
//                LogUtil.e("onProgressUpdate==========" + percentage);
                    }
                });
    }

    /**
     * 设置压缩质量
     *
     * @param position
     * @return
     */
    private int getEncodingBitrateLevel(int position) {
        return ENCODING_BITRATE_LEVEL_ARRAY[position];
    }

    /**
     * 选的越高文件质量越大,质量越好
     */
    public static final int[] ENCODING_BITRATE_LEVEL_ARRAY = {
            500 * 1000,
            800 * 1000,
            1000 * 1000,
            1200 * 1000,
            1600 * 1000,
            2000 * 1000,
            2500 * 1000,
            4000 * 1000,
            8000 * 1000,
    };
}

源码下载源码下载

猜你喜欢

转载自blog.csdn.net/jeff_yaojie/article/details/79460323