Compare commits
15 Commits
mobile/nat
...
fix/server
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d846f7fc7f | ||
|
|
efb4394c7b | ||
|
|
e2188867a6 | ||
|
|
5e32cc7bd5 | ||
|
|
1d55b5bfc0 | ||
|
|
60afd7b400 | ||
|
|
3f99ef90ec | ||
|
|
380fc06979 | ||
|
|
d34d92dca3 | ||
|
|
10f8e11db1 | ||
|
|
18b93ddc73 | ||
|
|
88ca1f31ad | ||
|
|
c30ef4dfd6 | ||
|
|
e851a9b099 | ||
|
|
e46db37e44 |
@@ -1,4 +1,4 @@
|
||||
FROM node:22.10.0-alpine3.20@sha256:fc95a044b87e95507c60c1f8c829e5d98ddf46401034932499db370c494ef0ff AS core
|
||||
FROM node:22.11.0-alpine3.20@sha256:f265794478aa0b1a23d85a492c8311ed795bc527c3fe7e43453b3c872dcd71a3 AS core
|
||||
|
||||
WORKDIR /usr/src/open-api/typescript-sdk
|
||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||
|
||||
10
cli/package-lock.json
generated
10
cli/package-lock.json
generated
@@ -24,7 +24,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
@@ -59,7 +59,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -1378,9 +1378,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz",
|
||||
"integrity": "sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
|
||||
34
e2e/package-lock.json
generated
34
e2e/package-lock.json
generated
@@ -15,7 +15,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
@@ -64,7 +64,7 @@
|
||||
"@types/cli-progress": "^3.11.0",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"@vitest/coverage-v8": "^2.0.5",
|
||||
@@ -99,7 +99,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -1613,9 +1613,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz",
|
||||
"integrity": "sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3294,9 +3294,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/exiftool-vendored": {
|
||||
"version": "28.6.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.6.0.tgz",
|
||||
"integrity": "sha512-Cx8/8ov1tKEacHhsi7FNYdisIhKq/SeQfprYSpYzwBuJwkPmCV8w7tTIvUJRQX9rvopXhBA4eBf1FPXqTZW5vA==",
|
||||
"version": "28.7.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.7.0.tgz",
|
||||
"integrity": "sha512-0zoq6kBS1yPjzJs+p0qZDinWEA72PTKoRk5ETYKfmeRcZAkhv83Y3HCpbb/LdgJJywfm8BcIJGezrBHvL7dVnQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -3307,14 +3307,14 @@
|
||||
"luxon": "^3.5.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"exiftool-vendored.exe": "12.97.0",
|
||||
"exiftool-vendored.pl": "12.97.0"
|
||||
"exiftool-vendored.exe": "12.99.0",
|
||||
"exiftool-vendored.pl": "12.99.0"
|
||||
}
|
||||
},
|
||||
"node_modules/exiftool-vendored.exe": {
|
||||
"version": "12.97.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.97.0.tgz",
|
||||
"integrity": "sha512-+HxyFigEJOtwRjP7PhEslhZKuVW2V0hvmHPHtbVtNKGfAUGcfc95xNTjASQfKJvc+9ZuvzdEBPkEQmyA/ZYdIw==",
|
||||
"version": "12.99.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.99.0.tgz",
|
||||
"integrity": "sha512-ffpJHCzC9OYJqw4JlPNtCwRy02jwhmnSJEF/QqEjpuIWDEnlRBQP/yWRh1Nw21K1R4FB4yG5PlCgEDu09VQz/w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
@@ -3323,9 +3323,9 @@
|
||||
]
|
||||
},
|
||||
"node_modules/exiftool-vendored.pl": {
|
||||
"version": "12.97.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.97.0.tgz",
|
||||
"integrity": "sha512-mXe9JEH3csfyPWcC7+H6IpfaokDMMr4S45n7MtiobGPdeeh+kFnf1SQ9cxg4sF403P6IKVeYYPbzgKMlpro9eQ==",
|
||||
"version": "12.99.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.99.0.tgz",
|
||||
"integrity": "sha512-qRVEPQxtoerXF+izJ0O7jGAr5o0Uyvnyu7ao5DTKzF+V7Fv3SurE0l43oCeZPFKo/Ld4V7vEylhFCm4IHVZKWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
"@immich/sdk": "file:../open-api/typescript-sdk",
|
||||
"@playwright/test": "^1.44.1",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@types/oidc-provider": "^8.5.1",
|
||||
"@types/pg": "^8.11.0",
|
||||
"@types/pngjs": "^6.0.4",
|
||||
|
||||
18
machine-learning/poetry.lock
generated
18
machine-learning/poetry.lock
generated
@@ -946,13 +946,13 @@ tqdm = ["tqdm"]
|
||||
|
||||
[[package]]
|
||||
name = "ftfy"
|
||||
version = "6.3.0"
|
||||
version = "6.3.1"
|
||||
description = "Fixes mojibake and other problems with Unicode, after the fact"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "ftfy-6.3.0-py3-none-any.whl", hash = "sha256:17aca296801f44142e3ff2c16f93fbf6a87609ebb3704a9a41dd5d4903396caf"},
|
||||
{file = "ftfy-6.3.0.tar.gz", hash = "sha256:1c7d6418e72b25a7760feb150acf574b86924dbb2e95b32c0b3abbd1ba3d7ad6"},
|
||||
{file = "ftfy-6.3.1-py3-none-any.whl", hash = "sha256:7c70eb532015cd2f9adb53f101fb6c7945988d023a085d127d1573dc49dd0083"},
|
||||
{file = "ftfy-6.3.1.tar.gz", hash = "sha256:9b3c3d90f84fb267fe64d375a07b7f8912d817cf86009ae134aa03e1819506ec"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1609,13 +1609,13 @@ test = ["pytest (>=7.4)", "pytest-cov (>=4.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "locust"
|
||||
version = "2.32.0"
|
||||
version = "2.32.1"
|
||||
description = "Developer-friendly load testing framework"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "locust-2.32.0-py3-none-any.whl", hash = "sha256:e004514332b8631ca91382d11d224baee4ced040c5f5c8b2233800ebcbc73c0e"},
|
||||
{file = "locust-2.32.0.tar.gz", hash = "sha256:d8f7f5d9d4e801b2e7b0ee3f31109333673da744ccedf85e7da0151f2d263dd9"},
|
||||
{file = "locust-2.32.1-py3-none-any.whl", hash = "sha256:3fb5548b4f2b6477fa5229ee55ac3dddbae56e86c3430bf2ba3fee358eb7e7bb"},
|
||||
{file = "locust-2.32.1.tar.gz", hash = "sha256:8c3b1094dbf20860fd2f6e26b68f0c6064dc28054f4462664389d102fce1448b"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -2749,13 +2749,13 @@ cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-multipart"
|
||||
version = "0.0.12"
|
||||
version = "0.0.17"
|
||||
description = "A streaming multipart parser for Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf"},
|
||||
{file = "python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb"},
|
||||
{file = "python_multipart-0.0.17-py3-none-any.whl", hash = "sha256:15dc4f487e0a9476cc1201261188ee0940165cffc94429b6fc565c4d3045cb5d"},
|
||||
{file = "python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
8
open-api/typescript-sdk/package-lock.json
generated
8
open-api/typescript-sdk/package-lock.json
generated
@@ -12,7 +12,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
},
|
||||
@@ -22,9 +22,9 @@
|
||||
"integrity": "sha512-8tKiYffhwTGHSHYGnZ3oneLGCjX0po/XAXQ5Ng9fqKkvIdl/xz8+Vh8i+6xjzZqvZ2pLVpUcuSfnvNI/x67L0g=="
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz",
|
||||
"integrity": "sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
"@oazapfts/runtime": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"typescript": "^5.3.3"
|
||||
},
|
||||
"repository": {
|
||||
|
||||
@@ -25,7 +25,7 @@ COPY --from=dev /usr/src/app/node_modules/@img ./node_modules/@img
|
||||
COPY --from=dev /usr/src/app/node_modules/exiftool-vendored.pl ./node_modules/exiftool-vendored.pl
|
||||
|
||||
# web build
|
||||
FROM node:22.10.0-alpine3.20@sha256:fc95a044b87e95507c60c1f8c829e5d98ddf46401034932499db370c494ef0ff AS web
|
||||
FROM node:22.11.0-alpine3.20@sha256:f265794478aa0b1a23d85a492c8311ed795bc527c3fe7e43453b3c872dcd71a3 AS web
|
||||
|
||||
WORKDIR /usr/src/open-api/typescript-sdk
|
||||
COPY open-api/typescript-sdk/package*.json open-api/typescript-sdk/tsconfig*.json ./
|
||||
|
||||
58
server/package-lock.json
generated
58
server/package-lock.json
generated
@@ -83,7 +83,7 @@
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/picomatch": "^3.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
@@ -5110,9 +5110,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz",
|
||||
"integrity": "sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"dependencies": {
|
||||
"undici-types": "~6.19.8"
|
||||
}
|
||||
@@ -8236,9 +8236,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/exiftool-vendored": {
|
||||
"version": "28.6.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.6.0.tgz",
|
||||
"integrity": "sha512-Cx8/8ov1tKEacHhsi7FNYdisIhKq/SeQfprYSpYzwBuJwkPmCV8w7tTIvUJRQX9rvopXhBA4eBf1FPXqTZW5vA==",
|
||||
"version": "28.7.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.7.0.tgz",
|
||||
"integrity": "sha512-0zoq6kBS1yPjzJs+p0qZDinWEA72PTKoRk5ETYKfmeRcZAkhv83Y3HCpbb/LdgJJywfm8BcIJGezrBHvL7dVnQ==",
|
||||
"dependencies": {
|
||||
"@photostructure/tz-lookup": "^11.0.0",
|
||||
"@types/luxon": "^3.4.2",
|
||||
@@ -8247,23 +8247,23 @@
|
||||
"luxon": "^3.5.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"exiftool-vendored.exe": "12.97.0",
|
||||
"exiftool-vendored.pl": "12.97.0"
|
||||
"exiftool-vendored.exe": "12.99.0",
|
||||
"exiftool-vendored.pl": "12.99.0"
|
||||
}
|
||||
},
|
||||
"node_modules/exiftool-vendored.exe": {
|
||||
"version": "12.97.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.97.0.tgz",
|
||||
"integrity": "sha512-+HxyFigEJOtwRjP7PhEslhZKuVW2V0hvmHPHtbVtNKGfAUGcfc95xNTjASQfKJvc+9ZuvzdEBPkEQmyA/ZYdIw==",
|
||||
"version": "12.99.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.99.0.tgz",
|
||||
"integrity": "sha512-ffpJHCzC9OYJqw4JlPNtCwRy02jwhmnSJEF/QqEjpuIWDEnlRBQP/yWRh1Nw21K1R4FB4yG5PlCgEDu09VQz/w==",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/exiftool-vendored.pl": {
|
||||
"version": "12.97.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.97.0.tgz",
|
||||
"integrity": "sha512-mXe9JEH3csfyPWcC7+H6IpfaokDMMr4S45n7MtiobGPdeeh+kFnf1SQ9cxg4sF403P6IKVeYYPbzgKMlpro9eQ==",
|
||||
"version": "12.99.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.99.0.tgz",
|
||||
"integrity": "sha512-qRVEPQxtoerXF+izJ0O7jGAr5o0Uyvnyu7ao5DTKzF+V7Fv3SurE0l43oCeZPFKo/Ld4V7vEylhFCm4IHVZKWA==",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"!win32"
|
||||
@@ -18258,9 +18258,9 @@
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "22.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.8.5.tgz",
|
||||
"integrity": "sha512-5iYk6AMPtsMbkZqCO1UGF9W5L38twq11S2pYWkybGHH2ogPUvXWNlQqJBzuEZWKj/WRH+QTeiv6ySWqJtvIEgA==",
|
||||
"version": "22.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz",
|
||||
"integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==",
|
||||
"requires": {
|
||||
"undici-types": "~6.19.8"
|
||||
}
|
||||
@@ -20579,29 +20579,29 @@
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
|
||||
},
|
||||
"exiftool-vendored": {
|
||||
"version": "28.6.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.6.0.tgz",
|
||||
"integrity": "sha512-Cx8/8ov1tKEacHhsi7FNYdisIhKq/SeQfprYSpYzwBuJwkPmCV8w7tTIvUJRQX9rvopXhBA4eBf1FPXqTZW5vA==",
|
||||
"version": "28.7.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored/-/exiftool-vendored-28.7.0.tgz",
|
||||
"integrity": "sha512-0zoq6kBS1yPjzJs+p0qZDinWEA72PTKoRk5ETYKfmeRcZAkhv83Y3HCpbb/LdgJJywfm8BcIJGezrBHvL7dVnQ==",
|
||||
"requires": {
|
||||
"@photostructure/tz-lookup": "^11.0.0",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"batch-cluster": "^13.0.0",
|
||||
"exiftool-vendored.exe": "12.97.0",
|
||||
"exiftool-vendored.pl": "12.97.0",
|
||||
"exiftool-vendored.exe": "12.99.0",
|
||||
"exiftool-vendored.pl": "12.99.0",
|
||||
"he": "^1.2.0",
|
||||
"luxon": "^3.5.0"
|
||||
}
|
||||
},
|
||||
"exiftool-vendored.exe": {
|
||||
"version": "12.97.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.97.0.tgz",
|
||||
"integrity": "sha512-+HxyFigEJOtwRjP7PhEslhZKuVW2V0hvmHPHtbVtNKGfAUGcfc95xNTjASQfKJvc+9ZuvzdEBPkEQmyA/ZYdIw==",
|
||||
"version": "12.99.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.exe/-/exiftool-vendored.exe-12.99.0.tgz",
|
||||
"integrity": "sha512-ffpJHCzC9OYJqw4JlPNtCwRy02jwhmnSJEF/QqEjpuIWDEnlRBQP/yWRh1Nw21K1R4FB4yG5PlCgEDu09VQz/w==",
|
||||
"optional": true
|
||||
},
|
||||
"exiftool-vendored.pl": {
|
||||
"version": "12.97.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.97.0.tgz",
|
||||
"integrity": "sha512-mXe9JEH3csfyPWcC7+H6IpfaokDMMr4S45n7MtiobGPdeeh+kFnf1SQ9cxg4sF403P6IKVeYYPbzgKMlpro9eQ==",
|
||||
"version": "12.99.0",
|
||||
"resolved": "https://registry.npmjs.org/exiftool-vendored.pl/-/exiftool-vendored.pl-12.99.0.tgz",
|
||||
"integrity": "sha512-qRVEPQxtoerXF+izJ0O7jGAr5o0Uyvnyu7ao5DTKzF+V7Fv3SurE0l43oCeZPFKo/Ld4V7vEylhFCm4IHVZKWA==",
|
||||
"optional": true
|
||||
},
|
||||
"express": {
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
"@types/lodash": "^4.14.197",
|
||||
"@types/mock-fs": "^4.13.1",
|
||||
"@types/multer": "^1.4.7",
|
||||
"@types/node": "^22.8.1",
|
||||
"@types/node": "^22.8.5",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/picomatch": "^3.0.0",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
|
||||
@@ -31,11 +31,23 @@ describe(SearchService.name, () => {
|
||||
|
||||
describe('getDuplicates', () => {
|
||||
it('should get duplicates', async () => {
|
||||
assetMock.getDuplicates.mockResolvedValue([assetStub.hasDupe]);
|
||||
assetMock.getDuplicates.mockResolvedValue([assetStub.hasDupe, assetStub.hasDupe]);
|
||||
await expect(sut.getDuplicates(authStub.admin)).resolves.toEqual([
|
||||
{ duplicateId: assetStub.hasDupe.duplicateId, assets: [expect.objectContaining({ id: assetStub.hasDupe.id })] },
|
||||
{
|
||||
duplicateId: assetStub.hasDupe.duplicateId,
|
||||
assets: [
|
||||
expect.objectContaining({ id: assetStub.hasDupe.id }),
|
||||
expect.objectContaining({ id: assetStub.hasDupe.id }),
|
||||
],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should update assets with duplicateId', async () => {
|
||||
assetMock.getDuplicates.mockResolvedValue([assetStub.hasDupe]);
|
||||
await expect(sut.getDuplicates(authStub.admin)).resolves.toEqual([]);
|
||||
expect(assetMock.updateAll).toHaveBeenCalledWith([assetStub.hasDupe.id], { duplicateId: null });
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleQueueSearchDuplicates', () => {
|
||||
|
||||
@@ -16,8 +16,24 @@ import { usePagination } from 'src/utils/pagination';
|
||||
export class DuplicateService extends BaseService {
|
||||
async getDuplicates(auth: AuthDto): Promise<DuplicateResponseDto[]> {
|
||||
const res = await this.assetRepository.getDuplicates({ userIds: [auth.user.id] });
|
||||
|
||||
return mapDuplicateResponse(res.map((a) => mapAsset(a, { auth, withStack: true })));
|
||||
const uniqueAssetIds: string[] = [];
|
||||
const duplicates = mapDuplicateResponse(res.map((a) => mapAsset(a, { auth, withStack: true }))).filter(
|
||||
(duplicate) => {
|
||||
if (duplicate.assets.length === 1) {
|
||||
uniqueAssetIds.push(duplicate.assets[0].id);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
);
|
||||
if (uniqueAssetIds.length > 0) {
|
||||
try {
|
||||
await this.assetRepository.updateAll(uniqueAssetIds, { duplicateId: null });
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Failed to remove duplicateId from assets: ${error.message}`);
|
||||
}
|
||||
}
|
||||
return duplicates;
|
||||
}
|
||||
|
||||
@OnJob({ name: JobName.QUEUE_DUPLICATE_DETECTION, queue: QueueName.DUPLICATE_DETECTION })
|
||||
|
||||
@@ -2133,7 +2133,7 @@ describe(MediaService.name, () => {
|
||||
'-map 0:1',
|
||||
'-g 256',
|
||||
'-v verbose',
|
||||
'-vf scale_rkrga=-2:720:format=nv12:afbc=1',
|
||||
'-vf scale_rkrga=-2:720:format=nv12:afbc=1:async_depth=4',
|
||||
'-level 51',
|
||||
'-rc_mode CQP',
|
||||
'-qp_init 23',
|
||||
@@ -2204,7 +2204,7 @@ describe(MediaService.name, () => {
|
||||
inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']),
|
||||
outputOptions: expect.arrayContaining([
|
||||
expect.stringContaining(
|
||||
'scale_rkrga=-2:720:format=p010:afbc=1,hwmap=derive_device=opencl:mode=read,tonemap_opencl=format=nv12:r=pc:p=bt709:t=bt709:m=bt709:tonemap=hable:desat=0:tonemap_mode=lum:peak=100,hwmap=derive_device=rkmpp:mode=write:reverse=1,format=drm_prime',
|
||||
'scale_rkrga=-2:720:format=p010:afbc=1:async_depth=4,hwmap=derive_device=opencl:mode=read,tonemap_opencl=format=nv12:r=pc:p=bt709:t=bt709:m=bt709:tonemap=hable:desat=0:tonemap_mode=lum:peak=100,hwmap=derive_device=rkmpp:mode=write:reverse=1,format=drm_prime',
|
||||
),
|
||||
]),
|
||||
twoPass: false,
|
||||
@@ -2212,6 +2212,28 @@ describe(MediaService.name, () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should set hardware decoding options for rkmpp when hardware decoding is enabled with no OpenCL on non-HDR file', async () => {
|
||||
storageMock.readdir.mockResolvedValue(['renderD128']);
|
||||
storageMock.stat.mockResolvedValue({ isFile: () => false, isCharacterDevice: () => false } as Stats);
|
||||
mediaMock.probe.mockResolvedValue(probeStub.noAudioStreams);
|
||||
systemMock.get.mockResolvedValue({
|
||||
ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: true, crf: 30, maxBitrate: '0' },
|
||||
});
|
||||
assetMock.getByIds.mockResolvedValue([assetStub.video]);
|
||||
await sut.handleVideoConversion({ id: assetStub.video.id });
|
||||
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
||||
'/original/path.ext',
|
||||
'upload/encoded-video/user-id/as/se/asset-id.mp4',
|
||||
expect.objectContaining({
|
||||
inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']),
|
||||
outputOptions: expect.arrayContaining([
|
||||
expect.stringContaining('scale_rkrga=-2:720:format=nv12:afbc=1:async_depth=4'),
|
||||
]),
|
||||
twoPass: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should use software decoding and tone-mapping if hardware decoding is disabled', async () => {
|
||||
storageMock.readdir.mockResolvedValue(['renderD128']);
|
||||
storageMock.stat.mockResolvedValue({ isFile: () => true, isCharacterDevice: () => true } as Stats);
|
||||
@@ -2236,7 +2258,7 @@ describe(MediaService.name, () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should use software decoding and tone-mapping if opencl is not available', async () => {
|
||||
it('should use software tone-mapping if opencl is not available', async () => {
|
||||
storageMock.readdir.mockResolvedValue(['renderD128']);
|
||||
storageMock.stat.mockResolvedValue({ isFile: () => false, isCharacterDevice: () => false } as Stats);
|
||||
mediaMock.probe.mockResolvedValue(probeStub.videoStreamHDR);
|
||||
@@ -2249,7 +2271,7 @@ describe(MediaService.name, () => {
|
||||
'/original/path.ext',
|
||||
'upload/encoded-video/user-id/as/se/asset-id.mp4',
|
||||
expect.objectContaining({
|
||||
inputOptions: [],
|
||||
inputOptions: expect.any(Array),
|
||||
outputOptions: expect.arrayContaining([
|
||||
expect.stringContaining(
|
||||
'tonemapx=tonemap=hable:desat=0:p=bt709:t=bt709:m=bt709:r=pc:peak=100:format=yuv420p',
|
||||
|
||||
@@ -329,9 +329,11 @@ export class MediaService extends BaseService {
|
||||
}
|
||||
|
||||
if (ffmpeg.accel === TranscodeHWAccel.DISABLED) {
|
||||
this.logger.log(`Encoding video ${asset.id} without hardware acceleration`);
|
||||
this.logger.log(`Transcoding video ${asset.id} without hardware acceleration`);
|
||||
} else {
|
||||
this.logger.log(`Encoding video ${asset.id} with ${ffmpeg.accel.toUpperCase()} acceleration`);
|
||||
this.logger.log(
|
||||
`Transcoding video ${asset.id} with ${ffmpeg.accel.toUpperCase()}-accelerated encoding and${ffmpeg.accelDecode ? '' : ' software'} decoding`,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -341,10 +343,26 @@ export class MediaService extends BaseService {
|
||||
if (ffmpeg.accel === TranscodeHWAccel.DISABLED) {
|
||||
return JobStatus.FAILED;
|
||||
}
|
||||
this.logger.error(`Retrying with ${ffmpeg.accel.toUpperCase()} acceleration disabled`);
|
||||
const config = BaseConfig.create({ ...ffmpeg, accel: TranscodeHWAccel.DISABLED });
|
||||
command = config.getCommand(target, mainVideoStream, mainAudioStream);
|
||||
await this.mediaRepository.transcode(input, output, command);
|
||||
|
||||
let partialFallbackSuccess = false;
|
||||
if (ffmpeg.accelDecode) {
|
||||
try {
|
||||
this.logger.error(`Retrying with ${ffmpeg.accel.toUpperCase()}-accelerated encoding and software decoding`);
|
||||
const config = BaseConfig.create({ ...ffmpeg, accelDecode: false });
|
||||
command = config.getCommand(target, mainVideoStream, mainAudioStream);
|
||||
await this.mediaRepository.transcode(input, output, command);
|
||||
partialFallbackSuccess = true;
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error occurred during transcoding: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!partialFallbackSuccess) {
|
||||
this.logger.error(`Retrying with ${ffmpeg.accel.toUpperCase()} acceleration disabled`);
|
||||
const config = BaseConfig.create({ ...ffmpeg, accel: TranscodeHWAccel.DISABLED });
|
||||
command = config.getCommand(target, mainVideoStream, mainAudioStream);
|
||||
await this.mediaRepository.transcode(input, output, command);
|
||||
}
|
||||
}
|
||||
|
||||
this.logger.log(`Successfully encoded ${asset.id}`);
|
||||
@@ -502,7 +520,7 @@ export class MediaService extends BaseService {
|
||||
const maliDeviceStat = await this.storageRepository.stat('/dev/mali0');
|
||||
this.maliOpenCL = maliIcdStat.isFile() && maliDeviceStat.isCharacterDevice();
|
||||
} catch {
|
||||
this.logger.debug('OpenCL not available for transcoding, so RKMPP acceleration will use CPU decoding');
|
||||
this.logger.debug('OpenCL not available for transcoding, so RKMPP acceleration will use CPU tonemapping');
|
||||
this.maliOpenCL = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +58,9 @@ export class BaseConfig implements VideoCodecSWConfig {
|
||||
break;
|
||||
}
|
||||
case TranscodeHWAccel.RKMPP: {
|
||||
handler =
|
||||
config.accelDecode && hasMaliOpenCL
|
||||
? new RkmppHwDecodeConfig(config, devices)
|
||||
: new RkmppSwDecodeConfig(config, devices);
|
||||
handler = config.accelDecode
|
||||
? new RkmppHwDecodeConfig(config, devices, hasMaliOpenCL)
|
||||
: new RkmppSwDecodeConfig(config, devices);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -327,6 +326,32 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
|
||||
this.devices = this.validateDevices(devices);
|
||||
}
|
||||
|
||||
getScalingFilter(videoStream: VideoStreamInfo, format: string) {
|
||||
return `scale_${this.config.accel}=${this.getScaling(videoStream)}:format=${format}`;
|
||||
}
|
||||
|
||||
getHwDecodeFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = [];
|
||||
const tonemapOptions = this.getToneMapping(videoStream);
|
||||
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
|
||||
const format = tonemapOptions.length === 0 ? 'nv12' : 'p010';
|
||||
options.push(this.getScalingFilter(videoStream, format));
|
||||
} else if (tonemapOptions.length > 0) {
|
||||
options.push('format=p010');
|
||||
}
|
||||
options.push(...tonemapOptions);
|
||||
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
||||
options.push('format=nv12');
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
return this.config.accelDecode
|
||||
? this.getHwDecodeFilterOptions(videoStream)
|
||||
: [`hwupload_${this.config.accel}`, ...this.getHwDecodeFilterOptions(videoStream)];
|
||||
}
|
||||
|
||||
getSupportedCodecs() {
|
||||
return [VideoCodec.H264, VideoCodec.HEVC];
|
||||
}
|
||||
@@ -370,6 +395,20 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
|
||||
|
||||
return `/dev/dri/${deviceName}`;
|
||||
}
|
||||
|
||||
getInputThreadOptions() {
|
||||
if (this.config.accelDecode) {
|
||||
return [`-threads 1`];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
getOutputThreadOptions() {
|
||||
if (this.config.accelDecode) {
|
||||
return [];
|
||||
}
|
||||
return super.getOutputThreadOptions();
|
||||
}
|
||||
}
|
||||
|
||||
export class ThumbnailConfig extends BaseConfig {
|
||||
@@ -504,15 +543,11 @@ export class AV1Config extends BaseConfig {
|
||||
}
|
||||
}
|
||||
|
||||
export class NvencSwDecodeConfig extends BaseHWConfig {
|
||||
export class NvencConfig extends BaseHWConfig {
|
||||
getSupportedCodecs() {
|
||||
return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.AV1];
|
||||
}
|
||||
|
||||
getBaseInputOptions() {
|
||||
return ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'];
|
||||
}
|
||||
|
||||
getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) {
|
||||
const options = [
|
||||
// below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding
|
||||
@@ -531,16 +566,6 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
|
||||
return options;
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = this.getToneMapping(videoStream);
|
||||
options.push('hwupload_cuda');
|
||||
if (this.shouldScale(videoStream)) {
|
||||
options.push(`scale_cuda=${this.getScaling(videoStream)}:format=nv12`);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
getPresetOptions() {
|
||||
let presetIndex = this.getPresetIndex();
|
||||
if (presetIndex < 0) {
|
||||
@@ -570,10 +595,6 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
|
||||
}
|
||||
}
|
||||
|
||||
getThreadOptions() {
|
||||
return [];
|
||||
}
|
||||
|
||||
getRefs() {
|
||||
const bframes = this.getBFrames();
|
||||
if (bframes > 0 && bframes < 3 && this.config.refs < 3) {
|
||||
@@ -581,27 +602,14 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
|
||||
}
|
||||
return this.config.refs;
|
||||
}
|
||||
}
|
||||
|
||||
export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
|
||||
getBaseInputOptions() {
|
||||
if (!this.config.accelDecode) {
|
||||
return ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'];
|
||||
}
|
||||
return ['-hwaccel cuda', '-hwaccel_output_format cuda', '-noautorotate', ...this.getInputThreadOptions()];
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = [];
|
||||
if (this.shouldScale(videoStream)) {
|
||||
options.push(`scale_cuda=${this.getScaling(videoStream)}`);
|
||||
}
|
||||
options.push(...this.getToneMapping(videoStream));
|
||||
if (options.length > 0) {
|
||||
options[options.length - 1] += ':format=nv12';
|
||||
} else if (!videoStream.pixelFormat.endsWith('420p')) {
|
||||
options.push('format=nv12');
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
getToneMapping(videoStream: VideoStreamInfo) {
|
||||
if (!this.shouldToneMap(videoStream)) {
|
||||
return [];
|
||||
@@ -617,28 +625,36 @@ export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
|
||||
'tonemap_mode=lum',
|
||||
`transfer=${transfer}`,
|
||||
'peak=100',
|
||||
'format=nv12',
|
||||
];
|
||||
|
||||
return [`tonemap_cuda=${tonemapOptions.join(':')}`];
|
||||
}
|
||||
|
||||
getInputThreadOptions() {
|
||||
return [`-threads 1`];
|
||||
}
|
||||
|
||||
getOutputThreadOptions() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export class QsvSwDecodeConfig extends BaseHWConfig {
|
||||
export class QsvConfig extends BaseHWConfig {
|
||||
getBaseInputOptions() {
|
||||
if (this.devices.length === 0) {
|
||||
throw new Error('No QSV device found');
|
||||
}
|
||||
|
||||
let qsvString = '';
|
||||
const hwDevice = this.getPreferredHardwareDevice();
|
||||
if (this.config.accelDecode) {
|
||||
const options = [
|
||||
'-hwaccel qsv',
|
||||
'-hwaccel_output_format qsv',
|
||||
'-async_depth 4',
|
||||
'-noautorotate',
|
||||
...this.getInputThreadOptions(),
|
||||
];
|
||||
if (hwDevice) {
|
||||
options.push(`-qsv_device ${hwDevice}`);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
let qsvString = '';
|
||||
if (hwDevice) {
|
||||
qsvString = `,child_device=${hwDevice}`;
|
||||
}
|
||||
@@ -655,15 +671,6 @@ export class QsvSwDecodeConfig extends BaseHWConfig {
|
||||
return options;
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = this.getToneMapping(videoStream);
|
||||
options.push('hwupload=extra_hw_frames=64');
|
||||
if (this.shouldScale(videoStream)) {
|
||||
options.push(`scale_qsv=${this.getScaling(videoStream)}:mode=hq:format=nv12`);
|
||||
}
|
||||
return options;
|
||||
}
|
||||
|
||||
getPresetOptions() {
|
||||
let presetIndex = this.getPresetIndex();
|
||||
if (presetIndex < 0) {
|
||||
@@ -709,44 +716,9 @@ export class QsvSwDecodeConfig extends BaseHWConfig {
|
||||
getScaling(videoStream: VideoStreamInfo): string {
|
||||
return super.getScaling(videoStream, 1);
|
||||
}
|
||||
}
|
||||
|
||||
export class QsvHwDecodeConfig extends QsvSwDecodeConfig {
|
||||
getBaseInputOptions() {
|
||||
if (this.devices.length === 0) {
|
||||
throw new Error('No QSV device found');
|
||||
}
|
||||
|
||||
const options = [
|
||||
'-hwaccel qsv',
|
||||
'-hwaccel_output_format qsv',
|
||||
'-async_depth 4',
|
||||
'-noautorotate',
|
||||
...this.getInputThreadOptions(),
|
||||
];
|
||||
const hwDevice = this.getPreferredHardwareDevice();
|
||||
if (hwDevice) {
|
||||
options.push(`-qsv_device ${hwDevice}`);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = [];
|
||||
const tonemapOptions = this.getToneMapping(videoStream);
|
||||
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
|
||||
let scaling = `scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq`;
|
||||
if (tonemapOptions.length === 0) {
|
||||
scaling += ':format=nv12';
|
||||
}
|
||||
options.push(scaling);
|
||||
}
|
||||
options.push(...tonemapOptions);
|
||||
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
||||
options.push('format=nv12');
|
||||
}
|
||||
return options;
|
||||
getScalingFilter(videoStream: VideoStreamInfo, format: string) {
|
||||
return `scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq:format=${format}`;
|
||||
}
|
||||
|
||||
getToneMapping(videoStream: VideoStreamInfo): string[] {
|
||||
@@ -773,19 +745,27 @@ export class QsvHwDecodeConfig extends QsvSwDecodeConfig {
|
||||
'hwmap=derive_device=qsv:reverse=1,format=qsv',
|
||||
];
|
||||
}
|
||||
|
||||
getInputThreadOptions() {
|
||||
return [`-threads 1`];
|
||||
}
|
||||
}
|
||||
|
||||
export class VaapiSwDecodeConfig extends BaseHWConfig {
|
||||
export class VaapiConfig extends BaseHWConfig {
|
||||
getBaseInputOptions() {
|
||||
if (this.devices.length === 0) {
|
||||
throw new Error('No VAAPI device found');
|
||||
}
|
||||
|
||||
let hwDevice = this.getPreferredHardwareDevice();
|
||||
if (this.config.accelDecode) {
|
||||
const options = [
|
||||
'-hwaccel vaapi',
|
||||
'-hwaccel_output_format vaapi',
|
||||
'-noautorotate',
|
||||
...this.getInputThreadOptions(),
|
||||
];
|
||||
if (hwDevice) {
|
||||
options.push(`-hwaccel_device ${hwDevice}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hwDevice) {
|
||||
hwDevice = `/dev/dri/${this.devices[0]}`;
|
||||
}
|
||||
@@ -793,16 +773,6 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
|
||||
return [`-init_hw_device vaapi=accel:${hwDevice}`, '-filter_hw_device accel'];
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = this.getToneMapping(videoStream);
|
||||
options.push('hwupload=extra_hw_frames=64');
|
||||
if (this.shouldScale(videoStream)) {
|
||||
options.push(`scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc:format=nv12`);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
getPresetOptions() {
|
||||
let presetIndex = this.getPresetIndex();
|
||||
if (presetIndex < 0) {
|
||||
@@ -844,43 +814,9 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
|
||||
useCQP() {
|
||||
return this.config.cqMode !== CQMode.ICQ || this.config.targetVideoCodec === VideoCodec.VP9;
|
||||
}
|
||||
}
|
||||
|
||||
export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig {
|
||||
getBaseInputOptions() {
|
||||
if (this.devices.length === 0) {
|
||||
throw new Error('No VAAPI device found');
|
||||
}
|
||||
|
||||
const options = [
|
||||
'-hwaccel vaapi',
|
||||
'-hwaccel_output_format vaapi',
|
||||
'-noautorotate',
|
||||
...this.getInputThreadOptions(),
|
||||
];
|
||||
const hwDevice = this.getPreferredHardwareDevice();
|
||||
if (hwDevice) {
|
||||
options.push(`-hwaccel_device ${hwDevice}`);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
const options = [];
|
||||
const tonemapOptions = this.getToneMapping(videoStream);
|
||||
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
|
||||
let scaling = `scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc`;
|
||||
if (tonemapOptions.length === 0) {
|
||||
scaling += ':format=nv12';
|
||||
}
|
||||
options.push(scaling);
|
||||
}
|
||||
options.push(...tonemapOptions);
|
||||
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
||||
options.push('format=nv12');
|
||||
}
|
||||
return options;
|
||||
getScalingFilter(videoStream: VideoStreamInfo, format: string) {
|
||||
return `scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc:format=${format}`;
|
||||
}
|
||||
|
||||
getToneMapping(videoStream: VideoStreamInfo): string[] {
|
||||
@@ -907,29 +843,33 @@ export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig {
|
||||
'hwmap=derive_device=vaapi:reverse=1,format=vaapi',
|
||||
];
|
||||
}
|
||||
|
||||
getInputThreadOptions() {
|
||||
return [`-threads 1`];
|
||||
}
|
||||
}
|
||||
|
||||
export class RkmppSwDecodeConfig extends BaseHWConfig {
|
||||
export class RkmppConfig extends BaseHWConfig {
|
||||
protected hasMaliOpenCL: boolean;
|
||||
constructor(
|
||||
protected config: SystemConfigFFmpegDto,
|
||||
devices: string[] = [],
|
||||
hasMaliOpenCL = false,
|
||||
) {
|
||||
super(config, devices);
|
||||
this.hasMaliOpenCL = hasMaliOpenCL;
|
||||
}
|
||||
|
||||
eligibleForTwoPass(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getBaseInputOptions(): string[] {
|
||||
getBaseInputOptions() {
|
||||
if (this.devices.length === 0) {
|
||||
throw new Error('No RKMPP device found');
|
||||
}
|
||||
return [];
|
||||
|
||||
if (this.config.accelDecode) {
|
||||
return ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga', '-noautorotate'];
|
||||
}
|
||||
|
||||
return ['-init_hw_device rkmpp=hw', '-filter_hw_device hw'];
|
||||
}
|
||||
|
||||
getPresetOptions() {
|
||||
@@ -962,32 +902,29 @@ export class RkmppSwDecodeConfig extends BaseHWConfig {
|
||||
return [VideoCodec.H264, VideoCodec.HEVC];
|
||||
}
|
||||
|
||||
getVideoCodec(): string {
|
||||
return `${this.config.targetVideoCodec}_rkmpp`;
|
||||
}
|
||||
}
|
||||
|
||||
export class RkmppHwDecodeConfig extends RkmppSwDecodeConfig {
|
||||
getBaseInputOptions() {
|
||||
if (this.devices.length === 0) {
|
||||
throw new Error('No RKMPP device found');
|
||||
}
|
||||
|
||||
return ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga', '-noautorotate'];
|
||||
}
|
||||
|
||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||
if (this.shouldToneMap(videoStream)) {
|
||||
const { primaries, transfer, matrix } = this.getColors();
|
||||
if (this.hasMaliOpenCL) {
|
||||
return [
|
||||
// use RKMPP for scaling, OpenCL for tone mapping
|
||||
`scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1:async_depth=4`,
|
||||
'hwmap=derive_device=opencl:mode=read',
|
||||
`tonemap_opencl=format=nv12:r=pc:p=${primaries}:t=${transfer}:m=${matrix}:tonemap=${this.config.tonemap}:desat=0:tonemap_mode=lum:peak=100`,
|
||||
'hwmap=derive_device=rkmpp:mode=write:reverse=1',
|
||||
'format=drm_prime',
|
||||
];
|
||||
}
|
||||
return [
|
||||
`scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1`,
|
||||
'hwmap=derive_device=opencl:mode=read',
|
||||
`tonemap_opencl=format=nv12:r=pc:p=${primaries}:t=${transfer}:m=${matrix}:tonemap=${this.config.tonemap}:desat=0:tonemap_mode=lum:peak=100`,
|
||||
'hwmap=derive_device=rkmpp:mode=write:reverse=1',
|
||||
'format=drm_prime',
|
||||
// use RKMPP for scaling, CPU for tone mapping (only works on RK3588, which supports 10-bit output)
|
||||
`scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1:async_depth=4`,
|
||||
'hwdownload',
|
||||
'format=p010',
|
||||
`tonemapx=tonemap=${this.config.tonemap}:desat=0:p=${primaries}:t=${transfer}:m=${matrix}:r=pc:peak=100:format=yuv420p`,
|
||||
'hwupload',
|
||||
];
|
||||
} else if (this.shouldScale(videoStream)) {
|
||||
return [`scale_rkrga=${this.getScaling(videoStream)}:format=nv12:afbc=1`];
|
||||
return [`scale_rkrga=${this.getScaling(videoStream)}:format=nv12:afbc=1:async_depth=4`];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:22.10.0-alpine3.20@sha256:fc95a044b87e95507c60c1f8c829e5d98ddf46401034932499db370c494ef0ff
|
||||
FROM node:22.11.0-alpine3.20@sha256:f265794478aa0b1a23d85a492c8311ed795bc527c3fe7e43453b3c872dcd71a3
|
||||
|
||||
RUN apk add --no-cache tini
|
||||
USER node
|
||||
|
||||
Reference in New Issue
Block a user