diff --git a/.dockerignore b/.dockerignore index 3b02d14..98f7644 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,4 @@ *.o -text_font.* -mtxrpicam -mtxrpicam_* +/deps +/prefix +/mtxrpicam_* diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8d0f6d8..59c916b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,12 +12,14 @@ jobs: steps: - uses: actions/checkout@v4 - - run: make -f utils.mk build32 + - run: make -f utils.mk build_32 + + - run: tar -czf mtxrpicam_32.tar.gz mtxrpicam_32 - uses: actions/upload-artifact@v4 with: - path: mtxrpicam_32 - name: mtxrpicam_32 + path: mtxrpicam_32.tar.gz + name: mtxrpicam_32.tar.gz build_64: runs-on: ubuntu-22.04 @@ -25,12 +27,14 @@ jobs: steps: - uses: actions/checkout@v4 - - run: make -f utils.mk build64 + - run: make -f utils.mk build_64 + + - run: tar -czf mtxrpicam_64.tar.gz mtxrpicam_64 - uses: actions/upload-artifact@v4 with: - path: mtxrpicam_64 - name: mtxrpicam_64 + path: mtxrpicam_64.tar.gz + name: mtxrpicam_64.tar.gz github_release: needs: @@ -41,12 +45,12 @@ jobs: steps: - uses: actions/download-artifact@v4 with: - name: mtxrpicam_32 + name: mtxrpicam_32.tar.gz path: binaries/ - uses: actions/download-artifact@v4 with: - name: mtxrpicam_64 + name: mtxrpicam_64.tar.gz path: binaries/ - uses: actions/github-script@v6 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0d10e2f..261b4d3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v4 - - run: make -f utils.mk build32 + - run: make -f utils.mk build_32 - uses: actions/upload-artifact@v4 with: @@ -26,14 +26,14 @@ jobs: steps: - uses: actions/checkout@v4 - - run: make -f utils.mk build64 + - run: make -f utils.mk build_64 - uses: actions/upload-artifact@v4 with: path: mtxrpicam_64 name: mtxrpicam_64 - test_32: + test_bullseye_32: needs: build_32 runs-on: ubuntu-22.04 @@ -45,11 +45,9 @@ jobs: name: mtxrpicam_32 path: . - - run: chmod +x mtxrpicam_32 + - run: make -f utils.mk test_bullseye_32 - - run: make -f utils.mk test32 - - test_64: + test_bullseye_64: needs: build_64 runs-on: ubuntu-22.04 @@ -61,6 +59,32 @@ jobs: name: mtxrpicam_64 path: . - - run: chmod +x mtxrpicam_64 + - run: make -f utils.mk test_bullseye_64 + + test_bookworm_32: + needs: build_32 + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: mtxrpicam_32 + path: . + + - run: make -f utils.mk test_bookworm_32 + + test_bookworm_64: + needs: build_64 + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: mtxrpicam_64 + path: . - - run: make -f utils.mk test64 + - run: make -f utils.mk test_bookworm_64 diff --git a/.gitignore b/.gitignore index 3b02d14..98f7644 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ *.o -text_font.* -mtxrpicam -mtxrpicam_* +/deps +/prefix +/mtxrpicam_* diff --git a/Makefile b/Makefile index ed23aa9..65ef636 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,113 @@ ifeq ($(shell gcc -dumpmachine),aarch64-linux-gnu) - EXECUTABLE_NAME = mtxrpicam_64 + OUT_DIR = mtxrpicam_64 else - EXECUTABLE_NAME = mtxrpicam_32 + OUT_DIR = mtxrpicam_32 endif -all: $(EXECUTABLE_NAME) +all: \ + $(OUT_DIR)/exe \ + $(OUT_DIR)/ipa_conf \ + $(OUT_DIR)/ipa_module \ + $(OUT_DIR)/libcamera.so.9.9 \ + $(OUT_DIR)/libcamera-base.so.9.9 + +folder: + mkdir -p $(OUT_DIR) + +################################################# +# openssl + +OPENSSL_REPO = https://github.com/openssl/openssl +OPENSSL_TAG = openssl-3.3.1 + +OPENSSL_TARGET = prefix/lib/libcrypto.a + +deps/openssl: + git clone -b $(OPENSSL_TAG) --depth=1 $(OPENSSL_REPO) $@ + +$(OPENSSL_TARGET): deps/openssl + cd $< \ + && ./Configure \ + --prefix=$(PWD)/prefix \ + no-shared \ + no-threads \ + no-quic \ + no-uplink \ + && make -j$$(nproc) \ + && make install_sw + +################################################# +# libcamera + +LIBCAMERA_REPO = https://github.com/raspberrypi/libcamera +LIBCAMERA_TAG = v0.3.0+rpt20240617 + +LIBCAMERA_TARGET = prefix/lib/libcamera.so + +deps/libcamera: + git clone -b $(LIBCAMERA_TAG) --depth=1 $(LIBCAMERA_REPO) $@ + +$(LIBCAMERA_TARGET): deps/libcamera $(OPENSSL_TARGET) + cd $< \ + && echo "0.3.0+mediamtx" > .tarball-version \ + && patch -p1 < ../../libcamera.patch \ + && PATH=$(PWD)/prefix/bin:$$PATH \ + PKG_CONFIG_PATH=$(PWD)/prefix/lib/pkgconfig \ + meson setup build \ + --prefix=$(PWD)/prefix \ + --buildtype=release \ + -Dwrap_mode=forcefallback \ + -Dlc-compliance=disabled \ + -Dipas=rpi/vc4 \ + -Dpipelines=rpi/vc4 \ + -Dcam=disabled \ + -Ddocumentation=disabled \ + -Dgstreamer=disabled \ + -Dpycamera=disabled \ + -Dqcam=disabled \ + -Dtracing=disabled \ + -Dudev=disabled \ + && ninja -C build install + +$(OUT_DIR)/ipa_conf: folder $(LIBCAMERA_TARGET) + cp -r prefix/share/libcamera/ipa $@ + +$(OUT_DIR)/ipa_module: folder $(LIBCAMERA_TARGET) + cp -r prefix/lib/libcamera $@ + +# $(OUT_DIR)/ipa_proxy: folder $(LIBCAMERA_TARGET) +# cp -r prefix/libexec/libcamera $@ + +$(OUT_DIR)/libcamera.so.9.9: folder $(LIBCAMERA_TARGET) + cp prefix/lib/libcamera.so.9.9 $@ + +$(OUT_DIR)/libcamera-base.so.9.9: folder $(LIBCAMERA_TARGET) + cp prefix/lib/libcamera-base.so.9.9 $@ + +################################################# +# libfreetype + +FREETYPE_REPO = https://github.com/freetype/freetype +FREETYPE_BRANCH = VER-2-11-1 + +FREETYPE_TARGET = prefix/lib/libfreetype.a + +deps/freetype: + git clone -b $(FREETYPE_BRANCH) --depth=1 $(FREETYPE_REPO) $@ + +$(FREETYPE_TARGET): deps/freetype + cd $< \ + && cmake -B build \ + -DCMAKE_INSTALL_PREFIX:PATH=$(PWD)/prefix \ + -D CMAKE_BUILD_TYPE=Release \ + -D BUILD_SHARED_LIBS=false \ + -D FT_DISABLE_ZLIB=TRUE \ + -D FT_DISABLE_BZIP2=TRUE \ + -D FT_DISABLE_PNG=TRUE \ + -D FT_DISABLE_HARFBUZZ=TRUE \ + -D FT_DISABLE_BROTLI=TRUE \ + && make -C build -j$$(nproc) \ + && make -C build install ################################################# # text font @@ -12,14 +115,15 @@ all: $(EXECUTABLE_NAME) TEXT_FONT_URL = https://github.com/IBM/plex/raw/v6.4.2/IBM-Plex-Mono/fonts/complete/ttf/IBMPlexMono-Medium.ttf TEXT_FONT_SHA256 = 0bede3debdea8488bbb927f8f0650d915073209734a67fe8cd5a3320b572511c -TEXT_FONT_TARGET = text_font.h +TEXT_FONT_TARGET = deps/text_font.h -text_font.ttf: +deps/text_font.ttf: + mkdir -p deps wget -O $@.tmp $(TEXT_FONT_URL) H=$$(sha256sum $@.tmp | awk '{ print $$1 }'); [ "$$H" = "$(TEXT_FONT_SHA256)" ] || { echo "hash mismatch; got $$H, expected $(TEXT_FONT_SHA256)"; exit 1; } mv $@.tmp $@ -$(TEXT_FONT_TARGET): text_font.ttf +$(TEXT_FONT_TARGET): deps/text_font.ttf xxd --include $< > $@ ################################################# @@ -32,7 +136,7 @@ CFLAGS = \ -Wextra \ -Wno-unused-parameter \ -Wno-unused-result \ - $$(pkg-config --cflags freetype2) + $$(PKG_CONFIG_PATH=$(PWD)/prefix/lib/pkgconfig pkg-config --cflags freetype2) CXXFLAGS = \ -Ofast \ @@ -42,13 +146,13 @@ CXXFLAGS = \ -Wno-unused-parameter \ -Wno-unused-result \ -std=c++17 \ - $$(pkg-config --cflags libcamera) + $$(PKG_CONFIG_PATH=$(PWD)/prefix/lib/pkgconfig pkg-config --cflags libcamera) LDFLAGS = \ -s \ -pthread \ - $$(pkg-config --libs freetype2) \ - $$(pkg-config --libs libcamera) + $$(PKG_CONFIG_PATH=$(PWD)/prefix/lib/pkgconfig pkg-config --libs freetype2) \ + $$(PKG_CONFIG_PATH=$(PWD)/prefix/lib/pkgconfig pkg-config --libs libcamera) OBJS = \ base64.o \ @@ -62,6 +166,8 @@ OBJS = \ window.o DEPENDENCIES = \ + $(LIBCAMERA_TARGET) \ + $(FREETYPE_TARGET) \ $(TEXT_FONT_TARGET) %.o: %.c $(DEPENDENCIES) @@ -70,5 +176,5 @@ DEPENDENCIES = \ %.o: %.cpp $(DEPENDENCIES) $(CXX) $(CXXFLAGS) -c $< -o $@ -$(EXECUTABLE_NAME): $(OBJS) +$(OUT_DIR)/exe: folder $(OBJS) $(CXX) $^ $(LDFLAGS) -o $@ diff --git a/README.md b/README.md index 2ffe581..18740bd 100644 --- a/README.md +++ b/README.md @@ -15,12 +15,17 @@ This is embedded into all MediaMTX releases and shouldn't normally be downloaded ```sh sudo apt install -y \ g++ \ - pkg-config \ make \ - libcamera-dev \ - libfreetype-dev \ xxd \ - wget + wget \ + git \ + cmake \ + meson \ + patch \ + pkg-config \ + python3-jinja2 \ + python3-yaml \ + python3-ply ``` 3. Build: @@ -29,7 +34,7 @@ This is embedded into all MediaMTX releases and shouldn't normally be downloaded make -j$(nproc) ``` - This will produce `mtxrpicam_32` or `mtxrpicam_64` (depending on the architecture). + This will produce the `mtxrpicam_32` or `mtxrpicam_64` folder (depending on the architecture). ## Cross-compile @@ -43,9 +48,9 @@ This is embedded into all MediaMTX releases and shouldn't normally be downloaded make -f utils.mk build ``` - This will produce `mtxrpicam_32` and `mtxrpicam_64`. + This will produce the `mtxrpicam_32` and `mtxrpicam_64` folders. -## Installation +## Install 1. Download MediaMTX source code and open a terminal in it diff --git a/camera.cpp b/camera.cpp index 73701a6..2b124a4 100644 --- a/camera.cpp +++ b/camera.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include "camera.h" @@ -26,6 +27,7 @@ using libcamera::ColorSpace; using libcamera::ControlList; using libcamera::FrameBufferAllocator; using libcamera::FrameBuffer; +using libcamera::Orientation; using libcamera::PixelFormat; using libcamera::Rectangle; using libcamera::Request; @@ -143,6 +145,11 @@ bool camera_create(const parameters_t *params, camera_frame_cb frame_cb, camera_ // We make sure to set the environment variable before libcamera init setenv("LIBCAMERA_RPI_TUNING_FILE", params->tuning_file, 1); + // TODO: move into embedded libcamera + setenv("LIBCAMERA_IPA_CONFIG_PATH", "./ipa_conf", 1); + setenv("LIBCAMERA_IPA_MODULE_PATH", "./ipa_module", 1); + setenv("LIBCAMERA_IPA_PROXY_PATH", "./ipa_proxy", 1); + camp->camera_manager = std::make_unique(); int ret = camp->camera_manager->start(); if (ret != 0) { @@ -199,12 +206,12 @@ bool camera_create(const parameters_t *params, camera_frame_cb frame_cb, camera_ raw_stream_conf.bufferCount = video_stream_conf.bufferCount; } - conf->transform = Transform::Identity; + conf->orientation = Orientation::Rotate0; if (params->h_flip) { - conf->transform = Transform::HFlip * conf->transform; + conf->orientation = conf->orientation * Transform::HFlip; } if (params->v_flip) { - conf->transform = Transform::VFlip * conf->transform; + conf->orientation = conf->orientation * Transform::VFlip; } CameraConfiguration::Status vstatus = conf->validate(); diff --git a/libcamera.patch b/libcamera.patch new file mode 100644 index 0000000..490c3f3 --- /dev/null +++ b/libcamera.patch @@ -0,0 +1,13 @@ +diff --git a/meson.build b/meson.build +index 58bb9893..41fc661f 100644 +--- a/meson.build ++++ b/meson.build +@@ -2,7 +2,7 @@ + + project('libcamera', 'c', 'cpp', + meson_version : '>= 0.60', +- version : '0.3.0', ++ version : '9.9.9', + default_options : [ + 'werror=true', + 'warning_level=2', diff --git a/text.c b/text.c index 4ec8593..261f1a3 100644 --- a/text.c +++ b/text.c @@ -3,7 +3,8 @@ #include #include FT_FREETYPE_H -#include "text_font.h" +#include "deps/text_font.h" + #include "text.h" static char errbuf[256]; @@ -42,8 +43,8 @@ bool text_create(const parameters_t *params, text_t **text) { error = FT_New_Memory_Face( textp->library, - text_font_ttf, - sizeof(text_font_ttf), + deps_text_font_ttf, + sizeof(deps_text_font_ttf), 0, &textp->face); if (error) { diff --git a/utils.mk b/utils.mk index ceecbce..21e3ae5 100644 --- a/utils.mk +++ b/utils.mk @@ -1,87 +1,121 @@ -RPI32_IMAGE = balenalib/raspberry-pi:bullseye-run-20240508 -RPI64_IMAGE = balenalib/raspberrypi3-64:bullseye-run-20240429 +BULLSEYE_32_IMAGE = balenalib/raspberry-pi:bullseye-run-20240508 +BULLSEYE_64_IMAGE = balenalib/raspberrypi3-64:bullseye-run-20240429 +BOOKWORM_32_IMAGE = balenalib/raspberry-pi:bookworm-run-20240527 +BOOKWORM_64_IMAGE = balenalib/raspberrypi3-64:bookworm-run-20240429 help: @echo "usage: make [action]" @echo "" @echo "available actions:" @echo "" - @echo " build build binaries for all platforms" - @echo " build32 build binaries for the 64-bit platform" - @echo " build64 build binaries for the 32-bit platform" - @echo " test32 test binaries for the 32-bit platform" - @echo " test64 test binaries for the 64-bit platform" + @echo " build build binaries for all architectures" + @echo " build_32 build binaries for 64-bit architectures" + @echo " build_64 build binaries for 32-bit architectures" + @echo " test_bullseye_32 test binaries on Raspberry Pi OS Bullseye 32-bit" + @echo " test_bullseye_64 test binaries on Raspberry Pi OS Bullseye 64-bit" + @echo " test_bookworm_32 test binaries on Raspberry Pi OS Bookworm 32-bit" + @echo " test_bookworm_64 test binaries on Raspberry Pi OS Bookworm 64-bit" @echo "" -build: build32 build64 +build: build_32 build_64 enable_multiarch: docker run --rm --privileged multiarch/qemu-user-static:register --reset --credential yes -define DOCKERFILE_BUILD32 +define DOCKERFILE_BUILD_32 FROM multiarch/qemu-user-static:x86_64-arm AS qemu -FROM $(RPI32_IMAGE) AS build +FROM $(BULLSEYE_32_IMAGE) AS build COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static RUN apt update && apt install -y --no-install-recommends \ g++ \ - pkg-config \ make \ - libcamera-dev \ - libfreetype-dev \ xxd \ - wget + wget \ + git \ + cmake \ + meson \ + patch \ + pkg-config \ + python3-jinja2 \ + python3-yaml \ + python3-ply WORKDIR /s COPY . . RUN make -j$$(nproc) endef -export DOCKERFILE_BUILD32 +export DOCKERFILE_BUILD_32 -build32: enable_multiarch - echo "$$DOCKERFILE_BUILD32" | docker build . -f - -t build32 +build_32: enable_multiarch + echo "$$DOCKERFILE_BUILD_32" | docker build . -f - -t build32 docker run --rm -v $(PWD):/o build32 sh -c "mv /s/mtxrpicam_32 /o/" -define DOCKERFILE_BUILD64 +define DOCKERFILE_BUILD_64 FROM multiarch/qemu-user-static:x86_64-aarch64 AS qemu -FROM $(RPI64_IMAGE) AS build +FROM $(BULLSEYE_64_IMAGE) AS build COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static RUN apt update && apt install -y --no-install-recommends \ g++ \ - pkg-config \ make \ - libcamera-dev \ - libfreetype-dev \ xxd \ - wget + wget \ + git \ + cmake \ + meson \ + patch \ + pkg-config \ + python3-jinja2 \ + python3-yaml \ + python3-ply WORKDIR /s COPY . . RUN make -j$$(nproc) endef -export DOCKERFILE_BUILD64 +export DOCKERFILE_BUILD_64 -build64: enable_multiarch - echo "$$DOCKERFILE_BUILD64" | docker build . -f - -t build64 +build_64: enable_multiarch + echo "$$DOCKERFILE_BUILD_64" | docker build . -f - -t build64 docker run --rm -v $(PWD):/o build64 sh -c "mv /s/mtxrpicam_64 /o/" -define DOCKERFILE_TEST32 +define DOCKERFILE_TEST_BULLSEYE_32 +FROM multiarch/qemu-user-static:x86_64-arm AS qemu +FROM $(BULLSEYE_32_IMAGE) AS build +COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static +endef +export DOCKERFILE_TEST_BULLSEYE_32 + +test_bullseye_32: enable_multiarch + echo "$$DOCKERFILE_TEST_BULLSEYE_32" | docker build . -f - -t test_bullseye_32 + docker run --rm --platform=linux/arm/v6 -v $(PWD):/s -w /s test_bullseye_32 bash -c "TEST=1 ./mtxrpicam_32" + +define DOCKERFILE_TEST_BULLSEYE_64 +FROM multiarch/qemu-user-static:x86_64-aarch64 AS qemu +FROM $(BULLSEYE_64_IMAGE) AS build +COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static +endef +export DOCKERFILE_TEST_BULLSEYE_64 + +test_bullseye_64: enable_multiarch + echo "$$DOCKERFILE_TEST_BULLSEYE_64" | docker build . -f - -t test_bullseye_64 + docker run --rm --platform=linux/arm64/v8 -v $(PWD):/s -w /s test_bullseye_64 bash -c "TEST=1 ./mtxrpicam_64" + +define DOCKERFILE_TEST_BOOKWORM_32 FROM multiarch/qemu-user-static:x86_64-arm AS qemu -FROM $(RPI32_IMAGE) AS build +FROM $(BOOKWORM_32_IMAGE) AS build COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin/qemu-arm-static -RUN apt update && apt install -y --no-install-recommends libcamera0 libfreetype6 && rm -rf /var/lib/apt/lists/* endef -export DOCKERFILE_TEST32 +export DOCKERFILE_TEST_BOOKWORM_32 -test32: enable_multiarch - echo "$$DOCKERFILE_TEST32" | docker build . -f - -t test32 - docker run --rm --platform=linux/arm/v6 -v $(PWD):/s -w /s test32 bash -c "TEST=1 ./mtxrpicam_32" +test_bookworm_32: enable_multiarch + echo "$$DOCKERFILE_TEST_BOOKWORM_32" | docker build . -f - -t test_bookworm_32 + docker run --rm --platform=linux/arm/v6 -v $(PWD):/s -w /s test_bookworm_32 bash -c "TEST=1 ./mtxrpicam_32" -define DOCKERFILE_TEST64 +define DOCKERFILE_TEST_BOOKWORM_64 FROM multiarch/qemu-user-static:x86_64-aarch64 AS qemu -FROM $(RPI64_IMAGE) AS build +FROM $(BOOKWORM_64_IMAGE) AS build COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin/qemu-aarch64-static -RUN apt update && apt install -y --no-install-recommends libcamera0 libfreetype6 && rm -rf /var/lib/apt/lists/* endef -export DOCKERFILE_TEST64 +export DOCKERFILE_TEST_BOOKWORM_64 -test64: enable_multiarch - echo "$$DOCKERFILE_TEST64" | docker build . -f - -t test64 - docker run --rm --platform=linux/arm64/v8 -v $(PWD):/s -w /s test64 bash -c "TEST=1 ./mtxrpicam_64" +test_bookworm_64: enable_multiarch + echo "$$DOCKERFILE_TEST_BOOKWORM_64" | docker build . -f - -t test_bookworm_64 + docker run --rm --platform=linux/arm64/v8 -v $(PWD):/s -w /s test_bookworm_64 bash -c "TEST=1 ./mtxrpicam_64"