Предварительный просмотр моей камеры захватывает со скоростью 1 кадр в секунду

Мое приложение в настоящее время имеет экран предварительного просмотра, и я хочу, чтобы он захватывал много кадров в секунду для обработки. На данный момент мой предварительный просмотр сохраняет изображение только каждую секунду, однако мне требуется гораздо большая скорость захвата кадров в секунду. Любая помощь будет оценена по достоинству.

Другая проблема (если вы можете) заключается в том, что мои изображения поворачиваются на 90 градусов, когда они появляются на моей SD-карте. Никакие интернет-решения пока не помогли мне решить эти проблемы :(

Спасибо :)

    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 источник


Ответы (2)


Во-первых, обратите внимание, что Camera.Parameters позволяет установить кадр оценить с setPreviewFrameRate. Значение должно находиться в диапазоне, описанном параметром getPreviewFpsRange.

Во-вторых, обработка кадров предварительного просмотра в byte[] будет сильно ограничивать частоту кадров из-за объема данных, которые необходимо копировать. Если вы хотите записать на диск немодифицированные полнокадровые данные YUV, то в настоящее время у вас нет выбора. Если вы можете справиться с артефактами сжатия и у вас Android 4.3 или более поздняя версия, вы можете просто сохранить данные как видео MPEG и прочитать кадры позже. Пример кода см. в примере CameraToMpegTest.java на этой странице.

Поворот изображения на 90 или 180 градусов кодировать просто. Класс Bitmap может это сделать, если вы не хотите писать его сами.

person fadden    schedule 27.08.2013

setPreviewCallback() — это простой, но менее эффективный способ запроса кадров предварительного просмотра. Основная проблема заключается в том, что фреймворк может быть очень занят выделением byte[] фрагментов для заполнения, и сборщик мусора может получить высокую цену. Предпочтительным методом является использование setPreviewCallbackWithBuffer(), но даже это не гарантирует желаемую частоту кадров, как показано в Как получить необработанные данные предварительного просмотра из объекта «Камера» со скоростью не менее 15 кадров в секунду в Android?

person Alex Cohn    schedule 02.01.2014