在 Android 中显示 YUV 图像

新手上路,请多包涵

在我的应用程序中,我们需要显示从服务器接收到我们的 android 应用程序的视频帧,

服务器以每秒 50 帧的速度发送视频数据,已在 WebM 中编码,即使用 libvpx 对图像进行编码和解码,

现在从 libvpx 解码后得到 YUV 数据,我们可以在图像布局上显示,

当前的实现是这样的,

在 JNI / Native C++ 代码中,我们将 YUV 数据转换为 RGB 数据 在 Android 框架中,调用

public Bitmap createImgae(byte[] bits, int width, int height, int scan) {
    Bitmap bitmap=null;
    System.out.println("video: creating bitmap");
    //try{

            bitmap = Bitmap.createBitmap(width, height,
                    Bitmap.Config.ARGB_8888);
            bitmap.copyPixelsFromBuffer(ByteBuffer.wrap(bits));

    //}catch(OutOfMemoryError ex){

    //}
            System.out.println("video: bitmap created");
    return bitmap;
}

要创建位图图像,

使用以下代码在 imageView 上显示图像,

                img = createImgae(imgRaw, imgInfo[0], imgInfo[1], 1);
               if(img!=null && !img.isRecycled()){

                    iv.setImageBitmap(img);
                    //img.recycle();
                    img=null;
                    System.out.println("video: image displayed");
                }

我的问题是,总体而言,此功能大约需要 40 毫秒,有什么方法可以优化它,

1 - 有什么方法可以将 YUV 数据显示到 imageView 吗?

2 – 有没有其他方法可以从 RGB 数据创建图像(位图图像),

3 – 我相信我总是在创建图像,但我想我应该只创建一次位图,并在我们收到时始终执行/提供新缓冲区。

请分享你的看法。

原文由 Amitg2k12 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.5k
2 个回答

以下代码解决了您的问题,并且在 Yuv 格式数据上花费的时间可能更少,因为 YuvImage 类是随 Android-SDK 一起提供的。

你可以试试这个,

 ByteArrayOutputStream out = new ByteArrayOutputStream();
YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, width, height, null);
yuvImage.compressToJpeg(new Rect(0, 0, width, height), 50, out);
byte[] imageBytes = out.toByteArray();
Bitmap image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
iv.setImageBitmap(image);

要么

void yourFunction(byte[] data, int mWidth, int mHeight)
{

int[] mIntArray = new int[mWidth*mHeight];

// Decode Yuv data to integer array
decodeYUV420SP(mIntArray, data, mWidth, mHeight);

//Initialize the bitmap, with the replaced color
Bitmap bmp = Bitmap.createBitmap(mIntArray, mWidth, mHeight, Bitmap.Config.ARGB_8888);

// Draw the bitmap with the replaced color
iv.setImageBitmap(bmp);

}

static public void decodeYUV420SP(int[] rgba, byte[] yuv420sp, int width,
    int height) {
final int frameSize = width * height;

for (int j = 0, yp = 0; j < height; j++) {
    int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
    for (int i = 0; i < width; i++, yp++) {
        int y = (0xff & ((int) yuv420sp[yp])) - 16;
        if (y < 0)
            y = 0;
        if ((i & 1) == 0) {
            v = (0xff & yuv420sp[uvp++]) - 128;
            u = (0xff & yuv420sp[uvp++]) - 128;
        }

        int y1192 = 1192 * y;
        int r = (y1192 + 1634 * v);
        int g = (y1192 - 833 * v - 400 * u);
        int b = (y1192 + 2066 * u);

        if (r < 0)
            r = 0;
        else if (r > 262143)
            r = 262143;
        if (g < 0)
            g = 0;
        else if (g > 262143)
            g = 262143;
        if (b < 0)
            b = 0;
        else if (b > 262143)
            b = 262143;

        // rgb[yp] = 0xff000000 | ((r << 6) & 0xff0000) | ((g >> 2) &
        // 0xff00) | ((b >> 10) & 0xff);
        // rgba, divide 2^10 ( >> 10)
        rgba[yp] = ((r << 14) & 0xff000000) | ((g << 6) & 0xff0000)
                | ((b >> 2) | 0xff00);
    }
}
}

原文由 Hitesh Patel 发布,翻译遵循 CC BY-SA 3.0 许可协议

另一种方法是使用 ScriptIntrinsicYuvToRGB ,这比每次 JPEG 编码(和解码)更有效

fun yuvByteArrayToBitmap(bytes: ByteArray, width: Int, height: Int): Bitmap {
    val rs = RenderScript.create(this)

    val yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
    val yuvType = Type.Builder(rs, Element.U8(rs)).setX(bytes.size);
    val input = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);

    val rgbaType = Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
    val output = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);

    input.copyFrom(bytes);

    yuvToRgbIntrinsic.setInput(input);
    yuvToRgbIntrinsic.forEach(output);

    val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
    output.copyTo(bitmap)

    input.destroy()
    output.destroy()
    yuvToRgbIntrinsic.destroy()
    rs.destroy()

    return bitmap
}

原文由 wiomoc 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题