Android P实现minicap客户端和解析minicap数据

minicap的socket方式:UNIX domain sockets。所以连接minicap的方式为:LocalSocket

一、运行minicap

minicap运行后,建立socket服务端。

minicap的编译和运行请参照文章:
https://blog.csdn.net/Sunxiaolin2016/article/details/90697555

二、Android代码建立客户端连接minicap,并解析minicap数据

public class MainActivity extends AppCompatActivity {

    //UNIX domain sockets service name(@minicap)
    private static final String SOCKET_ADDRESS = "minicap";

    //Locak socket
    LocalSocket mMinicapClientSocket = null;
    LocalSocketAddress mAddr;

    //Image UI , to show a image from minicap data
    Bitmap mBitmap = null;
    ImageView mImage;

    //Image data size
    public static final int MAX_FRAME = 50000;
    public static final int FRAME_SIZE = 1024 * 1024;
    boolean HEAD_ONCE_FLAG = true;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mImage = findViewById(R.id.imageView);

		// new LocalSocket
        mMinicapClientSocket = new LocalSocket();
        mAddr = new LocalSocketAddress(SOCKET_ADDRESS,LocalSocketAddress.Namespace.ABSTRACT);

        //connect minicap
        connectSocket();
    }

    private void connectSocket() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    //Connect minicao
                    mMinicapClientSocket.connect(mAddr);

                    InputStream inputStream = mMinicapClientSocket.getInputStream();
                    Log.i("LocalSocketDemo", "update Data");
                    int actualFrameSize = 0;
                    byte[] frameArr = new byte[MAX_FRAME];

                    byte[] bytes = new byte[FRAME_SIZE];
                    byte[] fourbts = new byte[4];
                    int hasread = 0, destSt = 0;
                    //读取socket数据,读取方式为阻塞方式
                    //minicap根据屏幕UI有更新是发送截屏数据,UI不更新不发送数据
                    while (((hasread = inputStream.read(bytes)) > 0)) {
                        Log.i("LocalSocketDemo", "while read Data");
                        if (HEAD_ONCE_FLAG) {        //第一次只接收header,bytes[24]为空
                            Log.i("LocalSocketDemo", "read Data,HEAD_ONCE_FLAG is true ");
                            HEAD_ONCE_FLAG = false;
                        } else {            //不是第一次发送,就不含有Header,头四个字节直接表示Frame size
                            Log.i("LocalSocketDemo", "read Data,HEAD_ONCE_FLAG is false destSt=" + destSt);
                            if (destSt <= 0) {
                                fourbts[0] = bytes[3];
                                fourbts[1] = bytes[2];
                                fourbts[2] = bytes[1];
                                fourbts[3] = bytes[0];
                                actualFrameSize = Util.bytes2int(fourbts);
                                Log.i("LocalSocketDemo", "actualFrameSize = " + actualFrameSize);
                                if (actualFrameSize > MAX_FRAME || actualFrameSize <= 0) {
                                    Log.i("LocalSocketDemo", "continue,actualFrameSize = " + actualFrameSize);
                                    continue;
                                }

                                destSt = copyByteArray(bytes, frameArr, 4, hasread - 1, 0);

                            } else {
                                destSt = copyByteArray(bytes, frameArr, 0, hasread - 1, destSt);
                                if (destSt >= actualFrameSize) {        //已经记录完成一帧
                                    ByteArrayInputStream bais = new ByteArrayInputStream(frameArr, 0, actualFrameSize - 1);
                                    byte[] bytesBitmap = new byte[(int) bais.available()];
                                    bais.read(bytesBitmap, 0, bytesBitmap.length);
                                    //this.bi1 =ImageIO.read(bais);

									//Get Bitmap
                                    mBitmap = BitmapFactory.decodeByteArray(bytesBitmap, 0, bytesBitmap.length);
									//Update UI
                                    handler.sendEmptyMessageDelayed(0, 0);
                                    bais.close();
                                    destSt = 0;
                                }
                            }
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }).start();
    }

    private int copyByteArray(byte[] sour, byte[] dest, int sourSt, int sourEn, int destSt){
        int k=0;
        for(int i=sourSt; i<=sourEn; i++){
            if(destSt+k >= dest.length) continue;
            dest[destSt+k] = sour[i];
            k++;
        }
        return destSt+k;
    }
}

    @Override
    protected void onStop() {
        super.onStop();
        try {
            if( null != mMinicapClientSocket){
            	//close the localsocket
                mMinicapClientSocket.close();
                mMinicapClientSocket = null;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

	//Update UI
    Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
                case 0:
                    if(null != mBitmap){
                        mImage.setImageBitmap(mBitmap);
                        Log.i("LocalSocketDemo","update Image" );
                    }
                    break;
            }
        }
    };

三、总结

1.通过LocalSocket连接minicap服务端;
2.需要主要截屏的尺寸,如果是1920x1080的尺寸图片数据过大,导致占用太大的内存空间,所以运行minicap的时候需要调整一些截屏图片的尺寸为600x480。
//start minicap
adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/minicap -P 1920x1080@600x480/0
3.minicap数据的解析需要参考minicap源码,发送的数据格式。

你可能感兴趣的:(android笔记)