2012-06-07 41 views
7

Tôi đang làm việc để tạo thanh tiến trình cho ffmpeg trong java. Vì vậy, cho rằng tôi cần phải thực hiện một lệnh, sau đó đọc tất cả các tiến bộ:Cách đọc phản hồi ffmpeg từ java và sử dụng nó để tạo thanh tiến trình?

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

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

Điều này chạy hoàn hảo. Tuy nhiên, tôi cần phải nắm bắt tất cả các tiến bộ để thực hiện một thanh tiến trình. Vậy làm thế nào tôi có thể đọc dữ liệu đó từ java?

+1

tôi nhận được kết quả như 'khung = 2822 fps = 493 q = 19,1 Lsize = 4082kB time = 117,66 bitrate = 284.2kbits/s' cách chính xác làm bạn có kế hoạch để trích xuất các -progress%? – aioobe

+0

xem trước hết nó cho biết Thời gian bắt đầu ... Tôi muốn đọc trước và chuyển đổi thành giây và lưu trữ rồi tất cả các dòng như 'frame = 2822 fps = 493 q = 19.1 Lsize = 4082kB time = 117.66 bitrate = 284.2kbits/s' và từ dòng này trích xuất giá trị time = và thông qua điều này tôi sẽ tìm tiến độ theo công thức '(thời gian/thời gian) * 100' – shalki

+0

Tôi hiểu. Hãy để tôi thử :-) – aioobe

Trả lời

16

Dưới đây là một ví dụ hoàn chỉnh cho bạn mà nên giúp bạn bắt đầu

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(); 

    } 
} 

Output:

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% 

Bạn cũng có thể xem xét sử dụng một số loại bindings Java cho ffmpeg như jjmpeg mà có thể cung cấp những gì bạn cần theo cách mạnh mẽ hơn.

EDIT

Với ffmpeg 2.0, đầu ra thời gian là HH:mm:ss.S nên timePattern cần để kết hợp một :

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

Bên cạnh đó, dur sẽ cần phải được chia trên : và tóm tắt lại với nhau

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

Lưu ý rằng toàn bộ chương trình bị treo trên câu hỏi 'Tệp' out.mp4 'đã tồn tại. Ghi đè? [y/N] 'nếu tệp tồn tại. – aioobe

+0

vâng ... Tôi biết rằng ... đó là lý do tại sao tôi đã đưa ra lệnh: 'String [] lệnh = {" gnome-terminal "," -x ","/bin/sh "," -c ", "ffmpeg -i /home/tmp/F.webm /home/tmp/converted1.mp4"}; 'Vì vậy, nó mở ra một thiết bị đầu cuối trong khi thực hiện quá trình này nhưng khi tôi làm điều này tôi không thể nhận được lỗi của quá trình ffmpeg ... đó là nơi mà sau đó tôi đã bị mắc kẹt và thậm chí bị mắc kẹt bây giờ ... Tôi đã nhận được đầu ra chỉ với lệnh ffmpeg như u đã đưa ra ở trên mã .. nhưng sau đó nó sẽ đóng băng nếu tập tin đã tồn tại ... – shalki

+0

Aha. Vâng, bạn không thể có được đầu ra ffmpeg nếu nó đang chạy bên trong một thiết bị đầu cuối gnome. Kiểm tra xem tệp có tồn tại hay không bằng cách sử dụng 'File.exists' trước khi khởi chạy' ffmpeg'. – aioobe

1

Bạn có thể thử phân tích cú pháp ffmpeg đầu ra và bằng cách nào đó hiểu công việc đã được thực hiện. Nhưng điều này là khó khăn và không ổn định anyway. Cả hai chúng tôi (những người dùng ffmpeg) hay bản thân ffmpeg cũng không biết và không thể biết về thời gian xử lý sẽ mất bao lâu.

Theo kinh nghiệm của tôi, cách dễ nhất là triển khai một loại phỏng đoán. Giả sử rằng thời gian xử lý tuyến tính phụ thuộc vào kích thước tệp. Cách tiếp cận này là "sai" nhưng đủ tốt và rất đơn giản. Bây giờ chạy chế biến của bạn với chính xác các tùy chọn tương tự bạn đang sử dụng trong cuộc sống thực với một số tệp có kích thước khác nhau. Tạo ánh xạ kích thước theo thời gian. Thực hiện phân tích thống kê và tạo công thức như time = something + coef * size.

Bây giờ bạn có thể tạo cho bạn quy trình thanh. Vì hầu hết các thanh xử lý nên đến đến ~ 95% và sau đó đợi thực sự chấm dứt quá trình.

Nó rất đơn giản và hoạt động không tồi tệ hơn bất kỳ giải pháp phức tạp nào khác.

+0

Hey điều này là không cần thiết .... Những gì tôi đang làm là chính xác ?? Cách tiếp cận của tôi là lấy Thời lượng của video đầu vào sẽ được hiển thị khi u thực hiện lệnh ffmpeg này ... và thậm chí nó sẽ hiển thị tiến trình sử dụng giá trị time = và thời gian đó cho biết số lượng video đã được chuyển đổi. .. ví dụ nếu thời lượng video đầu vào của tôi là 00: 04: 30.00 và tại thời điểm cụ thể tôi nhận được 'frame = 2822 fps = 493 q = 19.1 Lsize = 4082kB thời gian = 117.66 bitrate = 284.2kbits/s' thì điều đó có nghĩa là video 00: 01: 57.66 của tôi đã được chuyển đổi ... Vì vậy, bằng cách này tôi có thể có được sự tiến bộ .. – shalki

+0

nhưng vấn đề là làm thế nào tôi sẽ đọc nó từ chương trình java của tôi .... và ffmpeg gửi cho stderr. .. Tôi có thể chuyển hướng nó đến một tập tin .. nhưng tôi cần tiến bộ ngay lập tức đang xảy ra .. như tôi muốn thực hiện một thanh tiến trình khi quá trình đang diễn ra .. – shalki

+0

Để có được luồng lỗi của quá trình bạn làm 'p. getErrorStream() '. – aioobe

0

* Tôi đã hiển thị thành công ProgressBar cho lệnh ffmpeg bằng cách sử dụng mã sau.

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(); 
      } 
Các vấn đề liên quan