1 Star 0 Fork 6

pikaa / minicapGo

forked from Phery / minicapGo 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README

先看看效果:

1.项目地址:https://gitee.com/phery/minicapGo

2.实现原理:

手机画面同步:部署minicap程序到手机>执行minicap程序>绑定Socket端口到本地PC>监听并解析协议内容

调用adb模拟点击:获取鼠标按下x坐标>获取鼠标松开x坐标>计算两个x坐标的差值>换算成adb长按的时长

3.关键代码

初始化minicap:

package com.phery.minicap;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;

public class InitDevices
{
	public static int SDK_VERSION;
	public static String ABI;
	public static int PRE;
	public static String REL;
	public static String DIR;
	public static String BIN;

	public static void init()
	{
		SDK_VERSION = Integer.valueOf(excuteCommand("adb shell getprop ro.build.version.sdk")).intValue();
		ABI = excuteCommand("adb shell getprop ro.product.cpu.abi");
		String preSDK = excuteCommand("adb shell getprop ro.build.version.preview_sdk");
		if (!"".equals(preSDK))
			PRE = Integer.valueOf(preSDK).intValue();
		REL = excuteCommand("adb shell getprop ro.build.version.release");
		DIR = "/data/local/tmp/minicap-devel";
		if (PRE > 0)
			SDK_VERSION++;
		if (SDK_VERSION >= 16)
			BIN = "minicap";
		else
			BIN = "minicap-nopie";
		String result;
		result = excuteCommand("adb shell \"mkdir " + DIR + " 2>/dev/null || true\"");
		System.out.println(result);
		result = excuteCommand("adb push resource/libs/" + ABI + "/" + BIN + " " + DIR);
		System.out.println(result);
		result = excuteCommand("adb push resource/aosp/libs/android-" + SDK_VERSION + "/" + ABI + "/minicap.so " + DIR);
		System.out.println(result);
		result = excuteCommand("adb shell \"chmod 777 " + DIR + "/*\"");
		System.out.println(result);
		result = excuteCommand("adb forward tcp:1717 localabstract:minicap");
		System.out.println(result);

		String wmsize = excuteCommand("adb shell wm size");
		String[] value = wmsize.split(" ");
		wmsize = value[2];

		try
		{
			Runtime.getRuntime().exec(
					"adb shell LD_LIBRARY_PATH=" + DIR + " " + DIR + "/" + BIN + " -Q 100 -P " + wmsize + "@480x800/0");
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// System.out.println(result);

	}

	// public static void main(String[] args)
	// {
	// init();
	// }

	public static String excuteCommand(String cmd)
	{
		/* 获取cmd命令 */
		try
		{
			System.out.println("正在执行命令:" + cmd);
			Process pro = Runtime.getRuntime().exec(cmd); // 添加要进行的命令,"cmd
															// /c
															// calc"中calc代表要执行打开计算器,如何设置关机请自己查找cmd命令

			BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream())); // 虽然cmd命令可以直接输出,但是通过IO流技术可以保证对数据进行一个缓冲。
			String msg = null;
			String result = null;
			System.out.println("执行完成!!!");
			while ((msg = br.readLine()) != null)
			{
				System.out.println(msg);
				if (result == null)
					result = msg;
			}
			System.out.println(result);
			return result;
		} catch (IOException exception)
		{
			exception.printStackTrace();
			return "";
		}

		/*
		 * cmd /c dir 是执行完dir命令后关闭命令窗口 cmd /k dir 是执行完dir命令后不关闭命令窗口 cmd /c start
		 * dir 会打开一个新窗口后执行dir命令,原窗口会关闭 cmd /k start dir 会打开一个新窗口后执行dir命令,原窗口不会关闭
		 * cmd /? 查看帮助信息
		 */

	}

}

解析minicap协议:

package com.phery.minicap;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.Buffer;

public class MiniCap
{
	private RefreshListener listener;

	public MiniCap(RefreshListener listener)
	{
		this.listener = listener;
	}

	int readBannerBytes = 0;
	int bannerLength = 24;
	int readFrameBytes = 0;
	int frameBodyLength = 0;
	byte[] frameBody = new byte[0];
	String[] banner = new String[24];

	public void tryRead()
	{
		Socket socket;
		InputStream stream = null;
		try
		{
			socket = new Socket("127.0.0.1", 1717);
			stream = socket.getInputStream();
		} catch (UnknownHostException e1)
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e1)
		{
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		while (true)
		{
			try
			{
				DataInputStream input = new DataInputStream(stream);
				int len = input.available();// 获取读到的字节长度
				byte[] chunk = new byte[len];
				input.read(chunk);// 将读取的字节保存到chunk
				// System.out.println("拉取到长度:" + len);
				for (int cursor = 0; cursor < len;)
				{
					if (readBannerBytes < bannerLength)
					{
						switch (readBannerBytes)
						{
						case 0:
							// version
							banner[0] = chunk[cursor] + "";
							System.out.println("Banner Version:" + banner[0]);
							break;
						case 1:
							// length
							bannerLength = chunk[cursor];
							banner[1] = String.valueOf(bannerLength);
							System.out.println("Banner bannerLength:" + banner[1]);
							break;
						// case 2:
						// case 3:
						// case 4:
						case 5:

							// byte[] temp = new byte[4];
							// System.arraycopy(chunk, 2, temp, 0, 4);
							banner[5] = bytesToLong(chunk, 2) + "";
							// pid
							// banner[5] += (chunk[cursor] << ((readBannerBytes
							// - 2) * 8)) >>> 0;
							System.out.println("Banner pid:" + banner[5]);
							break;
						// case 6:
						// case 7:
						// case 8:
						case 9:
							// real width
							banner[9] = bytesToLong(chunk, 6) + "";
							// banner[9] += (chunk[cursor] << ((readBannerBytes
							// - 6) * 8)) >>> 0;
							System.out.println("Banner real width:" + banner[9]);
							break;
						// case 10:
						// case 11:
						// case 12:
						case 13:
							// real height
							banner[13] = bytesToLong(chunk, 10) + "";
							// banner[13] += (chunk[cursor] << ((readBannerBytes
							// - 10) * 8)) >>> 0;
							System.out.println("Banner real height:" + banner[13]);
							break;
						// case 14:
						// case 15:
						// case 16:
						case 17:
							// virtual width
							banner[17] = bytesToLong(chunk, 14) + "";
							// banner[17] += (chunk[cursor] << ((readBannerBytes
							// - 14) * 8)) >>> 0;
							System.out.println("Banner virtual width:" + banner[17]);
							break;
						// case 18:
						// case 19:
						// case 20:
						case 21:
							// virtual height
							banner[21] = bytesToLong(chunk, 18) + "";
							// banner[21] += (chunk[cursor] << ((readBannerBytes
							// - 18) * 8)) >>> 0;
							System.out.println("Banner virtual height:" + banner[21]);
							break;
						case 22:
							// orientation
							banner[22] += chunk[cursor] * 90;
							System.out.println("Banner orientation:" + banner[22]);
							break;
						case 23:
							// quirks
							banner[23] = chunk[cursor] + "";
							System.out.println("Banner quirks:" + banner[23]);
							break;
						}

						cursor += 1;
						readBannerBytes += 1;

						if (readBannerBytes == bannerLength)
						{
							System.out.println("banner读取完毕!");
							// console.log('banner', banner)
						}
					} else if (readFrameBytes < 4)
					{

						frameBodyLength = (int) bytesToLong(chunk, 0);
						// System.out.println("获取字节长度:" + frameBodyLength);
						// frameBodyLength += (chunk[cursor] << (readFrameBytes
						// * 8)) >>> 0;
						if (frameBodyLength < 0 || frameBodyLength > 999999)
						{

							cursor += frameBodyLength;
							frameBodyLength = readFrameBytes = 0;
							frameBody = new byte[0];
							continue;
						}
						cursor += 4;
						readFrameBytes += 4;
					} else
					{
						if (len - cursor >= frameBodyLength)
						{
							// console.info('bodyfin(len=%d,cursor=%d)',
							// frameBodyLength, cursor)
							byte[] temp = new byte[cursor + frameBodyLength];
							System.arraycopy(chunk, cursor, temp, 0, cursor + frameBodyLength);
							frameBody = addBytes(frameBody, temp);

							// Sanity check for JPG header, only here for
							// debugging purposes.
							// System.out.println("frameBody[0]:" + frameBody[0]
							// + " frameBody[1]" + frameBody[1]
							// + " 0xFF:" + 0xFF + " 0xD8:" + 0xD8);
							// if (frameBody[0] != -1 || frameBody[1] != -40)
							// {

							// cursor += frameBodyLength;
							// frameBodyLength = readFrameBytes = 0;
							// frameBody = new byte[0];
							// console.error(
							// 'Frame body does not start with JPG header',
							// frameBody)
							// continue;
							// }
							// System.out.println("读取完毕:" + frameBody.length);
							listener.refresh(frameBody);

							cursor += frameBodyLength;
							frameBodyLength = readFrameBytes = 0;
							frameBody = new byte[0];
						} else
						{
							// console.info('body(len=%d)', len - cursor)

							byte[] temp = new byte[len - cursor];
							System.arraycopy(chunk, cursor, temp, 0, len - cursor);
							frameBody = addBytes(frameBody, temp);
							// System.out.println("body:" + (len - cursor));
							// System.out.println("frameBodyLength:" +
							// frameBodyLength);

							frameBodyLength -= len - cursor;
							readFrameBytes += len - cursor;
							cursor = len;
						}
					}
				}
			} catch (Exception e)
			{
				e.printStackTrace();
				System.out.println("报错了");
			}
		}
	}

	/**
	 * byte数组中取int数值,本方法适用于(低位在前,高位在后)的顺序,和和intToBytes()配套使用
	 * 
	 * @param src
	 *            byte数组
	 * @param offset
	 *            从数组的第offset位开始
	 * @return int数值
	 */
	public static long bytesToLong(byte[] src, int offset)
	{
		long value;
		value = (long) ((src[offset] & 0xFF) | ((src[offset + 1] & 0xFF) << 8) | ((src[offset + 2] & 0xFF) << 16)
				| ((src[offset + 3] & 0xFF) << 24));
		return value;
	}

	/**
	 * 
	 * @param data1
	 * @param data2
	 * @return data1 与 data2拼接的结果
	 */
	public static byte[] addBytes(byte[] data1, byte[] data2)
	{
		byte[] data3 = new byte[data1.length + data2.length];
		System.arraycopy(data1, 0, data3, 0, data1.length);
		System.arraycopy(data2, 0, data3, data1.length, data2.length);
		return data3;

	}
}

空文件

简介

基于开源项目STF minicap的PC同步录屏软件,通过java实现视频源协议的解析 展开 收起
Java
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/pikaa/minicapGo.git
git@gitee.com:pikaa/minicapGo.git
pikaa
minicapGo
minicapGo
master

搜索帮助