Мы тестировали Khadas VIM4 Amogic A311D2 SBC с Ubuntu 22.04 немного дольше обычного, и хотя производительность в целом хорошая, такие функции, как ускорение 3D-графики и аппаратное декодирование видео, отсутствуют. Но нам бы хотелось увидеть раздел аппаратного кодирования видео Linux в Wiki, так как это не часто увидишь на ранних этапах. Итак, пробуем…
Во-первых, нам нужно сделать видео в формате пикселей NV12, которое обычно выводится с камер. Мы загрузили 45-секундный образец видео 1080p H.264 с Linaro и преобразовали его с помощью ffmpeg:
ffmpeg -i big_buck_bunny_1080p_H264_AAC_25fps_7200K.MP4 -pix_fmt nv12 big_buck_bunny_1080p_H264_AAC_25fps_7200K-nv12.yuv
Мы сделали это на ноутбуке. Как необработанное видео, оно довольно большое: 3,3 ГБ памяти используется для 45-секундного видео:
ls -lh
total 3.3G
-rw-rw-r-- 1 jaufranc jaufranc 40M Aug 5 2011 big_buck_bunny_1080p_H264_AAC_25fps_7200K.MP4
-rw-rw-r-- 1 jaufranc jaufranc 3.3G May 21 15:03 big_buck_bunny_1080p_H264_AAC_25fps_7200K-nv12.yuv
Теперь давайте попробуем закодировать видео в H.264 на плате Khadas VIM4, используя пример аппаратного кодирования видео aml_enc_test:
khadas@Khadas:~$ time aml_enc_test 1080p.nv12 dump.h264 1920 1080 30 25 6000000 1125 1 0 2 4
src_url is : 1080p.nv12 ;
out_url is : dump.h264 ;
width is : 1920 ;
height is : 1080 ;
gop is : 30 ;
frmrate is : 25 ;
bitrate is : 6000000 ;
frm_num is : 1125 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 4 ;
codec is H264
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 1920x1080
Encode End!width:1920
real 0m26.074s
user 0m1.832s
sys 0m4.883s
Вывод поясняет используемые параметры. Есть несколько сообщений об ошибках, но видео можно без проблем воспроизвести с помощью ffplay на компьютере.
Мы также можем видеть, что кодирование произошло за 26 секунд, что быстрее, чем в реальном времени, поскольку видео длится 45 секунд.
Попробуем то же самое с кодировкой H.265:
time aml_enc_test 1080p.nv12 dump.h265 1920 1080 30 25 6000000 1125 1 0 2 5
src_url is : 1080p.nv12 ;
out_url is : dump.h265 ;
width is : 1920 ;
height is : 1080 ;
gop is : 30 ;
frmrate is : 25 ;
bitrate is : 6000000 ;
frm_num is : 1125 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 5 ;
codec is H265
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 1920x1080
Encode End!width:1920
real 0m9.561s
user 0m1.348s
sys 0m2.576s
Это удивительно, но кодирование видео H.265 намного быстрее, чем кодирование видео H.264. Давайте снова попробуем кодировку H.264:
$ time aml_enc_test 1080p.nv12 dump2.h264 1920 1080 30 25 6000000 1125 1 0 2 4
src_url is : 1080p.nv12 ;
out_url is : dump2.h264 ;
width is : 1920 ;
height is : 1080 ;
gop is : 30 ;
frmrate is : 25 ;
bitrate is : 6000000 ;
frm_num is : 1125 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 4 ;
codec is H264
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 1920x1080
Encode End!width:1920
real 0m8.780s
user 0m1.416s
sys 0m2.274s
Теперь это занимает менее 9 секунд. В первый раз он считывает данные с флэш-памяти eMMC медленно, но, поскольку файл имеет размер 3,3 ГБ, он может поместиться в кеш, поэтому во второй раз узкого места в хранилище нет.
Тем не менее, файл dump.h265 также мог нормально воспроизводиться на компьютере, поэтому преобразование прошло успешно.
Спецификации Amlogic A311D2 говорят, что поддерживается кодирование видео «H.265 и H.264 при 4Kp50». Итак, давайте создадим 45-секундное видео 4Kp50 и конвертируем его в формат NV12 YUV. К сожалению, размер необработанного видео составляет 27 ГБ, и оно не поместится во флэш-память eMMC платы… Давайте сократим это до 30 секунд (около 18 ГБ)…
Теперь мы можем закодировать видео в H.264:
khadas@Khadas:~$ time aml_enc_test 4k.nv12 dump4k.h264 3840 2160 30 50 10000000 1501 1 0 2 4
src_url is : 4k.nv12 ;
out_url is : dump4k.h264 ;
width is : 3840 ;
height is : 2160 ;
gop is : 30 ;
frmrate is : 50 ;
bitrate is : 10000000 ;
frm_num is : 1501 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 4 ;
codec is H264
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 3840x2160
Encode End!width:3840
real 2m10.611s
user 0m5.819s
sys 0m26.130s
Две минуты, чтобы закодировать 30-секундное видео! Но, увы, это не работает, поэтому давайте снова запустим пример:
$ time aml_enc_test 4k.nv12 dump4k.h264 3840 2160 30 50 10000000 1501 1 0 2 4
src_url is : 4k.nv12 ;
out_url is : dump4k.h264 ;
width is : 3840 ;
height is : 2160 ;
gop is : 30 ;
frmrate is : 50 ;
bitrate is : 10000000 ;
frm_num is : 1501 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 4 ;
codec is H264
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 3840x2160
Encode End!width:3840
real 2m22.420s
user 0m6.543s
sys 0m28.102s
Это еще медленнее… Мы думаем, что хранилище является узким местом здесь, потому что требуемая скорость чтения для этого файла будет более 600 МБ/с для кодирования в реальном времени. Обычно система кодирует видео из потока камеры, а не из флэш-памяти eMMC. Мы должны были сначала запустить iozone:
$ iozone -e -I -a -s 1000M -r 4k -r 16k -r 512k -r 1024k -r 16384k -i 0 -i 1 -i 2
Iozone: Performance Test of File I/O
Version $Revision: 3.489 $
Compiled for 64 bit mode.
Build: linux
Output is in kBytes/sec
Time Resolution = 0.000001 seconds.
Processor cache size set to 1024 kBytes.
Processor cache line size set to 32 bytes.
File stride size set to 17 * record size.
random random bkwd record stride
kB reclen write rewrite read reread read write read rewrite read fwrite frewrite fread freread
1024000 4 42448 49401 33738 35273 30351 33959
1024000 16 95388 84746 83386 87949 78675 72818
1024000 512 109351 90438 166659 166804 144584 70463
1024000 1024 68088 98663 175108 174902 164769 58980
1024000 16384 71086 109715 178448 178144 182913 87181
iozone test complete.
Скорость последовательного чтения составляет около 178 МБ/с. У нас есть USB-концентратор MINIX с твердотельным накопителем на 480 ГБ, который мы тестировали со скоростью 400 МБ/с. Не совсем то, что нам нужно, но это должно привести к улучшениям.
К сожалению, диск не был смонтирован и даже не распознан даже такими инструментами, как fdisk и GParted. При перепроверке спецификаций Khadas VIM4 мы поняли, что порт USB Type-C — это интерфейс USB 2.0 OTG, который должен распознавать накопитель, но поддерживать только 480 Мбит/с, так что в любом случае это безнадежное дело… Единственный способ достичь более 600 МБ/с было бы использовать USB 3.0 NVMe SSD, но у нас его нет.
Вместо этого мы сделаем 5-секундное видео 4Kp50 размером около 2,9 ГБ.
Первый запуск с использованием H.265:
$ time aml_enc_test 4Kp50-5s.nv12 dump4k-5s.h265 3840 2160 30 50 10000000 249 1 0 2 5
src_url is : 4Kp50-5s.nv12 ;
out_url is : dump4k-5s.h265 ;
width is : 3840 ;
height is : 2160 ;
gop is : 30 ;
frmrate is : 50 ;
bitrate is : 10000000 ;
frm_num is : 249 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 5 ;
codec is H265
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 3840x2160
Encode End!width:3840
real 0m6.905s
user 0m0.661s
sys 0m1.885s
Второй запуск:
$ time aml_enc_test 4Kp50-5s.nv12 dump4k-5s-2.h265 3840 2160 30 50 10000000 249 1 0 2 5
src_url is : 4Kp50-5s.nv12 ;
out_url is : dump4k-5s-2.h265 ;
width is : 3840 ;
height is : 2160 ;
gop is : 30 ;
frmrate is : 50 ;
bitrate is : 10000000 ;
frm_num is : 249 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 5 ;
codec is H265
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 3840x2160
Encode End!width:3840
real 0m6.828s
user 0m0.663s
sys 0m1.822s
Последняя попытка с H.264:
$ time aml_enc_test 4Kp50-5s.nv12 dump4k-5s.h264 3840 2160 30 50 5000000 249 1 0 2 4
src_url is : 4Kp50-5s.nv12 ;
out_url is : dump4k-5s.h264 ;
width is : 3840 ;
height is : 2160 ;
gop is : 30 ;
frmrate is : 50 ;
bitrate is : 5000000 ;
frm_num is : 249 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 4 ;
codec is H264
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 3840x2160
Encode End!width:3840
real 0m6.422s
user 0m0.644s
sys 0m1.879s
Не совсем в реальном времени, но приближается, а это значит, что 4Kp30 должно быть возможно. Вот результат с 5-секундным видео 4Kp30 NV12, закодированным с помощью H.264:
$ time aml_enc_test 4Kp30-5s.nv12 dump4kp30-5s.h264 3840 2160 30 30 5000000 150 1 0 2 4
src_url is : 4Kp30-5s.nv12 ;
out_url is : dump4kp30-5s.h264 ;
width is : 3840 ;
height is : 2160 ;
gop is : 30 ;
frmrate is : 30 ;
bitrate is : 5000000 ;
frm_num is : 150 ;
fmt is : 1 ;
buf_type is : 0 ;
num_planes is : 2 ;
codec is : 4 ;
codec is H264
Set log level to 4
[initEncParams:177] enc_feature_opts is 0x0 , GopPresetis 0x0
[SetupEncoderOpenParam:513] GopPreset GOP format (2) period 30 LongTermRef 0
[vdi_sys_sync_inst_param:618] [VDI] fail to deliver sync instance param inst_idx=0
[AML_MultiEncInitialize:1378] VPU instance param sync with open param failed
[SetSequenceInfo:979] Required buffer fb_num=3, src_num=1, actual src=3 3840x2160
Encode End!width:3840
real 0m3.931s
user 0m0.378s
sys 0m1.161s
Меньше четырех секунд. Таким образом, аппаратное кодирование видео 4Kp30 H.264 в реальном времени определенно работает на процессоре Amlogic A311D2.
На нашем компьютере играет нормально.
Также возможно кодировать изображения NV12 YUV в JPEG, но это не будет работать с пользователем khadas:
$ jpeg_enc_test screenshot-1920x1080.nv12 dump.jpg 1920 1080 100 3 0 16 16 0
screenshot-1920x1080.nv12
dump.jpg
src url: screenshot-1920x1080.nv12
out url: dump.jpg
width : 1920
height : 1080
quality: 100
iformat: 3
oformat: 0
width alignment: 16
height alignment: 16
memory type: VMALLOC
align: 1920->1920
align: 1080->1088
hw_encode open device fail, 13:Permission denied
jpegenc_init failed
Но нет проблем с sudo:
khadas@Khadas:~$ time sudo jpeg_enc_test screenshot-1920x1080.nv12 dump.jpg 1920 1080 100 3 0 16 16 0
screenshot-1920x1080.nv12
dump.jpg
src url: screenshot-1920x1080.nv12
out url: dump.jpg
width : 1920
height : 1080
quality: 100
iformat: 3
oformat: 0
width alignment: 16
height alignment: 16
memory type: VMALLOC
align: 1920->1920
align: 1080->1088
mapped address is 0xffffb27f0000
hw_info->mmap_buff.size, 0x2300000, hw_info->input_buf.addr:0x0xffffb27f0000
hw_info->assit_buf.addr, 0x0xffffb466c000, hw_info->output_buf.addr:0x0xffffb46f0000
frame_size=3110400
rd_size=3110400, frame_size=3110400
offset=2088960
luma_stride=1920, h_stride=1088, hw_info->bpp=12
real 0m0.044s
user 0m0.004s
sys 0m0.009s
Вероятно, просто проблема с разрешением, задача была выполнена за 44 мс, и мы без проблем смогли открыть dump.jpg (скриншот).
Если используем ffmpeg для преобразования файла NV12 в jpeg, предположительно с программным кодированием, это занимает чуть менее 200 мс:
khadas@Khadas:~$ time ffmpeg -pix_fmt nv12 -s 1920x1080 -i screenshot-1920x1080-nv12.yuv dump-ffmpeg.jpg
ffmpeg version 4.4.1-3ubuntu5 Copyright (c) 2000-2021 the FFmpeg developers
built with gcc 11 (Ubuntu 11.2.0-18ubuntu1)
configuration: --prefix=/usr --extra-version=3ubuntu5 --toolchain=hardened --libdir=/usr/lib/aarch64-linux-gnu --incdir=/usr/include/aarch64-linux-gnu --arch=arm64 --enable-gpl --disable-stripping --enable-gnutls --enable-ladspa --enable-libaom --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libcodec2 --enable-libdav1d --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libjack --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librabbitmq --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzimg --enable-libzmq --enable-libzvbi --enable-lv2 --enable-omx --enable-openal --enable-opencl --enable-opengl --enable-sdl2 --enable-pocketsphinx --enable-librsvg --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libx264 --enable-shared
libavutil 56. 70.100 / 56. 70.100
libavcodec 58.134.100 / 58.134.100
libavformat 58. 76.100 / 58. 76.100
libavdevice 58. 13.100 / 58. 13.100
libavfilter 7.110.100 / 7.110.100
libswscale 5. 9.100 / 5. 9.100
libswresample 3. 9.100 / 3. 9.100
libpostproc 55. 9.100 / 55. 9.100
[rawvideo @ 0xaaaad7c07100] Estimating duration from bitrate, this may be inaccurate
Input #0, rawvideo, from 'screenshot-1920x1080-nv12.yuv':
Duration: 00:00:00.04, start: 0.000000, bitrate: 622080 kb/s
Stream #0:0: Video: rawvideo (NV12 / 0x3231564E), nv12, 1920x1080, 622080 kb/s, 25 tbr, 25 tbn, 25 tbc
Stream mapping:
Stream #0:0 -> #0:0 (rawvideo (native) -> mjpeg (native))
Press [q] to stop, [?] for help
[swscaler @ 0xaaaad7c1d2a0] deprecated pixel format used, make sure you did set range correctly
Output #0, image2, to 'dump-ffmpeg.jpg':
Metadata:
encoder : Lavf58.76.100
Stream #0:0: Video: mjpeg, yuvj420p(pc, progressive), 1920x1080, q=2-31, 200 kb/s, 25 fps, 25 tbn
Metadata:
encoder : Lavc58.134.100 mjpeg
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: N/A
frame= 1 fps=0.0 q=10.8 size=N/A time=00:00:00.04 bitrate=N/A speed=4e+04x frame= 1 fps=0.0 q=10.8 Lsize=N/A time=00:00:00.04 bitrate=N/A speed=0.514x
video:123kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: unknown
real 0m0.190s
user 0m0.150s
sys 0m0.037s
aml_enc_test и jpeg_enc_test — небольшие утилиты для тестирования аппаратного кодирования видео/изображений в Linux на Amlogic A311D2, но исходный код был бы хорош для интеграции этого в приложение. Но в настоящее время он не является общедоступным, поэтому мы предполагаем, что он является частью Amlogic SDK. Мы попросим у компании Khadas исходный код или способ его получения.
Выражаем свою благодарность источнику из которого взята и переведена статья, сайту cnx-software.com.
Оригинал статьи вы можете прочитать здесь.