Quería transformar una TYPE_3BYTE_BGR BufferedImage en Java a yuv usando la función sws_scale de FFMpeg a través de JNI. Primero extraigo los datos de mi imagen de BufferedImage como

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

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

Luego lo paso a la función processImage, que es una función nativa. El lado de C ++ se ve así:

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);

Sin embargo, después de ejecutar el código, aparece la advertencia: [swscaler @ 0x7fb598659480] Warning: data is not aligned! This can lead to a speedloss, everything crashes. y todo falla en la última línea. ¿Estoy haciendo las cosas correctamente en términos de pasar los argumentos correctos a sws_scale? (especialmente las zancadas).

Actualización: Había un error aparte aquí: SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)width, (int)width,0,NULL,NULL,NULL) que debería cambiarse a: SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)height, (int)width,0,NULL,NULL,NULL)

1
Hossein 30 jul. 2016 a las 01:51

2 respuestas

La mejor respuesta

El primer problema que veo: pasos incorrectos para la imagen de salida:

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
//                     ^^^^^^^  ^^^^^^^  ^^^^^^^

Los planos asignados no son lo suficientemente grandes para las zancadas pasadas. YUV420 usa un byte para cada canal, por lo que 3 es redundante y conduce a una violación limitada. debido rescaler se salta mucho espacio cuando pasa a la siguiente línea. A continuación, el ancho de croma real es la mitad del ancho de luma, por lo que si desea planos de crominancia y luma compactos sin espacios en los extremos de la línea, utilice lo siguiente:

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

Los tamaños de asignación siguen siendo los mismos.

2
Sergio 1 ago. 2016 a las 08:55

Mirando la fuente, en particular alrededor de la línea 321, aparece ese mensaje de advertencia si su sistema admite instrucciones AVX2 y los distintos punteros y tamaños no son múltiplos de 16. El bloqueo probablemente se deba a que las matrices que ingresa, inData, inLineSize y outLinesize, no son las adecuadas Talla. Las matrices de punteros deben tener al menos 3 elementos, y las matrices de stride necesitan 4. En algún lugar de sws_scale está accediendo a inData[1] que está fuera de los límites de su matriz, lo que da como resultado un puntero incorrecto.

1
1201ProgramAlarm 30 jul. 2016 a las 00:27