Video codec for Developer – Getting start

by monz
401 views
This entry is part [part not set] of 1 in the series Video Codec for Developer
  • Video codec for Developer – Getting start

Chắc hẳn ace đều đã, đang và có thể sẽ làm việc liên quan tới xử lí video (video playing, video streaming, video processing, …). Đây là một thế giới với kho kiến thức khổng lồ, hàng trăm, hàng ngàn paper phải đọc. Mình quyết định sẽ viết một series liên quan tới video codec dưới góc độ làm việc của một developer chứ không phải là R&D để tránh lan man.

Thông qua lượt bài này, mình hi vọng mọi người có thể tiếp cận nhanh và tối giản nhất có thể, để không cần phải đọc và hiểu hàng tá các thuật ngữ, các paper mà có thể khiến chúng ta nản ngay từ vòng gửi xe. Mình sẽ không đi quá sâu vào bất kì thành phần nào mà chỉ đưa ra những keyword cơ bản nhất, cũng như cố gắng giải thích dễ hiểu nhất nhằm giúp người đọc nắm bắt nhanh nhất.

Video codec là gì?

Nói một cách đơn giản thì đây là một (hoặc tập hợp) phương pháp mã hoá video. Mỗi video codec có thể được implement dựa vào phần cứng (hardware coding) hoặc phần mềm (software coding). Tất nhiên nếu sử dụng phần cứng thì sẽ luôn có sự tối ưu hơn với performance tốt hơn rất nhiều, nhưng một chipset sẽ không thể implement quá nhiều các loại thuật toán, vì thế nó vẫn luôn tồn tại song hành với software coding. Tuỳ vào cách lập trình của các lập trình viên cũng như sự hỗ trợ từ framework mà hardware coding có thể được ưu tiên hoặc không.

Phần lớn các chuẩn mã hoá đều là lossy compression (nén có hư tổn dữ liệu) nhằm tối ưu dung lượng lưu trữ cũng như tối ưu truyền tải dữ liệu trên internet. Người nén có thể lựa chọn cân bằng chất lượng hình ảnh với dung lượng từ video gốc sao cho phù hợp với nhu cầu của họ cũng như người sử dụng.

Có rất nhiều các loại codec cũng như các loại chuẩn (standard) được phát triển từ xưa tới nay, đến từ nhiều hãng khác nhau (như MPEG, Google, …), tuy nhiên mình sẽ chỉ focus vào nhóm chuẩn của MPEG (Moving Picture Experts Group) vì đây là các chuẩn thông dụng nhất, và cũng được hỗ trợ nhiều nhất ở thời điểm hiện tại.

Sơ lược về cách hoạt động của quá trình nén

Video codec làm gì mà thần thánh tới mức có thể giảm dung lượng video ghê gớm như vậy? Sau đây mình sẽ giải thích qua cơ chế xử lí của nó để các bạn nắm bắt được nhé.

Một video gốc (raw video) bao gồm rất nhiều các frames (raw frame) nối tiếp với nhau. Mỗi raw frame sẽ chứa thông tin chính xác của từng điểm ảnh, vì thế dung lượng của video sẽ bằng dung lượng của frame nhân với số lượng frame. Thật là kinh hoàng nếu nghĩ tới 1 video 4K@60fps dài khoảng 1 tiếng đúng ko? Các đĩa Bluray ngoài rạp coi film phần lớn đều sử dụng các video gốc như vậy (thậm chí là nhiều lớp) để tăng độ chi tiết cũng như trải nghiệm của người xem ở rạp. Đó là lí do vì sao coi film chiếu rạp luôn có cảm giác "thật" hơn là coi film nén trên mạng, mặc dù độ phân giải là như nhau đó.

Sẽ thật lãng phí nếu có một điểm ảnh không thay đổi trong suốt quá trình ghi lại video. Nếu điểm ảnh đó đã không thay đổi, thì chi bằng ta … khỏi lưu nó lại làm gì, phải không? Okay, đây là nguồn gốc quá trình nén của bất kì loại codec nào có hiện nay, chỉ có điều các kiểu nén có sự khác biệt về thuật toán mà thôi.

+-------+     +-------+
|   I   |     |   P   |
+-------+     +-------+      +-------+
|xxxxxxx|     | o     |      |xoxxxxx|
|xxxxxxx|  +  |    o  |  ->  |xxxxoxx|
|xxxxxxx|     |   o   |      |xxxoxxx|
+-------+     +-------+      +-------+

Ta tạm hiểu rằng mỗi video khi bắt đầu sẽ cần có 1 frame gốc để dựng hình, cái này gọi là intraframe (viết tắt là I-frame, hoặc còn được biết với các tên là keyframe). Đây là frame gốc, lưu trữ toàn bộ các điểm ảnh ban đầu để khi giải mã có thể dựng được frame đầu tiên (tất nhiên frame này cũng đã được nén, tương tự như nén ảnh). Sau intraframe là các interframe, mà nó không lưu trữ đủ thông tin các điểm ảnh, chỉ lưu trữ thông tin SỰ KHÁC NHAU giữa 2 frame. Có 2 loại interframe là P-frame (predictive frame) và B-frame (bi-directional predictive frame). P-frame được giải mã dựa trên I-frame hoặc P-frame ngay phía trước nó. B-frame cũng tương tự như P-frame, nhưng nó có thể giải mã dựa trên thông tin của cả frame phía sau nó nữa.

Trong một video sẽ có rất nhiều intraframe, mà tần suất xuất hiện của nó được qui định bằng GOP (hoặc GOV). Mục đích của nó là để giải quyết bài toán seeking, cũng như hạn chế việc loss thông tin trong quá trình giải mã video thì cần sync lại để tránh video bị lỗi quá nhiều. GOP (GOV) là viết tắt của cụm từ Group of Picture (hoặc Group of Video), mô tả số lượng I/P/B frames từ keyframe này tới keyframe tiếp theo. Trong một số hệ thống encoding sẽ không xuất hiện tham số GOP này mà sử dụng tham số I-frame interval. Con số này mô tả rằng sau bao nhiêu giây sẽ xuất hiện 1 I-frame

+-------------------------------------------------------------------------------+
| I | P | P | P | P | P | P | P | P | P | I | P | P | P | P | P | P | P | P | P |
+-------------------------------------------------------------------------------+
|                GOP = 10               |                GOP = 10               |
+-------------------------------------------------------------------------------+
|                                   20 frames                                   |
+-------------------------------------------------------------------------------+

Nếu ta cho rằng video trong sơ đồ phía trên có framerate (tốc độ khung hình) là 20fps, vậy đồng nghĩa với việc I-frame interval là 0.5. Quá đơn giản phải không nào 😀

Chất lượng của việc nén sẽ được qui định bằng con số bitrate, với đơn vị thường thấy là kbps (kilobits per sec). Hiểu một cách nôm na thì đây chính là kích thước thực của video trong mỗi giây. Con số này có thể là không đổi cho toàn bộ video (CBR – Constant Bitrate), hoặc cũng có thể thay đổi tuỳ vào thời điểm của video (VBR – Variable Bitrate), được qui định tại thời điểm encode. Giả dụ ta có 1 bài toán đơn giản như sau:

1 video được nén CBR, độ dài là 30s với bitrate = 5120kbps
=> dung lượng của video = 5120 / 8 * 30 = 19200 KB ~ 18.75MB

Như các bạn có thể thấy, dung lượng của video không còn quan tâm tới resolution (độ phân giải), mà dung lượng được quyết định bởi bitrate. Ồ, vậy thì độ phân giải còn có vai trò gì nữa? Tất nhiên là nó vẫn có rỗi. Với kiến thức thông thường, ta biết rằng độ phân giải sẽ quyết định mức độ chi tiết của ảnh. Độ chi tiết càng cao thì lượng thông tin càng lớn. Vì vậy nếu ta giữ nguyên bitrate để nén video với lượng thông tin lớn, thì hiển nhiên chất lượng của nó sẽ kém đi. Đây chính là lí do vì sao đôi khi ta gặp những video 4K nhưng lại có chất lượng kém hơn cả video 2K hay 1080p, đơn giản vì nó có bitrate thấp, không tương xứng với chất lượng hình ảnh.

Như ví dụ dưới đây, mình sẽ minh hoạ 2 trường hợp phổ biến mà ta thường gặp. Cho rằng dữ liệu gốc là không đổi (4K lossless downscale xuống 1K lossless), các bạn thử tự hình dung xem kết quả nào cho chất lượng tốt hơn nhé?

* TH1: nén video 4K với 300 units = bitrate 5120kbps?
* TH2: nén video 1K với 100 units = bitrate 5120kbps?

Trên đây mình đã mô tả một cách cơ bản nhất về quá trình mã hoá video. Các kiến thức trên là cơ bản nhất và nó gần như đúng với mọi loại thuật toán nén, mọi loại chuẩn nén. Các thuật toán đời mới hiện nay chỉ có sự khác biệt về tối ưu hoá chất lượng, dung lượng cũng như performance mà thôi.

Hẹn gặp lại các bạn ở bài viết sau. Nếu có phần nào không đúng, nhờ các bạn góp ý để chúng ta có nhiều hiểu biết hơn nhé.

Leave a Comment

* By using this form you agree with the storage and handling of your data by this website.