Sony製カメラから無線で映像を取り出す

Sony製カメラから無線で映像を取り出す

Tags
Container
Kubernetes
Server
Streaming
Published
December 4, 2024
Author
DDlia
Description
Containerに詰めたこの想いを
こんにちは、音楽技術部技術班のDDliaです。
現在サークルではカメラを所有しており、カメラ映像をHDMI経由でキャプチャーボードでPCに取り込んで、それをNDIで各種PCに送信しています。これは最小限の遅延(600ミリ秒程度)で伝送できるのですが、いちいちPC起動してケーブルをいろいろ挿して… とやるのは面倒なのでどうにかカメラから直接無線で映像を飛ばせるようにします。

カメラについて

使っているカメラはSony製のHDR-CX680というものです。部室に2台あります。Wi-Fi接続をサポートしており、ライブストリーミングも可能ですが……
Ustream(現 IBM Video Streaming)への配信しか対応していない!!
で、そのIBM Video Streamingはいくらかかるかというと…
notion image
一番安いプランで ¥21900/月 ですね。富豪じゃないのでさすがに出せない。

探してみる

私は富豪ではないので、どうにかならないか探してみるとGitHubでissueが開かれていました。
Sony製カメラでuStream以外へストリーミングするにはどうすればよいのかが議論されています。目を通してみると、
  • DNSスプーフィングで api.ustream.tv をLAN内のサーバに向ける
  • カメラがhttp://api.ustream.tv/users/self/channels.json から接続先情報を読み取るので、そこに配信先アドレスを記述する
  • 配信サーバからカメラに対して定期的にpingを送る(AMFメッセージを偽装)
  • カメラに配信用資格情報を書き込む
あたりをやればよさそう。

テスト

RTMPサーバを建てる

まずは配信用のRTMPサーバを建てます。
docker-composeで簡単に立ち上げれるようにしているので、適当なLinuxサーバで立ち上げます。
$ sudo dnf update -y && sudo dnf install -y git podman podman-compose podman-docker $ git clone https://github.com/TechnoTUT/rtmp-live-server.git $ cd rtmp-live-server $ podman-compose up -d

DNSスプーフィングで api.ustream.tv をLAN内のサーバに向ける

テスト環境ではNEC IX3110というルータを使っていて、DNSレコードを登録できる機能があるのでそれを使います。
dns host api.ustream.tv <カメラから映像を受け取るサーバのIPアドレス>

カメラから映像を受け取るRTMPサーバを建てる

先ほどのRTMPサーバとは別にカメラから映像を受け取るRTMPサーバを建てます。その辺に転がっているLinuxマシンを拾ってきましょう。配信サーバからカメラに対して定期的にpingを送る(AMFメッセージを偽装)必要があるので、nginxを自分でビルドします。
nginx-rtmp-moduleは以下を使います。
(https://github.com/transelement/nginx-rtmp-module だと自分の環境下ではビルドエラーが出たので修正してあります。)
$ sudo apt update -y && sudo apt install -y nginx git wget tar build-essential libperl-dev libgeoip-dev libgd-dev libpcre3 libpcre3-dev libxml2 libxslt1-dev libxslt1.1 libxslt1-dev $ wget https://nginx.org/download/nginx-1.22.1.tar.gz && tar xzf nginx-1.22.1.tar.gz && rm -f nginx-1.22.1.tar.gz $ wget https://www.openssl.org/source/openssl-3.3.1.tar.gz && tar xzf openssl-3.3.1.tar.gz && rm -f openssl-3.3.1.tar.gz $ git clone https://github.com/TechnoTUT/nginx-rtmp-module.git $ cd nginx-1.22.1 $ ./configure --with-cc-opt='-g -O2 -ffile-prefix-map=/build/nginx-AoTv4W/nginx-1.22.1=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' \ --with-ld-opt='-Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=stderr \ --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \ --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-compat --with-debug --with-pcre-jit --with-http_ssl_module \ --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads \ --with-http_addition_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_mp4_module --with-http_random_index_module --with-http_secure_link_module \ --with-http_sub_module --with-mail_ssl_module --with-stream_ssl_module --with-stream_ssl_preread_module --with-stream_realip_module --with-http_geoip_module=dynamic --with-http_image_filter_module=dynamic \ --with-http_perl_module=dynamic --with-http_xslt_module=dynamic --with-mail=dynamic --with-stream=dynamic --with-stream_geoip_module=dynamic \ --add-dynamic-module=~/nginx-rtmp-module --with-openssl=~/openssl-3.3.1 $ make modules $ mkdir -p /usr/lib/nginx/modules && cp ~/nginx-1.22.1/objs/*.so /usr/lib/nginx/modules $ mkdir -p /var/www/ustream/users/self && chown -R www-data:www-data /var/www/ustream
ビルドしたら、 /var/www/ustream/users/self に以下の内容でchannels.jsonを配置します。
{ "channels": { "12345678": { "broadcast_urls": [ "rtmp://api.ustream.tv/mystream" ] } } }
/etc/nginx/nginx.conf を以下に書き換えます。
user www-data; worker_processes auto; pid /run/nginx.pid; error_log /var/log/nginx/error.log; load_module /usr/lib/nginx/modules/ngx_rtmp_module.so; events { worker_connections 768; # multi_accept on; } rtmp { access_log /var/log/nginx/ustream-rtmp-access.log; server { listen 1935; chunk_size 4096; max_message 5M; ping 20s; ping_timeout 36000s; force_ping on; application mystream { live on; meta off; push <配信用RTMPサーバのURL>; # Reduce buffer size wait_key on; sync 10ms; drop_idle_publisher 5s; } } } http { ## # Basic Settings ## sendfile on; tcp_nopush on; types_hash_max_size 2048; # server_tokens off; # server_names_hash_bucket_size 64; # server_name_in_redirect off; include /etc/nginx/mime.types; default_type application/octet-stream; ## # SSL Settings ## ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE ssl_prefer_server_ciphers on; ## # Logging Settings ## access_log /var/log/nginx/access.log; ## # Gzip Settings ## gzip on; server { listen 80; server_name api.ustream.tv; error_log /var/log/nginx/ustream-error.log; access_log /var/log/nginx/ustream-access.log; location / { root /var/www/ustream/; } location /stat { rtmp_stat all; } } }
各種設定が済んだら、nginxを起動して配信サーバを起動します。
$ systemctl enable --now nginx

カメラに偽装した配信用資格情報を書き込む

以下のSony-PMCA-REを使用して、書き込みを行います。
Releaseから pmca-console をダウンロードします。
Windows環境であれば、 pmca-console.exeと同じディレクトリに以下の内容でstream.cfgを作成します。
[ [ "twitterEnabled", 0 ], [ "twitterConsumerKey", "" ], [ "twitterConsumerSecret", "" ], [ "twitterAccessToken1", "" ], [ "twitterAccessTokenSecret", "" ], [ "twitterMessage", "Live Streaming from Handycam by Sony" ], [ "facebookEnabled", 0 ], [ "facebookAccessToken", "" ], [ "facebookMessage", "Live Streaming from Handycam by Sony" ], [ "service", 0 ], [ "enabled", 1 ], [ "macId", "1234567890123456789012345678901234567890" ], [ "macSecret", "123456789012345678901234567890123467890" ], [ "macIssueTime", "a9315a5f00000000" ], [ "unknown", 1 ], [ "channels", [ 12345678 ] ], [ "shortURL", "http://ustre.am/1AAAA" ], [ "videoFormat", 3 ], [ "supportedFormats", [ 1, 3 ] ], [ "enableRecordMode", 0 ], [ "videoTitle", "Test" ], [ "videoDescription", "Test" ], [ "videoTag", "Test" ] ]
カメラをMTPモードで接続し、PCで書き込みます。
> pmca-console-v0.18-win.exe stream -w stream.cfg

動作確認

カメラをライブストリーミングモードに変更して、ストリームを開始します。
うまく動いたっぽい。

部室にデプロイ

テストはうまく行ったので、これを部室やコモンズイベントでも使えるようにしておきます。テスト環境と同じ手順で構築すれば動くわけですが、実際にはカメラが2台分あり、台数分のサーバ構築をするのは面倒です。
コンテナイメージを錬成して、部室のKubernetes環境に環境変数だけ変えてデプロイします。コンテナは神。

コンテナに想いを詰める

Dockerfileを書いて、それをビルドして ghcr.io で公開します。
https://ghcr.io/TechnoTUT/sonycam-nginx からpullできます。

マニフェストを書く

Kubernetesに載せるために、まずはマニフェストを書きます。
カメラから映像を受け取るnginxサーバは、先程錬成した ghcr.io/technotut/sonycam-nginx を使用し、api.ustream.tvをローカルIPで返すDNSサーバはCoreDNSを使っています。マニフェストは以下のように書いています。
apiVersion: apps/v1 kind: Deployment metadata: name: cam1-nginx-deployment labels: app: cam1-sonycam-nginx namespace: cam1 spec: selector: matchLabels: app: cam1-sonycam-nginx replicas: 1 template: metadata: labels: app: cam1-sonycam-nginx spec: containers: - name: cam1-sonycam-nginx image: ghcr.io/technotut/sonycam-nginx:main env: - name: SERVER_URL value: rtmp://rtmp-service.live.svc.cluster.local:1935/live/cam1 ports: - containerPort: 1935 - containerPort: 80 resources: limits: cpu: 1 memory: 256Mi restartPolicy: Always --- apiVersion: v1 kind: Service metadata: name: cam1-nginx-service labels: app: cam1-sonycam-nginx namespace: cam1 annotations: external-dns.alpha.kubernetes.io/hostname: cam1.kube.technotut.net spec: selector: app: cam1-sonycam-nginx type: LoadBalancer loadBalancerIP: 10.33.71.1 ports: - name: rtmp protocol: TCP port: 1935 targetPort: 1935 - name: http protocol: TCP port: 80 targetPort: 80
envで配信サーバのURLを指定し、 metadata.annotationsでホスト名を外部のDNSサーバに登録して cam1.kube.technotut.net でアクセスできるようにしています。 rtmp-service.live.svc.cluster.local はクラスタ内で利用可能なFQDNで、配信先サーバを指定しています。配信用RTMPサーバ用のマニフェストは以下の通りに作っています。
apiVersion: apps/v1 kind: Deployment metadata: name: rtmp-deployment labels: app: rtmp-live-server namespace: live spec: selector: matchLabels: app: rtmp-live-server replicas: 1 template: metadata: labels: app: rtmp-live-server spec: containers: - name: rtmp-live-server image: ghcr.io/technotut/rtmp-live-server:main ports: - containerPort: 1935 - containerPort: 8080 resources: limits: cpu: 1 memory: 256Mi restartPolicy: Always --- apiVersion: v1 kind: Service metadata: name: rtmp-service labels: app: rtmp-live-server namespace: live annotations: external-dns.alpha.kubernetes.io/hostname: live.kube.technotut.net spec: selector: app: rtmp-live-server type: LoadBalancer loadBalancerIP: 10.33.0.1 ports: - name: rtmp protocol: TCP port: 1935 targetPort: 1935 - name: http protocol: TCP port: 80 targetPort: 8080

ArgoCDに登録

ArgoCDでマニフェストを適用します。
ここで紹介した手順で操作します。
$ argocd login kube.intra.technotut.net:30001 $ kubectl create namespace cam1 $ argocd app create cam1 --repo https://github.com/TechnoTUT/k3s.git --path manifest/cam1 --dest-server https://kubernetes.default.svc --dest-namespace cam1 $ argocd app sync cam1 $ argocd app set cam1 --sync-policy automated
Wwb UIで確認してみると、ちゃんと動いていることが確認できますね。

動作確認

部室のKubernetesクラスタで動いた

Image
DDlia
DDlia
@ddLi907

とりあえずコンテナに詰めたけど動くかや TechnoTUT/sony-camera-rtmp-relay: Receive video via wireless from sony camera and send it to a local streaming server. github.com/TechnoTUT/sony…

7
Reply

使い方

OBSのメディアストリームなり、VLCなりで
rtmp://live.kube.technotut.net/live/cam1
rtmp://live.kube.technotut.net/live/cam2
を開くと映像を受信できます!

まとめ

というわけで、部室のカメラから直接PCに映像を飛ばせるようにしました。今後のイベント等で活用してもらえると嬉しいです。
また、部室にKubernetesの環境を用意してあるので、ぜひみなさんも部内に提供したいサービスを気軽にコンテナに詰めて動かしに来てください。
トップへ戻る