Làm cách nào để trích xuất khoảng thời gian từ đầu ra ffmpeg?


78

Để có được nhiều thông tin về một tệp phương tiện, người ta có thể làm

ffmpeg -i <filename>

nơi nó sẽ xuất ra rất nhiều dòng, cụ thể là một dòng

Duration: 00:08:07.98, start: 0.000000, bitrate: 2080 kb/s

Tôi chỉ muốn xuất ra 00:08:07.98, vì vậy tôi cố gắng

ffmpeg -i file.mp4 | grep Duration| sed 's/Duration: \(.*\), start/\1/g'

Nhưng nó in mọi thứ, và không chỉ chiều dài.

Ngay cả ffmpeg -i file.mp4 | grep Durationđầu ra mọi thứ.

Làm cách nào để tôi chỉ nhận được thời lượng?


1
IMHO MediaInfo chắc chắn sẽ cung cấp cho bạn cách phân tích cú pháp đầu ra dễ dàng hơn nhiều.
SirDarius

Câu trả lời:


61

ffmpeg đang ghi thông tin đó vào stderr, không phải stdout. Thử cái này:

ffmpeg -i file.mp4 2>&1 | grep Duration | sed 's/Duration: \(.*\), start/\1/g'

Lưu ý sự chuyển hướng stderrsang stdout:2>&1

BIÊN TẬP:

sedTuyên bố của bạn cũng không hoạt động. Thử cái này:

ffmpeg -i file.mp4 2>&1 | grep Duration | awk '{print $2}' | tr -d ,

3
Grep là không cần thiết, sed -n 's/Duration: \(.*\), start/\1/gp'là đủ.
potong

11
Trên thực tế, sedlà không cần thiết:ffmpeg -i file.mp4 2>&1 | grep -o -P "(?<=Duration: ).*?(?=,)"
ДМИТРИЙ МАЛИКОВ

1
Bối cảnh cho điều này là gì nếu tôi muốn lưu trữ thời lượng dưới dạng một biến được sử dụng trong cùng một tập lệnh PHP?
vertigo electro,

Làm thế nào để làm điều tương tự trong Python?
Prakhar Mohan Srivastava

18
Sử dụng ffprobe theo hướng dẫn trong câu trả lời khác dường như một cách sạch hơn và rắc rối-miễn phí-er tiếp cận :)
Pirkka Esko

166

Bạn có thể sử dụng ffprobe:

ffprobe -i <file> -show_entries format=duration -v quiet -of csv="p=0"

Nó sẽ xuất ra thời lượng tính bằng giây, chẳng hạn như:

154.12

Thêm -sexagesimaltùy chọn sẽ xuất ra thời lượng dưới dạng giờ: phút: giây.microseconds :

00:02:34.12

1
Đối với ffmpeg-0.6.5-1.el6.rf.x86_64 của tôi, định dạng là: ffprobe <file> -show_format 2> & 1 | sed -n 's / time = // p'
Sunry

2
Đây là con đường để đi. ffmpeg -i luôn muốn chuyển mã một tệp mới sau khi in dữ liệu. Cách giải pháp sạch hơn ngay tại đây.
Pirkka Esko

Nên là câu trả lời được chấp nhận, mặc dù định dạng đầu ra (giây) không hoàn toàn chính xác như những gì được yêu cầu.
bohesia

3
@bopris Answer được cập nhật với tùy chọn xuất ra định dạng mong muốn.
llogan

1
@LordNeckbeard Bây giờ nó thực sự nên là câu trả lời được chấp nhận!
bopris

13

Từ kinh nghiệm của tôi, nhiều công cụ cung cấp dữ liệu mong muốn trong một số loại cấu trúc bảng / có thứ tự và cũng cung cấp các tham số để thu thập các phần cụ thể của dữ liệu đó. Điều này cũng áp dụng cho ví dụ: smartctl, nvidia-smi và ffmpeg / ffprobe. Nói một cách đơn giản - thường không cần phải phân tích dữ liệu xung quanh hoặc mở các phiếu phụ cho một nhiệm vụ như vậy.

Do đó, tôi sẽ sử dụng công cụ phù hợp cho công việc - trong trường hợp đó, ffprobe sẽ trả về giá trị thời lượng thô tính bằng giây, sau đó người ta có thể tự tạo định dạng thời gian mong muốn:

$ ffmpeg --version
ffmpeg version 2.2.3 ...

Lệnh có thể khác nhau tùy thuộc vào phiên bản bạn đang sử dụng.

#!/usr/bin/env bash
input_file="/path/to/media/file"

# Get raw duration value
ffprobe -v quiet -print_format compact=print_section=0:nokey=1:escape=csv -show_entries format=duration "$input_file"

Một lời giải thích:

"-v yên tĩnh": Không xuất bất kỳ thứ gì khác ngoài giá trị dữ liệu thô mong muốn

"-print_format": Sử dụng một định dạng nhất định để in ra dữ liệu

"compact =": Sử dụng định dạng đầu ra nhỏ gọn

"print_section = 0": Không in tên phần

": nokey = 1": không in khóa của cặp key: value

": Escape = csv": thoát khỏi giá trị

"-show_entries format = time": Nhận các mục nhập của trường có tên thời lượng bên trong một phần được đặt tên là định dạng

Tham khảo: ffprobe man pages


6

Trong trường hợp có một tham số yêu cầu, đơn giản hơn là sử dụng mediainfo và định dạng đầu ra của nó như thế này (trong thời lượng; trả lời bằng mili giây)

mediainfo --Output="General;%Duration%" ~/work/files/testfiles/+h263_aac.avi 

đầu ra

24840

2
Đây phải là 'mediainfo --Inform = "General;% Duration%" ~ / work / files / testfiles / + h263_aac.avi'
Pogrindis

Cả hai biểu mẫu đều hoạt động giống nhau trong mediainfo v18.05 (và dường như với các phiên bản trước).
gemelen

4

Tôi khuyên bạn nên sử dụng định dạng json, nó sẽ dễ dàng hơn cho việc phân tích cú pháp

ffprobe -i your-input-file.mp4 -v quiet -print_format json -show_format -show_streams -hide_banner

{
    "streams": [
        {
            "index": 0,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "HE-AACv2",
            "codec_type": "audio",
            "codec_time_base": "1/44100",
            "codec_tag_string": "[0][0][0][0]",
            "codec_tag": "0x0000",
            "sample_fmt": "fltp",
            "sample_rate": "44100",
            "channels": 2,
            "channel_layout": "stereo",
            "bits_per_sample": 0,
            "r_frame_rate": "0/0",
            "avg_frame_rate": "0/0",
            "time_base": "1/28224000",
            "duration_ts": 305349201,
            "duration": "10.818778",
            "bit_rate": "27734",
            "disposition": {
                "default": 0,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0
            }
        }
    ],
    "format": {
        "filename": "your-input-file.mp4",
        "nb_streams": 1,
        "nb_programs": 0,
        "format_name": "aac",
        "format_long_name": "raw ADTS AAC (Advanced Audio Coding)",
        "duration": "10.818778",
        "size": "37506",
        "bit_rate": "27734",
        "probe_score": 51
    }
}

bạn có thể tìm thấy thông tin thời lượng trong phần định dạng, hoạt động cho cả video và âm thanh


Cảm ơn bạn! Đây chính xác là những gì tôi cần!
Matt W

4

Nếu bạn muốn truy xuất độ dài (và có thể là tất cả các siêu dữ liệu khác) từ tệp phương tiện của mình bằng ffmpeg bằng cách sử dụng tập lệnh python, bạn có thể thử cách này:

import subprocess
import json

input_file  = "< path to your input file here >"

metadata = subprocess.check_output(f"ffprobe -i {input_file} -v quiet -print_format json -show_format -hide_banner".split(" "))

metadata = json.loads(metadata)
print(f"Length of file is: {float(metadata['format']['duration'])}")
print(metadata)

Đầu ra:

Length of file is: 7579.977143

{
  "streams": [
    {
      "index": 0,
      "codec_name": "mp3",
      "codec_long_name": "MP3 (MPEG audio layer 3)",
      "codec_type": "audio",
      "codec_time_base": "1/44100",
      "codec_tag_string": "[0][0][0][0]",
      "codec_tag": "0x0000",
      "sample_fmt": "fltp",
      "sample_rate": "44100",
      "channels": 2,
      "channel_layout": "stereo",
      "bits_per_sample": 0,
      "r_frame_rate": "0/0",
      "avg_frame_rate": "0/0",
      "time_base": "1/14112000",
      "start_pts": 353600,
      "start_time": "0.025057",
      "duration_ts": 106968637440,
      "duration": "7579.977143",
      "bit_rate": "320000",
      ...
      ...

Mã này không hoạt động: Traceback (most recent call last): File "ffprobe.py", line 9, in <module> print("Length of file is: {}".format(float(length["format"]["duration"]))) NameError: name 'length' is not defined Điều này sẽ thực hiện công việc: import subprocess import json input_file = "out.mp4" metadata = subprocess.check_output(f"ffprobe -i {input_file} -v quiet -print_format json -show_format -hide_banner".split(" ")) metadata = json.loads(metadata) print("Length of file is: {}".format(float(metadata["format"]["duration"]))) print(metadata)
Rabindranath Andujar

@RabindranathAndujar Tôi đã kiểm tra lại. Bạn đúng rồi. Mã hoạt động, nhưng dòng cho bản in có lỗi trong đó. Tôi đã sửa mã và bây giờ nó chạy tốt. Cảm ơn đã chỉ ra điều đó.
petezurich

Tập lệnh này sẽ không thành công đối với tên tệp có ký tự đặc biệt trên cả Linux và windows
agarg

1

Đối với những người muốn thực hiện các phép tính tương tự mà không cần phần mềm bổ sung trong Windows, đây là tập lệnh cho tập lệnh dòng lệnh:

set input=video.ts

ffmpeg -i "%input%" 2> output.tmp

rem search "  Duration: HH:MM:SS.mm, start: NNNN.NNNN, bitrate: xxxx kb/s"
for /F "tokens=1,2,3,4,5,6 delims=:., " %%i in (output.tmp) do (
    if "%%i"=="Duration" call :calcLength %%j %%k %%l %%m
)
goto :EOF

:calcLength
set /A s=%3
set /A s=s+%2*60
set /A s=s+%1*60*60
set /A VIDEO_LENGTH_S = s
set /A VIDEO_LENGTH_MS = s*1000 + %4
echo Video duration %1:%2:%3.%4 = %VIDEO_LENGTH_MS%ms = %VIDEO_LENGTH_S%s

Câu trả lời tương tự được đăng ở đây: Cách cắt N giây cuối cùng từ video TS


Cách khác ffprobe -i "input.mp4" -show_entries format = thời gian -v yên tĩnh notice csv = "p = 0" -sexagesimal
Ray Woodcock

1
ffmpeg -i abc.mp4 2>&1 | grep Duration | cut -d ' ' -f 4 | sed s/,//

đưa ra đầu ra

HH: MM: SS.milisecs


grep, cutsedkhông cần thiết. Hãy xem câu trả lời của Ivan .
llogan

tại sao không cần thiết tôi không hiểu nó mang lại kết quả
turkane sparsh

Bởi vì bạn chỉ có thể sử dụng ffprobemột mình. Ngoài ra, đầu ra của ffmpegchỉ dành cho mục đích thông tin chứ không phải để phân tích cú pháp: nó không được đảm bảo luôn có cấu trúc, định dạng và thông tin giống nhau với nhiều ffmpegphiên bản và định dạng đầu vào khác nhau.
llogan

0

Giải pháp tốt nhất: cắt xuất và nhận một cái gì đó như 00: 05: 03.22

ffmpeg -i input 2>&1 | grep Duration | cut -c 13-23

-1

Tôi sẽ chỉ làm điều này trong C ++ với một tệp văn bản và trích xuất các mã thông báo. Tại sao? Tôi không phải là một chuyên gia về thiết bị đầu cuối linux như những người khác.
Để thiết lập nó, tôi sẽ thực hiện việc này trong Linux ..

ffmpeg -i 2>&1 | grep "" > mytext.txt

và sau đó chạy một số ứng dụng C ++ để lấy dữ liệu cần thiết. Có thể trích xuất tất cả các giá trị quan trọng và định dạng lại nó để xử lý thêm bằng cách sử dụng mã thông báo. Tôi sẽ chỉ phải làm việc trên giải pháp của riêng mình và mọi người sẽ chỉ giễu cợt tôi bởi vì tôi là một newbie linux và tôi không thích viết kịch bản quá nhiều.


-1

Argh. Quên đi. Có vẻ như tôi phải lấy mạng nhện ra khỏi lập trình C và C ++ của mình và sử dụng nó để thay thế. Tôi không biết tất cả các thủ thuật shell để nó hoạt động. Đây là cách tôi đã đi xa.

ffmpeg -i myfile 2>&1 | grep "" > textdump.txt

và sau đó tôi có thể sẽ trích xuất thời lượng bằng ứng dụng C ++ thay vì trích xuất mã thông báo.

Tôi không đăng giải pháp vì hiện tại tôi không phải là người tử tế

Cập nhật - Tôi có cách tiếp cận của mình để lấy dấu thời gian thời lượng đó

Bước 1 - Nhận thông tin phương tiện vào tệp văn bản
`ffprobe -i myfile 2>&1 | grep "" > textdump.txt`
HOẶC
`ffprobe -i myfile 2>&1 | awk '{ print }' > textdump.txt`

Bước 2 - Trang chủ thông tin cần thiết và trích xuất nó
cat textdump.txt | grep "Duration" | awk '{ print $2 }' | ./a.out
Thông báo a.out. Đó là mã C của tôi để cắt bỏ dấu phẩy kết quả vì đầu ra giống như 00: 00: 01.33,
Đây là mã C lấy stdin và xuất ra thông tin chính xác cần thiết. Tôi đã phải thực hiện nhiều hơn và ít hơn các đăng xuất để xem.

#include stdio.h #include string.h void main() { //by Admiral Smith Nov 3. 2016 char time[80]; int len; char *correct; scanf("%s", &time); correct = (char *)malloc(strlen(time)); if (!correct) { printf("\nmemory error"); return; } memcpy(correct,&time,strlen(time)-1); correct[strlen(time)]='/0'; printf("%s", correct); free(correct); }

Bây giờ các định dạng đầu ra chính xác như 00: 00: 01.33


-5

Bạn có thể thử điều này:

/*
* Determine video duration with ffmpeg
* ffmpeg should be installed on your server.
*/
function mbmGetFLVDuration($file){

  //$time = 00:00:00.000 format
  $time =  exec("ffmpeg -i ".$file." 2>&1 | grep 'Duration' | cut -d ' ' -f 4 | sed s/,//");

  $duration = explode(":",$time);
  $duration_in_seconds = $duration[0]*3600 + $duration[1]*60+ round($duration[2]);

  return $duration_in_seconds;

}

$duration = mbmGetFLVDuration('/home/username/webdir/video/file.mov');
echo $duration;

-5

ffmpeg đã được thay thế bởi avconv: chỉ cần thay thế avconb thành câu trả lời của Louis Marascio.

avconv -i file.mp4 2>&1 | grep Duration | sed 's/Duration: \(.*\), start.*/\1/g'

Lưu ý: điều kiện. * Sau khi bắt đầu để có thời gian một mình !!


1
Chữ "" giả ffmpegtừ Libav (một nhánh của dự án FFmpeg) đã được thay thế bằng avconvtừ Libav. ffmpegtừ FFmpeg đang được phát triển rất tích cực.
llogan
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.