簡體   English   中英

沒有為SurfaceView上顯示的每個幀調用onPreviewFrame

[英]onPreviewFrame not being called for every frame that is displayed on SurfaceView

我的SurfaceView子類實現Camera.PreviewCallbackSurfaceHolder.Callback

private SurfaceHolder mHolder;
private Camera mCamera;

private final FPSCounter fpscounter = new FPSCounter();

public MySurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
    mHolder = getHolder();
    mHolder.addCallback(this);
}

@Override
public void onPreviewFrame(byte[] data, Camera camera) {
    fpscounter.logFrame();
    Log.d("fps", String.valueOf(fpscounter.getLastFrameCount()));
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    synchronized (this) {
        mCamera.stopPreview();

        Camera.Parameters parameters = mCamera.getParameters();
        parameters.setRecordingHint(true);
        parameters.setPreviewFormat(ImageFormat.NV21);

        mCamera.setParameters(parameters);

        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.setPreviewCallback(this);
            mCamera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    synchronized (this) {
        setWillNotDraw(false);
        mCamera = Camera.open();
    }
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    synchronized (this) {
        try {
            if (mCamera != null) {
                mCamera.stopPreview();
                mCamera.release();
            }
        } catch (Exception e) {
            Log.e("cam error", e.getMessage());
        }
    }
}

FPSCounter

private long startTime; 
private int frames, lastFrameCount;

public void logFrame() {
    frames++;
    if (System.nanoTime() - startTime >= 1000000000) {
        lastFrameCount = frames;
        frames = 0;
        startTime = System.nanoTime();
    }
}

public int getLastFrameCount() {
    return lastFrameCount;
}

即使攝像機預覽非常流暢, onPreviewFrame()方法也僅onPreviewFrame()被調用5次。 為什么不為每一幀調用它?

您可能已經知道了:Camera.setPreviewCallback()給垃圾收集器施加了太多壓力。 您可以改用Camera.setPreviewCallbackWithBuffer()。

其次,如果onPreviewFrame()到達主(UI)線程,則它將與UI事件(例如觸摸,布局甚至渲染)競爭單個CPU時間。 要在單獨的線程上保持onPreviewFrame(),應在輔助Looper線程上打開()攝像頭,請參見例如https://stackoverflow.com/a/19154438/192373

第三,即使在這種情況下,預覽回調也會被序列化。 如果fpscounter.logFrame()Log().d花費X毫秒,則FPS不會超過1000 / X。

每幀都需要調用它。 您可以參考相機的在線參考 看這句話“除了在屏幕上顯示外,還為每個預覽幀安裝要調用的回調”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM