Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Android Fast YUV420P到ARGB8888的转换_Java_Android_C_Data Conversion - Fatal编程技术网

Java Android Fast YUV420P到ARGB8888的转换

Java Android Fast YUV420P到ARGB8888的转换,java,android,c,data-conversion,Java,Android,C,Data Conversion,我正在使用Android的MediaCodec API对来自网络的H.264编码视频数据进行解码,以进行实时流媒体传输 我知道,通过将解码器配置为在表面模式下运行,我可以直接将视频渲染到视图 然而,通过这样做,输出视频在某些平台上显示色带。出现此问题的目标平台是运行在Intel Celeron N2930处理器上的Android-x86 6.0 经过无数次的尝试来解决这个问题,我决定使用被称为ByteBuffer模式的解码器。在这种模式下,我接收字节缓冲区中的解码视频帧,字节缓冲区存储帧像素的颜

我正在使用Android的MediaCodec API对来自网络的H.264编码视频数据进行解码,以进行实时流媒体传输

我知道,通过将解码器配置为在表面模式下运行,我可以直接将视频渲染到视图

然而,通过这样做,输出视频在某些平台上显示色带。出现此问题的目标平台是运行在Intel Celeron N2930处理器上的Android-x86 6.0

经过无数次的尝试来解决这个问题,我决定使用被称为ByteBuffer模式的解码器。在这种模式下,我接收字节缓冲区中的解码视频帧,字节缓冲区存储帧像素的颜色值

对于我上面提到的目标平台,输出的视频帧是YUV420p。要在视图上显示视频帧,必须首先将其转换为位图。在创建位图之前,我应该首先将帧颜色格式转换为argb888

最初我用Java进行转换,但是这个过程太慢,对于实时流媒体来说没有任何用处,大约300+毫秒。然后我用本机C代码进行转换。设法将时间缩短到一半左右,但对于1920x1080视频而言,速度仍然太慢,无法达到20 fps

JNIEXPORT jintArray JNICALL
Java_my_package_name_class_convertYUV420PToARGB8888_1Native2(
        JNIEnv *env, jclass type, jbyteArray data_, jint width, jint height) {
    jbyte *data = (*env)->GetByteArrayElements(env, data_, NULL);
    if (!data) {
        __android_log_print(ANDROID_LOG_ERROR, TAG,
        return NULL;
    }

    const jint frameSize = width * height;
    const jint offset_u = frameSize;
    const jint offset_v = frameSize + frameSize / 4;

    jint *pixels = malloc(sizeof(jint) * frameSize);
    jint u, v, y1, y2, y3, y4;

    // i percorre os Y and the final pixels
    // k percorre os pixles U e V
    jint i;
    jint k;
    for (i = 0, k = 0; i < frameSize; i += 2, k += 1) {
        // process 2*2 pixels in one iteration
        y1 = data[i] & 0xff;
        y2 = data[i + 1] & 0xff;
        y3 = data[offset + i] & 0xff;
        y4 = data[width + i + 1] & 0xff;

        u = data[offset_u + k] & 0xff;
        v = data[offset_v + k] & 0xff;
        u = u - 128;
        v = v - 128;

        pixels[i] = convertYUVtoRGB(y1, u, v);
        pixels[i + 1] = convertYUVtoRGB(y2, u, v);
        pixels[width + i] = convertYUVtoRGB(y3, u, v);
        pixels[width + i + 1] = convertYUVtoRGB(y4, u, v);

        if (i != 0 && (i + 2) % width == 0) {
            i += width;
        }
    }

    jintArray result = (*env)->NewIntArray(env, frameSize);
    if (!result) {
        return NULL;
    }

    (*env)->SetIntArrayRegion(env, /* env */
                              result, /* array */
                              0, /* start */
                              frameSize, /* len */
                              pixels /* buf */
    );

    // free resources
    free(pixels);
    (*env)->ReleaseByteArrayElements(env,
                                     data_, /* array */
                                     data, /* elems */
                                     JNI_ABORT /* mode */
    );

    return result;
}

static jint convertYUVtoRGB(jint y, jint u, jint v) {
    jint r, g, b;

    r = y + (int) 1.402f * v;
    g = y - (int) (0.344f * u + 0.714f * v);
    b = y + (int) 1.772f * u;

    r = r > 255 ? 255 : r < 0 ? 0 : r;
    g = g > 255 ? 255 : g < 0 ? 0 : g;
    b = b > 255 ? 255 : b < 0 ? 0 : b;

    return 0xff000000 | (r << 16) | (g << 8) | b;
}
JNIEXPORT金塔瑞JNICALL
Java_my_package_name_class_ConvertYUV420PTORGB8888_1Native2(
JNIEnv*env,jclass类型,jbyteArray数据,jint宽度,jint高度){
jbyte*data=(*env)->GetByteArrayElements(env,data,NULL);
如果(!数据){
__安卓日志打印(安卓日志错误、标签、,
返回NULL;
}
const jint frameSize=宽度*高度;
const jint offset_=帧大小;
const jint offset_v=帧大小+帧大小/4;
jint*像素=malloc(sizeof(jint)*帧大小);
jint u、v、y1、y2、y3、y4;
//i percorre os Y和最终像素
//k percorre os pixles U e V
金特一世;
金特k;
对于(i=0,k=0;iNewIntArray(env,frameSize);
如果(!结果){
返回NULL;
}
(*env)->SetIntArrayRegion(env,/*env*/
结果,/*数组*/
0,/*开始*/
帧大小,/*len*/
像素/*buf*/
);
//免费资源
自由(像素);
(*env)->按环境发布,
数据,/*数组*/
数据,/*元素*/
JNI_中止/*模式*/
);
返回结果;
}
静态进料变换器(进料y、进料u、进料v){
金特r,g,b;
r=y+(int)1.402f*v;
g=y-(int)(0.344f*u+0.714f*v);
b=y+(int)1.772f*u;
r=r>255?255:r<0?0:r;
g=g>255?255:g<0?0:g;
b=b>255?255:b<0?0:b;

return 0xff000000 |(r通过使用ffmpeg中的libswscale库解决了这个问题。

@user3528438…我实际上知道这个方法,即使用整数乘法,然后用移位除法。但是,我试过了,并不认为它快得多。以下是一些测量方法:1)方法2在Approx原生:~140毫秒,2)method2浮点本机:~175毫秒,3)method2浮点java:~265毫秒,4)method2浮点java:~345毫秒,5)method1浮点本机:~180毫秒,6)method1浮点java:~420毫秒。方法1每次迭代处理1个像素,方法2每次迭代处理2x2个像素,原因是这4个像素共享相同的U和V值。