2012-06-07 10 views
7

Sto lavorando alla creazione di una barra di avanzamento per ffmpeg in java. Quindi per quello ho bisogno di eseguire un comando, quindi leggere tutti i progressi:Come leggere la risposta ffmpeg da java e usarla per creare una barra di avanzamento?

String[] command = {"gnome-terminal", "-x", "/bin/sh", "-c","ffmpeg -i /home/tmp/F.webm /home/tmp/converted1.mp4"}; 

Process process = Runtime.getRuntime().exec(command); 

Questo funziona perfettamente. Tuttavia, ho bisogno di catturare tutti i progressi per fare una barra di progresso. Quindi, come posso leggere quei dati da java?

+1

ottengo uscita come 'frame = 2.822 fps = 493 q = 19.1 tempo lSize = 4082kB = 117.66 bitrate = 284.2kbits/s' esattamente come si prevede di estrarre il registrare progressi%? – aioobe

+0

vedere prima di tutto che mostra la Durata all'avvio ... Voglio che sia letto per primo e lo convertirà in secondi e memorizziamo tutte le righe come 'frame = 2822 fps = 493 q = 19.1 Lsize = 4082kB time = 117,66 bitrate = 284,2kbits/s' e da questa riga estratto tempo = valore e attraverso questo troverò progresso con la formula '(tempo/durata) * 100' – shalki

+0

che vedo. Lasciatemi fare un tentativo :-) – aioobe

risposta

16

Ecco un esempio completo per voi che dovrebbe iniziare

import java.io.*; 
import java.util.Scanner; 
import java.util.regex.Pattern; 

class Test { 
    public static void main(String[] args) throws IOException { 
    ProcessBuilder pb = new ProcessBuilder("ffmpeg","-i","in.webm","out.mp4"); 
    final Process p = pb.start(); 

    new Thread() { 
     public void run() { 

     Scanner sc = new Scanner(p.getErrorStream()); 

     // Find duration 
     Pattern durPattern = Pattern.compile("(?<=Duration:)[^,]*"); 
     String dur = sc.findWithinHorizon(durPattern, 0); 
     if (dur == null) 
      throw new RuntimeException("Could not parse duration."); 
     String[] hms = dur.split(":"); 
     double totalSecs = Integer.parseInt(hms[0]) * 3600 
         + Integer.parseInt(hms[1]) * 60 
         + Double.parseDouble(hms[2]); 
     System.out.println("Total duration: " + totalSecs + " seconds."); 

     // Find time as long as possible. 
     Pattern timePattern = Pattern.compile("(?<=time=)[\\d.]*"); 
     String match; 
     while (null != (match = sc.findWithinHorizon(timePattern, 0))) { 
      double progress = Double.parseDouble(match)/totalSecs; 
      System.out.printf("Progress: %.2f%%%n", progress * 100); 
     } 
     } 
    }.start(); 

    } 
} 

uscita:

Total duration: 117.7 seconds. 
Progress: 7.71% 
Progress: 16.40% 
Progress: 25.00% 
Progress: 33.16% 
Progress: 42.67% 
Progress: 51.35% 
Progress: 60.57% 
Progress: 69.07% 
Progress: 78.02% 
Progress: 86.49% 
Progress: 95.94% 
Progress: 99.97% 

Si può anche considerare l'utilizzo di un qualche tipo di binding Java per ffmpeg come jjmpeg che può fornire quello che ti serve in un modo più robusto.

EDIT

Con ffmpeg 2.0, uscita tempo è HH:mm:ss.S così la timePattern bisogno di una incorporare un :

Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*"); 

Inoltre, dovranno essere diviso in : e sommati il ​​dur

String[] matchSplit; 
while (null != (match = sc.findWithinHorizon(timePattern, 0))) { 
    matchSplit = match.split(":") 
    double progress = Integer.parseInt(matchSplit[0]) * 3600 + 
     Integer.parseInt(matchSplit[1]) * 60 + 
     Double.parseDouble(matchSplit[2])/totalSecs; 
//... 
+0

Si noti che l'intero programma si blocca sulla domanda 'File 'out.mp4' esiste già. Sovrascrivi? [y/N] 'se il file esiste. – aioobe

+0

sì ... lo so ... ecco perché stavo dando il comando: 'String [] command = {" gnome-terminal "," -x ","/bin/sh "," -c ", "ffmpeg -i /home/tmp/F.webm /home/tmp/converted1.mp4"}; 'Così si apre un terminale mentre si fa questo processo, ma quando lo faccio non riesco ad ottenere l'errortream del processo ffmpeg ... questo è il punto in cui sono stato bloccato e persino bloccato ora ... stavo ottenendo l'output con solo il comando ffmpeg come hai indicato nel codice sopra .. ma poi si bloccherà se il file esiste già ... – shalki

+0

Aha. Bene, non è possibile ottenere l'output ffmpeg se è in esecuzione all'interno di un terminale gnome. Controlla se il file esiste usando 'File.esistenti' prima di lanciare' ffmpeg'. – aioobe

1

È possibile provare a analizzare l'output ffmpeg e in qualche modo capire quale lavoro è già stato eseguito. Ma questo è difficile e non stabile comunque. Né noi (gli utenti di ffmpeg) né ffmpeg stesso non conosciamo e non possiamo sapere in termini di tempo per quanto tempo l'elaborazione richiederà.

Secondo la mia esperienza, il modo più semplice è implementare un tipo di euristica. Supponiamo che il tempo di elaborazione in modo lineare dipenda dalla dimensione del file. Questo approccio è "sbagliato" ma abbastanza buono e molto semplice. Ora esegui l'elaborazione con esattamente le stesse opzioni che utilizzi nella vita reale con diversi file di dimensioni diverse. Crea una mappatura di dimensioni per volta. Fai analisi statistiche e crea una formula come time = something + coef * size.

Ora è possibile creare la barra di processo. Come la maggior parte delle barre di processo dovrebbe arrivare a ~ 95% e quindi attendere reale terminazione del processo.

È molto semplice e funziona non peggio di qualsiasi altra soluzione più sofisticata.

+0

Ehi, questo non è necessario .... Cosa sto facendo è corretto ?? Il mio approccio è quello di ottenere la durata del video di input che verrà visualizzato quando si esegue questo comando ffmpeg ... e mostrerà anche il progresso usando time = value e quel tempo è il tempo che indica quanto del video è stato convertito. .. per esempio se la durata del mio video in ingresso è 00: 04: 30.00 e in particolari momenti di tempo ottengo 'frame = 2822 fps = 493 q = 19.1 Lsize = 4082kB time = 117,66 bitrate = 284,2kbits/s', quindi significa che my 00: 01: 57.66 video è stato convertito ... Quindi con questo posso ottenere il progresso .. – shalki

+0

ma il problema è come leggerlo dal mio programma java .... e ffmpeg lo manda a stderr. .. posso reindirizzare a un file .. ma ho bisogno di progressi immediati che sta accadendo .. come voglio fare una barra di avanzamento quando il processo sta succedendo .. – shalki

+0

Per ottenere il flusso di errore del processo si fa 'p. getErrorStream() '. – aioobe

0

* Ho visualizzato con successo ProgressBar per il comando ffmpeg utilizzando il seguente codice.

try { 
       Scanner sc = new Scanner(process.getErrorStream()); 

       // Find duration 
       Pattern durPattern = Pattern.compile("(?<=Duration:)[^,]*"); 
       String dur = sc.findWithinHorizon(durPattern, 0); 
       Log.e("duration"+dur); 
       String givenDateString = dur; 
       SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.S"); 
       sdf.setTimeZone(TimeZone.getTimeZone("GMT")); 
       try { 
        Date mDate = sdf.parse(givenDateString); 
        totalDuration = mDate.getTime(); 
        System.out.println("Duration in milli :: " + totalDuration); 
       } catch (ParseException e) { 
        e.printStackTrace(); 
       } 

       // Find time as long as possible. 
       Pattern timePattern = Pattern.compile("(?<=time=)[\\d:.]*"); 
       String match; 
       String[] matchSplit; 
       while (null != (match = sc.findWithinHorizon(timePattern, 0))) { 
        if (isCancelled()) { 
         return; 
        } 
        Log.e("match"+match); 
        String givenDateString1 = match; 
        SimpleDateFormat sdf1 = new SimpleDateFormat("HH:mm:ss.S"); 
        sdf1.setTimeZone(TimeZone.getTimeZone("GMT")); 
        try { 
         Date mDate = sdf1.parse(givenDateString1); 
         currentDuration = mDate.getTime(); 
         System.out.println("Time in milli :: " + currentDuration); 
        } catch (ParseException e) { 
         e.printStackTrace(); 
        } 
        Double percentage = (double) 0; 

        long currentSeconds = (int) (currentDuration); 
        long totalSeconds = (int) (totalDuration); 

        // calculating percentage 
        percentage =(((double)currentSeconds)/totalSeconds)*100; 


        Log.e("Progress"+percentage); 
        publishProgress(""+percentage); 
       } 
      }catch (Exception e){ 
       e.printStackTrace(); 
      } 
Problemi correlati