Аппаратное кодирование видео Linux на процессоре Amlogic A311D2

Мы тестировали 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.

Оригинал статьи вы можете прочитать здесь.

5 1 vote
Article Rating
Подписаться
Уведомление о
guest

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

0 Комментарий
Inline Feedbacks
View all comments