在 Android 屏幕录制中 - 如何获取每一帧?
Posted
技术标签:
【中文标题】在 Android 屏幕录制中 - 如何获取每一帧?【英文标题】:In Android Screen Recording - How can I get each frame? 【发布时间】:2020-05-07 04:21:55 【问题描述】:我正在使用 MediaRecorder 和 MediaProjection Api 在 android 应用程序中录制屏幕。我无法获得可以通过 rtmp 流发送的每一帧。为了通过 RTMP 流发布,我使用的是 JAVACV Android 库。
例如 - 如果通过摄像头进行直播,我们可以在 onPreviewFrame() 回调中获取每一帧。获取每一帧后,我只需使用 JAVACV 库的 FFmpegFrameRecorder 将每一帧流式传输到 rtmp url。
如何通过屏幕录制实现同样的效果?
任何帮助将不胜感激。提前致谢!
【问题讨论】:
您是否尝试过从muxer.writeSampleData(trackIndex, encodedData, info)
获取关键帧缓冲区,假设您正在执行类似于:github.com/google/grafika/blob/master/app/src/main/java/com/… 的操作(假设帧出现的频率足够高,这可能不适合您的目的)。
@MorrisonChang:是的,我试过了,但它不能满足我的要求。
【参考方案1】:
首先,MediaProjection 没有回调接口,可以为您提供屏幕捕获帧的缓冲区,但SurfaceTexture 完全有可能。这是使用 SurfaceTexture 进行屏幕捕获的一种实现ScreenCapturerAndroid。
VideoCapturer 的实现,用于将屏幕内容捕获为视频流。 捕获是由 SurfaceTexture 上的 MediaProjection 完成的。我们与此互动 SurfaceTexture 使用 SurfaceTextureHelper。 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 流,您可以使用活动的父视图来捕获活动的所有内容。
【讨论】:
以上是关于在 Android 屏幕录制中 - 如何获取每一帧?的主要内容,如果未能解决你的问题,请参考以下文章
如何在android studio中获取camera2 api中的每一帧,例如camera api中的PreviewCallback和camerax中的ImageAnalysis.Analyzer?