-i là cờ dùng để xác định input, sau đó là tên file (input.mp4)
output.gif là tên file output. Đồng thời, phần đuôi .gif giúp FFmpeg hiểu rằng bạn đang muốn chuyển video thành ảnh động GIF.
-hide_banner dùng để ẩn những thông tin liên quan đến FFmpeg (phiên bản, các thư viện sử dụng,…)
Ví dụ mình convert thử một video dài 7s, kích thước 1920×1080, dung lượng ~ 5MB với câu lệnh trên và kết quả:
Convert video thành ảnh động GIF với câu lệnh đơn giản
Ảnh động GIF có kích thước cỡ ~21MB (gấp 4 lần video gốc).
Tại sao ảnh động GIF lại nặng hơn nhiều so với video tương ứng?
Bởi vì, ảnh động GIF được tạo bởi các ảnh riêng lẻ ứng với ảnh gốc. Trong khi đó, video chỉ lưu chúng lại thành các frame dạng I, P, B. Mà chỉ frame I là frame đầy đủ, còn frame P và B chỉ dùng để lưu lại sự thay đổi nhỏ giữa các frame. Điều này giải thích tại sao ảnh động GIF lại nặng hơn so với video tương ứng.
Vậy làm sao tối ưu được kích thước của ảnh động GIF?
Tối ưu kích thước ảnh động GIF
Thực ra, nếu nói tối ưu thì cũng không hẳn. Chỉ đơn giản là mình giảm kích thước của nó đi thôi.
Có 3 cách để giảm kích thước của ảnh động GIF là:
Giảm thời lượng của ảnh động GIF. Ví dụ: thay vì độ dài 20 giây thì mình chỉ lấy 10 giây, bắt đầu từ giây thứ 5 đến giây thứ 15 chẳng hạn.
Giảm kích thước của ảnh động GIF. Ví dụ: thay vì kích thước Full HD (1920×1080) thì mình giảm xuống HD (1280×720).
Giảm tốc độ framerate (tức số frame trên 1 giây). Ví dụ: thay vì fps=30 thì mình giảm xuống còn fps=20.
Xem thêm: [FFmpeg tutorial] Những câu lệnh FFmpeg xử lý video
Giảm thời lượng ảnh động GIF
Video input.mp4 bên trên có độ dài 7 giây. Mình muốn ảnh động GIF sẽ có độ dài 4 giây, bắt đầu từ giây thứ 2 đến giây thứ 6.
Để làm việc này, mình có thể sử dụng 1 trong 2 câu lệnh sau:
Cách đơn giản nhất để lấy ảnh từ video là trích xuất ra tất cả các ảnh. Để làm việc này, bạn có thể sử dụng câu lệnh sau:
ffmpeg -i mini-input.mp4 img%d.jpg -hide_banner
Trong đó:
-i là cờ xác định file đầu vào, sau đó là tên file đầu vào (ví dụ: mini-input.mp4). Ngoài ra, bạn cũng có thể sử dụng video với các định dạng khác như: webm, flv, mkv,…
img%d.jpg là tham số dùng để xác định tên của file ảnh đầu ra. Ở đây, mình sử dụng file đầu ra dạng jpg. Tuy nhiên, bạn cũng có thể xuất ra file png hoặc bmp,…
-hide_banner: dùng để ẩn những thông tin không cần thiết liên quan đến FFmpeg như phiên bản, các thư viện sử dụng,… như mình đã nói trong bài viết về lấy thông tin video bằng FFmpeg.
Ở đây, với định dạng file đầu ra là img%d thì các file ảnh đầu ra sẽ có tên lần lượt là: img1.jpg, img2.jpg, img3.jpg,… img10.jpg,… img100.jpg…. Nghĩa là độ dài kí tự không bằng nhau.
Nếu muốn độ dài của chúng bằng nhau, bạn có thể sửa lại câu lệnh trên một chút. Thay vì dùng img%d.jpg thì bạn dùng img%nd.jpg (với n là số tự nhiên). Cái này tương tự như lệnh printf trong lập trình C vậy.
Ví dụ: nếu bạn sử dụng img%3d.jpg thì ảnh đầu ra sẽ tên lần lượt là: img001.jpg, img002.jpg, img003.jpg,…
Lấy ra một vài ảnh từ video
Giả sử một video có framerate là 25 fps, độ dài 60 phút thì số lượng frame sẽ là: 25 * 60 * 60 = 90000. Như vậy là quá nhiều phải không?
Trong khi bạn chỉ muốn lấy ra một vài bức ảnh trong đó, thì việc sử dụng cách trên là quá mất thời gian. Thậm chí, máy bạn còn có thể bị đơ, thiếu bộ nhớ,….
Vì vậy, để lấy ra một vài bức ảnh từ video, bạn có thể sử dụng câu lệnh:
-ss là cờ dùng để xác định thời điểm bạn muốn lấy ảnh từ video. Tiếp sau đó là thời gian theo định dạng như trong câu lệnh trên (ví dụ: 00:00:02.000 ứng với thời điểm 2 giây).
-vframes là cờ dùng để xác định số frame muốn lấy ra. Sau đó là số lượng frame (trong ví dụ trên là 5 frame).
img%d.jpg là định dạng file đầu ra, giống như phần trên.
Lấy ra các ảnh cách nhau nhất định
Ngoài các cách trên, bạn có thể lấy ảnh từ video dựa trên một khoảng cách thời gian nhất định. Ví dụ bạn có thể lấy ra tất cả các ảnh cách nhau mỗi 1 giây.
Khi đó, bạn có thể dùng câu lệnh sau:
ffmpeg -i mini-input.mp4 -vf fps=1 img%d.jpg
Trong đó:
-i mini-input.mp4 dùng để xác định file đầu vào.
-vf là cờ dùng để áp dụng video filter vào câu lệnh này. Sau đó là công thức áp dụng. Ở đây mình dùng fps=1, nghĩa là lấy 1 ảnh sau mỗi 1 giây. Ngoài ra, bạn có thể sử dụng fps=1/n, với n là số tự nhiên. Khi đó, FFmpeg sẽ lấy ra 1 ảnh sau mỗi n giây.
img%d.jpg là định dạng file đầu ra, giống như phần trên.
Câu lệnh này có tác dụng khi bạn muốn lấy ra một số ảnh của video đầy đủ để làm một video dạng tóm tắt.
Lấy ra các ảnh là keyframes
Các phương pháp trên rất tốt nhưng bị một vấn đề là: chất lượng frame ảnh lấy ra có khả năng sẽ không tốt.
Vì đối với việc encode video, các frame sẽ được lưu trữ thành các frame dạng I, P, B. Trong đó, chỉ có frame dạng I là tương ứng với ảnh đầy đủ (là keyframe), còn các frame P và B chỉ lưu trữ sự thay đổi giữa các frame.
Do đó, để lấy ảnh từ video tốt nhất, bạn nên lấy ra các ảnh là keyframes bằng câu lệnh:
-vf là cờ dùng để áp dụng video filter vào câu lệnh này. Nhưng khác với câu lệnh phần trên, ở đây, mình sử dụng công thức “`”select=eq(pict_type\,I)”“`. Tạm dịch là: “lựa chọn ra các frame kiểu I”.
-vsync vfr dùng để nói với bộ filter sử dụng cơ chế đồng bộ bitrate. Thực ra, mình cũng không hiểu rõ cờ này cho lắm. Chỉ biết là nếu như không sử dụng cờ này thì kết quả có thể sẽ chứa những frame không phải là keyframe.
img%d.jpg là định dạng file đầu ra, giống như phần trên.
Lời kết
Như vậy là mình đã giới thiệu với bạn 4 cách để lấy ảnh từ video với FFmpeg. Mỗi cách có một tác dụng riêng. Tùy từng trường hợp mà bạn có thể chọn ra cách hợp lý nhất.
Nếu có gì sai sót, mình rất mong nhận được sự góp ý từ bạn.
Để 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 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 yuv420p; kí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à:
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.