mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-07 10:14:13 -04:00
Merge pull request #4 from AnonymusRaccoon/dev
Reworking the transmuxer to use HLS (it is really fast now).
This commit is contained in:
commit
3f284fad42
@ -18,6 +18,7 @@ int transmux(const char *path, const char *out_path, float *playable_duration)
|
|||||||
int *stream_map;
|
int *stream_map;
|
||||||
int stream_count;
|
int stream_count;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
std::string seg_path = ((std::string)out_path).substr(0, strrchr(out_path, '/') - out_path).append("/segments/");
|
||||||
|
|
||||||
*playable_duration = 0;
|
*playable_duration = 0;
|
||||||
if (open_input_context(&in_ctx, path) != 0)
|
if (open_input_context(&in_ctx, path) != 0)
|
||||||
@ -54,10 +55,10 @@ int transmux(const char *path, const char *out_path, float *playable_duration)
|
|||||||
}
|
}
|
||||||
|
|
||||||
av_dump_format(out_ctx, 0, out_path, true);
|
av_dump_format(out_ctx, 0, out_path, true);
|
||||||
|
std::filesystem::create_directory(seg_path);
|
||||||
std::filesystem::create_directory(((std::string)out_path).substr(0, strrchr(out_path, '/') - out_path).append("/dash/"));
|
av_dict_set(&options, "hls_segment_filename", seg_path.append("%v-%03d.ts").c_str(), 0);
|
||||||
av_dict_set(&options, "init_seg_name", "dash/init-stream$RepresentationID$.m4s", 0);
|
av_dict_set(&options, "hls_base_url", "segment/", 0);
|
||||||
av_dict_set(&options, "media_seg_name", "dash/chunk-stream$RepresentationID$-$Number%05d$.m4s", 0);
|
av_dict_set(&options, "hls_list_size", "0", 0);
|
||||||
av_dict_set(&options, "streaming", "1", 0);
|
av_dict_set(&options, "streaming", "1", 0);
|
||||||
|
|
||||||
if (open_output_file_for_write(out_ctx, out_path, &options) != 0)
|
if (open_output_file_for_write(out_ctx, out_path, &options) != 0)
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
"scripts": [
|
"scripts": [
|
||||||
"./node_modules/jquery/dist/jquery.min.js",
|
"./node_modules/jquery/dist/jquery.min.js",
|
||||||
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
"./node_modules/bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||||
"./node_modules/dashjs/dist/dash.all.min.js",
|
"./node_modules/hls.js/dist/hls.js",
|
||||||
"./src/libraries/subtitles.js"
|
"./src/libraries/subtitles.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
60
Kyoo/ClientApp/package-lock.json
generated
60
Kyoo/ClientApp/package-lock.json
generated
@ -1270,6 +1270,12 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/hls.js": {
|
||||||
|
"version": "0.12.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hls.js/-/hls.js-0.12.5.tgz",
|
||||||
|
"integrity": "sha512-UWNROsxKxW1yASacUZzvjGZwS1xGp1gN3Yyd6XWMpqr8HLiYepVWZLxsyfPNsgSJrQ1oyz03tV7y4dS5nlSOaw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/jasmine": {
|
"@types/jasmine": {
|
||||||
"version": "3.3.16",
|
"version": "3.3.16",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.3.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-3.3.16.tgz",
|
||||||
@ -2754,11 +2760,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"codem-isoboxer": {
|
|
||||||
"version": "0.3.6",
|
|
||||||
"resolved": "https://registry.npmjs.org/codem-isoboxer/-/codem-isoboxer-0.3.6.tgz",
|
|
||||||
"integrity": "sha512-LuO8/7LW6XuR5ERn1yavXAfodGRhuY2yP60JTZIw5yNYMCE5lUVbk3NFUCJxjnphQH+Xemp5hOGb1LgUXm00Xw=="
|
|
||||||
},
|
|
||||||
"collection-visit": {
|
"collection-visit": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
|
||||||
@ -3146,16 +3147,6 @@
|
|||||||
"assert-plus": "^1.0.0"
|
"assert-plus": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dashjs": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/dashjs/-/dashjs-3.0.0.tgz",
|
|
||||||
"integrity": "sha512-XyVkjeHB4mqzf/Y7ARQ1IqbRBaee0osAulwCFV5ZNZ734wea8LbSC/23zKI32BulW7Kk6f7I6onW1WDMHRgz7Q==",
|
|
||||||
"requires": {
|
|
||||||
"codem-isoboxer": "0.3.6",
|
|
||||||
"fast-deep-equal": "2.0.1",
|
|
||||||
"imsc": "^1.0.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"date-format": {
|
"date-format": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz",
|
||||||
@ -3999,7 +3990,8 @@
|
|||||||
"fast-deep-equal": {
|
"fast-deep-equal": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
|
||||||
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
|
"integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"fast-json-stable-stringify": {
|
"fast-json-stable-stringify": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@ -4555,6 +4547,22 @@
|
|||||||
"minimalistic-assert": "^1.0.1"
|
"minimalistic-assert": "^1.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"hls.js": {
|
||||||
|
"version": "0.12.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/hls.js/-/hls.js-0.12.4.tgz",
|
||||||
|
"integrity": "sha512-e8OPxQ60dBVsdkv4atdxR21KzC1mgwspM41qpozpj3Uv1Fz4CaeQy3FWoaV2O+QKKbNRvV5hW+/LipCWdrwnMQ==",
|
||||||
|
"requires": {
|
||||||
|
"eventemitter3": "3.1.0",
|
||||||
|
"url-toolkit": "^2.1.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"eventemitter3": {
|
||||||
|
"version": "3.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
|
||||||
|
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"hmac-drbg": {
|
"hmac-drbg": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||||
@ -4816,21 +4824,6 @@
|
|||||||
"resolve-cwd": "^2.0.0"
|
"resolve-cwd": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"imsc": {
|
|
||||||
"version": "1.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/imsc/-/imsc-1.1.0.tgz",
|
|
||||||
"integrity": "sha512-z2aUE3X00O39fCgkLHEVbfKG/D9cBrmsbf4NjP7K1gQb06YBjgljq5nZD72HYMFG2lRJI7QY7v+JVxg6o6I/Jg==",
|
|
||||||
"requires": {
|
|
||||||
"sax": "1.2.1"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"sax": {
|
|
||||||
"version": "1.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz",
|
|
||||||
"integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o="
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"imurmurhash": {
|
"imurmurhash": {
|
||||||
"version": "0.1.4",
|
"version": "0.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
|
||||||
@ -10220,6 +10213,11 @@
|
|||||||
"requires-port": "^1.0.0"
|
"requires-port": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"url-toolkit": {
|
||||||
|
"version": "2.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.1.6.tgz",
|
||||||
|
"integrity": "sha512-UaZ2+50am4HwrV2crR/JAf63Q4VvPYphe63WGeoJxeu8gmOm0qxPt+KsukfakPNrX9aymGNEkkaoICwn+OuvBw=="
|
||||||
|
},
|
||||||
"use": {
|
"use": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
|
||||||
|
@ -22,9 +22,9 @@
|
|||||||
"@angular/platform-browser-dynamic": "~8.2.0",
|
"@angular/platform-browser-dynamic": "~8.2.0",
|
||||||
"@angular/router": "~8.2.0",
|
"@angular/router": "~8.2.0",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
"dashjs": "^3.0.0",
|
|
||||||
"detect-browser": "^4.8.0",
|
"detect-browser": "^4.8.0",
|
||||||
"hammerjs": "^2.0.8",
|
"hammerjs": "^2.0.8",
|
||||||
|
"hls.js": "^0.12.4",
|
||||||
"jquery": "^3.4.1",
|
"jquery": "^3.4.1",
|
||||||
"popper.js": "^1.15.0",
|
"popper.js": "^1.15.0",
|
||||||
"zone.js": "~0.9.1"
|
"zone.js": "~0.9.1"
|
||||||
@ -35,6 +35,7 @@
|
|||||||
"@angular/compiler-cli": "~8.2.0",
|
"@angular/compiler-cli": "~8.2.0",
|
||||||
"@angular/language-service": "~8.2.0",
|
"@angular/language-service": "~8.2.0",
|
||||||
"@types/bootstrap": "^4.3.1",
|
"@types/bootstrap": "^4.3.1",
|
||||||
|
"@types/hls.js": "^0.12.5",
|
||||||
"@types/jasmine": "~3.3.8",
|
"@types/jasmine": "~3.3.8",
|
||||||
"@types/jasminewd2": "~2.0.3",
|
"@types/jasminewd2": "~2.0.3",
|
||||||
"@types/jquery": "^3.3.31",
|
"@types/jquery": "^3.3.31",
|
||||||
|
@ -4,7 +4,7 @@ import { DomSanitizer, Title } from "@angular/platform-browser";
|
|||||||
import { ActivatedRoute, Event, NavigationCancel, NavigationEnd, NavigationStart, Router } from "@angular/router";
|
import { ActivatedRoute, Event, NavigationCancel, NavigationEnd, NavigationStart, Router } from "@angular/router";
|
||||||
import { Track, WatchItem } from "../../models/watch-item";
|
import { Track, WatchItem } from "../../models/watch-item";
|
||||||
import { Location } from "@angular/common";
|
import { Location } from "@angular/common";
|
||||||
import { MediaPlayer } from "dashjs";
|
import * as Hls from "hls.js"
|
||||||
import { getPlaybackMethod, method } from "../../videoSupport/playbackMethodDetector";
|
import { getPlaybackMethod, method } from "../../videoSupport/playbackMethodDetector";
|
||||||
|
|
||||||
declare var SubtitleManager: any;
|
declare var SubtitleManager: any;
|
||||||
@ -43,8 +43,7 @@ export class PlayerComponent implements OnInit
|
|||||||
playMethod: method;
|
playMethod: method;
|
||||||
|
|
||||||
private player: HTMLVideoElement;
|
private player: HTMLVideoElement;
|
||||||
private dashPlayer: dashjs.MediaPlayerClass = MediaPlayer().create();
|
private hlsPlayer: Hls = new Hls();
|
||||||
private dashPlayerInitialized: boolean = false;
|
|
||||||
private thumb: HTMLElement;
|
private thumb: HTMLElement;
|
||||||
private progress: HTMLElement;
|
private progress: HTMLElement;
|
||||||
private buffered: HTMLElement;
|
private buffered: HTMLElement;
|
||||||
@ -381,22 +380,27 @@ export class PlayerComponent implements OnInit
|
|||||||
|
|
||||||
selectPlayMethod()
|
selectPlayMethod()
|
||||||
{
|
{
|
||||||
if (this.dashPlayerInitialized)
|
|
||||||
this.dashPlayer.reset();
|
|
||||||
if (this.playMethod == method.direct)
|
if (this.playMethod == method.direct)
|
||||||
{
|
{
|
||||||
this.player.src = "/video/" + this.item.link;
|
this.player.src = "/video/" + this.item.link;
|
||||||
this.dashPlayerInitialized = false;
|
|
||||||
}
|
}
|
||||||
else if (this.playMethod == method.transmux)
|
else if (this.playMethod == method.transmux)
|
||||||
{
|
{
|
||||||
this.dashPlayer.initialize(this.player, "/video/transmux/" + this.item.link + "/", true);
|
this.hlsPlayer.loadSource("/video/transmux/" + this.item.link + "/");
|
||||||
this.dashPlayerInitialized = true;
|
this.hlsPlayer.attachMedia(this.player);
|
||||||
|
this.hlsPlayer.on(Hls.Events.MANIFEST_LOADED, () =>
|
||||||
|
{
|
||||||
|
this.player.play();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.dashPlayer.initialize(this.player, "/video/transcode/" + this.item.link + "/", true);
|
this.hlsPlayer.loadSource("/video/transcode/" + this.item.link + "/");
|
||||||
this.dashPlayerInitialized = true;
|
this.hlsPlayer.attachMedia(this.player);
|
||||||
|
this.hlsPlayer.on(Hls.Events.MANIFEST_LOADED, () =>
|
||||||
|
{
|
||||||
|
this.player.play();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ namespace Kyoo.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}/")]
|
[HttpGet("transmux/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
public async Task<IActionResult> Transmux(string showSlug, long seasonNumber, long episodeNumber)
|
||||||
{
|
{
|
||||||
WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
|
||||||
@ -42,7 +42,7 @@ namespace Kyoo.Controllers
|
|||||||
{
|
{
|
||||||
string path = await transcoder.Transmux(episode);
|
string path = await transcoder.Transmux(episode);
|
||||||
if (path != null)
|
if (path != null)
|
||||||
return PhysicalFile(path, "application/dash+xml", true);
|
return PhysicalFile(path, "application/x-mpegURL ", true);
|
||||||
else
|
else
|
||||||
return StatusCode(500);
|
return StatusCode(500);
|
||||||
}
|
}
|
||||||
@ -50,13 +50,13 @@ namespace Kyoo.Controllers
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("transmux/{episodeLink}/dash/{chunk}")]
|
[HttpGet("transmux/{episodeLink}/segment/{chunk}")]
|
||||||
public IActionResult GetTransmuxedChunk(string episodeLink, string chunk)
|
public IActionResult GetTransmuxedChunk(string episodeLink, string chunk)
|
||||||
{
|
{
|
||||||
string path = Path.Combine(transmuxPath, episodeLink);
|
string path = Path.Combine(transmuxPath, episodeLink);
|
||||||
path = Path.Combine(path, "dash" + Path.DirectorySeparatorChar + chunk);
|
path = Path.Combine(path, "segments" + Path.DirectorySeparatorChar + chunk);
|
||||||
|
|
||||||
return PhysicalFile(path, "video/iso.segment");
|
return PhysicalFile(path, "video/MP2T");
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
[HttpGet("transcode/{showSlug}-s{seasonNumber}e{episodeNumber}")]
|
||||||
|
@ -43,7 +43,7 @@ namespace Kyoo.InternalAPI
|
|||||||
public async Task<string> Transmux(WatchItem episode)
|
public async Task<string> Transmux(WatchItem episode)
|
||||||
{
|
{
|
||||||
string folder = Path.Combine(transmuxPath, episode.Link);
|
string folder = Path.Combine(transmuxPath, episode.Link);
|
||||||
string manifest = Path.Combine(folder, episode.Link + ".mpd");
|
string manifest = Path.Combine(folder, episode.Link + ".m3u8");
|
||||||
float playableDuration = 0;
|
float playableDuration = 0;
|
||||||
bool transmuxFailed = false;
|
bool transmuxFailed = false;
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ namespace Kyoo
|
|||||||
ctx.Response.Headers.Remove("X-Powered-By");
|
ctx.Response.Headers.Remove("X-Powered-By");
|
||||||
ctx.Response.Headers.Remove("Server");
|
ctx.Response.Headers.Remove("Server");
|
||||||
ctx.Response.Headers.Add("Feature-Policy", "autoplay 'self'; fullscreen");
|
ctx.Response.Headers.Add("Feature-Policy", "autoplay 'self'; fullscreen");
|
||||||
ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'");
|
ctx.Response.Headers.Add("Content-Security-Policy", "default-src 'self' data: blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:; style-src 'self' 'unsafe-inline'");
|
||||||
ctx.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
|
ctx.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
|
||||||
ctx.Response.Headers.Add("Referrer-Policy", "no-referrer");
|
ctx.Response.Headers.Add("Referrer-Policy", "no-referrer");
|
||||||
ctx.Response.Headers.Add("Access-Control-Allow-Origin", "null");
|
ctx.Response.Headers.Add("Access-Control-Allow-Origin", "null");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user