0

I have to solve a problem with android hardware camera. I want my device always record landscape video even when its orientation is vertical. I'd drawn some pics to support my issue:

This is what I get: http://joxi.ru/9IHbU_3JTJDrRyVH-XA

This is what I want: http://joxi.ru/IYLbU4wyTJC1LhQcd4Q

I can't say is it even possible (I think it's not, because of hardware matrix can't rotate). But my client thinks it is. Please, judge us.

Update: there's my code.

//..import...
public class MainActivity extends Activity {

SurfaceView surfaceView;
Camera camera;
MediaRecorder mediaRecorder;
//...public and private variables...

@Override
protected void onCreate(Bundle savedInstanceState) {
//......
    SurfaceHolder holder = surfaceView.getHolder();
    holder.addCallback(new SurfaceHolder.Callback() {
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
            try {
                 camera.setPreviewDisplay(holder);
                 setCameraDisplayOrientation(CAM_ID);

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

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

        @Override
         public void surfaceDestroyed(SurfaceHolder holder) {
         }
    });
}

@Override
protected void onResume() {
    super.onResume();
    camera = Camera.open(this.CAM_ID);
 }

@Override
protected void onPause() {
    super.onPause();
    releaseMediaRecorder();
    if (camera != null)
        camera.release();
    camera = null;
}

public void setListeners() {/*....*/}
public void onClickStartRecord(View view) {
    if (prepareVideoRecorder()) {
        mediaRecorder.start();
    } else releaseMediaRecorder();
}

public void onClickStopRecord(View view) {
    if (mediaRecorder != null) {
        mediaRecorder.stop();
        releaseMediaRecorder();
    }
}

private boolean prepareVideoRecorder() {

    camera.unlock();

    mediaRecorder = new MediaRecorder();

    mediaRecorder.setCamera(camera);
    mediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT);
    mediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);

    CamcorderProfile profile = CamcorderProfile.get(this.CAM_ID, CamcorderProfile.QUALITY_LOW);
    mediaRecorder.setProfile(profile);
    if(this.orientation == 270 || this.orientation == 90 )
        mediaRecorder.setOrientationHint(90);

    mediaRecorder.setOutputFile(videoFile.getAbsolutePath());
    mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());

    try {
        mediaRecorder.prepare();
    } catch (Exception e) {
        e.printStackTrace();
        releaseMediaRecorder();
        return false;
    }
    return true;
}

private void releaseMediaRecorder() {
    if (mediaRecorder != null) {
        mediaRecorder.reset();
        mediaRecorder.release();
        mediaRecorder = null;
        camera.lock();
    }
}

private void setCameraDisplayOrientation(int cameraId) {
    // определяем насколько повернут экран от нормального положения
    int rotation = getWindowManager().getDefaultDisplay().getRotation();
    int degrees = 0;
    switch (rotation) {
    case Surface.ROTATION_0:
        degrees = 0;
        break;
    case Surface.ROTATION_90:
        degrees = 90;
        break;
    case Surface.ROTATION_180:
        degrees = 180;
        break;
    case Surface.ROTATION_270:
        degrees = 270;
        break;
    }

    int result = 0;

    CameraInfo info = new CameraInfo();
    Camera.getCameraInfo(cameraId, info);

    if (info.facing == CameraInfo.CAMERA_FACING_BACK) {
        result = ((360 - degrees) + info.orientation);
    } else
    if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
        result = ((360 - degrees) - info.orientation);
        result += 360;
    }
    result = result % 360;
    camera.setDisplayOrientation(result);

    this.orientation = result;
}

}
000
  • 26,951
  • 10
  • 71
  • 101
Nastya Kizza
  • 362
  • 3
  • 13
  • Duplicate of http://stackoverflow.com/questions/10994631/android-force-camera-to-take-photo-in-landscape-mode ? – Rob Aug 01 '14 at 12:10
  • have you started the cam via intent? – Opiatefuchs Aug 01 '14 at 12:11
  • SilentKiller, I'm afraid I don't have much to try. I can set video recording orientation with mediaRecorder.setOrientationHint and camera.setDisplayOrientation methods. But nothing of these solves my problem. I really think hardware won't allow to record landscape video when my devise is vertically oriented. But I have to ask :) – Nastya Kizza Aug 01 '14 at 12:16
  • Rob, I think it's not. All this topics are around video and photo orientation, but the matrix orientation is always similar to device (in my humble opinion). In other words, I can set portrait or landscape mode, but I can't record wide video when my device is vertical, I can record only narrow video. – Nastya Kizza Aug 01 '14 at 12:26
  • I´m not sure about it´s beeing not possible. Could You post some code? – Opiatefuchs Aug 01 '14 at 12:27
  • Opiatefuchs, sure. And I'm not using intent, it's android.hardware.camera – Nastya Kizza Aug 01 '14 at 12:29
  • @Rob, no it is not a duplicate of the linked Q. Here, we are not trying to configure the stock camera app via intents, but rather develop a _custom camera_. – Alex Cohn Aug 01 '14 at 21:18

1 Answers1

0

I believe it is pretty easy to achieve what your customer wants. So, you hold the device in Portrait mode, and you record video at resolution 1280x720. Obviously, it is portrait oriented: 720 is width, and 1280 is height (note that probably the encoded frames are still 1280 width and 720 height, but the video has a special rotation flag so that a compliant decoder will show the output at correct orientation).

Now, crop the video so that the result is 406x720 (yes, you loose a lot of pixels this way). But the result will have the desired landscape orientation. 406 is height, 720 is width.

Now to technical details: you can crop either live or after recording. In the latter case, you can run ffmpeg either on a server or on the device.

In the former case, you must receive the camera callbacks, crop the arriving data, and pass it to encoder. You can do it completely in Java, using the modern MediaCodec API. If you choose to write some native code, you can use ffmpeg libraries to perform the necessary operations.

You can even resize the resulting frames, such that video decoders will play the 406x720 originals at 1280x720 resolution. The quality will never be as the original (portrait) video.

Why I am speaking about the weird 406 height? To keep the standard aspect ratio. You may choose 540x720 if you can use 4:3 aspect ratio.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307