Android ビデオを録画するサンプルコード

Android
Android ビデオ録画機能を作る

Android ビデオを録画するサンプルコード

Androidでビデオをキャプチャするサンプルコードです。Intentとかで他のビデオアプリを使う簡単実装ではなく、ビデオアプリ自体をつくるやつです。
別に新しい話でもないし、気楽にできるかと思っていたらかなり時間がかかりましたので、ここにとりあえず出た結論を書いておきます。

「Androidのカメラは鬼門だ」と聞いてはいましたが、本当に、プレビューの画面が縦横が逆になったり、縦横比がおかしくなったり、録画した画像が縦横逆だったり、しょっちゅう落ちたり、と問題が多かったです。

ちなみに、GoogleのAndroidのサンプルコードが昔はあったらしいのですが、Android5(Lollipop)への対応だけのやつしか書いてない…。

それがコレ↓
http://developer.android.com/samples/Camera2Video/index.html

古いメソッドは、Deprecateされてしまっているので、注意が必要ですが、Android5だけに対応すればいい世の中って、2年は先だなぁ(現在2015年3月26日)…

で、色々とはまった結果、色々なサイトの参考情報を集結してこのようになりました。

このサンプルコードはビルドダーゲット4.3.1(APIレベル18)、最低対応バージョンが3.0(APIレベル11)です。

確認機種はGalaxy S3a(Android4.3), Experia SO-04D(Android4.1.2)です。

 
 //VideoAvtivity.java
 public class VideoActivity extends Activity implements SurfaceHolder.Callback{
    private SurfaceHolder surfaceHolder;
    private SurfaceView surfaceView;
    public MediaRecorder mrec = new MediaRecorder();
    //private Button stopRecording = null;
    File video;
    private Camera mCamera;
    private final static String TAG = "VideoActivity";
    
    private Context context;
    private Button startRecording;
    
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
                
        setContentView(R.layout.video);        
 
        context = this;
 
    }
 
    @Override
    public void onResume(){
        super.onResume();
        
        int numCams = Camera.getNumberOfCameras();
        if(numCams > 0){
            try{
                
                mCamera = Camera.open();
                surfaceView = (SurfaceView) findViewById(R.id.surface_camera);
                surfaceHolder = surfaceView.getHolder();
                surfaceHolder.addCallback(this);
 
            } catch (RuntimeException ex){
                Toast.makeText(context, "カメラがありません", Toast.LENGTH_LONG).show();
            }
        }
 
    }
    
 
    @Override
    protected void onPause() {
        if(mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        super.onPause();
    }
 
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        menu.add(0, 0, 0, "StartRecording");
        menu.add(0, 1, 0, "StopRecording");
        return super.onCreateOptionsMenu(menu);
    }
 
    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
       //この辺は若干適当なので利用する際はアレンジして頂きたいですが、
      //オプションのメニューアイテムで録画開始とストップをします。
        switch (item.getItemId())
        {
        case 0:
            try {
                startRecording();
            } catch (Exception e) {
                String message = e.getMessage();
                Log.i(null, "Problem Start"+message);
                mrec.release();
            }
            break;
 
        case 1: //GoToAllNotes
            
            mrec.stop();
            mrec.release();
            mrec = null;
            break;
 
        default:
            break;
        }
        return super.onOptionsItemSelected(item);
    }
 
    protected void startRecording() throws IOException 
    {
        mrec = new MediaRecorder();  // Works well
        mCamera.unlock();
 
        mrec.setCamera(mCamera);
 
        mrec.setPreviewDisplay(surfaceHolder.getSurface());
        mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mrec.setAudioSource(MediaRecorder.AudioSource.MIC); 
 
        //録画される画面の縦横を決める
        int degrees = getSurfaceDegrees();
        
        Camera.CameraInfo camInfo = new Camera.CameraInfo();
        int camera_id = findFrontFacingCameraID();
        Camera.getCameraInfo(camera_id, camInfo);
        
        int cameraRotationOffset = camInfo.orientation;
        int displayRotation = getDisplayRotation(camInfo, cameraRotationOffset, degrees);
        
        mrec.setOrientationHint(displayRotation);
        
        mrec.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
 
        Date date = new Date();
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        
        String file_name = sdf1.format(date)+".3gp";
        mrec.setOutputFile("/sdcard/"+file_name); 
 
        mrec.prepare();
        mrec.start();
    }
 
    protected void stopRecording() {
        mrec.stop();
        mrec.release();
    }
 
 
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {
        
        startPreview(holder);
    }
 
 
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        if (mCamera != null){
 
        } else {
            Toast.makeText(getApplicationContext(), "Camera not available!", Toast.LENGTH_LONG).show();
            finish();
        }
    }
 
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
 
        
    }
    
 
    public void startPreview(SurfaceHolder holder) {
        try {
            Log.i(TAG, "starting preview");
 
            Camera.CameraInfo camInfo = new Camera.CameraInfo();
            Camera.Parameters params = mCamera.getParameters();
            int camera_id = findFrontFacingCameraID();
            Camera.getCameraInfo(camera_id, camInfo);
            int cameraRotationOffset = camInfo.orientation;
 
            Camera.Parameters parameters = mCamera.getParameters();
            List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
            Camera.Size previewSize = null;
            float closestRatio = Float.MAX_VALUE;
 
            int targetPreviewWidth = isLandscape() ? getWidth() : getHeight();
            int targetPreviewHeight = isLandscape() ? getHeight() : getWidth();
            float targetRatio = targetPreviewWidth / (float) targetPreviewHeight;
 
            Log.v(TAG, "target size: " + targetPreviewWidth + " / " + targetPreviewHeight + " ratio:" + targetRatio);
            
            for (Camera.Size candidateSize : previewSizes) {
                float whRatio = candidateSize.width / (float) candidateSize.height;
                if (previewSize == null || Math.abs(targetRatio - whRatio) < Math.abs(targetRatio - closestRatio)) {
                    closestRatio = whRatio;
                    previewSize = candidateSize;
                }
            }
 
            
            int degrees = getSurfaceDegrees();
            
            
            int displayRotation = getDisplayRotation(camInfo, cameraRotationOffset, degrees);
 
            Log.d(TAG, "displayRotation:" + displayRotation);
 
            mCamera.setDisplayOrientation(displayRotation);
 
            int rotate = getRotation(camInfo, cameraRotationOffset, degrees);
            
            Log.v(TAG, "rotate: " + rotate); 
 
            Log.v(TAG, "preview size: " + previewSize.width + " / " + previewSize.height);
            parameters.setPreviewSize(previewSize.width, previewSize.height);
            parameters.setRotation(rotate);
 
            mCamera.setParameters(parameters);
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
 
            Log.d(TAG, "preview started");
 
 
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }
    
    private boolean isFrontFacingCam(Camera.CameraInfo camInfo){
        
        boolean isFrontFacingCam;
        
        if(camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
            isFrontFacingCam = true;
        }else{
            isFrontFacingCam = false;
        }
        
        return isFrontFacingCam;
    }
    
    private int getWidth(){
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
 
        int width = displayMetrics.widthPixels;
        
        return width;
    }
 
    private int getHeight(){
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
 
        int height = displayMetrics.heightPixels;
        
        return height;
    }
    
    private boolean isLandscape(){
        if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
            return true;
        }else{
            return false;
        }
    }
 
    private int getSurfaceDegrees(){
        
        int rotation = getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        
        switch (rotation) {
            case Surface.ROTATION_0:
                degrees = 0;
                break; // Natural orientation
            case Surface.ROTATION_90:
                degrees = 90;
                break; // Landscape left
            case Surface.ROTATION_180:
                degrees = 180;
                break;// Upside down
            case Surface.ROTATION_270:
                degrees = 270;
                break;// Landscape right
        }
        return degrees;
    }
    
    private int getRotation(Camera.CameraInfo camInfo, int cameraRotationOffset, int degrees){
        int rotate;
        if (isFrontFacingCam(camInfo)) {
            rotate = (360 + cameraRotationOffset + degrees) % 360;
        } else {
            rotate = (360 + cameraRotationOffset - degrees) % 360;
        }
        return rotate;
    }
    
    private int getDisplayRotation(Camera.CameraInfo camInfo, int cameraRotationOffset, int degrees){
        int displayRotation;
        if (isFrontFacingCam(camInfo)) {
            
            displayRotation = (cameraRotationOffset + degrees) % 360;
            displayRotation = (360 - displayRotation) % 360; 
            
        } else { // back-facing
            
            displayRotation = (cameraRotationOffset - degrees + 360) % 360;
        }
        return displayRotation;
    }
    
    private int findFrontFacingCameraID() {
          int cameraId = -1;
          // Search for the front facing camera
          int numberOfCameras = Camera.getNumberOfCameras();
          for (int i = 0; i < numberOfCameras; i++) {
            CameraInfo info = new CameraInfo();
            Camera.getCameraInfo(i, info);
            if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
              Log.d(TAG, "Camera found");
              cameraId = i;
              break;
            }
          }
          return cameraId;
       }
 
    
 }
 //video.xml
 <?xml version="1.0" encoding="UTF-8"?>
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical" >
 
 <SurfaceView
    android:id="@+id/surface_camera"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1" />
 
 />
 
 </RelativeLayout>

参考にしたサイト
http://stackoverflow.com/questions/22105251/android-mediarecorder-aspect-ratio-incorrect

他stackoverflowさん様様です。

Androidでビデオ録画機能を作る時に気をつけたいこと

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です