2016-03-21 22 views
0

Ich versuche, den Screenshot meiner Android-Anwendung von OnDrawFrame-Funktion meines Renderers zu erfassen. Es wird jedoch der Rahmen gelöscht und die Anwendung eingefroren, bis der Vorgang abgeschlossen ist. Ich versuche es auf einem anderen Thread, aber keinen Erfolg. Ist es möglich, den Bildschirm in einem anderen Thread zu sehen?Ist es möglich, Screenshot von GLSurfaceView von einem anderen Thread in Android zu nehmen?

+0

Post einige Code, Multi-Threading sollte diese Situation möglich sein, es hängt nur davon ab, wie Sie es tun. – zgc7009

Antwort

1

Sie können die glReadPixels() nicht aus einem anderen Thread ausführen, da der EGL-Kontext nur in einem Thread gleichzeitig aktuell sein kann und Sie mit GLSurfaceView keine Kontrolle darüber haben.

Allerdings werden 95 +% der Zeit, die für die Aufnahme eines Screenshots von GLES aufgewendet wird, für PNG/JPEG-Komprimierung und Disk I/O ausgegeben. Also, wenn Sie den glReadPixels() Anruf von onDrawFrame() machen, und dann die Daten an einen neuen Thread übergeben, sollten Sie in der Lage sein, weiter zu laufen, während der Screenshot im Hintergrund verarbeitet wird.

1

Wie bereits erwähnt, kann ein direktes Lesen von einem anderen Thread unmöglich sein, aber es gibt andere Möglichkeiten.

Anstatt Ihre Szene direkt in die Oberflächenansicht zu zeichnen, können Sie sie in ein Rahmenpufferobjekt (FBO) mit angehängter Textur zeichnen und dann die Textur in den Hauptpuffer zurückzeichnen. Dies ist ein ziemlich übliches Verfahren für die Nachbearbeitung und dergleichen und hat keine hohen Auswirkungen auf die Leistung. Um das zu realisieren, müssen Sie nur schauen, wie Sie den FBO erstellen, ihn binden, bevor die Zeichnung beginnt und der Rest Ihres Codes sollte so bleiben wie er ist. Fügen Sie dann auch den Code hinzu, um die FBO-Textur auf dem Bildschirm neu zu zeichnen, indem Sie den Hauptpuffer binden (der Index sollte ausreichen).

Für den Screenshot in einem separaten Thread müssen Sie nun einen neuen Thread und einen neuen Kontext erstellen, der auf diesem Thread festgelegt ist. Der neue Kontext muss mit dem Hauptkontext geteilt werden (ich glaube, es gibt einen Konstruktor, der den Hauptkontext dafür akzeptiert), sodass Sie die Textur teilen können. Jetzt der spaßige Teil: Wenn Sie den Screenshot machen wollen, müssen Sie eine neue Textur erstellen, die neue Textur an den FBO anhängen und die alte Textur lösen. Auf diese Weise stiehlst du die Textur, zu der der Inhalt gezeichnet wird, und du kannst damit machen, was du willst und mit jedem Thread, den du willst. Also lege es in deinen sekundären Thread und in diesem Kontext kannst du einen anderen FBO erstellen, es binden und die Pixel davon in diesem Thread lesen. Vergiss aber nicht zu säubern.

Einige Vorsicht ist jedoch ratsam. Diese Art von Verfahren kann gut sein, wenn Sie eine relativ kleine Menge an Screenshot machen. Wenn ein Screenshot nicht vollständig erstellt wird, bevor ein anderer gestartet wird, wird die Speicherauslastung aufgebläht und die App stürzt höchstwahrscheinlich ab. Seien Sie also vorsichtig, wenn Sie das nicht tun, erstellen Sie eine Art Sperrmechanismus oder beschränken Sie die Anzahl der Screenshots, die gerade verarbeitet werden. Und dies ist nicht nur für openGL, das gleiche Problem kann auftreten, wenn Sie einfach die Bilddaten kodieren.

Und nur eine Anmerkung zu Ihrer ursprünglichen Idee: Selbst wenn Sie die Oberflächenansicht auf einem separaten Thread verwenden und Pixel aus dem Hauptpuffer lesen könnten Sie nicht erwarten, dass Sie ein gutes Ergebnis erhalten. Auf den Puffer kann während des Lesens zugegriffen werden, so dass Sie Daten aus verschiedenen Frames erhalten könnten. Das ist nur theoretisch, denn die Wahrheit ist, dass der Puffer einfach gesperrt wäre und Ihre Anwendung abstürzen würde, während Sie versuchen, darauf zuzugreifen. Das ist also in keiner Weise möglich und selbst wenn es das Ergebnis wäre, wäre das unvorhersehbar.

+0

Seien Sie vorsichtig - das Teilen von Texturen zwischen Kontexten in verschiedenen Threads kann race-Bedingungen haben. Ich habe das in Grafika falsch verstanden; siehe https://github.com/google/grafika/issues/36. – fadden

+0

Und deshalb sage ich, dass Sie die Textur "stehlen" müssen. Sie müssen die aktuelle Textur, die Sie zeichnen, durch eine neue ersetzen. Sie könnten tatsächlich doppelte Pufferung mit 2 Texturen machen. –