🛴

カメラからのMJPEGをTCPで送って別のPCで観られるようにした

2023/04/23に公開

USBWebcamはラズパイやjetson nanoにつないで使っていますが、どちらもディスプレイはつないでいません。なので、MJPEGで保存したファイルをscpで転送してから画面のあるPC(MacBookAir)で再生していました。

ファイルに書く代わりにTCP socketに流す

前回のサンプルプログラムを少し改造して、MJPEGをファイルに書き込む代わりに直接TCPで別のPCに送って見ることができるようにしてみました

https://github.com/tetsu-koba/v4l2capture/tree/temp_tcp_socket
クイックハックなので別のブランチ(temp_tcp_socket)にpushしておきました。
修正は以下の通り。ファイルをcreateする代わりにtcpのstreamに書くようにしただけ。

$ git show
commit d2526b52d7edbd594493d59cf25dac4755d07a33 (HEAD -> temp_tcp_socket, origin/temp_tcp_socket)
Author: Tetsuyuki Kobayashi <tetsu.koba@gmail.com>
Date:   Sun Apr 23 16:05:07 2023 +0900

    temp: Send to TCP socket instead of writing to file

diff --git a/src/main.zig b/src/main.zig
index 32e16bd..8e3483a 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -5,7 +5,8 @@ const time = std.time;
 const v = @import("v4l2capture.zig");
 
 var running: bool = false;
-var outFile: std.fs.File = undefined;
+//var outFile: std.fs.File = undefined;
+var tcp: std.net.Stream = undefined;
 
 fn signalHandler(signo: c_int) align(1) callconv(.C) void {
     switch (signo) {
@@ -22,7 +23,8 @@ fn signalHandler(signo: c_int) align(1) callconv(.C) void {
 }
 
 fn frameHandler(frame: []const u8) bool {
-    outFile.writeAll(frame) catch {
+    //outFile.writeAll(frame) catch {
+    tcp.writeAll(frame) catch {
         // TODO err handling
         return false;
     };
@@ -53,8 +55,12 @@ pub fn main() !void {
         framerate = try std.fmt.parseInt(u32, args[5], 10);
     }
 
-    outFile = try std.fs.cwd().createFile(outfile, .{});
-    defer outFile.close();
+    // outFile = try std.fs.cwd().createFile(outfile, .{});
+    // defer outFile.close();
+
+    // temporary: use outfile as hosthame
+    tcp = try std.net.tcpConnectToHost(alc, outfile, 8999);
+    defer tcp.close();
 
     var cap = try v.Capturer.init(alc, devname, width, height, framerate);
     defer cap.deinit();

使い方

ポート番号は8999に固定です。ファイル名を指定するところをに代わりにホスト名を指定します。

受信側

MacBookAir のffplayを使用しました。

ffplay -hide_banner -autoexit "tcp://:8999?listen=1"

こちらを先に起動しておきます。これのホスト名はkoba-mac.localです。

送信側

temp_tcp_socketのブランチでビルドし、保存するファイル名の代わりにホスト名を指定します。

zig-out/bin/v4l2capture /dev/video0 koba-mac.local 320 240 15

MJPEGは圧縮率が高くないのでとりあえず小さめの映像サイズでやってみました。320x240@15fpsでも2Mbpsくらいの帯域を使っているようです。
高画質な映像には向きませんが、手っ取り早くMJPEGの映像取得の動作確認する手段としてはアリかと思います。

2024/04/24 追記

ファイルへの保存とTCPへの送信の両方に対応させて、mainブランチにマージしました。

$ zig-out/bin/v4l2capture
Usage: zig-out/bin/v4l2capture /dev/videoX URL [width height framerate]
default is 640x480@30fps
URL is 'file://filename', 'tcp://hostname:port' or just filename.

README.mdも更新しました。使い方はこちらを見てください。
https://github.com/tetsu-koba/v4l2capture

関連

https://zenn.dev/tetsu_koba/articles/29bc1c5192a7ab

Discussion