Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 使用FFmpeg 裁剪出正方形視頻

Android 使用FFmpeg 裁剪出正方形視頻

編輯:關於Android編程

到目前為止 Android 中還不能直接錄制正方形的視頻, 雖然不能直接錄但是我們也有一些方式來處理錄制後的視頻, 之前我寫過一篇文章 Android 自定義Camera(一), 可以先了解一下如何做一個簡單的自定義相機demo, 那錄制視頻也要開啟相機預覽, 有以下幾個步驟和需要注意的地方:

1. 獲取相機實例

/**
     * 獲取Camera實例
     *
     * @return
     */
    private Camera getCamera(int id) {
        Camera camera = null;
        try {
            camera = Camera.open(id);
        } catch (Exception e) {

        }
        return camera;
    }

2. 開啟預覽
要注意, 開啟預覽要在 Activity 的 onResume 方法裡面開啟, 然後在 onPause 方法裡面釋放相機資源, 舉一個簡單的例子, 如果你在預覽的時候按下了home鍵, 此時再次打開程序, 如果你是在 Oncreate 方法裡面開啟相機, 那麼再次打開預覽界面應該會卡住。

/**
     * 預覽相機
     */
    private void startPreview(Camera camera, SurfaceHolder holder) {
        try {
            setupCamera(camera);
            camera.setPreviewDisplay(holder);
            //獲取相機預覽角度, 後面錄制視頻需要用
            recorderRotation = CameraUtil.getInstance().getRecorderRotation(mCameraId);
            CameraUtil.getInstance().setCameraDisplayOrientation(this, mCameraId, camera);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 設置
     */
    private void setupCamera(Camera camera) {
        if (camera != null) {
            Camera.Parameters parameters = camera.getParameters();

            List focusModes = parameters.getSupportedFocusModes();
            if (focusModes != null && focusModes.size() > 0) {
                if (focusModes.contains(
                        Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                    //設置自動對焦
                    parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
                }
            }

            List videoSiezes = null;
            if (parameters != null) {
                //獲取相機所有支持尺寸
                videoSiezes = parameters.getSupportedVideoSizes();
                for (Camera.Size size : videoSiezes) {
                }
            }

            if (videoSiezes != null && videoSiezes.size() > 0) {
                //拿到一個預覽寬度最小為720像素的預覽值 
                Camera.Size videoSize = CameraUtil.getInstance().getPropVideoSize(videoSiezes, 720);
                video_width = videoSize.width;
                video_height = videoSize.height;
                LogUtils.i("video_width===" + video_width);
                LogUtils.i("video_height===" + video_height);
            }

            //這裡第三個參數為最小尺寸 getPropPreviewSize方法會對從最小尺寸開始升序排列 取出所有支持尺寸的最小尺寸
            Camera.Size previewSize = CameraUtil.getInstance().getPropPreviewSize(parameters.getSupportedPreviewSizes(), video_width);
            parameters.setPreviewSize(previewSize.width, previewSize.height);

            Camera.Size pictrueSize = CameraUtil.getInstance().getPropPictureSize(parameters.getSupportedPictureSizes(), video_width);
            parameters.setPictureSize(pictrueSize.width, pictrueSize.height);

            camera.setParameters(parameters);

            /**
             * 設置surfaceView的尺寸 因為camera默認是橫屏,所以取得支持尺寸也都是橫屏的尺寸
             * 我們在startPreview方法裡面把它矯正了過來,但是這裡我們設置設置surfaceView的尺寸的時候要注意 previewSize.height

3. 開始錄制

這裡要注意的是 MediaRecorder 的相關方法的調用順序時候不能亂的, 詳細可以看官網api說明

接下來開啟錄制:

protected void start() {
        try {
            pathName = System.currentTimeMillis() + "";
            //視頻存儲路徑
            file = new File(MyApplication.getInstance().getTempPath() + File.separator + pathName + AppConfig.MP4);

            //如果沒有要創建
            BitmapUtils.makeDir(file);

            //初始化一個MediaRecorder
            if (mediaRecorder == null) {
                mediaRecorder = new MediaRecorder();
            } else {
                mediaRecorder.reset();
            }

            mCamera.unlock();
            mediaRecorder.setCamera(mCamera);
            //設置視頻輸出的方向 很多設備在播放的時候需要設個參數 這算是一個文件屬性
            mediaRecorder.setOrientationHint(recorderRotation);

            //視頻源類型
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            mediaRecorder.setAudioChannels(2);
            // 設置視頻圖像的錄入源
            // 設置錄入媒體的輸出格式
//            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            // 設置音頻的編碼格式
//            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            // 設置視頻的編碼格式
//            mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);

            if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
                profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
            } /*else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
                profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
            } */ else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) {
                profile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
            } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH)) {
                profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
            } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_LOW)) {
                profile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW);
            }

            if (profile != null) {
                profile.audioCodec = MediaRecorder.AudioEncoder.AAC;
                profile.audioChannels = 1;
                profile.audioSampleRate = 16000;

                profile.videoCodec = MediaRecorder.VideoEncoder.H264;
                mediaRecorder.setProfile(profile);
            }

            //視頻尺寸
            mediaRecorder.setVideoSize(video_width, video_height);

            //數值越大 視頻質量越高
            mediaRecorder.setVideoEncodingBitRate(5 * 1024 * 1024);

            // 設置視頻的采樣率,每秒幀數
//            mediaRecorder.setVideoFrameRate(5);

            // 設置錄制視頻文件的輸出路徑
            mediaRecorder.setOutputFile(file.getAbsolutePath());
            mediaRecorder.setMaxDuration(2000);

            // 設置捕獲視頻圖像的預覽界面
            mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());

            mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {

                @Override
                public void onError(MediaRecorder mr, int what, int extra) {
                    // 發生錯誤,停止錄制
                    if (mediaRecorder != null) {
                        mediaRecorder.stop();
                        mediaRecorder.release();
                        mediaRecorder = null;
                        LogUtils.i("Error");
                    }
                }
            });

            mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
                @Override
                public void onInfo(MediaRecorder mr, int what, int extra) {
                    //錄制完成
                }
            });

            // 准備、開始
            mediaRecorder.prepare();
            mediaRecorder.start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < PROGRESS_MAX; i++) {
                        try {
                            Thread.currentThread().sleep(20);

                            Message message = new Message();
                            message.what = 1;
                            message.obj = i;
                            handler.sendMessage(message);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

4. 錄制成功後接下來的重點來了

使用 ffmpeg 對視頻進行裁剪正方形, ffmpeg 使用Shell命令的方式進行視頻操作, 執行效率也是非常好, 那首先你要集成FFmpeg 到Android 項目裡面, 這裡我下載好了一個library, 直接引入到項目即可, 感興趣的伙伴可以自己編譯一個庫, 這裡我把命令貼出來解釋一下,

ffmpeg -threads 4 -y -i /storage/emulated/0/CustomCamera/temp/1476598263062.mp4 -metadata:s:v rotate="0" -vf transpose=1, crop=width:height:x:y -preset ultrafast -tune zerolatency -r 25 -vcodec libx264 -acodec copy /storage/emulated/0/CustomCamera/VIDEO/1476598263062.mp4

-y: 如果文件存在那麼覆蓋掉

-i: 輸入

metadata:s:v rotate=”0” : 重新編碼 除去rotate, 因為默認錄制出來的是橫屏視頻, 這裡重新編碼

transpose=1 :
0 = 90CounterCLockwise and Vertical Flip (default) 逆時針旋轉90度並且垂直翻轉, 下面類推
1 = 90Clockwise
2 = 90CounterClockwise
3 = 90Clockwise and Vertical Flip

crop=width:height:x:y,其中 width 和 height 表示裁剪後的尺寸,x:y 表示裁剪區域的左上角坐標

-preset ultrafast -tune zerolatency: 加快效率

r 25:幀率

-vcodec libx264 -acodec: 編碼方式libx264
如果想知道更多關於ffmpeg的東西可以訪問官網 https://ffmpeg.org/

再貼一下我的代碼調用:

try {
                    fc.compress_clipVideo(file.getAbsolutePath(),
                            file2.getAbsolutePath(), mCameraId, video_width, video_height, 0, 0,
                            new ShellUtils.ShellCallback() {

                                @Override
                                public void shellOut(String shellLine) {
                                }

                                @Override
                                public void processComplete(int exitValue) {
                                    dialog.dismiss();
                                    if (exitValue != 0) {
                                        ToastFactory.showLongToast(context, getResources().getString(R.string.state_compress_error));
                                        mHandler.sendEmptyMessage(R.string.state_compress_error);
                                    } else {
                                        mHandler.sendEmptyMessage(R.string.state_compress_end);
                                    }
                                }
                            });

                } catch (Exception e) {
                    e.printStackTrace();
                }

FFmpeg編譯出來的Android 庫還是很大的, 大約15M左右, 無疑增加了apk的大小, 如果你的產品方向是視頻圖片gif等等的格式轉換類似的功能可以考慮使用

如果你對這樣的功能感興趣可以詳細查看源碼:

github 地址

https://github.com/jinguangyue/Android-CustomCamera

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved