2013-01-19 10 views
13

Tôi gặp sự cố với máy ảnh. Tôi muốn có được hình ảnh trong onPreviewFrame nhưng nó không bao giờ được gọi. Tôi đã mở một máy ảnh, đặt xem trước Hiển thị và xem trước gọi lại nhưng không có gì. Tôi chỉ muốn hiểu nơi tôi đã sai.Android onPreviewFrame không được gọi là

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

    } 

} 

Đã thử mã này trên 2 thiết bị khác (điện thoại HTS và Sony Xperia) và mọi thứ hoạt động tốt. Nhưng trên máy tính bảng của tôi nó không hoạt động. Tôi bối rối.

Trả lời

0

Bạn có thể cần phải đặt độ phân giải xem trước thấp hơn cho các thiết bị được hỗ trợ thấp. Đặt kích thước surfaceview thành 320x240 không ảnh hưởng đến độ phân giải xem trước của máy ảnh, Độ phân giải xem trước phải được đặt rõ ràng. Bạn có thể thử một cái gì đó như thế này:

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

tôi khuyên bạn nên di chuyển mã trong surfaceCreated vào surfaceChanged, đặc biệt là kể từ khi bạn đang trọng bố trí bề mặt xem trước trong thời gian onCreate (trong initialize()).

Nói chung, an toàn hơn khi chỉ phản hồi với surfaceChanged, vì nó sẽ được gọi mỗi khi có thay đổi kích thước bề mặt. Bạn có lẽ nên kiểm tra xem bạn đã có xem trước đang chạy trong surfaceChanged.

Như những người khác đã nói, kích thước của bề mặt xem trước không xác định kích thước của bộ đệm xem trước bạn nhận được trong cuộc gọi lại xem trước; đó là thiết lập theo phương pháp setPreviewSize, và bạn phải sử dụng một giá trị từ danh sách các kích thước xem trước được hỗ trợ mà bạn nhận được từ

Camera.Parameters.getSupportedPreviewSizes(). 
2

Bạn phải gọi setPreviewCallback trong phương pháp surfaceChanged, không chỉ trong surfaceCreated. Đây là chính tôi 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(); 
     } 
    } 

} 

Và đây là CameraPreview.java tôi:

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

Bỏ qua đọc và ZXing điều, đó là một bằng chứng của khái niệm cho chương trình bố trí trên phát hiện qr trong Thư viện ZXing.

Đây là giải pháp hỗn hợp được tìm thấy trong khi tìm kiếm các lỗi mã của tôi trong StackOverflow.

+0

Bản xem trước của tôi chưa bao giờ thay đổi kể từ khi được tạo. – Rayz

+1

Xem câu trả lời của @Eddy về đề xuất di chuyển vào bề mặtThay đổi. Tôi sẽ chỉnh sửa câu trả lời hiển thị tất cả mã làm việc của mình. – Neonigma

+0

@Neonigma u có thể giúp tôi làm thế nào tôi có thể hiển thị xem trước trực tiếp trong nhiều hơn một framelayouts .... i m không hiển thị xem trước máy ảnh sống của tôi trong framelayouts thứ hai – Erum

14

tôi đã phải vật lộn với vấn đề này cho đôi và giải pháp đối với tôi là để gọi Camera.setPreviewCallback ngay sau Camera.setPreviewDisplay trong 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); 
    } 
} 

Đọc nhiều bài viết tôi nhận ra setPreviewCallback có thể thất bại nếu máy ảnh không có SurfaceHolder được khởi tạo đầy đủ.

Tôi hy vọng điều này sẽ giúp ...

+0

Sup'b Works Fine.Thanks –