Sách

Thứ Hai, 4 tháng 3, 2019

[ffmpeg Tutorial] Lấy Thông Tin Video Bằng Ffmpeg

Lấy thông tin video sử dụng ffmpeg

Câu lệnh

Để lấy được thông tin video bằng ffmpeg bạn có thể sử dụng câu lệnh sau:
ffmpeg -i input.mp4 -hide_banner
Trong đó:
  • -i là cờ dùng để xác định file input, sau đó là tên của file đầu vào (input.mp4)
  • -hide_banner là cờ dùng để bỏ qua thông tin liên quan đến phiên bản, các thư viện mà FFmpeg sử dụng,…

Phân tích kết quả

Ví dụ khi mình lấy thông tin của video bằng FFmpeg như sau:



Lấy thông tin của video sử dụng ffmpeg.exe
Lấy thông tin video bằng FFmpeg sử dụng ffmpeg.exe

Bạn có thể thấy video mà mình thử nghiệm ở đây có thời lượng (duration) là 00:21:38.21 (tức ~ 21 phút 38 giây) và bitrate là 1123kb/s.
Ngoài ra, bạn cũng thấy rằng file này có 2 stream (hay gọi là 2 kênh cho dễ hiểu). Kênh 1 ứng với Stream #0:0 và kênh 2 ứng với Stream #0: 1.
Trong đó:
  • Kênh 1 (video) được encode theo chuẩn h264 với profile level là Main; mỗi frame ảnh có định dạng yuv420pkích thước video là 854×480 (với width=854 và height=480); bitrate của kênh video là 990 kb/s (dĩ nhiên sẽ nhỏ hơn bitrate tổng của cả video); tỉ lệ framerate là 23.98 fps; 
  • Kênh 2 (audio) có chuẩn aac; sample rate là 44100 Hz; âm thanh dạng stereo; bitrate là 127 kb/s. 
Đây là những thông tin của video mà bạn cần phải biết. Ngoài ra, nếu muốn biết thêm nhiều thông tin hơn nữa thì bạn có thể sử dụng công cụ ffprobe.exe như sau.

Lấy thông tin video sử dụng ffprobe.exe

Câu lệnh cơ bản

Câu lệnh cơ bản sử dụng ffprobe.exe để lấy thông tin video là:
ffprobe -v error -show_format -show_streams input.mp4
Kết quả hiển thị khá dài:
[STREAM]
index=0
codec_name=h264
codec_long_name=H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10
profile=Main
codec_type=video
codec_time_base=38946407/1867560000
codec_tag_string=avc1
codec_tag=0x31637661
width=854
height=480
coded_width=854
coded_height=480
has_b_frames=2
sample_aspect_ratio=0:1
display_aspect_ratio=0:1
pix_fmt=yuv420p
level=30
color_range=tv
color_space=bt709
color_transfer=bt709
color_primaries=bt709
chroma_location=left
field_order=unknown
timecode=N/A
refs=1
is_avc=true
nal_length_size=4
id=N/A
r_frame_rate=24000/1001
avg_frame_rate=933780000/38946407
time_base=1/90000
start_pts=0
start_time=0.000000
duration_ts=116839221
duration=1298.213567
bit_rate=990486
max_bit_rate=N/A
bits_per_raw_sample=8
nb_frames=31126
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:creation_time=2013-03-21T04:50:31.000000Z
TAG:language=und
TAG:encoder=JVT/AVC Coding
[/STREAM]
[STREAM]
index=1
codec_name=aac
codec_long_name=AAC (Advanced Audio Coding)
profile=LC
codec_type=audio
codec_time_base=1/44100
codec_tag_string=mp4a
codec_tag=0x6134706d
sample_fmt=fltp
sample_rate=44100
channels=2
channel_layout=stereo
bits_per_sample=0
id=N/A
r_frame_rate=0/0
avg_frame_rate=0/0
time_base=1/44100
start_pts=0
start_time=0.000000
duration_ts=57250816
duration=1298.204444
bit_rate=127986
max_bit_rate=185256
bits_per_raw_sample=N/A
nb_frames=55909
nb_read_frames=N/A
nb_read_packets=N/A
DISPOSITION:default=1
DISPOSITION:dub=0
DISPOSITION:original=0
DISPOSITION:comment=0
DISPOSITION:lyrics=0
DISPOSITION:karaoke=0
DISPOSITION:forced=0
DISPOSITION:hearing_impaired=0
DISPOSITION:visual_impaired=0
DISPOSITION:clean_effects=0
DISPOSITION:attached_pic=0
DISPOSITION:timed_thumbnails=0
TAG:creation_time=2013-03-21T04:50:31.000000Z
TAG:language=eng
[/STREAM]
[FORMAT]
filename=input.mp4
nb_streams=2
nb_programs=0
format_name=mov,mp4,m4a,3gp,3g2,mj2
format_long_name=QuickTime / MOV
start_time=0.000000
duration=1298.213567
size=182308296
bit_rate=1123441
probe_score=100
TAG:major_brand=mp42
TAG:minor_version=0
TAG:compatible_brands=mp42isomavc1
TAG:creation_time=2013-03-21T04:50:31.000000Z
TAG:encoder=HandBrake rev4860 2012121899
[/FORMAT]
Có khá nhiều thông tin ở đây mà mình nghĩ là rất khó để thể giải thích hết ở đây được (bạn thông cảm nhé).
Dĩ nhiên, với yêu cầu sử dụng FFmpeg cơ bản thì mình nghĩ rằng bạn không cần thiết phải biết hết những thông tin này.
Cái nào cần thì mình tra thôi. Nhưng, biết đâu đấy, sau này cần phải dùng thì sao nhỉ?
À mà ffprobe.exe còn hỗ trợ việc lấy ra thông tin video dạng JSON hoặc XML. Khi đó, bạn có thể sử dụng kết quả ở nhiều nơi khác nữa (khi lập trình hoặc viết script chạy tự động,…).

Lấy thông tin video dạng JSON

Để thực hiện việc này bạn chỉ cần thêm cờ  -print_format với giá trị json.
Khi đó, câu lệnh trên trở thành:
ffprobe -v error -print_format json -show_format -show_streams input.mp4
Kết quả dạng JSON:
{
    "streams": [
        {
            "index": 0,
            "codec_name": "h264",
            "codec_long_name": "H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10",
            "profile": "Main",
            "codec_type": "video",
            "codec_time_base": "38946407/1867560000",
            "codec_tag_string": "avc1",
            "codec_tag": "0x31637661",
            "width": 854,
            "height": 480,
            "coded_width": 854,
            "coded_height": 480,
            "has_b_frames": 2,
            "sample_aspect_ratio": "0:1",
            "display_aspect_ratio": "0:1",
            "pix_fmt": "yuv420p",
            "level": 30,
            "color_range": "tv",
            "color_space": "bt709",
            "color_transfer": "bt709",
            "color_primaries": "bt709",
            "chroma_location": "left",
            "refs": 1,
            "is_avc": "true",
            "nal_length_size": "4",
            "r_frame_rate": "24000/1001",
            "avg_frame_rate": "933780000/38946407",
            "time_base": "1/90000",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 116839221,
            "duration": "1298.213567",
            "bit_rate": "990486",
            "bits_per_raw_sample": "8",
            "nb_frames": "31126",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2013-03-21T04:50:31.000000Z",
                "language": "und",
                "encoder": "JVT/AVC Coding"
            }
        },
        {
            "index": 1,
            "codec_name": "aac",
            "codec_long_name": "AAC (Advanced Audio Coding)",
            "profile": "LC",
            "codec_type": "audio",
            "codec_time_base": "1/44100",
            "codec_tag_string": "mp4a",
            "codec_tag": "0x6134706d",
            "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/44100",
            "start_pts": 0,
            "start_time": "0.000000",
            "duration_ts": 57250816,
            "duration": "1298.204444",
            "bit_rate": "127986",
            "max_bit_rate": "185256",
            "nb_frames": "55909",
            "disposition": {
                "default": 1,
                "dub": 0,
                "original": 0,
                "comment": 0,
                "lyrics": 0,
                "karaoke": 0,
                "forced": 0,
                "hearing_impaired": 0,
                "visual_impaired": 0,
                "clean_effects": 0,
                "attached_pic": 0,
                "timed_thumbnails": 0
            },
            "tags": {
                "creation_time": "2013-03-21T04:50:31.000000Z",
                "language": "eng"
            }
        }
    ],
    "format": {
        "filename": "input.mp4",
        "nb_streams": 2,
        "nb_programs": 0,
        "format_name": "mov,mp4,m4a,3gp,3g2,mj2",
        "format_long_name": "QuickTime / MOV",
        "start_time": "0.000000",
        "duration": "1298.213567",
        "size": "182308296",
        "bit_rate": "1123441",
        "probe_score": 100,
        "tags": {
            "major_brand": "mp42",
            "minor_version": "0",
            "compatible_brands": "mp42isomavc1",
            "creation_time": "2013-03-21T04:50:31.000000Z",
            "encoder": "HandBrake rev4860 2012121899"
        }
    }
}

Lấy thông tin video dạng XML

Tương tự, để lấy thông tin video dạng XML, bạn chỉ cần thêm cờ -print_format với giá trị là xml.
Khi đó, câu lệnh trên trở thành:
ffprobe -v error -print_format xml -show_format -show_streams input.mp4
Kết quả dạng XML:
<?xml version="1.0" encoding="UTF-8"?>
<ffprobe>
    <streams>
        <stream index="0" codec_name="h264" codec_long_name="H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10" profile="Main" codec_type="video" codec_time_base="38946407/1867560000" codec_tag_string="avc1" codec_tag="0x31637661" width="854" height="480" coded_width="854" coded_height="480" has_b_frames="2" sample_aspect_ratio="0:1" display_aspect_ratio="0:1" pix_fmt="yuv420p" level="30" color_range="tv" color_space="bt709" color_transfer="bt709" color_primaries="bt709" chroma_location="left" refs="1" is_avc="true" nal_length_size="4" r_frame_rate="24000/1001" avg_frame_rate="933780000/38946407" time_base="1/90000" start_pts="0" start_time="0.000000" duration_ts="116839221" duration="1298.213567" bit_rate="990486" bits_per_raw_sample="8" nb_frames="31126">
            <disposition default="1" dub="0" original="0" comment="0" lyrics="0" karaoke="0" forced="0" hearing_impaired="0" visual_impaired="0" clean_effects="0" attached_pic="0" timed_thumbnails="0"/>
            <tag key="creation_time" value="2013-03-21T04:50:31.000000Z"/>
            <tag key="language" value="und"/>
            <tag key="encoder" value="JVT/AVC Coding"/>
        </stream>
        <stream index="1" codec_name="aac" codec_long_name="AAC (Advanced Audio Coding)" profile="LC" codec_type="audio" codec_time_base="1/44100" codec_tag_string="mp4a" codec_tag="0x6134706d" 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/44100" start_pts="0" start_time="0.000000" duration_ts="57250816" duration="1298.204444" bit_rate="127986" max_bit_rate="185256" nb_frames="55909">
            <disposition default="1" dub="0" original="0" comment="0" lyrics="0" karaoke="0" forced="0" hearing_impaired="0" visual_impaired="0" clean_effects="0" attached_pic="0" timed_thumbnails="0"/>
            <tag key="creation_time" value="2013-03-21T04:50:31.000000Z"/>
            <tag key="language" value="eng"/>
        </stream>
    </streams>

    <format filename="input.mp4" nb_streams="2" nb_programs="0" format_name="mov,mp4,m4a,3gp,3g2,mj2" format_long_name="QuickTime / MOV" start_time="0.000000" duration="1298.213567" size="182308296" bit_rate="1123441" probe_score="100">
        <tag key="major_brand" value="mp42"/>
        <tag key="minor_version" value="0"/>
        <tag key="compatible_brands" value="mp42isomavc1"/>
        <tag key="creation_time" value="2013-03-21T04:50:31.000000Z"/>
        <tag key="encoder" value="HandBrake rev4860 2012121899"/>
    </format>
</ffprobe>

Lời kết

Trên đây là 2 cách để lấy thông tin video bằng FFmpeg. Nếu có gì sai sót, bạn vui lòng góp ý cho mình biết trong phần bình luận phía dưới nhé!
Xin chào và hẹn gặp lại, thân ái!

[ffmpeg Tutorial] Những Câu Lệnh Ffmpeg Xử Lý Video

FFmpeg là một công cụ miễn phí mà rất mạnh trong việc xử lý hình ảnh, video, audio,… Nếu bạn chưa biết cách cài đặt FFmpeg, vui lòng tham khảo thêm tại bài viết hướng dẫn tìm hiểu FFmpeg cơ bản. Còn trong bài viết này, mình sẽ giúp bạn tổng hợp những câu lệnh FFmpeg xử lý video đơn giản và hiệu quả nhất. Mời bạn theo dõi bài viết!

Thay đổi kích thước video

Thay đổi kích thước video với kích thước xác định

Nếu bạn đơn giản muốn thay đổi kích thước video thành một kích thước xác định trước, thì bạn có thể sử dụng câu lệnh sau:
ffmpeg -i input.mp4 -vf scale=320:240 output.mp4
Trong đó:
  • ffmpeg: tên chương trình
  • -i: cờ xác định đầu vào (input)
  • input.mp4: tên video đầu vào
  • -vf: cờ xác định biểu thức cho việc scale video
  • scale=320:240: biểu thức để scale video
  • output.mp4: tên video đầu ra
Câu lệnh này scale video thành kích thước 320×240 (width=320 và height=240). Lúc này toàn bộ video sẽ bị co hoặc dãn đến kích thước 320×240.

Thay đổi kích thước video giữ nguyên tỉ lệ

Nếu chỉ sử dụng câu lệnh như trên thì rất có thể tỉ lệ width/height của video sẽ bị thay đổi, dẫn đến hình ảnh bị méo mó. Do đó, để giữ nguyên tỉ lệ video bạn có thể thay đổi câu lệnh trên một chút, bằng cách chỉ xác định width hoặc height, chiều còn lại bạn để -1, như sau đây.
Giữ nguyên chiều rộng:
ffmpeg -i input.mp4 -vf scale=320:-1 output.mp4
Giữ nguyên chiều cao:
ffmpeg -i input.mp4 -vf scale=-1:240 output.mp4
Chú ý: Một vài định dạng video yêu cầu chiều dài, chiều rộng phải chia hết cho số n(thường n = 2). Khi đó, bạn chỉ cần thay -1 thành -n.
Giữ nguyên chiều rộng:
ffmpeg -i input.mp4 -vf scale=320:-n output.mp4
Giữ nguyên chiều cao:
ffmpeg -i input.mp4 -vf scale=-n:240 output.mp4

Thay đổi kích thước video sử dụng biến số

Nhiều khi bạn sẽ muốn thay đổi kích thước video bằng cách nhân/chia chiều rộng/cao cho một số bất kỳ. Lúc này bạn có thể sử dụng biến số iw (chiều rộng), ih (chiều cao). Ví dụ, để tăng kích thước chiều rộng và chiều cao của video lên 2 lần bạn có thể sử dụng câu lệnh sau:
ffmpeg -i input.mp4 -vf scale=iw*2:ih*2 output.mp4
Ngược lại, nếu bạn muốn giảm kích thước video đi 2 lần, bạn có thể nhân 2 kích thước với 0.5:
ffmpeg -i input.mp4 -vf scale=iw*0.5:ih*0.5 output.mp4
hoặc chia 2 kích thước cho 2:
ffmpeg -i input.mp4 -vf scale=iw/2:ih/2 output.mp4

Tránh tăng kích thước của video có kích thước quá nhỏ

Giả sử, bạn muốn thu nhỏ kích thước video xuống thành 320×240. Nhưng thực tế, kích thước của video đã nhỏ hơn 320×240 rồi. Khi đó, bạn muốn giữ nguyên kích thước của video. Hay nói cách khác, bạn sẽ chỉ thu nhỏ kích thước của video xuống 320×240 nếu kích thước thực tế lớn hơn 320×240.
Lúc này, bạn có thể sử dụng biểu thức min:
ffmpeg -i input.mp4 -vf scale='min(320,iw)':'min(240,ih)' output.mp4

Làm cho video phù hợp với khung hình có sẵn

Trong trường hợp bạn muốn video của mình có kích thước phù hợp với một khung hình chữ nhật cho trước, mà vẫn muốn giữ nguyên tỉ lệ width/height. Khi đó bạn có thể sử dụng option force_original_aspect_ratio với 2 giá trị là:
  • decrease: video đầu ra sẽ tự động giảm kích thước nếu cần thiết
  • increase: video đầu ra sẽ tự động tăng kích thước nếu cần thiết
Ví dụ: đoạn code sau sẽ giảm kích thước của video để phù hợp với khung hình 320×240:
ffmpeg -i input.mp4 -vf scale=w=320:h=240:force_original_aspect_ratio=decrease output.mp4
Vì bạn giữ nguyên tỉ lệ video, nên rất có thể sẽ xuất hiện khoảng trống của video so với khung hình. Lúc này, bạn có thể sử dụng filter pad để điền đầy màu đen vào khoảng trống kia:
ffmpeg -i input.mp4 -vf "scale=320:240:force_original_aspect_ratio=decrease,pad=320:240:(ow-iw)/2:(oh-ih)/2" output.mp4

Xác định thuật toán scale

FFmpeg hỗ trợ nhiều loại thuật toán để scale video, bao gồm: fastbilinear, bilinear, bicubic, experimental, neighbor, area, bicublin, gauss, sinc, lanczos, spline, accuraternd, fullchromaint, fullchromainp, bitexact. Thuật toán mặc định là: bicubic.
Để có thể lựa chọn thuật toán thay đổi kích thước video, bạn cần sử dụng option -sws_flags.
Ví dụ, bạn muốn sử dụng thuật toán bilinear thay vì thuật toán mặc định bicubic thì có thể sử dụng câu lệnh sau:
ffmpeg -i input.mp4 -vf scale=320:240 -sws_flags bilinear output.mp4
Để sử dụng nhiều giá trị cho cờ trên, bạn có thể sử dụng dấu +, ví dụ:
ffmpeg -i input.mp4 -vf scale=320:240 -sws_flags lanczos+full_chroma_inp output.mp4

Thay đổi định dạng video

ffmpeg -i input.xxx output.yyy
Trong đó:
  • File đầu vào là input.xxx với xxx là các định dạng video của file đầu vào: mp4, avi, mpg, flv,…
  • File đầu ra là output.yyy với yyy cũng là các định dạng video của file đầu vào: mp4, avi, mpg, flv,…
Ví dụ, mình muốn chuyển từ định dạng mp4 sang flv, thì câu lệnh sẽ là:
ffmpeg -i input.mp4 output.flv

Thay đổi framerate của video

Video thường có rất nhiều giá trị framerate khác nhau như: 24, 25, 29.97, 30, 60,… Khi bạn muốn ghép nhiều video với nhau thì một trong những việc bạn cần phải làm là đưa chúng về cùng framerate.
Ví dụ, câu lệnh sau sẽ thay đổi framerate của video thành 25 (frame/second):
ffmpeg -i input.mp4 -r 25 output.mp4

Encode video thành chuẩn H264

Chuẩn H264 (MPEG-4 Part 10, MPEG-4 AVC) là một chuẩn mã hoá video rất phổ biến. Những video theo chuẩn H264 thường có đuôi là .mp4. Vì vậy, những video theo chuẩn này có thể play trên rất nhiều thiết bị khác nhau.
Để encode video thành chuẩn H264, bạn có thể sử dụng 2 phương pháp: Constant Rate Factor (CRF) hoặc Two-Pass ABR. Tuy nhiên, mình thấy phương pháp CRF có vẻ đơn giản hơn.
Ví dụ câu lệnh sau sẽ encode video về chuẩn H264 sử dụng CRF:
ffmpeg -i input.avi -c:v libx264 -preset slow -crf 22 -c:a copy output.mp4
Ngoài những thứ cơ bản mà mình đã nói ở các phần trên thì những thông tin bạn cần phải quan tâm đó là:
  • -c:v: cờ dùng để xác định thư viện dùng để encode h264
  • libx264: tên thư viện dùng để encode h264. Ngoài libx264, bạn có thể sử dụng lib h264. Nói vậy thôi, nhưng thực tế, h264 chỉ free cho việc decode h264. Trong khi đó, libx264 là free, open source cho cả decode và encode. Vì vậy, bạn nên sử dụng libx264.
  • -preset: cờ dùng để xác định preset được sử dụng. Giá trị này sẽ quyết định tốc độ mã hoá.
  • slow: tên preset sử dụng. Ngoài slow, bạn có thể dùng: ultrafast, superfast, veryfast, faster, fast, medium (default preset), slow, slower, veryslow. Trong dãy các giá trị trên, từ trái sang phải sẽ cho chất lượng video tăng dần, nhưng tốc độ mã hoá sẽ giảm dần. Hay nói cách khác, tốc độ mã hoá video càng chậm thì chất lượng video càng tốt.
  • -crf: cờ xác định hệ số CRF.
  • 22: hệ số CRF. Giá trị CRF có thể là từ 0 đến 51, với giá trị mặc định là 23. Giá trị CRF càng lớn thì chất lượng video càng giảm và ngược lại.
  • -c:a: cờ dùng để xác định thư viện encode audio.
  • copy: trong bài viết này, mình chỉ quan tâm tới video, nên audio sẽ không thay đổi. Hay nó sẽ được copy từ input sang output.

Thay đổi bitrate của video

Giả sử bạn đang muốn Live Streaming một video. Video này có bitrate cỡ 5Mbps. Tuy nhiên, tốc độ mạng cho phép chỉ trong khoảng 1Mbps. Lúc này, bạn cần phải giảm bitrate của video xuống nhỏ hơn 1Mbps.
Ví dụ câu lệnh sau sẽ giới hạn bitrate của video xuống nhỏ hơn hoặc bằng 1Mbps:
ffmpeg -i input -c:v libx264 -crf 23 -maxrate 1M -bufsize 2M output.mp4
Trong đó, những giá trị quan trọng là:
  • -maxrate 1M: xác định bitrate tối đa là 1Mbps
  • -bufsize 2M: xác định buffer cho việc encode video là 2MB.
  • -crf 23: xác định hệ số CRF là 23

Lời kết

Trên đây là một số câu lệnh FFmpeg xử lý video rất phổ biến. Nếu có câu lệnh nào bạn chưa hiểu hoặc bạn cần phải xử lý video về một khía cạnh nào đó mà mình chưa chia sẻ thì bạn có thể để lại câu hỏi trong phần bình luận, mình sẽ cố gắng sưu tầm và chia sẻ lại với bạn.
Xin chào và hẹn gặp lại trong bài viết tiếp theo, thân ái!