startPreview失败但并非所有设备都失败

时间:2013-06-17 06:17:54

标签: android parameters android-camera preview

我收到错误startPreview失败但不是所有设备。 在摩托罗拉RAZR和三星Galaxy S3中,它运行良好。 有些人告诉我他们在其他设备上遇到了同样的问题(Galaxy SII Lite,Galaxy Ace Duos,Samsung Galaxy Y等) 我正试图在三星Galaxy Y中测试,这是我在Logcat中得到的东西

java.lang.RuntimeException: startPreview failed
    at android.hardware.Camera.startPreview(Native Method)
    at br.com.timo.tubagram.CameraSurfaceView.surfaceCreated(CameraSurfaceView.java:47)
    at android.view.SurfaceView.updateWindow(SurfaceView.java:601)
    at android.view.SurfaceView.updateWindow(SurfaceView.java:413)
    at android.view.SurfaceView.dispatchDraw(SurfaceView.java:358)
    at android.view.View.draw(View.java:7083)
    at android.view.SurfaceView.draw(SurfaceView.java:344)
    at android.view.View.buildDrawingCache(View.java:6842)
    at android.view.View.getDrawingCache(View.java:6628)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1571)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.View.draw(View.java:7083)
    at android.widget.FrameLayout.draw(FrameLayout.java:357)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
    at android.view.View.draw(View.java:7083)
    at android.widget.FrameLayout.draw(FrameLayout.java:357)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2108)
    at android.view.ViewRoot.draw(ViewRoot.java:1540)
    at android.view.ViewRoot.performTraversals(ViewRoot.java:1276)
    at android.view.ViewRoot.handleMessage(ViewRoot.java:1878)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:130)
    at android.app.ActivityThread.main(ActivityThread.java:3770)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:670)
    at dalvik.system.NativeStart.main(Native Method)

我的代码在哪里

public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, PreviewCallback{

    private SurfaceHolder holder;
    private Camera camera;
    private Camera.Parameters parameters;
    boolean front = false;

    public CameraSurfaceView(Context context) {
        super(context);

        this.holder = this.getHolder();
        this.holder.addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            this.holder = holder;
            camera = Camera.open();
            camera.setPreviewDisplay(holder);
            parameters = parametrosCamera();
            camera.setParameters(parameters);
            camera.setDisplayOrientation(90);
            camera.startPreview();
        } catch (IOException ioe) {
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.stopPreview();
        camera.release();   
        camera = null;
    }

    private Parameters parametrosCamera(){
        Parameters parameters = camera.getParameters();
        List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
        if (sizes != null){
            Size min = sizes.get(0);
            for (Size size : sizes){
                if (size.width < min.width){ 
                    min = size;
                }else{
                    parameters.setPreviewSize(min.width, min.height);
                    parameters.setPictureSize(min.width, min.height);
                }
            }
            parameters.set("orientation", "portrait");
            parameters.setRotation(90);
        }
        if (parameters.getFlashMode() != null){
            parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
        }
        return parameters;
    }
}

我的 PrincipalActivity

public class PrincipalActivity extends Activity{

Camera camera;
File sdImageMainDirectory;
CameraSurfaceView cameraSurfaceView;
Button principalActivity_bt_TirarFoto;
Button principalActivity_bt_VirarFoto;
Button principalActivity_bt_Aceitar;
Button principalActivity_bt_Cancelar;
FrameLayout preview;
ImageView principalActivity_iv_UltimaFoto;

HandlePictureStorage hps;
int wid = 0;
boolean imageSelected = false;
boolean front = false;
String caminhoImagens;
String url;

//  File storagePath = new File(Environment.getExternalStorageDirectory() + "/Tubagram/");

@SuppressWarnings("deprecation")
@SuppressLint("NewApi") 
public void onCreate(Bundle savedInstanceState) {
    Log.i("PrincipalActivity","onCreate");
    super.onCreate(savedInstanceState);

    setContentView(R.layout.principal_activity);
    principalActivity_bt_TirarFoto = (Button) findViewById(R.id.principalActivity_bt_TirarFoto);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    cameraSurfaceView = new CameraSurfaceView(principalActivity_bt_TirarFoto.getContext());
    cameraSurfaceView.setSoundEffectsEnabled(true);
    cameraSurfaceView.setDrawingCacheEnabled(true);
    preview = (FrameLayout) findViewById(R.id.principalActivity_fl_Camera);

    preview.addView(cameraSurfaceView);

    principalActivity_bt_TirarFoto.setSoundEffectsEnabled(true);
    principalActivity_bt_TirarFoto.setOnClickListener(new OnClickListener() {

        @SuppressLint("NewApi") 
        @Override
        public void onClick(View v) {
            Log.i("PrincipalActivity","onClick - TirarFoto");
            camera = cameraSurfaceView.getCamera();
            camera.takePicture(new ShutterCallback() {

                @Override
                public void onShutter() {
                    AudioManager mgr = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
                    mgr.playSoundEffect(AudioManager.FLAG_PLAY_SOUND);

                }
            }, null, hps = new HandlePictureStorage());

            imageSelected = false;

            mostrarBotoesConfirma();

        }
    });

    principalActivity_bt_Aceitar = (Button) findViewById(R.id.principalActivity_bt_Aceitar);
    principalActivity_bt_Aceitar.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Log.i("PrincipalActivity","onClick - Aceitar");
            if (verificaInstagram()){

                ByteArrayOutputStream stream = new ByteArrayOutputStream();

                if (imageSelected){
                    Bitmap bitmap = ((BitmapDrawable)cameraSurfaceView.getBackground()).getBitmap();
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
                }else{
                    hps.getBitmap().compress(Bitmap.CompressFormat.PNG, 100, stream);
                }

                salvarImagemSelecionada(stream.toByteArray());

                Intent shareIntent = new Intent(android.content.Intent.ACTION_SEND);
                shareIntent.setType("image/*");

                caminhoImagens = getRealPathFromURI(Uri.parse(url));

                Log.i("Caminho imagem: ", caminhoImagens);

                shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("file://" + caminhoImagens));
                shareIntent.setPackage("com.instagram.android");

                startActivity(shareIntent);
                //                  }
            }else{
                Toast.makeText(v.getContext(), "Você não possui o Instagram no seu smartphone!", Toast.LENGTH_SHORT).show();
            }

        }
    });

    principalActivity_bt_Cancelar = (Button) findViewById(R.id.principalActivity_bt_Cancelar);
    principalActivity_bt_Cancelar.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Log.i("PrincipalActivity","onClick - Cancelar");

            esconderBotoesConfirma();

            cameraSurfaceView.setBackgroundColor(Color.TRANSPARENT);

            cameraSurfaceView.voltarCamera();
        }
    });

    int qtdCameras = Camera.getNumberOfCameras();
    principalActivity_bt_VirarFoto = (Button) findViewById(R.id.principalActivity_bt_VirarFoto);
    if(qtdCameras > 1){
        principalActivity_bt_VirarFoto.setOnClickListener(new OnClickListener() {

            public void onClick(View v) {
                Log.i("PrincipalActivity","onClick - VirarCamera");
                Thread t = new Thread(){
                    @Override
                    public void run() {
                        cameraSurfaceView.flipit();
                        front = cameraSurfaceView.getFront();
                    }
                };
                t.start();
            }
        });
    }else{
        principalActivity_bt_VirarFoto.setVisibility(View.INVISIBLE);
    }

    LinearLayout principalActivity_ll_Molduras = (LinearLayout) findViewById(R.id.principalActivity_ll_Molduras);
    principalActivity_ll_Molduras.setVisibility(View.VISIBLE);

    List<Integer> listaMoldurasMenores = new ArrayList<Integer>();
    final List<Integer> listaMoldurasMaiores = new ArrayList<Integer>();

    //      listaMoldurasMenores.add(R.drawable.moldura_menor0);
    listaMoldurasMenores.add(R.drawable.moldura_menor1);
    listaMoldurasMenores.add(R.drawable.moldura_menor2);
    listaMoldurasMenores.add(R.drawable.moldura_menor3);
    listaMoldurasMenores.add(R.drawable.moldura_menor4);
    listaMoldurasMenores.add(R.drawable.moldura_menor5);
    listaMoldurasMenores.add(R.drawable.moldura_menor6);

    listaMoldurasMaiores.add(R.drawable.moldura_maior1);
    listaMoldurasMaiores.add(R.drawable.moldura_maior2);
    listaMoldurasMaiores.add(R.drawable.moldura_maior3);
    listaMoldurasMaiores.add(R.drawable.moldura_maior4);
    listaMoldurasMaiores.add(R.drawable.moldura_maior5);
    listaMoldurasMaiores.add(R.drawable.moldura_maior6);

    for (int i = 0; i < listaMoldurasMenores.size(); i++) {
        final ImageView imagem_moldura = new ImageView(this);
        imagem_moldura.setScaleType(ScaleType.FIT_XY);
        imagem_moldura.setId(i);
        imagem_moldura.setImageResource(listaMoldurasMenores.get(i));
        imagem_moldura.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                Log.i("PrincipalActivity","onClick - Molduras");
                ImageView imagem_moldura_maior = new ImageView(v.getContext());
                imagem_moldura_maior.setImageResource(listaMoldurasMaiores.get(imagem_moldura.getId()));
                preview.setForeground(imagem_moldura_maior.getDrawable());
            }
        });
        principalActivity_ll_Molduras.addView(imagem_moldura,i);
    }

    principalActivity_iv_UltimaFoto = (ImageView) findViewById(R.id.principalActivity_iv_UltimaFoto);
    principalActivity_iv_UltimaFoto.setAdjustViewBounds(false);

    Uri uri = buscaUltimaFotoAlbum();
    Drawable backgroundGaleria;

    if (uri != null){
        String caminhosImagensGaleria = getRealPathFromURI(uri);
        backgroundGaleria = Drawable.createFromPath(caminhosImagensGaleria);
        principalActivity_iv_UltimaFoto.setBackgroundDrawable(backgroundGaleria);
    }else{
        principalActivity_iv_UltimaFoto.setBackgroundResource(R.drawable.box_imagem_album);
    }

    principalActivity_iv_UltimaFoto.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI);
            final int ACTION_SELECT_IMAGE = 1;
            intent.putExtra("crop", "true");
            intent.putExtra("aspectX", 10);
            intent.putExtra("aspectY", 10);
            intent.putExtra("outputX", 256);
            intent.putExtra("outputY", 256);
            intent.putExtra("scale", true);
            intent.putExtra("return-data", true);
            startActivityForResult(intent,ACTION_SELECT_IMAGE);
        }
    });
}

编辑1 - 06/20/2013

我改变了一点我的代码,现在在我的Galaxy Y中运行,但我的FrameLayout与相机无法正常工作。我在FrameLayout上获得了黑屏。 谁知道为什么?

我改变了什么:

我把这一行放在我的构造函数

this.holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

我将surfaceCreatedsurfaceChanged更改为此

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
        int height) {
    try {
        camera.stopPreview();
        parameters = parametrosCamera();
        camera.setParameters(parameters);
        camera.setDisplayOrientation(90);
        camera.setPreviewDisplay(holder);
        camera.startPreview();
    } 
    catch (IOException e) {
    } 
    catch (Exception e){
    }
}

@SuppressLint("NewApi") 
@Override
public void surfaceCreated(SurfaceHolder holder) {
    try {
        camera = Camera.open(0);
        camera.setPreviewDisplay(this.holder);
        camera.startPreview();
    } catch (IOException ioe) {
    } catch (Exception e){
    }
}

P.S。

我放了一些Log来获取my setPreviewSize使用我的方法获得的大小

private Parameters parametrosCamera(){
    Parameters parameters = camera.getParameters();
    List<Camera.Size> sizes = parameters.getSupportedPreviewSizes();
    if (sizes != null){
        Size min = sizes.get(0);
        for (Size size : sizes){
            if (size.width < min.width){
                min = size;
            }else{
                parameters.setPreviewSize(min.width, min.height);
                parameters.setPictureSize(min.width, min.height);
                Log.i("Ultima Camera Width: " + min.width, "Ultima Camera Height: " + min.height);
            }
        }
        parameters.set("orientation", "portrait");
        parameters.setRotation(90);
    }
    if (parameters.getFlashMode() != null){
        parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
    }
    return parameters;
}

然后我登录surfaceChanged来获取宽度和高度(我不使用这个宽度和高度),看看是否相同,我得到了这个结果

Motorola RAZR HD(非常适用)

surfaceChanged:540 x 573 方法parametrosCamera:640 x 480

三星Galaxy Y(不显示我的预览)

surfaceChanged:240 x 162(宽x高) 方法parametrosCamera:320 x 240

在我的方法parametrosCamera中我使用了这两行

parameters.set("orientation", "portrait");
parameters.setRotation(90);

我认为我的问题的答案就在我的代码的这一部分。

2 个答案:

答案 0 :(得分:0)

您似乎在寻找支持的最小预览尺寸。但是,如果图片大小不支持此尺寸,则代码会将相机初始化为不受支持的状态。某些设备可能会选择无法在此状态下打开预览。

我不确定你真的需要图片大小等于预览帧大小。如果您不这样做,则可以单独对parameters.getSupportedPictureSizes()的值进行迭代。

另一个常见错误(不一定适用于您的使用案例)的根源在于后置摄像头的尺寸与前置摄像头的尺寸不匹配。因此,切换相机时必须始终重新计算尺寸。

答案 1 :(得分:0)

问题未使用与相机管理器相关的库,因此提问海报没有用(我认为它的古老我认为他已经修复或不再关心发布),但是此答案可能会有所帮助或修复仅在某些各种设备上遇到问题 startpreview 错误的用户。

原因

经过深度调试,我发现如果没有精确的尺寸匹配,相机管理器库会尝试使用最大的合适分辨率。

CameraConfiguration.findBestPreviewSizeValue()

// If no exact match, use largest preview size. This was not a great
// idea on older devices because
// of the additional computation needed. We're likely to get here on
// newer Android 4+ devices, where
// the CPU is much more powerful.
if (!supportedPreviewSizes.isEmpty()) {
    Camera.Size largestPreview = supportedPreviewSizes.get(0);
    Point largestSize = new Point(largestPreview.width, largestPreview.height);
    Log.i(TAG, "Using largest suitable preview size: " + largestSize);
    return largestSize;
}

这对设备制造商已正确设置支持的预览尺寸很好。

但事情有时会发生!设备可能会报告荒谬的高分辨率,使设备在 startPreview() 上不堪重负,其中发生内部驱动程序错误“预览超时”,仅在目录中可见。

让我们修复它!

  • 改为使用最接近屏幕的分辨率!

修改 CameraConfiguration.java 或可能在 CameraConfigurationUtils.java 中:

<块引用>

... 跳过几行直到找到下一个模式(请注意,您的来源可能略有不同!)

+ 添加行

- 删除行

...
...
public static Point findBestPreviewSizeValue(Camera.Parameters parameters, Point screenResolution) {
...
...
    // Find a suitable size, with max resolution
    int maxResolution = 0;
    Camera.Size maxResPreviewSize = null;
  + double closestResolutionDrift = 1024*1024;
  + Camera.Size closestResolution = null;
    for (Camera.Size size : rawSupportedSizes) {
...
...
        Log.i(TAG, "Found preview size exactly matching screen size: " + exactPoint);
        return exactPoint;
    }
  + 
  + double drift = (maybeFlippedWidth * maybeFlippedHeight)-(screenResolution.x * screenResolution.y);
  + if (drift < closestResolutionDrift && resolution>(screenResolution.x * screenResolution.y)) {
  +   closestResolutionDrift = drift;
  +   closestResolution = size;
  + }
...
...
    //If no exact match, use largest preview size. This was not a great idea on older devices because
    //of the additional computation needed. We're likely to get here on newer Android 4+ devices, where
    //the CPU is much more powerful.
  - if (maxResPreviewSize != null) {
  -      Point largestSize = new Point(maxResPreviewSize.width, maxResPreviewSize.height);
  -     Log.i(TAG, "Using largest suitable preview size: " + largestSize);
  -     return largestSize;
  - }
  + //if (maxResPreviewSize != null) {
  + //     Point largestSize = new Point(maxResPreviewSize.width, maxResPreviewSize.height);
  + //    Log.i(TAG, "Using largest suitable preview size: " + largestSize);
  + //    return largestSize;
  + //}
  + 
  + // Dont! Some low end device still report ridiculous high resolution which overwhelming startPreview!
  + if(closestResolution!=null){
  +     Point closestSize = new Point(closestResolution.width, closestResolution.height);
  +     Log.i(TAG, "Using closest suitable preview size: " + closestSize);
  +     return closestSize;
  + }