在Android屏幕录制中,我如何获取每一帧?

10
我正在使用MediaRecorder和MediaProjection API在Android应用程序中录制屏幕。我无法获取每一帧并将其发送到RTMP流中。为了在RTMP流上发布,我正在使用JAVACV Android库。
例如,在通过相机进行实时流传输的情况下,我们可以在onPreviewFrame()回调中获取每个帧。获取每个帧后,我只需使用JAVACV库的FFmpegFrameRecorder来将每个帧流式传输到rtmp url上。
如何在屏幕录制方面实现相同的功能?
这里任何帮助都将不胜感激。先感谢您!

你尝试过从 muxer.writeSampleData(trackIndex, encodedData, info) 获取关键帧缓冲区吗?假设你正在进行类似于 https://github.com/google/grafika/blob/master/app/src/main/java/com/android/grafika/ScreenRecordActivity.java 的操作(假设帧足够频繁,但对于你的目的可能不是这样)。 - Morrison Chang
@MorrisonChang:是的,我尝试过这个方法,但它并不能满足我的需求。 - umesh lohani
1个回答

8
首先,MediaProjection没有回调接口可以给你屏幕捕获帧的缓冲区,但使用SurfaceTexture则非常可能实现。这里有一个名为ScreenCapturerAndroid的实现,可通过SurfaceTexture进行屏幕捕获。

VideoCapturer的一种实现,用于捕获屏幕内容作为视频流。捕获是由MediaProjection在SurfaceTexture上完成的。我们使用SurfaceTextureHelper与此SurfaceTexture进行交互。SurfaceTextureHelper由本机代码创建并传递给该捕获器的VideoCapturer.initialize()中。每当接收到新帧时,此捕获器将其作为纹理通过CapturerObserver.onFrameCaptured()传递给本机代码。这发生在给定SurfaceTextureHelper的HandlerThread上。处理完每个帧后,本机代码会将缓冲区返回给SurfaceTextureHelper。

但如果您想发送应用视图的流,则以下屏幕捕获器将对您有所帮助。

public class ScreenCapturer {
    private boolean capturing = false;
    private int fps=15;
    private int width,height;
    private Context context;
    private int[] frame;
    private Bitmap bmp;
    private Canvas canvas;
    private View contentView;
    private Handler mHandler = new Handler();
    public ScreenCapturer(Context context, View view) {
        this.context = context;
        this.contentView = view;
    }

    public void startCapturing(){
        capturing = true;

        mHandler.postDelayed(newFrame, 1000 / fps);
    }
    public void stopCapturing(){
        capturing = false;
        mHandler.removeCallbacks(newFrame);
    }
    private Runnable newFrame = new Runnable() {
        @Override
        public void run() {
            if (capturing) {
                int width = contentView.getWidth();
                int height = contentView.getHeight();
                if (frame == null ||
                        ScreenCapturer. this.width != width ||
                        ScreenCapturer.this.height != height) {

                    ScreenCapturer.this.width = width;
                    ScreenCapturer.this.height = height;

                    if (bmp != null) {
                        bmp.recycle();
                        bmp = null;
                    }
                    bmp = Bitmap.createBitmap(width,
                            height, Bitmap.Config.ARGB_8888);

                    canvas = new Canvas(bmp);
                    frame = new int[width * height];
                }
                canvas.saveLayer(0, 0, width, height, null);
                canvas.translate(-contentView.getScrollX(), - contentView.getScrollY());
                contentView.draw(canvas);

                bmp.getPixels(frame, 0, width, 0, 0, width, height);


               //frame[] is a rgb pixel array compress it to YUV if want and send over RTMP

                canvas.restore();
                mHandler.postDelayed(newFrame, 1000 / fps);

            }
        }
    };


}


使用方法

...
//Use this in your activity 

private View parentView;

parentView = findViewById(R.id.parentView);
capturer = new ScreenCapturer(this,parentView);

//To start capturing
 capturer.startCapturing();


//To Stop capturer
capturer.stopCapturing();


使用此功能,您可以将视图内容发送到RTMP流中,您可以使用您活动的父视图来捕获活动的所有内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接