Live video on the AT Protocol

add ffmpeg, rust, and signed segmentation of livestreams!

See merge request aquareum-tv/aquareum!52

Changelog: feature

+532 -57
+1 -1
.ci/dockerfile-hash.yaml
··· 1 1 variables: 2 - DOCKERFILE_HASH: 0da21c7476971854cc93c0eaa26219b34eb91e70 2 + DOCKERFILE_HASH: 12c515a3a32f0d583a6cf197332140674b47533f
+12 -1
.gitlab-ci.yml
··· 28 28 reports: 29 29 dotenv: .ci/build.env 30 30 31 + test: 32 + stage: build 33 + interruptible: true 34 + image: "$CI_REGISTRY_IMAGE:builder-$DOCKERFILE_HASH" 35 + script: 36 + - git fetch --unshallow || echo 'already unshallow' 37 + - make ci-test -j$(nproc) 38 + 31 39 build-docker-amd64: 32 40 stage: build 33 41 interruptible: true ··· 104 112 script: 105 113 - git fetch --unshallow || echo 'already unshallow' 106 114 - brew install meson ninja go && go version 107 - - make ci-macos -j16 115 + - sudo gem install --user-install xcpretty 116 + - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh && bash rustup.sh -y && rm rustup.sh 117 + - PATH="$PATH:$HOME/.cargo/bin:$(find $HOME/.gem/ruby -type d -name bin -maxdepth 2)" make ci-macos -j16 108 118 109 119 release: 110 120 stage: build ··· 117 127 - build-docker-arm64 118 128 - build-docker-manifest 119 129 - build 130 + - test 120 131 rules: 121 132 - if: '$CI_COMMIT_TAG =~ /^v?\d+\.\d+\.\d+$/' 122 133 script:
+2 -1
.vscode/settings.json
··· 4 4 }, 5 5 "files.associations": { 6 6 "mistserver.h": "c", 7 - "aquareum.h": "c" 7 + "aquareum.h": "c", 8 + "avfilter.h": "c" 8 9 } 9 10 }
+18 -6
Makefile
··· 41 41 && go run pkg/crypto/signers/eip712/export-schema/export-schema.go > js/app/generated/eip712-schema.json 42 42 43 43 .PHONY: test 44 - test: app 45 - go test ./pkg/... ./cmd/... 44 + test: 45 + meson test -C build go-tests 46 46 47 47 .PHONY: all 48 48 all: version install check app test node-all-platforms android 49 49 50 50 .PHONY: ci 51 - ci: version install check app test node-all-platforms ci-upload-node 51 + ci: version install check app node-all-platforms ci-upload-node 52 52 53 53 .PHONY: ci-macos 54 54 ci-macos: version install check app node-all-platforms-macos ci-upload-node-macos ios ci-upload-ios 55 55 56 56 .PHONY: ci-macos 57 57 ci-android: version install check android ci-upload-android 58 + 59 + .PHONY: ci-test 60 + ci-test: app 61 + meson setup build 62 + meson test -C build go-tests 58 63 59 64 .PHONY: android 60 65 android: app .build/bundletool.jar ··· 83 88 AD_HOC_CODE_SIGNING_ALLOWED=YES \ 84 89 CODE_SIGN_STYLE=Automatic \ 85 90 DEVELOPMENT_TEAM=ZZZZZZZZZZ \ 86 - clean archive \ 91 + clean archive | xcpretty \ 87 92 && cd bin \ 88 93 && tar -czvf aquareum-$(VERSION)-ios-release.xcarchive.tar.gz aquareum-$(VERSION)-ios-release.xcarchive 89 94 ··· 97 102 node-all-platforms: app 98 103 meson setup build 99 104 meson compile -C build archive 105 + rustup target add aarch64-unknown-linux-gnu 100 106 meson setup --cross-file util/linux-arm64-gnu.ini build-aarch64 101 107 meson compile -C build-aarch64 archive 102 108 ··· 104 110 node-all-platforms-macos: app 105 111 meson setup build 106 112 meson compile -C build archive 113 + rustup target add x86_64-apple-darwin 107 114 meson setup --cross-file util/darwin-amd64-apple.ini build-amd64 108 115 meson compile -C build-amd64 archive 109 116 ··· 113 120 rm -rf subprojects/mistserver 114 121 ln -s $$(realpath ../mistserver) ./subprojects/mistserver 115 122 123 + # link your local version of c2pa-gop for dev 124 + .PHONY: link-c2pa-go 125 + link-c2pa-go: 126 + rm -rf subprojects/c2pa_go 127 + ln -s $$(realpath ../c2pa-go) ./subprojects/c2pa_go 128 + 116 129 .PHONY: docker-build 117 130 docker-build: docker-build-builder docker-build-in-container 118 131 ··· 123 136 124 137 .PHONY: docker-build-builder 125 138 docker-build-in-container: 126 - docker run -v $$(pwd):$$(pwd) -w $$(pwd) --rm -it aqrm.io/aquareum-tv/aquareum:builder make 139 + docker run -v $$(pwd):$$(pwd) -w $$(pwd) --rm -it aqrm.io/aquareum-tv/aquareum:builder make android 127 140 128 141 .PHONY: docker-release 129 142 docker-release: 130 143 cd docker \ 131 144 && docker build -f release.Dockerfile \ 132 145 --build-arg TARGETARCH=$(BUILDARCH) \ 133 - --build-arg AQUAREUM_URL=https://git.aquareum.tv/aquareum-tv/aquareum/-/package_files/773/download \ 134 146 -t aqrm.io/aquareum-tv/aquareum \ 135 147 . 136 148
+12 -7
docker/build.Dockerfile
··· 10 10 ENV NODE_VERSION 22.3.0 11 11 12 12 RUN apt update \ 13 - && apt install -y build-essential curl git openjdk-17-jdk unzip jq g++ python3-pip ninja-build gcc-aarch64-linux-gnu g++-aarch64-linux-gnu clang lld qemu-user-static \ 14 - && pip install meson \ 13 + && apt install -y build-essential curl git openjdk-17-jdk unzip jq g++ python3-pip ninja-build \ 14 + gcc-aarch64-linux-gnu g++-aarch64-linux-gnu clang lld qemu-user-static pkg-config \ 15 + && pip install meson tomli \ 15 16 && curl -L --fail https://go.dev/dl/go$GO_VERSION.linux-$TARGETARCH.tar.gz -o go.tar.gz \ 16 17 && tar -C /usr/local -xf go.tar.gz \ 17 18 && rm go.tar.gz 18 - ENV PATH $PATH:/usr/local/go/bin:/root/go/bin 19 + ENV PATH $PATH:/usr/local/go/bin:/root/go/bin:/root/.cargo/bin 19 20 20 21 RUN echo 'deb [arch=arm64] http://ports.ubuntu.com/ jammy main multiverse universe' >> /etc/apt/sources.list \ 21 22 && echo 'deb [arch=arm64] http://ports.ubuntu.com/ jammy-security main multiverse universe' >> /etc/apt/sources.list \ ··· 43 44 rm *tools*linux*.zip && \ 44 45 curl -L https://raw.githubusercontent.com/thyrlian/AndroidSDK/bfcbf0cdfd6bb1ef45579e6ddc4d3876264cbdd1/android-sdk/license_accepter.sh | bash 45 46 47 + RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh \ 48 + && bash rustup.sh -y \ 49 + && rm rustup.sh 50 + 46 51 FROM builder AS cached-builder 47 - ARG CI_COMMIT_BRANCH=next 48 - ENV CI_COMMIT_BRANCH $CI_COMMIT_BRANCH 49 - WORKDIR /cached-build 50 - RUN git clone https://git.aquareum.tv/aquareum-tv/aquareum && cd aquareum && make all -j$(nproc) && cd .. && rm -rf aquareum 52 + # ARG CI_COMMIT_BRANCH=next 53 + # ENV CI_COMMIT_BRANCH $CI_COMMIT_BRANCH 54 + # WORKDIR /cached-build 55 + # RUN git clone https://git.aquareum.tv/aquareum-tv/aquareum && cd aquareum && make all -j$(nproc) && cd .. && rm -rf aquareum
+5
go.mod
··· 4 4 5 5 require ( 6 6 firebase.google.com/go/v4 v4.14.1 7 + git.aquareum.tv/aquareum-tv/c2pa-go v0.0.0-20240814230802-09d77c1e2b38 7 8 github.com/NYTimes/gziphandler v1.1.1 8 9 github.com/adrg/xdg v0.4.0 9 10 github.com/dunglas/httpsfv v1.0.2 ··· 12 13 github.com/golang/glog v1.2.0 13 14 github.com/google/uuid v1.6.0 14 15 github.com/julienschmidt/httprouter v1.3.0 16 + github.com/livepeer/lpms v0.0.0-20240812093642-b5181eb92cb2 15 17 github.com/lmittmann/tint v1.0.4 16 18 github.com/orandin/slog-gorm v1.3.2 17 19 github.com/peterbourgon/ff/v3 v3.3.1 ··· 64 66 github.com/crate-crypto/go-kzg-4844 v1.0.0 // indirect 65 67 github.com/cyphar/filepath-securejoin v0.2.4 // indirect 66 68 github.com/deckarep/golang-set/v2 v2.6.0 // indirect 69 + github.com/decred/dcrd/dcrec/secp256k1 v1.0.4 // indirect 70 + github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0 // indirect 67 71 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 68 72 github.com/emirpasic/gods v1.18.1 // indirect 69 73 github.com/ethereum/c-kzg-4844 v1.0.0 // indirect ··· 86 90 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 87 91 github.com/jstemmer/go-junit-report v1.0.0 // indirect 88 92 github.com/kevinburke/ssh_config v1.2.0 // indirect 93 + github.com/livepeer/m3u8 v0.11.1 // indirect 89 94 github.com/mitchellh/gox v1.0.1 // indirect 90 95 github.com/mitchellh/iochan v1.0.0 // indirect 91 96 github.com/mmcloughlin/addchain v0.4.0 // indirect
+17
go.sum
··· 19 19 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 20 20 firebase.google.com/go/v4 v4.14.1 h1:4qiUETaFRWoFGE1XP5VbcEdtPX93Qs+8B/7KvP2825g= 21 21 firebase.google.com/go/v4 v4.14.1/go.mod h1:fgk2XshgNDEKaioKco+AouiegSI9oTWVqRaBdTTGBoM= 22 + git.aquareum.tv/aquareum-tv/c2pa-go v0.0.0-20240814230802-09d77c1e2b38 h1:8MBirN1hbiSAhnI3v4vKW3PjZ0/gkeqPeDpRBrxbh/A= 23 + git.aquareum.tv/aquareum-tv/c2pa-go v0.0.0-20240814230802-09d77c1e2b38/go.mod h1:lp4UzqUyNZ4gieOSCdjsGoSUudZsDrBpsBgnRoNLlSw= 22 24 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 23 25 github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= 24 26 github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= ··· 91 93 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 92 94 github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= 93 95 github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= 96 + github.com/decred/dcrd/chaincfg/chainhash v1.0.2 h1:rt5Vlq/jM3ZawwiacWjPa+smINyLRN07EO0cNBV6DGU= 97 + github.com/decred/dcrd/chaincfg/chainhash v1.0.2/go.mod h1:BpbrGgrPTr3YJYRN3Bm+D9NuaFd+zGyNeIKgrhCXK60= 94 98 github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= 95 99 github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= 100 + github.com/decred/dcrd/dcrec/secp256k1 v1.0.4 h1:0XErmfJBiVbl0NvyclGn4jr+1hIylDf5beFi9W0o7Fc= 101 + github.com/decred/dcrd/dcrec/secp256k1 v1.0.4/go.mod h1:00z7mJdugt+GBAzPN1QrDRGCXxyKUiexEHu6ukxEw3k= 102 + github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0 h1:3GIJYXQDAKpLEFriGFN8SbSffak10UXHGdIcFaMPykY= 103 + github.com/decred/dcrd/dcrec/secp256k1/v2 v2.0.0/go.mod h1:3s92l0paYkZoIHuj4X93Teg/HB7eGM9x/zokGw+u4mY= 96 104 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= 97 105 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= 98 106 github.com/dunglas/httpsfv v1.0.2 h1:iERDp/YAfnojSDJ7PW3dj1AReJz4MrwbECSSE59JWL0= ··· 158 166 github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 159 167 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 160 168 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 169 + github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 161 170 github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= 162 171 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= 163 172 github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk= ··· 168 177 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 169 178 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 170 179 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 180 + github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 171 181 github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 172 182 github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 173 183 github.com/google/martian/v3 v3.3.3 h1:DIhPTQrbPkgs2yJYdXU/eNACCG5DVQjySNRNlflZ9Fc= ··· 217 227 github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 218 228 github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= 219 229 github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8= 230 + github.com/livepeer/joy4 v0.1.2-0.20191121080656-b2fea45cbded/go.mod h1:xkDdm+akniYxVT9KW1Y2Y7Hso6aW+rZObz3nrA9yTHw= 231 + github.com/livepeer/lpms v0.0.0-20240812093642-b5181eb92cb2 h1:2Cjgt/Bg6bVSPHwUUeSf3n55JuCQGGfD7HXk2Qcg0I8= 232 + github.com/livepeer/lpms v0.0.0-20240812093642-b5181eb92cb2/go.mod h1:z5ROP1l5OzAKSoqVRLc34MjUdueil6wHSecQYV7llIw= 233 + github.com/livepeer/m3u8 v0.11.1 h1:VkUJzfNTyjy9mqsgp5JPvouwna8wGZMvd/gAfT5FinU= 234 + github.com/livepeer/m3u8 v0.11.1/go.mod h1:IUqAtwWPAG2CblfQa4SVzTQoDcEMPyfNOaBSxqHMS04= 220 235 github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= 221 236 github.com/lmittmann/tint v1.0.4/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= 222 237 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= ··· 444 459 google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 445 460 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 446 461 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 462 + google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 463 + google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 447 464 google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= 448 465 google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= 449 466 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+1 -1
js/app/package.json
··· 14 14 "build:web": "yarn run export && node exportClientExpoConfig.js > dist/expoConfig.json", 15 15 "export": "expo export || expo export", 16 16 "check": "npx tsc -p . --outFile $(mktemp)", 17 - "prebuild": "EXPO_NO_GIT_STATUS=1 expo prebuild --clean && sed -i.bak 's/org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m/org.gradle.jvmargs=-Xmx8192m -XX:MaxMetaspaceSize=2048m/' android/gradle.properties && echo '\nnetworkTimeout=100000' >> android/gradle.properties && yarn run find-node", 17 + "prebuild": "EXPO_NO_GIT_STATUS=1 expo prebuild --clean && sed -i.bak 's/org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m/org.gradle.jvmargs=-Xmx8192m -XX:MaxMetaspaceSize=2048m/' android/gradle.properties && echo '\nnetworkTimeout=100000' >> android/gradle.properties && sed -i.bak 's/plugins { id(\"com.facebook.react.settings\") }//' android/settings.gradle && yarn run find-node", 18 18 "postinstall": "which pod && yarn run postinstall-ios || echo 'not a mac, not installing pods'", 19 19 "postinstall-ios": "cd ios && pod install && yarn run find-node", 20 20 "find-node": "node -p '`NODE_BINARY=${process.argv[0]}`' > ios/.xcode.env.local",
+90 -27
meson.build
··· 1 - project('aquareum', 'c', 'cpp', 2 - default_options: [ 3 - 'cpp_std=c++98', 4 - 'default_library=static' 5 - ] 1 + project( 2 + 'aquareum', 3 + 'c', 4 + 'cpp', 5 + default_options: ['cpp_std=c++98', 'default_library=static'], 6 6 ) 7 7 8 - fs = import('fs') 8 + fs = import('fs') 9 9 10 10 prog_go = find_program('go') 11 11 12 - flagbuilder = custom_target('flagbuilder', 12 + flagbuilder = custom_target( 13 + 'flagbuilder', 13 14 input: ['pkg/config/git/git.go'], 14 15 output: ['flagbuilder'], 15 16 command: [prog_go, 'build', '-o', '@OUTPUT0@', '@INPUT@'], 16 17 build_always_stale: true, 17 18 ) 18 19 19 - flags = custom_target('flags', 20 + flags = custom_target( 21 + 'flags', 20 22 input: [], 21 23 output: ['build-flags.go'], 22 24 command: [flagbuilder, '-o', '@OUTPUT0@'], ··· 26 28 version_cmd = run_command(prog_go, 'run', 'pkg/config/git/git.go', '-v', check: true) 27 29 version = version_cmd.stdout().strip() 28 30 29 - aquareum_go = custom_target('aquareum.go', 30 - input : 'cmd/libaquareum/aquareum.go', 31 - output : 'aquareum.go', 32 - command : ['cp', '@INPUT@', '@OUTPUT@'], 31 + aquareum_go = custom_target( 32 + 'aquareum.go', 33 + input: 'cmd/libaquareum/aquareum.go', 34 + output: 'aquareum.go', 35 + command: ['cp', '@INPUT@', '@OUTPUT@'], 33 36 ) 34 37 35 - env = {} 38 + env = { 39 + 'PKG_CONFIG_PATH': meson.current_build_dir() + '/meson-private', 40 + 'CPATH': meson.current_source_dir() + '/subprojects/ffmpeg' + ':' + meson.current_build_dir() + '/subprojects/ffmpeg', 41 + } 36 42 GOOS = meson.get_external_property('GOOS', host_machine.system()) 37 43 GOARCH = meson.get_external_property('GOARCH', host_machine.cpu()) 38 44 if GOARCH == 'x86_64' ··· 42 48 GOARCH = 'arm64' 43 49 endif 44 50 if meson.is_cross_build() 45 - env = { 51 + env += { 46 52 'GOOS': GOOS, 47 53 'GOARCH': GOARCH, 48 54 'CGO_ENABLED': '1', 49 - 'CC': meson.get_compiler('c', native : false).cmd_array()[0], 55 + 'CC': meson.get_compiler('c', native: false).cmd_array()[0], 50 56 } 51 57 endif 52 - libaquareum = custom_target('libaquareum', 58 + 59 + c2pa_go_opts = {} 60 + triple = meson.get_external_property('RUST_TRIPLE', '') 61 + if triple != '' 62 + c2pa_go_opts += {'RUST_TRIPLE': triple} 63 + endif 64 + c2pa_go_proj = subproject( 65 + 'c2pa_go', 66 + default_options: c2pa_go_opts, 67 + ) 68 + c2pa_go_dep = c2pa_go_proj.get_variable('c2pa_go_dep') 69 + 70 + mistserver_proj = subproject( 71 + 'mistserver', 72 + default_options: { 73 + 'APPNAME': 'MistServer', 74 + }, 75 + ) 76 + mistserver = mistserver_proj.get_variable('libmistserver_dep') 77 + 78 + ffmpeg_proj = subproject( 79 + 'ffmpeg', 80 + # vvc seems to have problems building as a submodule? 81 + default_options: { 82 + 'vvc_decoder': 'disabled', 83 + 'vvc_demuxer': 'disabled', 84 + 'vvc_metadata_bsf': 'disabled', 85 + 'vvc_mp4toannexb_bsf': 'disabled', 86 + 'vvc_muxer': 'disabled', 87 + 'vvc_parser': 'disabled', 88 + 'signature_cuda_filter': 'enabled', 89 + 'signature_filter': 'enabled', 90 + 'gpl': 'enabled', 91 + }, 92 + ) 93 + avformat = ffmpeg_proj.get_variable('libavformat_dep') 94 + avfilter = ffmpeg_proj.get_variable('libavfilter_dep') 95 + 96 + libaquareum = custom_target( 97 + 'libaquareum', 53 98 input: [aquareum_go, flags], 54 99 output: ['aquareum.a', 'aquareum.h'], 55 - command: [prog_go, 'build', '-o', '@OUTPUT0@', '-buildmode', 'c-archive', '-tags', 'netgo', '@INPUT@'], 100 + command: [ 101 + prog_go, 102 + 'build', 103 + '-o', '@OUTPUT0@', 104 + '-buildmode', 'c-archive', 105 + '-tags', 'netgo', 106 + '@INPUT@', 107 + ], 56 108 build_always_stale: true, 57 - env: env 109 + env: env, 58 110 ) 59 111 60 - mistserver_proj = subproject('mistserver', default_options: { 61 - 'APPNAME': 'MistServer', 62 - }) 63 - mistserver = mistserver_proj.get_variable('libmistserver_dep') 64 - 65 112 aquareum_deps = [] 66 113 if host_machine.system() == 'darwin' 67 - aquareum_deps += [dependency('appleframeworks', modules : ['CoreFoundation', 'Security'])] 114 + aquareum_deps += [dependency('appleframeworks', modules: ['CoreFoundation', 'Security'])] 68 115 endif 69 116 aquareum = executable( 70 117 'aquareum', 71 118 ['cmd/aquareum/aquareum.c', libaquareum], 72 - dependencies: [mistserver, aquareum_deps] 119 + dependencies: [avformat, avfilter, mistserver, aquareum_deps], 120 + link_with: [c2pa_go_dep], 121 + ) 122 + 123 + if not meson.is_cross_build() 124 + test('go-tests', prog_go, 125 + depends: [aquareum], 126 + env: env, 127 + verbose: true, 128 + timeout: 0, 129 + args : [ 130 + 'test', 131 + '@0@/pkg/...'.format(meson.current_source_dir()), 132 + '@0@/cmd/...'.format(meson.current_source_dir()), 133 + ] 73 134 ) 135 + endif 74 136 75 137 prog_tar = find_program('tar') 76 138 # archive_name = aquareum-$(VERSION)-$$GOOS-$$GOARCH.tar.gz 77 139 archive_name = 'aquareum-' + version + '-' + GOOS + '-' + GOARCH + '.tar.gz' 78 - archive = custom_target('archive', 140 + custom_target( 141 + 'archive', 79 142 input: [aquareum], 80 143 output: [archive_name], 81 144 command: [prog_tar, '-czvf', '../bin/@OUTPUT0@', '@INPUT@'], 82 145 install: true, 83 146 install_dir: './bin', 84 147 build_by_default: false, 85 - ) 148 + )
+80
pkg/api/api_internal.go
··· 1 1 package api 2 2 3 3 import ( 4 + "bytes" 4 5 "context" 6 + "fmt" 5 7 "log/slog" 6 8 "net/http" 9 + "os" 10 + "path" 11 + "regexp" 12 + "strconv" 13 + "time" 7 14 15 + "aquareum.tv/aquareum/pkg/errors" 8 16 "aquareum.tv/aquareum/pkg/log" 17 + "aquareum.tv/aquareum/pkg/media" 18 + "aquareum.tv/aquareum/pkg/mist/mistconfig" 9 19 "aquareum.tv/aquareum/pkg/mist/misttriggers" 10 20 "github.com/julienschmidt/httprouter" 11 21 sloghttp "github.com/samber/slog-http" ··· 23 33 }) 24 34 } 25 35 36 + var segmentRE *regexp.Regexp 37 + 38 + func init() { 39 + segmentRE = regexp.MustCompile(`^\/segment\/([a-z0-9-\.]+)_([0-9]+)\/([0-9]+)\.ts$`) 40 + } 41 + 26 42 func (a *AquareumAPI) InternalHandler(ctx context.Context) (http.Handler, error) { 27 43 router := httprouter.New() 28 44 broker := misttriggers.NewTriggerBroker() 45 + broker.OnPushOutStart(func(ctx context.Context, payload *misttriggers.PushOutStartPayload) (string, error) { 46 + return payload.URL, nil 47 + }) 48 + broker.OnPushRewrite(func(ctx context.Context, payload *misttriggers.PushRewritePayload) (string, error) { 49 + log.Log(ctx, "got push out start", "streamName", payload.StreamName, "url", payload.URL.String()) 50 + 51 + ms := time.Now().UnixMilli() 52 + out := fmt.Sprintf("%s+%s_%d", mistconfig.STREAM_NAME, payload.StreamName, ms) 53 + 54 + return out, nil 55 + }) 29 56 triggerCollection := misttriggers.NewMistCallbackHandlersCollection(a.CLI, broker) 30 57 router.POST("/mist-trigger", triggerCollection.Trigger()) 58 + router.POST("/segment/*anything", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { 59 + log.Log(ctx, "segment start") 60 + ms := time.Now().UnixMilli() 61 + matches := segmentRE.FindStringSubmatch(r.URL.Path) 62 + if len(matches) != 4 { 63 + log.Log(ctx, "regex failed on /segment/url", "path", r.URL.Path) 64 + errors.WriteHTTPInternalServerError(w, "segment error", nil) 65 + return 66 + } 67 + user := matches[1] 68 + startTimeStr := matches[2] 69 + mediaTimeStr := matches[3] 70 + startTime, err := strconv.ParseInt(startTimeStr, 10, 64) 71 + if err != nil { 72 + log.Log(ctx, "error parsing number", "error", err) 73 + errors.WriteHTTPInternalServerError(w, "error parsing number", err) 74 + return 75 + } 76 + mediaTime, err := strconv.ParseInt(mediaTimeStr, 10, 64) 77 + if err != nil { 78 + log.Log(ctx, "error parsing number", "error", err) 79 + errors.WriteHTTPInternalServerError(w, "error parsing number", err) 80 + return 81 + } 82 + segmentTime := startTime + mediaTime 83 + drift := ms - segmentTime 84 + 85 + userDir := path.Join(a.CLI.DataDir, "segments", user) 86 + err = os.MkdirAll(userDir, 0700) 87 + if err != nil { 88 + log.Log(ctx, "error making directory", "error", err) 89 + errors.WriteHTTPInternalServerError(w, "directory create error", err) 90 + return 91 + } 92 + segmentFile := path.Join(userDir, fmt.Sprintf("%d.mp4", segmentTime)) 93 + f, err := os.Create(segmentFile) 94 + if err != nil { 95 + log.Log(ctx, "error opening file", "error", err) 96 + errors.WriteHTTPInternalServerError(w, "file open error", err) 97 + return 98 + } 99 + defer f.Close() 100 + buf := bytes.Buffer{} 101 + err = media.MuxToMP4(ctx, r.Body, &buf) 102 + reader := bytes.NewReader(buf.Bytes()) 103 + media.SignMP4(ctx, reader, f) 104 + if err != nil { 105 + log.Log(ctx, "segment error", "error", err) 106 + errors.WriteHTTPInternalServerError(w, "segment error", err) 107 + return 108 + } 109 + log.Log(ctx, "segment success", "url", r.URL.String(), "file", segmentFile, "drift", drift) 110 + }) 31 111 handler := sloghttp.Recovery(router) 32 112 handler = sloghttp.New(slog.Default())(handler) 33 113 return handler, nil
+1
pkg/api/api_test.go
··· 10 10 "aquareum.tv/aquareum/pkg/config" 11 11 "aquareum.tv/aquareum/pkg/crypto/signers/eip712" 12 12 "aquareum.tv/aquareum/pkg/crypto/signers/eip712/eip712test" 13 + _ "aquareum.tv/aquareum/pkg/media/mediatesting" 13 14 "aquareum.tv/aquareum/pkg/model" 14 15 v0 "aquareum.tv/aquareum/pkg/schema/v0" 15 16 "github.com/stretchr/testify/assert"
+40
pkg/cmd/aquareum.go
··· 1 1 package cmd 2 2 3 3 import ( 4 + "bufio" 4 5 "context" 5 6 "flag" 6 7 "fmt" 8 + "net/http" 7 9 "os" 8 10 "os/signal" 9 11 "runtime" 12 + "strings" 10 13 "syscall" 11 14 12 15 "aquareum.tv/aquareum/pkg/crypto/signers/eip712" ··· 24 27 25 28 // parse the CLI and fire up an aquareum node! 26 29 func Start(build *config.BuildFlags) error { 30 + if os.Args[1] == "slurp-file" { 31 + fs := flag.NewFlagSet("aquareum-slurp-file", flag.ExitOnError) 32 + inurl := fs.String("url", "", "Base URL to send slurped files to") 33 + fname := fs.String("file", "", "Name of this file we're uploading") 34 + ff.Parse( 35 + fs, os.Args[2:], 36 + ff.WithEnvVarPrefix("AQ"), 37 + ) 38 + *fname = strings.TrimPrefix(*fname, config.AQUAREUM_SCHEME_PREFIX) 39 + 40 + fullURL := fmt.Sprintf("%s/segment/%s", *inurl, *fname) 41 + 42 + reader := bufio.NewReader(os.Stdin) 43 + req, err := http.NewRequest("POST", fullURL, reader) 44 + if err != nil { 45 + panic(err) 46 + } 47 + client := &http.Client{} 48 + resp, err := client.Do(req) 49 + if err != nil { 50 + panic(err) 51 + } 52 + if resp.StatusCode != 200 { 53 + fmt.Printf("http %s\n", resp.Status) 54 + } 55 + os.Exit(0) 56 + } 27 57 err := normalizeXDG() 28 58 if err != nil { 29 59 return err ··· 43 73 } 44 74 dbFile = fmt.Sprintf("sqlite://%s", dbFile) 45 75 76 + defaultDataDir, err := config.DefaultDataDir() 77 + if err != nil { 78 + return err 79 + } 80 + 46 81 fs := flag.NewFlagSet("aquareum", flag.ExitOnError) 47 82 cli := config.CLI{Build: build} 48 83 fs.StringVar(&cli.HttpAddr, "http-addr", ":8080", "Public HTTP address") ··· 59 94 fs.IntVar(&cli.MistRTMPPort, "mist-rtmp-port", 11935, "MistServer RTMP port (internal use only)") 60 95 fs.IntVar(&cli.MistHTTPPort, "mist-http-port", 18080, "MistServer HTTP port (internal use only)") 61 96 fs.StringVar(&cli.GitLabURL, "gitlab-url", "https://git.aquareum.tv/api/v4/projects/1", "gitlab url for generating download links") 97 + fs.StringVar(&cli.DataDir, "data-dir", defaultDataDir, "directory for keeping all aquareum data") 62 98 version := fs.Bool("version", false, "print version and exit") 63 99 64 100 ff.Parse( ··· 77 113 return nil 78 114 } 79 115 116 + err = os.MkdirAll(cli.DataDir, os.ModePerm) 117 + if err != nil { 118 + return fmt.Errorf("error creating aquareum dir at %s:%w", cli.DataDir, err) 119 + } 80 120 schema, err := v0.MakeV0Schema() 81 121 if err != nil { 82 122 return err
+22 -10
pkg/config/config.go
··· 7 7 "fmt" 8 8 "net" 9 9 "os" 10 + "path" 10 11 "time" 11 12 12 13 "golang.org/x/exp/rand" ··· 29 30 } 30 31 31 32 type CLI struct { 32 - TLSCertPath string 33 - TLSKeyPath string 34 - SigningKeyPath string 33 + AdminAccount string 34 + Build *BuildFlags 35 + DataDir string 35 36 DBPath string 36 - Insecure bool 37 + FirebaseServiceAccount string 38 + GitLabURL string 37 39 HttpAddr string 38 - HttpsAddr string 39 40 HttpInternalAddr string 40 - GitLabURL string 41 - FirebaseServiceAccount string 42 - AdminAccount string 43 - Build *BuildFlags 41 + HttpsAddr string 42 + Insecure bool 44 43 MistAdminPort int 45 - MistRTMPPort int 46 44 MistHTTPPort int 45 + MistRTMPPort int 46 + SigningKeyPath string 47 + TLSCertPath string 48 + TLSKeyPath string 47 49 } 50 + 51 + var AQUAREUM_SCHEME_PREFIX = "aquareum://" 48 52 49 53 func (cli *CLI) OwnInternalURL() string { 50 54 // No errors because we know it's valid from AddrFlag ··· 82 86 } 83 87 return string(res) 84 88 } 89 + 90 + func DefaultDataDir() (string, error) { 91 + home, err := os.UserHomeDir() 92 + if err != nil { 93 + return "", fmt.Errorf("error finding default data dir: %w", err) 94 + } 95 + return path.Join(home, ".aquareum"), nil 96 + }
+6
pkg/log/log.go
··· 94 94 if !glog.V(v.level) { 95 95 return 96 96 } 97 + // I want a compile time assertion for this... but short of that let's be REALLY ANNOYING 98 + if len(args)%2 != 0 { 99 + for range 6 { 100 + fmt.Println("!!!!!!!!!!!!!!!! FOLLOWING LOG LINE HAS AN ODD NUMBER OF ARGUMENTS !!!!!!!!!!!!!!!!") 101 + } 102 + } 97 103 meta, _ := ctx.Value(clogContextKey).(metadata) 98 104 hasCaller := false 99 105
+151
pkg/media/media.go
··· 1 + package media 2 + 3 + import ( 4 + "context" 5 + "encoding/json" 6 + "fmt" 7 + "io" 8 + "os" 9 + "path/filepath" 10 + 11 + "aquareum.tv/aquareum/pkg/log" 12 + "github.com/livepeer/lpms/ffmpeg" 13 + "golang.org/x/sync/errgroup" 14 + 15 + "git.aquareum.tv/aquareum-tv/c2pa-go/pkg/c2pa" 16 + ) 17 + 18 + func MuxToMP4(ctx context.Context, input io.Reader, output io.Writer) error { 19 + tc := ffmpeg.NewTranscoder() 20 + ir, iw, err := os.Pipe() 21 + if err != nil { 22 + return fmt.Errorf("error opening pipe: %w", err) 23 + } 24 + dname, err := os.MkdirTemp("", "sampledir") 25 + if err != nil { 26 + return fmt.Errorf("error making temp directory: %w", err) 27 + } 28 + defer func() { 29 + os.RemoveAll(dname) 30 + log.Log(ctx, "cleaning up") 31 + tc.StopTranscoder() 32 + }() 33 + oname := filepath.Join(dname, "output.mp4") 34 + out := []ffmpeg.TranscodeOptions{ 35 + { 36 + Oname: oname, 37 + VideoEncoder: ffmpeg.ComponentOptions{ 38 + Name: "copy", 39 + }, 40 + AudioEncoder: ffmpeg.ComponentOptions{ 41 + Name: "copy", 42 + }, 43 + Profile: ffmpeg.VideoProfile{Format: ffmpeg.FormatNone}, 44 + Muxer: ffmpeg.ComponentOptions{ 45 + Name: "mp4", 46 + // main option is 'frag_keyframe' which tells ffmpeg to create fragmented MP4 (which we need to be able to stream generatd file) 47 + // other options is not mandatory but they will slightly improve generated MP4 file 48 + // Opts: map[string]string{"movflags": "frag_keyframe+negative_cts_offsets+omit_tfhd_offset+disable_chpl+default_base_moof"}, 49 + }, 50 + }, 51 + } 52 + iname := fmt.Sprintf("pipe:%d", ir.Fd()) 53 + in := &ffmpeg.TranscodeOptionsIn{Fname: iname, Transmuxing: true} 54 + g, _ := errgroup.WithContext(ctx) 55 + g.Go(func() error { 56 + _, err := io.Copy(iw, input) 57 + log.Log(ctx, "input copy done", "error", err) 58 + iw.Close() 59 + return err 60 + }) 61 + g.Go(func() error { 62 + _, err = tc.Transcode(in, out) 63 + log.Log(ctx, "transcode done", "error", err) 64 + tc.StopTranscoder() 65 + ir.Close() 66 + return err 67 + }) 68 + err = g.Wait() 69 + if err != nil { 70 + return err 71 + } 72 + of, err := os.Open(oname) 73 + if err != nil { 74 + return err 75 + } 76 + defer of.Close() 77 + of.WriteTo(output) 78 + return nil 79 + } 80 + 81 + var certBytes = []byte(`-----BEGIN CERTIFICATE----- 82 + MIIChDCCAiugAwIBAgIUBW/ByXEeQ0Qpgc6G1HYKjM2j6JcwCgYIKoZIzj0EAwIw 83 + gYwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJU29tZXdoZXJl 84 + MScwJQYDVQQKDB5DMlBBIFRlc3QgSW50ZXJtZWRpYXRlIFJvb3QgQ0ExGTAXBgNV 85 + BAsMEEZPUiBURVNUSU5HX09OTFkxGDAWBgNVBAMMD0ludGVybWVkaWF0ZSBDQTAe 86 + Fw0yNDA4MTEyMzM0NTZaFw0zNDA4MDkyMzM0NTZaMIGAMQswCQYDVQQGEwJVUzEL 87 + MAkGA1UECAwCQ0ExEjAQBgNVBAcMCVNvbWV3aGVyZTEfMB0GA1UECgwWQzJQQSBU 88 + ZXN0IFNpZ25pbmcgQ2VydDEZMBcGA1UECwwQRk9SIFRFU1RJTkdfT05MWTEUMBIG 89 + A1UEAwwLQzJQQSBTaWduZXIwVjAQBgcqhkjOPQIBBgUrgQQACgNCAAR1RJfnhmsE 90 + HUATmWV+p0fuOPl+G0TwZ5ZisGwWFA/J+fD6wjP6mW44Ob3TTMLMCCFfy5Gl5Cju 91 + XJru19UH0wVLo3gwdjAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUF 92 + BwMEMA4GA1UdDwEB/wQEAwIGwDAdBgNVHQ4EFgQUoEZwqyiVTYCOTjxn9MeCBDvk 93 + hecwHwYDVR0jBBgwFoAUP9auno3ORuwY1JnRQHu3RCiWgi0wCgYIKoZIzj0EAwID 94 + RwAwRAIgaOz0GFjrKWJMs2epuDqUOis7MsH0ivrPfonvwapYpfYCIBqOURwT+pYf 95 + W0VshLAxI/iVw/5eVXtDPZzCX0b0xq3f 96 + -----END CERTIFICATE----- 97 + -----BEGIN CERTIFICATE----- 98 + MIICZTCCAgygAwIBAgIUIiJUPMeqKEyhrHFdKsVYF6STAqAwCgYIKoZIzj0EAwIw 99 + dzELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlTb21ld2hlcmUx 100 + GjAYBgNVBAoMEUMyUEEgVGVzdCBSb290IENBMRkwFwYDVQQLDBBGT1IgVEVTVElO 101 + R19PTkxZMRAwDgYDVQQDDAdSb290IENBMB4XDTI0MDgxMTIzMzQ1NloXDTM0MDgw 102 + OTIzMzQ1NlowgYwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJDQTESMBAGA1UEBwwJ 103 + U29tZXdoZXJlMScwJQYDVQQKDB5DMlBBIFRlc3QgSW50ZXJtZWRpYXRlIFJvb3Qg 104 + Q0ExGTAXBgNVBAsMEEZPUiBURVNUSU5HX09OTFkxGDAWBgNVBAMMD0ludGVybWVk 105 + aWF0ZSBDQTBWMBAGByqGSM49AgEGBSuBBAAKA0IABMi5X2ELOtZ2i19DplQKEgAf 106 + Et6eCXpF+s4M57ak7Rd+1LzpQ+hlRXzvrpW6hLiO+ZaRTmQyqozgWwOBUm52rT2j 107 + YzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQ/ 108 + 1q6ejc5G7BjUmdFAe7dEKJaCLTAfBgNVHSMEGDAWgBSloXNM8yfsV/w3xH7H3pfj 109 + cfWj6jAKBggqhkjOPQQDAgNHADBEAiBievQIsuEy1I3p5XNtpHZ3MBifukoYwo/a 110 + 4ZXq8/VK7wIgMseui+Y0BFyDd+d3vd5Jy4d3uhpho6aNFln0qHbhFr8= 111 + -----END CERTIFICATE-----`) 112 + 113 + var keyBytes = []byte(`-----BEGIN PRIVATE KEY----- 114 + MIGEAgEAMBAGByqGSM49AgEGBSuBBAAKBG0wawIBAQQgKJyB05ZmsgeVQ/291hKX 115 + mLsopnxVDVAEYoL1vL1jglahRANCAAR1RJfnhmsEHUATmWV+p0fuOPl+G0TwZ5Zi 116 + sGwWFA/J+fD6wjP6mW44Ob3TTMLMCCFfy5Gl5CjuXJru19UH0wVL 117 + -----END PRIVATE KEY-----`) 118 + 119 + func SignMP4(ctx context.Context, input io.ReadSeeker, output io.Writer) error { 120 + manifestBs := []byte(` 121 + { 122 + "title": "Image File", 123 + "assertions": [ 124 + { 125 + "label": "c2pa.actions", 126 + "data": { "actions": [{ "action": "c2pa.published" }] } 127 + } 128 + ] 129 + } 130 + `) 131 + var manifest c2pa.ManifestDefinition 132 + err := json.Unmarshal(manifestBs, &manifest) 133 + if err != nil { 134 + return err 135 + } 136 + b, err := c2pa.NewBuilder(&manifest, &c2pa.BuilderParams{ 137 + Cert: certBytes, 138 + Key: keyBytes, 139 + Algorithm: "es256k", 140 + TAURL: "http://timestamp.digicert.com", 141 + }) 142 + if err != nil { 143 + return err 144 + } 145 + 146 + err = b.Sign(input, output, "video/mp4") 147 + if err != nil { 148 + return err 149 + } 150 + return nil 151 + }
+31
pkg/media/media_test.go
··· 1 + package media 2 + 3 + import ( 4 + "bufio" 5 + "bytes" 6 + "context" 7 + "os" 8 + "path/filepath" 9 + "runtime" 10 + "testing" 11 + 12 + _ "aquareum.tv/aquareum/pkg/media/mediatesting" 13 + "github.com/stretchr/testify/require" 14 + ) 15 + 16 + func getFixture(name string) string { 17 + _, filename, _, _ := runtime.Caller(0) 18 + dir := filepath.Dir(filename) 19 + return filepath.Join(dir, "..", "..", "test", "fixtures", name) 20 + } 21 + 22 + func TestMuxToMP4(t *testing.T) { 23 + f, err := os.Open(getFixture("video.mpegts")) 24 + require.NoError(t, err) 25 + defer f.Close() 26 + buf := bytes.Buffer{} 27 + w := bufio.NewWriter(&buf) 28 + err = MuxToMP4(context.Background(), f, w) 29 + require.NoError(t, err) 30 + require.Greater(t, len(buf.Bytes()), 0) 31 + }
+7
pkg/media/mediatesting/mediatesting.go
··· 1 + package mediatesting 2 + 3 + // This exists entirely to give a hardcoded list of LDFLAGS to the testing binary. 4 + // idk. There's probably a better way. 5 + 6 + // #cgo LDFLAGS: -L ../../../build/subprojects/ffmpeg -L ../../../build/subprojects/c2pa_go -lavcodec -lavfilter -lavformat -lavutil -lm -lpostproc -lswresample -lswscale -lz 7 + import "C"
+20 -2
pkg/mist/mistconfig/mistconfig.go
··· 4 4 "crypto/md5" 5 5 "encoding/json" 6 6 "fmt" 7 + "os" 7 8 8 9 "aquareum.tv/aquareum/pkg/config" 9 10 "aquareum.tv/aquareum/pkg/mist/misttriggers" 10 11 ) 11 12 13 + var STREAM_NAME = "stream" 14 + 12 15 func Generate(cli *config.CLI) ([]byte, error) { 16 + exec, err := os.Executable() 17 + if err != nil { 18 + return nil, fmt.Errorf("couldn't find my path for extwriter purposes: %w", err) 19 + } 13 20 triggers := map[string][]map[string]any{} 14 21 for name, blocking := range misttriggers.BlockingTriggers { 15 22 triggers[name] = []map[string]any{{ ··· 25 32 "password": md5.Sum([]byte("aquareum")), 26 33 }, 27 34 }, 35 + "autopushes": [][]any{{ 36 + fmt.Sprintf("%s+", STREAM_NAME), 37 + fmt.Sprintf("%s$wildcard/$currentMediaTime.ts?split=1&video=maxbps&audio=AAC&append=1", config.AQUAREUM_SCHEME_PREFIX), 38 + }}, 28 39 "bandwidth": map[string]any{ 29 40 "exceptions": []string{ 30 41 "::1", ··· 32 43 "10.0.0.0/8", 33 44 "192.168.0.0/16", 34 45 "172.16.0.0/12", 46 + }, 47 + }, 48 + "extwriters": [][]any{ 49 + { 50 + "aquareum", 51 + fmt.Sprintf("%s slurp-file --url=%s --file", exec, cli.OwnInternalURL()), 52 + []string{"aquareum"}, 35 53 }, 36 54 }, 37 55 "config": map[string]any{ ··· 80 98 "trustedproxy": []string{}, 81 99 }, 82 100 "streams": map[string]map[string]any{ 83 - "stream": { 84 - "name": "stream", 101 + STREAM_NAME: { 102 + "name": STREAM_NAME, 85 103 "segmentsize": 1, 86 104 "source": "push://", 87 105 "stop_sessions": false,
+3 -1
subprojects/.gitignore
··· 1 1 * 2 2 !.gitignore 3 - !mistserver.wrap 3 + !mistserver.wrap 4 + !ffmpeg.wrap 5 + !c2pa_go.wrap
+4
subprojects/c2pa_go.wrap
··· 1 + [wrap-git] 2 + url = https://git.aquareum.tv/aquareum-tv/c2pa-go.git 3 + revision = main 4 + depth = 1
+4
subprojects/ffmpeg.wrap
··· 1 + [wrap-git] 2 + url = https://git.aquareum.tv/aquareum-tv/ffmpeg.git 3 + revision = e092301689cc32607d79bee6c4c2cd59f1ffd496 4 + depth = 1
test/fixtures/video.mpegts

This is a binary file and will not be displayed.

+4
util/darwin-amd64-apple.ini
··· 1 1 [binaries] 2 2 c = 'clang' 3 3 cpp = 'clang++' 4 + objc = 'clang' 4 5 ; ar = 'llvm-ar' 5 6 ; strip = 'llvm-strip' 6 7 ··· 9 10 c_link_args = ['--target=x86_64-apple-darwin'] 10 11 cpp_args = ['--target=x86_64-apple-darwin'] 11 12 cpp_link_args = ['--target=x86_64-apple-darwin'] 13 + objc_args = ['--target=x86_64-apple-darwin'] 14 + objc_link_args = ['--target=x86_64-apple-darwin'] 12 15 objcpp_args = ['-arch', 'x86_64'] 13 16 objcpp_link_args = ['-arch', 'x86_64'] 14 17 ··· 21 24 [properties] 22 25 GOOS = 'darwin' 23 26 GOARCH = 'amd64' 27 + RUST_TRIPLE = 'x86_64-apple-darwin'
+1
util/linux-arm64-gnu.ini
··· 9 9 GOOS = 'linux' 10 10 GOARCH = 'arm64' 11 11 exe_wrapper = 'qemu-aarch64-static' 12 + RUST_TRIPLE = 'aarch64-unknown-linux-gnu' 12 13 13 14 [host_machine] 14 15 system = 'linux'