1. 程式人生 > >Android多媒體之Camera的相關操作

Android多媒體之Camera的相關操作

零、前言

今天主要有兩點

1).介面佈局,檢視仿一下我手機自帶的相機
2).Camera的簡單使用,雖然Camera已經過時了,但還是來看一下,由簡入深
下一篇會介紹替代者:Camera2 溫馨提示:本文多圖預警,請Wifi觀看~

許可權申請自行解決

<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>


<uses-permission android:name="android.permission.RECORD_AUDIO"/>


一、SurfaceView與Camera

1.View繪製原理及普通View侷限性
View通過重新整理重繪檢視,Android系統通過發出VSYNC訊號進行螢幕的重繪,重新整理的間隔時間為16ms。
如果16ms內View完成需要執行的所有操作,在視覺上,不會產生卡頓的感覺;反之卡頓。
特別的需要頻繁重新整理的介面上,如遊戲(60FPS以上),就會不斷阻塞主執行緒,從而導致介面卡頓。
複製程式碼
比較 重新整理 重新整理時執行緒 雙緩衝
普通View 主動 僅主執行緒
SurfaceView 被動 允許子執行緒
SurfaceView相當於是另一個繪圖執行緒,它是不會阻礙主執行緒,並且它在底層實現機制中實現了雙緩衝機制
一個View需要頻繁的重新整理,或者在重新整理時資料處理量大(可能引起卡頓),可以考慮使用SurfaceView來替代。
很明顯相機隨時捕捉畫面,需要頻繁的重新整理,使用SurfaceView比較好
複製程式碼

2.佈局-整個SurfaceView
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".CameraActivity">

    <SurfaceView
        android:id="@+id/id_sv_video"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</android.support.constraint.ConstraintLayout>
複製程式碼

3.SurfaceView和Camera的使用
public class CameraActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    @BindView(R.id.id_sv_video)
    SurfaceView mIdSvVideo;
    private Camera camera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        mIdSvVideo.getHolder().addCallback(this);

        // 開啟攝像頭並將展示方向旋轉90度
        camera = Camera.open();
        camera.setDisplayOrientation(90);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            camera.setPreviewDisplay(holder);//Camera+SurfaceHolder
            camera.startPreview();//開啟預覽
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.release();//釋放資源
    }
}
複製程式碼

二、介面佈局:

1.這是手機自帶的Camera佈局


2.下載圖示:iconfont+

下載圖示.png


3.仿製介面

這是我仿的佈局,具體怎麼佈局的,不是本篇的要點,自己看原始碼吧。

仿製介面


三、資料的捕獲

1.Camera類中的回撥介面
1.1--PreviewCallback

經測試camera.startPreview();之後,PreviewCallback的onPreviewFrame方法會不斷回撥
也就是說監聽這個方法就可以獲得連續的幀,這也是視訊資料的來源

public interface PreviewCallback{
    void onPreviewFrame(byte[] data, Camera camera);
};
複製程式碼

1.2--ShutterCallback

拍照的那一刻回撥

 @Deprecated
 public interface ShutterCallback{
    void onShutter();
 }
複製程式碼

1.3--PictureCallback

拍照後回撥--data便是圖片資料

@Deprecated
public interface PictureCallback {
    void onPictureTaken(byte[] data, Camera camera);
};
複製程式碼

1.4--AutoFocusCallback

自動聚焦監聽

@Deprecated
public interface AutoFocusCallback{
    void onAutoFocus(boolean success, Camera camera);
}
複製程式碼

2.常用方法
2.1.拍照方法:takePicture
Camera open() 開啟一個Camera(生成物件)
void startPreview() 開啟預覽
void stopPreview() 關閉預覽
void release() 釋放資源
void autoFocus(AutoFocusCallback cb) 自動聚焦
複製程式碼
2.1.拍照方法:takePicture
---->[四參的:takePicture]-------------

 * @param shutter   拍照瞬間回撥
 * @param raw       回撥未壓縮的原始資料
 * @param postview  回撥與postview影象資料
 * @param jpeg      回撥JPEG圖片資料
 */
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
        PictureCallback postview, PictureCallback jpeg) {
      
 ---->[三參的:takePicture,第三參null]-------------       
public final void takePicture(ShutterCallback shutter, PictureCallback raw,
        PictureCallback jpeg) {
    takePicture(shutter, raw, null, jpeg);
}
複製程式碼

4.拍照的功能實現

拍完照要camera.startPreview();再開啟預覽, 否則介面就不動了
這裡測試拍照的檔名寫死了(避免拍太多測試照片...),你可以用當前時間當檔名

hello.jpg

mIdIvSnap.setOnClickListener(v->{
    camera.takePicture(new Camera.ShutterCallback() {
        @Override
        public void onShutter() {
        }
    }, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
        }
    }, new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
             File pic = FileHelper.get().createFile("pic/hello.jpg");
             FileOutputStream fos = null;
             try {
                 fos = new FileOutputStream(pic);
                 fos.write(data);
                 fos.flush();
                 fos.close();
                 camera.startPreview();
             } catch (IOException e) {
                 e.printStackTrace();
                 try {
                     assert fos != null;
                     fos.close();
                 } catch (IOException e1) {
                     e1.printStackTrace();
                 }
             }
    });
});
複製程式碼

5.延遲拍照

思路很簡單,就是用Handler傳送延遲訊息,將一個TextView先居中隱藏

延遲拍照.gif


5.1:延遲按鈕的點選效果

選中時拍照延遲3s(此處簡單地寫死,當然你也可以暴漏設定方法)

延遲按鈕點選.gif

private boolean isDelay = false;//是否延遲

mIdIvDelay.setOnClickListener(v -> {
    if (!isDelay) {
        mIdIvDelay.setImageTintList(ColorStateList.valueOf(0xffEFB90F));
    } else {
        mIdIvDelay.setImageTintList(ColorStateList.valueOf(0xfffffffF));
    }
    isDelay = !isDelay;
});
複製程式碼

5.2:Handler傳送延遲訊息
private static final int DEFAULT_DELAY_COUNT = 3 + 1;//預設延遲時間3s
private int mCurDelayCount = DEFAULT_DELAY_COUNT;//當前倒計時時間

private Handler mHandler = new Handler() {//Handler
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        mIdTvCountDown.setText(mCurDelayCount + "");
    }
};


//點選拍照按鈕
mIdIvSnap.setOnClickListener(v -> {
    if (!isDelay) {//如果無延遲直接拍
        takePicture("pic/hello.jpg");
        return;
    }
    mIdTvCountDown.setVisibility(View.VISIBLE);
    mCurDelayCount = DEFAULT_DELAY_COUNT;
    mHandler.post(new Runnable() {
        @Override
        public void run() {
            if (mCurDelayCount > 0) {
                mCurDelayCount--;
                L.d(mCurDelayCount + L.l());
                mHandler.postDelayed(this, 1000);//延遲1s
                mHandler.sendEmptyMessage(0);//傳送訊息
            } else {
                takePicture("pic/hello.jpg");
                mIdTvCountDown.setVisibility(View.GONE);
            }
        }
    });
});

/**
 * 拍照方法封裝
 *
 * @param name 圖片名稱(加資料夾:形式如:pic/hello.jpg)
 */
private void takePicture(String name) {
    camera.takePicture(null, null, (data, camera) -> {
        File pic = FileHelper.get().createFile(name);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(pic);
            fos.write(data);
            fos.flush();
            fos.close();
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
            try {
                assert fos != null;
                fos.close();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    });
}
複製程式碼

三、其他相關

1.自動聚焦

點選SurfaceView自動聚焦(也就是變清楚)

//自動聚焦
mIdSvVideo.setOnClickListener(v -> {
    camera.autoFocus(new Camera.AutoFocusCallback() {
        @Override
        public void onAutoFocus(boolean success, Camera camera) {
        }
    });
});
複製程式碼

2.改變焦距(即放大縮小)

我預設給了10個等級,放到最大之後回到開始大小

變焦.gif

private int currZoom;//當前縮放數
mParameters = camera.getParameters();//相機引數

/**
 * 縮放封裝
 */
public void setZoom() {
    if (mParameters.isZoomSupported()) {//是否支援縮放
        try {
            Camera.Parameters params = mParameters;
            final int maxZoom = params.getMaxZoom();
            if (maxZoom == 0) return;
            currZoom = params.getZoom();
            currZoom += maxZoom / 10;
            if (currZoom > maxZoom) {
                currZoom = 0;
            }
            params.setZoom(currZoom);
            camera.setParameters(params);
            String rate = new DecimalFormat("#.0").format(currZoom / (maxZoom / 10 * 2.f) + 1);
            mIdIvZoom.setText(rate + "x");
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        ToastUtil.show(this, "您的手機不支援變焦功能!");
    }
}
複製程式碼

3.打燈

打燈.gif

private boolean isFlashLight;//是否開啟閃光燈

//開閃光燈
mIdIvSplash.setOnClickListener(v -> {
    if (!isFlashLight) {
        mIdIvSplash.setImageTintList(ColorStateList.valueOf(0xffEFB90F));
    } else {
        mIdIvSplash.setImageTintList(ColorStateList.valueOf(0xfffffffF));
    }
    isFlashLight = !isFlashLight;
    mParameters.setFlashMode(
            isFlashLight?Camera.Parameters.FLASH_MODE_TORCH:Camera.Parameters.FLASH_MODE_OFF);
    camera.setParameters(mParameters);
});
複製程式碼

3.切換鏡頭

好吧,哥露臉了...

切換鏡頭.gif

//切換鏡頭
mIdIvSwitch.setOnClickListener(v -> {
    if (!isBack) {
        mIdIvSwitch.setImageTintList(ColorStateList.valueOf(0xffEFB90F));
    } else {
        mIdIvSwitch.setImageTintList(ColorStateList.valueOf(0xfffffffF));
    }
    changeCamera(isBack ? BACK : FRONT);
    isBack = !isBack;
});

private void changeCamera(int type) {
    camera.stopPreview();
    camera.release();
    camera = openCamera(type);
    try {
        camera.setPreviewDisplay(mHolder);
        camera.setDisplayOrientation(90);//並將展示方向旋轉90度--水平-->豎直
    } catch (IOException e) {
        e.printStackTrace();
    }
    camera.startPreview();
}

private Camera openCamera(int type) {
    int frontIndex = -1;
    int backIndex = -1;
    int cameraCount = Camera.getNumberOfCameras();
    Camera.CameraInfo info = new Camera.CameraInfo();
    for (int cameraIndex = 0; cameraIndex < cameraCount; cameraIndex++) {
        Camera.getCameraInfo(cameraIndex, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            frontIndex = cameraIndex;
        } else if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            backIndex = cameraIndex;
        }
    }
    if (type == FRONT && frontIndex != -1) {
        return Camera.open(frontIndex);
    } else if (type == BACK && backIndex != -1) {
        return Camera.open(backIndex);
    }
    return null;
}
複製程式碼

四、視訊資料的收集

Android 中Google支援的 PreviewCallback.onPreviewFrame的YUV常用格式有兩種:
一個是NV21,一個是YV12。Android一般預設使用YCbCr_420_SP的格式(NV21)。

1.實現介面效果

拍照和錄影的切換,視訊下:變紅(偶數次點選)時開始錄影,變藍(奇數次點選)停止

未命名專案.gif

private boolean isPhoto = true;//是否是拍照
private boolean isRecoding;//是否在錄影
private int clickRecordCount = 0;//錄屏時的點選錄屏次數

//切換到錄製
mIdTvVideo.setOnClickListener(v -> {
    mIdTvVideo.setTextColor(0xffEFB90F);
    mIdTvPic.setTextColor(0xfffffffF);
    mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xff0FC2EF));
    isPhoto = false;
});

//切換到拍照
mIdTvPic.setOnClickListener(v -> {
    mIdTvVideo.setTextColor(0xfffffffF);
    mIdIvSnap.setImageTintList(ColorStateList.valueOf(0x88ffffff));
    mIdTvPic.setTextColor(0xffEFB90F);
    isPhoto = true;
});

//開始按鈕
mIdIvSnap.setOnClickListener(v -> {
    if (isPhoto) {
        takePhoto();//照相
    } else {
        if (clickRecordCount % 2 == 0) {
            recodeVideo();//錄製
        } else {
            stopRecodeVideo();//停止錄製
        }
    }
    clickRecordCount++;
});

/**
 * 錄影
 */
private void recodeVideo() {
    isRecoding = true;
    mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xffff0000));
    camera.startPreview();
}
/**
 * 停止錄影
 */
private void stopRecodeVideo() {
    isRecoding = false;
    mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xff0FC2EF));
}

//視訊錄影
camera.setPreviewCallback((data, camera) -> {
            if (isRecoding) {
                L.d("onPreviewFrame--" + Thread.currentThread().getName() + L.l());
                //TODO 收集資料
            }
        }
);
複製程式碼

2.關於資料的尺寸

拍張照都2M多,錄影還得了?隨便設了兩個尺寸沒效果...
Camera支援的尺寸是固定的哪幾種...

mParameters.setPictureSize(720, 480);//設定圖片尺寸
mParameters.setPreviewSize(720, 480);//設定預覽尺寸
複製程式碼

//檢視支援的尺寸
List<Camera.Size> pictureSizes = camera.getParameters().getSupportedPictureSizes();
List<Camera.Size> previewSizes = camera.getParameters().getSupportedPreviewSizes();
for (int i = 0; i < pictureSizes.size(); i++) {
    Camera.Size pSize = pictureSizes.get(i);
    L.d("PictureSize.width = " + pSize.width + "--------PictureSize.height = " + pSize.height);
}
for (int i = 0; i < previewSizes.size(); i++) {
    Camera.Size pSize = previewSizes.get(i);
    L.d("previewSize.width = " + pSize.width + "-------previewSize.height = " + pSize.height);
}


PictureSize.width = 5184--------PictureSize.height = 3880
PictureSize.width = 4608--------PictureSize.height = 3456
PictureSize.width = 4608--------PictureSize.height = 2592
PictureSize.width = 4608--------PictureSize.height = 2304
PictureSize.width = 4608--------PictureSize.height = 2176
PictureSize.width = 4608--------PictureSize.height = 2126
PictureSize.width = 4160--------PictureSize.height = 3120
PictureSize.width = 4160--------PictureSize.height = 2340
PictureSize.width = 4000--------PictureSize.height = 3000
PictureSize.width = 3840--------PictureSize.height = 2160
PictureSize.width = 3264--------PictureSize.height = 2448
PictureSize.width = 3264--------PictureSize.height = 1632
PictureSize.width = 3264--------PictureSize.height = 1552
PictureSize.width = 3264--------PictureSize.height = 1504
PictureSize.width = 3200--------PictureSize.height = 2400
PictureSize.width = 2592--------PictureSize.height = 1944
PictureSize.width = 2592--------PictureSize.height = 1940
PictureSize.width = 2592--------PictureSize.height = 1296
PictureSize.width = 2592--------PictureSize.height = 1232
PictureSize.width = 2592--------PictureSize.height = 1458
PictureSize.width = 2560--------PictureSize.height = 1920
PictureSize.width = 2688--------PictureSize.height = 1512
PictureSize.width = 2304--------PictureSize.height = 1728
PictureSize.width = 2304--------PictureSize.height = 1296
PictureSize.width = 2048--------PictureSize.height = 1536
PictureSize.width = 1920--------PictureSize.height = 1080
PictureSize.width = 1840--------PictureSize.height = 1380
PictureSize.width = 1600--------PictureSize.height = 1200
PictureSize.width = 1600--------PictureSize.height = 900
PictureSize.width = 1440--------PictureSize.height = 1080
PictureSize.width = 1280--------PictureSize.height = 960
PictureSize.width = 1280--------PictureSize.height = 768
PictureSize.width = 1280--------PictureSize.height = 720
PictureSize.width = 1024--------PictureSize.height = 768
PictureSize.width = 800--------PictureSize.height = 600
PictureSize.width = 800--------PictureSize.height = 480
PictureSize.width = 720--------PictureSize.height = 480
PictureSize.width = 640--------PictureSize.height = 480
PictureSize.width = 352--------PictureSize.height = 288
PictureSize.width = 320--------PictureSize.height = 240
PictureSize.width = 176--------PictureSize.height = 144


previewSize.width = 2160-------previewSize.height = 1080
previewSize.width = 1920-------previewSize.height = 1080
previewSize.width = 1600-------previewSize.height = 900
previewSize.width = 1520-------previewSize.height = 720
previewSize.width = 1440-------previewSize.height = 1080
previewSize.width = 1280-------previewSize.height = 960
previewSize.width = 1280-------previewSize.height = 720
previewSize.width = 960-------previewSize.height = 720
previewSize.width = 720-------previewSize.height = 480
previewSize.width = 640-------previewSize.height = 480
previewSize.width = 352-------previewSize.height = 288
previewSize.width = 320-------previewSize.height = 240
previewSize.width = 176-------previewSize.height = 144
複製程式碼

3.視訊資料的收集

獲取的資料暫時還無法解析,先留著吧

錄製.png

//視訊錄影
camera.setPreviewCallback((data, camera) -> {
            if (isRecoding) {
                collectData(data);
            }
        }
);

 /**
  * 收集資料
  *
  * @param data
  */
 private void collectData(byte[] data) {
     try {
         mFosVideo.write(data);
     } catch (IOException e) {
         e.printStackTrace();
     }
 }
 
/**
 * 錄影時生成流mFosVideo
 */
private void recodeVideo() {
    isRecoding = true;
    File videoFile = FileHelper.get().createFile("video/hello");
    try {
        mFosVideo = new FileOutputStream(videoFile);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }
    
    mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xffff0000));
    camera.startPreview();
}

/**
 * 停止錄影關閉流
 */
private void stopRecodeVideo() {
    isRecoding = false;
    mIdIvSnap.setImageTintList(ColorStateList.valueOf(0xff0FC2EF));
    try {
        mFosVideo.flush();
        mFosVideo.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
複製程式碼

五、視訊資料的收集:Camera+MediaRecorder

MediaRecorder不止能錄音頻,結合Camera還能錄視訊

視訊錄製.png


1.支援的視訊尺寸也是有限制的
videoSize.width = 2160-------videoSize.height = 1080
videoSize.width = 1920-------videoSize.height = 1080
videoSize.width = 1280-------videoSize.height = 960
videoSize.width = 1440-------videoSize.height = 720
videoSize.width = 1280-------videoSize.height = 720
videoSize.width = 864-------videoSize.height = 480
videoSize.width = 800-------videoSize.height = 480
videoSize.width = 720-------videoSize.height = 480
videoSize.width = 640-------videoSize.height = 480
videoSize.width = 352-------videoSize.height = 288
videoSize.width = 320-------videoSize.height = 240
videoSize.width = 176-------videoSize.height = 144
複製程式碼

視訊錄製輔助類
/**
 * 作者:張風捷特烈<br/>
 * 時間:2019/1/8 0008:16:29<br/>
 * 郵箱:[email protected]<br/>
 * 說明:視訊錄製輔助類
 */
public class VideoRecorderUtils {
    private MediaRecorder mediaRecorder;
    private Camera camera;
    private SurfaceHolder.Callback callback;
    private SurfaceView surfaceView;
    private int height, width;
    public static Point WH_2160X1080 = new Point(2160, 1080);
    public static Point WH_1920X1080 = new Point(1920, 1080);
    public static Point WH_1280X960 = new Point(1280, 960);
    public static Point WH_1440X720 = new Point(1440, 720);
    public static Point WH_1280X720 = new Point(1280, 720);
    public static Point WH_864X480 = new Point(864, 480);
    public static Point WH_800X480 = new Point(800, 480);
    public static Point WH_720X480 = new Point(720, 480);
    public static Point WH_640X480 = new Point(640, 480);
    public static Point WH_352X288 = new Point(352, 288);
    public static Point WH_320X240 = new Point(320, 240);
    public static Point WH_176X144 = new Point(176, 144);
    public void create(SurfaceView surfaceView,Point point) {
        this.surfaceView = surfaceView;
        surfaceView.setKeepScreenOn(true);
        callback = new SurfaceHolder.Callback() {
            public void surfaceCreated(SurfaceHolder holder) {
                camera = Camera.open();
                width = point.x;
                height = point.y;
                mediaRecorder = new MediaRecorder();
            }
            public void surfaceChanged(SurfaceHolder holder, int format,
                                       int width, int height) {
                doChange(holder);
            }
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (camera != null) {
                    camera.release();
                    camera = null;
                }
            }
        };
        surfaceView.getHolder().addCallback(callback);
    }
    private void doChange(SurfaceHolder holder) {
        try {
            camera.setPreviewDisplay(holder);
            camera.setDisplayOrientation(90);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public void stopRecord() {
        mediaRecorder.release();
        camera.release();
        mediaRecorder = null;
        camera = Camera.open();
        mediaRecorder = new MediaRecorder();
        doChange(surfaceView.getHolder());
    }
    public void stop() {
        if (mediaRecorder != null && camera != null) {
            mediaRecorder.release();
            camera.release();
        }
    }
    public void destroy() {
        if (mediaRecorder != null && camera != null) {
            mediaRecorder.release();
            camera.release();
            mediaRecorder = null;
            camera = null;
        }
    }
    /**
     * @param path 儲存的路徑
     * @param name 錄影視訊名稱(不包含字尾)
     */
    public void startRecord(String path, String name) {
        camera.unlock();
        mediaRecorder.setCamera(camera);
        mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
        mediaRecorder.setVideoEncodingBitRate(700 * 1024);
        mediaRecorder.setVideoSize(width, height);
        mediaRecorder.setVideoFrameRate(24);
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
        mediaRecorder.setOutputFile(path + File.separator + name + ".mp4");
        File file1 = new File(path + File.separator + name + ".mp4");
        if (file1.exists()) {
            file1.delete();
        }
        mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface()
        mediaRecorder.setOrientationHint(0);
        try {
            mediaRecorder.prepare();
            mediaRecorder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
複製程式碼

3.輔助類的使用

避免看起來雜亂,新建了一個Activity類 使用的核心方法:

private boolean isRecording;

mVideoRecorderUtils = new VideoRecorderUtils();
mVideoRecorderUtils.create(mIdSvVideo, VideoRecorderUtils.WH_720X480);
path = Environment.getExternalStorageDirectory().getAbsolutePath();
mIdIvSnap.setOnClickListener(view -> {
    if (!isRecording) {
        mVideoRecorderUtils.startRecord(path, "Video");
    } else {
        mVideoRecorderUtils.stopRecord();
    }
    isRecording = !isRecording;
});
複製程式碼

OK,就這樣,還有寫Camera的特效,等以後把圖片知識弄好,再說吧


後記:捷文規範

1.本文成長記錄及勘誤表
專案原始碼 日期 備註
V0.1-github 2018-1-8 Android多媒體之Camera的相關操作](www.jianshu.com/p/6db677f9d…)
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
我的github 我的簡書 我的掘金 個人網站
3.宣告

1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大程式設計愛好者共同交流
3----個人能力有限,如有不正之處歡迎大家批評指證,必定虛心改正
4----看到這裡,我在此感謝你的喜歡與支援


icon_wx_200.png