Android - cam.setPreviewDisplay(holder) running into IOError

前端 未结 2 1117
长发绾君心
长发绾君心 2021-01-03 16:33

I am trying to use the camera\'s image as part of live wallpaper.

In the Engine that I declared, I have this code:

public class Class extends Wallpa         


        
相关标签:
2条回答
  • 2021-01-03 17:03

    I have seen the following gotcha giving me java.io.IOException: setPreviewDisplay failed:

    If you do both video and photo, there are two functions, camera.unlock() and camera.reconnect(). You must camera.unlock() before recording a video and camera.reconnect() before taking a photo.

    0 讨论(0)
  • 2021-01-03 17:17

    It more or less follows your code with a few changes.

    import java.io.IOException;
    import android.hardware.Camera;
    import android.view.SurfaceHolder;
    
    public class GenericaCamera implements SurfaceHolder.Callback {
    
        private Camera         cameraDevice        = null;
        private SurfaceHolder  cameraSurfaceHolder = null; 
    
        // MODIFIED FROM ORIGINAL SEE UPDATE AT BOTTOM
        public GenericaCamera(SurfaceHolder holder)
        {
            cameraSurfaceHolder = holder;
            cameraSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
            cameraSurfaceHolder.addCallback(this);
        }
    
         // Required camera surface holder interface Callback's
         public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
         {
             Camera.Parameters params = cameraDevice.getParameters();
             Camera.Size       size   = getBestPreviewSize(params,w,h);
    
             if (size != null)
                params.setPreviewSize(size.width, size.height);
             cameraDevice.startPreview();
         }
    
         // When the surface is ready then we can build the camera and attach 
         // the camera preview output to the UI holder 
         public void surfaceCreated(SurfaceHolder holder)
         {
            try {
    
                cameraDevice = Camera.open();  
                cameraDevice.setPreviewDisplay(cameraSurfaceHolder);
    
            } catch (IOException e) { }
    
        }
    
        // Stop the camera preview and dispose of the camera object 
        public void surfaceDestroyed(SurfaceHolder holder)
        {
            if (null == cameraDevice)
                return; 
            cameraDevice.stopPreview(); 
            cameraDevice.release(); 
            cameraDevice = null; 
        }
    
        public Camera.Size getBestPreviewSize(Camera.Parameters parameters, int w, int h)
        {
            Camera.Size result = null; 
    
            for (Camera.Size size : parameters.getSupportedPreviewSizes())
            {
                if (size.width <= w && size.height <= h)
                {
                    if (null == result)
                    result = size; 
                else
                {
                    int resultDelta = w - result.width + h - result.height;
                    int newDelta    = w - size.width   + h - size.height;
    
                        if (newDelta < resultDelta)
                    result = size; 
                }
                } 
            }
            return result; 
        }
    

    }

    Update

    Went into the wallpaper code and figured it out, still problems but at least I got it to basically work, order of when is important because of the push buffers setup

    Problems

    1. Not in landscape mode, this causes a distorted image to be previewed, known issue of the camera just havent tried to lock into landscape yet

    2. In preview if you use back key everything is destroyed properly (camera released) but if you set the wallpaper the class does not call the onDestroy method so this means that you can't get the camera because the preview instance of the class has not released it

    3. It also shows up as the lock screen image, not sure how to override that, probably receive and respond via intents and turn it off when you are in the guard/lock screen

    4. Have not handled visibility event, so other camera classes won't work, potential unnecessary battery drain etc.

    Anyway with all of that said the modifications are as follows to get this to at least start working

    In the engine class create the camera from the above class in the onCreate, any later and problems occur because of the push buffers setup, and even though this is deprecated in later 2.3+ it is still required in older versions. Matter of fact have not tested this above 2.2 yet.

    @Override
        public void onCreate(SurfaceHolder holder) {
            Log.d("CameraWallpaper","onCreate(SurfaceHolder holder)");
            if (null == GC)
            GC = new GenericaCamera(holder);
        super.onCreate(holder);
    }
    

    Then in the GenericCamera class change to the following constructor pattern

    public GenericaCamera(SurfaceHolder holder)
    {
         cameraSurfaceHolder = holder;
         cameraSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
         cameraSurfaceHolder.addCallback(this);
    }
    

    That's basically it, at least this should get you started, and if you find any solutions to 1-4 let the community know!

    Update 2

    It seems that Android 3+ breaks this, not sure why since the source for those platforms is still closed.

    So final answer for upto 2.3 is that above works, but on 3+ it will not.

    0 讨论(0)
提交回复
热议问题