使用FFMpeg将BGR BufferedImage快速转换为YUV

时间:2016-07-29 22:51:53

标签: java c++ ffmpeg java-native-interface

我想使用FFMpeg的sws_scale函数通过JNI将Java中的TYPE_3BYTE_BGR BufferedImage转换为yuv。我首先从BufferedImage中提取我的图像数据

    byte[] imgData = ((DataBufferByte) myImage.getRaster().getDataBuffer()).getData();

    byte[] output = processImage(toSend,0);     

然后我将它传递给processImage函数,这是一个本机函数。 C ++方面如下所示:

JNIEXPORT jbyteArray JNICALL Java_jni_JniExample_processData
  (JNIEnv *env, jobject obj, jbyteArray data, jint index)
{

    jboolean isCopy;
    uint8_t *test  = (uint8_t *)env->GetPrimitiveArrayCritical(data, &isCopy);
    uint8_t *inData[1]; // RGB24 have one plane
    inData[0] = test;


SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)width, (int)width,
        AV_PIX_FMT_YUV420P, 0, 0, 0, 0);

    int lumaPlaneSize = width *height;
    uint8_t *yuv[3];

    yuv[0] = new uint8_t[lumaPlaneSize];
    yuv[1] = new uint8_t[lumaPlaneSize/4];
    yuv[2] = new uint8_t[lumaPlaneSize/4];

    int inLinesize[1] = { 3*nvEncoder->width }; // RGB stride
    int outLinesize[3] = { 3*width ,3*width ,3*width }; // YUV stride

    sws_scale(ctx, inData, inLinesize, 0, height , yuv, outLinesize);

但是,运行代码后,我收到警告:[swscaler @ 0x7fb598659480] Warning: data is not aligned! This can lead to a speedloss, everything crashes.,一切都在最后一行崩溃。我是否正确地将正确的参数传递给sws_scale? (特别是步伐)。

更新 此处有一个单独的错误:SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)width, (int)width,0,NULL,NULL,NULL)应更改为:SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)height, (int)width,0,NULL,NULL,NULL)

2 个答案:

答案 0 :(得分:1)

查看source,特别是在第321行附近,如果您的系统支持AVX2指令并且各种指针和大小不是16的倍数,则会收到该警告消息。崩溃可能是因为阵列是您的传入,inDatainLineSizeoutLinesize的尺寸不合适。指针数组需要至少有3个元素,并且步长数组需要4. sws_scale中的某个地方正在访问inData[1],它超出了数组的边界,导致指针错误。

答案 1 :(得分:1)

我看到的第一个问题 - 输出图像的步幅错误:

yuv[0] = new uint8_t[lumaPlaneSize];
yuv[1] = new uint8_t[lumaPlaneSize/4];
yuv[2] = new uint8_t[lumaPlaneSize/4];

int inLinesize[1] = { 3*nvEncoder->width }; // RGB stride
int outLinesize[3] = { 3*width ,3*width ,3*width }; // YUV stride
//                     ^^^^^^^  ^^^^^^^  ^^^^^^^

分配的飞机不足以通过步幅。 YUV420为每个通道使用一个字节,因此3是多余的,并导致绑定违规。到达下一行时,到期的rescaler会跳过很多空间。接下来,实际的色度宽度是亮度宽度的一半,所以如果你想要紧凑的亮度和色度平面,在线端没有间隙,请使用下一个:

int outLinesize[3] = { width , width / 2 , width / 2 }; // YUV stride

分配大小保持不变。