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 ...
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. –
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
@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