SurfaceTexture ist onFrameAvailable () - Methode wird immer aufgerufen, zu spät
Ich versuche, den folgenden MediaExtractor Beispiel funktioniert:
http://bigflake.com/mediacodec/- ExtractMpegFramesTest.java (erfordert 4.1, API 16)
Das problem, das ich habe, ist, dass outputSurface.awaitNewImage(); scheint immer throw RuntimeException("frame-wait timed out"), die ausgelöst wird, wenn die mFrameSyncObject.wait(TIMEOUT_MS)
rufen Sie mal aus. Egal was ich einstelle TIMEOUT_MS
werden, onFrameAvailable()
immer aufgerufen wird direkt nach das timeout Auftritt. Ich habe versucht, mit 50ms und mit 30000ms und es ist das gleiche.
Scheint es, wie die onFrameAvailable()
Anruf kann nicht ausgeführt werden, während der thread beschäftigt ist, und sobald das timeout passiert, endet der thread die Ausführung von code, kann es analysieren, die onFrameAvailable()
nennen.
Hat jemand es geschafft, dieses Beispiel funktioniert, oder weiß, wie MediaExtractor funktionieren soll mit den GL-Texturen?
Edit: versucht, diese auf Geräte mit API 4.4 und 4.1.1 und das gleiche passiert auf beiden.
Edit 2:
Habe es funktioniert auf 4.4 Dank fadden. Das Problem war, dass die ExtractMpegFramesWrapper.runTest()
Methode namens th.join();
die blockiert den main thread und verhindert die onFrameAvailable()
Anruf verarbeitet. Einmal sagte ich: th.join();
es funktioniert auf 4.4. Ich denke, vielleicht die ExtractMpegFramesWrapper.runTest()
selbst war laufen soll, auf noch einem anderen thread, damit der Haupt-thread nicht blockiert.
Gab es auch ein kleines Problem auf 4.1.2 beim Aufruf codec.configure()
, gab es den Fehler:
A/ACodec(2566): frameworks/av/media/libstagefright/ACodec.cpp:1041 CHECK(def.nBufferSize >= size) failed.
A/libc(2566): Fatal signal 11 (SIGSEGV) at 0xdeadbaad (code=1), thread 2625 (CodecLooper)
Welche ich gelöst, indem Sie die folgende, bevor der Anruf:
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 0);
Aber ich habe das problem jetzt auf beiden 4.1.1 (Galaxy S2 GT-I9100) und 4.1.2 (Samsung Galaxy Tab GT-P3110) ist, dass Sie beide immer info.Größe 0 für alle frames. Hier ist die log-Ausgabe:
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
input buffer not available
no output from decoder available
loop
submitted frame 0 to dec, size=20562
no output from decoder available
loop
submitted frame 1 to dec, size=7193
no output from decoder available
loop
[... skipped 18 lines ...]
submitted frame 8 to dec, size=6531
no output from decoder available
loop
submitted frame 9 to dec, size=5639
decoder output format changed: {height=240, what=1869968451, color-format=19, slice-height=240, crop-left=0, width=320, crop-bottom=239, crop-top=0, mime=video/raw, stride=320, crop-right=319}
loop
submitted frame 10 to dec, size=6272
surface decoder given buffer 0 (size=0)
loop
[... skipped 1211 lines ...]
submitted frame 409 to dec, size=456
surface decoder given buffer 1 (size=0)
loop
sent input EOS
surface decoder given buffer 0 (size=0)
loop
surface decoder given buffer 1 (size=0)
loop
surface decoder given buffer 0 (size=0)
loop
surface decoder given buffer 1 (size=0)
loop
[... skipped 27 lines all with size=0 ...]
surface decoder given buffer 1 (size=0)
loop
surface decoder given buffer 0 (size=0)
output EOS
Saving 0 frames took ? us per frame //edited to avoid division-by-zero error
Also keine Bilder gespeichert. Aber die gleiche code-und video-arbeiten auf 4.3. Das video, das ich verwende, ist ein .mp4-Datei mit "H264 - MPEG-4 AVC (avc1)" video-codec und "MPEG-AAAC-Audio (mp4a)" - audio-codec.
Ich habe auch versucht, andere video-Formate, aber Sie scheinen zu sterben sogar früher auf 4.1.x, während die beiden die Arbeit an 4.3.
Edit 3:
Ich Tat, wie Sie vorgeschlagen, und es scheint zum speichern der Bilder richtig. Danke.
Bezüglich KEY_MAX_INPUT_SIZE, versuchte ich die Einstellung nicht, oder die Einstellung auf 0, 20, 200, ... 200000000, alle mit dem gleichen Ergebnis-info.Größe=0.
Ich bin jetzt nicht der render zu einem SurfaceView oder TextureView auf mein layout. Ich habe versucht, ersetzen Sie diese Zeile:
mSurfaceTexture = new SurfaceTexture(mTextureRender.getTextureId());
mit dabei, wo surfaceTexture
ist ein SurfaceTexture definiert in meine xml-layout:
mSurfaceTexture = textureView.getSurfaceTexture();
mSurfaceTexture.attachToGLContext(mTextureRender.getTextureId());
aber es wirft einen seltsamen Fehler mit getMessage()==null
auf die zweite Zeile. Ich konnte nicht finden einen anderen Weg, um es zu ziehen, auf einen Blick auf einige Art. Wie kann ich den decoder zum anzeigen der frames, die auf eine Oberfläche/SurfaceView/TextureView statt Sie zu sichern?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Den Weg
SurfaceTexture
funktioniert, macht das ein bisschen schwierig, richtig zu machen.Den docs sagen, dass die frame-verfügbar callback "genannt wird, auf einem beliebigen thread". Die
SurfaceTexture
Klasse hat ein bisschen code, der Folgendes macht beim initialisieren (Linie 318):Rahmen-verfügbare Ereignisse geliefert werden, um Ihre app durch die üblichen
Looper
/Handler
Mechanismus. Dieser Mechanismus ist nur eine Warteschlange, was bedeutet, dass der Faden muss sitzen, in derLooper
Ereignis-Schleife wartet auf Sie, um anzukommen. Das Problem ist, wenn Sie schlafen, inawaitNewImage()
Sie sind nicht gerade dieLooper
Warteschlange. So dass die Veranstaltung ankommt, aber niemand sieht es. SchließlichawaitNewImage()
mal aus, und der thread kehrt zu beobachten, die Ereignis-queue, wo es sofort entdeckt, die ausstehende "new frame" - Meldung.Also der trick ist, um sicherzustellen, dass die frame-verfügbare Ereignisse kommen in einem anderen thread von dem einen sitzen in
awaitNewImage()
. In derExtractMpegFramesTest
Beispiel, dies geschieht durch ausführen der test in einem neu erstellten thread (sieheExtractMpegFramesWrapper
Klasse), die nicht über eineLooper
. (Aus irgendeinem Grund ist der thread, der führt die CTS-tests hat ein looper.) Die frame-verfügbare Ereignisse kommen auf den main-UI-thread.Update (für "edit 3"): ich bin ein bisschen traurig, dass ignorieren das Feld "Größe" geholfen, aber pre-4.3 es ist schwer vorherzusagen, wie sich Geräte Verhalten wird.
Wenn Sie nur wollen, um den Rahmen, übergeben Sie die
Surface
bekommen Sie von derSurfaceView
oderTextureView
in dieMediaCodec
decoderconfigure()
nennen. Dann sollten Sie nicht zu verwirren haben mitSurfaceTexture
überhaupt-die Bilder werden so dargestellt, wie man Sie entschlüsseln. Siehe die beiden "video Abspielen" - Aktivitäten in Grafika für Beispiele.Wenn Sie wirklich wollen, zu gehen durch eine
SurfaceTexture
müssen Sie ändern CodecOutputSurface zu machen, um eine Oberfläche der Fenster eher als eine pbuffer. (Die off-screen-rendering ist getan, so dass wir verwenden könnenglReadPixels()
in eine headless-test.)KEY_MAX_INPUT_SIZE
zu einem großen Wert anstelle von null? (Ich glaube nicht, dass ich jemals festgelegt, dass-nicht sicher, warum Sie immer waren, dass assert-Fehler.)SurfaceHolder
. Kann ein GL textureId zugewiesen werden, um eine vorhandeneSurfaceHolder
oderSurface
? Die Beispiele verwenden Sie immernew SurfaceTexture(mTextureId)
, aber ich muss an eine bestehendeSurface
.Surface
undEGLSurface
sind Verwandte, aber unabhängige Konzepte.Surfaces
sind Warteschlangen von Grafik-Puffer, die sind völlig unabhängig von GL. Texturen sind GL Konzepte. DieSurfaceTexture
Klasse ist ein verschmelzen der beiden: wenn Sie uns einen Puffer, verwandelt es sich in eine GL-textur. EbensoeglCreateWindowSurface()
schafft ein GL-Kontext, macht auf eineSurface
. Aber Sie können frei verwenden, mit GL, ohneSurface
(pbuffers) und Umgekehrt (MediaCodec
decodierenSurfaceView
).