2016-07-29 19 views
1

Ich wollte ein TYPE_3BYTE_BGR BufferedImage in Java zu Yuv mit der Funktion sws_scale von FFMpeg durch JNI transformieren. Ich extrahieren die Daten zuerst von meinem Bild von der BufferedImage alsSchnelle Umwandlung von BGR BufferedImage nach YUV mit FFMpeg

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

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

Dann habe ich es in die processImage Funktion übergeben, die eine native Funktion ist. Die C++ Seite sieht wie folgt aus:

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

Doch nach den Code ausgeführt wird, ich die Warnung erhalten: [swscaler @ 0x7fb598659480] Warning: data is not aligned! This can lead to a speedloss, everything crashes., und alles stürzt in der letzten Zeile. Mache ich Dinge richtig in Bezug auf die Übergabe der richtigen Argumente an sws_scale? (besonders die Schritte).

Update: Es gibt einen separaten Fehler hier war: SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)width, (int)width,0,NULL,NULL,NULL), die geändert werden sollen: SwsContext * ctx = sws_getContext(width,height,AV_PIX_FMT_BGR24, (int)height, (int)width,0,NULL,NULL,NULL)

Antwort

1

Das erste Problem, das ich sehe - falsche Schritte für die Ausgabe Bild:

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

Zugeteilte Flugzeuge sind für bestandene Fortschritte nicht groß genug. YUV420 verwendet für jeden Kanal ein Byte, so dass 3 redundant ist und zu einer Verletzung führt. Der Rescaler überspringt viel Platz, wenn er zur nächsten Zeile geht.

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

Allocation Größen bleiben die gleichen: Verwendung nächsten Als nächstes wird eine Hälfte der Luma-Breite ist tatsächlich Chroma Breite, so dass, wenn Sie an den Leitungsenden lückenlos dicht gepackten Luma und Chroma-Ebenen wollen.

+0

Vielen Dank für Ihre Antwort, aber ich habe noch einige Probleme. Wenn ich die Schritte auf yuv [1] = new einstellen uint8_t [lumaPlaneSize/2]; und yuv [1] = neu uint8_t [lumaPlaneSize/2]; scheint alles in Ordnung zu sein mit der vorgeschlagenen outputLinesize. Außer wenn ich die Ausgabe in eine Datei schreibe: fwrite (yuv [0], 1, lumaPlaneSize, fp); fwrite (yuv [1], 1, LumaPlaneSize/4, fp); fwrite (yuv [2], 1, LumaPlaneSize/4, fp); Es scheint, dass das Bild skaliert und unvollständig ist. Ich ändere zu fwrite (yuv [1 und 2], 1, lumaPlaneSize/2, fp); dann ist das Bild insgesamt schlecht Was soll ich tun? – Hossein

+1

Wie genau ein unvollständiges Bild aussieht? – Sergio

+0

vor: https://postimg.org/image/gr93ykns1/ nach: https://postimg.org/image/f0mg9dyvb/ – Hossein

1

Mit Blick auf die source, insbesondere um die Linie 321, Sie erhalten die Warnmeldung, wenn Ihr System AVX2 Anweisungen unterstützt und die verschiedenen Zeiger und Größen sind keine Vielfachen von 16. Der Absturz tritt wahrscheinlich auf, weil die Arrays, die Sie übergeben, inData, inLineSize und outLinesize, nicht die richtige Größe haben. Die Zeigerarrays müssen mindestens 3 Elemente enthalten, und die Schrittarrays müssen 4 sein. Irgendwo in sws_scale greift sie auf inData[1] zu, was außerhalb der Grenzen Ihres Arrays liegt, was zu einem schlechten Zeiger führt.

+1

"Die Zeigerarrays müssen mindestens 3 Elemente haben und die Schrittarrays müssen 4 ..." - Nein, diese Größen sind streng durch das verwendete Pixelformat definiert und im Falle von YUV420 müssen sowohl das Pufferarray als auch das Schrittarray enthalten sein genau 3 Elemente - für Y, Cr, Cb Ebenen jeweils. – Sergio