Подтвердить что ты не робот

Android onPreviewFrame не вызывается

У меня проблема с камерой. Я хочу получить изображение в onPreviewFrame, но он никогда не вызывал. Я открыл камеру, установил предварительный просмотр Дисплей и просмотрел Обратный звонок, но ничего. Я просто хочу понять, где я был неправ.

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)
    {

    }

}

Пробовал этот код на 2 других устройствах (телефоны HTS и Sony Xperia), и все работало нормально. Но на моем планшете это не работает. Я в замешательстве.

4b9b3361

Ответ 1

Я когда-то боролся с этой проблемой, и решение для меня заключалось в вызове Camera.setPreviewCallback сразу после Camera.setPreviewDisplay в 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);
    }
}

Читая многочисленные статьи, я понял, что setPreviewCallback может выйти из строя, если камера не имеет полностью инициализированного SurfaceHolder.

Надеюсь, это поможет...

Ответ 2

Я бы рекомендовал переместить код в surfaceCreated в surfaceChanged, тем более, что вы переопределяете макет предварительного просмотра во время onCreate (в initialize()).

В общем, безопаснее просто реагировать на surfaceChanged, так как он будет вызываться каждый раз, когда на поверхность изменяется размер. Вероятно, вы должны проверить, есть ли у вас предварительный просмотр в файле surfaceChanged.

Как говорили другие, размер поверхности предварительного просмотра не определяет размер буферов предварительного просмотра, которые вы получаете в обратном вызове предварительного просмотра; которые устанавливаются методом setPreviewSize, и вы должны использовать значение из списка поддерживаемых размеров предварительного просмотра, которые вы получаете из

  Camera.Parameters.getSupportedPreviewSizes().

Ответ 3

Вы должны вызвать setPreviewCallback в методе surfaceChanged, а не только в surfaceCreated. Это моя главная 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();
        }
    }

 }

И это мой 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;
    }
}

Игнорируйте читатель и вещи zxing, это доказательство концепции для макетов show over qr detection в библиотеке ZXing.

Это смешанное решение, найденное при поиске ошибок кода в StackOverflow.

Ответ 4

Вам может потребоваться установить более низкое разрешение предварительного просмотра для маломощных устройств. Настройка размера вашего экрана 320x240 не влияет на разрешение предварительного просмотра самой камеры, разрешение предварительного просмотра должно быть явно задано. Вы можете попробовать что-то вроде этого:

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