簡體   English   中英

未調用Android onPreviewFrame

[英]Android onPreviewFrame is not called

我的相機有問題。 我想在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和索尼Xperia)上嘗試了這個代碼,一切正常。 但在我的平板電腦上它不起作用。 我糊塗了。

我一直在努力解決這個問題,我的解決方案就是在SurfaceView.surfaceChanged中的Camera.setPreviewDisplay之后調用Camera.setPreviewCallback:

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

閱讀大量文章我意識到如果相機沒有完全初始化的SurfaceHolder,setPreviewCallback可能會失敗。

我希望這有幫助 ...

我建議將surfaceCreated中的代碼移動到surfaceChanged中,特別是因為你在onCreate(在initialize()中)覆蓋了預覽表面的布局。

一般來說,只響應surfaceChanged更安全,因為每次表面尺寸發生變化時都會調用它。 您應該檢查是否已在surfaceChanged中運行預覽。

正如其他人所說,預覽表面的大小不會決定您在預覽回調中收到的預覽緩沖區的大小; 這是由setPreviewSize方法設置的,你必須使用你從中獲得的支持的預覽大小列表中的值

  Camera.Parameters.getSupportedPreviewSizes().

您必須在surfaceChanged方法中調用setPreviewCallback,而不僅僅是在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事物,它是ZXing庫中qr檢測的顯示布局的概念證明。

這是在StackOverflow中搜索我的代碼錯誤時發現的混合解決方案。

您可能需要為低功耗設備設置較低的預覽分辨率。 將曲面視圖大小設置為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);

對我來說,某些設備(例如lg Rebel 3)從不調用onPreviewFrame()而其他設備(任何三星)。 結果問題是我使用的是setPreviewCallbackWithBuffer()方法而不是setPreviewCallback() 我試圖提高記憶力。 一旦我改回setPreviewCallback()一切都在嗡嗡作響。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM