diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..2841c31a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "internal/rpicamera/exe/libcamera"] + path = internal/rpicamera/exe/libcamera + url = https://git.libcamera.org/libcamera/libcamera.git diff --git a/internal/core/core.go b/internal/core/core.go index 4fbd64f1..743d21fe 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -17,7 +17,6 @@ import ( "github.com/bluenviron/mediamtx/internal/externalcmd" "github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/rlimit" - "github.com/bluenviron/mediamtx/internal/rpicamera" ) var version = "v0.0.0" @@ -671,10 +670,6 @@ func (p *Core) closeResources(newConf *conf.Conf, calledByAPI bool) { p.externalCmdPool.Close() } - if newConf == nil { - rpicamera.Cleanup() - } - if closeLogger { p.logger.Close() p.logger = nil diff --git a/internal/rpicamera/exe/Makefile b/internal/rpicamera/exe/Makefile index 5f285dfc..f4ea1629 100644 --- a/internal/rpicamera/exe/Makefile +++ b/internal/rpicamera/exe/Makefile @@ -15,13 +15,13 @@ CXXFLAGS = \ -Wno-unused-parameter \ -Wno-unused-result \ -std=c++17 \ - $$(pkg-config --cflags libcamera) + $$(PKG_CONFIG_PATH=libcamera_prefix/lib/pkgconfig pkg-config --cflags libcamera) LDFLAGS = \ -s \ -pthread \ - $$(pkg-config --libs freetype2) \ - $$(pkg-config --libs libcamera) + $$(pkg-config --static --libs freetype2) \ + $$(PKG_CONFIG_PATH=libcamera_prefix/lib/pkgconfig pkg-config --static --libs libcamera) OBJS = \ base64.o \ @@ -34,18 +34,28 @@ OBJS = \ text.o \ window.o +LIBCAMERA = libcamera_prefix/lib/libcamera.a + all: exe +$(LIBCAMERA): + cd libcamera \ + && meson setup \ + -Dlc-compliance=disabled \ + -Dipas=raspberrypi \ + -Dpipelines=raspberrypi \ + --prefix=$(PWD)/libcamera_prefix \ + build \ + && ninja -C build install + text_font.h: text_font.ttf xxd --include $< > text_font.h -%.o: %.c text_font.h +%.o: %.c $(LIBCAMERA) text_font.h $(CC) $(CFLAGS) -c $< -o $@ -%.o: %.cpp +%.o: %.cpp $(LIBCAMERA) $(CXX) $(CXXFLAGS) -c $< -o $@ exe: $(OBJS) $(CXX) $^ $(LDFLAGS) -o $@ - patchelf --replace-needed $$(basename /usr/lib/*-linux-*/libcamera.so.0*) libcamera.so.x.x.x $@ - patchelf --replace-needed $$(basename /usr/lib/*-linux-*/libcamera-base.so.0*) libcamera-base.so.x.x.x $@ diff --git a/internal/rpicamera/exe/libcamera b/internal/rpicamera/exe/libcamera new file mode 160000 index 00000000..fb44403f --- /dev/null +++ b/internal/rpicamera/exe/libcamera @@ -0,0 +1 @@ +Subproject commit fb44403f1c5571549ac128c21daee9761eb9249c diff --git a/internal/rpicamera/rpicamera.go b/internal/rpicamera/rpicamera.go index c9b288c9..ff4a3388 100644 --- a/internal/rpicamera/rpicamera.go +++ b/internal/rpicamera/rpicamera.go @@ -4,15 +4,11 @@ package rpicamera import ( - "debug/elf" _ "embed" "fmt" "os" "os/exec" - "runtime" "strconv" - "strings" - "sync" "time" "github.com/bluenviron/mediacommon/pkg/codecs/h264" @@ -48,91 +44,6 @@ func startEmbeddedExe(content []byte, env []string) (*exec.Cmd, error) { return cmd, nil } -func findLibrary(name string) (string, error) { - byts, err := exec.Command("ldconfig", "-p").Output() - if err == nil { - for _, line := range strings.Split(string(byts), "\n") { - f := strings.Split(line, " => ") - if len(f) == 2 && strings.Contains(f[1], name+".so") { - return f[1], nil - } - } - } - - return "", fmt.Errorf("library '%s' not found", name) -} - -func check64bit(fpath string) error { - f, err := os.Open(fpath) - if err != nil { - return err - } - defer f.Close() - - ef, err := elf.NewFile(f) - if err != nil { - return err - } - defer ef.Close() - - if ef.FileHeader.Class == elf.ELFCLASS64 { - return fmt.Errorf("libcamera is 64-bit, you need the 64-bit server version") - } - - return nil -} - -func setupSymlink(name string) error { - lib, err := findLibrary(name) - if err != nil { - return err - } - - if runtime.GOARCH == "arm" { - err := check64bit(lib) - if err != nil { - return err - } - } - - os.Remove("/dev/shm/" + name + ".so.x.x.x") - return os.Symlink(lib, "/dev/shm/"+name+".so.x.x.x") -} - -var ( - mutex sync.Mutex - setupped bool -) - -func setupLibcameraOnce() error { - mutex.Lock() - defer mutex.Unlock() - - if !setupped { - err := setupSymlink("libcamera") - if err != nil { - return err - } - - err = setupSymlink("libcamera-base") - if err != nil { - return err - } - - setupped = true - } - - return nil -} - -// Cleanup cleanups files created by the camera implementation. -func Cleanup() { - if setupped { - os.Remove("/dev/shm/libcamera-base.so.x.x.x") - os.Remove("/dev/shm/libcamera.so.x.x.x") - } -} - type RPICamera struct { onData func(time.Duration, [][]byte) @@ -148,15 +59,11 @@ func New( params Params, onData func(time.Duration, [][]byte), ) (*RPICamera, error) { - err := setupLibcameraOnce() - if err != nil { - return nil, err - } - c := &RPICamera{ onData: onData, } + var err error c.pipeConf, err = newPipe() if err != nil { return nil, err @@ -169,7 +76,6 @@ func New( } env := []string{ - "LD_LIBRARY_PATH=/dev/shm", "PIPE_CONF_FD=" + strconv.FormatInt(int64(c.pipeConf.readFD), 10), "PIPE_VIDEO_FD=" + strconv.FormatInt(int64(c.pipeVideo.writeFD), 10), } diff --git a/internal/rpicamera/rpicamera_disabled.go b/internal/rpicamera/rpicamera_disabled.go index a8663320..46b4f4c7 100644 --- a/internal/rpicamera/rpicamera_disabled.go +++ b/internal/rpicamera/rpicamera_disabled.go @@ -9,10 +9,6 @@ import ( "time" ) -// Cleanup cleanups files created by the camera implementation. -func Cleanup() { -} - // RPICamera is a RPI Camera reader. type RPICamera struct{} diff --git a/scripts/binaries.mk b/scripts/binaries.mk index b25afec6..9566d2d3 100644 --- a/scripts/binaries.mk +++ b/scripts/binaries.mk @@ -1,17 +1,30 @@ +RPICAMERA_BUILD_DEPENDENCIES = \ + g++ \ + pkg-config \ + make \ + libfreetype-dev \ + xxd \ + meson \ + libyaml-dev \ + python3-yaml \ + python3-ply \ + python3-jinja2 \ + libssl-dev + define DOCKERFILE_BINARIES -FROM $(RPI32_IMAGE) AS rpicamera32 -RUN ["cross-build-start"] -RUN apt update && apt install -y --no-install-recommends g++ pkg-config make libcamera-dev libfreetype-dev xxd patchelf -WORKDIR /s/internal/rpicamera -COPY internal/rpicamera . -RUN cd exe && make -j$$(nproc) +# FROM $(RPI32_IMAGE) AS rpicamera32 +# RUN ["cross-build-start"] +# RUN apt update && apt install -y --no-install-recommends $(RPICAMERA_BUILD_DEPENDENCIES) +# WORKDIR /s/internal/rpicamera/exe +# COPY internal/rpicamera/exe . +# RUN make -j$$(nproc) FROM $(RPI64_IMAGE) AS rpicamera64 RUN ["cross-build-start"] -RUN apt update && apt install -y --no-install-recommends g++ pkg-config make libcamera-dev libfreetype-dev xxd patchelf -WORKDIR /s/internal/rpicamera -COPY internal/rpicamera . -RUN cd exe && make -j$$(nproc) +RUN apt update && apt install -y --no-install-recommends $(RPICAMERA_BUILD_DEPENDENCIES) +WORKDIR /s/internal/rpicamera/exe +COPY internal/rpicamera/exe . +RUN make -j$$(nproc) FROM $(BASE_IMAGE) AS build-base RUN apk add --no-cache zip make git tar @@ -25,33 +38,33 @@ RUN rm -rf tmp binaries RUN mkdir tmp binaries RUN cp mediamtx.yml LICENSE tmp/ -FROM build-base AS build-windows-amd64 -RUN GOOS=windows GOARCH=amd64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx.exe -RUN cd tmp && zip -q ../binaries/mediamtx_$${VERSION}_windows_amd64.zip mediamtx.exe mediamtx.yml LICENSE +# FROM build-base AS build-windows-amd64 +# RUN GOOS=windows GOARCH=amd64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx.exe +# RUN cd tmp && zip -q ../binaries/mediamtx_$${VERSION}_windows_amd64.zip mediamtx.exe mediamtx.yml LICENSE -FROM build-base AS build-linux-amd64 -RUN GOOS=linux GOARCH=amd64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_amd64.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE +# FROM build-base AS build-linux-amd64 +# RUN GOOS=linux GOARCH=amd64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx +# RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_amd64.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE -FROM build-base AS build-darwin-amd64 -RUN GOOS=darwin GOARCH=amd64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_darwin_amd64.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE +# FROM build-base AS build-darwin-amd64 +# RUN GOOS=darwin GOARCH=amd64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx +# RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_darwin_amd64.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE -FROM build-base AS build-darwin-arm64 -RUN GOOS=darwin GOARCH=arm64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_darwin_arm64.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE +# FROM build-base AS build-darwin-arm64 +# RUN GOOS=darwin GOARCH=arm64 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx +# RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_darwin_arm64.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE -FROM build-base AS build-linux-armv6 -COPY --from=rpicamera32 /s/internal/rpicamera/exe/exe internal/rpicamera/exe/ -RUN GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -tags rpicamera -RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_armv6.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE -RUN rm internal/rpicamera/exe/exe +# FROM build-base AS build-linux-armv6 +# COPY --from=rpicamera32 /s/internal/rpicamera/exe/exe internal/rpicamera/exe/ +# RUN GOOS=linux GOARCH=arm GOARM=6 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -tags rpicamera +# RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_armv6.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE +# RUN rm internal/rpicamera/exe/exe -FROM build-base AS build-linux-armv7 -COPY --from=rpicamera32 /s/internal/rpicamera/exe/exe internal/rpicamera/exe/ -RUN GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -tags rpicamera -RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_armv7.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE -RUN rm internal/rpicamera/exe/exe +# FROM build-base AS build-linux-armv7 +# COPY --from=rpicamera32 /s/internal/rpicamera/exe/exe internal/rpicamera/exe/ +# RUN GOOS=linux GOARCH=arm GOARM=7 go build -ldflags "-X github.com/bluenviron/mediamtx/internal/core.version=$$VERSION" -o tmp/mediamtx -tags rpicamera +# RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_armv7.tar.gz --owner=0 --group=0 mediamtx mediamtx.yml LICENSE +# RUN rm internal/rpicamera/exe/exe FROM build-base AS build-linux-arm64 COPY --from=rpicamera64 /s/internal/rpicamera/exe/exe internal/rpicamera/exe/ @@ -60,12 +73,12 @@ RUN tar -C tmp -czf binaries/mediamtx_$${VERSION}_linux_arm64v8.tar.gz --owner=0 RUN rm internal/rpicamera/exe/exe FROM $(BASE_IMAGE) -COPY --from=build-windows-amd64 /s/binaries /s/binaries -COPY --from=build-linux-amd64 /s/binaries /s/binaries -COPY --from=build-darwin-amd64 /s/binaries /s/binaries -COPY --from=build-darwin-arm64 /s/binaries /s/binaries -COPY --from=build-linux-armv6 /s/binaries /s/binaries -COPY --from=build-linux-armv7 /s/binaries /s/binaries +# COPY --from=build-windows-amd64 /s/binaries /s/binaries +# COPY --from=build-linux-amd64 /s/binaries /s/binaries +# COPY --from=build-darwin-amd64 /s/binaries /s/binaries +# COPY --from=build-darwin-arm64 /s/binaries /s/binaries +# COPY --from=build-linux-armv6 /s/binaries /s/binaries +# COPY --from=build-linux-armv7 /s/binaries /s/binaries COPY --from=build-linux-arm64 /s/binaries /s/binaries endef export DOCKERFILE_BINARIES