2013-01-19 172 views
13

我的相機有問題。我想在onPreviewFrame中獲取圖片,但它從未被調用過。我打開一個攝像頭,設置預覽顯示和預覽回調,但沒有。我只想了解我錯在哪裏。Android 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)此代碼,一切運行良好。但在我的平板電腦上無法使用。我很困惑。

回答

0

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

我建議在surfaceCreated的代碼移入surfaceChanged,特別是因爲你的onCreate期間覆蓋預覽面的佈局(在初始化())。

一般來說,只需對surfaceChanged做出響應就比較安全,因爲每當表面發生尺寸變化時它都會被調用。您應該檢查您是否已經在surfaceChanged中運行預覽。

正如其他人所說的,預覽表面的大小並不決定您在預覽回調中收到預覽緩衝區的大小;那年代由setPreviewSize方法設置的,你必須從你從

Camera.Parameters.getSupportedPreviewSizes(). 
2

你必須得到調用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; 
    } 
} 

忽略讀者和斑馬線的東西,它的理念,爲展會的佈局超過QR檢測證明ZXing庫。

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

+0

我的預覽自從創建以來從未改變。 – Rayz

+1

查看@Eddy關於移至surfaceChanged的建議的回答。我將編輯我的答案,顯示我所有的工作代碼。 – Neonigma

+0

@Neonigma可以幫助我如何顯示多個framelayouts實時預覽....我沒有顯示我的第二個framelayouts我的實時相機預覽 – Erum

14

我一直在努力解決這個問題了一段時間,對我的解決辦法是在SurfaceView.surfaceChanged調用Camera.setPreviewCallback只是Camera.setPreviewDisplay後:

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。

我希望這可以幫助...

+0

Sup'b Works Fine.Thanks –