Camera orientation with Surfaceview

Asked

Viewed 887 times

0

I’m having a problem using the SurfaceView for a custom camera on Android, I can’t work the camera orientation with the SurfaceView, no matter how I turn the Smartphone it always behaves strangely, in case I made two layouts for the two orientations, follows picture:

inserir a descrição da imagem aqui

Before posting the code I wanted to know if the most correct way to work with Surfaceview is to leave your permanent guidance, being it Portrait or Landscape as in this manifest: android:screenOrientation="portrait" or if I leave it free, in the example above it is with free guidance.

Excerpt from the code for guidance

    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());
        }

    }

Full 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>

2 answers

2

Fala Vinithius,

Try to do the following, right after that line:

camera = Camera.open();

Add that line:

camera.setDisplayOrientation(90);

See if it solves your problem.

Hugs.

  • Leonardo speaks, blz? Man, let’s say 50% of the problem has been solved, it fits well when it gets in position PORTRAIT, but as I rotate the mobile the orientation gets messy again, I believe that if I seek to capture this movement and change to camera.setDisplayOrientation(180); can work, but I have a question, I leave the orientation free or should I "FREEZE THE ORIENTATION" in the manifest? Like this: <activity android:name=".activity.CameraApp" android:theme="@android:style/Theme.NoTitleBar" android:screenOrientation="portrait"/>

1

I managed to correct the problem of rotation using a basic Switch, with the help of colleague Leonardo I did the following in the method surfaceCreated:

@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());
        }

    }

From what I understand camera.setDisplayOrientation(180); adjusts the orientation of the camera (Preview) and the parameters.setRotation(180); adjusts the orientation of the saved photo, because without it he was saving the photos with different orientation.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.