核心HOOK思路源码开源了,仅供学习,用的一个java类实现的,但是成品我不提供奥,就提供下实现虚拟视频hook类的java代码【我已经把dex文件里面实现hook的字节码代码转换成java代码了】,仅供大家研究,用工具是Smali将字节码代码转换为Java代码,工具下面地址可以自己网上搜。
下面是我测试一个效果视频【仅供学习】:
虚拟摄像头插件,玩玩,支持微信QQ,替换摄像头,还是开源的!!!
下面是实现HOOk的java代码,我已经用Smali导出来了:
===================================================================
//
// Decompiled by Jadx - 791ms
//
package com.exampsle.vcam;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.media.Image;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCrypto;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.util.Log;
import android.view.Surface;
import de.robv.android.xposed.XposedBridge;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.nio.ByteBuffer;
import java.util.concurrent.LinkedBlockingQueue;
public class VideoToFrames implements Runnable {
private static final int COLOR_FormatI420 = 1;
private static final int COLOR_FormatNV21 = 2;
private static final long DEFAULT_TIMEOUT_US = 10000;
private static final String TAG = "VideoToFrames";
private static final boolean VERBOSE = false;
private Callback callback;
private Thread childThread;
private LinkedBlockingQueue<byte[]> mQueue;
private OutputImageFormat outputImageFormat;
private Surface play_surf;
private Throwable throwable;
private String videoFilePath;
private final int decodeColorFormat = 0x7f420888;
private boolean stopDecode = false;
public void setCallback(Callback callback) {
this.callback = callback;
}
public void setEnqueue(LinkedBlockingQueue<byte[]> linkedBlockingQueue) {
this.mQueue = linkedBlockingQueue;
}
public void setSaveFrames(String str, OutputImageFormat outputImageFormat) throws IOException {
this.outputImageFormat = outputImageFormat;
}
public void set_surfcae(Surface surface) {
if (surface != null) {
this.play_surf = surface;
}
}
public void stopDecode() {
this.stopDecode = true;
}
public void decode(String str) throws Throwable {
this.videoFilePath = str;
if (this.childThread == null) {
Thread thread = new Thread(this, "decode");
this.childThread = thread;
thread.start();
Throwable th = this.throwable;
if (th != null) {
throw th;
}
}
}
@Override
public void run() {
try {
videoDecode(this.videoFilePath);
} catch (Throwable th) {
this.throwable = th;
}
}
/* JADX WARN: Multi-variable type inference failed */
/* JADX WARN: Removed duplicated region for block: B:32:0x00c1 */
/* JADX WARN: Removed duplicated region for block: B:34:0x00c9 */
/* JADX WARN: Type inference failed for: r0v1, types: [android.media.MediaCodec, android.media.MediaExtractor] */
/* JADX WARN: Type inference failed for: r0v3 */
/* JADX WARN: Type inference failed for: r0v4, types: [android.media.MediaCodec] */
/* JADX WARN: Type inference failed for: r0v5 */
/*
Code decompiled incorrectly, please refer to instructions dump.
*/
public void videoDecode(String str) throws IOException {
MediaExtractor mediaExtractor;
XposedBridge.log("【VCAM】【decoder】开始解码");
MediaCodec mediaCodec = 0;
mediaCodec = 0;
try {
try {
new File(str);
mediaExtractor = new MediaExtractor();
try {
mediaExtractor.setDataSource(str);
int selectTrack = selectTrack(mediaExtractor);
if (selectTrack < 0) {
XposedBridge.log("【VCAM】【decoder】No video track found in " + str);
}
mediaExtractor.selectTrack(selectTrack);
MediaFormat trackFormat = mediaExtractor.getTrackFormat(selectTrack);
String string = trackFormat.getString("mime");
mediaCodec = MediaCodec.createDecoderByType(string);
showSupportedColorFormat(mediaCodec.getCodecInfo().getCapabilitiesForType(string));
if (isColorFormatSupported(0x7f420888, mediaCodec.getCodecInfo().getCapabilitiesForType(string))) {
trackFormat.setInteger("color-format", 0x7f420888);
XposedBridge.log("【VCAM】【decoder】set decode color format to type 2135033992");
} else {
Log.i(TAG, "unable to set decode color format, color format type 0x7f420888 not supported");
XposedBridge.log("【VCAM】【decoder】unable to set decode color format, color format type 0x7f420888 not supported");
}
decodeFramesToImage(mediaCodec, mediaExtractor, trackFormat);
mediaCodec.stop();
while (!this.stopDecode) {
mediaExtractor.seekTo(0L, 0);
decodeFramesToImage(mediaCodec, mediaExtractor, trackFormat);
mediaCodec.stop();
}
if (mediaCodec != 0) {
mediaCodec.stop();
mediaCodec.release();
}
} catch (Exception e) {
e = e;
XposedBridge.log("【VCAM】[videofile]" + e.toString());
if (mediaCodec != 0) {
mediaCodec.stop();
mediaCodec.release();
}
if (mediaExtractor == null) {
return;
}
mediaExtractor.release();
}
} catch (Throwable th) {
th = th;
if (0 != 0) {
mediaCodec.stop();
mediaCodec.release();
}
if (0 != 0) {
mediaCodec.release();
}
throw th;
}
} catch (Exception e2) {
e = e2;
mediaExtractor = null;
} catch (Throwable th2) {
th = th2;
if (0 != 0) {
}
if (0 != 0) {
}
throw th;
}
mediaExtractor.release();
}
private void showSupportedColorFormat(MediaCodecInfo.CodecCapabilities codecCapabilities) {
System.out.print("supported color format: ");
int[] iArr = codecCapabilities.colorFormats;
int length = iArr.length;
for (int i = 0; i < length; i += COLOR_FormatI420) {
int i2 = iArr[i];
PrintStream printStream = System.out;
printStream.print(i2 + "\t");
}
System.out.println();
}
private boolean isColorFormatSupported(int i, MediaCodecInfo.CodecCapabilities codecCapabilities) {
int[] iArr = codecCapabilities.colorFormats;
int length = iArr.length;
for (int i2 = 0; i2 < length; i2 += COLOR_FormatI420) {
if (iArr[i2] == i) {
return true;
}
}
return false;
}
private void decodeFramesToImage(MediaCodec mediaCodec, MediaExtractor mediaExtractor, MediaFormat mediaFormat) {
long j;
int dequeueInputBuffer;
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
mediaCodec.configure(mediaFormat, this.play_surf, (MediaCrypto) null, 0);
mediaCodec.start();
mediaFormat.getInteger("width");
mediaFormat.getInteger("height");
boolean z = false;
boolean z2 = false;
int i = 0;
boolean z3 = false;
long j2 = 0;
while (!z && !this.stopDecode) {
if (z2 || (dequeueInputBuffer = mediaCodec.dequeueInputBuffer(DEFAULT_TIMEOUT_US)) < 0) {
j = 10000;
} else {
int readSampleData = mediaExtractor.readSampleData(mediaCodec.getInputBuffer(dequeueInputBuffer), 0);
if (readSampleData < 0) {
j = 10000;
z2 = true;
mediaCodec.queueInputBuffer(dequeueInputBuffer, 0, 0, 0L, 4);
} else {
j = 10000;
mediaCodec.queueInputBuffer(dequeueInputBuffer, 0, readSampleData, mediaExtractor.getSampleTime(), 0);
mediaExtractor.advance();
}
}
int dequeueOutputBuffer = mediaCodec.dequeueOutputBuffer(bufferInfo, j);
if (dequeueOutputBuffer >= 0) {
boolean z4 = (bufferInfo.flags & 4) != 0 ? true : z;
if (bufferInfo.size != 0) {
i += COLOR_FormatI420;
Callback callback = this.callback;
if (callback != null) {
callback.onDecodeFrame(i);
}
if (!z3) {
j2 = System.currentTimeMillis();
z3 = true;
}
if (this.play_surf == null) {
Image outputImage = mediaCodec.getOutputImage(dequeueOutputBuffer);
ByteBuffer buffer = outputImage.getPlanes()[0].getBuffer();
byte[] bArr = new byte[buffer.remaining()];
buffer.get(bArr);
LinkedBlockingQueue<byte[]> linkedBlockingQueue = this.mQueue;
if (linkedBlockingQueue != null) {
try {
linkedBlockingQueue.put(bArr);
} catch (InterruptedException e) {
XposedBridge.log("【VCAM】" + e.toString());
}
}
if (this.outputImageFormat != null) {
HookMain.data_buffer = getDataFromImage(outputImage, COLOR_FormatNV21);
}
outputImage.close();
}
long currentTimeMillis = (bufferInfo.presentationTimeUs / 1000) - (System.currentTimeMillis() - j2);
if (currentTimeMillis > 0) {
try {
Thread.sleep(currentTimeMillis);
} catch (InterruptedException e2) {
XposedBridge.log("【VCAM】" + e2.toString());
XposedBridge.log("【VCAM】线程延迟出错");
}
}
mediaCodec.releaseOutputBuffer(dequeueOutputBuffer, true);
}
z = z4;
}
}
Callback callback2 = this.callback;
if (callback2 != null) {
callback2.onFinishDecode();
}
}
private static int selectTrack(MediaExtractor mediaExtractor) {
int trackCount = mediaExtractor.getTrackCount();
for (int i = 0; i < trackCount; i += COLOR_FormatI420) {
if (mediaExtractor.getTrackFormat(i).getString("mime").startsWith("video/")) {
return i;
}
}
return -1;
}
private static boolean isImageFormatSupported(Image image) {
int format = image.getFormat();
return format == 17 || format == 35 || format == 0x32315659;
}
/* JADX WARN: Removed duplicated region for block: B:30:0x007a */
/* JADX WARN: Removed duplicated region for block: B:31:0x007d */
/* JADX WARN: Removed duplicated region for block: B:34:0x0098 */
/*
Code decompiled incorrectly, please refer to instructions dump.
*/
private static byte[] getDataFromImage(Image image, int i) {
int i2;
int i3;
Rect rect;
int i4;
int i5 = i;
int i6 = COLOR_FormatNV21;
int i7 = COLOR_FormatI420;
if (i5 != COLOR_FormatI420 && i5 != COLOR_FormatNV21) {
throw new IllegalArgumentException("only support COLOR_FormatI420 and COLOR_FormatNV21");
}
if (!isImageFormatSupported(image)) {
throw new RuntimeException("can't convert Image to byte array, format " + image.getFormat());
}
Rect cropRect = image.getCropRect();
int format = image.getFormat();
int width = cropRect.width();
int height = cropRect.height();
Image.Plane[] planes = image.getPlanes();
int i8 = width * height;
byte[] bArr = new byte[(ImageFormat.getBitsPerPixel(format) * i8) / 8];
byte[] bArr2 = new byte[planes[0].getRowStride()];
int i9 = 0;
int i10 = 0;
int i11 = COLOR_FormatI420;
while (i9 < planes.length) {
if (i9 == 0) {
i10 = 0;
} else if (i9 != i7) {
if (i9 == i6) {
if (i5 == i7) {
i10 = (int) (i8 * 1.25d);
} else if (i5 == i6) {
i10 = i8;
i11 = COLOR_FormatNV21;
}
}
ByteBuffer buffer = planes[i9].getBuffer();
int rowStride = planes[i9].getRowStride();
int pixelStride = planes[i9].getPixelStride();
int i12 = i9 == 0 ? 0 : COLOR_FormatI420;
int i13 = width >> i12;
i2 = height >> i12;
int i14 = width;
buffer.position(((cropRect.top >> i12) * rowStride) + ((cropRect.left >> i12) * pixelStride));
i3 = 0;
while (i3 < i2) {
if (pixelStride == COLOR_FormatI420 && i11 == COLOR_FormatI420) {
buffer.get(bArr, i10, i13);
i10 += i13;
rect = cropRect;
i4 = i13;
} else {
rect = cropRect;
i4 = ((i13 - 1) * pixelStride) + COLOR_FormatI420;
buffer.get(bArr2, 0, i4);
for (int i15 = 0; i15 < i13; i15 += COLOR_FormatI420) {
bArr[i10] = bArr2[i15 * pixelStride];
i10 += i11;
}
}
if (i3 < i2 - 1) {
buffer.position((buffer.position() + rowStride) - i4);
}
i3 += COLOR_FormatI420;
cropRect = rect;
}
i9 += COLOR_FormatI420;
i5 = i;
width = i14;
i6 = COLOR_FormatNV21;
i7 = COLOR_FormatI420;
} else if (i5 == i7) {
i10 = i8;
} else {
if (i5 == i6) {
i10 = i8 + COLOR_FormatI420;
i11 = COLOR_FormatNV21;
}
ByteBuffer buffer2 = planes[i9].getBuffer();
int rowStride2 = planes[i9].getRowStride();
int pixelStride2 = planes[i9].getPixelStride();
if (i9 == 0) {
}
int i132 = width >> i12;
i2 = height >> i12;
int i142 = width;
buffer2.position(((cropRect.top >> i12) * rowStride2) + ((cropRect.left >> i12) * pixelStride2));
i3 = 0;
while (i3 < i2) {
}
i9 += COLOR_FormatI420;
i5 = i;
width = i142;
i6 = COLOR_FormatNV21;
i7 = COLOR_FormatI420;
}
i11 = COLOR_FormatI420;
ByteBuffer buffer22 = planes[i9].getBuffer();
int rowStride22 = planes[i9].getRowStride();
int pixelStride22 = planes[i9].getPixelStride();
if (i9 == 0) {
}
int i1322 = width >> i12;
i2 = height >> i12;
int i1422 = width;
buffer22.position(((cropRect.top >> i12) * rowStride22) + ((cropRect.left >> i12) * pixelStride22));
i3 = 0;
while (i3 < i2) {
}
i9 += COLOR_FormatI420;
i5 = i;
width = i1422;
i6 = COLOR_FormatNV21;
i7 = COLOR_FormatI420;
}
return bArr;
}
}文章来源:https://www.toymoban.com/news/detail-795757.html
================================================================= 文章来源地址https://www.toymoban.com/news/detail-795757.html
到了这里,关于安卓虚拟相机虚拟摄像头插件,IOS苹果iphone,微信QQ都支持,提供dex\hook类代码的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!