2012-06-14 8 views
5

Ich arbeite an einer kleinen Android-App, um einige Kamerabilder (als eine Reihe von JPEGs) zu meinem Computer zu streamen. Ohne Bildverarbeitung empfängt der Framebuffer Kamera-Vorschaubilder mit etwa 18 fps. Wenn ich inMein JNI JPEG-Encoder für Android ist wirklich langsam

YuvImage yuv = new YuvImage(data, ImageFormat.NV21, dimensions.width, dimensions.height, null); 
yuv.compressToJpeg(new Rect(0, 0, dimensions.width, dimensions.height), 40, out); 

hinzufügen, fällt die Bildrate auf etwa 7 fps. Also dachte ich, ich würde meinen eigenen JPEG-Encoder in C schreiben und etwas beschleunigen. Nun, ich war überrascht. Ich bekomme jetzt 0.4 fps!

Jetzt muss ich meinen C-Code profilieren und optimieren, aber ich weiß nicht wirklich wo ich anfangen soll. Ich verwende diese GCC-Flags:

-Wall -std=c99 -ffast-math -O3 -funroll-loops 

Gibt es etwas, das ich dort verbessern kann?

Ansonsten ist mein JPEG-Encoder nur eine einfache Implementierung. Schreibe Header-Informationen, schreibe Quantisierungs- und Huffman-Tabellen, dann kodiere Entropie die Daten. Die DCT verwendet AA & N Methode ich glaube, ist der schnellste Weg, dies zu tun.

Vielleicht gibt es ein Problem mit dem JNI Overhead?

ich den Speicher in Java Zuweisung mit:

frame_buffer = ByteBuffer.allocate(raw_preview_buffer_size).array(); 
jpeg_buffer = ByteBuffer.allocate(10000000).array(); 

und es dann mit diesem Code in Zug (verzeihen Sie die Spaghetti im Moment):

void Java_com_nechtan_limelight_activities_CameraPreview_handleFrame(JNIEnv* env, jobject this, jbyteArray nv21data, jbyteArray jpeg_buffer) { 
    jboolean isCopyNV21; 
    jboolean isCopyJPEG; 
    int jpeg_size = 0; 

    jbyte* nv21databytes = (*env)->GetByteArrayElements(env, nv21data, &isCopyNV21); 
    jbyte* jpeg_buffer_bytes = (*env)->GetByteArrayElements(env, jpeg_buffer, &isCopyJPEG); 

    if (nv21databytes != NULL) { 
     if (jpeg_buffer_bytes != NULL) { 
      jpeg_size = compressToJpeg((UCHAR*) nv21databytes, (UCHAR*) jpeg_buffer_bytes, 640, 480); 
      (*env)->ReleaseByteArrayElements(env, jpeg_buffer, jpeg_buffer_bytes, 0); 
      (*env)->ReleaseByteArrayElements(env, nv21data, nv21databytes, JNI_ABORT); 
      } 
     else { 
      __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "JPEG data null!"); 
      } 
     } 
    else { 
     __android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, "NV21 data null!"); 
     } 

    } 

Mache ich etwas ineffizient Hier? Was ist eine gute Möglichkeit, JNI-Code zu profilieren?

Abgesehen von diesen Dingen kann ich nur daran denken, dass ich über NEON lesen und dieses Zeug vektorisieren muss. Ugh ...

+2

einen fertigen Encoder, wo jemand bereits alles vernünftige Optimierung täte, würde der logische erste Schritt sein. Es kann auch ratsam sein, die Komprimierung von der Akquisition zu entkoppeln. –

+1

Wenn Sie Speicher in Java zuweisen und ihn dann im nativen Modus verwenden, wird die Leistung beeinträchtigt. Sie können Speicherzuweisung und Datei-I/O innerhalb von nativem Code durchführen und es wird viel besser funktionieren. Ich kann Ihren JPEG-Code nicht kommentieren, weil Sie ihn nicht geteilt haben, aber mein nativer JPEG-Encoder/Decoder funktioniert unter Android gut, indem Sie alles auf der nativen Seite behalten. – BitBank

+0

@Seva, es wird nicht bleiben JPEG - es wird schließlich in eine der Wavelet-Encoder für Video, aber ich brauche eine Grundlinie, um sicherzustellen, dass ich alles richtig optimiert bekommen – Nick

Antwort

0

Versuchen Sie, die Build-in-Encoder:

private byte[] compressYuvToJpeg(final byte[] yuvData) { 
    mJpegCompressionBuffer.reset(); 
    YuvImage yuvImage = 
     new YuvImage(yuvData, ImageFormat.NV21, mPreviewWidth, mPreviewHeight, null); 
    yuvImage.compressToJpeg(new Rect(0, 0, mPreviewWidth, mPreviewHeight), mJpegQuality, 
     mJpegCompressionBuffer); 
    return mJpegCompressionBuffer.toByteArray(); 
    } 
+1

Ganz oben in meinem Beitrag, das ist eigentlich das, was ich ursprünglich gemacht habe. Es ist jedoch nicht schnell genug.Mit dem 800-MHz-Prozessor, den mein Telefon hat, sind das ungefähr 96 Taktzyklen pro Farbmuster, um 18 fps aufrechtzuerhalten. Es sollte auf die eine oder andere Weise möglich sein. – Nick

+0

Ich schlage vor zu überprüfen, welche Funktion die meiste Rechenzeit in Anspruch nimmt, einfach indem man eine oder mehrere Funktionen weglässt und die Empfangszeit auf der PC-Seite misst. Beachten Sie auch, dass es einen h264 Streamer für Android gibt, http://code.google.com/p/ipcamera-for-android/ –

Verwandte Themen