Skip to content

Commit

Permalink
修复漏帧问题,硬解码还没实现
Browse files Browse the repository at this point in the history
  • Loading branch information
w2016561536 committed Aug 25, 2021
1 parent 345a56c commit 4645c1e
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 14 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@
xposed安卓虚拟摄像头
## 感谢https://github.com/wangwei1237/CameraHook 提供的HOOK思路!!

已加入Camera2支持,抖音测试通过,需要**不静音**的可以在no-silent的分支/app/release/app-release.apk下载。(链接全部放下面了)
已加入Camera2支持,抖音测试通过,需要**不静音**的可以在no-silent的分支/app/release/app-release.apk下载(no-silent更新很不及时)。(链接全部放下面了)
### github release里全是静音的。
### 软件对TextureView预览信息替换的视频是 /sdcard/DCIM/Camera/virtual.mp4
### 软件对onPreviewFrame预览信息替换的**照片**是 /sdcard/DCIM/Camera/bmp/****.bmp
**命名规则**:"****.bmp" 是bmp图片,文件命名的规则为:从1000.bmp开始,按帧排序依次为1000.bmp,1001.bmp,1002.bmp……,最少有3张图片,最大不超过999张(超过了的话文件名会多一位),可以使用Premiere将视频转化为BMP。
**命名规则**:"****.bmp" 是bmp图片,文件命名的规则为:从1000.bmp开始,按帧排序依次为1000.bmp,1001.bmp,1002.bmp……,最少有1张图片,最大不超过1000张(超过了的话文件名会多一位),可以使用Premiere将视频转化为BMP。

## 具体的使用方法:
1、安装xposed框架(传统xposed,edxp,lsp等均可,不确定虚拟框架能否使用,已经确定VMOS可用,应用转生不可用)
2、安装模块,启用模块,lsp等包含定义域的框架需要选勾目标app,但无需选勾系统框架。
3、对于大多数应用,只需要将替换的视频命名为virtual.mp4,放在/sdcard/DCIM/Camera/目录下。
4、多余少部分应用(如腾讯会议,和其他应用大部分的二维码扫描),需要使用premiere或其它剪辑软件将视频拆分成BMP格式图片(命名格式见上,PR视频总帧数超过1000帧自动按以上的命名格式命名),要注意的是图片分辨率需要与目标分辨率匹配(获取分辨率方法见下),将这些图片放在/sdcard/DCIM/Camera/bmp/目录下(没有的话自己创建)。
4、多余少部分应用(如腾讯会议,和其他应用大部分的二维码扫描),需要使用premiere或其它剪辑软件将视频拆分成BMP格式图片(命名格式见上,premiere视频总帧数超过1000帧,导出时名字设置为1.bmp,会自动按以上的命名格式命名),要注意的是图片分辨率需要与目标分辨率匹配(获取分辨率方法见下),将这些图片放在/sdcard/DCIM/Camera/bmp/目录下(没有的话自己创建)。
5、强制结束目标应用/重启手机。

## > 如何获得分辨率??(仅onPreviewFrame需要,其它系统自动处理)
在目标应用中打开摄像头,若创建回调则即可在Xposed log得到分辨率(可查看到字样为:预览回调初始化:宽……高…………)。
在目标应用中打开摄像头,若创建回调则即可在Xposed log得到分辨率(可查看到字样为:帧预览回调初始化:宽……高…………)。

## Camera2接口有问题??
是的,目前Camera2接口的HOOK不是所有应用程序都能生效,部分app报错打开相机失败,如果想停用Camera2接口的HOOK,可在/sdcard/DCIM下创建disable.jpg,以停用此项HOOK
Expand Down
Binary file modified app/release/app-release.apk
Binary file not shown.
30 changes: 20 additions & 10 deletions app/src/main/java/com/example/vcam/HookMain.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ protected void afterHookedMethod(MethodHookParam param) throws Throwable {
protected void beforeHookedMethod(MethodHookParam param) {
File file = new File("/sdcard/DCIM/Camera/virtual.mp4");
File control_file = new File("/sdcard/DCIM/disable.jpg");
if (control_file.exists() && control_file.exists()) {
if (control_file.exists() && (!control_file.exists())) {

if (HookMain.c2_builder != null && HookMain.c2_builder.equals(param.thisObject)) {
param.args[0] = HookMain.c2_image_reader.getSurface();
Expand Down Expand Up @@ -214,6 +214,19 @@ protected void beforeHookedMethod(MethodHookParam param) {
}
});

XposedHelpers.findAndHookMethod("android.hardware.Camera", lpparam.classLoader, "addCallbackBuffer", byte[].class, new XC_MethodHook() {
@SuppressLint("SdCardPath")
@Override
protected void beforeHookedMethod(MethodHookParam param) {
if (param.args[0] == null){
return;
}
Camera thiscam = (Camera) param.thisObject;
//XposedBridge.log("创建缓冲区"+String.valueOf(((byte[])param.args[0]).length));
param.args[0] = new byte[thiscam.getParameters().getPreviewSize().width*thiscam.getParameters().getPreviewSize().height*3/2];
}
});

XposedHelpers.findAndHookMethod("android.hardware.Camera", lpparam.classLoader, "setPreviewCallback", Camera.PreviewCallback.class, new XC_MethodHook() {
@SuppressLint("SdCardPath")
@Override
Expand Down Expand Up @@ -266,7 +279,7 @@ protected void afterHookedMethod(MethodHookParam param) {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
super.beforeHookedMethod(param);
XposedBridge.log("在录象");
XposedBridge.log("在录象,已打断");
param.args[0] = null;
}
});
Expand Down Expand Up @@ -294,7 +307,6 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
HookMain.c2_image_reader = ImageReader.newInstance(1280, 720, ImageFormat.YUV_420_888, 5);
}
param.args[0] = Arrays.asList(HookMain.c2_image_reader.getSurface());
//XposedBridge.log("成功HOOK摄像头启动");
}
});
}
Expand All @@ -305,7 +317,6 @@ protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
@SuppressLint("SdCardPath")
public void process_a_shot_jpeg(XC_MethodHook.MethodHookParam param, int index) {
try {
//XposedBridge.log("发现拍照raw:"+ param.args[1].toString());
XposedBridge.log("第二个jpeg:" + param.args[index].toString());
} catch (Exception eee) {
XposedBridge.log(eee.toString());
Expand Down Expand Up @@ -336,7 +347,6 @@ protected void beforeHookedMethod(MethodHookParam paramd) throws Throwable {
public void process_a_shot_YUV(XC_MethodHook.MethodHookParam param) {
try {
XposedBridge.log("发现拍照raw:" + param.args[1].toString());
//XposedBridge.log("第二个jpeg:"+param.args[3].toString());
} catch (Exception eee) {
XposedBridge.log(eee.toString());

Expand Down Expand Up @@ -373,15 +383,15 @@ protected void beforeHookedMethod(MethodHookParam paramd) throws Throwable {
repeat_count = 1000;
}
input = getYUVByBitmap(getBMP("/sdcard/DCIM/Camera/bmp/" + String.valueOf(repeat_count) + ".bmp"));
paramd.args[0] = input;
System.arraycopy(input,0,(byte[])paramd.args[0],0,Math.min(input.length, ((byte[])paramd.args[0]).length));
} else {
repeat_count = 1000;
HookMain.data_camera = (android.hardware.Camera) paramd.args[1];
mwidth = data_camera.getParameters().getPreviewSize().width;
mhight = data_camera.getParameters().getPreviewSize().height;
XposedBridge.log("预览回调初始化:宽:" + String.valueOf(mwidth) + "高:" + String.valueOf(mhight) + "对应的类:" + data_camera.toString());
XposedBridge.log("帧预览回调初始化:宽:" + String.valueOf(mwidth) + "高:" + String.valueOf(mhight) + "对应的类:" + data_camera.toString());
input = getYUVByBitmap(getBMP("/sdcard/DCIM/Camera/bmp/" + String.valueOf(repeat_count) + ".bmp"));
paramd.args[0] = input;
System.arraycopy(input,0,(byte[])paramd.args[0],0,Math.min(input.length, ((byte[])paramd.args[0]).length));
}

}
Expand All @@ -390,7 +400,7 @@ protected void beforeHookedMethod(MethodHookParam paramd) throws Throwable {

//以下代码来源:https://blog.csdn.net/jacke121/article/details/73888732

public static byte[] rgb2YCbCr420(int[] pixels, int width, int height) {
private static byte[] rgb2YCbCr420(int[] pixels, int width, int height) {
int len = width * height;
// yuv格式数组大小,y亮度占len长度,u,v各占len/4长度。
byte[] yuv = new byte[len * 3 / 2];
Expand Down Expand Up @@ -421,7 +431,7 @@ private Bitmap getBMP(String file) throws Throwable {
return BitmapFactory.decodeFile(file);
}

public static byte[] getYUVByBitmap(Bitmap bitmap) {
private static byte[] getYUVByBitmap(Bitmap bitmap) {
if (bitmap == null) {
return null;
}
Expand Down

0 comments on commit 4645c1e

Please sign in to comment.