

SPRESENSE Arduino で libjpeg を使いたいと思っています。SDK ではライブラリとして使えるように思えるのですが、Arduino
環境ではどうやったら使えるのでしょうか？サブコアで libjpeg を動かしたいと思っています。


CC BY-SA 4.0
2021-01-14T15:37:13.873
73301
2022-03-11T00:54:55.443
39850
question
spresense arduino
SPRESENSE Arduino で libjpeg を使いたい


こんにちは。  
私もオリジナルのライブラリを追加してみたことがあるので、その時の方法を書いてみます。

今回の場合はlibjpegを有効にしたSDKのパッケージを作成するとlibjpegを使用できると思います。

ソニーのサイトの[4.2.2.
ローカルパッケージの作成方法](https://developer.sony.com/develop/spresense/docs/arduino_set_up_ja.html#_%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90%E6%96%B9%E6%B3%95)を使えばオリジナルのパッケージを作成できるようす。

また恐らく、spresense-arduino-compatibleリポジトリの
[tools/configs/spresense_sub.conf](https://github.com/sonydevworld/spresense-
arduino-compatible/blob/master/tools/configs/spresense_sub.conf)
が、パッケージを作成するときの設定だと思われるのでこれに `feature/libjpeg`
を追加すれば作成されるパッケージにlibjpegが追加されるのではないかと。

なんとなく、パッケージを作成するときに使われているスクリプト(spresenseリポジトリ)
[sdk/tools/mksdkexport.sh](https://github.com/sonydevworld/spresense/blob/master/sdk/tools/mksdkexport.sh)
で書庫ファイルを追加してあげないといけないような気がするので 135 行目に

[code]

    ${SDK_DIR}/../externals/libjpeg/libjpeg.a\
    
[/code]

を追加してあげた方が良いと思います。

ご参考になれば幸いです！


CC BY-SA 4.0
2021-01-20T09:10:32.207
73436
2021-01-20T09:10:32.207
32034
73301
answer


こちら、メインコアですが、試す必要があってやってみました。この内容はサブコアにも応用できると思います。実際にやってみたところ、いくつかポイントがあったので備忘録として記載しておきます。（思った以上に大変でした）

  1. SpresenseSDKのインストール  
<https://developer.sony.com/develop/spresense/docs/sdk_set_up_ja.html>

  2. spresense-arduino-compatibleをクローン  
`$ git clone --recursive https://github.com/sonydevworld/spresense-arduino-
compatible.git`

  3. spresense-arduino-compatible/tools/configs/spresense.confの書き換え  
次の内容を加えます。(subcoreの場合は、spresense_sub.conf）

`feature/libjpeg`  
`+ARCH_SETJMP_H=y`

  4. spresense/sdk/tools/mksdkexport.shの書き換え  
135行目 `${SDK_DIR}/../externals/libjpeg/libjpeg.a\`  
113行目(2行追加)  
`mkdir -p ${TMP_DIR}/${SDK_EXP_SDK}/externals/include/libjpeg`  
`cp -a ${SDK_DIR}/../externals/libjpeg/*.h \
${TMP_DIR}/${SDK_EXP_SDK}/externals/include/libjpeg/`

  5. borad.txt の書き換え  
`spresense-arduino-
comaptible/Arduino15/packages/SPRESENSE/hardware/spresense/1.0.0/board.txt`
を編集  
100行目 `spresense,menu.Core.Main.build.libs` に `"{build.libpath}/libjpeg.a"`
を追加

  6. Arduino の boolean の定義を変更  
libjpegでもbooleanを定義しています。libjpeg の
booleanの定義を変更すると容量計算が狂ってしまい、デコード時にエラーが出てしまいます。そのため、Arduinoのbooleanの定義を変更しなければなりません。次のファイルで定義されています。  
`spresense-arudino-
comaptible/Arduino15/packages/SPRESENSE/hardware/spresense/1.0.0/cores/spresense/WCharacter.h`

46行目の`typedef bool boolean`を`typedef int boolean`に変更

  7. Arduino Library Packageを生成/コピー  
`$ cd spresense-arduino-compatible`  
`$ ./tools/prepare_arduino.sh -S ~/spresense -c spresense -d disable -p`  
`$ ./tools/prepare_arduino.sh -S ~/spresense -c spresense -d enable -p`  
`$ ./tools/prepare_arduino.sh -S ~/spresense -c spresense_sub -d disable -p`  
`$ ./tools/prepare_arduino.sh -S ~/spresense -c spresense_sub -d enable -p`  
`$ make`  
`$ cp ./out/package_spresense_local_index.json
/home/<user>/snap/arduino/61/.arduino15`  
`$ cp -r ./out/staging /home/<user>/snap/arduino/61/.arduino15`

  8. Arduino IDE でボードマネージャーに追加  
環境設定で「追加のボードマネージャのURL」に`file:///home/<user>/snap/arduino/61/.arduino15/package_spresense_local_index.json`を設定（Linuxの場合）  
ボードマネージャーを使って「Spresense local Board」をインストール

  9. libjpeg のテスト用スケッチを使って動作確認  
確認には、小さめのJPEGを用意してください。私は添付のものを使用しました。注意する点としては、setjmp/longjmp
はlibc.aに含まれますので`extern "C"` で囲わないとリンクエラーが出ます。

[![テスト用画像](https://i.stack.imgur.com/nwROe.jpg)](https://i.stack.imgur.com/nwROe.jpg)

[code]

    #define HAVE_BOOLEAN
    
    #include <nuttx/config.h>
    #include <sys/stat.h>
    #include <unistd.h>
    #include <libjpeg/jpeglib.h>
    extern "C" {
    #include <setjmp.h>
    }
    
    extern JSAMPLE* image_buffer;
    
    struct my_error_mgr {
      struct jpeg_error_mgr pub;    /* "public" fields */
      jmp_buf setjmp_buffer;        /* for return to caller */
    };
    
    typedef struct my_error_mgr* my_error_ptr;
    
    
    char filename[16] = "/mnt/sd0/in.jpg";
    char outfile[17] = "/mnt/sd0/out.rgb";
    
    
    METHODDEF(void) my_error_exit(j_common_ptr cinfo) {
      my_error_ptr myerr = (my_error_ptr) cinfo->err;
      (*cinfo->err->output_message) (cinfo);
      longjmp(myerr->setjmp_buffer, 1);
    }
    
    
    void setup() {
      static struct jpeg_decompress_struct cinfo;
      struct my_error_mgr jerr;
      FILE * infile;                /* source file */
      FILE* out;                    /* output file */
      JSAMPARRAY buffer;            /* Output row buffer */
      int row_stride;               /* physical row width in output buffer */
    
      struct stat buf;
      for (;;) {
        int ret = stat("/mnt/sd0", &buf);
        if (ret) {
          printf("Please insert formatted SD Card.\n");
          sleep(1);
        } else {
          break;
        }
      }
    
      if ((infile = fopen(filename, "rb")) == NULL) {
        fprintf(stderr, "can't open %s\n", filename);
        return 0;
      }
      printf("open %s\n", filename);
    
      if ((out = fopen(outfile, "wb")) == NULL) {
        fprintf(stderr, "can't open %s\n", outfile);
        return 0;    
      }
      printf("create %s\n", outfile);
    
      /* Step 1: allocate and initialize JPEG decompression object */
      /* We set up the normal JPEG error routines, then override error_exit. */
      cinfo.err = jpeg_std_error(&jerr.pub);
      jerr.pub.error_exit = my_error_exit;
      /* Establish the setjmp return context for my_error_exit to use. */
      if (setjmp(jerr.setjmp_buffer)) {
        /* If we get here, the JPEG code has signaled an error.
         * We need to clean up the JPEG object, close the input file, and return.
         */
        jpeg_destroy_decompress(&cinfo);
        fprintf(stderr, "can't make decompress object\n");
        fclose(infile);
        return;
      }
      /* Now we can initialize the JPEG decompression object. */
      jpeg_create_decompress(&cinfo);
      printf("Step1: create decompress object\n");
    
      /* Step 2: specify data source (eg, a file) */
      jpeg_stdio_src(&cinfo, infile);
      printf("Step2: set the data source\n");
    
      /* Step 3: read file parameters with jpeg_read_header() */
      (void)jpeg_read_header(&cinfo, TRUE);
      printf("Step3: read the data header\n");
      /* We can ignore the return value from jpeg_read_header since
       *   (a) suspension is not possible with the stdio data source, and
       *   (b) we passed TRUE to reject a tables-only JPEG file as an error.
       * See libjpeg.txt for more info.
       */
    
      /* Step 4: set parameters for decompression */
      cinfo.out_color_space = JCS_RGB;
      printf("Step4: set the output parameter as JCS_RGB\n");
    
      /* Step 5: Start decompressor */
      (void) jpeg_start_decompress(&cinfo);
      printf("Step5: start decompression\n");
      /* JSAMPLEs per row in output buffer */
      /* Modified for Spresense by Sony Semiconductor Solutions.
       * CbYCrY format has 16bpp. So, stride is width * 2 bytes.
       */
      /* row_stride = cinfo.output_width * cinfo.output_components; */
      //row_stride = cinfo.output_width * 2; // in case of YCbCr
      row_stride = cinfo.output_width * 3; // in case of RGB
      /* Make a one-row-high sample array that will go away when done with image */
      buffer = (*cinfo.mem->alloc_sarray)
                    ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
    
      /* Step 6: while (scan lines remain to be read) */
      printf("Step6: read scanlines\n");
      int n = 0;
      while (cinfo.output_scanline < cinfo.output_height) {
        /* jpeg_read_scanlines expects an array of pointers to scanlines.
         * Here the array is only one element long, but you could ask for
         * more than one scanline at a time if that's more convenient.
         */
        (void) jpeg_read_scanlines(&cinfo, buffer, 1);
        if (row_stride != fwrite(buffer[0], 1, row_stride, out)) {
          printf("fwrite error : %d\n", errno);
        }
        ++n;
      }
      printf("read lines: %d\n", n);
      printf("close output file\n");
      fclose(out);
    
      /* Step 7: Finish decompression */
      printf("Step7: finish decompression\n");  
      (void) jpeg_finish_decompress(&cinfo);
    
      /* Step 8: Release JPEG decompression object */
      printf("Step8: destroy decompress object\n");  
      jpeg_destroy_decompress(&cinfo);
      printf("Step9: close infile\n");
      fclose(infile);
    }
    
    void loop() {}
    
[/code]

【補足】  
Spresense SDK
はデフォルトの状態では解凍だけサポートしており圧縮はサポートしていません。圧縮も有効にしたい場合は、`spresense/sdk/externals/libjpeg/Makefile`
に次のファイルを追記してコンパイル対象にする必要があります。

[code]

    CSRCS += jcapimin.c jcapistd.c jcarith.c jccoefct.c jccolor.c
    CSRCS += jcdctmgr.c jchuff.c jcinit.c jcmainct.c jcmarker.c jcmaster.c
    CSRCS += jcparam.c jcprepct.c jcsample.c jctrans.c jdatadst.c
    CSRCS += jfdctflt.c jfdctfst.c jfdctint.c
    
[/code]


CC BY-SA 4.0
2022-01-06T08:08:58.777
85518
2022-03-11T00:54:55.443
2022-03-11T00:54:55.443
27334
27334
73301
answer