2024,江端さんの技術メモ

まず、ネットワークをキャプチャして、停止する

パケットの一つを選んで、「・・・としてデコード」を選択

「現在」のところをクリック

プロトコルとして「RTP」を選ぶ

XXXXX

「電話(y)」のメニューを選択

「RTP」→「RTPストリーム」を選択

ストリーム一式が表示される

現在、「wiresharkでRTPのパケットロスを検知する方法」には至っていません。

2024,江端さんの技術メモ

ラズパイに、ラズパイにWebカメラ C270n HD 720Pを接続して、RTSPカメラを作ろうとしました。

以下のソースコードをコンパイルしました。

/*
  dummy_usbcam_0.2.c
  
  ■環境設定を行います。
  sudo apt-get update
  sudo apt-get install libgstrtspserver-1.0-dev

  export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig:$PKG_CONFIG_PATH

 
  ■プログラムをコンパイルして実行するには、以下のコマンドを使用します:
  gcc -o dummy_usbcam_0.2 dummy_usbcam_0.2.c `pkg-config --cflags --libs gstreamer-1.0 gstreamer-rtsp-server-1.0`

  ./dummy_usbcam_0.2 -r rtsp://127.0.0.1:8554/custom -d /dev/video0

  ■また、ヘルプメッセージを表示するには、以下のコマンドを使用します:

  ./dummy_usbcam_0.2 -h

  ■稼動確認環境
   (車上) 192.168.101.30
   cam@cam-desktop:~/cpp/src$ ./dummy_usbcam_0.2
   cam@cam-desktop:~/cpp/src$ ./abc_vtp_0.1 -i 192.168.101.10 -p 38089 -r rtsp://127.0.0.1:8554/test

   (地上) 192.168.101.10
pt@pt-desktop:~/go/src$ more srt_rtsp_server_38089.sh 

#!/bin/bash
gst-launch-1.0 srtsrc uri=srt://:38089 keep-listening=true ! decodebin ! autovid
eosink

  
*/

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>
#include <stdio.h>
#include <string.h>

void print_usage(const char *prog_name) {
    g_print("Usage: %s -r [RTSP_URL] -d [DEVICE]\n", prog_name);
    g_print("Default RTSP_URL: rtsp://127.0.0.1:8554/test\n");
    g_print("Default DEVICE: /dev/video0\n");
    g_print("Example: %s -r rtsp://127.0.0.1:8554/test -d /dev/video0\n", prog_name);
}

int main(int argc, char *argv[]) {
    GMainLoop *loop;
    GstRTSPServer *server;
    GstRTSPMountPoints *mounts;
    GstRTSPMediaFactory *factory;
    const char *default_url = "rtsp://127.0.0.1:8554/test";
    const char *default_device = "/dev/video0";
    const char *rtsp_url = default_url;
    const char *device = default_device;
    char path[256] = "/test";
    char service[6] = "8554";  // ポート番号のデフォルト値

    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0) {
            print_usage(argv[0]);
            return 0;
        } else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
            rtsp_url = argv[++i];
            // RTSP URLのポート番号とパス部分を抽出
            const char *url_port = strchr(rtsp_url + strlen("rtsp://"), ':');
            if (url_port != NULL) {
                url_port++;
                const char *url_path = strchr(url_port, '/');
                if (url_path != NULL) {
                    strncpy(path, url_path, sizeof(path) - 1);
                    path[sizeof(path) - 1] = '\0';  // Null terminatorを追加

                    int port_length = url_path - url_port;
                    if (port_length < sizeof(service)) {
                        strncpy(service, url_port, port_length);
                        service[port_length] = '\0';  // Null terminatorを追加
                    }
                }
            }
        } else if (strcmp(argv[i], "-d") == 0 && i + 1 < argc) {
            device = argv[++i];
        }
    }

    gst_init(&argc, &argv);

    loop = g_main_loop_new(NULL, FALSE);

    server = gst_rtsp_server_new();
    gst_rtsp_server_set_service(server, service);

    mounts = gst_rtsp_server_get_mount_points(server);

    factory = gst_rtsp_media_factory_new();
    char launch_string[512];
    snprintf(launch_string, sizeof(launch_string),
             "( v4l2src device=%s ! videoconvert ! x264enc speed-preset=ultrafast tune=zerolatency ! rtph264pay pt=96 name=pay0 )",
             device);
    gst_rtsp_media_factory_set_launch(factory, launch_string);

    gst_rtsp_mount_points_add_factory(mounts, path, factory);

    g_object_unref(mounts);

    gst_rtsp_server_attach(server, NULL);

    g_print("Stream ready at %s with device %s\n", rtsp_url, device);
    g_main_loop_run(loop);

    return 0;
}

で、

$ ./dummy_usbcam_0.2

をして、

$ gst-launch-1.0 rtspsrc location=rtsp://127.0.0.1:8554/test ! decodebin ! autovideosink

で、映像を受信しようとしたのですが、動きませんでした。

-----

そもそも、"/dev/video0"が見つかりません。

Raspberry PiがWebカメラを認識できるように、必要なパッケージをインストールします。

$ sudo apt-get update
$ sudo apt-get install v4l-utils

v4l-utilsは、Video4Linux(V4L)デバイスを操作するためのツールセットです。

次に、WebカメラがRaspberry Piに認識されているかを確認します。以下のコマンドを実行して、デバイスが認識されているか確認します。

$ lsusb

このコマンドは、接続されているUSBデバイスのリストを表示します。

Bus 001 Device 004: ID 046d:0825 Logitech, Inc. Webcam C270

が表示されれば、成功です。

で、あとはGStreamerでデバイスが動くことを確認しました。

$ gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! autovideosink

後は念の為、GStreamerのインストールができているかを確認して下さい。

$ sudo apt-get update
$ sudo apt-get install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav

で、

$ gst-launch-1.0 v4l2src device=/dev/video0 ! videoconvert ! autovideosink

で、ローカルにカメラ映像が表示されれば成功です。

で、この後、プログラムを起動して、リモートで、

$ gst-launch-1.0 rtspsrc location=rtsp://192.168.0.200:8554/test ! decodebin ! autovideosink

(192.168.0.200はラズパイのIPアドレスです)

で、RTSPプロトコルで転送された映像が表示されるようになりました。

以上

 

2024,江端さんの技術メモ

.emacs はこんなかんじ

;; 英字フォントを設定
(set-face-attribute 'default nil
:family "Ubuntu Mono"
:height 120
:weight 'normal
:width 'normal)

;; 日本語フォントを設定
(set-fontset-font t 'japanese-jisx0208
		  (font-spec :family "Noto Sans CJK JP" :size 14))


(require 'skk-autoloads)
(setq skk-user-directory "~/.emacs.d/skk")
;(setq skk-large-jisyo "/usr/share/skk/SKK-JISYO.L")
(setq skk-large-jisyo "~/.emacs.d/skk/SKK-JISYO.L")
(setq skk-server-host "localhost")
(setq skk-server-portnum 1178)
(global-set-key (kbd "C-x C-j") 'skk-mode)

;; ネイティブコンパイルの警告を無効にする
(setq native-comp-async-report-warnings-errors nil)

で、あとはこんなことをやっておく

$ wget https://skk-dev.github.io/dict/SKK-JISYO.L.gz
$ gunzip SKK-JISYO.L.gz
$ mkdir -p ~/.emacs.d/skk
$ mv SKK-JISYO.L ~/.emacs.d/skk/

$ sudo apt update
$ sudo apt install ddskk

とりあえず「動けばいい」の方向で。

2024,江端さんの技術メモ

C言語のプログラムで、コマンドパラメタを入力する部分をつくっていたのですが、ファイルを作ってほしくないケースが出てきました。

// 引数からIPアドレス、ポート、RTSP URL、ファイル名を取得
    char *srt_ip = DEFAULT_IP;
    int srt_port = DEFAULT_PORT;
    char *rtsp = DEFAULT_RTSP;
    char *filename = DEFAULT_FILENAME;
    int udp_port = DEFAULT_UDP_PORT;

    for (int i = 1; i < argc; i++) {
      if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
        srt_ip = argv[i + 1];
        i++;
      } else if (strcmp(argv[i], "-p") == 0 && i + 1 < argc) {
        srt_port = atoi(argv[i + 1]);
        i++;
      } else if (strcmp(argv[i], "-r") == 0 && i + 1 < argc) {
        rtsp = argv[i + 1];
        i++;
      } else if (strcmp(argv[i], "-f") == 0 && i + 1 < argc) {
        filename = argv[i + 1];
        i++;
      } else if (strcmp(argv[i], "-u") == 0 && i + 1 < argc) {  // UDPポート番号の引数を追加
        udp_port = atoi(argv[i + 1]);
        i++;
      } else {
        printf("Usage: %s [-i ip_address] [-p port] [-r rtsp_url] [-f filename] [-u udp_port]\n", argv[0]);
	    printf("./abc_vtp_0.3 -i 192.168.101.10 -p 38090 -r rtsp://cam:Cam12345@192.168.0.11/Src/MediaInput/stream_1 -f 2jcie/data_test2.csv -u 12346 \n");
    	    printf("-f /dev/null とすることでSRTメトリックス情報は廃棄されます \n");
	    printf("-u 0 とすることで制御用スレッドは起動しなくなります\n ");


        return 1;
      }
    }
    
    printf("IP: %s\nPort: %d\nRTSP: %s\nFilename: %s\nUDP Port: %d\n", srt_ip, srt_port, rtsp, filename, udp_port);

しかし上記のプログラムでは、ファイル名を無視すると、デフォルトのファイル名を選んでしまいます。そんでもって、プログラムの改造もしたくありませんでした。

今更ながらなのですが、ファイル名を

/dev/null

とすると、ファイルを作らずにデータを捨ててくれるようです。
(コマンドプロンプトでしか使えないと思っていた)

いや、本当に助かった。変なコード追加しなくて済んだし。

それ以上に、この程度のことを、今の今まで、私が知らなかったことが驚きです。

まあ、私の力量などこの程度です(乾いた笑い)。

 

 

2024,江端さんの技術メモ

ubuntu 22.04をホストOSとして、ubuntu24.04 をゲストOSとした、そのゲストosの環境で、fastapiをインストールしようとしましたが、上手く動きませんでした。

pythonでFastAPIを試す

cam@cam-desktop:/$ pip3 install fastapi uvicorn error: externally-managed-environment といわれました。
「システム全体のPython環境にパッケージをインストールする必要がある場合は、--break-system-packagesオプションを使用して強制的にインストールすることも可能です」
と言われました。
「システム全体」でかまわなかったので、強行しました。
cam@cam-desktop:~/testapi$ pip install fastapi uvicorn --break-system-packages
$make testapi
$cd testapi
$touch main.py

以下のサンプルコードを main.py に記述します。

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
    return {"Hello": "World"}
で、
$ uvicorn main:app --host 0.0.0.0 --port 8000
http://localhost:8000 で稼働確認できましたので、とりあえずここからです。
cam@cam-desktop:~/fastapi6d$ pip3 install request --break-system-packages
で、(私の場合)ようやく起動しました。

2024,江端さんの技術メモ

GISでシミュレーションを行う上で、鈴木紀明先生のこの方法を使い倒させていただいております。

先生には大変申し訳ないのですが、もし、このリンクが消えたら私にとって大打撃なので、先生に無許諾で切り取り&貼り付けをさせて頂いております(御叱り頂ければ、このページを即時抹消致します)。

2024,江端さんの技術メモ

key-word ubuntu emacs 漢字 汚い

.emacsまたはinit.elファイルに次のコードを追加します。

;; 英字フォントを設定
(set-face-attribute 'default nil
:family "Ubuntu Mono"
:height 120
:weight 'normal
:width 'normal)

;; 日本語フォントを設定
(set-fontset-font t 'japanese-jisx0208
(font-spec :family "Noto Sans CJK JP" :size 14))

 

2024,江端さんの技術メモ

$ sudo mkdir -p /mnt/smb_mount

$ sudo mount -t cifs -o username=guest, password=, vers=3.0 //10.42.0.1/usb_mount /mnt/smb_mount

で、できた。

cifsがなければ、インストールしろと言われるだろうから、素直に従うこと。

ーーーー

NIC透過環境のdockerのゲストOSでは、
”Unable to apply new capability set."といわれてしまいました

(まあ、そんなに簡単にいくとはおもっていませんでしたが)

 

 

2024,江端さんの技術メモ

UDPは一斉送信できるのは知っていましたが、いままで一度も使ったことがありませんでした。

で、今回試してみたら、メチャクチャ便利だなぁ、と実感しましたので、自分の為にコードを残しておきます。

受信側の「SO_REUSEADDRオプションを設定」がキモです。"bind: Address already in use"の呪いを受けなくてもすみます。

udp_multicast_send に対して、複数個のudp_multicast_recv でメッセージ受信できます。

(送信側) udp_multicast_send.c

#include <stdio.h>
/*
gcc -o udp_multicast_send  udp_multicast_send.c
*/

#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MULTICAST_GROUP "239.0.0.1"
#define MULTICAST_PORT 12345

void receive_process_count() {
    int sock;
    struct sockaddr_in addr;
    struct ip_mreq mreq;
    char message[256];

    // ソケットの作成
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        exit(1);
    }

    // 受信するアドレスとポートを設定
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(MULTICAST_PORT);

    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        perror("bind");
        exit(1);
    }

    // マルチキャストグループに参加
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        perror("setsockopt");
        exit(1);
    }

    // メッセージの受信
    while (1) {
        int nbytes = recv(sock, message, sizeof(message), 0);
        if (nbytes < 0) {
            perror("recv");
            exit(1);
        }

        message[nbytes] = '\0';
        printf("Received process count: %s\n", message);
    }
}

int main() {
    printf("abc_vtp_0.2 process started. Waiting for process count...\n");
    receive_process_count();
    return 0;
}

(受信側) udp_multicast_recv.c

/* gcc -o udp_multicast_recv udp_multicast_recv.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define MULTICAST_GROUP "239.0.0.1"
#define MULTICAST_PORT 12345

void receive_process_count() {
    int sock;
    struct sockaddr_in addr;
    struct ip_mreq mreq;
    char message[256];

    // ソケットの作成
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        perror("socket");
        exit(1);
    }

    // SO_REUSEADDRオプションを設定
    int reuse = 1;
    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
        perror("Setting SO_REUSEADDR error");
        close(sock);
        exit(1);
    }

    // 受信するアドレスとポートを設定
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(MULTICAST_PORT);

    if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        perror("bind");
        exit(1);
    }

    // マルチキャストグループに参加
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
    if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
        perror("setsockopt");
        exit(1);
    }

    // メッセージの受信
    while (1) {
        int nbytes = recv(sock, message, sizeof(message), 0);
        if (nbytes < 0) {
            perror("recv");
            exit(1);
        }

        message[nbytes] = '\0';
        printf("Received process count: %s\n", message);
    }
}

int main() {
    printf("abc_vtp_0.2 process started. Waiting for process count...\n");
    receive_process_count();
    return 0;
}

2024,江端さんの忘備録

私は、大学のころ山岳サークルに入っていましたが、1年目で早々に退会しました。

I was in a college mountain club but left early after my first year.

理由は色々あったのですが、登山が本当に好きであれば、止めなかったとは思うので、私はそんなに好きではなかったのでしょう。

There were many reasons, but I don't think I would have stopped if I liked climbing, so I guess I didn't like it that much.

それ以上に、登山というのは本当に苦しかった。普通に登るだけでも辛いのに、そこにあの荷物です。

But more than that, climbing the mountain was a real pain. It was usually hard enough to climb, but then there was all that luggage.

荷物が重すぎて(20kgくらい)、正しい手順を正確に行わないと、立ち上がることすらできない。

The load was so heavy (about 20 kg) that I could not stand up if I didn't strictly follow the correct procedure.

ようやく立ち上がって、5歩進めば『もう嫌』と思えるようなものが、楽しいわけがない。

It's no fun to finally get up, take five steps forward, and think, 'I don't want to do this anymore.

あと、絶望的な「非日常感」ですね。「ここで滑落すれば死ぬ」は当然として、「ここで骨を折るだけで死ぬ」「ここで腹痛おこせば死ぬ」というのは、日常ではありえない状況です。

Another thing is the hopeless sense of the extraordinary. It is natural that “if you slip and fall here, you will die,” but “if you just break a bone here, you will die,” or “if you have a stomachache here, you will die” are situations that would not be possible in everyday life.

山には楽しいこともあったと思うのですが ―― けど、それ以上に、私にとって、山は辛く、怖いものだったのです。

I think there were fun things about the mountains -- but more than that, for me, the mountains were rugged and scary.

今となっては良く分からいのですが、あの敗北感が、その後の、私の海外放浪に繋ったと思うこともあります。

I am unsure now, but I sometimes think that sense of defeat led to my subsequent wandering abroad.

まあ、全く無関係だった、という気もしますが。

Well, I also feel that it was utterly irrelevant.

-----

私は、登山に関するドキュメンタリーとか映画とかは、好きです。

I like documentaries and movies about mountaineering.

故井上靖先生の『氷壁』(1956年)や『岩壁』、ちょっと方向は違いますが、高村薫先生の『マークスの山』(1993年)も好きです。

I also like “Ice Wall” (1956) and “Rock Wall” by the late Yasushi Inoue and, although in a slightly different direction, “Mark's Mountain” (1993) by Kaoru Takamura.

新田次郎先生の『剱岳 点の記』(2009年)、古いもので言えば、『八甲田山』(1977年)など、小説も映画もなんども読み直しました。

I have reread many novels and movies, including Jiro Nitta's “Tsurugidake: Ten no Ki” (2009) and an older one, “Hakkoudasan” (1977).

『剱岳 点の記』は、Making of  の方も何度も見直しています。

I have reviewed the Making of Edition of “Tsurugidake: Ten no Ki” many times.

神々の山嶺(アニメの方)」は、もう3回以上も見ています。

I've watched “Ridge of the Gods (the animated one)” more than three times now.

(夢枕獏さんの小説を谷口ジローさんが漫画化し、『フランスのアニメ制作陣によって手がけられ』、フランスで最も有名なアニメ作品の一つである、というのも結構ビックリなのですが)

(It is also quite surprising that Taniguchi Jiro's manga adaptation of Yumemakura Baku's novel was “created by a French animation production team” and is one of the most famous French animation works.)

山を愛する人の狂気を描いた作品として、ズバ抜けています。

It is an outstanding work about the madness of a mountain lover.

私も『狂気だけが才能を越える』と主張してきた一人ですが、この山を愛する人の狂気には遠く及ばない気がします。

I have insisted that 'only Madne's surpasses talent,' but I feel that I am not far from the madness of this mountain lover.

課題で「主観的幸福(SWB)」を調べているのですが、なかなか興味深いです

登山家の死亡率は、恐しく高いです。

The mortality rate for climbers is frighteningly high.

ChatGPTに推定をお願いしたところ、『ベレストや他の難関山岳に挑戦する登山家の死亡率が約1~30%であるのに対し、一般人の年間死亡率は約0.1%以下』いうことでした。

ChatGPT estimated that “the annual mortality rate for the general public is about 0.1% or less, compared to about 1-30% for climbers who attempt Mount Everest and other rugged mountains.

登山家の死亡率はもっとも楽観的な数値で10倍、最悪値で300倍以上ということになります。

The mortality rate for climbers is ten times higher at the most optimistic value and more than 300 times higher at the worst value.

-----

そういえば、私、ティーンエイジャのころ、母親から『冬山をやったら、親子の縁を切る』とまで言われていましたが、母の心配はまったくの杞憂でした。

Come to think of it, when I was a teenager, my mother even told me that if I did winter mountaineering, she would cut me off from my parents, but her fears were completely unfounded.

―― あなたの息子は、冬山どころか、夏の北アルプスの1週間の縦走くらいで簡単に根を上げる、軟弱者でしたよ

Your son was feeble-minded and gave up quickly climbing just for a weeklong traverse of the Northern Alps in summer, let alone winter mountains.

と、空に向かって呟いています。

I muttered to the sky.

------

愛の中でも、ロジックを越えた狂気の(ように見える)愛は、代償が大きいです。

Among love, crazy (seemingly) love that transcends logic has a high price to pay.

「命を賭けた愛」と呼ぶに値するものは、『ここ』にしかない、という気すらします。

I even feel that the only thing worthy of being called “love at the risk of one's life” can be found in “Mountain Climbing.