我想在Android中制作一个Presentation对象的“即时”屏幕截图。我的演示文稿通常呈现为虚拟显示(PRIVATE),该显示由设置为记录视频的MediaRecorder的表面支持。将演示文稿录制为视频效果很好。
mMediaRecorder = new MediaRecorder();
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setOutputFile(getScratchFile().getAbsolutePath());
mMediaRecorder.setVideoEncodingBitRate(bitrateInBitsPerSecond);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(mVideoSize.getWidth(), mVideoSize.getHeight());
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mVirtualDisplay = mDisplayManager.createVirtualDisplay(
DISPLAY_NAME, // string name required
mVideoSize.getWidth(),
mVideoSize.getHeight(),
160, // screen densityDpi, not sure what it means in this context
mMediaRecorder.getSurface(), // the media recorder must already be {@code prepare()}'d
DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY); // only we can use it
mPresentation = new MyPresentation(getActivity(), mVirtualDisplay().getDisplay());
如何随时获取mMediaRecorder.getSurface()的屏幕截图,包括何时设置mMediaRecorder但未录制?
我在Presentation根视图对象上尝试了许多与view.getDrawingCache()相关的方法,我只得到清除/黑色输出。演示文稿本身包含TextureView对象,我猜这些对象正在弄乱这个策略。 我也尝试使用带有mMediaRecorder的DisplayPreview的ImageReader,但它在回调中没有收到图像 - 曾经
mMediaRecorder.setDisplayPreview(mImageReader.getSurface());
我真的很喜欢镜像Surface的一些方法,它将演示文稿支持到ImageReader并将其用作消费者,我只是看不到如何将一个表面“镜像”为生产者而另一个“消费者”类。看来SurfaceFlinger应该有一个简单的方法。
答案 0 :(得分:1)
Surfaces是生产者 - 消费者数据结构的生产者端。生产者无法将数据从管道中取出,因此尝试从Surface读取帧是不可能的。
在提供MediaCodec或MediaRecorder时,消费者端处于管理媒体硬件的不同过程(mediaserver
)。对于SurfaceView,消费者使用SurfaceFlinger。对于TextureView,两端都在你的应用程序中,这就是为什么你可以从TextureView轻松获取一个框架(调用getBitmap()
)。
要拦截传入的数据,您需要在同一过程中同时拥有生产者和消费者。 SurfaceTexture类(也称为" GLConsumer")提供了这个 - 它是一个消费者,它将收到的帧转换为GLES纹理。
因此,我们的想法是创建一个SurfaceTexture,从中创建一个新的Surface(您将注意到Surface only public constructor采用SurfaceTexture),并将该Surface作为虚拟显示传递输出表面。然后随着框架进入你的前进"通过使用OpenGL ES渲染纹理,将它们传送到MediaRecorder。
这并非完全直截了当,特别是如果您之前没有使用过OpenGL ES。可以在Grafika中找到各种示例(例如"来自相机的纹理"以及"记录GL应用")。
我不知道setDisplayPreview()
是否适用于除相机之外的其他任何内容。