Armadilloフォーラム

Armadillo-440で"gstreamer1.0"を使ってRAWデータ(RGB形式)をJPEG圧縮する方法

k-nakai

2025年3月5日 16時40分

==========
製品型番:Armadillo-440
Debian/ABOSバージョン:atmark-dist v1.55.1
カーネルバージョン:Linux 3.14.36-at13
3G/LTE モジュール情報 (Debianのみ):-
その他:-
==========

お世話になっております。
中居と申します。

Armadillo上でRAWデータ(RGB形式)をJPEG圧縮したく、"gstreamer1.0"を有効にしたimageを使用しています。
有効箇所は以下で投稿した内容と同じです。
https://armadillo.atmark-techno.com/forum/armadillo/24297

Armadillo上で以下のように"gst-launch-1.0"コマンドを実行し、RAWデータ(RGB形式)のJPEG圧縮を試みましたが、
出力されたファイルが0byteとなり、うまく変換できておらず困っております。

[root@armadillo440-0 (ttymxc1) ~]# gst-launch-1.0 -vvv filesrc location=/mnt/test/DSC00058.rgb blocksize=$((2832*4240*2)) num-buffers=1 ! video/x-raw,format=RGB,width=2832,height=4240,framerate=1/1 ! jpegenc ! filesink location=/mnt/test/out.jpg
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:src: caps = video/x-raw, format=(string)RGB, width=(int)2832, height=(int)4240, framerate=(fraction)1/1
/GstPipeline:pipeline0/GstJpegEnc:jpegenc0.GstPad:sink: caps = video/x-raw, format=(string)RGB, width=(int)2832, height=(int)4240, framerate=(fraction)1/1
Pipeline is PREROLLED ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Got EOS from element "pipeline0".
Execution ended after 31007384 ns.
Setting pipeline to PAUSED ...
Setting pipeline to READY ...
Setting pipeline to NULL ...
Freeing pipeline ...
[root@armadillo440-0 (ttymxc1) ~]# ls -l /mnt/test/
total 71096
-rwxr-xr-x    1 root     root      72794880 Feb 28 16:33 DSC00058.rgb*
-rwxr-xr-x    1 root     root             0 Feb 28 16:39 out.jpg*
[root@armadillo440-0 (ttymxc1) ~]#

※1 圧縮対象のRAWデータ(DSC00058.rgb)について、以下の通りです。
 ①SONY社の以下のJPEGデータをダウンロード。
  https://www.dpreview.com/sample-galleries/6733082169/sony-a7s-iii-sampl…
 ②以下のサイトにて、JPEGからRGB形式に変換したものをArmadillo上で使用。
  https://convertio.co/ja/
※2 画像サイズの指定(2832×4240)については、※1①のサイトに記載の"Dimensions"をもとに設定しております。

コマンドのオプション指定が悪いのか、そもそも何か足りていないのか、
もし分かる方いらっしゃいましたらご教示いただけますと幸いです。

コメント

佐藤です。

gst-launch-1.0 コマンドのなかの
blocksize=$((2832*4240*2))

blocksize=$((2832*4240*3))
にしてみてください。

佐藤様

返信ありがとうございます。

> gst-launch-1.0 コマンドのなかの
> blocksize=$((2832*4240*2))
> を
> blocksize=$((2832*4240*3))
> にしてみてください。

上記の通り、実行してみましたが、failed to allocateとエラーになってしまいました。
実行結果を以下に記します。

[root@armadillo440-0 (ttymxc1) ~]# gst-launch-1.0 -vvv filesrc location=/mnt/test/DSC00058.rgb blocksize=$((2832*4240*3)) num-buffers=1 ! video/x-raw,format=RGB,width=2832,height=4240,framerate=1/1 ! jpegenc ! filesink location=/mnt/test/out.jpg
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:src: caps = video/x-raw, format=(string)RGB, width=(int)2832, height=(int)4240, framerate=(fraction)1/1
/GstPipeline:pipeline0/GstJpegEnc:jpegenc0.GstPad:sink: caps = video/x-raw, format=(string)RGB, width=(int)2832, height=(int)4240, framerate=(fraction)1/1
 
(gst-launch-1.0:1676): GLib-ERROR **: /build/buildd-glib2.0_2.33.12+really2.32.4-5-armel-5oMrEa/glib2.0-2.33.12+really2.32.4/./glib/gmem.c:165: failed to allocate 36023126 bytes
Trace/breakpoint trap
[root@armadillo440-0 (ttymxc1) ~]#

佐藤です。

すいません。確認させてください。
ご自身の環境では DSC00058.rgb ファイルのファイルサイズは以下のとおりになっていますが、

-rwxr-xr-x    1 root     root      72794880 Feb 28 16:33 DSC00058.rgb*

実際に以下の手順をやってみますと、
 ①SONY社の以下のJPEGデータをダウンロード。
  https://www.dpreview.com/sample-galleries/6733082169/sony-a7s-iii-sampl…
 ②以下のサイトにて、JPEGからRGB形式に変換したものをArmadillo上で使用。
  https://convertio.co/ja/
できあがる .rgb ファイルのファイルサイズは "36023040" でした。
DSC00058.rgb を作成した手順などに誤りはないでしょうか?

佐藤様

中居です。

> できあがる .rgb ファイルのファイルサイズは "36023040" でした。
> DSC00058.rgb を作成した手順などに誤りはないでしょうか?

申し訳ございません。ご指摘の通りです。
誤ったファイルを指定しておりました。
記載した手順で再度DSC00058.rgbを作成したところ、ファイルサイズは"36023040"でした。

ただ、再度作成したDSC00058.rgbを指定して、"blocksize=$((2832*4240*3))"でJPEG圧縮を試してみましたが、
変わらずfailed to allocateとエラーになってしまいました。実行結果を以下に記します。

[root@armadillo440-0 (ttymxc1) ~]# gst-launch-1.0 -vvv filesrc location=/mnt/test/DSC00058.rgb blocksize=$((2832*4240*3)) num-buffers=1 ! video/x-raw,format=RGB,width=2832,height=4240,framerate=1/1 ! jpegenc ! filesink location=/mnt/test/out.jpg
Setting pipeline to PAUSED ...
Pipeline is PREROLLING ...
/GstPipeline:pipeline0/GstCapsFilter:capsfilter0.GstPad:src: caps = video/x-raw, format=(string)RGB, width=(int)2832, height=(int)4240, framerate=(fraction)1/1
/GstPipeline:pipeline0/GstJpegEnc:jpegenc0.GstPad:sink: caps = video/x-raw, format=(string)RGB, width=(int)2832, height=(int)4240, framerate=(fraction)1/1
 
(gst-launch-1.0:1698): GLib-ERROR **: /build/buildd-glib2.0_2.33.12+really2.32.4-5-armel-5oMrEa/glib2.0-2.33.12+really2.32.4/./glib/gmem.c:165: failed to allocate 36023126 bytes
Trace/breakpoint trap
[root@armadillo440-0 (ttymxc1) ~]# ls -l /mnt/test
total 35184
-rwxr-xr-x    1 root     root      36023040 Mar  5  2025 DSC00058.rgb*
-rwxr-xr-x    1 root     root             0 Feb 28 18:23 out.jpg*
[root@armadillo440-0 (ttymxc1) ~]#

at_shota.shimoyama

2025年3月5日 20時40分

下山です。

以下のコマンドだとどうでしょうか?

gst-launch-1.0 -v filesrc location=/mnt/test/DSC00058.rgb ! rawvideoparse format=rgb width=2832 height=4240 ! jpegenc ! filesink location=/mnt/test/out.jpg

下山様

中居です。
回答ありがとうございます。

> gst-launch-1.0 -v filesrc location=/mnt/test/DSC00058.rgb ! rawvideoparse format=rgb width=2832 height=4240 ! jpegenc ! filesink location=/mnt/test/out.jpg

上記のコマンドを実行したところ、no elementのWARNINGが出力されました。
何か足りないのでしょうか。実行結果を以下に記します。

[root@armadillo440-0 (ttymxc1) ~]# gst-launch-1.0 -v filesrc location=/mnt/test/DSC00058.rgb ! rawvideoparse format=rgb width=2832 height=4240 ! jpegenc ! filesink location=/mnt/test/out.jpg
WARNING: erroneous pipeline: no element "rawvideoparse"
[root@armadillo440-0 (ttymxc1) ~]# ls -l /mnt/test
total 35184
-rwxr-xr-x    1 root     root      36023040 Mar  5  2025 DSC00058.rgb*
-rwxr-xr-x    1 root     root             0 Feb 28  2025 out.jpg*
[root@armadillo440-0 (ttymxc1) ~]#

at_shota.shimoyama

2025年3月6日 11時42分

中居様

すみません、rawvideoparseだったらもしかしたらと思ったんですが、
gstreamerのバージョンが古くてrawvideoparseエレメントがそもそも無かったようですね…

(gst-launch-1.0:1698): GLib-ERROR **: /build/buildd-glib2.0_2.33.12+really2.32.4-5-armel-5oMrEa/glib2.0-2.33.12+really2.32.4/./glib/gmem.c:165: failed to allocate 36023126 bytes

元々のコマンドのエラー内容に戻りますが、こちらは36MBの領域の割り当てに失敗しているという意味です。
ほぼ画像のサイズと同じなので、おそらくgstreamerの内部で画像と同じサイズの領域以上をメモリに確保する処理があり、
メモリ不足のために失敗していると思われます。

ですので、解決するためには、
1.画像サイズを小さくする
2.gstreamerではなく、(動作は確認していませんが)libjpegや省メモリな組み込み向けのJPEG圧縮ソフト
  https://github.com/bitbank2/JPEGENC
  などを試してみる
3.Armadillo-640などのより豊富なメモリのCPUボードを使用する

などが考えられます。

差し支えなければ
・Armadillo-440の使用
・JPEG圧縮
の背景についてお聞きしてもよろしいでしょうか?

よろしくお願いします。

下山様

回答ありがとうございます。
また、返信が遅くなってしまい申し訳ございません。

> gstreamerのバージョンが古くてrawvideoparseエレメントがそもそも無かったようですね…

"--gst-debug=6"でデバッグログを出力してみたところ、videoparseエレメントではないかという内容が読み取れました。
videoparseエレメントで試したところ、"no element"のWARNINGは出力されませんでしたが、
"failed to allocate 36023126 bytes"のエラーが再び出力されるようになりました。

上記のエラーはメモリ不足によるものなのですね。また解決策について、ご提示ありがとうございます。
一番有力なのは、"1.画像サイズを小さくする"だと思います。
まだ入手できていないのですが、本番環境で使用想定の画像サイズ(※)は
テスト用で使用している画像より小さい想定です。入手でき次第再度試してみようと思います。
※同様の画像サイズのものがなかったため、テスト用では異なる画像サイズを使用しておりました。

> 差し支えなければ
> ・Armadillo-440の使用
> ・JPEG圧縮
> の背景についてお聞きしてもよろしいでしょうか?

上記に関してですが、どちらも「顧客からの要望のため」という回答になってしまいます。
ただし、Armadillo-440の使用については確定事項ではなく、使用する可能性が高いという段階です。
ご期待する回答ではないかもしれませんが、よろしくお願いいたします。

at_kazutaka.bito

2025年3月11日 16時10分

尾藤です。

RGB形式をJPEG圧縮するだけのプログラム(お試し用。エラー処理とかない)です。

ATDE5でrgb2jpeg.cを作成します。
補足)ソースコード内で、WindowsPCのペイントで作成した
 1920x1080の24ビットbmp(ヘッダ(DIB?)付き:54Byte)用に固定にしてます。

rgb2jpeg.c

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <jpeglib.h>
 
#define RAW_WIDTH	1920 // 2832 // 4k:3840 // fhd:1920
#define RAW_HEIGHT 	1080 // 4240 // 4k:2160 // fhd:1080
#define PIX_SIZE 	3 // RGB888
#define HEADER 	54 // header length
#define JPEG_QUALITY	10
 
char rgb_file[] = "/mnt/original.bmp";
char jpg_file[] = "/home/www-data/result.jpg";
 
int main() {
	struct jpeg_compress_struct cinfo;
	struct jpeg_error_mgr jerr;
	FILE *outfile;
	FILE *infile;
 
	JSAMPARRAY img;
    	int i, j;
 
	unsigned char *img_buf;
 
	img_buf = (unsigned char*)malloc(RAW_WIDTH *RAW_HEIGHT * 3 + HEADER);
 
	infile = fopen(rgb_file, "rb");
	fread(img_buf, PIX_SIZE, RAW_WIDTH * RAW_HEIGHT + HEADER, infile);
	fclose(infile);
 
	img = (JSAMPARRAY)malloc(sizeof(JSAMPROW) * RAW_HEIGHT);
	for(i = 0; i < RAW_HEIGHT; i++) {
		img[i] = (JSAMPROW)malloc(sizeof(JSAMPLE) * 3 * RAW_WIDTH);
		for(j = 0; j < RAW_WIDTH; j++) {
			int org_i = RAW_HEIGHT - i;	// if need to reverse virtial of original data
            		img[i][j * 3 + 0] = *(img_buf + HEADER + (org_i * RAW_WIDTH * 3 + j * 3 + 2)); // BGR to RGB
            		img[i][j * 3 + 1] = *(img_buf + HEADER + (org_i * RAW_WIDTH * 3 + j * 3 + 1)); // BGR to RGB
             		img[i][j * 3 + 2] = *(img_buf + HEADER + (org_i * RAW_WIDTH * 3 + j * 3 + 0)); // BGR to RGB
        	}
    	}
 
	free(img_buf);
 
    	cinfo.err = jpeg_std_error(&jerr);
    	jpeg_create_compress(&cinfo);
 
    	outfile = fopen(jpg_file, "wb");
    	jpeg_stdio_dest(&cinfo, outfile);
 
    	cinfo.image_width = RAW_WIDTH;
    	cinfo.image_height = RAW_HEIGHT;
    	cinfo.input_components = 3;		// RGB color
    	cinfo.in_color_space = JCS_RGB;	// RGB color
 
    	jpeg_set_defaults(&cinfo);
    	jpeg_set_quality(&cinfo, JPEG_QUALITY, TRUE);
 
    	jpeg_start_compress(&cinfo, TRUE);
    	jpeg_write_scanlines(&cinfo, img, RAW_HEIGHT);
    	jpeg_finish_compress(&cinfo);
    	jpeg_destroy_compress(&cinfo);
 
    	fclose(outfile);
 
    	for(i = 0; i < RAW_HEIGHT; i++) {
        	free(img[i]);
    	}
    	free(img);
}

ビルドします。

atmark@atde5:~$ arm-linux-gnueabi-gcc rgb2jpeg.c -o rgb2jpeg -ljpeg

ビルドにより生成された実行ファイル(rgb2jpeg)を
Armadillo-440に置いて、実行権限を付けます。

[root@armadillo440-0 (ttymxc1) ~]# chmod +x rgb2jpeg

Armadillo-440の/mntにRGBファイル(※)を「original.bmp」という名前で配置します。
備考)上記ソースのままビルドすると、DIB(54Byte)付の1920x1080のRGBファイル

original.bmpをUSBメモリのトップフォルダに置いてマウントする場合

[root@armadillo440-0 (ttymxc1) ~]# mount -t vfat /dev/sda1 /mnt

original.bmpを/mntをRAMDISKのまま置く場合(/mntのtmpfs化が必要)

[root@armadillo440-0 (ttymxc1) ~]# mount -t tmpfs tmpfs /mnt
#実行後、/mntにoriginal.bmpを置く。

実行します。

[root@armadillo440-0 (ttymxc1) ~]# ./rgb2jpeg

/mnt/original.bmpをJPEG化して、/home/www/result.jpg(※)に保存されます。
※)/home/wwwに置いてあるので、PCとArmadillo-440が同一ネットワークであれば、
PCのWebブラウザで、下記のURLでJPEG化された画像が見れます。

[Armadillo-440のIPアドレス]/result.jpg

============================================
ここからが、2832×4240への挑戦です。

結論から言うと、下記制限を設けた方法でギリッギリできました。
(他のアプリ動かないと思います。できたといえるのか?)

Armadillo-440のカーネルとユーザーランドを下記にします。

Linuxカーネル ベーシックモデル用 (Linux 3.14対応) v2.08
https://armadillo.atmark-techno.com/files/downloads/armadillo-440/image…

ユーザーランド ベーシックモデル用 (Linux 3.14対応) v2.04
https://armadillo.atmark-techno.com/files/downloads/armadillo-420/image…

上記だと、RAMは80MBくらい使えます。

[root@armadillo440-0 (ttymxc1) ~]# free
             total         used         free       shared      buffers
Mem:        123204        35524        87680            0          520
-/+ buffers:              35004        88200

rgb2jpeg.cのdefineを2832×4240用にします。
(ヘッダが54Byteを想定してます。)

#define RAW_WIDTH	2832 // 2832 // 4k:3840 // fhd:1920
#define RAW_HEIGHT 	4240 // 4240 // 4k:2160 // fhd:1080
#define PIX_SIZE 	3 // RGB888
#define HEADER 	54 // header length
#define JPEG_QUALITY	10

備考)DSC00058.rgbのサイズが、36023040byteということは、
ヘッダが無いので、この場合、HEADERは、0にします。

2832×4240のbmpファイルをoriginal.bmpという名前で作成し、
USBメモリのトップフォルダに置いてマウントします。(後述、参考1参照)

[root@armadillo440-0 (ttymxc1) ~]# mount -t vfat /dev/sda1 /mnt

rgb2jpegの実行と実行結果result.jpgは上述と同じです。

参考1)
実行中のメモリ消費具合を見てると、使用可能な約80MB中、ほぼ80MB消費してました。
(つまり、2832×4240のbmpファイルをArmadillo-440のRAMDISKに置く余裕は全くないので、
 USBメモリをマウントして、USBメモリ上のoriginal.bmpを直接扱うようにしてます。)

参考2)
JPEG_QUALITY
を上げると、生成されるJPEGファイルが大きくなりメモリを消費します。

ちなみに、圧縮率の悪そうなurandamで作った2832×4240を試すと、
JPEG_QUALITY 10
で、JPEGファイルサイズが1MBちょい、が限界でした。
(普通の画像はここまで圧縮率悪くないので、JPEG_QUALITYは上げれるかと思います。)

参考3)
上下が逆転する、RGBが入れ替わる、などの場合は、rgb2jpeg.cの下記の箇所を調整ください。

			int org_i = RAW_HEIGHT - i;	// if need to reverse virtial of original data
            		img[i][j * 3 + 0] = *(img_buf + HEADER + (org_i * RAW_WIDTH * 3 + j * 3 + 2)); // BGR to RGB
            		img[i][j * 3 + 1] = *(img_buf + HEADER + (org_i * RAW_WIDTH * 3 + j * 3 + 1)); // BGR to RGB
             		img[i][j * 3 + 2] = *(img_buf + HEADER + (org_i * RAW_WIDTH * 3 + j * 3 + 0)); // BGR to RGB

at_shota.shimoyama

2025年3月12日 11時44分

中居様

> まだ入手できていないのですが、本番環境で使用想定の画像サイズ(※)は
> テスト用で使用している画像より小さい想定です。入手でき次第再度試してみようと思います。
> ※同様の画像サイズのものがなかったため、テスト用では異なる画像サイズを使用しておりました。

左様でしたか。差し支えなければ本番環境で使用想定の画像サイズをお聞きしてもよろしいでしょうか?
(もし具体的なサイズが分かっていれば、ツールなどで用意できるのではないかと思った次第です)

ちなみに、前の回答で
2.gstreamerではなく、(動作は確認していませんが)libjpegや省メモリな組み込み向けのJPEG圧縮ソフト
  https://github.com/bitbank2/JPEGENC
  などを試してみる
と申し上げましたが、libjpeg-toolsとJPEGENCについてDSC00058の画像でそれぞれ検証してみました。

結論ですが、libjpeg-toolsについてはgstreamer同様、メモリ不足となりJPEG圧縮できませんでした。
JPEGENCについては素のままでは化け&メモリ不足となりJPEG圧縮できませんでしたが、
化け&メモリ不足どちらも解消するパッチを作ったところ、DSC00058でもJPEG圧縮することができました。

■パッチを当てたJPEGENCの使用方法
以下、JPEGENCにパッチを当てて使用する手順になります。ご参考になれば幸いです。

1.ATDE5のホームディレクトリでJPEGENCをダウンロードする

atmark@atde5:~$ git clone https://github.com/bitbank2/JPEGENC.git

2.~/JPEGENC/ に添付のパッチファイル(jpegenc_readbmp-memsave.patch)をコピー

3.パッチを適用

atmark@atde5:~$ cd JPEGENC
atmark@atde5:~/JPEGENC$ cat jpegenc_readbmp-memsave.patch | patch -p1

4.コンパイル

atmark@atde5:~/JPEGENC$ cd linux
atmark@atde5:~/JPEGENC/linux$ CC=arm-linux-gnueabi-gcc CXX=arm-linux-gnueabi-g++ make

5.~/JPEGENC/linux/jpegenc というバイナリができるので、これをArmadilloにコピーします。

6./mnt/test.bmpを/mnt/test.jpgにJPEG圧縮

[root@armadillo440-0 (ttymxc1) ~]# ./jpegenc /mnt/test.bmp /mnt/test.jpg

■JPEGENC使用の前提
JPEGENCを使用するにあたって、入力ファイルはWindows BMP形式(.bmp)である必要があります。
.bmpと.rgbとの違いはほとんどヘッダーの有無です。
入力画像を.bmpとして入手できれば確実ですが、もし.rgbとして入手することが決まっている場合は、
.rgbにヘッダーをつけて.bmpにするようなプログラムを用意するか、JPEGENC内のヘッダー読み取り部分の処理を改造して.rgb対応のプログラムに直すかといった処置が必要になると思います。

■パッチを当てたJPEGENCの使用メモリ量
元々のJPEGENCでは入力画像2枚分のメモリの空き容量(DSC00058であれば72MB)が必要なのですが、入力画像1枚分の空き容量(DSC00058であれば36MB)で済むようにプログラムを修正しました。

何かご不明な点がございましたら遠慮なくお聞きください。
よろしくおねがいします。

ファイル ファイルの説明
jpegenc_readbmp-memsave.patch

下山様、尾藤様

白川と申します。本件に関して、諸事情で私が引き継ぎました。
色々と調査いただきありがとうございます、大変助かります。順次確認してまいります。

取り急ぎ、本番環境で使用予定のサイズは以下になります。
2048x1944

当初使用していたサイズ(2832×4240)は、たまたま見つけた画像がそうだっただけで、大きな意味はありません。混乱を招いてしまい申し訳ございません。