当前位置:   article > 正文

安卓虚拟相机虚拟摄像头插件,IOS苹果iphone,微信QQ都支持,提供dex\hook类代码

安卓虚拟相机

核心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;

    }

}

================================================================= 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/324598
推荐阅读
  

闽ICP备14008679号