Libc

Bắt đầu từ đoạn code nhỏ dưới viết bằng ngôn ngữ C. Ngoài dòng có chữ printf ra, thì các dòng khác được được biên dịch trực tiếp ra ASM và sang mã máy mà không cần thông qua thư viện nào hỗ trợ. Dĩ nhiên rồi cái nào cũng ra mã máy cả, nhưng printf có gì đặc biệt.

libc

Quay lại chút về ngôn ngữ C, được Dennis Ritchie xây dựng vào 1978, dựa trên ngôn ngữ B, đằng sau đó là 1 câu chuyện dài thú vị, nhưng giờ không phải lúc để kể. C là một ngôn ngữ lập trình, tất nhiên ai cũng biết rồi, tức là để tạo nên C sẽ có 1 loạt qui định về cấu trúc mã lệnh, từ khóa, toán tử … Bên cạnh đó có 1 thứ gần như luôn đi cùng đó là thư viện chuẩn của C, còn gọi là libc, quá quen thuộc với những ai lập trình C. Thư viện này được chuẩn hóa C POSIX library hẳn hỏi, và vẫn được bổ sung theo thời gian.

Thư viện này thuộc loại căn bản của C rồi, nên gần như nó luôn tồn tại sẵn làm người ta đôi lúc quên mất sự hiện diện của nó. Thực tế cũng giống như các thư viện khác, dựa vào đặc tả trên, nó cũng được code, biên dịch trước thành mã máy để liên kết vào chương trình nào dùng đến nó.
Trên môi trường GNU/Linux thì dùng glibc của GNU, trên android thì có bionic do google thực hiện để tránh cho Android đỡ dính đến copyleft licenses chừng nào có thể (trong khi đó vẫn dùng Linux Kernel → LOL), trên các hệ điều hành BSD ( ex: MacOS) cũng tự tạo BSD libc riêng của nó, ngoài ra còn nhiều trường hợp khác cũng viết lại thư viện này, để phù hợp hơn với yêu cầu hệ thống, ví dụ như đôi lúc không cần thiết phải dùng hết toàn bộ libc nhất là đối với môi trường hạn chế tài nguyên.

Trở lại vấn đề chút đoạn mã trên, vậy cái hàm printf trên nó là thuộc libc, chi tiết hơn là thư viện chuẩn vào ra (I/O) stdio.h. Nếu biên dịch trên GNU/Linux thì nó liên kết đến thư viện glibc trên đó để tạo ra mã máy.

Ngó qua chút xem 1 hàm “đơn giản” như printf thì có mã lệnh thế nào.
Official glibc repo ở đây, hàm printf nó ở chỗ này, rồi nhảy sang chỗ này, tổng cộng chỉ có “ít ỏi” gần 2500 dòng lệnh.

Đến đây có chút thú vị trên môi trường OS dùng nhân linux, do chỉ dùng glibc trên user space, nên thành ra ở kernel space không dùng được các hàm libc. Do đó lúc muốn printf thì làm sao giờ?, vậy là Linus viết luôn hàm printk thay thế, đúng theo triết lý, thấy ổ gà thì lấp.

Hậu quả do rò rỉ thông tin

Đọc lại 7 viên ngọc rồng, bản dịch theo đúng nguyên bản gốc (đã so sánh với vài quyển bản tiếng Nhật) ở link dưới.
https://blogtruyen69.com/truyen-tranh/15-dragon-ball-7-vien-ngoc-rong.html

Đọc bản gốc mới thấy, bản dịch sang tiếng Việt ngày xưa bị biên tập sửa đổi quá nhiều chi tiết. Tạm chấp nhận phải cắt đi bỏ chi tiết 16+ (mặc dù mình thì thấy cái đó mới hay =]] ), nhưng nhiều chi tiết cũng bị cắt hoặc thay đổi, nhiều điểm còn làm cho truyện mẫu thuẫn hoặc nhiều điểm không hiểu nổi, theo mình thì làm giảm đi giá trị truyện.
Không rõ tác giả Akira Toriyama có biết không, nếu không biết thì khi biết liệu có chấp nhận sự biên tập đó không nhỉ?

Nhưng thôi, vấn đề muốn bàn ở đây là hậu quả của việc không ý thức được bảo mật thông tin. Cụ thể qua 2 chi tiết dưới.

1. Piccolo sơ hở để Vegeta và Nappa biết biết chuyện viên ngọc lúc đánh nhau với Raditz.
pic

Kết quả là 1 năm sau, bị thiệt mạng do ăn đòn của Nappa lúc đỡ cho Gohan.
pic1

2. Vegeta lại để Frieza nghe lén nên lộ bí mật về chuyện Namek.
ve1

Hậu quả là bỏ mạng dưới tay Frieza ở Namek.
ve2

Thế mới thấy bảo mật thông tin nó quan trọng thế nào? Nhất là trong thời đại cái gì cũng bị cho lên NET hết 🙂

Apple codec & Sony codec

1. Vô đề.
Nghỉ hè dẫn vợ con đi chơi Fuji-Q, vùng dưới chân nói Phú Sỹ. Nhân dịp này mang con Handycam HDR-CX470 của Sony đi quay thằng ku chơi để về up lên cho các cụ ở nhà xem.
Vì không phải dân biết chơi Camcorder nên không có ý định review đánh giá con Handycam, chỉ là về xử lý thấy dung lượng file lớn quá, trong chừng mức có thể (về công cụ lẫn thời gian) thử xem qua xem các thánh Sony đang thiết kế bộ codec thế nào.
Vì đang dùng iphoneSE thần thánh, nên cũng tiện tay lướt qua xem Apple bí hiểm có gì khác không.

2. Công cụ sử dụng.
2.1. FFMPEG.
Trong thế giới multimedia processing, thì ffmpeg thì quá nổi tiểng nên không cần giới thiệu chi tiết. Đây là công cụ mã nguồn mở (opensource) mạnh mẽ, hỗ trợ đủ mọi video/audio đến multimedia file format (container).

FFMPEG được bắt đầu từ hồi “em mong ước đến năm 2000″(nhưng chiến tranh không tàn mà còn sống khỏe) bởi Fabrice Bellard (một trong những lập trình viên đẳng cấp nhất thế gian mà đang còn sống cho đến thời điểm hiện tại 07-2018) cho đến 2004. Sau đó được dẫn dắt bởi Michael Niedermayer Từ 2004 đến 2015.

Đến 13/03/2011, sau một thập kỉ phát triên, do không đồng quan điểm, một số thành viên nhóm phát triển (chắc ngộ Clean Code) muốn ưu tiên nâng cao chất lượng code & API. Các thanh niên đó đã tách thành dự án libav, vụ này gây ra bao nhiêu phiền hà cho cộng đồng :-(. Tuy nhiên các sửa đổi của libav vẫn được merger vào ffmpeg, có vẻ công việc này nhàm chán quá nên Michael Niedermayer đã từ chức leader vào 2015[4].

Ffmpeg được release theo package cho từng os riêng. Nếu không có mục đích tham gia phát triển ffmpeg hoặc cần sửa đổi source code thì strong recommend là lên trang chủ down về mà dùng luôn, vì nó đã enable rất nhiều lib phụ thuộc.

2.2. JM tool.
Trái ngược với ffmpeg, thì không nhiều người biết đến công cụ này, chắc chỉ sử dụng trong giới nghiên cứu về video coding, vốn dĩ đấy cũng là mục đích của nó chứ không phải hướng đến lĩnh vực ứng dụng. JM là viết tắt của Join Model (nghe tên hơi cà rốt), đây là h.264 codec (jvt codec),được nhóm JVT (nhóm hợp tác MPEG và VCEG) phát triển và dùng để xây dựng chuẩn nén h.264. Làm gì có codec nào có trước khi public chuẩn nén, nên dĩ nhiên nó dành quán quân về h.264 codec đầu tiên trên thế giới :-).

JM là full codec,  đầy đủ cả decoder lẫn encoder h.264. Sử dụng decoder của JM cho phép phân tích các thông tin chi tiết hơn về h.264.
JM có thể down trên trang chủ của ITU-T ở đây[3], theo README là có thể biên dịch ^^.

3. Thực hành.
3.1. Chuẩn bị video.
Đặt HDR-CX470 ở chế độ 1080P, 60fps, quay video nhiều cảnh động để đảm bảo bộ encoder làm việc tích cực nhất có thể. Sẽ phân tích tầm 1 phút, thời gian đủ dài để bộ encoder ổn định, do đó cần quay hơn 1 phút.

ffmpeg command cắt lấy 1 phút đầu tiên.

ffmpeg -ss 00:00:00 -to 00:01:00 -i 20180718125711.MTS -c copy sony.mts

3.2. Phân tích thông tin video cơ bản.
Cần tham khảo document của ffmpeg để hiểu các thông tin trong khi phân tích.
● Đầu tiên là xem thông tin cơ bản nhất về các stream video/audio, bằng command dưới.

ffprobe -show_streams sony.mts

Từ output log, lấy ra một số giá trị như dưới.

str1
str2

Từ đó có thể rút ra được vài thông tin sau.
– Birate 27 Mbps
– High profile, level 4.2. xem ý nghĩa profile/level ở [7].
– Khi encode, chỉ sử dụng 1 picture để tham chiếu đối với tham chiếu liên ảnh. (Với level 4.2 thì h.264 support tối đa có thể tham chiếu đồng thời 4 ảnh).

● Phân tích chi tiết hơn chút về thông tin từng ảnh.

ffprobe  -show_frames -select_streams v:0 sony.mts

Chỉ tập trung vào 2 thông tin khoanh đỏ.
str3
Thông tin này thay đổi theo từng picture, hình ở trên chỉ là picture đầu tiên.
Sau khi kiểm tra toàn bộ thông tin ở trên với tất cả các picture thì được như dưới.
Về pict_type thì thấy được cấu trúc I,P,P …I,P,P … Có 29 ảnh P giữa các ảnh I, không có ảnh B.
→ GOP có dạng I,P,P …P (30 ảnh). Việc không có ảnh B làm cho độ phức tạp khi thiết kế bộ codec giảm đi đáng kể.
→ Theo thông tin trên chỉ số ảnh dùng tham chiếu (refs=1), do đó chỉ là ảnh sau tham chiếu ảnh trước.

pts (Presentation Time Stamp) để chỉ thời điểm mà picture đó được hiện thị, xem giá trị này với tất cả các picture thì ta thấy giá trị này tăng đều.
→ Các ảnh không bị thay đổi thứ tự trong quá trình encode.  Từ thông tin chỉ có ảnh I,P (không có B) cũng dễ đoán được điều này.

● Và nhiều thông tin cực kì chi tiết
Dùng ffmpeg bằng các option của nó (ex: debug …) có thể phân tích thông tin rất chi tiết đến cả macroblock, nhưng nó ngoài phạm vi bài viết.

3.3. Phân tích QP của picture.
QP là của mỗi picture, sinh ra từ quá trình rate control xem ở [5]. Xem QP của mỗi picture cho ta hình dung qua được độ phức tạp của chiến lược rate control trong bộ codec.

Tìm mãi không thấy command cho phép ffmpeg log giá trị trung bình QP của từng picture nên đành dùng JM. JM chỉ làm việc với element stream, tức là raw h.264 chứ không chơi với container, như mts, mp4 … Do đó đầu tiên vẫn phải nhờ ffmpeg bóc cái h.264 element stream ra.

ffmpeg.exe -i sony.mts -c:v copy sony.264

Đưa vào JM, và thực hiện decode bằng command dưới.

ldecod.exe -d decoder -P InputFile=sony.264

qp
Ôi, than ơi, các thánh chơi QP cố định = 30 cho các picture cmnl. Vậy ở level picture thì giá trị QP chả điều chỉnh gì hết, tất nhiên xuống mức macroblock có thể điều chỉnh quanh giá trị này.

4. IphoneSE của Apple thì sao.
– Birate 23.7 Mbps
– High profile, level 4.2.
– Khi encode, chỉ sử dụng 1 picture để tham chiếu.
– GOP: I,P,P ..P (60 ảnh).
– Không có ảnh B, tức là không có sự thay đổi thứ tự để hiển thị.
– Rate control có vẻ tích cực hơn, QP thay đổi từ 20 ~ 31 . I picture là ảnh quan trọng ảnh hưởng nhiều đến chất lượng,  vì thế nên nên được encoder với QP thấp hơn.
– Cơ bản Apple dùng QP thấp hơn, độ mất mát thông tin ít hơn, nhưng vẫn nén được bitrate thấp hơn Sony? ( thật ra phải cùng 1 data đầu vào mới nói được vậy).

5. Kết luận.
A/e được học video coding, bao nhiêu thứ phức tạp như ảnh B tham chiếu 2 chiều cả quá khứ lẫn tương lai, h.264 cho phép 1 picture có thể đa tham chiếu (multi refer) lên đến 16 picture, cấu trúc GOP của h.264 rất tự do cho phép reorder, tham chiếu thoải mái …
Nhưng thực tế phũ phàng là để đạt được realtime (chắc là thế) các bộ encoder trong các thiết bị có vẻ phải hi sinh nhiều thứ để giảm độ phức tạp. Thậm chí cấu trúc GOP trên của h.264 còn đơn giản hơn cấu trúc của MPEG2-Video có ảnh B.
Mặc dù có vẻ codec trong IphoneSE chỉnh chu hơn HDR-CX470, nhưng để so sánh codec là vấn đề rất phức tạp mà cái quan trọng nhất là phải chung 1 dữ liệu đầu vào, trong khi đã đóng gói trong sản phẩm thì điều đó là không thể. Bài viết cũng chỉ là ngó qua một số thông tin từ kết quả video để phán đoán 1 chút về bộ encoder.

Tuy nhiên, một thiết bị quay video tốt, thì bộ encoder không phải là tất cả, ngoài ra còn ống kính, tính năng room, chống rung … tác động rất lớn đến chất lượng video và trải nghiệm.

Tham khảo.
[1]https://www.ffmpeg.org/
[2]https://en.wikipedia.org/wiki/FFmpeg
[3]https://www.itu.int/rec/T-REC-H.264.2-201602-I/en
[4]https://ffmpeg.org/pipermail/ffmpeg-devel/2015-July/176489.html
[5]https://vcostudy.com/2018/04/21/rate-control-video-coding
[6]https://www.ffmpeg.org/documentation.html
[7]https://vcostudy.com/2018/04/14/profile-va-level-trong-ma-hoa-video

Raspberry PI transcodes video

1. Transcode là gì.
Transcode là quá trình chuyển đổi từ định dạng mã hóa hiện tại sang một dạng mã hóa khác, ví dụ như chuyển đổi video, audio coding format …
Thông thường thì việc thực hiện transcode có 2 lý do chính:
– Giảm dung lượng lưu trữ mà có thể đảm bảo được chất lượng video, bằng việc sử dụng video coding format tân tiến hơn, tăng khả năng nén hơn, nên các dữ liệu video đang sử dụng coding format cũ thường chuyển sang format mới để giảm dung lượng lưu trữ.
– Thiết bị đầu cuối không hỗ trợ video or audio hiện tại, do đó cần convert sang cái dạng mà nó hỗ trợ.

Trên thực tế hiện nay thì dễ thấy nhất là khi upload 1 file video lên facebook hoặc youtube, thì file video đó luôn được youtube/facebook xử lý thành định dạng khác trong quá trình upload.

Cơ bản thì quá trình transcode có thể hình dung đơn giản như dưới.

input file/stream → |decode| → |encode| → output file/stream

Từ dữ liệu đầu vào, có thể là multimedia file format (MKV, MP4 …) hoặc stream (udp, tcp/ip …). Bước đầu tiên là giải mã (decode) thành phần đầu vào (video or audio tùy thuộc vào cái nào cần transcode) thành raw data. Tiếp đó thực hiện mã hóa (encode) thành định dạng mới ở dữ liệu đầu ra.

Transcode có thể realtime or non-realtime tùy thuộc vào từng yêu cầu của hệ thống. Trong các dữ liệu cần transcode thì video là phức tạp, tốn nhiều hiện năng nhất, và thường quan tâm nhất , do việc nén video theo chuẩn mới có thể tiết kiệm rất nhiều dung lượng or bitrate.

2. Video decoder/encoder trên RPI.
Raspberry pi(RPI) hỗ trợ cả hardware decoder lẫn encoder, do đó rất phù hợp nếu sử dụng nó để thực hiện transcode.
2 bộ decoder và encoder trên RPI được thiết kế theo API của openmax mà cụ thể là openmax-il.
Openmax là chuẩn các api do khronos đưa ra để thiết kế hệ thống xử  lý multimedia, nó gồm có 3 phần tương được với 3 layer, nhìn hình dưới lấy từ trang chủ có nó thì hiểu, khỏi cần giải thích.
media_portability
Cái gì mà được chuẩn hoá thì mục đích cao nhất của nó là giúp giảm thời gian tích hợp, 2 thằng không cần biết nhau trước đó mà chỉ cần cùng tuân theo 1 chuẩn là dễ dàng tích hợp với nhau.
Openmax-il có thể hiểu là lớp trung gian giữa phần cứng (hardware) và application hay còn gọi là firmware, đây cũng là phần API được sử dụng rộng rãi nhất của openmax. Android media framework, ffmpeg, gstreamer đều đã hỗ trợ openmax-il với tư cách là IL client, tức là layer ngay ở trên openmax-il . Do đó nếu bạn rảnh rỗi thiết kế 1 con chip hỗ trợ video decoder tuân thủ theo đúng api của openmax-il thì bạn có thể nhanh chóng tích hợp được vào các hế thống trên :-), và bán con chip đó luôn được để kiếm xèng.

Chi tiết openmax thì vào trang chủ của nó để tham khảo ở đây[3].
Thông tin các openmax-il component trên RPI thì tham khảo chỗ này[5].

3. Thực hiện transcode video trên RPI.
3.1. Thực hành transcode với RPI.
Omxplayer là cli hoạt động rất ổn định khi dùng play video trên RPI. Mình vẫn dùng để mở clip tàu điện Nhật Bản phục vụ ông con thích tàu xe.
Omxplayer sử dụng hardware decoder của RPI, và tất nhiên là thông qua openmax-il, cấu trúc của nó như hình dưới.
dec_rpi

Xuất phát từ ý tưởng dùng RPI để chuyển đổi video streaming mpeg2-video đang có sẵn thành h.264 để giảm bitrate nhằm tiết kiệm băng thông. Dựa trên omxplayer
với một chút sửa đổi nhỏ sau:
– Bỏ audio decoder, vì audio chiếm băng thông không đáng kể, không cần thiết transcode nên audio vào thế nào cho ra thế đó.
– Cắt bỏ phần xử lý hiện thị (render component), vì chỉ cần chuyển đổi sang video format khác, kết quả sẽ streaming hoặc lưu thành file.
– Thêm component encoder, nối vào ngay sau decoder. Để thực hiện encode lại ảnh, kết quả của bộ decoder sau khi giải mã đầu vào.
– Thêm phần xử lý output streamer, module này có nhiệm vụ lưu audio + video sau khi convert thành file hoặc streaming qua udp hoặc tcp/ip hoặc protocol nào đấy.

Sau khi sửa đổi thì cấu trúc nó thay hình đổi dạng như dưới.
transcode_rpi

Source code & readme hướng dẫn sử dụng chứa ở đây

Kết quả chạy thử, đạt được realtime và bitrate giảm 1 nửa.
input http streaming: mpeg2-video,size 720×576, 25fps, bitrate 4mbps.
output udp streaming: h.264, size 720×576, 25fps, bitrate 2mbps.

Khi play stream gốc và stream sau khi đã transcode thì chất lượng theo đánh giá chủ quan là tương đương nhau. Cần chú ý rằng, đây chỉ là về mặt visual, còn nén video là nén mất dữ liệu (lossly) do đó cái output không bao giờ bằng được input nếu nói trên quan điểm thông tin.

●Hiện tại đang có các điểm hạn chế cần điều tra và cải thiện:
– Chạy được tầm 1h ~ 2h thì tự dưng lăn quay là treo → bug cần điều tra.
– Openmax-il có định nghĩa 2 kiểu kết nối để component truyền data cho nhau, là tunnel (kết nối trực tiếp) và non-tunnel (kết nối gián tiếp thông qua IL client). Định dùng tunnel cho đơn giản, nhưng thử mãi không được nên đang dùng non-tunnel, thành ra quản lý buffer đang hơi stupid nên output buffer của decoder được copy sang encoder. → Cần điều tra lại đển dùng tunnel hoặc improve việc quản lý buffer để bỏ xử lý copy.
–  Phần output streamer module cần design là 1 thread độc lập, nhận video/audio buffer ở component trước đó thông qua queue, nhưng hiện tại đang thực hiện như bằng context của video & audio (được buffer nào thì streaming luôn).

3.2. Dùng ffmpeg.
Đợt này có chút thời gian, định quay lại xử lý mấy hạn chế & bug của 3.1 thì mới để ý thấy ffmpeg nó cũng support openmax rồi, như vậy đơn giản thế này thôi.
– Clone ffmpeg và tham khảo chỗ này để enable omx khi compile.
– Nếu ngại complile từ source code thì có thể cài đặt ffmpeg thông qua repo của RPI, package đã được enable omx: sudo apt-get install ffmpeg

Dùng command dưới là xong :-).

ffmpeg -c:v mpeg2_mmal -i http://address_input -c:a copy -c:v h264_omx -b:v 2000k -f mpegts udp://address:port

Tuy nhiên có vẻ có vấn đề với input streaming interlace, ngoài ra chưa stress test nên chưa biết thế nào. Từ POC (proof-of-concept) đến Mass Product là một khoảng cách lớn, haizz …

●24/07/2018 update: Input stream đang sử dụng là interlace, trong khi đó bộ encoder h.264 trên RPI không support interlace nên aspect ratio output stream bị sai. Có thể cần xử lý de-interlace trước khi encode. Hoặc với video hiện tại thì có thể dùng encoder bằng software encoder (libx264) như command dưới, sử dụng option encode performance gần cao nhất, với video size 720×576 thì vẫn đạt được realtime, tuy nhiên con chip nóng quá, không dám chạy stress-test vì sợ nó ngỏm.

ffmpeg -c:v mpeg2_mmal -i http://address_input
-c:v libx264 -preset superfast -f mpegts -b:v 2000k -s 720×576
udp://address:port

P/S: Lưu ý, RPI mặc định chưa enable hardware mpeg2-video codec, muốn dùng phải bỏ tiền ra mua ở đây.

Tham khảo.
[1]https://en.wikipedia.org/wiki/Transcoding
[2]https://www.raspberrypi.org/forums/viewtopic.php?f=72&t=72260
[3]https://www.khronos.org/openmax/
[4]https://source.android.com/devices/media/
[5]http://www.jvcref.com/files/PI/documentation/ilcomponents/
[6]https://github.com/popcornmix/omxplayer
[7]https://github.com/truongpt/rpi_transcode

Lần đầu học online

Hôm nay viết mail xin nghỉ việc ở FPT Japan, chuẩn bị kết thúc sau 9 năm gắn bó.
Vậy đã 9 năm, kinh nghiệm chỉ gói gọn trong vài ba chữ, embedded, c/c++, video coding, linux driver. 9 năm làm có từng đó, nói ra lại tưởng là cỡ chuyên gia nhưng hóa ra không phải, cái nào cũng lõm bõm.

Tốt nghiệp kĩ sư điện, nên cơ bản kinh nghiệm coding đều học hỏi trong quá trình làm việc, thành ra nhận được kiến thức kiểu làm nhiều thì quen tay hơn là dùng não, nhìn đến cái nào cũng thấy cái nền móng thiêu thiếu cái gì đấy.

Ờ, thôi biết vậy, thiếu nhưng biết bù thì không sao, khóa học online giờ rất rất nhiều, cứ muốn là học được, chỉ là có chịu học hay không mới là vấn đề thôi.

Thử bắt đầu bằng khóa này xem, thấy kha khá các expert gợi ý.
https://see.stanford.edu/Course/CS107/
Song song đọc quyển “programming perspective“, là giáo trình của course trên.

Có 27 bài giảng, nếu cứ đều đều 1 ngày 1 bài hết 27 ngày.
Có tài liệu & bài tập … thong thả tính 2 ngày để làm.
Vậy có 3 ngày/1 bài → 3 tháng.
Nếu bắt đầu học từ giờ 21/06 thì đến 21/08 là xong.
Thử bắt đầu thật nghiêm túc 1 khóa học online xem thế nào vậy!

Từ khóa register trong C

Trong lập trình nhúng (embedded programming), thi thoảng hay bắt gặp từ khóa register, thường là những chỗ tính toán loằng ngoằng, bit biếc dịch ngược dịch xuôi. Register được dùng đặt trước kiểu dữ liệu khi khai báo biến. Tác dụng của từ khóa register, nói một cách ngắn gọn là làm tăng hiệu năng(performance) của chương trình.

Thêm cái của nợ này vào thì tại sao có thể tăng được hiệu năng?. Mà thực sự tăng thật thì tăng được bao nhiêu?
Để thêm phần sinh động, thử một ví dụ nhỏ dưới xem nó có ra cái gì không?

void main()
{
clock_t start, end;
double t;
int i; // không dùng register
//register int i; // sử dụng register
start = clock();
while(i < 0xFFFFFFFF) i++;
end = clock();

t = ((double) (end – start)) / CLOCKS_PER_SEC;
printf("time used %f\n",t);
}

Biên dịch với gcc version 6.3.0
Chạy trên Raspberry Pi 2B (ARMv7 Processor rev 5 (v7l)).
– Sử dụng từ khóa register: time used 9.583080 giây
– Không sử dụng từ khóa register: time used 38.256520 giây

Ví dụ trên cho thấy dùng từ khóa register, thì hiệu năng nó tăng thật, riêng trong trường hợp này thì cũng đang kể đấy chứ nhỉ :-).Tất nhiên cải thiện được bao nhiêu thì phải tùy vào hoàn cảnh cụ thể khi sử dụng, mức độ sử dụng biến đó … Nhưng mà ngon lành vậy thì toàn bộ khai báo biến trong chương trình cứ mặc định thêm luôn từ khóa này thì chuyện gì xẩy ra?.
Để hiểu được điều đó thì trước hết thử xem tại sao hiệu năng nó tăng?
Quay lại với vấn đề cơ bản hơn một chút, trong kiến trúc của vi xử lý thì ALU (Arithmetic Logic Unit) là con trâu đóng vai trò xử lý các tính toán số học. Dữ liệu đưa vào làm việc với ALU phải chứa trong một vùng đặc biệt, gọi là các thanh ghi(register), và ALU chỉ làm việc với đống thanh ghi đó. Trong khi đó các biến khai báo trong chương trình thì đặt ở bộ nhớ ngoài (RAM chẳng hạn …). Do đó với khai báo biến thông thường, để thực hiện một phép tính thì cần có 3 bước.
① Nạp giá trị từ vùng nhớ chứa biến vào register
➁ Yêu cầu ALU xử lý register vừa được nạp giá trị.
③ Đưa kết quả vừa xử lý của ALU ra ngoài vùng nhớ chứa biến.
Hình dung thô thiển như hình vẽ dưới đây.

alu

Khi thêm từ khóa register để khai báo biến, thì tức là ta đã yêu cầu trình biên dịch ưu tiên đặc biệt dành luôn vùng register để chứa biến đó. Và hiển nhiên khi thực hiện tính toán trên biến đó thì giảm được bước ①&③, giảm bớt thủ tục thì hiệu năng nó tăng lên là chuyện dễ hiểu :-).
Quay lại với ví dụ trên, để đảm bảo đúng như thánh phán, thử thêm option “-save-temps” để lấy tập mã lệnh assembly xem nó có thật vậy không.

gcc register.c -o test -save-temps

Đoạn mã assembly ở dưới tương ứng với vòng while loop ở ví dụ trên. Dễ thấy chỗ bôi màu đó khi không dùng từ khóa register tương ứng với bước ①&③ ở trên. Còn khi dùng từ khóa register thì trình biên dịch nó dùng luôn thanh ghi r4 cho việc chứa biến i.
p/s: Nếu không dễ thấy thì tự tra cứu lại lệnh assembly của ARM

Không sử dụng từ khóa register

ldr r3, [fp, #-8] // bước ①
add r3, r3, #1
str r3, [fp, #-8] // bước ③
.L2:
ldr r3, [fp, #-8]
cmn r3, #1
bne .L3

Sử dụng từ khóa register

.L3:
add r4, r4, #1
.L2:
cmn r4, #1
bne .L3

Đến đây, ta thấy rõ ràng khi dùng từ khóa register, thì thay vì dùng bộ nhớ ngoài đển lưu biến thì chương trình sẽ sử dụng luôn register để lưu biến đó. Cái gì ngon, quí thì dĩ nhiên hiếm, register cũng thấy, số lượng register rất nhỏ so với bộ nhớ ngoài, mà đây còn là tài nguyên dùng chung. Do đó không thể chơi kiểu vô tổ chức để thằng nào thích lấy làm đồ riêng thì lấy được. Tùy từng tình huống, yêu cầu để lựa chọn phần xử lý nào nên sử dụng register để tăng hiệu năng mà có thể chấp nhận cho nó xin một vài register về làm của riêng.
Nếu không tin thì thử thêm đoạn code này “register int k[100*1024*1024];” vào
để chiếm register xem chương trình xem nó có ngỏm không ^.^

Zero start with video coding

Hoàn cảnh éo le.
Ra trường giữa 2009, tham gia 1 dự án làm về DTV (Digital Television) đến tận đầu 2012, vậy là 2 năm rưỡi, biết được một chút về video decoding do đàn anh  chỉ dạy cho lúc bắt đầu dự án, còn lại OT vật vã cho kịp deadline. Sau này ngẫm lại thấy đa phần kiến thức cơ bản về video coding bị sai → quá nguy hiểm.
Vào 7/2013 sang Nhật làm việc đến 4/2017 trong dòng dự án về 4k – Television và Camera recorder. Trong thời gian đó có tầm 1 năm rưỡi cuối làm về video encoding. Về công việc thì test nhiều hơn là code. Do  rảnh rỗi không biết làm gì, nên học thêm chút về video encoding cho qua ngày.
Rút ra được vài ba kinh nghiệm quí báu, khi làm việc trong cái mảng việc này (mảng khác chắc cũng thế).
– ① Nên theo từ lúc đang đi học, như thế sẽ được chỉ dạy kiến thức cơ bản bởi những người biết về kiến thức cơ bản.
– ➁ Nếu ko có cơ hội ①, khi vào dự án chiến luôn mà nghe trong team chém gió (sợ nhất là các thánh phán), phải điều tra cẩn thận trước khi coi đó là chân lý.
– ③ Cái số ➁ cực kì nguy hiểm, nếu không may mắn có cái ① thì nên tìm sư huynh cho thật ngon mà học, vừa nhanh vừa an toàn.
Mình là nạn nhân con số ➁, sau nhiều năm mới sửa sai được một số vấn đề cơ bản, mà suýt bị nó làm cho tẩu hỏa nhập ma. Ngoài ra công việc gián đoạn không làm video coding nữa, nên giờ ngồi viết lại, lỡ sau này may mắn có cơ hội làm tiếp về video coding thì có chỗ mà tra cứu cho nhanh :-).

Một vài điểm bắt đầu.
Có mail hỏi 1 ông anh, chuyên gia video coding ở Đức, thì đại ka gợi ý đọc quyển này. Mình nhai mãi chưa xong (vẫn tiếp tục nhai khi có thời gian), toàn kiến thức nền tảng, phù hợp cho ai thích đi theo hướng nghiên cứu. Còn giờ đang cần tiếp cận theo hướng ứng dụng.
Bắt đầu một vài gạch đầu dòng cơ bản.
– Video thực ra là một chuỗi ảnh(picture) sắp xếp liên tục theo thời gian (có lẽ ai cũng biết?), vì vậy nén video chẳng qua là nén lần lượt các ảnh này.
– Nén video cơ bản là nén mất dữ liệu (lossly), nhưng bất kì chuẩn nén video nào cũng chứa 2 giai đoạn. Giai đoạn 1 nén lossly (transform + quantization) và giai đoạn 2 nén lossless (entropy coding). Một số chuẩn nén như AVC/H.264, HEVC/H.265… cho phép chỉ nén lossless bằng cách cho phép bỏ quá trình nén lossly.
– Xét ở đặc điểm sau khi nén của picture, có thể chia thành 2 loại kỹ thuật nén là INTRA (nén trong ảnh) & INTER (nén liên ảnh). INTRA là cách nén picture chỉ dựa vào thông tin chứa trong bản thân picture đó, ngược lại INTER có sử dụng thông tin các picture lân cận để thực hiện nén picture đó.
– Quá trình nén picture được thực hiện theo từng block có kích thước vuông giống nhau. Đối với chuẩn nén H.264 trở về trước gọi là Macroblock kích thước 16×16 pixel, còn đối với H.265 gọi là Coding Tree Unit và nó cho phép chọn từ 16×16 ~ 64×64 pixel. Với các chuẩn nén không phải của ISO or ITU-T, ví dụ VP8, VP9 của google, tên gọi các block đó có thể khác nhưng cơ bản đều mang ý nghĩa giống nhau.

Sẽ có rất nhiều thắc mắc, ví dụ INTRA & INTER được thực thi cụ thể thế nào? nó thể hiện thế nào trong quá trình xử lý các block trong từng picture?, google phát toàn ra 1 đống như motion vector nó nằm ở đâu trong khái niệm trên? vân vân và vân vân. Với một cơ số khái niệm, cùng với đống tài liệu trên mạng (rác cũng nhiều), vội vàng dễ bị chết đuối cho nên đừng vội tham lam, đi từ từ rồi sẽ đến.
P/S: Kiến thức mình chia sẻ thuộc trường hợp số ➁, cẩn thận khi có ý định sử dụng nhé!