IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> vysor原理以及Android同屏方案 -> 正文阅读

[移动开发]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这个函数是怎样实现截图的呢?

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:14:01  更:2022-02-16 13:15:24 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 14:28:10-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码