Camera Orientation with SurfaceView

0

I have a problem using SurfaceView for a custom camera on Android, I can not work the camera orientation with SurfaceView , no matter how I rotate the Smartphone it always behaves strangely, in the if I made two layouts for the two orientations, follow the image:

BeforepostingthecodeIwantedtoknowifthemostcorrectwaytoworkwithSurfaceViewisleavingitsorientationpermanent,beingPortraitorLandscapeasinthismanifest:android:screenOrientation="portrait" or leave free, in the example above it is with the free orientation.

Guidance code snippet

    public int onOrientationChanged() {

        int orientation = this.getWindowManager().getDefaultDisplay().getOrientation();

        android.hardware.Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();

        android.hardware.Camera.getCameraInfo(0, info);

        orientation = (orientation + 45) / 90 * 90;

        int rotation = 0;

        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            rotation = (info.orientation - orientation + 360) % 360;
        } else {  // back-facing camera
            rotation = (info.orientation + orientation) % 360;
        }
        return rotation;
    }

 @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //Abre a câmera
        try{
            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            //int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
            camera = Camera.open();

            Camera.Parameters parameters;
            parameters = camera.getParameters();
            parameters.setPreviewFrameRate(20);
            parameters.setPictureSize(size.x,size.y);
            int orientation = onOrientationChanged();
            parameters.setRotation(orientation);
            camera.setParameters(parameters);
            //camera.setDisplayOrientation(mOrientation);

        }catch (RuntimeException ex){
            Log.e("ERRO",ex.getMessage());
            Toast.makeText(this,"Ocorreu um erro com a câmera! ", Toast.LENGTH_SHORT);
        }

        try{
            //O SurfaceView tem sido criado, agora comunica-se com a câmera para desenhar o Preview.
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        }catch (Exception e){
            Log.e("ERRO",e.getMessage());
        }

    }

Complete Java code:

public class CameraApp extends FragmentActivity implements SurfaceHolder.Callback {

    private Camera camera = null;
    private int camId = 1;
    @InjectView(R.id.surfaceView)
    SurfaceView surfaceView;
    @InjectView(R.id.btn_take_photo)
    FloatingActionButton btn_take_photo;
    SurfaceHolder surfaceHolder;
    Camera.PictureCallback jpegCallback;
    Camera.ShutterCallback shutterCallback;
    private Context context = this;
    private Evento evento;
    private String dir;
    private OrientationEventListener mOrientationEventListener;
    private int mOrientation =  -1;
    private static final int ORIENTATION_PORTRAIT_NORMAL =  1;
    private static final int ORIENTATION_PORTRAIT_INVERTED =  2;
    private static final int ORIENTATION_LANDSCAPE_NORMAL =  3;
    private static final int ORIENTATION_LANDSCAPE_INVERTED =  4;

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

        evento = (Evento) getIntent().getSerializableExtra("item");
        dir = (String) getIntent().getSerializableExtra("item2");
        surfaceHolder = surfaceView.getHolder();

        //Instalamos uma surfaceHolder.Callback então nós notificamos quando o underlying surface é criado e destroido.
        surfaceHolder.addCallback(this);
        //Confirguração precaria, ,as requer um android versão rioritaria 3.0
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        btn_take_photo.setOnClickListener(new FloatingActionButton.OnClickListener() {
            @Override
            public void onClick(View view) {
                cameraImage();
            }
        });
        jpegCallback = new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] bytes, Camera camera) {
                FileOutputStream outputStream = null;
                File file_image = getDirc();
                if(!file_image.exists() && !file_image.mkdirs()){
                    Toast.makeText(getApplicationContext(),"Não pode criar diretorio para salvar imagem", Toast.LENGTH_SHORT).show();
                    return;
                }
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyymmddhhmmss");
                String date = simpleDateFormat.format(new Date());
                String photofile =  dir.trim().replace(" ", "").toLowerCase() + "_" + evento.getNomeDoEvento().trim().replace(" ", "").toLowerCase() + "_" + date.trim().replace(" ", "") + ".jpeg";
                String file_name = file_image.getAbsolutePath() + "/" + photofile;
                File picFile = new File(file_name);
                try{
                    outputStream = new FileOutputStream(picFile);
                    outputStream.write(bytes);
                    outputStream.close();

                }catch (FileNotFoundException e) {

                }catch (IOException ex){

                }finally {

                }
                Toast.makeText(getApplicationContext(),file_name, Toast.LENGTH_SHORT).show();
                refreshCamera();
                refreshGallery(picFile);
            }
        };
    }

    public int onOrientationChanged() {

        int orientation = this.getWindowManager().getDefaultDisplay().getOrientation();

        android.hardware.Camera.CameraInfo info =
                new android.hardware.Camera.CameraInfo();

        android.hardware.Camera.getCameraInfo(0, info);

        orientation = (orientation + 45) / 90 * 90;

        int rotation = 0;

        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            rotation = (info.orientation - orientation + 360) % 360;
        } else {  // back-facing camera
            rotation = (info.orientation + orientation) % 360;
        }
        return rotation;
    }

    public void refreshCamera(){
        if(surfaceHolder.getSurface() == null){
            //Preview surface não existe
            return;
        }
        //Para preview antes de fazer as mudanças
        try{
            camera.stopPreview();
        }catch (Exception e){

        }
        //Coloca no preview tamanho e faz alguma mudança de tamanho, rotação ou reformata as mudanças aqui,
        // inicia o preview com novas configurações.
        try{
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        }catch (Exception e){

        }
    }

    public void refreshGallery(File file){
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        intent.setData(Uri.fromFile(file));
        sendBroadcast(intent);
    }

    private File getDirc(){
        File dics = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "/Hashmidia/" + evento.getNomeDoEvento().trim().replace(" ", ""));
        return new File(dics,dir.trim().replace(" ", ""));
    }

    public void cameraImage(){
        //Tira a foto
        camera.takePicture(null,null,jpegCallback);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //Abre a câmera
        try{
            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            //int rotation = this.getWindowManager().getDefaultDisplay().getRotation();
            camera = Camera.open();

            Camera.Parameters parameters;
            parameters = camera.getParameters();
            parameters.setPreviewFrameRate(20);
            parameters.setPictureSize(size.x,size.y);
            int orientation = onOrientationChanged();
            parameters.setRotation(orientation);
            camera.setParameters(parameters);
            //camera.setDisplayOrientation(mOrientation);

        }catch (RuntimeException ex){
            Log.e("ERRO",ex.getMessage());
            Toast.makeText(this,"Ocorreu um erro com a câmera! ", Toast.LENGTH_SHORT);
        }

        try{
            //O SurfaceView tem sido criado, agora comunica-se com a câmera para desenhar o Preview.
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        }catch (Exception e){
            Log.e("ERRO",e.getMessage());
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        refreshCamera();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        //para preview w reinicia camera
        camera.stopPreview();
        camera.release();
        camera = null;
    }

    private int pixels(float cm){
        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        int width = size.x;
        int height = size.y;
        return width;
    }

    @Override
    public void onBackPressed() {
        //onBackPressed desabilitado
        startActivity(new Intent(context, Gerenciador.class).putExtra("item",evento));
    }
}

XML

<FrameLayout 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=".activity.CameraApp">

    <RelativeLayout
        android:id="@+id/btn_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <SurfaceView
            android:id="@+id/surfaceView"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" />

        <RelativeLayout
            android:id="@+id/layout_area2"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_alignParentTop="true"
            android:background="#000000FF">

            <ImageView
                android:id="@+id/image_flash"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:layout_margin="10dp"
                android:src="@android:drawable/ic_lock_idle_low_battery"/>

        </RelativeLayout>

        <RelativeLayout
            android:id="@+id/layout_area1"
            android:layout_width="match_parent"
            android:layout_height="100dp"
            android:layout_alignParentBottom="true"
            android:background="#000000FF">

            <com.melnykov.fab.FloatingActionButton
                android:id="@+id/btn_take_photo"
                android:layout_width="60dp"
                android:layout_height="60dp"
                android:layout_centerInParent="true"
                android:src="@drawable/fab_shadow"/>

            <ImageView
                android:id="@+id/image_galeria"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentRight="true"
                android:layout_centerVertical="true"
                android:layout_margin="10dp"
                android:src="@android:drawable/ic_menu_gallery"/>

            <ImageView
                android:id="@+id/image_moldura"
                android:layout_width="50dp"
                android:layout_height="50dp"
                android:layout_alignParentLeft="true"
                android:layout_centerVertical="true"
                android:layout_margin="10dp"
                android:src="@android:drawable/ic_dialog_dialer"/>

        </RelativeLayout>
    </RelativeLayout>
</FrameLayout>
    
asked by anonymous 04.08.2016 / 23:15

2 answers

1

Speak Vinithius,

Try to do the following just after this line:

camera = Camera.open();

Add this line:

camera.setDisplayOrientation(90);

See if it solves your problem.

Hugs.

    
05.08.2016 / 15:05
1

I was able to fix the rotation problem using a Basic Switch, with the help of Leonardo. I did the following in the surfaceCreated method:

@Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        //Abre a câmera
        try{
            Display display = getWindowManager().getDefaultDisplay();
            Point size = new Point();
            display.getSize(size);
            camera = Camera.open();
            Camera.Parameters parameters;
            parameters = camera.getParameters();
            int aux = display.getRotation();
            switch (aux){
                case 0:
                    camera.setDisplayOrientation(90);
                    parameters.setRotation(90);
                    //orientation = 90;
                        break;
                case 1:
                    camera.setDisplayOrientation(360);
                    parameters.setRotation(360);
                    //orientation = 360;
                    break;
                case 2:
                    camera.setDisplayOrientation(90);
                    parameters.setRotation(90);
                    //orientation = 90;
                    break;
                case 3:
                    camera.setDisplayOrientation(180);
                    parameters.setRotation(180);
                    //orientation = 180;
                    break;
            }
            parameters.setPreviewFrameRate(20);
            parameters.setPictureSize(size.x,size.y);
            parameters.setJpegQuality(100);
            camera.setParameters(parameters);

        }catch (RuntimeException ex){
            Log.e("ERRO",ex.getMessage());
            Toast.makeText(this,"Ocorreu um erro com a câmera! ", Toast.LENGTH_SHORT);
        }

        try{
            //O SurfaceView tem sido criado, agora comunica-se com a câmera para desenhar o Preview.
            camera.setPreviewDisplay(surfaceHolder);
            camera.startPreview();
        }catch (Exception e){
            Log.e("ERRO",e.getMessage());
        }

    }

As far as I understand the camera.setDisplayOrientation(180); adjusts the orientation of the camera (Preview) and parameters.setRotation(180); adjusts the orientation of the saved photo, otherwise without this it was saving the photos with different orientation.

    
05.08.2016 / 21:03