vysor原理以及Android同屏方案

今天调式个8155 的demo板子,显示模块插拔线没有,无法看到显示的画面,但是领导要看画面,后来想到了使用android模拟器的环境进行搭建,最早调式手机的时候都是没有屏幕的,都是使用安卓模拟器调式的,下面介绍些vysor的同屏显示原理

===》vysor 同屏显示原理
直接上干活

adb shell能够调用screencap或者screenshot来截取屏幕,那就说明adb shell具备截屏的权限。Surface/SurfaceControl和screenshot/screencap它们内部的实现机制应该是相同的,因此也就是说adb shell是具备截屏权限的也就是可以调用到Surface/SurfaceControl。那么咱们怎么经过adb shell来调用到这两个类呢,答案就是app_process。app_process能够直接运行一个普通的java类,详细的资料你们能够在网上找到。也就是说咱们经过adb shell运行app_process,而后经过app_process来运行一个java类,在java类中就能够访问到Surface/SurfaceControl这两个类,是否是很巧妙?

adb shell 截屏

H264 压缩

encoder  编码压缩

public static void main(String[] args) throws Exception {
        if (args.length > 0) {
            commandLinePassword = args[0];
            Log.i(LOGTAG, "Received command line password: " + commandLinePassword);
        }
        Looper.prepare();
        looper = Looper.myLooper();
        AsyncServer server = new AsyncServer();
        AsyncHttpServer httpServer = new AsyncHttpServer() {
            protected boolean onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
                Log.i(Main.LOGTAG, request.getHeaders().toString());
                return super.onRequest(request, response);
            }
        };
        String str = "getInstance";
        Object[] objArr = new Object[0];
        InputManager im = (InputManager) InputManager.class.getDeclaredMethod(r20, new Class[0]).invoke(null, objArr);
        str = "obtain";
        MotionEvent.class.getDeclaredMethod(r20, new Class[0]).setAccessible(true);
        str = "injectInputEvent";
        Method injectInputEventMethod = InputManager.class.getMethod(r20, new Class[]{InputEvent.class, Integer.TYPE});
        KeyCharacterMap kcm = KeyCharacterMap.load(-1);
        Class cls = Class.forName("android.os.ServiceManager");
        Method getServiceMethod = cls.getDeclaredMethod("getService", new Class[]{String.class});
        IClipboard clipboard = IClipboard.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"clipboard"}));
        clipboard.addPrimaryClipChangedListener(new AnonymousClass3(clipboard), null);
        IPowerManager pm = IPowerManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"power"}));
        IWindowManager wm = IWindowManager.Stub.asInterface((IBinder) getServiceMethod.invoke(null, new Object[]{"window"}));
        IRotationWatcher watcher = new Stub() {
            public void onRotationChanged(int rotation) throws RemoteException {
                if (Main.webSocket != null) {
                    Point displaySize = SurfaceControlVirtualDisplayFactory.getCurrentDisplaySize();
                    JSONObject json = new JSONObject();
                    try {
                        json.put("type", "displaySize");
                        json.put("screenWidth", displaySize.x);
                        json.put("screenHeight", displaySize.y);
                        json.put("nav", Main.hasNavBar());
                        Main.webSocket.send(json.toString());
                    } catch (JSONException e) {
                    }
                }
            }
        };
        wm.watchRotation(watcher);
        httpServer.get("/screenshot.jpg", new AnonymousClass5(wm));
        httpServer.websocket("/input", "mirror-protocol", new AnonymousClass6(watcher, im, injectInputEventMethod, pm, wm, kcm));
        httpServer.get("/h264", new AnonymousClass7(im, injectInputEventMethod, pm, wm));
        Log.i(LOGTAG, "Server starting");
        AsyncServerSocket rawSocket = server.listen(null, 53517, new AnonymousClass8(wm));
        if (httpServer.listen(server, 53516) == null || rawSocket == null) {
            System.out.println("No server socket?");
            Log.e(LOGTAG, "No server socket?");
            throw new AssertionError("No server socket?");
        }
        System.out.println("Started");
        Log.i(LOGTAG, "Waiting for exit");
        Looper.loop();
        Log.i(LOGTAG, "Looper done");
        server.stop();
        if (current != null) {
            current.stop();
            current = null;
        }
        Log.i(LOGTAG, "Done!");
        System.exit(0);
    }

这个软件koushikdutta是由开发的,这个团队之前发布过一个很是流行的开源网络库:async。在这个项目中也用到了这个开源库。main函数主要是新建了一个httpserver而后开放了几个接口,经过screenshot.jpg获取截图,经过socket input接口来发送点击信息,经过h264这个接口来获取实时的屏幕视频流。每个接口都有对应的响应函数,这里咱们主要研究截图,因此就看screenshot这个接口。h264这个接口传输的是实时的视频流,因此就流畅性来讲应该会更好,它也是经过virtualdisplay来实现的有兴趣的读者能够自行研究。

接下来咱们来看screenshot对应的响应函数AnonymousClass5的实现代码。

* renamed from: com.koushikdutta.vysor.Main.5 */
    static class AnonymousClass5 implements HttpServerRequestCallback {
        final /* synthetic */ IWindowManager val$wm;

        AnonymousClass5(IWindowManager iWindowManager) {
            this.val$wm = iWindowManager;
        }

        public void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
            if (Main.checkPassword(request.getQuery().getString("password"))) {
                Log.i(Main.LOGTAG, "screenshot authentication success");
                try {
                    Bitmap bitmap = EncoderFeeder.screenshot(this.val$wm);
                    ByteArrayOutputStream bout = new ByteArrayOutputStream();
                    bitmap.compress(CompressFormat.JPEG, 100, bout);
                    bout.flush();
                    response.send("image/jpeg", bout.toByteArray());
                    return;
                } catch (Exception e) {
                    response.code(500);
                    response.send(e.toString());
                    return;
                }
            }
            Log.i(Main.LOGTAG, "screenshot authentication failed");
            response.code(401);
            response.send("Not Authorized.");
        }
    }

这个类传入了一个wm类,这个类是用来监听屏幕旋转的,这里不用管它。另外在vysor开始运行时,会随机生成一个验证码,只有验证经过才能进行链接,因此这里有一个验证的过程,这里也不过管。能够看到这个类定义的响应函数的代码很是简单,就是经过EncoderFeeder.screenshot()函数来过去截图的bitmap,而后返回给请求端。那么EncoderFeeder.screenshot这个函数是怎样实现截图的呢?

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值