Pratinjau kamera saya menangkap dengan kecepatan 1 bingkai per detik [duplikat]

Aplikasi saya saat ini memiliki layar pratinjau dan saya ingin aplikasi tersebut menangkap banyak frame per detik untuk diproses. Saat ini, pratinjau saya hanya menyimpan gambar setiap detik, namun saya memerlukan kecepatan pengambilan fps yang jauh lebih besar. Bantuan apa pun akan dihargai.

Masalah lainnya (jika bisa) adalah gambar saya diputar 90 derajat saat muncul di kartu sd saya. Sejauh ini tidak ada solusi internet yang membantu saya mengatasi masalah ini :(

Terima kasih :)

    public class MyCameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback{

    private SurfaceHolder mHolder;
    private Camera mCamera;

    public MyCameraSurfaceView(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int weight,
                               int height) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
        mCamera.setDisplayOrientation(90);

        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
        }

        // make any resize, rotate or reformatting changes here

        // start preview with new settings
        try {

            mCamera.setPreviewDisplay(mHolder);
            Camera.Parameters parameters = mCamera.getParameters();
            List<Camera.Size> size = parameters.getSupportedPreviewSizes();
            parameters.setPreviewSize(size.get(0).width, size.get(0).height);
            mCamera.setParameters(parameters);
            mCamera.startPreview();

        } catch (Exception e){}

        mCamera.setPreviewCallback(new Camera.PreviewCallback() {

            public void onPreviewFrame(byte[] data, Camera camera) {

                Camera.Parameters parameters = camera.getParameters();

                int format = parameters.getPreviewFormat();

                //YUV formats require more conversion
                if (format == ImageFormat.NV21 || format == ImageFormat.YUY2 || format == ImageFormat.NV16) {
                    int w = parameters.getPreviewSize().width;
                    int h = parameters.getPreviewSize().height;

                    // Get the YuV image
                    YuvImage yuv_image = new YuvImage(data, format, w, h, null);
                    // Convert YuV to Jpeg
                    Rect rect = new Rect(0, 0, w, h);
                    ByteArrayOutputStream output_stream = new ByteArrayOutputStream();

                    yuv_image.compressToJpeg(rect, 10, output_stream);
                    byte[] byt = output_stream.toByteArray();

                    FileOutputStream outStream = null;
                    try {
                        outStream = new FileOutputStream(String.format(
                                "/sdcard/bb%d.jpg", System.currentTimeMillis() / 1000));

                        outStream.write(byt);
                        outStream.close();


                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {

                    }

                }

            }
        });

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setDisplayOrientation(90);
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();


        } catch (IOException e) {
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub

    }

}

person Snoople    schedule 27.08.2013    source sumber


Jawaban (2)


Pertama, perhatikan bahwa Camera.Parameters memungkinkan Anda menyetel bingkai nilai dengan setPreviewFrameRate. Nilainya harus berada dalam kisaran yang dijelaskan oleh getPreviewFpsRange.

Kedua, menangani bingkai pratinjau di byte[] akan sangat membatasi kecepatan bingkai Anda karena banyaknya data yang harus disalin. Jika Anda ingin menulis data YUV full-frame yang tidak dimodifikasi ke disk, maka saat ini Anda tidak punya pilihan. Jika Anda dapat mengatasi artefak kompresi, dan Anda memiliki Android 4.3 atau lebih baru, Anda cukup menyimpan data sebagai video MPEG dan membaca kembali frame tersebut nanti. Lihat contoh CameraToMpegTest.java di laman ini untuk contoh kode.

Memutar gambar sebesar 90 atau 180 derajat sangatlah mudah untuk dikodekan. Kelas Bitmap dapat melakukannya jika Anda tidak ingin menulisnya sendiri.

person fadden    schedule 27.08.2013

setPreviewCallback() adalah cara yang mudah, namun kurang efisien untuk meminta bingkai pratinjau. Masalah utamanya adalah kerangka kerja mungkin sangat sibuk mengalokasikan byte[] potongan untuk diisi, dan pengumpul sampah mungkin harus membayar mahal. Metode yang lebih disukai adalah menggunakan setPreviewCallbackWithBuffer(), namun ini pun tidak menjamin kecepatan bingkai yang diinginkan, seperti dapat dilihat di Bagaimana cara mendapatkan data pratinjau mentah dari objek Kamera setidaknya 15 frame per detik di Android?

person Alex Cohn    schedule 02.01.2014