Android多媒體之Camera的相關操做

零、前言

今天主要有兩點

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

權限申請自行解決

<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"/>git


1、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();//釋放資源
    }
}
複製代碼

2、界面佈局:

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


2.下載圖標:iconfont+

下載圖標.png


3.仿製界面

這是我仿的佈局,具體怎麼佈局的,不是本篇的要點,本身看源碼吧。github

仿製界面


3、數據的捕獲

1.Camera類中的回調接口
1.1--PreviewCallback

經測試camera.startPreview();以後,PreviewCallback的onPreviewFrame方法會不斷回調
也就是說監聽這個方法就能夠得到連續的幀,這也是視頻數據的來源編程

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

1.2--ShutterCallback

拍照的那一刻回調bash

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

1.3--PictureCallback

拍照後回調--data即是圖片數據微信

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

1.4--AutoFocusCallback

自動聚焦監聽ide

@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先居中隱藏post

延遲拍照.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();
            }
        }
    });
}
複製代碼

3、其餘相關

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;
}
複製代碼

4、視頻數據的收集

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();
    }
}
複製代碼

5、視頻數據的收集: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/>
 * 郵箱:1981462002@qq.com<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的相關操做](https://www.jianshu.com/p/6db677f9dc9e)
2.更多關於我
筆名 QQ 微信 愛好
張風捷特烈 1981462002 zdl1994328 語言
個人github 個人簡書 個人掘金 我的網站
3.聲明

1----本文由張風捷特烈原創,轉載請註明
2----歡迎廣大編程愛好者共同交流
3----我的能力有限,若有不正之處歡迎你們批評指證,一定虛心改正
4----看到這裏,我在此感謝你的喜歡與支持


icon_wx_200.png
相關文章
相關標籤/搜索