mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2024-11-17 10:58:20 -07:00
Support H264 Level 52 (Tizen 5.0) - app only
This commit is contained in:
commit
1f71b6bd14
@ -1,900 +0,0 @@
|
|||||||
define(['browser'], function (browser) {
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
function canPlayH264(videoTestElement) {
|
|
||||||
return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
function canPlayH265(videoTestElement, options) {
|
|
||||||
if (browser.tizen || browser.orsay || browser.xboxOne || browser.web0s || options.supportsHevc) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userAgent = navigator.userAgent.toLowerCase();
|
|
||||||
if (browser.chromecast) {
|
|
||||||
var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
|
||||||
if (isChromecastUltra) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.ps4) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!videoTestElement.canPlayType &&
|
|
||||||
(videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.L120"').replace(/no/, '') ||
|
|
||||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.L120"').replace(/no/, '') ||
|
|
||||||
videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.0.L120"').replace(/no/, '') ||
|
|
||||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.0.L120"').replace(/no/, ''));
|
|
||||||
}
|
|
||||||
|
|
||||||
var _supportsTextTracks;
|
|
||||||
function supportsTextTracks() {
|
|
||||||
if (browser.tizen || browser.orsay) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_supportsTextTracks == null) {
|
|
||||||
_supportsTextTracks = document.createElement('video').textTracks != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now, until ready
|
|
||||||
return _supportsTextTracks;
|
|
||||||
}
|
|
||||||
|
|
||||||
var _canPlayHls;
|
|
||||||
function canPlayHls() {
|
|
||||||
if (_canPlayHls == null) {
|
|
||||||
_canPlayHls = canPlayNativeHls() || canPlayHlsWithMSE();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _canPlayHls;
|
|
||||||
}
|
|
||||||
|
|
||||||
function canPlayNativeHls() {
|
|
||||||
if (browser.tizen || browser.orsay) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var media = document.createElement('video');
|
|
||||||
if (media.canPlayType('application/x-mpegURL').replace(/no/, '') ||
|
|
||||||
media.canPlayType('application/vnd.apple.mpegURL').replace(/no/, '')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function canPlayHlsWithMSE() {
|
|
||||||
// text tracks don’t work with this in firefox
|
|
||||||
return window.MediaSource != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function supportsAc3(videoTestElement) {
|
|
||||||
if (browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return videoTestElement.canPlayType('audio/mp4; codecs="ac-3"').replace(/no/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function supportsEac3(videoTestElement) {
|
|
||||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return videoTestElement.canPlayType('audio/mp4; codecs="ec-3"').replace(/no/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function supportsAc3InHls(videoTestElement) {
|
|
||||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoTestElement.canPlayType) {
|
|
||||||
return videoTestElement.canPlayType('application/x-mpegurl; codecs="avc1.42E01E, ac-3"').replace(/no/, '') ||
|
|
||||||
videoTestElement.canPlayType('application/vnd.apple.mpegURL; codecs="avc1.42E01E, ac-3"').replace(/no/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function canPlayAudioFormat(format) {
|
|
||||||
var typeString;
|
|
||||||
|
|
||||||
if (format === 'flac') {
|
|
||||||
if (browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (format === 'wma') {
|
|
||||||
if (browser.tizen || browser.orsay || browser.edgeUwp) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (format === 'asf') {
|
|
||||||
if (browser.tizen || browser.web0s || browser.edgeUwp) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (format === 'opus') {
|
|
||||||
if (!browser.web0s) {
|
|
||||||
typeString = 'audio/ogg; codecs="opus"';
|
|
||||||
return !!document.createElement('audio').canPlayType(typeString).replace(/no/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else if (format === 'alac') {
|
|
||||||
if (browser.iOS || browser.osx) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if (format === 'mp2') {
|
|
||||||
// For now
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (format === 'webma') {
|
|
||||||
typeString = 'audio/webm';
|
|
||||||
} else if (format === 'mp2') {
|
|
||||||
typeString = 'audio/mpeg';
|
|
||||||
} else {
|
|
||||||
typeString = 'audio/' + format;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!document.createElement('audio').canPlayType(typeString).replace(/no/, '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function testCanPlayMkv(videoTestElement) {
|
|
||||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (videoTestElement.canPlayType('video/x-matroska').replace(/no/, '') ||
|
|
||||||
videoTestElement.canPlayType('video/mkv').replace(/no/, '')) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unfortunately there's no real way to detect mkv support
|
|
||||||
if (browser.chrome) {
|
|
||||||
// Not supported on opera tv
|
|
||||||
if (browser.operaTv) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var userAgent = navigator.userAgent.toLowerCase();
|
|
||||||
|
|
||||||
// Filter out browsers based on chromium that don't support mkv
|
|
||||||
if (userAgent.indexOf('vivaldi') !== -1 || userAgent.indexOf('opera') !== -1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.edgeUwp) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function testCanPlayTs() {
|
|
||||||
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function supportsMpeg2Video() {
|
|
||||||
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function supportsVc1() {
|
|
||||||
return browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFlvMseDirectPlayProfile() {
|
|
||||||
var videoAudioCodecs = ['aac'];
|
|
||||||
if (!browser.edge && !browser.msie) {
|
|
||||||
videoAudioCodecs.push('mp3');
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
Container: 'flv',
|
|
||||||
Type: 'Video',
|
|
||||||
VideoCodec: 'h264',
|
|
||||||
AudioCodec: videoAudioCodecs.join(',')
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options) {
|
|
||||||
var supported = false;
|
|
||||||
var profileContainer = container;
|
|
||||||
var videoCodecs = [];
|
|
||||||
|
|
||||||
switch (container) {
|
|
||||||
case 'asf':
|
|
||||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
videoAudioCodecs = [];
|
|
||||||
break;
|
|
||||||
case 'avi':
|
|
||||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
// New Samsung TV don't support XviD/DivX
|
|
||||||
// Explicitly add supported codecs to make other codecs be transcoded
|
|
||||||
if (browser.tizenVersion >= 4) {
|
|
||||||
videoCodecs.push('h264');
|
|
||||||
if (canPlayH265(videoTestElement, options)) {
|
|
||||||
videoCodecs.push('h265');
|
|
||||||
videoCodecs.push('hevc');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'mpg':
|
|
||||||
case 'mpeg':
|
|
||||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
break;
|
|
||||||
case 'flv':
|
|
||||||
supported = browser.tizen || browser.orsay;
|
|
||||||
//if (!supported && window.MediaSource != null && window.MediaSource.isTypeSupported('video/mp4; codecs="avc1.42E01E,mp4a.40.2"')) {
|
|
||||||
// return getFlvMseDirectPlayProfile();
|
|
||||||
//}
|
|
||||||
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.web0s || browser.chrome || browser.edgeUwp;
|
|
||||||
videoCodecs.push('h264');
|
|
||||||
break;
|
|
||||||
case 'm2ts':
|
|
||||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
videoCodecs.push('h264');
|
|
||||||
if (supportsVc1()) {
|
|
||||||
videoCodecs.push('vc1');
|
|
||||||
}
|
|
||||||
if (supportsMpeg2Video()) {
|
|
||||||
videoCodecs.push('mpeg2video');
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'wmv':
|
|
||||||
supported = browser.tizen || browser.orsay || browser.web0s || browser.edgeUwp;
|
|
||||||
videoAudioCodecs = [];
|
|
||||||
break;
|
|
||||||
case 'ts':
|
|
||||||
supported = testCanPlayTs();
|
|
||||||
videoCodecs.push('h264');
|
|
||||||
if (canPlayH265(videoTestElement, options)) {
|
|
||||||
videoCodecs.push('h265');
|
|
||||||
videoCodecs.push('hevc');
|
|
||||||
}
|
|
||||||
if (supportsVc1()) {
|
|
||||||
videoCodecs.push('vc1');
|
|
||||||
}
|
|
||||||
if (supportsMpeg2Video()) {
|
|
||||||
videoCodecs.push('mpeg2video');
|
|
||||||
}
|
|
||||||
profileContainer = 'ts,mpegts';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return supported ? {
|
|
||||||
Container: profileContainer,
|
|
||||||
Type: 'Video',
|
|
||||||
VideoCodec: videoCodecs.join(','),
|
|
||||||
AudioCodec: videoAudioCodecs.join(',')
|
|
||||||
} : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMaxBitrate() {
|
|
||||||
return 120000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getGlobalMaxVideoBitrate() {
|
|
||||||
var userAgent = navigator.userAgent.toLowerCase();
|
|
||||||
if (browser.chromecast) {
|
|
||||||
var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
|
||||||
if (isChromecastUltra) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a hack to try and detect chromecast on vizio
|
|
||||||
if (self.screen && self.screen.width >= 3800) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 30000000;
|
|
||||||
}
|
|
||||||
|
|
||||||
var isTizenFhd = false;
|
|
||||||
if (browser.tizen) {
|
|
||||||
try {
|
|
||||||
var isTizenUhd = webapis.productinfo.isUdPanelSupported();
|
|
||||||
isTizenFhd = !isTizenUhd;
|
|
||||||
console.debug("isTizenFhd = " + isTizenFhd);
|
|
||||||
} catch (error) {
|
|
||||||
console.error("isUdPanelSupported() error code = " + error.code);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return browser.ps4 ? 8000000 :
|
|
||||||
(browser.xboxOne ? 12000000 :
|
|
||||||
(browser.edgeUwp ? null :
|
|
||||||
(browser.tizen && isTizenFhd ? 20000000 : null)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return function (options) {
|
|
||||||
options = options || {};
|
|
||||||
|
|
||||||
var physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
|
|
||||||
|
|
||||||
var bitrateSetting = getMaxBitrate();
|
|
||||||
|
|
||||||
var videoTestElement = document.createElement('video');
|
|
||||||
|
|
||||||
var canPlayVp8 = videoTestElement.canPlayType('video/webm; codecs="vp8"').replace(/no/, '');
|
|
||||||
var canPlayVp9 = videoTestElement.canPlayType('video/webm; codecs="vp9"').replace(/no/, '');
|
|
||||||
var webmAudioCodecs = ['vorbis'];
|
|
||||||
|
|
||||||
var canPlayMkv = testCanPlayMkv(videoTestElement);
|
|
||||||
|
|
||||||
var profile = {};
|
|
||||||
|
|
||||||
profile.MaxStreamingBitrate = bitrateSetting;
|
|
||||||
profile.MaxStaticBitrate = 100000000;
|
|
||||||
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000);
|
|
||||||
|
|
||||||
profile.DirectPlayProfiles = [];
|
|
||||||
|
|
||||||
var videoAudioCodecs = [];
|
|
||||||
var hlsVideoAudioCodecs = [];
|
|
||||||
|
|
||||||
var supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '') ||
|
|
||||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '');
|
|
||||||
|
|
||||||
// Not sure how to test for this
|
|
||||||
var supportsMp2VideoAudio = browser.edgeUwp || browser.tizen || browser.orsay || browser.web0s;
|
|
||||||
|
|
||||||
var maxVideoWidth = browser.xboxOne ?
|
|
||||||
(self.screen ? self.screen.width : null) :
|
|
||||||
null;
|
|
||||||
|
|
||||||
if (options.maxVideoWidth) {
|
|
||||||
maxVideoWidth = options.maxVideoWidth;
|
|
||||||
}
|
|
||||||
|
|
||||||
var canPlayAacVideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"').replace(/no/, '');
|
|
||||||
|
|
||||||
if (canPlayAacVideoAudio && browser.chromecast && physicalAudioChannels <= 2) {
|
|
||||||
// prioritize this first
|
|
||||||
videoAudioCodecs.push('aac');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only put mp3 first if mkv support is there
|
|
||||||
// Otherwise with HLS and mp3 audio we're seeing some browsers
|
|
||||||
// safari is lying
|
|
||||||
if (supportsAc3(videoTestElement)) {
|
|
||||||
|
|
||||||
videoAudioCodecs.push('ac3');
|
|
||||||
|
|
||||||
var eAc3 = supportsEac3(videoTestElement);
|
|
||||||
if (eAc3) {
|
|
||||||
videoAudioCodecs.push('eac3');
|
|
||||||
}
|
|
||||||
|
|
||||||
// This works in edge desktop, but not mobile
|
|
||||||
// TODO: Retest this on mobile
|
|
||||||
if (supportsAc3InHls(videoTestElement)) {
|
|
||||||
hlsVideoAudioCodecs.push('ac3');
|
|
||||||
if (eAc3) {
|
|
||||||
hlsVideoAudioCodecs.push('eac3');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayAacVideoAudio && browser.chromecast && videoAudioCodecs.indexOf('aac') === -1) {
|
|
||||||
// prioritize this first
|
|
||||||
videoAudioCodecs.push('aac');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsMp3VideoAudio) {
|
|
||||||
videoAudioCodecs.push('mp3');
|
|
||||||
|
|
||||||
// PS4 fails to load HLS with mp3 audio
|
|
||||||
if (!browser.ps4) {
|
|
||||||
// mp3 encoder only supports 2 channels, so only make that preferred if we're only requesting 2 channels
|
|
||||||
// Also apply it for chromecast because it no longer supports AAC 5.1
|
|
||||||
if (physicalAudioChannels <= 2) {
|
|
||||||
hlsVideoAudioCodecs.push('mp3');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayAacVideoAudio) {
|
|
||||||
if (videoAudioCodecs.indexOf('aac') === -1) {
|
|
||||||
videoAudioCodecs.push('aac');
|
|
||||||
}
|
|
||||||
|
|
||||||
hlsVideoAudioCodecs.push('aac');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsMp3VideoAudio) {
|
|
||||||
// PS4 fails to load HLS with mp3 audio
|
|
||||||
if (!browser.ps4) {
|
|
||||||
if (hlsVideoAudioCodecs.indexOf('mp3') === -1) {
|
|
||||||
hlsVideoAudioCodecs.push('mp3');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsMp2VideoAudio) {
|
|
||||||
videoAudioCodecs.push('mp2');
|
|
||||||
}
|
|
||||||
|
|
||||||
var supportsDts = browser.tizen || browser.orsay || browser.web0s || options.supportsDts;
|
|
||||||
|
|
||||||
// DTS audio not supported in 2018 models (Tizen 4.0)
|
|
||||||
if (browser.tizenVersion >= 4) {
|
|
||||||
supportsDts = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsDts) {
|
|
||||||
videoAudioCodecs.push('dca');
|
|
||||||
videoAudioCodecs.push('dts');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.tizen || browser.orsay || browser.web0s) {
|
|
||||||
videoAudioCodecs.push('pcm_s16le');
|
|
||||||
videoAudioCodecs.push('pcm_s24le');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.supportsTrueHd) {
|
|
||||||
videoAudioCodecs.push('truehd');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.tizen || browser.orsay) {
|
|
||||||
videoAudioCodecs.push('aac_latm');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayAudioFormat('opus')) {
|
|
||||||
videoAudioCodecs.push('opus');
|
|
||||||
hlsVideoAudioCodecs.push('opus');
|
|
||||||
webmAudioCodecs.push('opus');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayAudioFormat('flac')) {
|
|
||||||
videoAudioCodecs.push('flac');
|
|
||||||
}
|
|
||||||
|
|
||||||
videoAudioCodecs = videoAudioCodecs.filter(function (c) {
|
|
||||||
return (options.disableVideoAudioCodecs || []).indexOf(c) === -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
hlsVideoAudioCodecs = hlsVideoAudioCodecs.filter(function (c) {
|
|
||||||
return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1;
|
|
||||||
});
|
|
||||||
|
|
||||||
var mp4VideoCodecs = [];
|
|
||||||
var hlsVideoCodecs = [];
|
|
||||||
|
|
||||||
if (canPlayH264(videoTestElement)) {
|
|
||||||
mp4VideoCodecs.push('h264');
|
|
||||||
hlsVideoCodecs.push('h264');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayH265(videoTestElement, options)) {
|
|
||||||
mp4VideoCodecs.push('h265');
|
|
||||||
mp4VideoCodecs.push('hevc');
|
|
||||||
|
|
||||||
if (browser.tizen || browser.web0s) {
|
|
||||||
hlsVideoCodecs.push('h265');
|
|
||||||
hlsVideoCodecs.push('hevc');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsMpeg2Video()) {
|
|
||||||
mp4VideoCodecs.push('mpeg2video');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (supportsVc1()) {
|
|
||||||
mp4VideoCodecs.push('vc1');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.tizen || browser.orsay) {
|
|
||||||
mp4VideoCodecs.push('msmpeg4v2');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayVp8) {
|
|
||||||
mp4VideoCodecs.push('vp8');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayVp9) {
|
|
||||||
mp4VideoCodecs.push('vp9');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayVp8 || browser.tizen || browser.orsay) {
|
|
||||||
videoAudioCodecs.push('vorbis');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mp4VideoCodecs.length) {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: 'mp4,m4v',
|
|
||||||
Type: 'Video',
|
|
||||||
VideoCodec: mp4VideoCodecs.join(','),
|
|
||||||
AudioCodec: videoAudioCodecs.join(',')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayMkv && mp4VideoCodecs.length) {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: 'mkv',
|
|
||||||
Type: 'Video',
|
|
||||||
VideoCodec: mp4VideoCodecs.join(','),
|
|
||||||
AudioCodec: videoAudioCodecs.join(',')
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// These are formats we can't test for but some devices will support
|
|
||||||
['m2ts', 'wmv', 'ts', 'asf', 'avi', 'mpg', 'mpeg', 'flv', '3gp', 'mts', 'trp', 'vob', 'vro', 'mov'].map(function (container) {
|
|
||||||
return getDirectPlayProfileForVideoContainer(container, videoAudioCodecs, videoTestElement, options);
|
|
||||||
}).filter(function (i) {
|
|
||||||
return i != null;
|
|
||||||
}).forEach(function (i) {
|
|
||||||
profile.DirectPlayProfiles.push(i);
|
|
||||||
});
|
|
||||||
|
|
||||||
['opus', 'mp3', 'mp2', 'aac', 'flac', 'alac', 'webma', 'wma', 'wav', 'ogg', 'oga'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
|
||||||
|
|
||||||
if (audioFormat === 'mp2') {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: 'mp2,mp3',
|
|
||||||
Type: 'Audio',
|
|
||||||
AudioCodec: audioFormat
|
|
||||||
});
|
|
||||||
} else if (audioFormat === 'mp3') {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: audioFormat,
|
|
||||||
Type: 'Audio',
|
|
||||||
AudioCodec: audioFormat
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: audioFormat === 'webma' ? 'webma,webm' : audioFormat,
|
|
||||||
Type: 'Audio'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// aac also appears in the m4a and m4b container
|
|
||||||
if (audioFormat === 'aac' || audioFormat === 'alac') {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: 'm4a,m4b',
|
|
||||||
AudioCodec: audioFormat,
|
|
||||||
Type: 'Audio'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (canPlayVp8) {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: 'webm',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: webmAudioCodecs.join(','),
|
|
||||||
VideoCodec: 'VP8'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayVp9) {
|
|
||||||
profile.DirectPlayProfiles.push({
|
|
||||||
Container: 'webm',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: webmAudioCodecs.join(','),
|
|
||||||
VideoCodec: 'VP9'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.TranscodingProfiles = [];
|
|
||||||
|
|
||||||
var hlsBreakOnNonKeyFrames = browser.iOS || browser.osx || browser.edge || !canPlayNativeHls() ? true : false;
|
|
||||||
|
|
||||||
if (canPlayHls() && browser.enableHlsAudio !== false) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
// hlsjs, edge, and android all seem to require ts container
|
|
||||||
Container: !canPlayNativeHls() || browser.edge || browser.android ? 'ts' : 'aac',
|
|
||||||
Type: 'Audio',
|
|
||||||
AudioCodec: 'aac',
|
|
||||||
Context: 'Streaming',
|
|
||||||
Protocol: 'hls',
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
|
||||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
|
||||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// For streaming, prioritize opus transcoding after mp3/aac. It is too problematic with random failures
|
|
||||||
// But for static (offline sync), it will be just fine.
|
|
||||||
// Prioritize aac higher because the encoder can accept more channels than mp3
|
|
||||||
['aac', 'mp3', 'opus', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: audioFormat,
|
|
||||||
Type: 'Audio',
|
|
||||||
AudioCodec: audioFormat,
|
|
||||||
Context: 'Streaming',
|
|
||||||
Protocol: 'http',
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
['opus', 'mp3', 'aac', 'wav'].filter(canPlayAudioFormat).forEach(function (audioFormat) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: audioFormat,
|
|
||||||
Type: 'Audio',
|
|
||||||
AudioCodec: audioFormat,
|
|
||||||
Context: 'Static',
|
|
||||||
Protocol: 'http',
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString()
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (canPlayMkv && !browser.tizen && !browser.orsay && options.enableMkvProgressive !== false) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: 'mkv',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: videoAudioCodecs.join(','),
|
|
||||||
VideoCodec: mp4VideoCodecs.join(','),
|
|
||||||
Context: 'Streaming',
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
|
||||||
CopyTimestamps: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayMkv) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: 'mkv',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: videoAudioCodecs.join(','),
|
|
||||||
VideoCodec: mp4VideoCodecs.join(','),
|
|
||||||
Context: 'Static',
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
|
||||||
CopyTimestamps: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayHls() && hlsVideoAudioCodecs.length && options.enableHls !== false) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: 'ts',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: hlsVideoAudioCodecs.join(','),
|
|
||||||
VideoCodec: hlsVideoCodecs.join(','),
|
|
||||||
Context: 'Streaming',
|
|
||||||
Protocol: 'hls',
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
|
||||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
|
||||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canPlayVp8) {
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: 'webm',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: 'vorbis',
|
|
||||||
VideoCodec: 'vpx',
|
|
||||||
Context: 'Streaming',
|
|
||||||
Protocol: 'http',
|
|
||||||
// If audio transcoding is needed, limit channels to number of physical audio channels
|
|
||||||
// Trying to transcode to 5 channels when there are only 2 speakers generally does not sound good
|
|
||||||
MaxAudioChannels: physicalAudioChannels.toString()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.TranscodingProfiles.push({
|
|
||||||
Container: 'mp4',
|
|
||||||
Type: 'Video',
|
|
||||||
AudioCodec: videoAudioCodecs.join(','),
|
|
||||||
VideoCodec: 'h264',
|
|
||||||
Context: 'Static',
|
|
||||||
Protocol: 'http'
|
|
||||||
});
|
|
||||||
|
|
||||||
profile.ContainerProfiles = [];
|
|
||||||
|
|
||||||
profile.CodecProfiles = [];
|
|
||||||
|
|
||||||
var supportsSecondaryAudio = browser.tizen || browser.orsay || videoTestElement.audioTracks;
|
|
||||||
|
|
||||||
var aacCodecProfileConditions = [];
|
|
||||||
|
|
||||||
// Handle he-aac not supported
|
|
||||||
if (!videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.5"').replace(/no/, '')) {
|
|
||||||
// TODO: This needs to become part of the stream url in order to prevent stream copy
|
|
||||||
aacCodecProfileConditions.push({
|
|
||||||
Condition: 'NotEquals',
|
|
||||||
Property: 'AudioProfile',
|
|
||||||
Value: 'HE-AAC'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportsSecondaryAudio) {
|
|
||||||
aacCodecProfileConditions.push({
|
|
||||||
Condition: 'Equals',
|
|
||||||
Property: 'IsSecondaryAudio',
|
|
||||||
Value: 'false',
|
|
||||||
IsRequired: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.chromecast) {
|
|
||||||
aacCodecProfileConditions.push({
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'AudioChannels',
|
|
||||||
Value: '2',
|
|
||||||
IsRequired: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (aacCodecProfileConditions.length) {
|
|
||||||
profile.CodecProfiles.push({
|
|
||||||
Type: 'VideoAudio',
|
|
||||||
Codec: 'aac',
|
|
||||||
Conditions: aacCodecProfileConditions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!supportsSecondaryAudio) {
|
|
||||||
profile.CodecProfiles.push({
|
|
||||||
Type: 'VideoAudio',
|
|
||||||
Conditions: [
|
|
||||||
{
|
|
||||||
Condition: 'Equals',
|
|
||||||
Property: 'IsSecondaryAudio',
|
|
||||||
Value: 'false',
|
|
||||||
IsRequired: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var maxH264Level = 42;
|
|
||||||
var h264Profiles = 'high|main|baseline|constrained baseline';
|
|
||||||
|
|
||||||
if (browser.tizen || browser.orsay || browser.web0s ||
|
|
||||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.640833"').replace(/no/, '')) {
|
|
||||||
maxH264Level = 51;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Support H264 Level 52 (Tizen 5.0) - app only
|
|
||||||
if (browser.tizenVersion >= 5 && window.NativeShell) {
|
|
||||||
maxH264Level = 52;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.tizen || browser.orsay ||
|
|
||||||
videoTestElement.canPlayType('video/mp4; codecs="avc1.6e0033"').replace(/no/, '')) {
|
|
||||||
|
|
||||||
// These tests are passing in safari, but playback is failing
|
|
||||||
if (!browser.safari && !browser.iOS && !browser.web0s && !browser.edge && !browser.mobile) {
|
|
||||||
h264Profiles += '|high 10';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.CodecProfiles.push({
|
|
||||||
Type: 'Video',
|
|
||||||
Codec: 'h264',
|
|
||||||
Conditions: [
|
|
||||||
{
|
|
||||||
Condition: 'NotEquals',
|
|
||||||
Property: 'IsAnamorphic',
|
|
||||||
Value: 'true',
|
|
||||||
IsRequired: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Condition: 'EqualsAny',
|
|
||||||
Property: 'VideoProfile',
|
|
||||||
Value: h264Profiles,
|
|
||||||
IsRequired: false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'VideoLevel',
|
|
||||||
Value: maxH264Level.toString(),
|
|
||||||
IsRequired: false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!browser.edgeUwp && !browser.tizen && !browser.orsay && !browser.web0s) {
|
|
||||||
//profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
|
||||||
// Condition: 'NotEquals',
|
|
||||||
// Property: 'IsAVC',
|
|
||||||
// Value: 'false',
|
|
||||||
// IsRequired: false
|
|
||||||
//});
|
|
||||||
|
|
||||||
//profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
|
||||||
// Condition: 'NotEquals',
|
|
||||||
// Property: 'IsInterlaced',
|
|
||||||
// Value: 'true',
|
|
||||||
// IsRequired: false
|
|
||||||
//});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxVideoWidth) {
|
|
||||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'Width',
|
|
||||||
Value: maxVideoWidth.toString(),
|
|
||||||
IsRequired: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString();
|
|
||||||
|
|
||||||
var h264MaxVideoBitrate = globalMaxVideoBitrate;
|
|
||||||
|
|
||||||
if (h264MaxVideoBitrate) {
|
|
||||||
profile.CodecProfiles[profile.CodecProfiles.length - 1].Conditions.push({
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'VideoBitrate',
|
|
||||||
Value: h264MaxVideoBitrate,
|
|
||||||
IsRequired: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
var globalVideoConditions = [];
|
|
||||||
|
|
||||||
if (globalMaxVideoBitrate) {
|
|
||||||
globalVideoConditions.push({
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'VideoBitrate',
|
|
||||||
Value: globalMaxVideoBitrate
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (maxVideoWidth) {
|
|
||||||
globalVideoConditions.push({
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'Width',
|
|
||||||
Value: maxVideoWidth.toString(),
|
|
||||||
IsRequired: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (globalVideoConditions.length) {
|
|
||||||
profile.CodecProfiles.push({
|
|
||||||
Type: 'Video',
|
|
||||||
Conditions: globalVideoConditions
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (browser.chromecast) {
|
|
||||||
profile.CodecProfiles.push({
|
|
||||||
Type: 'Audio',
|
|
||||||
Codec: 'flac',
|
|
||||||
Conditions: [
|
|
||||||
{
|
|
||||||
Condition: 'LessThanEqual',
|
|
||||||
Property: 'AudioSampleRate',
|
|
||||||
Value: '96000'
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtitle profiles
|
|
||||||
// External vtt or burn in
|
|
||||||
profile.SubtitleProfiles = [];
|
|
||||||
if (supportsTextTracks()) {
|
|
||||||
profile.SubtitleProfiles.push({
|
|
||||||
Format: 'vtt',
|
|
||||||
Method: 'External'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
profile.ResponseProfiles = [];
|
|
||||||
profile.ResponseProfiles.push({
|
|
||||||
Type: 'Video',
|
|
||||||
Container: 'm4v',
|
|
||||||
MimeType: 'video/mp4'
|
|
||||||
});
|
|
||||||
|
|
||||||
return profile;
|
|
||||||
};
|
|
||||||
});
|
|
Loading…
Reference in New Issue
Block a user