minicap的socket方式:UNIX domain sockets。所以连接minicap的方式为:LocalSocket
一、运行minicap
minicap运行后,建立socket服务端。
minicap的编译和运行请参照文章:
https://blog.youkuaiyun.com/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源码,发送的数据格式。