💡 Với video mạng xã hội, nền tảng quyết định phương pháp. TikTok và Instagram Reels không nhận file phụ đề bên ngoài, vì vậy phụ đề nhúng cứng là cách duy nhất để có văn bản có style. YouTube và YouTube Shorts nhận upload SRT trực tiếp, nên track phụ đề mềm là lựa chọn tốt hơn: không encode lại, người xem tắt bật được, dùng lại cho nhiều ngôn ngữ.
Ý chính
- Nhúng cứng:
-vf "subtitles=captions.srt:force_style='FontName=Arial,FontSize=28,Outline=2,MarginV=160'"kèm encode lại bằng-c:v libx264 -crf 23. Văn bản trở thành pixel vĩnh viễn. - Track mềm (MP4):
-c:s mov_text -metadata:s:s:0 language=vie -disposition:s:0 default. Video và âm thanh sao chép bằng-c:v copy -c:a copy: không encode lại, không mất chất lượng. - TikTok và Instagram Reels: không có slot upload file phụ đề. Nhúng cứng là cách duy nhất giao nộp phụ đề có style và vị trí chính xác trước khi upload.
- YouTube và YouTube Shorts: upload SRT hoặc VTT trực tiếp trong YouTube Studio. Không cần export lại video; người xem bật tắt được track.
- Phụ đề nhúng cứng không đáp ứng WCAG 1.2.2 cho web video (không tắt được). Track mềm là bắt buộc khi có yêu cầu tuân thủ khả năng tiếp cận.
Phụ đề nhúng cứng và phụ đề mềm khác nhau như thế nào?
Phụ đề nhúng cứng (burn-in hoặc hardcoded captions) được render trực tiếp vào khung hình video: mỗi pixel văn bản trở thành một phần của hình ảnh vĩnh viễn. Sau khi encode xong, không thể xóa hay di chuyển chúng. Phải encode lại là điều không thể tránh khỏi vì bộ lọc subtitles chạy trong video filter graph của ffmpeg và yêu cầu video phải được giải mã, lọc rồi nén lại.
Phụ đề mềm nằm trong một track riêng bên trong container. Player render chúng khi phát. Luồng video không bị động đến: -c:v copy truyền nguyên byte qua. Tôi dùng track mềm cho mọi nội dung cần chỉnh sửa sau, giao nộp nhiều ngôn ngữ, hay để người xem tự kiểm soát.
| Yếu tố | Nhúng cứng | Track mềm |
|---|---|---|
| Người xem tắt bật được | Không | Có (menu phụ đề) |
| Cần encode lại video | Có | Không (-c:v copy) |
| Chỉnh sửa được sau khi giao | Không | Có (thay file phụ đề) |
| Nhiều ngôn ngữ | Mỗi ngôn ngữ một lần encode | Nhiều track, một file video |
| WCAG 1.2.2 (web) | Không đáp ứng (không tắt được) | Đáp ứng yêu cầu bật tắt |
Những nền tảng mạng xã hội nào chấp nhận upload file phụ đề?
Đây là điểm phân kỳ quyết định toàn bộ quy trình. YouTube là ngoại lệ giúp track mềm khả thi với creator. TikTok và Reels là lý do tại sao burn-in tồn tại như một quy trình creator.
| Nền tảng | Upload SRT | Upload VTT | Auto-captions | Chỉnh sửa trong app |
|---|---|---|---|---|
| YouTube / Shorts | Có | Có | Có | Có (YouTube Studio) |
| TikTok | Không | Không | Có | Có (sau auto-gen) |
| Instagram Reels | Không | Không | Có | Có (app Edits) |
YouTube còn nhận SBV, SCC, TTML và nhiều định dạng khác. Với creator cần giao nộp track phụ đề đã dịch, SRT là lựa chọn đơn giản nhất: văn bản thuần, chỉnh sửa được bằng bất kỳ editor nào.
TikTok và Instagram tự tạo auto-captions từ âm thanh sau khi upload, và đều cho phép chỉnh sửa text trong app. Không nền tảng nào có slot upload file phụ đề bên ngoài. Nếu text tự động sai hoặc cần track ngôn ngữ thứ hai, tùy chọn duy nhất là burn phiên bản đã sửa vào pixel video trước khi upload.
Làm thế nào để burn phụ đề vào video bằng ffmpeg?
Bộ lọc subtitles render SRT, WebVTT hoặc bất kỳ định dạng nào libass hỗ trợ. Tùy chọn force_style ghi đè style libass mặc định bằng tên trường ASS V4+. Đây là lệnh tôi dùng cho video dọc 1080x1920 để đăng lên TikTok hoặc Reels:
ffmpeg -i input.mp4 \
-vf "subtitles=captions.srt:force_style='FontName=Arial,FontSize=28,PrimaryColour=&H00FFFFFF,OutlineColour=&H00000000,BorderStyle=1,Outline=2,Shadow=0,MarginV=160'" \
-c:v libx264 -crf 23 -preset slow \
-pix_fmt yuv420p \
-c:a copy \
burned_output.mp4
Các flag quan trọng:
force_style='...': ghi đè style libass mặc định. Màu sắc ASS dùng thứ tự byte ABGR: trắng là&H00FFFFFF, viền đen đặc là&H00000000. Byte alpha00= hoàn toàn không trong suốt.MarginV=160: khoảng cách pixel từ mép dưới frame 1080x1920. Tôi giữ ở 160px trên video dọc để văn bản không bị UI phía dưới của TikTok và Reels che khuất.-c:v libx264 -crf 23 -preset slow: encode H.264 ở CRF 23 với preset slow để nén tốt hơn. Dùng-crf 18nếu cần chất lượng cao hơn.-pix_fmt yuv420p: bắt buộc chroma subsampling 4:2:0. Một số bản build ffmpeg sinh ra yuv420p10 khi libass render; nền tảng sẽ convert lại và làm mờ text thêm một lần nữa.-c:a copy: bộ lọc subtitle không động đến âm thanh. Sao chép nguyên vẹn.
Làm thế nào để thêm track phụ đề mềm mà không encode lại video?
Với output MP4, codec subtitle văn bản duy nhất được chấp nhận là mov_text (3GPP Timed Text). Dùng -c:s srt hoặc -c:s copy vào output MP4 sẽ báo lỗi hoặc ghi track mà hầu hết player âm thầm bỏ qua. Với YouTube, tôi sản xuất MP4 trước, rồi upload file .srt riêng qua YouTube Studio: không encode lại ở bất kỳ bước nào.
ffmpeg -i video.mp4 -i captions.srt \
-map 0 -map 1 \
-c:v copy -c:a copy \
-c:s mov_text \
-metadata:s:s:0 language=vie \
-metadata:s:s:0 title="Vietnamese" \
-disposition:s:0 default \
soft_output.mp4
Ý nghĩa từng flag:
-map 0 -map 1: đưa tất cả stream từ video input, cộng stream đầu tiên từ SRT input.-c:v copy -c:a copy: truyền video và âm thanh nguyên byte. Không mất chất lượng, gần như không tốn thời gian xử lý.-c:s mov_text: chuyển SRT sang định dạng 3GPP Timed Text, codec subtitle văn bản duy nhất MP4 hỗ trợ.-metadata:s:s:0 language=vie: mã ISO 639-2 cho tiếng Việt. Dùngengcho tiếng Anh,fracho tiếng Pháp.-disposition:s:0 default: đánh dấu track này là mặc định, player sẽ tự chọn khi phát.
Kiểm tra kết quả: ffprobe -v error -select_streams s -show_entries stream=codec_name:stream_tags=language -of default=noprint_wrappers=1 soft_output.mp4. Nếu codec_name không phải mov_text, hầu hết player sẽ âm thầm bỏ qua track đó.
Có nên kết hợp cả hai phương pháp trên cùng một file không?
Tôi làm điều này khi client cần cả hai: cả độ phủ nền tảng lẫn khả năng tùy chỉnh cho người xem. Quy trình: bắt đầu từ cùng một video nguồn và SRT, sản xuất file MP4 nhúng cứng cho TikTok và Reels, và file MP4 riêng với track mềm cho YouTube. Cả hai output dùng chung timing và text: không có sự phân kỳ giữa các phiên bản.
Trường hợp kết hợp mang lại giá trị rõ nhất là track phụ đề đã dịch. Burn phiên bản tiếng Việt vào bản TikTok (vì TikTok không nhận file sidecar). Nhúng track tiếng Việt mềm vào bản YouTube cạnh track tiếng Anh. Một SRT mỗi ngôn ngữ, hai biến thể giao nộp, không cần dịch lại.
Tự làm được gì và khi nào chuyên gia thực sự cần thiết?
Cả hai lệnh trên hoàn toàn tự làm được. Viết SRT, burn cho TikTok và Reels, upload SRT lên YouTube Studio. Với nội dung một ngôn ngữ và giọng nói rõ ràng, quy trình này bao phủ toàn bộ yêu cầu kỹ thuật.
Bài toán thay đổi khi cần phụ đề đã dịch. Tiếng Việt dịch từ tiếng Anh thường vượt giới hạn tốc độ đọc vì dòng tiếng Việt dài hơn gốc tiếng Anh. File .srt dịch máy được timing theo cue tiếng Anh thường chạy quá nhanh. Tôi dịch trong Subtitle Edit với cảnh báo CPS hiển thị trực tiếp, điều chỉnh ngắt dòng cho đến khi mọi event nằm trong giới hạn tốc độ đọc trước khi đưa vào ffmpeg.
Với series video thương hiệu, giao nộp nhiều ngôn ngữ, hay web video cần đáp ứng style guide, timing chuyên nghiệp và QC ngôn ngữ bản địa xứng đáng với chi phí. Dịch vụ phụ đề dọc của tôi bao gồm cả hướng burn-in lẫn hướng giao nộp track mềm, từ dịch thuật đến export ffmpeg.
Câu hỏi thường gặp
Có thể burn phụ đề mà không encode lại video không?
Không. Bộ lọc subtitles và ass chạy trong video filter graph của ffmpeg, đòi hỏi giải mã và encode lại luồng video. Dùng -c:v copy trong khi có -vf filter sẽ báo lỗi. Âm thanh không bị ảnh hưởng: -c:a copy luôn hoạt động song song với subtitle filter.
Tại sao phụ đề burn-in của tôi bị mờ sau khi upload lên TikTok?
TikTok encode lại mọi video upload. Nếu phụ đề được render lên proxy đã scale xuống trước khi encode H.264 cuối, quá trình upload encode nhân thêm độ mờ. Luôn burn trên frame đầy đủ 1080x1920. Cũng kiểm tra đã thêm -pix_fmt yuv420p chưa: một số bản ffmpeg sinh yuv420p10 khi libass render, và pipeline của TikTok xử lý điều đó với thêm một lần chuyển đổi chroma.
Có thể upload phụ đề tiếng Việt lên YouTube như track mềm không?
Có. Upload file .srt tiếng Việt trong YouTube Studio và chọn ngôn ngữ Vietnamese. Người xem chọn track đó từ menu phụ đề cạnh các track khác. Lưu file ở chế độ UTF-8 không có BOM từ Subtitle Edit: ký tự tiếng Việt đầy đủ dấu nằm trong phạm vi UTF-8 và hiển thị đúng trên player YouTube.
mov_text có giữ nguyên dấu tiếng Việt trong file MP4 không?
Có, miễn là SRT nguồn được encode UTF-8. Codec mov_text lưu text trong UTF-8 bên trong MP4. Trường hợp thất bại thường gặp là file nguồn được lưu dưới Windows-1252: dấu tiếng Việt bị lỗi trước khi ffmpeg xử lý text. Kiểm tra File > Character encoding trong Subtitle Edit và lưu lại dưới UTF-8 không có BOM trước khi chạy lệnh ffmpeg.
Dùng CRF bao nhiêu khi burn phụ đề cho video mạng xã hội?
Với TikTok và Reels, tôi dùng -crf 23: tạo file sạch ở dung lượng hợp lý và nền tảng sẽ encode lại ở phía họ dù sao. Với upload YouTube nơi nền tảng giữ lại nhiều chất lượng hơn, tôi thích -crf 18 để text burn-in sắc nét hơn sau khi platform xử lý. Cả hai dùng -preset slow để nén tốt hơn ở cùng mức chất lượng.
Nguồn
- FFmpeg documentation: bộ lọc subtitles và tùy chọn force_style - tài liệu tham chiếu chính thức cho các lệnh burn-in và trường style libass. Kiểm tra tháng 10/2026.
- FFmpeg codec documentation: codec subtitle mov_text - xác nhận mov_text là codec bắt buộc cho track phụ đề mềm trong MP4. Kiểm tra tháng 10/2026.
- YouTube Help: Supported subtitle and closed caption files - liệt kê SRT, VTT, SBV, SCC và tất cả định dạng được chấp nhận. Kiểm tra tháng 10/2026.
- TikTok Newsroom: Introducing auto captions - xác nhận tính năng auto-caption và chỉnh sửa trong app; không đề cập upload file phụ đề. Kiểm tra tháng 10/2026.
- Instagram Help: Manage closed captions for your reels - xác nhận auto-captions qua nhận dạng giọng nói và chỉnh sửa trong app. Kiểm tra tháng 10/2026.

Bài viết bởi Đào Huy (Lucas), biên dịch viên và chuyên viên bản địa hóa tiếng Việt (Anh, Trung, Pháp sang Việt). See translation services →
