android - 在 Android 屏幕录制中 - 如何获取每一帧?
问题描述
我正在使用 MediaRecorder 和 MediaProjection Api 在 Android 应用程序中录制屏幕。我无法获得可以通过 rtmp 流发送的每一帧。为了通过 RTMP 流发布,我使用的是 JAVACV Android 库。
例如 - 如果通过摄像头进行直播,我们可以在 onPreviewFrame() 回调中获取每一帧。获取每一帧后,我只需使用 JAVACV 库的 FFmpegFrameRecorder 将每一帧流式传输到 rtmp url。
如何通过屏幕录制实现相同的效果?
任何帮助将不胜感激。提前致谢!
解决方案
首先,MediaProjection 没有回调接口,可以为您提供屏幕捕获帧的缓冲区,但SurfaceTexture很有可能。这是使用 SurfaceTexture 进行屏幕捕获的一种实现ScreenCapturerAndroid。
VideoCapturer 的实现,用于将屏幕内容捕获为视频流。捕捉是由 SurfaceTexture 上的 MediaProjection 完成的。我们使用 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 流,您可以使用活动的父视图来捕获活动的所有内容。
推荐阅读
- java - GUI bug in JDialog box?
- css - 在 Stylus 中对媒体查询进行分组
- unreal-engine4 - 如何使用 C++ 从虚幻引擎设备访问 ID3D11DepthStencilView
- c# - 如何使用从列表框拖放到 WPF 中的文本框来替换文本?
- c# - 如何将多个 tiff 作为 http 响应返回?
- excel - Excel 2016 在框中用重复的问号替换复制的文本
- python - 存储用于自动上传 Youtube 的 Google 授权码
- json - 使用 Swift 从 Firebase 获取 nil 值
- shuffle - 拆分训练集和测试集时是否洗牌
- java - 如何在eclipse中调试用ant编译的java项目?