scrcpy的开发文档DEVELOP.md中,对屏幕获取的方法是轻描淡写的说了下,使用MediaCodeC的相关接口,关联屏幕surface对象,就可以获取屏幕数据了。
https://github.com/Genymobile/scrcpy
打不开的可以看这个
https://gitee.com/mirrors/scrcpy/blob/master/DEVELOP.md
Screen video encoding
The encoding is managed by ScreenEncoder
.
The video is encoded using the MediaCodec
API. The codec takes its input from a surface associated to the display, and writes the resulting H.264 stream to the provided output stream (the socket connected to the client).
code
private void internalStreamScreen(Device device, FileDescriptor fd) throws IOException {
MediaFormat format = createFormat(bitRate, maxFps, codecOptions);
device.setRotationListener(this);
boolean alive;
try {
do {
MediaCodec codec = createCodec();
IBinder display = createDisplay();
ScreenInfo screenInfo = device.getScreenInfo();
Rect contentRect = screenInfo.getContentRect();
// include the locked video orientation
Rect videoRect = screenInfo.getVideoSize().toRect();
// does not include the locked video orientation
Rect unlockedVideoRect = screenInfo.getUnlockedVideoSize().toRect();
int videoRotation = screenInfo.getVideoRotation();
int layerStack = device.getLayerStack();
setSize(format, videoRect.width(), videoRect.height());
configure(codec, format);
Surface surface = codec.createInputSurface();
setDisplaySurface(display, surface, videoRotation, contentRect, unlockedVideoRect, layerStack);
codec.start();
try {
alive = encode(codec, fd);
// do not call stop() on exception, it would trigger an IllegalStateException
codec.stop();
} finally {
destroyDisplay(display);
codec.release();
surface.release();
}
} while (alive);
} finally {
device.setRotationListener(null);
}
}
private static IBinder createDisplay() {
return SurfaceControl.createDisplay("scrcpy", true);
}
现在录屏使用virsualDisplay较多,以下是另外的获取屏幕实现
https://blog.csdn.net/u012894808/article/details/112395881
public void startEncode() {
//声明MediaFormat,创建视频格式。
MediaFormat mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_HEVC, width, height);
//描述视频格式的内容的颜色格式
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
//比特率(比特/秒)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height);
//帧率
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 20);
//I帧的频率
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
try {
//创建编码MediaCodec 类型是video/hevc
mediaCodec = MediaCodec.createEncoderByType(enCodeType);
//配置编码器
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
//创建一个目的surface来存放输入数据
Surface surface = mediaCodec.createInputSurface();
//获取屏幕流
mediaProjection.createVirtualDisplay("screen", width, height, 1, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC
, surface, null, null);
} catch (IOException e) {
Log.d(TAG,"initEncode IOException");
e.printStackTrace();
}
//启动子线程
this.start();
}
@Override
public void run() {
//编解码器立即进入刷新子状态
mediaCodec.start();
//缓存区的元数据
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
//子线程需要一直运行,进行编码推流,所以要一直循环
while (play) {
//查询编码输出
int outPutBufferId = mediaCodec.dequeueOutputBuffer(bufferInfo, timeOut);
if (outPutBufferId >= 0) {
//获取编码之后的数据输出流队列
ByteBuffer byteBuffer = mediaCodec.getOutputBuffer(outPutBufferId);
//添加上vps,sps,pps
reEncode(byteBuffer, bufferInfo);
//处理完成,释放ByteBuffer数据
mediaCodec.releaseOutputBuffer(outPutBufferId, false);
}
}
}
————————————————
版权声明:本文为CSDN博主「coder_soldier」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u012894808/article/details/112395881