【问题标题】:Android - cam.setPreviewDisplay(holder) running into IOErrorAndroid - cam.setPreviewDisplay(holder) 遇到 IOError
【发布时间】:2011-07-26 04:06:35
【问题描述】:

我正在尝试将相机的图像用作动态壁纸的一部分。

在我声明的引擎中,我有以下代码:

public class Class extends WallpaperService
{
    Camera cam;

    @Override
    public void onCreate()
    {
        super.onCreate();
        cam = Camera.open();
    }

    //...

    @Override
    public Engine onCreateEngine()
    {
        return new CubeEngine(cam);
    }

    class CubeEngine extends Engine
    {
        Camera cam;

        CubeEngine(Camera cam)
        {
            this.cam=cam;
        }

        //...

        @Override
        public void onDestroy()
        {
            if (cam != null)
            {
                cam.stopPreview();
                cam.setPreviewCallback(null);
                cam.release();
                cam = null;
            }
            super.onDestroy();
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format,
                int width, int height)
        {
            try
            {
                cam.setPreviewDisplay(holder);
                cam.startPreview();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            super.onSurfaceChanged(holder, format, width, height);
        }

        @Override
        public void onSurfaceCreated(SurfaceHolder holder)
        {
            super.onSurfaceCreated(holder);
        }

        @Override
        public void onSurfaceDestroyed(SurfaceHolder holder)
        {
            if (cam != null)
            {
                cam.stopPreview();
                cam.setPreviewCallback(null);
                cam.release();
                cam = null;
            }
            super.onSurfaceDestroyed(holder);
        }

        //...
    }
}

cam 是一个被声明为 Camera.open();

的相机

当我运行它时,我得到:java.io.IOException: setPreviewDisplay failed

我现在遇到了这个异常:

    07-26 00:12:18.399: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.419: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.439: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.459: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.479: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.509: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.529: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.549: WARN/CameraService(1357): Overlay create failed - retrying
07-26 00:12:18.569: ERROR/CameraService(1357): Overlay Creation Failed!


07-26 00:12:18.609: WARN/System.err(4104): java.lang.RuntimeException: startPreview failed
07-26 00:12:18.609: WARN/System.err(4104):     at android.hardware.Camera.startPreview(Native Method)
07-26 00:12:18.609: WARN/System.err(4104):     at com.petrifiednightmares.transparentphone.main.GenericaCamera.surfaceChanged(GenericaCamera.java:29)
07-26 00:12:18.609: WARN/System.err(4104):     at android.service.wallpaper.WallpaperService$Engine.updateSurface(WallpaperService.java:687)
07-26 00:12:18.609: WARN/System.err(4104):     at android.service.wallpaper.WallpaperService$Engine.attach(WallpaperService.java:749)
07-26 00:12:18.619: WARN/System.err(4104):     at android.service.wallpaper.WallpaperService$IWallpaperEngineWrapper.executeMessage(WallpaperService.java:984)
07-26 00:12:18.619: WARN/System.err(4104):     at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:61)
07-26 00:12:18.619: WARN/System.err(4104):     at android.os.Handler.dispatchMessage(Handler.java:99)
07-26 00:12:18.619: WARN/System.err(4104):     at android.os.Looper.loop(Looper.java:143)
07-26 00:12:18.619: WARN/System.err(4104):     at android.app.ActivityThread.main(ActivityThread.java:4293)
07-26 00:12:18.629: WARN/System.err(4104):     at java.lang.reflect.Method.invokeNative(Native Method)
07-26 00:12:18.629: WARN/System.err(4104):     at java.lang.reflect.Method.invoke(Method.java:507)
07-26 00:12:18.629: WARN/System.err(4104):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
07-26 00:12:18.629: WARN/System.err(4104):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
07-26 00:12:18.629: WARN/System.err(4104):     at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

  • 我认为您将不得不添加更多代码,以便我们可以在课堂上看到您正在使用它的相机的整个设置。
  • 是的,您需要显示更多代码。例如,您是如何创建表面的?
  • 我放了更多代码。这是我第一次涉足android开发,所以如果我犯了一些非常愚蠢的错误,请告诉我。 :)
  • 虽然我会做一些不同的设置事件,但我看到的唯一缺少的是设置相机的预览大小。我有兴趣看看墙纸的表面视图是否可以处理相机预览。不要认为这是一个好主意,但听起来是一个有趣的项目。
  • 是的,这就是我不确定的事情。我还没有看到任何利用相机的动态壁纸,因此决定编写一个快速应用程序作为概念证明(可以演变成一个成熟的 AR 应用程序)。一个很大的可能性是墙纸根本无法处理相机预览(可能是android开发人员为防止过度使用电池而故意采取的举措?)

标签: android camera android-camera live-wallpaper


【解决方案1】:

它或多或少地遵循您的代码并进行了一些更改。

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

}

更新

进入壁纸代码并弄清楚,仍然存在问题,但至少我让它基本上可以工作,由于推送缓冲区设置,时间顺序很重要

问题

  1. 不在横向模式下,这会导致预览图像失真,相机的已知问题只是尚未尝试锁定横向

  2. 在预览中,如果您使用返回键,一切都会被正确销毁(相机已释放),但如果您设置壁纸,该类不会调用 onDestroy 方法,因此这意味着您无法获取相机,因为预览实例类的还没有发布呢

  3. 它也显示为锁定屏幕图像,不知道如何覆盖它,可能通过意图接收和响应,并在您处于保护/锁定屏幕时将其关闭

  4. 尚未处理可见性事件,因此其他相机类将无法工作,可能会消耗不必要的电池等。

无论如何,修改如下,以使其至少开始工作

在引擎类中,在 onCreate 中从上述类创建相机,任何稍后都会出现问题,因为推送缓冲区设置,即使在以后的 2.3+ 中已弃用,但在旧版本中仍然需要。事实上还没有在 2.2 以上测试过。

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

然后在 GenericCamera 类中改成如下构造函数模式

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

基本上就是这样,至少这应该让你开始,如果你找到任何解决方案 1-4 让社区知道!

更新 2

Android 3+ 似乎打破了这一点,不知道为什么,因为这些平台的源代码仍然关闭。

因此,最高 2.3 的最终答案是上述工作,但在 3+ 上则不会。

【讨论】:

  • 好的,我尝试简单地将您的代码批发并在我的代码的surfaceCreated() 处实例化它并将其传递给SurfaceHandler。 (我稍微修改了你的类以使用 SurfaceHandlers 而不是 SurfaceViews。同样的问题仍然存在,我开始认为墙纸表面不适合相机。
  • 其实错误改了,现在是破坏 startPreview() 而不是 setPreviewSize()
  • 我将通过复制粘贴异常来修改我的问题。
  • 我还没有让它工作,你做了什么改变让它工作?
  • 可能,在相机代码中取出推送缓冲区调用,对于应该被弃用的姜饼,但我没有测试它。稍后我将使用平板电脑上的 3.1 对其进行测试。你接电话对吗? (笑,但我把我的放在桌子上,镜头被盖住了)
【解决方案2】:

我看到以下问题给了我java.io.IOException: setPreviewDisplay failed

如果你同时做视频和照片,有两个函数,camera.unlock()camera.reconnect()。您必须在录制视频之前camera.unlock() 并在拍照之前camera.reconnect()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 2014-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-06
    相关资源
    最近更新 更多