Android onPreviewFrame no se llama

Tengo un problema con la cámara. Quiero conseguir la imagen en onPreviewFrame pero nunca se llama. He abierto una cámara, establecer la vista previa Mostrar y previsualizar la devolución de llamada, pero nada. Sólo quiero entender dónde estaba equivocado.

public class VideoCall extends Activity implements View.OnClickListener, Callback, PreviewCallback { TabHost thVideoChat; Button btnVideoUp, btnVideoDown; Handler uiHandler; SurfaceView videoPrev; SurfaceHolder surfaceHolder; Camera camera; Timer timer; boolean getPic; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.a_video); initialize(); Log.d("RAYZ", "onCreate"); } private void initialize() { thVideoChat = (TabHost) findViewById(R.id.thVideoChat); thVideoChat.setup(); TabSpec specs = thVideoChat.newTabSpec("1"); specs.setContent(R.id.tabVideo); specs.setIndicator("Видео", getResources().getDrawable(R.drawable.mcam)); thVideoChat.addTab(specs); specs = thVideoChat.newTabSpec("2"); specs.setContent(R.id.tabChat); specs.setIndicator("Чат", getResources().getDrawable(R.drawable.mchat)); thVideoChat.addTab(specs); btnVideoUp = (Button) findViewById(R.id.btnVideoUp); btnVideoDown = (Button) findViewById(R.id.btnVideoDown); btnVideoUp.setOnClickListener(this); btnVideoDown.setOnClickListener(this); videoPrev = (SurfaceView) findViewById(R.id.videoPrev); if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { LayoutParams lp = videoPrev.getLayoutParams(); lp.height = 320; lp.width = 240; videoPrev.setLayoutParams(lp); } else { LayoutParams lp = videoPrev.getLayoutParams(); lp.height = 240; lp.width = 320; videoPrev.setLayoutParams(lp); } surfaceHolder = videoPrev.getHolder(); surfaceHolder.addCallback(this); surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); uiHandler = new Handler(); getPic = false; } @Override protected void onPause() { Log.d("RAYZ", "onPause"); if (camera != null) { camera.setPreviewCallback(null); camera.stopPreview(); camera.release(); camera = null; } if (timer != null) { timer.cancel(); } super.onPause(); } @Override protected void onResume() { super.onResume(); camera = Camera.open(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.btnVideoUp: { btnVideoUp.setEnabled(false); btnVideoDown.setEnabled(true); timer = new Timer(); Log.d("RAYZ", "G_BTN"); timer.schedule(new TimerTask() { @Override public void run() { uiHandler.post(new Runnable() { @Override public void run() { getPic = true; } }); } }, 0L, 1L * 500L); break; } case R.id.btnVideoDown: { btnVideoUp.setEnabled(true); btnVideoDown.setEnabled(false); Log.d("RAYZ", "R_BTN"); timer.cancel(); timer = null; break; } default: break; } } @Override public void onPreviewFrame(byte[] data, Camera camera) { Log.d("RAYZ", "getPic"); // if (getPic) // { // } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceCreated(SurfaceHolder holder) { try { camera.setPreviewDisplay(holder); camera.setPreviewCallback(this); camera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceDestroyed(SurfaceHolder holder) { } } 

Probado este código en otros 2 dispositivos (teléfonos HTS y Sony Xperia) y todo funcionó bien. Pero en mi tableta no funciona. Estoy confundido.

He estado luchando con este problema por algún tiempo y la solución para mí era llamar Camera.setPreviewCallback justo después de Camera.setPreviewDisplay en SurfaceView.surfaceChanged:

 public void onCreate(Bundle state) { log("onCreate"); try { super.onCreate(state); setContentView(R.layout.main); text = (TextView) findViewById(R.id.text); surface = (SurfaceView) findViewById(R.id.surface); int type = SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS; surface.getHolder().setType(type);//REQUIRED:API10 surface.getHolder().addCallback(this); camera = Camera.open(); camera.setDisplayOrientation(90); // portrait mode only } catch (Exception e) { showException(e); } } public void surfaceChanged(SurfaceHolder sh, int format, int w, int h) { log("surfaceChanged"); try { camera.stopPreview(); Size s = camera.getParameters().getPreviewSize(); LayoutParams params = surface.getLayoutParams(); params.height = w*s.width/s.height; // portrait mode only surface.setLayoutParams(params); camera.setPreviewDisplay(sh); camera.setPreviewCallback(this); camera.startPreview(); } catch (Exception ex) { showException(ex); } } 

Leyendo el artículo numeroso realicé que el setPreviewCallback puede fallar si la cámara no tiene un SurfaceHolder completamente inicializado.

Espero que esto ayude …

Recomendaría mover el código en surfaceCreated en surfaceChanged, especialmente desde que está reemplazando el diseño de la superficie de vista previa durante onCreate (en initialize ()).

En general, es más seguro responder sólo a surfaceChanged, ya que se llamará cada vez que hay un cambio de tamaño a la superficie. Probablemente debería comprobar si ya tiene una vista previa ejecutándose en surfaceChanged.

Como otros han dicho, el tamaño de la superficie de vista previa no determina el tamaño de los búferes de vista previa que recibe en la devolución de llamada de vista previa; Que se establece por el método setPreviewSize, y debe utilizar un valor de la lista de tamaños de vista previa compatibles que obtiene de

  Camera.Parameters.getSupportedPreviewSizes(). 

Debe llamar a setPreviewCallback en el método surfaceChanged, no sólo en surfaceCreated. Esta es mi principal CameraActivity.java :

 package com.example.cameraview; import java.util.Hashtable; import android.app.Activity; import android.hardware.Camera; import android.hardware.Camera.Size; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.FrameLayout; import android.widget.ImageView; import com.google.zxing.BinaryBitmap; import com.google.zxing.DecodeHintType; import com.google.zxing.MultiFormatReader; import com.google.zxing.NotFoundException; import com.google.zxing.PlanarYUVLuminanceSource; import com.google.zxing.Result; import com.google.zxing.common.HybridBinarizer; public class CameraActivity extends Activity implements Camera.PreviewCallback { private Camera mCamera; private CameraPreview mPreview; private Result result; private MultiFormatReader reader; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); reader = new MultiFormatReader(); Hashtable<DecodeHintType, Object> hints = new Hashtable<DecodeHintType, Object>(); hints.put(DecodeHintType.TRY_HARDER, Boolean.TRUE); reader.setHints(hints); // Create an instance of Camera mCamera = getCameraInstance(); // Create our Preview view and set it as the content of our activity. mPreview = new CameraPreview(this, mCamera); FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview); preview.addView(mPreview); } public void onPause() { super.onPause(); if (mCamera != null) { mCamera.setPreviewCallback(null); mPreview.getHolder().removeCallback(mPreview); mCamera.release(); } } /** A safe way to get an instance of the Camera object. */ public static Camera getCameraInstance(){ Camera c = null; try { c = Camera.open(); // attempt to get a Camera instance } catch (Exception e){ // Camera is not available (in use or does not exist) } return c; // returns null if camera is unavailable } public void onPreviewFrame(byte[] data, Camera camera) { Size size = mCamera.getParameters().getPreviewSize(); PlanarYUVLuminanceSource source = new PlanarYUVLuminanceSource(data, size.width, size.height, 0, 0, size.width, size.height, false); HybridBinarizer hybBin = new HybridBinarizer(source); BinaryBitmap bitmap = new BinaryBitmap(hybBin); ImageView myImage = (ImageView) findViewById(R.id.foto); try { result = reader.decode(bitmap); Log.d("Result", "Result found!: " + String.valueOf(result)); myImage.setVisibility(View.VISIBLE); if (String.valueOf(result).contentEquals("1")) myImage.setImageResource(R.drawable.juan); else if (String.valueOf(result).contentEquals("2")) myImage.setImageResource(R.drawable.antonio); } catch (NotFoundException e1) { if (myImage != null) myImage.setVisibility(View.INVISIBLE); Log.d("NotFoundException", "NotFoundException"); } finally { reader.reset(); } } } 

Y este es mi CameraPreview.java:

 package com.example.cameraview; import java.io.IOException; import java.util.List; import android.content.Context; import android.hardware.Camera; import android.hardware.Camera.PreviewCallback; import android.hardware.Camera.Size; import android.hardware.Camera.Parameters; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; /** A basic Camera preview class */ public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mHolder; private Camera mCamera; private String TAG = "CameraPreview"; private Context context; @SuppressWarnings("deprecation") public CameraPreview(Context context, Camera camera) { super(context); mCamera = camera; this.context = context; // Install a SurfaceHolder.Callback so we get notified when the // underlying surface is created and destroyed. mHolder = getHolder(); // deprecated setting, but required on Android versions prior to 3.0 mHolder.addCallback(this); mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); } public void surfaceCreated(SurfaceHolder holder) { // The Surface has been created, now tell the camera where to draw the preview. try { mCamera.setPreviewDisplay(holder); mCamera.startPreview(); } catch (NullPointerException e) { Log.d(TAG, "Error setting camera preview - nullpointerexception: " + e.getMessage()); } catch (IOException e) { Log.d(TAG, "Error setting camera preview: " + e.getMessage()); } } public void surfaceDestroyed(SurfaceHolder holder) { // empty. Take care of releasing the Camera preview in your activity. } public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { // If your preview can change or rotate, take care of those events here. // Make sure to stop the preview before resizing or reformatting it. if (mHolder.getSurface() == null){ // preview surface does not exist return; } // stop preview before making changes try { mCamera.stopPreview(); } catch (Exception e){ // ignore: tried to stop a non-existent preview } // set preview size and make any resize, rotate or // reformatting changes here // start preview with new settings try { Parameters parameters = mCamera.getParameters(); List<Size> sizes = parameters.getSupportedPreviewSizes(); Size optimalSize = getOptimalPreviewSize(sizes, w, h); parameters.setPreviewSize(optimalSize.width, optimalSize.height); if (context.getPackageManager().hasSystemFeature("android.hardware.camera.autofocus")) parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); mCamera.setParameters(parameters); mCamera.setPreviewCallback((PreviewCallback) context); mCamera.setPreviewDisplay(mHolder); mCamera.startPreview(); } catch (Exception e){ Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.05; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } } 

Ignore las cosas de lector y zxing, es una prueba de concepto para los diseños de espectáculos sobre la detección qr en la biblioteca ZXing.

Esta es una solución mixta encontrada al buscar mis errores de código en StackOverflow.

Es posible que deba establecer una resolución de vista previa inferior para dispositivos de baja potencia. La configuración de su tamaño de vista de superficie a 320×240 no tiene ningún efecto sobre la resolución de vista previa de la cámara en sí, la resolución de vista previa debe establecerse de forma explícita. Puede intentar algo como esto:

 List<Camera.Size> resList = camera.getParameters().getSupportedPreviewSizes(); int w=0, h=0; final int desiredRes_W = 176; for ( Camera.Size size : resList ) { // find a supported res nearest to desired_Res if ( w==0 ) { w = size.width; h = size.height; } else if ( size.width >= desiredRes_W && size.width <= w ) { w=size.width; h = size.height; } } // 176x144, 320x240 ... Parameters par = camera.getParameters(); par.setPreviewSize(w, h); // ALSO set width/height of the SurfaceView to the same aspect ratio. camera.setParameters(par); camera.setPreviewDisplay(holder); 
  • Cómo saber qué aplicación (proceso) está utilizando la cámara en Android
  • Cómo obtener id de la cámara frente a frente con Camera2?
  • Cómo aumentar la resolución de la cámara cuando se utiliza IMAGE_CAPTURE intención
  • Excepción de puntero nulo en la intención de la cámara cuando elijo una cámara de terceros
  • Error de la cámara Android 5001
  • Cámara Android: ¿Hilos? Que debe hacer lo que
  • El tamaño de imagen de Android cambia después de la devolución de llamada de la cámara
  • Obtener el ángulo de visión del dispositivo de la cámara Android
  • ¿Cuál es la mejor manera de llamar a StartPreview () después de capturar una imagen?
  • Android: onAutoFocus () no está desencadenando en android 4.0 (sandwich de helado) dispositivo virtual
  • Android: toma fotos sin interfaz de usuario
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.