【问题标题】:Play yuv frames in Android在 Android 中播放 yuv 帧
【发布时间】:2013-02-05 07:14:30
【问题描述】:

您好,我的任务是在 android 中显示一组解码帧。在我的本机代码中,我有一个字符(char)指针,它保存解码帧的地址。我想在我的设备上显示这个框架,所以我得到了一个提示: Displaying YUV Image in Android 因此在我的活动课上我写了以下函数:

public void displayFrame(byte[] data, int fwidth,int fheight){

    ImageView frameImgView=(ImageView) findViewById(R.id.imageView2);

    ByteArrayOutputStream out=new ByteArrayOutputStream();
    YuvImage yuvimg=new YuvImage(data, ImageFormat.NV21, fwidth, fheight, null);
    yuvimg.compressToJpeg(new Rect(0, 0, fwidth, fheight), 100, out);
    byte[] imageBytes = out.toByteArray();
    Bitmap image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
    frameImgView.setImageBitmap(image);
    return;
}

因此,从我的本机代码中,我需要在 java 中调用此函数。从链接: http://www.altdevblogaday.com/2011/12/09/running-native-code-on-android-part-1/ 我开始知道如何从原生 c 调用 java 函数。 但是,要调用 java 函数,我们需要一个环境变量来执行此操作。我的 java 类我已经将 main 函数声明为 native 并为该 main 函数生成了一个标头:

JNIEXPORT jint JNICALL Java_com_example_decoder_Decoder_mainFunction(JNIEnv *env, jclass jobj, jint argc, jstring argv1, jstring argv2);

但是我的 mainFunction 调用了一个函数“fwriter(some pointer, some pointer)”,它有一个指针作为参数。我如何获得相同的环境变量。我知道在java类中我需要将“fwriter”函数声明为native但是我将指针表示为什么??

例如:我的 c 函数是:

void fwriter(int *ptr, char *ptr)
{
  ....
}

在我的 java 类中,我如何将此函数声明为本地函数? 请帮忙。 在 java/Android 中显示 YUV 的任何其他方法也将受到赞赏。 谢谢。

【问题讨论】:

    标签: java android java-native-interface


    【解决方案1】:

    虽然 JPEG 编码和解码可以在大多数手机上进行硬件加速,但我希望您自己编写的简单 RGB->YUV 转换 for-loop 会快得多(即使在没有 Java 的情况下也足够快)使用本地库)并且更简单。

    Here 是公式。如果您使用 OpenGLES 进行显示,请考虑使用 fragment shader 进行即时转换。

    最后,这是您可以在 CPU 上使用的纯整数代码:

    Ytmp =      4768 * (Y - 16);
    R = (Ytmp + 6537 * (V - 128)) >> 12;
    G = (Ytmp - 3330 * (V - 128) - 1602 * (U - 128)) >> 12;
    B = (Ytmp + 8266 * (U - 128)) >> 12;
    

    【讨论】:

    • 感谢您的回复.... +1 为您的努力...但我认为使用 openGLES 也会减慢该过程。所以我需要用c代码本身做事情。我的意思是从 yuv 到 rgb 的转换。但是,如果我的 yuv 是 yuv 4:4:4,我可以直接应用公式并转换为相应的 rgb。但我的是 YUV 4:2:0 所以你能建议我如何将它转换为 rgb 格式。将等待答复。在此先感谢...
    • @Zax 1) 如果您的目的是显示它,那么使用 GPU 将是最快的; 2)我自己为商业项目编写了代码,即使在 4:2:0 中您也可以直接应用公式,只需每隔一帧增加一些指针; 3)我将粘贴经典的整数数学yuv转换
    • 感谢您的快速回复。是的,我的主要目的是展示它。在我的本机代码中,我正在解码视频,解码的缓冲区是 yuv 格式。所以我的主要工作就是展示这个yuv框架。每次迭代都会解码一帧,我必须显示它,使其看起来像视频。所以请帮助解决同样的问题。你也有将 420 转换为 RGB 的代码吗?如果是这样,请给我发邮件。我也尝试了一些代码,但输出是一组彩色线条:(
    【解决方案2】:

    您可以使用 RenderScript 内部函数将 YUV 图像转换为位图。

    您可以一次性准备这些对象:

    RenderScript rs = RenderScript.create(getContext());
    ScriptIntrinsicYuvToRGB yuvToRgb = 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(fwidth).setY(fheight);
    Allocation out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
    
    Bitmap image = Bitmap.createBitmap(fwidth, fheight, Bitmap.Config.ARGB_8888);
    

    并且对于您执行转换的每一帧:

    in.copyFrom(data);
    
    yuvToRgb.setInput(in);
    yuvToRgb.forEach(out);
    
    out.copyTo(image);
    

    【讨论】:

    • 从哪个版本的Android可以使用这个功能?
    • Renderscript 是在 API 级别 11 中引入的,但 ScriptIntrinsicYuvToRGB 是在 API 级别 17 中添加的
    猜你喜欢
    • 2012-01-24
    • 1970-01-01
    • 2014-01-19
    • 2014-12-11
    • 1970-01-01
    • 2022-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多