mirror of
https://github.com/chrisbenincasa/tunarr.git
synced 2026-04-18 09:03:35 -04:00
fix(streaming): include Quadro M2000, etc in special Maxwell cards that can decode HEVC
This commit is contained in:
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -303,6 +303,9 @@ importers:
|
||||
esbuild-plugin-pino:
|
||||
specifier: ^2.2.1
|
||||
version: 2.2.1(esbuild@0.19.12)
|
||||
fast-check:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.0
|
||||
fast-glob:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
@@ -3807,7 +3810,7 @@ packages:
|
||||
'@types/sql.js': '*'
|
||||
'@vercel/postgres': '>=0.8.0'
|
||||
'@xata.io/client': '*'
|
||||
better-sqlite3: '>=7'
|
||||
better-sqlite3: 9.4.5
|
||||
bun-types: '*'
|
||||
expo-sqlite: '>=14.0.0'
|
||||
knex: '*'
|
||||
@@ -4202,6 +4205,10 @@ packages:
|
||||
resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
fast-check@4.2.0:
|
||||
resolution: {integrity: sha512-buxrKEaSseOwFjt6K1REcGMeFOrb0wk3cXifeMAG8yahcE9kV20PjQn1OdzPGL6OBFTbYXfjleNBARf/aCfV1A==}
|
||||
engines: {node: '>=12.17.0'}
|
||||
|
||||
fast-copy@3.0.2:
|
||||
resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==}
|
||||
|
||||
@@ -6027,6 +6034,9 @@ packages:
|
||||
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
pure-rand@7.0.1:
|
||||
resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==}
|
||||
|
||||
qs@6.12.0:
|
||||
resolution: {integrity: sha512-trVZiI6RMOkO476zLGaBIzszOdFPnCCXHPG9kn0yuS1uz6xdVxPfZdB3vUig9pxPFDM9BRAgz/YUIVQ1/vuiUg==}
|
||||
engines: {node: '>=0.6'}
|
||||
@@ -11255,6 +11265,10 @@ snapshots:
|
||||
iconv-lite: 0.4.24
|
||||
tmp: 0.0.33
|
||||
|
||||
fast-check@4.2.0:
|
||||
dependencies:
|
||||
pure-rand: 7.0.1
|
||||
|
||||
fast-copy@3.0.2: {}
|
||||
|
||||
fast-decode-uri-component@1.0.1: {}
|
||||
@@ -13268,6 +13282,8 @@ snapshots:
|
||||
|
||||
punycode@2.3.1: {}
|
||||
|
||||
pure-rand@7.0.1: {}
|
||||
|
||||
qs@6.12.0:
|
||||
dependencies:
|
||||
side-channel: 1.0.6
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
"dotenv-cli": "^7.4.1",
|
||||
"drizzle-kit": "^0.30.4",
|
||||
"esbuild-plugin-pino": "^2.2.1",
|
||||
"fast-check": "^4.2.0",
|
||||
"fast-glob": "^3.3.2",
|
||||
"globals": "^15.0.0",
|
||||
"kysely-ctl": "^0.9.0",
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
import fc from 'fast-check';
|
||||
import { VideoFormats } from '../constants.ts';
|
||||
import {
|
||||
PixelFormatYuv420P,
|
||||
PixelFormatYuv420P10Le,
|
||||
} from '../format/PixelFormat.ts';
|
||||
import { NvidiaHardwareCapabilities } from './NvidiaHardwareCapabilities.ts';
|
||||
|
||||
describe('NvidiaHardwareCapabilities', () => {
|
||||
test('Quadro M2000 can decode HEVC 10-bit', () => {
|
||||
const capabilities = new NvidiaHardwareCapabilities('Quadro M2000', 52);
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.Hevc,
|
||||
undefined,
|
||||
new PixelFormatYuv420P10Le(),
|
||||
),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
test('any card SM 6.0 or higher can decode HEVC', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
const val = arch >= 60;
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.Hevc,
|
||||
undefined,
|
||||
new PixelFormatYuv420P10Le(),
|
||||
),
|
||||
).toBe(val);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('any card SM 6.0 or higher can encode 10-bit HEVC', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
const val = arch >= 60;
|
||||
expect(
|
||||
capabilities.canEncode(
|
||||
VideoFormats.Hevc,
|
||||
undefined,
|
||||
new PixelFormatYuv420P10Le(),
|
||||
),
|
||||
).toBe(val);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('any card SM 5.2 or higher can encode 8-bit HEVC', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
const val = arch >= 52;
|
||||
expect(
|
||||
capabilities.canEncode(
|
||||
VideoFormats.Hevc,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBe(val);
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('any card can decode 8-bit H264', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.H264,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBeTruthy();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('no card can decode 10-bit H264', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.H264,
|
||||
undefined,
|
||||
new PixelFormatYuv420P10Le(),
|
||||
),
|
||||
).toBeFalsy();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('no card can encode 10-bit H264', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
expect(
|
||||
capabilities.canEncode(
|
||||
VideoFormats.H264,
|
||||
undefined,
|
||||
new PixelFormatYuv420P10Le(),
|
||||
),
|
||||
).toBeFalsy();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('any card can decode mpeg2', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.Mpeg2Video,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBeTruthy();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('any card can decode vc1', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.Mpeg2Video,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBeTruthy();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('no card can decode mpeg4', () => {
|
||||
fc.assert(
|
||||
fc.property(fc.string(), fc.integer(), (model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.Mpeg4,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBeFalsy();
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
test('cards with Compute SM >8.6 can decode AV1', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.string(),
|
||||
fc.integer().filter((n) => n > 0),
|
||||
(model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
let ex = false;
|
||||
if (arch >= 86) {
|
||||
ex = true;
|
||||
}
|
||||
expect(
|
||||
capabilities.canDecode(
|
||||
VideoFormats.Av1,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBe(ex);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test('cards with Compute SM >8.0 can encode AV1', () => {
|
||||
fc.assert(
|
||||
fc.property(
|
||||
fc.string(),
|
||||
fc.integer().filter((n) => n > 0),
|
||||
(model, arch) => {
|
||||
const capabilities = new NvidiaHardwareCapabilities(model, arch);
|
||||
let ex = false;
|
||||
if (arch >= 80) {
|
||||
ex = true;
|
||||
}
|
||||
expect(
|
||||
capabilities.canEncode(
|
||||
VideoFormats.Av1,
|
||||
undefined,
|
||||
new PixelFormatYuv420P(),
|
||||
),
|
||||
).toBe(ex);
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -8,6 +8,9 @@ const MaxwellGm206Models = new Set([
|
||||
'GTX 950',
|
||||
'GTX 960',
|
||||
'GTX 965M',
|
||||
'Quadro M2000',
|
||||
'Quadro M2200M',
|
||||
'Tesla M4',
|
||||
]);
|
||||
|
||||
// https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new
|
||||
@@ -74,7 +77,6 @@ export class NvidiaHardwareCapabilities extends BaseFfmpegHardwareCapabilities {
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO: Check binary capabilities
|
||||
return canUseHardware;
|
||||
}
|
||||
|
||||
@@ -83,7 +85,6 @@ export class NvidiaHardwareCapabilities extends BaseFfmpegHardwareCapabilities {
|
||||
_videoProfile: Maybe<string>,
|
||||
pixelFormat: Maybe<PixelFormat>,
|
||||
): boolean {
|
||||
// TODO: Clean this up with ffmpeg builder and consts
|
||||
const bitDepth = pixelFormat?.bitDepth ?? 8;
|
||||
|
||||
if (videoFormat === VideoFormats.Hevc) {
|
||||
|
||||
@@ -16,7 +16,8 @@ import { KEYS } from '../../../types/inject.ts';
|
||||
import { Result } from '../../../types/result.ts';
|
||||
|
||||
const NvidiaGpuArchPattern = /SM\s+(\d+\.\d+)/;
|
||||
const NvidiaGpuModelPattern = /(([G|R]TX|Quadro)\s+[0-9a-zA-Z]+[\sTtIi]+)/;
|
||||
const NvidiaGpuModelPattern =
|
||||
/(([G|R]TX|Quadro|Tesla)\s+[0-9a-zA-Z]+[\sTtIi]+)/;
|
||||
|
||||
type NvidiaGpuDetectionResponse = {
|
||||
model?: string;
|
||||
|
||||
Reference in New Issue
Block a user