diff --git a/Kyoo/ClientApp/src/app/player/player.component.ts b/Kyoo/ClientApp/src/app/player/player.component.ts index 43fe71d9..de3ff900 100644 --- a/Kyoo/ClientApp/src/app/player/player.component.ts +++ b/Kyoo/ClientApp/src/app/player/player.component.ts @@ -339,7 +339,7 @@ export class PlayerComponent implements OnInit init() { - let playbackMethod = getPlaybackMethod(this.item); + let playbackMethod = getPlaybackMethod(this.player, this.item); if (playbackMethod == method.direct) { this.player.src = "/video/" + this.item.link; diff --git a/Kyoo/ClientApp/src/models/watch-item.ts b/Kyoo/ClientApp/src/models/watch-item.ts index 62a535c7..93361c49 100644 --- a/Kyoo/ClientApp/src/models/watch-item.ts +++ b/Kyoo/ClientApp/src/models/watch-item.ts @@ -14,6 +14,8 @@ export interface WatchItem previousEpisode: string; nextEpisode: Episode; + container: string; + video: Track; audios: Track[]; subtitles: Track[]; } diff --git a/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js b/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js index 092ea6d2..8a2ed9a2 100644 --- a/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js +++ b/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js @@ -1,5 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); +var detect_browser_1 = require("detect-browser"); var method; (function (method) { method[method["direct"] = 0] = "direct"; @@ -7,8 +8,135 @@ var method; method[method["transcode"] = 2] = "transcode"; })(method = exports.method || (exports.method = {})); ; -function getPlaybackMethod(item) { - return method.direct; +function getPlaybackMethod(player, item) { + var browser = detect_browser_1.detect(); + // If we can't find the browser, transcode (It may or may not support containers/codecs) + if (!browser) + return method.transcode; + if (containerIsSupported(player, item.container, browser.name)) { + if (videoCodecIsSupported(player, item.video.codec, browser.name) && + audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name)) + return method.direct; + return method.transcode; + } + if (videoCodecIsSupported(player, item.video.codec, browser.name) && + audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name)) + return method.transmux; + return method.transcode; } exports.getPlaybackMethod = getPlaybackMethod; +function containerIsSupported(player, container, browser) { + var supported = false; + switch (container) { + case "asf": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + //videoAudioCodecs = []; + break; + case "avi": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "mpg": + case "mpeg": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "flv": + supported = browser == "tizen" || browser == "orsay"; + break; + case "3gp": + case "mts": + case "trp": + case "vob": + case "vro": + supported = browser == "tizen" || browser == "orsay"; + break; + case "mov": + supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome"; + break; + case "m2ts": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "wmv": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + //videoAudioCodecs = []; + break; + case "ts": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "mp4": + case "m4v": + supported = true; + break; + case "mkv": + supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge"; + if (supported) + break; + if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv")) + supported = true; + break; + default: + break; + } + return supported; +} +//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers) +function videoCodecIsSupported(player, codec, browser) { + switch (codec) { + case "h264": + return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool + case "h265": + case "hevc": + if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios") + return true; + //SHOULD SUPPORT CHROMECAST ULTRA + // if (browser.chromecast) + // { + // var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; + // if (isChromecastUltra) + // { + // return true; + // } + // } + return !!player.canPlayType('video/hevc; codecs="hevc, aac"'); + case "mpeg2video": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "vc1": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "msmpeg4v2": + return browser == "orsay" || browser == "tizen"; + case "vp8": + return !!player.canPlayType('video/webm; codecs="vp8'); + case "vp9": + return !!player.canPlayType('video/webm; codecs="vp9"'); + case "vorbis": + return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8'); + default: + return false; + } +} +//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers) +function audioCodecIsSupported(player, codecs, browser) { + for (var _i = 0, codecs_1 = codecs; _i < codecs_1.length; _i++) { + var codec = codecs_1[_i]; + switch (codec) { + case "mp3": + return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') || + !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"'); + case "aac": + return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"'); + case "mp2": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "pcm_s16le": + case "pcm_s24le": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "aac_latm": + return browser == "orsay" || browser == "tizen"; + case "opus": + return !!player.canPlayType('audio/ogg; codecs="opus"'); + case "flac": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + default: + return false; + } + } +} //# sourceMappingURL=playbackMethodDetector.js.map \ No newline at end of file diff --git a/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js.map b/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js.map index 7cc2feb5..ffb37a1f 100644 --- a/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js.map +++ b/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.js.map @@ -1 +1 @@ -{"version":3,"file":"playbackMethodDetector.js","sourceRoot":"","sources":["playbackMethodDetector.ts"],"names":[],"mappings":";;AAEA,IAAY,MAKX;AALD,WAAY,MAAM;IAEjB,uCAAM,CAAA;IACN,2CAAQ,CAAA;IACP,6CAAS,CAAA;AACX,CAAC,EALW,MAAM,GAAN,cAAM,KAAN,cAAM,QAKjB;AAAA,CAAC;AAEF,SAAgB,iBAAiB,CAAC,IAAe;IAEhD,OAAO,MAAM,CAAC,MAAM,CAAC;AACtB,CAAC;AAHD,8CAGC"} \ No newline at end of file +{"version":3,"file":"playbackMethodDetector.js","sourceRoot":"","sources":["playbackMethodDetector.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.ts b/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.ts index 8d2b4e1d..c6ab269c 100644 --- a/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.ts +++ b/Kyoo/ClientApp/src/videoSupport/playbackMethodDetector.ts @@ -1,13 +1,158 @@ -import { WatchItem } from "../models/watch-item"; - +import { WatchItem, Track } from "../models/watch-item"; +import { detect, BrowserInfo } from "detect-browser"; + export enum method { direct, transmux, - transcode + transcode }; -export function getPlaybackMethod(item: WatchItem): method +export function getPlaybackMethod(player: HTMLVideoElement, item: WatchItem): method { - return method.direct; + let browser = detect(); + + // If we can't find the browser, transcode (It may or may not support containers/codecs) + if (!browser) + return method.transcode; + + if (containerIsSupported(player, item.container, browser.name)) + { + if (videoCodecIsSupported(player, item.video.codec, browser.name) && + audioCodecIsSupported(player, item.audios.map((value: Track) => value.codec), browser.name)) + return method.direct; + return method.transcode; + } + + if (videoCodecIsSupported(player, item.video.codec, browser.name) && + audioCodecIsSupported(player, item.audios.map((value: Track) => value.codec), browser.name)) + return method.transmux; + return method.transcode; +} + +function containerIsSupported(player: HTMLVideoElement, container: string, browser: string): boolean +{ + let supported: boolean = false; + + switch (container) + { + case "asf": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + //videoAudioCodecs = []; + break; + case "avi": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "mpg": + case "mpeg": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "flv": + supported = browser == "tizen" || browser == "orsay"; + break; + case "3gp": + case "mts": + case "trp": + case "vob": + case "vro": + supported = browser == "tizen" || browser == "orsay"; + break; + case "mov": + supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome"; + break; + case "m2ts": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "wmv": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + //videoAudioCodecs = []; + break; + case "ts": + supported = browser == "tizen" || browser == "orsay" || browser == "edge"; + break; + case "mp4": + case "m4v": + supported = true; + break; + case "mkv": + supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge"; + + if (supported) + break; + + if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv")) + supported = true; + break; + default: + break; + } + return supported; +} + +//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers) +function videoCodecIsSupported(player: HTMLVideoElement, codec: string, browser: string): boolean +{ + switch (codec) + { + case "h264": + return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool + case "h265": + case "hevc": + if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios") + return true; + //SHOULD SUPPORT CHROMECAST ULTRA + // if (browser.chromecast) + // { + + // var isChromecastUltra = userAgent.indexOf('aarch64') !== -1; + // if (isChromecastUltra) + // { + // return true; + // } + // } + return !!player.canPlayType('video/hevc; codecs="hevc, aac"'); + case "mpeg2video": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "vc1": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "msmpeg4v2": + return browser == "orsay" || browser == "tizen"; + case "vp8": + return !!player.canPlayType('video/webm; codecs="vp8'); + case "vp9": + return !!player.canPlayType('video/webm; codecs="vp9"'); + case "vorbis": + return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8'); + default: + return false; + } +} + +//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers) +function audioCodecIsSupported(player: HTMLVideoElement, codecs: string[], browser: string): boolean +{ + for (let codec of codecs) + { + switch (codec) + { + case "mp3": + return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') || + !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"'); + case "aac": + return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"'); + case "mp2": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "pcm_s16le": + case "pcm_s24le": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + case "aac_latm": + return browser == "orsay" || browser == "tizen"; + case "opus": + return !!player.canPlayType('audio/ogg; codecs="opus"'); + case "flac": + return browser == "orsay" || browser == "tizen" || browser == "edge"; + default: + return false; + } + } } diff --git a/Kyoo/InternalAPI/Crawler/Crawler.cs b/Kyoo/InternalAPI/Crawler/Crawler.cs index 13eff220..3b17ddd8 100644 --- a/Kyoo/InternalAPI/Crawler/Crawler.cs +++ b/Kyoo/InternalAPI/Crawler/Crawler.cs @@ -269,7 +269,6 @@ namespace Kyoo.InternalAPI } } - private bool FindExtractedSubtitles(Episode episode) { string path = Path.Combine(Path.GetDirectoryName(episode.Path), "Subtitles"); diff --git a/Kyoo/InternalAPI/Transcoder/Transcoder.cs b/Kyoo/InternalAPI/Transcoder/Transcoder.cs index 71f64930..ae02e8f0 100644 --- a/Kyoo/InternalAPI/Transcoder/Transcoder.cs +++ b/Kyoo/InternalAPI/Transcoder/Transcoder.cs @@ -43,13 +43,14 @@ namespace Kyoo.InternalAPI if (File.Exists(manifest)) return manifest; - Task.Run(() => + // Added an await and removed the while -> await because the dynamic dash file can't be played for now (maybe ffmpeg doesn't process in the playback order). + await Task.Run(() => { transmuxFailed = TranscoderAPI.transmux(episode.Path, manifest.Replace('\\', '/'), out playableDuration) != 0; playableDuration = float.MaxValue; }); - while (playableDuration < 20 || (!File.Exists(manifest) && !transmuxFailed)) - await Task.Delay(10); + //while (playableDuration < 20 || (!File.Exists(manifest) && !transmuxFailed)) + // await Task.Delay(10); return transmuxFailed ? null : manifest; }