it-swarm-id.com

Bagaimana cara mendapatkan data pratinjau mentah dari objek Kamera setidaknya 15 frame per detik di Android?

Saya perlu mendapatkan data pratinjau mentah dari objek Camera setidaknya 15 frame per detik , tapi saya hanya bisa mendapatkan frame dalam 110 milidetik yang berarti saya hanya bisa mendapatkan 9 frame per detik. Saya memberi kode singkat di bawah ini.

Camera mCamera = Camera.open();
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewFrameRate(30);
parameters.setPreviewFpsRange(15000,30000);
mCamera.setParameters(parameters);
mCamera.addCallbackBuffer(new byte[dataBufferSize]);
//dataBufferSize stands for the byte size for a picture frame
mCamera.addCallbackBuffer(new byte[dataBufferSize]);
mCamera.addCallbackBuffer(new byte[dataBufferSize]);
mCamera.setPreviewDisplay(videoCaptureViewHolder);
//videoCaptureViewHolder is a SurfaceHolder object
mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
  private long timestamp=0;
  public synchronized void onPreviewFrame(byte[] data, Camera camera) {
    Log.v("CameraTest","Time Gap = "+(System.currentTimeMillis()-timestamp));
    timestamp=System.currentTimeMillis();
    //do picture data process
    camera.addCallbackBuffer(data);
    return;
  }
}
mCamera.startPreview();

Dalam kode singkat di atas, dataBufferSize dan videoCaptureViewHolder didefinisikan dan dihitung atau ditugaskan dalam pernyataan lain.

Saya menjalankan kode saya, saya dapat melihat pratinjau di layar dan saya mendapatkan log di bawah ini:

...
V/CameraTest( 5396): Time Gap = 105
V/CameraTest( 5396): Time Gap = 112
V/CameraTest( 5396): Time Gap = 113
V/CameraTest( 5396): Time Gap = 115
V/CameraTest( 5396): Time Gap = 116
V/CameraTest( 5396): Time Gap = 113
V/CameraTest( 5396): Time Gap = 115
...

Ini berarti onPreviewFrame (byte [] data, Kamera kamera) dipanggil setiap 110 milidetik sehingga saya tidak bisa mendapatkan lebih dari 9 frame per detik. Dan apa pun frame rate pratinjau yang saya tetapkan oleh issue setPreviewFrameRate () dan preview Fps range apa yang saya tetapkan oleh issue setPreviewFpsRange () , lognya sama.

Apakah seseorang akan memberi saya bantuan untuk masalah ini? Saya perlu memperoleh data pratinjau mentah dari objek Camera setidaknya 15 frame per detik. Terima kasih sebelumnya.

Saya meletakkan seluruh kode saya di bawah ini.

CameraTest.Java

package test.cameratest;

import Java.io.IOException;
import Java.util.Iterator;
import Java.util.List;
import Android.app.Activity;
import Android.graphics.ImageFormat;
import Android.hardware.Camera;
import Android.hardware.Camera.ErrorCallback;
import Android.hardware.Camera.Parameters;
import Android.hardware.Camera.Size;
import Android.os.Bundle;
import Android.util.Log;
import Android.view.SurfaceHolder;
import Android.view.SurfaceView;
import Android.view.SurfaceHolder.Callback;

public class CameraTestActivity extends Activity {
    SurfaceView mVideoCaptureView;
    Camera mCamera;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mVideoCaptureView = (SurfaceView) findViewById(R.id.video_capture_surface);
        SurfaceHolder videoCaptureViewHolder = mVideoCaptureView.getHolder();
        videoCaptureViewHolder.setType(SurfaceHolder.SURFACE_TYPE_Push_BUFFERS);
        videoCaptureViewHolder.addCallback(new Callback() {
            public void surfaceDestroyed(SurfaceHolder holder) {
            }

            public void surfaceCreated(SurfaceHolder holder) {
                startVideo();
            }

            public void surfaceChanged(SurfaceHolder holder, int format,
                    int width, int height) {
            }
        });
    }
    private void startVideo() {
        SurfaceHolder videoCaptureViewHolder = null;
        try {
            mCamera = Camera.open();
        } catch (RuntimeException e) {
            Log.e("CameraTest", "Camera Open filed");
            return;
        }
        mCamera.setErrorCallback(new ErrorCallback() {
            public void onError(int error, Camera camera) {
            }
        }); 
        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setPreviewFrameRate(30);
        parameters.setPreviewFpsRange(15000,30000);
        List<int[]> supportedPreviewFps=parameters.getSupportedPreviewFpsRange();
        Iterator<int[]> supportedPreviewFpsIterator=supportedPreviewFps.iterator();
        while(supportedPreviewFpsIterator.hasNext()){
            int[] tmpRate=supportedPreviewFpsIterator.next();
            StringBuffer sb=new StringBuffer();
            sb.append("supportedPreviewRate: ");
            for(int i=tmpRate.length,j=0;j<i;j++){
                sb.append(tmpRate[j]+", ");
            }
            Log.v("CameraTest",sb.toString());
        }

        List<Size> supportedPreviewSizes=parameters.getSupportedPreviewSizes();
        Iterator<Size> supportedPreviewSizesIterator=supportedPreviewSizes.iterator();
        while(supportedPreviewSizesIterator.hasNext()){
            Size tmpSize=supportedPreviewSizesIterator.next();
            Log.v("CameraTest","supportedPreviewSize.width = "+tmpSize.width+"supportedPreviewSize.height = "+tmpSize.height);
        }

        mCamera.setParameters(parameters);
        if (null != mVideoCaptureView)
            videoCaptureViewHolder = mVideoCaptureView.getHolder();
        try {
            mCamera.setPreviewDisplay(videoCaptureViewHolder);
        } catch (Throwable t) {
        }
        Log.v("CameraTest","Camera PreviewFrameRate = "+mCamera.getParameters().getPreviewFrameRate());
        Size previewSize=mCamera.getParameters().getPreviewSize();
        int dataBufferSize=(int)(previewSize.height*previewSize.width*
                               (ImageFormat.getBitsPerPixel(mCamera.getParameters().getPreviewFormat())/8.0));
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.addCallbackBuffer(new byte[dataBufferSize]);
        mCamera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
            private long timestamp=0;
            public synchronized void onPreviewFrame(byte[] data, Camera camera) {
                Log.v("CameraTest","Time Gap = "+(System.currentTimeMillis()-timestamp));
                timestamp=System.currentTimeMillis();
                try{
                    camera.addCallbackBuffer(data);
                }catch (Exception e) {
                    Log.e("CameraTest", "addCallbackBuffer error");
                    return;
                }
                return;
            }
        });
        try {
            mCamera.startPreview();
        } catch (Throwable e) {
            mCamera.release();
            mCamera = null;
            return;
        }
    }
    private void stopVideo() {
        if(null==mCamera)
            return;
        try {
            mCamera.stopPreview();
            mCamera.setPreviewDisplay(null);
            mCamera.setPreviewCallbackWithBuffer(null);
            mCamera.release();
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }
        mCamera = null;
    }
    public void finish(){
        stopVideo();
        super.finish();
    };
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
      package="test.cameratest"
      Android:versionCode="1"
      Android:versionName="1.0">
    <uses-sdk Android:minSdkVersion="9" Android:targetSdkVersion="10" Android:maxSdkVersion="10"/>
    <uses-permission Android:name="Android.permission.CAMERA" />
    <uses-permission Android:name="Android.permission.INTERNET" />
    <uses-permission Android:name="Android.permission.VIBRATE" />
    <uses-permission Android:name="Android.permission.ACCESS_WIFI_STATE" />
    <uses-permission Android:name="Android.permission.WAKE_LOCK" />
    <uses-permission Android:name="Android.permission.RECORD_AUDIO" />
    <uses-permission Android:name="Android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
    <uses-permission Android:name="Android.permission.READ_CONTACTS"/>
    <uses-permission Android:name="Android.permission.MODIFY_AUDIO_SETTINGS"/>
    <uses-permission Android:name="Android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission Android:name="Android.permission.PROCESS_OUTGOING_CALLS"/>
    <uses-permission Android:name="Android.permission.CALL_PHONE"/>
    <uses-permission Android:name="Android.permission.BOOT_COMPLETED"/>
    <uses-permission Android:name="Android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission Android:name="Android.permission.WRITE_SETTINGS" />    
    <application Android:icon="@drawable/icon" Android:label="@string/app_name">
        <activity Android:name=".CameraTestActivity"
                  Android:label="@string/app_name">
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN" />
                <category Android:name="Android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
30
EricOops

Aku takut, kamu tidak bisa. Pengaturan framerate preview adalah petunjuk untuk aplikasi kamera (yang berjalan dalam proses terpisah) - dan bebas untuk menerima atau mengabaikannya diam-diam. Ini juga tidak terkait dengan pengambilan bingkai pratinjau

Ketika Anda meminta bingkai pratinjau, Anda hanya mengatakan aplikasi eksternal yang Anda ingin memilikinya. Buffer untuk itu dialokasikan dalam aplikasi kamera dan kemudian diteruskan ke aktivitas Anda melalui segmen memori mmaped - ini membutuhkan waktu. 

Anda mungkin mendapatkan kinerja yang diinginkan pada beberapa perangkat, tetapi tidak harus pada yang Anda mainkan. 

Jika Anda membutuhkan frame rate yang ditentukan, Anda harus mengambil video dan kemudian mengurai/mendekompresi aliran biner yang dihasilkan. 

7

Pengalaman saya dengan hal-hal kamera telah fiddly dan perangkat keras tergantung. Jadi cobalah menjalankannya di perangkat keras lain kapan saja jika Anda bisa. 

Mungkin juga ada baiknya mencoba beberapa pengaturan kamera lagi.

Terima kasih telah menyertakan contoh kode btw.

6
leorleor

Ini seharusnya tidak menjadi masalah. Aplikasi androangelo saya (ada di pasaran) mendapatkan hingga 30 frame per detik (setidaknya saya menerapkan laju rem untuk memperlambatnya).

Harap periksa dengan seksama, apakah log Anda diisi dengan laporan pengumpul sampah. Ini adalah kasus jika buffer terlalu sedikit ditambahkan. Ini menjadi trik bagiku. Setidaknya saya datang untuk menambah 20! buffer ke kamera.

Maka pemrosesan setiap frame harus dilakukan dalam utas terpisah. Saat gambar berada di utas untuk diproses, panggilan balik harus melewati bingkai saat ini.

4
Kai

Dalam pemahaman saya, Android tidak mengizinkan pengguna untuk menetapkan framerate tetap, juga tidak menjamin nilai fps yang Anda tentukan akan dihormati karena waktu bingkainya frame yang diatur oleh perangkat keras atau firmware kamera. Kecepatan bingkai yang Anda amati mungkin merupakan fungsi dari kondisi pencahayaan. Misalnya, telepon tertentu dapat memberi Anda tingkat pratinjau 30fps dalam cahaya sehari tetapi hanya 7 fps jika Anda membuat film dalam kondisi kurang cahaya.

2
Yevgeni Litvin

Satu hal yang tampaknya meningkatkan fluiditas pratinjau, jika tidak tentu FPS yang sebenarnya, adalah mengatur previewFormat ke YV12 jika didukung. Ini lebih sedikit byte untuk disalin, selaras 16-byte, dan mungkin dioptimalkan dengan cara lain:

    // PREVIEW FORMATS
    List<Integer> supportedPreviewFormats = parameters.getSupportedPreviewFormats();
    Iterator<Integer> supportedPreviewFormatsIterator = supportedPreviewFormats.iterator();
    while(supportedPreviewFormatsIterator.hasNext()){
        Integer previewFormat =supportedPreviewFormatsIterator.next();
        // 16 ~ NV16 ~ YCbCr
        // 17 ~ NV21 ~ YCbCr ~ DEFAULT
        // 4  ~ RGB_565
        // 256~ JPEG
        // 20 ~ YUY2 ~ YcbCr ...
        // 842094169 ~ YV12 ~ 4:2:0 YCrCb comprised of WXH Y plane, W/2xH/2 Cr & Cb. see documentation
        Log.v("CameraTest","Supported preview format:"+previewFormat);
        if (previewFormat == ImageFormat.YV12) {
            parameters.setPreviewFormat(previewFormat);
            Log.v("CameraTest","SETTING FANCY YV12 FORMAT");                
        }
    }

http://developer.Android.com/reference/Android/graphics/ImageFormat.html#YV12 menjelaskan formatnya. Ini ditambah beberapa buffer cadangan memberi saya "Kesenjangan Waktu" serendah 80 ... yang masih belum "cukup baik", tapi ... lebih baik? (Sebenarnya saya punya satu di 69 ... tapi sungguh, mereka lebih rata-rata sekitar 90). Tidak yakin berapa banyak logging yang memperlambat segalanya?

Mengatur previewSize ke 320x240 (dibandingkan 1280x720) membuat semuanya turun ke kisaran 50-70msec ... jadi mungkin itu yang perlu Anda lakukan? Diakui, bahwa sedikit data mungkin jauh kurang bermanfaat.

// semua diuji pada Nexus4

1
Kaolin Fire

Saya biasanya mendeklarasikan lockCameraUse boolean global. Fungsi panggilan balik biasanya terlihat seperti ini.

  public void onPreviewFrame(byte[] data, Camera camera) {
    if (lockCameraUse) {
      camera.addCallbackBuffer(data);
      return;
    }
    lockCameraUse = true;
    // processinng data

    // done processing data
    camera.addCallbackBuffer(data);
    lockCameraUse = false;
    return;
  }
0
DXM