コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2024年12月9日 >>> 2024年11月26日
link もっと後

2024年12月9日

nvJPEGとNVJPGとJetson APIその4 - Jetson Linux API

目次: Linux

半年経ったら完全に忘れるのでメモします。最近JPEGのデコードエンコードが必要になって色々調べていました。Jetson特有のAPI群がありまして、API名はJetson Linux API(のなかのMultimedia APIs)だそうです(Jetson Linux APIドキュメント)。

セットアップ方法

Jetsonを持っていないと使えません。最新機種はJetson AGX OrinかJetson Orin Nanoですが、AGX Orinは40万円、Orin Nanoは10万円近くするボッタクリ価格です。Xavierまではそこそこ安かったのにねえ……。

Jetson Linux APIがもしシステムにインストールされていなければapt-get install nvidia-l4t-jetson-multimedia-apiで使えるようになるはずです。Jetson用のパッケージは一覧があります(一覧へのリンク)ので、手動でダウンロードしたいときにはありがたいですね。

Jetson APIの実装

Jetson Linux APIは実装も使い方もかなり独特というか……はっきり言って変です。

変な点その1、APIの提供方法です。API実装は/usr/src/jetson_multimedia_api/samples/common/classesにソースコードで置かれています。ライセンスはBSDライセンスです。なぜ*.soや*.aで提供しないのでしょう?

後ほど紹介するJPEGデコード、エンコードのコンパイルにはNvJpegDecoder.cppとNvJpegEncoder.cppとお供のツール類が必要ですから、あえてディレクトリ名を省かずに書くと、下記のようなコマンドでコンパイルできます。面倒ならばjetson_multimedia_api/samples/common/classes/*.cppで良いです、NVIDIA提供のサンプルもワイルドカードを使っていました。

Jetson Linux APIのJPEG機能を使ったアプリケーションのコンパイル方法

g++ -O2 -g -Wall \
  -I jetson_multimedia_api/include/ \
  -I jetson_multimedia_api/include/libjpeg-8b/ \
  jetson_multimedia_api/samples/common/classes/NvJpegDecoder.cpp \
  jetson_multimedia_api/samples/common/classes/NvJpegEncoder.cpp \
  jetson_multimedia_api/samples/common/classes/NvBuffer.cpp \
  jetson_multimedia_api/samples/common/classes/NvElement.cpp \
  jetson_multimedia_api/samples/common/classes/NvElementProfiler.cpp \
  jetson_multimedia_api/samples/common/classes/NvLogging.cpp \
  (自分のソースコード) \
  -L /usr/lib/aarch64-linux-gnu/nvidia/ \
  -lnvjpeg

変な点その2、JPEG機能のヘッダ名です。jetson_multimedia_api/include/NvJpegDecoder.hを見ると、JPEG関連の機能はjetson_multimedia_api/include/libjpeg-8b/jpeglib.hにあるjpeglib.hヘッダにて定義されています。そう、このヘッダ名はIJG JPEGライブラリのヘッダと同じ名前です。なぜそんな場所にヘッダを置くのか?IJG JPEGと互換性がない(APIが増えている)のになぜ同じ名前?

変な点その3、JPEG機能のライブラリ名です。jpeglib.hだからlibjpeg.soかと思うじゃないですか、それは罠でリンクすべきはlibnvjpeg.soです。良くないことにlibjpeg.soも存在していて、さらに良くないことにデコード機能だけ使っている場合は間違ってlibjpeg.soを指定してもリンクできてしまい、

libjpeg.soを間違ってリンクしたときの実行時エラー
$ ./a.out

JPEG parameter struct mismatch: library thinks size is 656, caller expects 776

実行時にこのようなエラーが出るだけでうんともすんとも動きません。IJG JPEGと同じAPI名にするならTurbo JPEGのようにlibjpeg.soの方も置き換えれば問題は起きなかったのに、なぜ中途半端な実装に?

変な点その4、Jetson APIとNVJPEGの衝突です。以前紹介したNVJPEGはJetsonでも動きますがインストールはオススメしないです。

  • Jetsonのlibnvjpeg.so: IJG JPEGみたいなAPI実装、API名はjpeg_から始まります、インストール場所は/usr/lib/aarch64-linux-gnu/nvidiaです。
  • CUDAのlibnvjpeg.so: NVJPEGのAPI実装、API名はnvjpegから始まります、インストール場所は/usr/local/cuda-12.x/lib64らへんが多いです。

この2つが両方ともインストールされ、同じ-lnvjpegでリンクしてもライブラリパスによってリンクエラーになったり実行時のダイナミックリンクエラーになります。全く違う機能とAPI体系なのに、なぜ同じライブラリ名になっているの?

JPEGデコードの話は次にしたいと思います。Jetsonは適当なのか突貫なのか知りませんが、すっごい変だしちょっと使っただけなのに無限に疑問が出てきます。みんな良くこんなの使ってるなあ……。

編集者:すずき(2024/12/19 11:01)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年12月6日

YUVのrawvideo画像を生成、表示する方法

目次: Linux

FFMPEG(ffmpeg)を使ってYUV420やYUV444のrawvideo画像を生成する方法です。元にしたJPEG画像の解像度は1920x1440なので、YUV444の場合は1920 * 1440 * 3 = 8294400バイト、YUV420の場合は1920 * 1440 * 1.5 = 4147200バイトになるはずです。

YUV444, YUV420のrawvideo画像を生成する方法
$ ffmpeg -i test_420.jpg -f rawvideo -pix_fmt yuvj444p output_444.yuv

$ ls -la output.yuv
-rw-r--r-- 1 katsuhiro katsuhiro 8294400 12月  4 00:43 output_444.yuv


$ ffmpeg -i test_420.jpg -f rawvideo -pix_fmt yuvj420p output_420.yuv

$ ls -la  output_420.yuv
-rw-r--r-- 1 katsuhiro katsuhiro 4147200 12月  4 00:44 output_420.yuv

FFMPEG(ffplay)を使ってYUV420やYUV444のrawvideo画像を表示する方法です。ffmpegとffplayはピクセルフォーマットのオプションが微妙に違うのが嫌なところですね……。

YUV420のrawvideo画像を表示する方法
$ ffplay -f rawvideo -video_size 1920x1440 -pixel_format yuv420p output_420.yuv
編集者:すずき(2024/12/09 00:08)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年12月5日

libjpeg-turboのAPIその2 - encode

目次: Linux

半年経ったら完全に忘れるのでメモします。最近JPEGのデコードエンコードが必要になって色々調べていました。libjpeg-turboを使ってJPEGのデコードとエンコードを行う方法を紹介します(公式ドキュメントへのリンク)。

以前(2024年11月25日の日記参照)紹介したようにlibjpeg-turboは2.x系と3.x系の2系統のAPIがありまして、今回は2.x系APIの使い方を紹介します。DebianやUbuntuのaptパッケージだと2.x系が使われているので特に困らないと思いますが、最新版をビルドして使う場合は3.x系APIになるのでご注意ください。

エンコード

デコードと対になるような作りです。libjpeg-turboはとても簡単でありがたい。

libjpeg-turbo encodingのAPI呼び出し順

	tj_handle = tjInitCompress();

	// Rawvideo
	img_stride[0] = width;
	img_stride[1] = width / 2;
	img_stride[2] = width / 2;
	img_buf[0] = (uint8_t *)malloc(img_stride[0] * height);
	img_buf[1] = (uint8_t *)malloc(img_stride[1] * height / 2);
	img_buf[2] = (uint8_t *)malloc(img_stride[2] * height / 2);

	// Encoding
	tjCompressFromYUVPlanes(tj_handle, (const uint8_t **)img_buf, width, img_stride, height, subsamp, &jpegbuf, &jpegsize, quality, 0);

	// Destroy
	free(img_buf[0]);
	free(img_buf[1]);
	free(img_buf[2]);

	tjDestroy(tj_handle);

デコード同様にinitしてエンコードするだけです。デコードと違う点が1つあって、エンコードではJPEGを格納するバッファ(上記だとjpegbuf)のサイズが不明である問題があります。解決方法は2つあります。連続でエンコードする場合など、メモリの確保解放を減らしたい場合は1番目が良いでしょう。1枚だけエンコードするだけならどちらでも構いません。

  • JPEGを格納するために十分に大きなバッファを確保してからエンコード関数を呼ぶ
  • バッファを確保せずにエンコード関数を呼ぶ(エンコード関数内でメモリが確保される)

やってはいけないのが1番目だけどバッファサイズが不足することです。エンコード関数が勝手にバッファmalloc()してポインタを返してきて、元々確保していたバッファが行方不明になってしまいます。メモリリークするので注意が必要です。

私のコードは1番目の方法をとっていて、バッファサイズはYUV420つまり非圧縮時のサイズです。非圧縮時のサイズを上回ることはほぼないらしいのであまり問題ないはず。気になる人はlibjpeg-turboのAPIにJPEGサイズの最大値を返すtjBufSize()があるので、APIが返す値でjpegbufを確保するのが正しいお作法です。

実行

ソースコードを置いておきます。

使い方はコードの先頭にコメントで書いている通りですが、ここでも説明しておきます。引数はありません。ファイル名test_420.yuvのRaw YUV420ファイルを読み込んで、ファイル名turbo2_420.jpgのJPEGファイルを書き出します。

コンパイル、結果確認
$ g++ -g -O2 -Wall 20241205_turbo2_enc.cpp -lturbojpeg
$ ./a.out

$ ffplay -i turbo2_420.jpg

エンコード結果はJPEGです。ffplayでも普段お使いの画像ビューアでも、何を使って確認しても構いません。

編集者:すずき(2024/12/08 15:27)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年12月4日

libjpeg-turboのAPIその1 - decode

目次: Linux

半年経ったら完全に忘れるのでメモします。最近JPEGのデコードエンコードが必要になって色々調べていました。libjpeg-turboを使ってJPEGのデコードとエンコードを行う方法を紹介します(公式ドキュメントへのリンク)。

以前(2024年11月25日の日記参照)紹介したようにlibjpeg-turboは2.x系と3.x系の2系統のAPIがありまして、今回は2.x系APIの使い方を紹介します。DebianやUbuntuのaptパッケージだと2.x系が使われているので特に困らないと思いますが、最新版をビルドして使う場合は3.x系APIになるのでご注意ください。

デコード

前に使ったnvJPEGは訳のわからん儀式が必要でしたが、libjpeg-turboはとても簡単です。

libjpeg-turbo decodingのAPI呼び出し順

	// Create
	tj_handle = tjInitDecompress();
		
	// Rawvideo
	img_stride[0] = width;
	img_stride[1] = width / 2;
	img_stride[2] = width / 2;
	img_sz[0] = img_stride[0] * height;
	img_sz[1] = img_stride[1] * height / 2;
	img_sz[2] = img_stride[2] * height / 2;
	img_buf[0] = (uint8_t *)malloc(img_sz[0]);
	img_buf[1] = (uint8_t *)malloc(img_sz[1]);
	img_buf[2] = (uint8_t *)malloc(img_sz[2]);

	// Decoding
	tjDecompressToYUVPlanes(tj_handle, jpegbuf, jpegsize, img_buf, width, img_stride, height, 0);

	// Destroy
	free(img_buf[0]);
	free(img_buf[1]);
	free(img_buf[2]);

	tjDestroy(tj_handle);

基本的にはinitしてデコードするだけです。

実行

ソースコードを置いておきます。

使い方はコードの先頭にコメントで書いている通りですが、ここでも説明しておきます。引数はありません。ファイル名test_420.jpgのJPEGファイルを読み込んで、ファイル名turbo2_420.yuvのRawvideoファイルを書き出します。

コンパイル、結果確認
$ g++ -g -O2 -Wall 20241204_turbo2_dec.cpp -lturbojpeg
$ ./a.out

$ ffplay -f rawvideo -video_size 1920x1440 -pixel_format yuv420p -i turbo2_420.yuv

デコード結果のRawvideoを確認するときはffplayを使うと便利です。

編集者:すずき(2024/12/08 15:00)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年12月2日

Debian TestingでX.orgが起動しなくなった

目次: Linux

Debian Testingのapt-get updateをしたら、xrdp経由で起動しているX.orgがエラーで起動しなくなりました。こんなエラーが出ています。

X.orgの起動ログ
[  1416.016] (EE)
[  1416.016] (EE) Backtrace:
[  1416.016] (EE) 0: /usr/lib/xorg/Xorg (OsLookupColor+0x14d) [0x556fb13c8dad]
[  1416.017] (EE) 1: /lib/x86_64-linux-gnu/libc.so.6 (__sigaction+0x40) [0x7f084f9dad20]
[  1416.017] (EE) 2: /lib/x86_64-linux-gnu/libc.so.6 (pthread_key_delete+0x14c) [0x7f084fa2ee5c]
[  1416.017] (EE) 3: /lib/x86_64-linux-gnu/libc.so.6 (gsignal+0x12) [0x7f084f9dac82]
[  1416.018] (EE) 4: /lib/x86_64-linux-gnu/libc.so.6 (abort+0xd3) [0x7f084f9c34f0]
[  1416.018] (EE) 5: /lib/x86_64-linux-gnu/libc.so.6 (perror+0xcb7) [0x7f084f9c432d]
[  1416.018] (EE) 6: /lib/x86_64-linux-gnu/libc.so.6 (timer_settime+0x395) [0x7f084fa389e5]
[  1416.019] (EE) 7: /lib/x86_64-linux-gnu/libc.so.6 (timer_settime+0x59c) [0x7f084fa38bec]
[  1416.019] (EE) 8: /lib/x86_64-linux-gnu/libc.so.6 (__libc_free+0xb8) [0x7f084fa3d548]
[  1416.019] (EE) 9: /lib/x86_64-linux-gnu/libdrm.so.2 (drmFreeDevice+0x7d) [0x7f084febf13d]
[  1416.020] (EE) 10: /lib/x86_64-linux-gnu/libdrm.so.2 (drmFreeDevices+0x2e) [0x7f084febf2ae]
[  1416.020] (EE) 11: /lib/x86_64-linux-gnu/libnvidia-egl-gbm.so.1 (loadEGLExternalPlatform+0x8a8) [0x7f084477dd18]
[  1416.020] (EE) 12: /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 (NvEglwlaf47906in+0x6e240) [0x7f08404ad480]
[  1416.020] (EE) 13: /lib/x86_64-linux-gnu/libEGL_nvidia.so.0 (NvEglwlaf47906in+0xd73c) [0x7f084044c97c]
[  1416.020] (EE) unw_get_proc_name failed: no unwind info found [-10]
[  1416.020] (EE) 14: /lib/x86_64-linux-gnu/libEGL.so.1 (?+0x0) [0x7f0844a6ead5]
[  1416.020] (EE) unw_get_proc_name failed: no unwind info found [-10]
[  1416.020] (EE) 15: /usr/lib/x86_64-linux-gnu/dri/swrast_dri.so (?+0x0) [0x7f0844aaf3f3]
[  1416.021] (EE) unw_get_proc_name failed: no unwind info found [-10]
[  1416.021] (EE) 16: /usr/lib/xorg/modules/extensions/libglx.so (?+0x0) [0x7f084f65cbe3]
[  1416.021] (EE) unw_get_proc_name failed: no unwind info found [-10]
[  1416.021] (EE) 17: /usr/lib/xorg/modules/extensions/libglx.so (?+0x0) [0x7f084f65ba1f]
[  1416.021] (EE) 18: /usr/lib/xorg/Xorg (_CallCallbacks+0x3c) [0x556fb125002c]
[  1416.021] (EE) 19: /usr/lib/xorg/Xorg (dri3_send_open_reply+0x111f) [0x556fb138334f]
[  1416.021] (EE) 20: /usr/lib/xorg/Xorg (InitExtensions+0x89) [0x556fb12bde29]
[  1416.021] (EE) 21: /usr/lib/xorg/Xorg (InitFonts+0x1f8) [0x556fb124e968]
[  1416.022] (EE) 22: /lib/x86_64-linux-gnu/libc.so.6 (__libc_init_first+0x88) [0x7f084f9c4d68]
[  1416.022] (EE) 23: /lib/x86_64-linux-gnu/libc.so.6 (__libc_start_main+0x85) [0x7f084f9c4e25]
[  1416.022] (EE) 24: /usr/lib/xorg/Xorg (_start+0x21) [0x556fb12373f1]
[  1416.022] (EE)
[  1416.022] (EE)
Fatal server error:
[  1416.022] (EE) Caught signal 6 (Aborted). Server aborting
[  1416.022] (EE)
[  1416.022] (EE)
Please consult the The X.Org Foundation support
         at http://wiki.x.org
 for help.
[  1416.022] (EE) Please also check the log file at ".xorgxrdp.10.log" for additional information.
[  1416.022] (EE)
[  1416.022] rdpLeaveVT:
[  1416.022] (EE) Server terminated with error (1). Closing log file.

エラーの原因であるlibEGL_nvidia.soを削除すれば起動しそうだったので、libegl-nvidia0パッケージを消したところX.orgが起動しました。めでたしめでたし……ではありません。どうしてこうなった?

NVIDIAドライバを復活させる

他にも何か起きているだろうか?と調べたらCUDAが使えないし、nvidia-smiがデバイスがないと言っています。NVIDIA系の機能が全滅です。どうやらnvidia.koが消滅していて、GPUカードが認識されなくなったようです。NVIDIAドライバパッケージを再インストールするとこんなメッセージが出ました。

NVIDIAのドライバパッケージのエラーメッセージ
nvidia-kernel-dkms (535.216.03-1) を設定しています ...
Loading new nvidia-current-535.216.03 DKMS files...
Building for 6.11.10-amd64
Module build for kernel 6.11.10-amd64 was skipped since the
kernel headers for this kernel do not seem to be installed.

メッセージはカーネルヘッダをインストールしないとカーネルモジュールがビルドされないとおっしゃっています。カーネルヘッダパッケージlinux-headers-6.11.10-amd64をインストールしたところ無事/lib/modules/6.11.10-amd64/updates/dkms/の下にnvidia-current.ko.xzが生成され、CUDAが復活しました。めでたしめでたし……じゃないんだ、まだ。

DRMを復活させる

X.orgは/dev/driの下にあるデバイスファイルにアクセスするので、DRM関連のドライバも必要です。DRM用のドライバパッケージをインストールするとnvidia-current-drm.ko.xzが生成されます。たしかパッケージ名はnvidia-vdpau-driverだったと思います。

カーネルモジュールが生成されたらmodprobe nvidia-drmでロードすれば/dev/dri/card0が出現します。先ほど削除したlibegl-nvidia0パッケージを再インストールしてもX.orgの起動に失敗しなくなりました。めでたしめでたし。

とはいえxrdp経由で起動していると、DRMが有効でも"unsupported render mode"と言われてしまってHWアクセラレーションが効いてなさそうに見えます。せっかく直したのに悲しいですね……。

編集者:すずき(2024/12/05 23:07)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2024年11月28日

BIOS/UEFI画面に入る方法

PCは起動時にあるキーを押すとBIOS/UEFIの設定画面に遷移します。良く見るパターンはF1, F2, DELキー辺りですが、メーカーごとに完全にバラバラで統一感なしです。私の場合、初めて見るPCのBIOS/UEFI画面を拝みたいときはEsc, F1, F2, F12, DEL辺りを乱打しながら起動します。これでもたまに普通に起動してしまうPCがあってイライラします。

Twitterでこの話に言及したら、いくつか知らないパターンを教えてもらいましたのでそれも紹介します。

こんなものに独自性を出して誰が幸せになるんでしょうか?実に不毛です。PCメーカーとBIOSメーカーはさっさとキーを統一してください……。

編集者:すずき(2024/12/01 00:53)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2024年12月9日 >>> 2024年11月26日
link もっと後

管理用メニュー

link 記事を新規作成

<2024>
<<<12>>>
1234567
891011121314
15161718192021
22232425262728
293031----

最近のコメント5件

  • link 21年9月20日
    すずきさん (11/19 01:04)
    「It was my pleasure.」
  • link 21年9月20日
    whtさん (11/17 23:41)
    「This blog solves my ...」
  • link 24年10月1日
    すずきさん (10/06 03:41)
    「xrdpで十分動作しているので、Wayl...」
  • link 24年10月1日
    hdkさん (10/03 19:05)
    「GNOMEをお使いでしたら今はWayla...」
  • link 24年10月1日
    すずきさん (10/03 10:12)
    「私は逆にVNCサーバーに繋ぐ使い方をした...」

最近の記事3件

  • link 24年12月9日
    すずき (12/19 11:01)
    「[nvJPEGとNVJPGとJetson APIその4 - Jetson Linux API] 目次: Linux半年経ったら...」
  • link 24年12月11日
    すずき (12/18 00:00)
    「[nvJPEGとNVJPGとJetson APIその5 - Jetson Linux API JPEG decode編] 目次...」
  • link 24年12月13日
    すずき (12/18 00:00)
    「[nvJPEGとNVJPGとJetson APIその6 - Jetson Linux API JPEG encode編] 目次...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 12/19 11:01