2023,江端さんの技術メモ

まず、WIndows10のWSL Ubuntu-20.04 を WSL2にしなければなりません。

WSLのバージョンが"1"だったので"2"に変えようとしたら、ちょっと酷い目にあった件

でもって、さらに、このWSL2に usbのデバイスを使えるようにしなければなりません。

再度、『wsl で USBのWebカメラを使う』に挑戦中

でもって、Gstreamの環境がインストールされていることが前提です。

Windows10のWSLでX11アプリケーションを実行してみた + GStreamerを試してみた

と、ターゲットのカメラはこれ

Webカメラ C270n HD 720P

=====  手続の備忘録 ======

Step 1: powershellを管理者モードで立ち上げて、"
usbipd server"投入

Step 2: コマンドプロンプトから、"C:\Users\ebata>wsl -d Ubuntu-20.04"を投入

Step 3: 別のpowershellを管理者モードで立ち上げて、"
usbipd wsl attach --distribution Ubuntu-20.04 --busid 8-3"を投入

Step 4: コマンドプロンプトから、"C:\Users\ebata>sudo chmod 777 /dev/video*"を投入

これらを乗り超えて、ようやく、Gstreamer で、Webカメラの映像をループバックで表示しようとしたのですが、これが全く分からなくて、色々試しました。やけくそのトアイアンドエラー

gst-launch-1.0 videotestsrc ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500
(成功)

gst-launch-1.0 v4l2src device="/dev/video0" ! 'video/x-raw, width=640, height=480, framerate=30/1' ! videoconvert ! nv3dsink (失敗)

gst-launch-1.0 videotestsrc ! videoconvert ! video/x-raw,width=1280,height=720,framerate=30/1 ! autovideosink

gst-launch-1.0 -e filesrc location=start_up.mp4 ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500
(失敗)

gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=30/1 ! autovideosink
(動く)

gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=30/1 ! srtserversink uri="srt://:12345" latency=500(動く)

gst-launch-1.0 v4l2src ! videoconvert ! ximagesink (動くが、大きなブラック画面がでてきただけ)

gst-launch-1.0 v4l2src device="/dev/video0" ! videoconvert ! ximagesink

gst-launch-1.0 v4l2src device="/dev/video0" ! 'video/x-raw, width=640, height=480, framerate=30/1' ! videoconvert ! nv3dsink

gst-launch-1.0 v4l2src device="/dev/video0" ! 'video/x-raw, width=640, height=480, framerate=30/1' ! videoconvert ! ximagesink
(これは黒い画面が表示される)

gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=1/1 ! srtserversink uri="srt://:12345" latency=500
(失敗)
00:40:58.339192/multiqueue0:src*E:SRT.c: LiveCC: payload size: 506880 exceeds maximum allowed 1316
00:40:59.339081/multiqueue0:src*E:SRT.c: LiveCC: payload size: 506880 exceeds maximum allowed 1316
00:41:00.339101/multiqueue0:src*E:SRT.c: LiveCC: payload size: 506880 exceeds maximum allowed 1316
00:41:01.339057/multiqueue0:src*E:SRT.c: LiveCC: payload size: 506880 exceeds maximum allowed 1316

gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=1/1 ! autovideosink
(成功)

gst-launch-1.0 filesrc location=start_up.mp4 ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500
(失敗)

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw, height=480, width=640 ! videoconvert ! x264enc tune=zerolatency ! video/x-h264, profile=high ! mpegtsmux ! srtserversink uri=srt://:12345/
(エラーは出ていないが表示もされない)
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Setting pipeline to PLAYING ...
New clock: GstSystemClock
Redistribute latency...
^Chandling interrupt.
Interrupt: Stopping pipeline ...
Execution ended after 0:01:50.658920768
Setting pipeline to NULL ...
Freeing pipeline ...

gst-launch-1.0 v4l2src device=/dev/video0 ! video/x-raw, height=480, width=640 ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500
(失敗)

gst-launch-1.0 -v filesrc location=start_up.mp4 ! qtdemux ! queue ! h264parse ! avdec_h264 ! video/x-raw, height=1080, width=1920 ! videoconvert ! x264enc tune=zerolatency ! video/x-h264, profile=high ! mpegtsmux ! srtsink uri=srt://:12345/
(失敗)

gst-launch-1.0 filesrc location=start_up.mp4 ! qtdemux ! h264parse ! rtph264pay ! udpsink host=127.0.0.1 port=5000
(失敗)

gst-launch-1.0 filesrc location=30ftp.mp4 ! qtdemux ! h264parse ! rtph264pay ! srtsink uri=srt://:12345
(失敗)

gst-launch-1.0 filesrc location=30ftp.mp4 ! qtdemux ! h264parse ! identity drop-probability=1 ! rtph264pay ! srtsink uri=srt://:12345

gst-launch-1.0 v4l2src ! video/x-raw,width=640,height=480 ! autovideosink

gst-launch-1.0 v4l2src device="/dev/video0" ! 'image/jpeg, width=1280, height=720, framerate=30/1' ! jpegdec ! nv3dsink

gst-launch-1.0 v4l2src device=/dev/video0 ! 'video/x-raw,format=(string)YUYV,width=640,height=480,framerate=30/1' ! autovideosink

gst-launch-1.0 v4l2src device=/dev/video0 ! 'video/x-raw,width=640,height=480,framerate=30/1' ! videoconvert ! autovideosink

ChatGPTが示してきた答え
gst-launch-1.0 v4l2src device=/dev/video0 ! 'video/x-raw,format=(string)YUY2,width=640,height=480,framerate=30/1' ! autovideosink

でも、これでもエラーはでてこないが、動かない。

C270nのWebカメラ映像をGstreamerで録画したい
(ChatGPTが示してきた答え)
gst-launch-1.0 v4l2src device=/dev/video0 ! 'video/x-raw,format=(string)YUY2,width=640,height=480,framerate=30/1' ! videoconvert ! x264enc ! mp4mux ! filesink location=output.mp4

で、ようやく動いたのが、これ

gst-launch-1.0 v4l2src device="/dev/video0" ! 'image/jpeg, width=1280, height=720, framerate=30/1' ! jpegdec ! autovideosink

ちょっと画面が大きいので、今、表示しているのは、以下のコマンドで少し小さくして表示

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata/Gstreamer$ gst-launch-1.0 v4l2src device="/dev/video0" ! 'image/jpeg, width=640, height=480, framerate=30/1' ! jpegdec ! autovideosink
Setting pipeline to PAUSED ...
Pipeline is live and does not need PREROLL ...
Got context from element 'autovideosink0': gst.gl.GLDisplay=context, gst.gl.GLDisplay=(GstGLDisplay)"\(GstGLDisplayX11\)\ gldisplayx11-0";
Setting pipeline to PLAYING ...
New clock: GstSystemClock
WARNING: from element /GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstGLImageSinkBin:autovideosink0-actual-sink-glimage/GstGLImageSink:sink: A lot of buffers are being dropped.
Additional debug info:
gstbasesink.c(3003): gst_base_sink_is_too_late (): /GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstGLImageSinkBin:autovideosink0-actual-sink-glimage/GstGLImageSink:sink:
There may be a timestamping problem, or this computer is too slow.
WARNING: from element /GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstGLImageSinkBin:autovideosink0-actual-sink-glimage/GstGLImageSink:sink: A lot of buffers are being dropped.
Additional debug info:
gstbasesink.c(3003): gst_base_sink_is_too_late (): /GstPipeline:pipeline0/GstAutoVideoSink:autovideosink0/GstGLImageSinkBin:autovideosink0-actual-sink-glimage/GstGLImageSink:sink:
There may be a timestamping problem, or this computer is too slow

表示されたのはいいけど、警告が凄い

ちなみに、SRTの通信にも成功してVLCで表示できました(遅延が凄いけど(2~3秒))。

gst-launch-1.0 v4l2src device="/dev/video0" ! 'image/jpeg, width=640, height=480, framerate=30/1' ! jpegdec ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500

コマンドをかたっぱしからくっつけたでけです。

2023,江端さんの技術メモ

WSLのバージョンが"1"だったので"2"に変えようとしたら、ちょっと酷い目にあった件

を経て、再度、wsl で USBのWebカメラを使うに、挑戦中。

ちなみにターゲットのカメラはこちら(ロジクール Webカメラ C270n HD 720P)です。

ちなみに前提として、https://github.com/dorssel/usbipd-win/releases から、usbipd-win_3.0.0.msiをダウンードしてWIndows10に入れています。

とりあえずWindows10(×11)の、powershell(管理者モード)で、以下を確認

PS C:\WINDOWS\system32> wsl --list --all --verbose
NAME STATE VERSION
* docker-desktop-data Stopped 2
Ubuntu-20.04 Running 2
docker-desktop Stopped 2

という、いわゆる「オール2」をなんとか実現。

PS C:\WINDOWS\system32> usbipd wsl list
BUSID VID:PID DEVICE STATE
4-1 1058:25a2 USB 大容量記憶装置 Not attached
4-2 04bb:011c USB 大容量記憶装置 Not attached
5-3 04d9:1400 USB 入力デバイス Not attached
6-1 0d8a:0103 USB 印刷サポート Not attached
6-3 093a:2510 USB 入力デバイス Not attached
7-2 04f9:02c0 USB 印刷サポート, Brother DCP-J940N, USB 大容量記憶装置 Not attached
8-1 0a12:0001 Generic Bluetooth Radio Not attached
8-2 0d8c:0139 USB PnP Sound Device, USB 入力デバイス Not attached
8-3 046d:0825 Logi C270 HD WebCam Not attached
8-4 04e6:511a SCR3310-NTTCom USB SmartCard Reader Not attached

までは、なんとか出てくるのだけど、

PS C:\WINDOWS\system32> usbipd wsl attach --busid 8-3
usbipd: info: Using default WSL distribution 'docker-desktop-data'; specify the '--distribution' option to select a different one.
usbipd: error: The selected WSL distribution is not running; keep a command prompt to the distribution open to leave it running.

このエラーが取れない(いまいましい)。

https://github.com/dorssel/usbipd-win/issues/136 のページを読んでいたら、ちょっと気になった一節があったので、これを試してみました。

PS C:\WINDOWS\system32> usbipd wsl attach --distribution Ubuntu-20.04 --busid 8-3

としたら、何も言わずに、「通し」ました。

通らない場合もありました。

usbipd: error: The service is currently not running; a reboot should fix that.

というエラーがでてきて困りました。

この場合、管理者モードで立ち上げたpowershellから、

usbipd server

を投入しつつ、別の管理者モードでpowershellから、"usbipd wsl attach --distribution Ubuntu-20.04 --busid 8-3" を実施すると上手くみたいです(powershellが2つも上がっている状態はうっとうしですが)

BUSID VID:PID DEVICE STATE
4-1 1058:25a2 USB 大容量記憶装置 Not attached
4-2 04bb:011c USB 大容量記憶装置 Not attached
5-3 04d9:1400 USB 入力デバイス Not attached
6-1 0d8a:0103 USB 印刷サポート Not attached
6-3 093a:2510 USB 入力デバイス Not attached
7-2 04f9:02c0 USB 印刷サポート, Brother DCP-J940N, USB 大容量記憶装置 Not attached
8-1 0a12:0001 Generic Bluetooth Radio Not attached
8-2 0d8c:0139 USB PnP Sound Device, USB 入力デバイス Not attached
8-3 046d:0825 Logi C270 HD WebCam Attached - Ubuntu-20.04
8-4 04e6:511a SCR3310-NTTCom USB SmartCard Reader Not attached

おお、通ったようだ ―― では、ここからどうすればいいだっけ?

WSLからlsusbを実行し、接続されているUSBデバイスをリストアップすると、ッデバイスが見えるようになっていました。

ebata@DESKTOP-P6KREM0:/dev$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

ここから先は、

WSL2 USBカメラ+他のUSB機器 2022年09月06日版

を参照。

私の環境でも、

ebata@DESKTOP-P6KREM0:/dev$ ls -l /dev/video
ls: cannot access '/dev/video': No such file or directory

となったので、Linuxカーネルをカスタムビルド に入る準備が整ったのだろう。憂鬱だ。カーネルのビルドと聞くだけで、おぞましい記憶が蘇えってくるから

と、泣き言をいってもしかたがないので、

https://github.com/PINTO0309/wsl2_linux_kernel_usbcam_enable_conf

に突っ込むこととする。

On WSL2.

ebata@DESKTOP-P6KREM0:~$ uname -r -v
5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023

幸い、ページの内容と同じのようだ。

On Windows Terminal.

PS C:\WINDOWS\system32> wsl --update
更新プログラムを確認しています。
Linux 用 Windows サブシステムの最新バージョンは既にインストールされています。
PS C:\WINDOWS\system32> wsl --shutdown

で、

PS C:\WINDOWS\system32> wsl --install -d Ubuntu-20.04
Ubuntu 20.04 LTS は既にインストールされています。
Ubuntu 20.04 LTS を起動しています...

で、
On WSL2

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ uname -r -v
5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023

で、

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ sudo apt update && sudo apt upgrade -y
[sudo] password for ebata:
Hit:1 http://ppa.launchpad.net/longsleep/golang-backports/ubuntu focal InRelease
(中略)
Calculating upgrade... Done
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

で、

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ sudo apt install -y build-essential flex bison libgtk-3-dev libelf-dev libncurses-dev autoconf libudev-dev libtool zip unzip v4l-utils libssl-dev python3-pip cmake git iputils-ping net-tools dwarves guvcview python-is-python3 bc
Reading package lists... Done

(中略)

Processing triggers for install-info (6.7.0.dfsg.2-5) ...
Processing triggers for desktop-file-utils (0.24-1ubuntu3) ...

で、

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ cd /usr/src
ebata@DESKTOP-P6KREM0:/usr/src$ TAGVERNUM=5.15.90.1 && TAGVER=linux-msft-wsl-${TAGVERNUM} && WINUSERNAME=ebata
ebata@DESKTOP-P6KREM0:/usr/src$ sudo git clone --depth 1 -b ${TAGVER} https://github.com/microsoft/WSL2-Linux-Kernel.git ${TAGVERNUM}-microsoft-standard && cd ${TAGVERNUM}-microsoft-standard
Cloning into '5.15.90.1-microsoft-standard'...

(中略)

Updating files: 100% (73704/73704), done.

で、

ebata@DESKTOP-P6KREM0:/usr/src/5.15.90.1-microsoft-standard$ sudo wget -O .config https://github.com/PINTO0309/wsl2_linux_kernel_usbcam_enable_conf/raw/main/${TAGVER}/config-${WSL_DISTRO_NAME} && sudo chmod 777 .config && sudo make clean
--2023-06-08 23:52:43-- https://github.com/PINTO0309/wsl2_linux_kernel_usbcam_enable_conf/raw/main/linux-msft-wsl-5.15.90.1/config-Ubuntu-20.04
(中略)

2023-06-08 23:52:44 (11.3 MB/s) - ‘.config’ saved [123800/123800]

で、ここからが、本格的なカーネルコンパイルのようで、相当時間がかかった。パスワードを1回聞かれました

ebata@DESKTOP-P6KREM0:/usr/src/5.15.90.1-microsoft-standard$ sudo make -j$(nproc) KCONFIG_CONFIG=.config && sudo make modules_install -j$(nproc) && sudo make install -j$(nproc)
SYNC include/config/auto.conf.cmd

(中略)

BUILD arch/x86/boot/bzImage
Kernel: arch/x86/boot/bzImage is ready (#1)
[sudo] password for ebata:
arch/x86/Makefile:142: CONFIG_X86_X32 enabled but no binutils support

(中略)

I: /boot/initrd.img is now a symlink to initrd.img-5.15.90.1-microsoft-standard-WSL2+

で、

ebata@DESKTOP-P6KREM0:/usr/src/5.15.90.1-microsoft-standard$ sudo rm /mnt/c/Users/${WINUSERNAME}/vmlinux
rm: cannot remove '/mnt/c/Users/ebata/vmlinux': No such file or directory

(ここで初めてエラーになった。で、実際に、vmlinuxがなかったので、このままにして次に進んだ)

ebata@DESKTOP-P6KREM0:/usr/src/5.15.90.1-microsoft-standard$ sudo cp /usr/src/${TAGVERNUM}-microsoft-standard/vmlinux /mnt/c/Users/${WINUSERNAME}/

で、

ebata@DESKTOP-P6KREM0:/usr/src/5.15.90.1-microsoft-standard$ cat << 'EOT' > /mnt/c/Users/${WINUSERNAME}/.wslconfig
> [wsl2]
> kernel=C:\\Users\\ebata\\vmlinux
> EOT

で、

On Windows Terminal. (新しいターミナルから)

PS C:\WINDOWS\system32> wsl --shutdown

On WSL2。ビルドされたカーネルが正常にロードされた場合、カーネル名の末尾に+が表示されます。#nはカーネルがビルドされた回数です。

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ uname -r -v
5.15.90.1-microsoft-standard-WSL2+ #1 SMP Thu Jun 8 23:54:50 JST 2023

で、 On WSL2.で

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ cd /usr/src

ebata@DESKTOP-P6KREM0:/usr/src$ TAGVERNUM=6.1.21.2

ここの6.1.21.2は、

https://github.com/microsoft/WSL2-Linux-Kernel/tags

にあった最新のものを適当に入れた(知らん)。

On WSL2.

ebata@DESKTOP-P6KREM0:/usr/src$ sudo git clone -b ${TAGVER} https://github.com/microsoft/WSL2-Linux-Kernel.git ${TAGVERNUM}-microsoft-standard && cd ${TAGVERNUM}-microsoft-standard

で、これが結構長かった。

で、

ebata@DESKTOP-P6KREM0:/usr/src/6.1.21.2-microsoft-standard$ sudo cp /proc/config.gz config.gz && sudo gunzip config.gz && sudo mv config .config
ebata@DESKTOP-P6KREM0:/usr/src/6.1.21.2-microsoft-standard$ sudo make menuconfig
HOSTCC scripts/basic/fixdep

(中略)

HOSTLD scripts/kconfig/mconf

(ここで、GUIが突然登場してビビったが、"save"を選んで、".config"を選んで終了させる)
*** End of the configuration.
*** Execute 'make' to start the build or try 'make help'.

で、On Windows Terminal.で

$ wsl --shutdown
$wsl -d Ubuntu-20.04

で、

PS C:\WINDOWS\system32> usbipd wsl attach --busid 8-3
usbipd: info: Using default WSL distribution 'docker-desktop-data'; specify the '--distribution' option to select a different one.
usbipd: error: The selected WSL distribution is not running; keep a command prompt to the distribution open to leave it running.

とあいもかわらず、このエラーがでるので、

PS C:\WINDOWS\system32> usbipd wsl attach --distribution Ubuntu-20.04 --busid 8-3

で、対処。

で、WSLからどーなったか見てみる。

ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 046d:0825 Logitech, Inc. Webcam C270
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
ebata@DESKTOP-P6KREM0:/mnt/c/Users/ebata$ ls -l /dev/video*
crw------- 1 root root 81, 0 Jun 9 00:57 /dev/video0
crw------- 1 root root 81, 1 Jun 9 00:57 /dev/video1

あ、ようやくデバイスがきた。この2行の為に、これまでの苦労があった。

で、後は、https://zenn.dev/pinto0309/articles/e1432253d29e30に記載されているpythonのプログラムをそのまま使わせて頂き、カメラから映像がでることを確認しました。

Corrupt JPEG data: 2 extraneous bytes before marker 0xd6
Corrupt JPEG data: 6 extraneous bytes before marker 0xd2
Corrupt JPEG data: 1 extraneous bytes before marker 0xd0
Corrupt JPEG data: 2 extraneous bytes before marker 0xd0
Corrupt JPEG data: 1 extraneous bytes before marker 0xd4
Corrupt JPEG data: 2 extraneous bytes before marker 0xd3
Corrupt JPEG data: 1 extraneous bytes before marker 0xd0
Corrupt JPEG data: 11 extraneous bytes before marker 0xd3

が出てきていますが、気にしません。

ちなみに、画像が出てこなかったので、XWinrcを起動したところ、表示ができたようです。https://dev.classmethod.jp/articles/wsl-x-window/

と、/dev/videoを作るためだけに、何時間かが溶けました。


ところが、

ebata@DESKTOP-P6KREM0:/dev$ gst-launch-1.0 videotestsrc ! v4l2sink device=/dev/video0
Setting pipeline to PAUSED ...
ERROR: Pipeline doesn't want to pause.
ERROR: from element /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0: Could not open device '/dev/video0' for reading and writing.
Additional debug info:
v4l2_calls.c(621): gst_v4l2_open (): /GstPipeline:pipeline0/GstV4l2Sink:v4l2sink0:
system error: Permission denied
Setting pipeline to NULL ...
Freeing pipeline ...

って、何だ、これ?

で、やっと分かったんですが。

ebata@DESKTOP-P6KREM0:/dev$ ls -la video*
crw------- 1 root root 81, 0 Jun 9 23:35 video0
crw------- 1 root root 81, 1 Jun 9 23:35 video1

となっていて、

オープンするには

  • root ユーザ
  • video グループに所属

である必要があるらしいのです。

だた、どーしてもGstreamerでは表示できないのですよ
(以下に続く)

WIndows10のWSL Ubuntu-20.04に仮想の/dev/video*を作って、Webカメラ C270n をGstreamer で表示できるようにするまでの軌跡

 

2023,江端さんの技術メモ

WSLでUSBカメラをどうにかしたくて、すったもんだしていました。

で、管理者モードでPowershellを立ち上げて

PS C:\WINDOWS\system32> wsl -l -v
NAME STATE VERSION
* docker-desktop-data Stopped 2
Ubuntu-20.04 Running 1
docker-desktop Stopped 2

の部分の1を2にしなければならないことが分かったので、

Windows10のWSLをWSL2に変換する手順

を参考にさせて貰って、

PS C:\WINDOWS\system32> wsl --set-version Ubuntu-20.04 2

をやりました、

ところが、数分どころか、いつまで経っても終わらないのでCrtl-Cで強制打ち切りをしたら、wslが全く動かなくなってしまいました。

いろいろやったのですが、最終的には、

起動しなくなったWSL2を復活させるまでにしたあれこれ

を参考にして、元に戻すことができました。

(大変失礼ながら、以下コピペをさせて頂いております。上記のページのリンクが切れると、私がパニックになりますので)

WSL2無効化→有効化

Ubuntuアンインストールでダメな場合(ダメでした)、WSL2を一回機能をオフにして再起動します。

「コントロールパネル -> プログラム -> Windowsの機能の有効化または無効化」を選択します。

「Linux用Windowsサブシステム」のチェックを外して再起動します。

で、チェックを外してから、なかなかシステムが終了を出してこないのですが、ここばガマンです。それでも10分はかからないと思います。

でもって次は、「Linux用Windowsサブシステム」のチェックを付けて再起動します。これも、いい感じでまたされますが、我慢します。

で、これらを終えて、やっと、コマンドプロンプトから、

$ wsl -d Ubuntu-20.04

と入力したのですが、それでも動きません。

管理者モードでPowershellを立ち上げて、

$ wsl --update

をして、別画面を経ち上げなおして、再度、

$ wsl -d Ubuntu-20.04

をしたところ、やっと、元の環境に戻りました(多分)。

「WSLでUSBカメラをどうにかする」をとっとと諦めていれば、こういう目に合わないのですが ―― エンジニアの性(さが)ですかねえ。

まあ、「別のマシンで同じ環境のシミュレータが動いている」という安心感があってのことでしたが。

で、まあ、ここからまた挑戦するんですよ。性懲りもなく。

 

2023,江端さんの技術メモ

この週末2日間かけるつもりだった「カメラレディ」を、"grammarly"のおかげもありまして、1日で投稿し、学会へのレジストレーションを終えました。

―― どの評価を信じればいい?

週末エンジニアの、この貴重な一日を何に使うか ――

うん、これに使わせて頂こう、と決めました。

今回、以下のコラムを寄稿致しました。

で、読者の方(Sさん)から、以下のメールを頂きました。

江端智一 様

初めてメールさせていただきます。"S"と申します。
いつも記事・日記ともに楽しく拝見させていただいております。
今回:ChatGPTの記事で一点気になるところがあり、ご連絡させていただきました。

6ページ目以降、「ChatGPTの本体は、ニューラルネットワークです。」とまとめている点は少し実体と異なっている気がいたします。
GPT-3の主要な要素Transformerにおいては、ニューラルネットではなく、Attention機構がその主役です。
(2層のフィードフォワードのニューラルネットは使われていますが、CNNやRNNは使われていないのが特長とのことです。)

・参考① オミータ氏の記事
https://qiita.com/omiita/items/07e69aef6c156d23c538

・参考② 杉山聡氏 「分析モデル入門」
(執筆者の杉山聡氏がYoutubeでも解説しています
https://www.youtube.com/watch?v=50XvMaWhiTY&t=498s)

特に②の受け売りですと、Attention機構は内積を用いた類似度計算が肝とのことです。
ですので、「ChatGPTの本体は、内積を用いた類似度計算です。」という方がしっくりきます。

私自身ソフトウェア(組込)系ではありますがデータサイエンス・機械学習等に詳しいわけではないので、
参考情報として受け取っていただければと思います。

以上、ご確認いただけましたら幸いです。

いつもながら、大変ありがたいことです。私の記事は読者の皆様によって支えられております。引き続き、よろしくお願い致します。

で、改めて確認してみましたが、ご指摘は正しいと確認いたしました。

ニューラルネットワーク(フィードフォワード型と、SoftMax Function)も使っていますが、どちらかというと、「ニューラルネットワークの学習で汗をかく」というよりは、「(文章コーパスのデータを使った?)統計処理&類似度の確率計算をする」という処理が、全体のほぼ9割くらい、という感じでした。

上記のコラムのp.7に記載した「対訳コーパスとEBMT/SMTの関係」の図のイメージに近い感じ、と思っています。

わざわざニューラルネットワークで非線形関係を学ばせまでもなく「Attention機構の内積を用いた類似度計算」で、バッチリ行けるぜ ―― という風に、(私は)理解しました。

うん、ニューラルネットワークなんぞ、使わずにすめばそれに越したことはありません(私は、第2次AIブームで、ニューラルネットワークで痛い思いをしています)。

ちなみに、私、杉山聡氏のYoutubeには、たびたびお世話になっております。今回も、紹介して頂いた映像で勉強致しました。

今回私が驚いたのは、このビデオクリップの最後の方に出てくる、Multi-Head Attention の concatです。このビデオではよく分からなかったのですが、ベクトルXに対して、回転変換(でいいんのかな?)する行列の内積を取る、というのは、まさに類似度計算です。

ただ、今、私が分かっていないのは、行列の回転角をどうやって決めているのだろう、ということです。これってGivenで与えられる値なのか、あるいは、フレーズ(から求められたベクトル)毎に、何かのアルゴルズムを使って回転角θを求めているのか ―― あるいは、私が、全く的外れなことを言っているのか ―― が、まだ分かっていません。

ただ、この技術は、様々な分野(ゲームなど)にも使われているとの話を鑑みれば、「ニューラルネットワーク学習の悪夢」なしに、過去の膨大な情報と行列式だけで、非線形の関連の出力を得られるということになります。

これはAI技術にとって、大きな福音です。アホみたいに膨大な学習プロセスなしに、非線形関係が求められるのであれば ―― 少なくとも、学習計算にかかるコンピュータの電気料金の節約の効果は計り知れません


この度メールでご指摘を頂いた、"S"さんに、最大級の感謝を申し上げます。
また、素晴しい解説記事を書かれているオミータさん、論文調査で困った時にいつでもYouTubeで助けて頂いている杉山聡さんに、感謝申し上げます。

今後も助けて頂く予定としております。
引き続きよろしくお願い申し上げます。

江端智一

2023,江端さんの技術メモ

『コーディングが嫌になったのなら、ドキュメントを書けばいいのに』という、某国の最後の王妃となった、マリーなんとかさんの声が脳内から聞こえてくるようです。

提出するペーパーに数式を記載しなければならないのですが、

とまあ、コピペが美しくなくて、レビューアの心象悪くしそうです。

今さらLatexで数式を記載するのは、冗談ではありませんし、Wordの数式記載の手間は、1行記載するだけで1日の時間をもっていかれそうです。

私の汚ない数式を整形してくれるツールはないかな、と、10秒くらい探したら、見つかりました。

iPadに、neboといアプリをインストールして対応しました。

(Step 1)新規をApple Penでクリック

(Step 2)新規"文章"をクリック

(Step 3) "+" → "数式"をクリック

(Step 4) Apple Penを使って、数式を手書きする

で、数式を記載した領域をタップすると、

となる(魔法のようだ)。

(Step 5) エクスポートでword形式にして、好きなところに飛ばす(私の場合LINEの"自分メモ"に飛ばしました)

転送されたwordファイルを開いたら、こんな感じになっていました。

必要な数式をコピペして完了 (青色の数式を、黒に変える)


感想:中古で購入したApple Penが、ようやく役に立った。

2023,江端さんの技術メモ

最近、映像制御の仕事をすることになりました。

WSLを使って、作業効率をはかりたいと考えていますが、WSLは基本的にコマンドインターフェースなので、表示システムを作らなければなりません。

「Windows11にWSL2+Ubuntu20.04をインストールする」を試してみて、Golangをインストールしてみた件

すったもんだしているのですが、とりあえず、Windows10の方にX-Windowの方に、X serverを立てて表示ができたので、メモを残しておきます。

(というか、『Windows10上で、X-Windowsのサーバ動かす』という発想ができなかったので、

(gedit:5386): Gtk-WARNING **: cannot open display やらで、悩んでいました。

基本は、

Windows10のWSLでX11アプリケーションを実行してみた

の通りに実施したら動きました(実は、ここまで、手当たりしだい "sudo apt-get install" を乱発して

WSLの方から、

>export DISPLAY=:0

>gedit dummy.txt

 

と投入したら、X-windowsのエディタが立ち上がってきましたが、

など、たくさん問題が出ているようなので、対応を続けます(続く)

ところで、

WSLでGUIアプリを実行する

などで、自分の「上手くできなかったことを、きちんと書き残している方」のメモは本当に素晴しい。こういうメモは、普通の成功パターンしか記載していないメモの何十倍も役に立つのです。

で、まあ、それはさておき。


本命はこちら ――

GStreamer

です。

私、映像の伝送の研究は色々やってきたのですが(10~15年前)、映像そのものの研究は初めてなので、まずは、ローカルのパソコンで色々遊ぶ・・・もとい、調査することにしました。

で、今の私、GStreamerが何なのかも分かっていないのですが、「これを使え」と指示されているので、「これに突っ込んでいく」だけです。

『ほとんどの入門書は、入門者にとっては、ただの"ゴミ"』

マルチメディアフレームワークGStreamer ~ 入門編

を参考にさせて頂き、

$ export DISPLAY=:0

$ gst-launch-1.0 videotestsrc ! autovideosink

で、これが出てきました。

おお! やった!

WSLの方はこんな感じです。

$ gst-launch-1.0 filesrc location=./out.h264 ! avdev_h264 ! autovideosink

も、ちゃんと表示されるようです。映像の違いは分かりませんが。

カーネルコンパイルしたら表示されなくなりました(それが理由かは分かりません)。

$ gst-launch-1.0 -v videotestsrc ! x264enc ! avdec_h264 ! videoconvert ! autovideosink

で、表示できました。

(とりあえず、error: XDG_RUNTIME_DIR not set in the environment. だけでも潰しておこう)

ともあれ、最初の一歩は確保しました。

エラーコメントの表示対応のため、以下の設定をしておきました。

$ cd ~
$ vi .bash_profile

以下の2行を追加(正直、上の設定の意味は分からんが、とりあえずエラーは消える)。

export XDG_RUNTIME_DIR=/tmp/runtime-futa
export DISPLAY=:0


GStreamerによるレートコントロールについて調べています。

ラズパイにWEBカメラを接続してGStreamerを使った際に小一時間ハマった話

こちらに、

そして、例えば、任意のサイズやフレームレートでキャプチャを行いたい場合は、video/x-raw,width=1280,height=720,framerate=30/1 のような指定を行います。

というような記載がありました。

$ gst-launch-1.0 videotestsrc ! autovideosink

をちょっと変更して試してみました。

$ gst-launch-1.0 videotestsrc ! videoconvert ! video/x-raw,width=1280,height=720,framerate=30/1 ! autovideosink

画面がでっかくなって表示されました。

$ gst-launch-1.0 videotestsrc ! videoconvert ! video/x-raw,width=1280,height=720,framerate=1/1 ! autovideosink

これで、1fpsの表示になりました。

で、実際に映像ファイル(start_up.mp4)を持ち込んで表示してみました。

$gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=30/1 ! autovideosink

これを、1fpsの表示に変えてみます。

$gst-launch-1.0 filesrc location=start_up.mp4 ! decodebin ! videorate ! video/x-raw,framerate=1/1 ! autovideosink

これを、1fpsのmp4ファイルとして保存してみます。

■1ftp映像に変換したもの "1ftp.mp4"$ gst-launch-1.0 -e filesrc location=start_up.mp4 ! decodebin ! videoconvert ! videoscale ! videorate ! "video/x-raw,framerate=1/1" ! videoconvert ! x264enc bitrate=2000 ! mp4mux ! filesink location=1ftp.mp4

上記のコマンドでは、GStreamerのgst-launch-1.0ユーティリティを使用しています。filesrcエレメントを使用して入力ファイルを読み込み、decodebinエレメントを使用してデコードします。その後、videoconvertvideoscaleエレメントを使用して動画の形式を変換し、videorateエレメントを使用してフレームレートを変更します。最後に、x264encエレメントを使用してビットレートを設定し、mp4muxエレメントを使用して新しいmp4ファイルに変換します。


ひき続き、SRTの通信実験を行ってみます。

(2)映像転送プロトコルは、現在、SRTが有力候補

     (a)タイムスタンプが付与した再送機能付きUDP(と理解)

     (b)Gstreamerに標準装備されている(らしい)

で、高信頼の映像通信を実現するプロトコルのようです。

GStreamer で SRT を使用する その1

の内容をマネします。

私の場合、新規の設定をしないでも以下のコマンドが動きましたので、どっかで設定を終えてしまったのだと思います。

$ gst-launch-1.0 videotestsrc ! videoconvert ! x264enc tune=zerolatency key-int-max=30 ! mpegtsmux ! srtserversink uri="srt://:12345" latency=500

で、SRT の配信には、srtserversink を使用しているようです。

で、受信側は、VLCメディアプレーヤを用います。

※WSL2にしてカーネルコンパイルした後、

C:\Users\ebata>ipconfig

(中略)

Windows IP 構成

イーサネット アダプター vEthernet (WSL):

接続固有の DNS サフィックス . . . . .:
リンクローカル IPv6 アドレス. . . . .: fe80::c317:ce40:f52f:1a41%40
IPv4 アドレス . . . . . . . . . . . .: 172.22.144.1
サブネット マスク . . . . . . . . . .: 255.255.240.0
デフォルト ゲートウェイ . . . . . . .:

しか使えなくなってしまったので、上記のVLCのアドレスは、

とする必要が生じました。

これで、「再生(P)ボタン」を押すと、テスト映像が表示されます。


次にWebRTCの実験を行います。

ここでは、

Go + GStreamer でお手軽 WebRTC 体験

を試させて頂きました。

GOのソースは一つだけだったので、WSL環境から行ってみました(最初、エラーの嵐だったのですが、よく考えれば、私はWSLの方にGStremaerの環境を立てていたので当然でした。

結構エラーが出てきましたので、色々対応をしていました。

sudo apt-get install libgstreamer-plugins-base1.0-dev

で、一部解決したのですが、以下のエラーが取れません。
# pkg-config --cflags -- gstreamer-1.0 gstreamer-base-1.0 gstreamer-app-1.0 gstreamer-plugins-base-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 gstreamer-plugins-bad-1.0 Package gstreamer-plugins-bad-1.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gstreamer-plugins-bad-1.0.pc' to the PKG_CONFIG_PATH environment variable
No package 'gstreamer-plugins-bad-1.0' found pkg-config: exit status 1

で、

https://github.com/notedit/gstreamer-go

に訪問してみたところ、

$ sudo apt-get install libgstreamer-plugins-bad1.0-dev

が、当たりだったようです。

で、後は上記のページの記載通りにGOプログラムを動かしたのですが、

2023/05/25 17:57:31 peer state change: failed

が登場してきて、変だなーと思ていたのですが、実はこれ成功しています。

このメッセージの上に、Goの出力の「長い文字列」が主力されていました。

これを入力して、「start session」ボタンを押下したら、以下の画面がブラウザに表示されました。

では、動作も確認できたので、ここからコードの勉強に入りましょう。


WebRTC を今から学ぶ人に向けて

の中にある、

WebRTC コトハジメ

が分かりやすい。

好奇心旺盛な人のためのWebRTC

も良い。

私はGolang使いなので、https://github.com/pion/webrtcを使いこなしたいが、膨大で手が出ない状況。今、とっかかりを探している。

とりあえず、wsl -d Ubuntu-20.04で、
ebata@DESKTOP-P6KREM0:/mnt/c/users/ebata/から、
get clone https://github.com/pion/webrtc で、インストール。

https://github.com/pion/webrtc/blob/master/examples/README.md

から、

$ cd webrtc
$ cd examples
$ go run examples.go --address :8080

で、ブラウザ http://localhost:8080で以下の画面が出てくる。

で、

のところで、"Run JavaScript"を押して、暫く(2~3分)待っていると、

という漢字で文字列が出てくるので、これを、上記のGo + GStreamer でお手軽 WebRTC 体験 のプログラムに放り込んで、同じように得られた文字列を放り込むと、

てな感じで映像が表示される。


$git clone https://github.com/pion/rtwatch.git

に挑戦。

https://github.com/pion/rtwatch の内容通りに設定するが、実行のところだけ少し違った

ebata@DESKTOP-P6KREM0:/mnt/c/users/ebata/rtwatch$ go run main.go -container-path=start_up.mp4
Video file 'start_up.mp4' is now available on ':8080', have fun!

これで、複数の、http://localhost:8080/ から同期した映像が配信されるようすが分かる。

2023,江端さんの技術メモ

FASTAPIを使ってPOSTでファイルを送り込む方法

 main.py

import uvicorn
from fastapi import FastAPI, File, UploadFile

import shutil
import os

app = FastAPI()

@app.post("/files/")
async def file(file: bytes = File(...)):
    content = file.decode('utf-8')
    formatfile = content.split('\n')
    return {'filedetail': formatfile}

@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    if file:
        filename = file.filename
        fileobj = file.file
        #UPLOAD_DIR = os.getcwd() 
        #print(UPLOAD_DIR)
        #upload_dir = open(os.path.join(UPLOAD_DIR, filename),'wb+')
        upload_dir = open(os.path.join("C:\\Users\\ebata\\fastapi6\\", filename),'wb+')
        shutil.copyfileobj(fileobj, upload_dir)
        upload_dir.close()
        return {"アップロードファイル名": filename}
    return {"Error": "アップロードファイルが見つかりません。"}



'''
@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    return {'filename': file.filename}
'''

で、

> uvicorn main:app --reload

でAPIサーバを起動する。

request.py

import requests
import json

# curl -X POST http://127.0.0.1:8000/uploadfile/ -H 'accept: application/json' -H 'Content-Type: multipart/form-data' -F file=@dummy.txt;type=text/plain と同じ機能を実現
# C:\Users\ebata>curl -X POST http://127.0.0.1:8000/uploadfile/  -F file=@dummy.txt;type=text/plain とすれば、エラーメッセージは出てこない

url = 'http://localhost:8000/uploadfile/'

# headers = {'Accept': 'application/json', 'Content-Type': 'application/json'} //失敗
# headers = {'Accept': 'application/json', 'Content-Type': 'text/html'} # 失敗
headers = {'Accept': 'application/json'} # 成功

# file_payload = {'file=@dummy.txt;type=text/plain'} # 失敗
file_payload = {'file':open('data/dummy1.csv','rb')} # 成功  ファイルはdataというフォルダを掘って、dummy1.csv という名前のファイルを放り込んでおく

print("headers:",headers)
print("payload:",file_payload)

# r = requests.post('http://localhost:8000/uploadfile/', headers=headers,files=file_payload) # 成功
r = requests.post(url, headers=headers,files=file_payload) # 成功

print("--->1:", r.url)
print("--->2:",r.status_code)
print("--->3:",r.text)
print("--->4:",r.json())

>python requests.py

でクライアント起動。

以上

2023,江端さんの技術メモ

> uvicorn main:app --reload

main.py

import uvicorn
from fastapi import FastAPI, File, UploadFile

import shutil
import os

app = FastAPI()

@app.post("/files/")
async def file(file: bytes = File(...)):
    content = file.decode('utf-8')
    formatfile = content.split('\n')
    return {'filedetail': formatfile}

@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    if file:
        filename = file.filename
        fileobj = file.file
        #UPLOAD_DIR = os.getcwd() 
        #print(UPLOAD_DIR)
        #upload_dir = open(os.path.join(UPLOAD_DIR, filename),'wb+')
        upload_dir = open(os.path.join("C:\\Users\\ebata\\fastapi6\\", filename),'wb+')
        shutil.copyfileobj(fileobj, upload_dir)
        upload_dir.close()
        return {"アップロードファイル名": filename}
    return {"Error": "アップロードファイルが見つかりません。"}



'''
@app.post("/uploadfile/")
async def upload_file(file: UploadFile = File(...)):
    return {'filename': file.filename}
'''

クライアントは、こうなる。

前提は、C:\Users\ebata に dummy.txtがあること。
そして上記のmain.pyは、C:\Users\ebata\fastapi6にあること(まあ、そのへんは適当に変えて使って下さい)

 

C:\Users\ebata>curl -X POST http://127.0.0.1:8000/uploadfile/ -H 'accept: application/json' -H 'Content-Type: multipart/form-data' -F file=@dummy.txt;type=text/plain

クライアントプログラムは作成中

2023,江端さんの技術メモ

https://teratail.com/questions/8xzab7sat8gujj#reply-3jfh5txotuqxqb

の質問サイトに投げたものですが、ローカルでも作っておきます。

実現したいこと

TLS対応にしているGo言語のサーバを、Dockerコンテナの中から使えるようにしたい

前提

GO言語を使ってサーバを作っています。これらのサーバをDockerコンテナに格納して、運用しやすくしたいと考えております。

発生している問題・エラーメッセージ

Dockerコンテナに格納すると、https(×http)通信が使えません。

cert.pem、key.pemを使わない場合、http://127.0.0.1:18888で、ブラウザに"hello"メッセージがされますが、cert.pem、key.pemを使ってhttps://127.0.0.1:18888とした場合、「このサイトにアクセスできません」と表示されます。

該当のソースコード

GO言語

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"net/http/httputil"
	"os"
)

var url_host string

func handler(w http.ResponseWriter, r *http.Request) {
	dump, err := httputil.DumpRequest(r, true)
	if err != nil {
		http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
		return
	}
	fmt.Println(string(dump))
	fmt.Fprintf(w, "<html><body>hello</body></html>\n")
}

var addr = flag.String("addr", "127.0.0.1:18888", "http service address") // テスト

func main() {
	http.HandleFunc("/", handler)
	fmt.Println("url_host:", url_host)

	log.Println("start http listening :18888")

	var httpErr error
	if _, err := os.Stat("./cert.pem"); err == nil {
		if httpErr = http.ListenAndServeTLS(*addr, "./cert.pem", "./key.pem", nil); httpErr != nil {
			log.Fatal("No pem file with https error: ", httpErr.Error())
		}
	}
}

ちなみに、cert.pemと、key.pemは、"127.0.0.1","localhost"で通るように作ってあります。

ローカルネットワークにおける「オレオレ証明書」の作り方 "http: TLS handshake error from 192.168.0.22:59914: remote error: tls: unknown certificate"のエラーを、ようやく消せました

Dockerfile
#FROM golang:apline
FROM golang:1.16.3-alpine
WORKDIR /go
ADD . /go
CMD ["go", "run", "main.go"]

docker-compose.yml

version: '3'
services:
  app:
    build: .
    ports:
      - "18888:18888" # "ホストのポート:コンテナのポート"

試したこと

上記のmain.go のfunc main()を以下のようにしている場合は,http(×https)で通信できます。

func main() {
    var httpServer http.Server
    http.HandleFunc("/", handler)
    log.Println("start http listening :18888")
    httpServer.Addr = ":18888"
    log.Println(httpServer.ListenAndServe())
}

補足情報(FW/ツールのバージョンなど)

■Windows10上のDocker for Windowsを使用しています。
■Dockerコンテナを使わないで、 windowsのコマンドプロンプトから起動する場合は、"https://127.0.0.1:18888"は問題なく起動します。

で、頂いたご回答が以下の通り。

Dockerfile

#FROM golang:apline
FROM golang:1.16.3-alpine
WORKDIR /app
ADD . /app
CMD ["go", "run", "main.go", "-addr", ":18888"]

と最後の一行を、CMD ["go", "run", "main.go", "-addr", ":18888"]

とするだけでした。

で、以外な盲点が、

ブラウザのキャッシュを消去しないと、変更がブラウザに反映されない

だったりします。(何度も経験しているのに、これをよく忘れるんだよなぁ)

感想

散々、色々試したあげく、最初に頂いた、Dockerfileの内容に変更することで、無事問題を解決することができました。現在、Dockerの中で立ち上げたgoのサーバに対して、https://localhost:18888で表示されることを確認しました。

今後のサーバ立ち上げに関して、かなり有益な知見となりました(実サーバ運用では、ご指摘の内容を反映してリスクを回避したいと思います)。 この度は、誠にありがとうございました。

以上

2023,江端さんの技術メモ

cert.pem やら key.pem に、localhost や 127.0.0.1を含めて作っていなかったから。以上

C:\Users\ebata\kitaya>curl https://localhost:8080
curl: (35) schannel: next InitializeSecurityContext failed: Unknown error (0x80092012) - 失効の関数は証明書の失効を確認できませんでした。

cert.pem = fullchain.pem  key.pem = privkey.pem ということで良いのだろう

ローカルネットワークにおける「オレオレ証明書」の作り方 "http: TLS handshake error from 192.168.0.22:59914: remote error: tls: unknown certificate"のエラーを、ようやく消せました