如何使用Android Camera2处理视频的每一帧并在帧之间移动像素

时间:2019-11-04 14:03:00

标签: android-camera2

我是Android新手,在我的应用程序中,我需要从摄像机接收视频并混合不同帧中的像素。我尝试使用mediaMetaDataRetriever从捕获的视频中获取帧,但是花费的时间太长。现在,我使用ImageReader来获取每个实时帧,创建一个位图并将其放入数组中。这将占用非常多的RAM空间。并且此数组具有三个周期的后续处理也很长。 那么,如何使用Camera2解决此问题?

混合位图数组:

 val outputFrames = arrayOfNulls<Bitmap>(1080)
    var videoDuration = frames.size
    if(videoDuration%2 != 0) videoDuration--
    var index = 0
    while (index < videoDuration) {
        var indexWidth = 1079
        while (indexWidth >= 0) {
            var indexHeight = 1919
            while (indexHeight >= 0) {
                if (outputFrames[indexWidth] == null) {
                    outputFrames[indexWidth] =
                        Bitmap.createBitmap(videoDuration, 1920, Bitmap.Config.ARGB_8888)
                    outputFrames[indexWidth]!![index, indexHeight] =
                        frames[0][indexWidth, indexHeight]
                } else outputFrames[indexWidth]!![index, indexHeight] =
                    frames[0][indexWidth, indexHeight]
                //Log.e("frame:", "$indexWidth $indexHeight /${outputFrames[indexWidth]}/")
                indexHeight--
            }
            indexWidth--
        }
        frames.removeAt(0)
        index++
    }

我的图片阅读器:

mImageReader = ImageReader.newInstance(mWidth,mHeight, PixelFormat.RGBA_8888,1)
    mImageReader.setOnImageAvailableListener(
        { reader ->
            val image = reader.acquireLatestImage()
            val planes = image.planes
            val buffer = planes[0].buffer
            val offset = 0
            val pixelStride = planes[0].pixelStride
            val rowStride = planes[0].rowStride
            val rowPadding = rowStride - pixelStride * mWidth
            // create bitmap
            val bitmap = Bitmap.createBitmap(
                mWidth + rowPadding / pixelStride,
                mHeight,
                Bitmap.Config.ARGB_8888
            )
            bitmap.copyPixelsFromBuffer(buffer)
            image.close()

        },
        mBackgroundHandler)

1 个答案:

答案 0 :(得分:0)

创建位图非常昂贵,并且会降低您的App的运行速度。尝试将您的图片获取为:

mImageReader = ImageReader.newInstance(DISPLAY_WIDTH, DISPLAY_HEIGHT, ImageFormat.YUV_420_888, Runtime.getRuntime().availableProcessors());

然后,您可以使用ScriptIntrinsicYuvToRGB来创建位图,例如:

Image.Plane Y = mImage.getPlanes()[0];
        Image.Plane U = mImage.getPlanes()[1];
        Image.Plane V = mImage.getPlanes()[2];

        int Yb = Y.getBuffer().remaining();
        int Ub = U.getBuffer().remaining();
        int Vb = V.getBuffer().remaining();

        byte[] data = new byte[Yb + Ub + Vb];

        Y.getBuffer().get(data, 0, Yb);
        V.getBuffer().get(data, Yb, Vb);
        U.getBuffer().get(data, Yb + Vb, Ub);

        RenderScript rs = RenderScript.create(Main2Activity.this);
        ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));

        Type.Builder yuvType = new Type.Builder(rs, Element.U8(rs)).setX(data.length);
        Allocation in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);

        Type.Builder rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(DISPLAY_WIDTH).setY(DISPLAY_HEIGHT);
        Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);

        final Bitmap bmpout = Bitmap.createBitmap(DISPLAY_WIDTH, DISPLAY_HEIGHT, Bitmap.Config.ARGB_8888);

        in.copyFromUnchecked(data);

        yuvToRgbIntrinsic.setInput(in);
        yuvToRgbIntrinsic.forEach(out);
        out.copyTo(bmpout);

如果在后台线程中使用此代码,它将大大加快所有操作。