试用 Laravel + 树莓派搭建视频监控,并支持线上访问

上周受 YouTube 视频 的刺激,买了个树莓派,原作者用 Next.js 演示的,我买的是树莓派 5 的 8GB 版本的,跑 Laravel 肯定没问题。

树莓派搭建 Laravel 运行环境

树莓派是基于 Debian 的发行版,使用 APT 和 Systemd,我采用 PHP FPM + Caddy 方案,首先安装:

sudo apt install composer php-fpm caddy

安装成功后,PHP-FPM 和 Caddy 服务会自动运行,更新下 Caddy 配置:

# /etc/caddy/Caddyfile
:80 {
        root * /srv/learn-raspi-laravel/public
        php_fastcgi unix//run/php/php-fpm.sock
        file_server
}

安装 Laravel 项目时会提示缺少一些 PHP 扩展,按照报错提示安装即可。

调用相机拍照

树莓派+像机v1.3

我买的套餐中包含了一个相机,有 500 万像素(我并不懂这个数字是啥意思),这是第一代树莓派相机,现在已经到第三代了,这是最便宜的,效果自然也最差。

像机连上主板就能拍照录像了,树莓派系统预装了 rpicam-apps 包,用命令 rpicam-jpeg 拍照、 rpicam-vid 录像,比如:

# 拍照
$ rpicam-jpeg --output frame.jpg

# 录像(默认5秒)
$ rpicam-vid -o video.mp4

简单封装下 rpicam-jpeg, 就能给 Laravel 使用了:

<?php
// app/Http/Controllers/CameraController.php
class CameraController extends Controller
{
    public function jpeg()
    {
        $path = Storage::disk('public')->path('frame.jpeg');
        Process::run(sprintf('rpicam-jpeg -n -v 0 --width 640 --height 480 -o "%s"', $path))->throw();

        return response()->file($path);
    }
}

// web.php
Route::get('/jpeg', [CameraController::class, 'jpeg']);

这样每次访问 /jpeg 就能拍一张照片了,HTML 中使用 <img src="/jpeg"> 就能显示了。

用 M-JPEG 实现视频直播

M 指 Motion,即动态的JPEG,服务器把一帧帧 JPEG 图片,按顺序发送,浏览器的 <img 标签原生支持,非常类似 SSE,这是最简单的播放视频直播的方案了,只是很好理解。

下面用 magick 演示下 M-JPEG 在 PHP 下的实现,效果是显示当前的时间会一直更新:

试用 Laravel + 树莓派搭建视频监控,并支持线上访问

class MjpegController extends Controller
{
    private function frame()
    {
        $path = storage_path('app/frame.jpeg');
        Process::run(
            sprintf(
                'magick -size 300x100 xc:white -gravity center -pointsize 20 -annotate 0 "%s" %s',
                now()->format('Y-m-d H:i:s'),
                $path
  )
        )->throw();

        return $path;
    }

    public function stream()
    {
        $response = response()->stream(null, 200, [
            'Age' => 0,
            'Cache-Control' => 'no-cache, private',
            'Pragma' => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type' => 'multipart/x-mixed-replace; boundary=FRAME',
        ]);

        $response->sendHeaders();

        while (true) {
            $path = $this->frame();
            echo "--FRAME\r\n";
            echo "Content-Type: image/jpeg\r\n";
            echo 'Content-Length: '.filesize($path)."\r\n";
            echo "\r\n";
            readfile($path);
            echo "\r\n";

            if (ob_get_level() > 0) {
                ob_flush();
            }

            flush();
            sleep(0.2);
        }
    }
}

可惜的是,我准备把上面的 magick 替换成 rpicam-jpeg,但是我发现这个命令是在是太慢了,一张图片需要5s,压根就没法儿用。

还是老老实实用 Python API 的实现,比命令行高效很多,虽然我不懂 Python,但是官方的例子直接就能跑:

为了方便后续代理到公网使用,把 http://localhost:8000/stream.mjpg 代理到 /stream.mjpg

# Caddyfile
:80 {
        root * /home/xcy/learn-raspi-laravel/public
        php_fastcgi unix//run/php/php-fpm.sock
        file_server

      @stream {
          path /stream.mjpg
      }
      reverse_proxy @stream http://localhost:8000
}

然后在 Laravel 模版中使用 <img src="/stream.mjpg"> 就能看到直播了。

用 Expose 公网访问

Expose 是一个用 PHP/Laravel Zero 开发的 ngrok 替代品,支持自托管。分享到公网:

expose share --subdomain=pi http://localhost;

Expose 代理非常容易内存溢出,特别是我们使用的 M-JPEG 方式,溢出之后会自动退出,为了避免退出,可以用简单的反噬重启下:

while true; do expose share --subdomain=pi http://localhost; done

试用 Laravel + 树莓派搭建视频监控,并支持线上访问

本帖已被设为精华帖!
本帖由系统于 1个月前 自动加精
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 19

大佬厉害啊

1个月前 评论

已经被你玩出花了 :+1:

1个月前 评论
fatrbaby

学习了兄弟

1个月前 评论

有点东西啊

1个月前 评论
Aaron

当时也用树莓派做了一个视频监控,通过ssh数据转发实现线上访问,自己玩玩可以,要想达到专业监控那样的稳定性还差很多。

1个月前 评论
xuchunyang (楼主) 1个月前
xuchunyang (楼主) 1个月前
jatdung 1个月前

没有音频吗?

4周前 评论
xuchunyang (楼主) 4周前

其实用golang玩树莓派更丝滑。

3周前 评论
xuchunyang (楼主) 3周前

膜。。。膜拜大佬!直播的话可以搭建srs,或者webrtc,还能有音频。

3周前 评论

我也准备买个树莓派玩一下,大家什么建议么?以免踩坑

3周前 评论

老哥还是很厉害的,学习一下

6天前 评论

在哪买的?有推荐吗?全套开发版那种也行

6天前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!