2017-12-01 1 views
2

Ich versuche, AndroidSequenceEncoder verwenden, um eine Video-Diashow zu erstellen. Um dies zu tun, habe ich eine Methode, die eine ArrayList von Bitmaps und eine Zeichenfolge abruft, die den Dateinamen des Videos darstellt. Im Folgenden ist der Code ist meine Methode:Empfangen "Keine Frames ausgegeben" bei Verwendung von AndroidSequenceEncoder

public class ImageToVideo 
{ 
    //used to input frames (images) into the video file 
    private AndroidSequenceEncoder ase; 
    //Arraylist containing the frames to input 
    private ArrayList<Bitmap> bi; 
    //temporary variable used for AsyncTask below 
    private Bitmap image; 
    //This method is called until main code can be written to retrieve the proper length of the audio file 
    public AndroidSequenceEncoder videoEncode(final ArrayList<Bitmap> images, String filename) throws IOException 
    { 
     ase = AndroidSequenceEncoder.createSequenceEncoder(new File(filename), 3); 
     bi = images; 
     Log.d("SEQUENCEENCODER", "SequenceEncoder created"); 
     //outer for-loop; goes through each image individually 
     for(int i = 0; i < images.size(); i++) 
     { 
      Log.d("SEQUENCEENCODER", "Retrieving image " + i + " of " + (images.size() - 1)); 
     //inner for-loop; adds the given image a number of times determined by how long each image is on-screen 
     //since encoder's fps is currently set to 3, this loops once for each second the picture should be on-screen times 3 
     for(int j = 0; j < 3; j++) 
     { 
      Log.d("SEQUENCEENCODER", "Encoding image " + i + ", " + (j+1) + " of " + 3); 
      image = bi.get((i)); 
      //used because of error "Choreographer: Skipped ~90 frames! The application may be doing too much work on its main thread" 
      AsyncTask.execute(new Runnable() 
      { 
       @Override 
       public void run() 
       { 
        try 
        { 
         ase.encodeImage(image); 
        } 
        catch(IOException e) 
        { 
         e.printStackTrace(); 
        } 
       } 
      }); 
     } 
    } 
    ase.finish(); 
    return ase; 
} 

Die fps des AndroidSequenceEncoder auf 3 gesetzt ist als temporärer Wert; Wenn ich mehr an dem Code arbeite, möchte ich, dass diese Methode auch die Länge des Videos annimmt, so dass die Methode fps basierend darauf bestimmt, wie lange jedes Bild auf dem Bildschirm sein sollte, wenn sie jeweils die gleiche Zeit haben. Wenn Sie diese Methode mit 4 Bildern ausgeführt wird, erhalte ich folgende Meldungen

D/SEQUENCEENCODER: SequenceEncoder created 
D/SEQUENCEENCODER: Retrieving image 0 of 3 
D/SEQUENCEENCODER: Encoding image 0, 1 of 3 
D/SEQUENCEENCODER: Encoding image 0, 2 of 3 
D/SEQUENCEENCODER: Encoding image 0, 3 of 3 
D/SEQUENCEENCODER: Retrieving image 1 of 3 
D/SEQUENCEENCODER: Encoding image 1, 1 of 3 
D/SEQUENCEENCODER: Encoding image 1, 2 of 3 
D/SEQUENCEENCODER: Encoding image 1, 3 of 3 
D/SEQUENCEENCODER: Retrieving image 2 of 3 
D/SEQUENCEENCODER: Encoding image 2, 1 of 3 
D/SEQUENCEENCODER: Encoding image 2, 2 of 3 
D/SEQUENCEENCODER: Encoding image 2, 3 of 3 
D/SEQUENCEENCODER: Retrieving image 3 of 3 
D/SEQUENCEENCODER: Encoding image 3, 1 of 3 
D/SEQUENCEENCODER: Encoding image 3, 2 of 3 
D/SEQUENCEENCODER: Encoding image 3, 3 of 3 
I/System.out: [WARN] . (:0): No frames output. 
D/EGL_emulation: eglMakeCurrent: 0xa8a05240: ver 2 0 (tinfo 0xa8a03250) 
D/EGL_emulation: eglMakeCurrent: 0xa8a05240: ver 2 0 (tinfo 0xa8a03250) 
I/chatty: uid=10080(projectname) RenderThread identical 1 line 
D/EGL_emulation: eglMakeCurrent: 0xa8a05240: ver 2 0 (tinfo 0xa8a03250) 
I/zygote: Do partial code cache collection, code=122KB, data=94KB 
I/zygote: After code cache collection, code=117KB, data=92KB 
I/zygote: Increasing code cache capacity to 512KB 

durch eine lange Liste von Systemfehlern folgte auf den Befehl, die zurück

ase.encodeImage(image); 

Eine neue Videodatei im Android erstellt Bekommt Virtual Device, aber es endet fast sofort nach dem Spielen, obwohl es sagt, dass seine Länge 4 Sekunden ist. Ich frage mich, was ich im Code falsch mache, um das zu verursachen.

Antwort

0

Ein Problem, das ich mit dem obigen Code sehe, ist, dass die eigentliche Codierung von Frames in einem separaten (Hintergrund-) Thread stattfindet. Unter bestimmten Umständen ist es also möglich, dass keiner der Frames tatsächlich von der Zeit codiert wird, die "finish" aufgerufen wird. Was Sie tun müssen, ist sicherzustellen, dass "Finish" aufgerufen wird, nachdem die Codierung aller Frames tatsächlich stattgefunden hat. Es gibt mehrere Möglichkeiten, dies zu erreichen:

  1. Verschieben Sie Ihre Schleifen vollständig innerhalb der asynchronen Aufgabe gefolgt von beenden;
  2. Wenn es nur einen Executor-Thread gibt, können Sie mit der Ausführung von 'finish' innerhalb der asynchronen Task fortfahren. Auf diese Weise verlassen Sie sich auf die interne Executor-Warteschlange, um Ihr 'finish' am Ende auszuführen;
  3. Verwenden Sie Grundelemente für die Thread-Synchronisierung, z. B. "Warten/Benachrichtigen". So können Sie im Hauptthread "warten", bevor Sie "fertig" aufrufen und in der asynchronen Task "benachrichtigen". Obwohl dies eine praktikable Option ist, rate ich Ihnen dringend davon ab, es aus einer Vielzahl anderer Gründe zu verwenden.
Verwandte Themen