1
0
Fork 0
mirror of https://github.com/jellyfin/jellyfin-web synced 2025-03-30 19:56:21 +00:00

Added native PGS (graphical subtitle) rendering for external streams.

This commit is contained in:
David Schulte 2024-06-08 00:55:35 +02:00
parent 9184f06d79
commit e9aedc3305
4 changed files with 81 additions and 2 deletions

35
package-lock.json generated
View file

@ -45,6 +45,7 @@
"jquery": "3.7.1", "jquery": "3.7.1",
"jstree": "3.3.16", "jstree": "3.3.16",
"libarchive.js": "2.0.2", "libarchive.js": "2.0.2",
"libpgs": "0.2.0",
"lodash-es": "4.17.21", "lodash-es": "4.17.21",
"markdown-it": "14.1.0", "markdown-it": "14.1.0",
"material-design-icons-iconfont": "6.7.0", "material-design-icons-iconfont": "6.7.0",
@ -138,6 +139,22 @@
"sass-embedded": "1.77.8" "sass-embedded": "1.77.8"
} }
}, },
"../libpgs-js": {
"name": "libpgs",
"version": "0.2.0",
"license": "MIT",
"devDependencies": {
"@tsconfig/recommended": "^1.0.6",
"@types/jest": "^29.5.12",
"jest": "^29.7.0",
"ts-jest": "^29.1.4",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
},
"node_modules/@aashutoshrathi/word-wrap": { "node_modules/@aashutoshrathi/word-wrap": {
"version": "1.2.6", "version": "1.2.6",
"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
@ -14971,6 +14988,10 @@
"comlink": "^4.4.1" "comlink": "^4.4.1"
} }
}, },
"node_modules/libpgs": {
"resolved": "../libpgs-js",
"link": true
},
"node_modules/lie": { "node_modules/lie": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",
@ -36529,6 +36550,20 @@
"comlink": "^4.4.1" "comlink": "^4.4.1"
} }
}, },
"libpgs": {
"version": "file:../libpgs-js",
"requires": {
"@tsconfig/recommended": "^1.0.6",
"@types/jest": "^29.5.12",
"jest": "^29.7.0",
"ts-jest": "^29.1.4",
"ts-loader": "^9.5.1",
"ts-node": "^10.9.2",
"typescript": "^5.4.5",
"webpack": "^5.91.0",
"webpack-cli": "^5.1.4"
}
},
"lie": { "lie": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz",

View file

@ -123,7 +123,8 @@
"swiper": "11.1.12", "swiper": "11.1.12",
"usehooks-ts": "3.1.0", "usehooks-ts": "3.1.0",
"webcomponents.js": "0.7.24", "webcomponents.js": "0.7.24",
"whatwg-fetch": "3.6.20" "whatwg-fetch": "3.6.20",
"libpgs": "0.2.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"sass-embedded": "1.77.8" "sass-embedded": "1.77.8"

View file

@ -100,7 +100,7 @@ function enableNativeTrackSupport(mediaSource, track) {
if (track) { if (track) {
const format = (track.Codec || '').toLowerCase(); const format = (track.Codec || '').toLowerCase();
if (format === 'ssa' || format === 'ass') { if (format === 'ssa' || format === 'ass' || format === 'pgssub') {
return false; return false;
} }
} }
@ -213,6 +213,10 @@ export class HtmlVideoPlayer {
* @type {any | null | undefined} * @type {any | null | undefined}
*/ */
#currentAssRenderer; #currentAssRenderer;
/**
* @type {any | null | undefined}
*/
#currentPgsRenderer;
/** /**
* @type {number | undefined} * @type {number | undefined}
*/ */
@ -1172,6 +1176,12 @@ export class HtmlVideoPlayer {
octopus.dispose(); octopus.dispose();
} }
this.#currentAssRenderer = null; this.#currentAssRenderer = null;
const pgsRenderer = this.#currentPgsRenderer;
if (pgsRenderer) {
pgsRenderer.dispose();
}
this.#currentPgsRenderer = null;
} }
/** /**
@ -1316,6 +1326,19 @@ export class HtmlVideoPlayer {
}); });
} }
/**
* @private
*/
renderPgs(videoElement, track, item) {
import('libpgs').then((libpgs) => {
const options = {
video: videoElement,
subUrl: getTextTrackUrl(track, item)
};
this.#currentPgsRenderer = new libpgs.PgsRenderer(options);
});
}
/** /**
* @private * @private
*/ */
@ -1434,6 +1457,10 @@ export class HtmlVideoPlayer {
this.renderSsaAss(videoElement, track, item); this.renderSsaAss(videoElement, track, item);
return; return;
} }
if (format === 'pgssub') {
this.renderPgs(videoElement, track, item);
return;
}
if (this.requiresCustomSubtitlesElement()) { if (this.requiresCustomSubtitlesElement()) {
this.renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex); this.renderSubtitlesWithCustomElement(videoElement, track, item, targetTextTrackIndex);

View file

@ -48,6 +48,15 @@ function supportsTextTracks() {
return _supportsTextTracks; return _supportsTextTracks;
} }
let _supportsCanvas2D;
function supportsCanvas2D() {
if (_supportsCanvas2D == null) {
_supportsCanvas2D = document.createElement('canvas').getContext('2d') != null;
}
return _supportsCanvas2D;
}
let _canPlayHls; let _canPlayHls;
function canPlayHls() { function canPlayHls() {
if (_canPlayHls == null) { if (_canPlayHls == null) {
@ -1432,6 +1441,13 @@ export default function (options) {
Method: 'External' Method: 'External'
}); });
} }
if (supportsCanvas2D()) {
profile.SubtitleProfiles.push({
Format: 'pgssub',
Method: 'External'
});
}
} }
profile.ResponseProfiles = []; profile.ResponseProfiles = [];