add initial support for fMP4-HLS
This commit is contained in:
parent
0985909943
commit
54db12359c
9 changed files with 255 additions and 45 deletions
|
@ -33,7 +33,6 @@ function getDeviceProfile(item, options = {}) {
|
|||
profile = window.NativeShell.AppHost.getDeviceProfile(profileBuilder);
|
||||
} else {
|
||||
const builderOpts = getBaseProfileOptions(item);
|
||||
builderOpts.enableSsaRender = (item && !options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats');
|
||||
profile = profileBuilder(builderOpts);
|
||||
}
|
||||
|
||||
|
|
|
@ -145,6 +145,8 @@ import 'emby-checkbox';
|
|||
|
||||
showHideQualityFields(context, user, apiClient);
|
||||
|
||||
context.querySelector('#selectAllowedAudioChannels').value = userSettings.allowedAudioChannels();
|
||||
|
||||
apiClient.getCultures().then(allCultures => {
|
||||
populateLanguages(context.querySelector('#selectAudioLanguage'), allCultures);
|
||||
|
||||
|
@ -187,6 +189,7 @@ import 'emby-checkbox';
|
|||
}
|
||||
|
||||
context.querySelector('.chkPlayDefaultAudioTrack').checked = user.Configuration.PlayDefaultAudioTrack || false;
|
||||
context.querySelector('.chkPreferFmp4HlsContainer').checked = userSettings.preferFmp4HlsContainer();
|
||||
context.querySelector('.chkEnableCinemaMode').checked = userSettings.enableCinemaMode();
|
||||
context.querySelector('.chkEnableNextVideoOverlay').checked = userSettings.enableNextVideoInfoOverlay();
|
||||
context.querySelector('.chkExternalVideoPlayer').checked = appSettings.enableSystemExternalPlayers();
|
||||
|
@ -222,10 +225,11 @@ import 'emby-checkbox';
|
|||
setMaxBitrateFromField(context.querySelector('.selectVideoInternetQuality'), false, 'Video');
|
||||
setMaxBitrateFromField(context.querySelector('.selectMusicInternetQuality'), false, 'Audio');
|
||||
|
||||
userSettingsInstance.allowedAudioChannels(context.querySelector('#selectAllowedAudioChannels').value);
|
||||
user.Configuration.AudioLanguagePreference = context.querySelector('#selectAudioLanguage').value;
|
||||
user.Configuration.PlayDefaultAudioTrack = context.querySelector('.chkPlayDefaultAudioTrack').checked;
|
||||
user.Configuration.EnableNextEpisodeAutoPlay = context.querySelector('.chkEpisodeAutoPlay').checked;
|
||||
|
||||
userSettingsInstance.preferFmp4HlsContainer(context.querySelector('.chkPreferFmp4HlsContainer').checked);
|
||||
userSettingsInstance.enableCinemaMode(context.querySelector('.chkEnableCinemaMode').checked);
|
||||
|
||||
userSettingsInstance.enableNextVideoInfoOverlay(context.querySelector('.chkEnableNextVideoOverlay').checked);
|
||||
|
|
|
@ -4,6 +4,16 @@
|
|||
${HeaderAudioSettings}
|
||||
</h2>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectAllowedAudioChannels" label="${LabelAllowedAudioChannels}">
|
||||
<option value="-1">${Auto}</option>
|
||||
<option value="1">${LabelSelectMono}</option>
|
||||
<option value="2">${LabelSelectStereo}</option>
|
||||
<option value="6">5.1 ${LabelSelectAudioChannels}</option>
|
||||
<option value="8">7.1 ${LabelSelectAudioChannels}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="selectContainer">
|
||||
<select is="emby-select" id="selectAudioLanguage" label="${LabelAudioLanguagePreference}"></select>
|
||||
</div>
|
||||
|
@ -49,6 +59,14 @@
|
|||
${TabAdvanced}
|
||||
</h2>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkPreferFmp4HlsContainer" />
|
||||
<span>${PreferFmp4HlsContainer}</span>
|
||||
</label>
|
||||
<div class="fieldDescription checkboxFieldDescription">${PreferFmp4HlsContainerHelp}</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxContainer checkboxContainer-withDescription cinemaModeOptions">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" class="chkEnableCinemaMode" />
|
||||
|
|
|
@ -92,6 +92,15 @@
|
|||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="checkboxListContainer">
|
||||
<div class="checkboxList">
|
||||
<label>
|
||||
<input type="checkbox" is="emby-checkbox" id="chkAllowHevcEncoding" />
|
||||
<span>${AllowHevcEncoding}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tonemappingOptions hide">
|
||||
|
|
|
@ -13,6 +13,7 @@ import libraryMenu from 'libraryMenu';
|
|||
page.querySelector('#chkDecodingColorDepth10Hevc').checked = config.EnableDecodingColorDepth10Hevc;
|
||||
page.querySelector('#chkDecodingColorDepth10Vp9').checked = config.EnableDecodingColorDepth10Vp9;
|
||||
page.querySelector('#chkHardwareEncoding').checked = config.EnableHardwareEncoding;
|
||||
page.querySelector('#chkAllowHevcEncoding').checked = config.AllowHevcEncoding;
|
||||
$('#selectVideoDecoder', page).val(config.HardwareAccelerationType);
|
||||
$('#selectThreadCount', page).val(config.EncodingThreadCount);
|
||||
$('#txtDownMixAudioBoost', page).val(config.DownMixAudioBoost);
|
||||
|
@ -98,6 +99,7 @@ import libraryMenu from 'libraryMenu';
|
|||
config.EnableDecodingColorDepth10Hevc = form.querySelector('#chkDecodingColorDepth10Hevc').checked;
|
||||
config.EnableDecodingColorDepth10Vp9 = form.querySelector('#chkDecodingColorDepth10Vp9').checked;
|
||||
config.EnableHardwareEncoding = form.querySelector('#chkHardwareEncoding').checked;
|
||||
config.AllowHevcEncoding = form.querySelector('#chkAllowHevcEncoding').checked;
|
||||
ApiClient.updateNamedConfiguration('encoding', config).then(function () {
|
||||
updateEncoder(form);
|
||||
}, function () {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
define(['browser'], function (browser) {
|
||||
define(['browser', 'userSettings', 'appSettings'], function (browser, userSettings, appSettings) {
|
||||
'use strict';
|
||||
|
||||
browser = browser.default || browser;
|
||||
|
@ -7,7 +7,7 @@ define(['browser'], function (browser) {
|
|||
return !!(videoTestElement.canPlayType && videoTestElement.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''));
|
||||
}
|
||||
|
||||
function canPlayH265(videoTestElement, options) {
|
||||
function canPlayHevc(videoTestElement, options) {
|
||||
if (browser.tizen || browser.xboxOne || browser.web0s || options.supportsHevc) {
|
||||
return true;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ define(['browser'], function (browser) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// hevc main level 4.0
|
||||
return !!videoTestElement.canPlayType &&
|
||||
(videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.L120"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.L120"').replace(/no/, '') ||
|
||||
|
@ -207,8 +208,7 @@ define(['browser'], function (browser) {
|
|||
// Explicitly add supported codecs to make other codecs be transcoded
|
||||
if (browser.tizenVersion >= 4) {
|
||||
videoCodecs.push('h264');
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
videoCodecs.push('h265');
|
||||
if (canPlayHevc(videoTestElement, options)) {
|
||||
videoCodecs.push('hevc');
|
||||
}
|
||||
}
|
||||
|
@ -248,8 +248,8 @@ define(['browser'], function (browser) {
|
|||
case 'ts':
|
||||
supported = testCanPlayTs();
|
||||
videoCodecs.push('h264');
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
videoCodecs.push('h265');
|
||||
// safari doesn't support hevc in TS-HLS
|
||||
if ((browser.tizen || browser.web0s) && canPlayHevc(videoTestElement, options)) {
|
||||
videoCodecs.push('hevc');
|
||||
}
|
||||
if (supportsVc1(videoTestElement)) {
|
||||
|
@ -297,7 +297,9 @@ define(['browser'], function (browser) {
|
|||
return function (options) {
|
||||
options = options || {};
|
||||
|
||||
const physicalAudioChannels = options.audioChannels || (browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
|
||||
const isSurroundSoundSupportedBrowser = browser.safari || browser.chrome || browser.edgeChromium || browser.firefox;
|
||||
const allowedAudioChannels = parseInt(userSettings.allowedAudioChannels() || '-1');
|
||||
const physicalAudioChannels = (allowedAudioChannels > 0 ? allowedAudioChannels : null) || options.audioChannels || (isSurroundSoundSupportedBrowser || browser.tv || browser.ps4 || browser.xboxOne ? 6 : 2);
|
||||
|
||||
const bitrateSetting = getMaxBitrate();
|
||||
|
||||
|
@ -313,12 +315,13 @@ define(['browser'], function (browser) {
|
|||
|
||||
profile.MaxStreamingBitrate = bitrateSetting;
|
||||
profile.MaxStaticBitrate = 100000000;
|
||||
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 192000);
|
||||
profile.MusicStreamingTranscodingBitrate = Math.min(bitrateSetting, 384000);
|
||||
|
||||
profile.DirectPlayProfiles = [];
|
||||
|
||||
let videoAudioCodecs = [];
|
||||
let hlsVideoAudioCodecs = [];
|
||||
let hlsInTsVideoAudioCodecs = [];
|
||||
let hlsInFmp4VideoAudioCodecs = [];
|
||||
|
||||
const supportsMp3VideoAudio = videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"').replace(/no/, '')
|
||||
|| videoTestElement.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"').replace(/no/, '')
|
||||
|
@ -353,16 +356,19 @@ define(['browser'], function (browser) {
|
|||
// Transcoding codec is the first in hlsVideoAudioCodecs
|
||||
// Put ac3/eac3 first only when the audio channels > 2 and need transcoding
|
||||
if (canPlayAc3VideoAudioInHls && physicalAudioChannels > 2) {
|
||||
hlsVideoAudioCodecs.push('ac3');
|
||||
hlsInTsVideoAudioCodecs.push('ac3');
|
||||
hlsInFmp4VideoAudioCodecs.push('ac3');
|
||||
if (canPlayEac3VideoAudio) {
|
||||
hlsVideoAudioCodecs.push('eac3');
|
||||
hlsInTsVideoAudioCodecs.push('eac3');
|
||||
hlsInFmp4VideoAudioCodecs.push('eac3');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayAacVideoAudio) {
|
||||
videoAudioCodecs.push('aac');
|
||||
hlsVideoAudioCodecs.push('aac');
|
||||
hlsInTsVideoAudioCodecs.push('aac');
|
||||
hlsInFmp4VideoAudioCodecs.push('aac');
|
||||
}
|
||||
|
||||
if (supportsMp3VideoAudio) {
|
||||
|
@ -370,16 +376,31 @@ define(['browser'], function (browser) {
|
|||
|
||||
// PS4 fails to load HLS with mp3 audio
|
||||
if (!browser.ps4) {
|
||||
hlsVideoAudioCodecs.push('mp3');
|
||||
hlsInTsVideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
hlsInFmp4VideoAudioCodecs.push('mp3');
|
||||
}
|
||||
|
||||
// For ac3/eac3 directstream
|
||||
if (canPlayAc3VideoAudio) {
|
||||
if (canPlayAc3VideoAudioInHls && hlsVideoAudioCodecs.indexOf('ac3') === -1) {
|
||||
hlsVideoAudioCodecs.push('ac3');
|
||||
if (canPlayEac3VideoAudio && hlsVideoAudioCodecs.indexOf('eac3') === -1) {
|
||||
hlsVideoAudioCodecs.push('eac3');
|
||||
if (canPlayAc3VideoAudioInHls) {
|
||||
if (hlsInTsVideoAudioCodecs.indexOf('ac3') === -1) {
|
||||
hlsInTsVideoAudioCodecs.push('ac3');
|
||||
}
|
||||
|
||||
if (hlsInFmp4VideoAudioCodecs.indexOf('ac3') === -1) {
|
||||
hlsInFmp4VideoAudioCodecs.push('ac3');
|
||||
}
|
||||
|
||||
if (canPlayEac3VideoAudio) {
|
||||
if (hlsInTsVideoAudioCodecs.indexOf('eac3') === -1) {
|
||||
hlsInTsVideoAudioCodecs.push('eac3');
|
||||
}
|
||||
|
||||
if (hlsInFmp4VideoAudioCodecs.indexOf('eac3') === -1) {
|
||||
hlsInFmp4VideoAudioCodecs.push('eac3');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -415,38 +436,54 @@ define(['browser'], function (browser) {
|
|||
|
||||
if (canPlayAudioFormat('opus')) {
|
||||
videoAudioCodecs.push('opus');
|
||||
hlsVideoAudioCodecs.push('opus');
|
||||
hlsInTsVideoAudioCodecs.push('opus');
|
||||
webmAudioCodecs.push('opus');
|
||||
}
|
||||
|
||||
if (canPlayAudioFormat('flac')) {
|
||||
videoAudioCodecs.push('flac');
|
||||
hlsInFmp4VideoAudioCodecs.push('flac');
|
||||
}
|
||||
|
||||
if (canPlayAudioFormat('alac')) {
|
||||
videoAudioCodecs.push('alac');
|
||||
hlsInFmp4VideoAudioCodecs.push('alac');
|
||||
}
|
||||
|
||||
videoAudioCodecs = videoAudioCodecs.filter(function (c) {
|
||||
return (options.disableVideoAudioCodecs || []).indexOf(c) === -1;
|
||||
});
|
||||
|
||||
hlsVideoAudioCodecs = hlsVideoAudioCodecs.filter(function (c) {
|
||||
hlsInTsVideoAudioCodecs = hlsInTsVideoAudioCodecs.filter(function (c) {
|
||||
return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1;
|
||||
});
|
||||
|
||||
hlsInFmp4VideoAudioCodecs = hlsInFmp4VideoAudioCodecs.filter(function (c) {
|
||||
return (options.disableHlsVideoAudioCodecs || []).indexOf(c) === -1;
|
||||
});
|
||||
|
||||
const mp4VideoCodecs = [];
|
||||
const webmVideoCodecs = [];
|
||||
const hlsVideoCodecs = [];
|
||||
const hlsInTsVideoCodecs = [];
|
||||
const hlsInFmp4VideoCodecs = [];
|
||||
|
||||
if (browser.safari || browser.tizen || browser.web0s && canPlayHevc(videoTestElement, options)) {
|
||||
hlsInFmp4VideoCodecs.push('hevc');
|
||||
}
|
||||
|
||||
if (canPlayH264(videoTestElement)) {
|
||||
mp4VideoCodecs.push('h264');
|
||||
hlsVideoCodecs.push('h264');
|
||||
hlsInTsVideoCodecs.push('h264');
|
||||
|
||||
if (browser.safari || browser.tizen || browser.web0s) {
|
||||
hlsInFmp4VideoCodecs.push('h264');
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayH265(videoTestElement, options)) {
|
||||
mp4VideoCodecs.push('h265');
|
||||
mp4VideoCodecs.push('hevc');
|
||||
|
||||
if (browser.tizen || browser.web0s) {
|
||||
hlsVideoCodecs.push('h265');
|
||||
hlsVideoCodecs.push('hevc');
|
||||
if (canPlayHevc(videoTestElement, options)) {
|
||||
// safari is lying on HDR and 60fps videos, use fMP4 instead
|
||||
if (!browser.safari) {
|
||||
mp4VideoCodecs.push('hevc');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -606,18 +643,34 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
}
|
||||
|
||||
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 (canPlayHls() && options.enableHls !== false) {
|
||||
if (hlsInFmp4VideoCodecs.length && hlsInFmp4VideoAudioCodecs.length && userSettings.preferFmp4HlsContainer() && (browser.safari || browser.tizen || browser.web0s)) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'mp4',
|
||||
Type: 'Video',
|
||||
AudioCodec: hlsInFmp4VideoAudioCodecs.join(','),
|
||||
VideoCodec: hlsInFmp4VideoCodecs.join(','),
|
||||
Context: 'Streaming',
|
||||
Protocol: 'hls',
|
||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
||||
});
|
||||
}
|
||||
|
||||
if (hlsInTsVideoCodecs.length && hlsInTsVideoAudioCodecs.length) {
|
||||
profile.TranscodingProfiles.push({
|
||||
Container: 'ts',
|
||||
Type: 'Video',
|
||||
AudioCodec: hlsInTsVideoAudioCodecs.join(','),
|
||||
VideoCodec: hlsInTsVideoCodecs.join(','),
|
||||
Context: 'Streaming',
|
||||
Protocol: 'hls',
|
||||
MaxAudioChannels: physicalAudioChannels.toString(),
|
||||
MinSegments: browser.iOS || browser.osx ? '2' : '1',
|
||||
BreakOnNonKeyFrames: hlsBreakOnNonKeyFrames
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (canPlayVp8) {
|
||||
|
@ -713,6 +766,36 @@ define(['browser'], function (browser) {
|
|||
}
|
||||
}
|
||||
|
||||
let maxHevcLevel = 120;
|
||||
let hevcProfiles = 'main';
|
||||
|
||||
// hevc main level 4.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.1.4.L123"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.1.4.L123"').replace(/no/, '')) {
|
||||
maxHevcLevel = 123;
|
||||
}
|
||||
|
||||
// hevc main10 level 4.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L123"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L123"').replace(/no/, '')) {
|
||||
maxHevcLevel = 123;
|
||||
hevcProfiles = 'main|main 10';
|
||||
}
|
||||
|
||||
// hevc main10 level 5.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L153"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hev1.2.4.L153"').replace(/no/, '')) {
|
||||
maxHevcLevel = 153;
|
||||
hevcProfiles = 'main|main 10';
|
||||
}
|
||||
|
||||
// hevc main10 level 6.1
|
||||
if (videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '') ||
|
||||
videoTestElement.canPlayType('video/mp4; codecs="hvc1.2.4.L183"').replace(/no/, '')) {
|
||||
maxHevcLevel = 183;
|
||||
hevcProfiles = 'main|main 10';
|
||||
}
|
||||
|
||||
const h264CodecProfileConditions = [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
|
@ -734,6 +817,27 @@ define(['browser'], function (browser) {
|
|||
}
|
||||
];
|
||||
|
||||
const hevcCodecProfileConditions = [
|
||||
{
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsAnamorphic',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'EqualsAny',
|
||||
Property: 'VideoProfile',
|
||||
Value: hevcProfiles,
|
||||
IsRequired: false
|
||||
},
|
||||
{
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoLevel',
|
||||
Value: maxHevcLevel.toString(),
|
||||
IsRequired: false
|
||||
}
|
||||
];
|
||||
|
||||
if (!browser.edgeUwp && !browser.tizen && !browser.web0s) {
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'NotEquals',
|
||||
|
@ -741,6 +845,13 @@ define(['browser'], function (browser) {
|
|||
Value: 'true',
|
||||
IsRequired: false
|
||||
});
|
||||
|
||||
hevcCodecProfileConditions.push({
|
||||
Condition: 'NotEquals',
|
||||
Property: 'IsInterlaced',
|
||||
Value: 'true',
|
||||
IsRequired: false
|
||||
});
|
||||
}
|
||||
|
||||
if (maxVideoWidth) {
|
||||
|
@ -750,12 +861,21 @@ define(['browser'], function (browser) {
|
|||
Value: maxVideoWidth.toString(),
|
||||
IsRequired: false
|
||||
});
|
||||
|
||||
hevcCodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'Width',
|
||||
Value: maxVideoWidth.toString(),
|
||||
IsRequired: false
|
||||
});
|
||||
}
|
||||
|
||||
const globalMaxVideoBitrate = (getGlobalMaxVideoBitrate() || '').toString();
|
||||
|
||||
const h264MaxVideoBitrate = globalMaxVideoBitrate;
|
||||
|
||||
const hevcMaxVideoBitrate = globalMaxVideoBitrate;
|
||||
|
||||
if (h264MaxVideoBitrate) {
|
||||
h264CodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
|
@ -765,6 +885,15 @@ define(['browser'], function (browser) {
|
|||
});
|
||||
}
|
||||
|
||||
if (hevcMaxVideoBitrate) {
|
||||
hevcCodecProfileConditions.push({
|
||||
Condition: 'LessThanEqual',
|
||||
Property: 'VideoBitrate',
|
||||
Value: hevcMaxVideoBitrate,
|
||||
IsRequired: true
|
||||
});
|
||||
}
|
||||
|
||||
// On iOS 12.x, for TS container max h264 level is 4.2
|
||||
if (browser.iOS && browser.iOSVersion < 13) {
|
||||
const codecProfile = {
|
||||
|
@ -792,6 +921,12 @@ define(['browser'], function (browser) {
|
|||
Conditions: h264CodecProfileConditions
|
||||
});
|
||||
|
||||
profile.CodecProfiles.push({
|
||||
Type: 'Video',
|
||||
Codec: 'hevc',
|
||||
Conditions: hevcCodecProfileConditions
|
||||
});
|
||||
|
||||
const globalVideoConditions = [];
|
||||
|
||||
if (globalMaxVideoBitrate) {
|
||||
|
@ -827,7 +962,7 @@ define(['browser'], function (browser) {
|
|||
Method: 'External'
|
||||
});
|
||||
}
|
||||
if (options.enableSsaRender) {
|
||||
if (options.enableSsaRender !== false && (!options.isRetry && appSettings.get('subtitleburnin') !== 'allcomplexformats')) {
|
||||
profile.SubtitleProfiles.push({
|
||||
Format: 'ass',
|
||||
Method: 'External'
|
||||
|
|
|
@ -114,6 +114,33 @@ export class UserSettings {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Allowed Audio Channels'.
|
||||
* @param {string|undefined} val - 'Allowed Audio Channels'.
|
||||
* @return {string} 'Allowed Audio Channels'.
|
||||
*/
|
||||
allowedAudioChannels(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('allowedAudioChannels', val, false);
|
||||
}
|
||||
|
||||
return this.get('allowedAudioChannels', false) || '-1';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Perfer fMP4-HLS Container' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Perfer fMP4-HLS Container' or undefined.
|
||||
* @return {boolean} 'Prefer fMP4-HLS Container' state.
|
||||
*/
|
||||
preferFmp4HlsContainer(val) {
|
||||
if (val !== undefined) {
|
||||
return this.set('preferFmp4HlsContainer', val.toString(), false);
|
||||
}
|
||||
|
||||
val = this.get('preferFmp4HlsContainer', false);
|
||||
return val === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or set 'Cinema Mode' state.
|
||||
* @param {boolean|undefined} val - Flag to enable 'Cinema Mode' or undefined.
|
||||
|
@ -457,6 +484,8 @@ export const importFrom = currentSettings.importFrom.bind(currentSettings);
|
|||
export const set = currentSettings.set.bind(currentSettings);
|
||||
export const get = currentSettings.get.bind(currentSettings);
|
||||
export const serverConfig = currentSettings.serverConfig.bind(currentSettings);
|
||||
export const allowedAudioChannels = currentSettings.allowedAudioChannels.bind(currentSettings);
|
||||
export const preferFmp4HlsContainer = currentSettings.preferFmp4HlsContainer.bind(currentSettings);
|
||||
export const enableCinemaMode = currentSettings.enableCinemaMode.bind(currentSettings);
|
||||
export const enableNextVideoInfoOverlay = currentSettings.enableNextVideoInfoOverlay.bind(currentSettings);
|
||||
export const enableThemeSongs = currentSettings.enableThemeSongs.bind(currentSettings);
|
||||
|
|
|
@ -1424,5 +1424,12 @@
|
|||
"SubtitleVerticalPositionHelp": "Line number where text appears. Positive numbers indicate top down. Negative numbers indicate bottom up.",
|
||||
"Preview": "Preview",
|
||||
"LabelMaxMuxingQueueSize": "Max muxing queue size:",
|
||||
"LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048."
|
||||
"LabelMaxMuxingQueueSizeHelp": "Maximum number of packets that can be buffered while waiting for all streams to initialize. Try to increase it if you still encounter \"Too many packets buffered for output stream\" error in ffmpeg logs. The recommended value is 2048.",
|
||||
"PreferFmp4HlsContainer": "Prefer fMP4-HLS Media Container",
|
||||
"PreferFmp4HlsContainerHelp": "Prefer to use fMP4 as the default container for HLS, making it possible to direct streaming HEVC content on supported devices.",
|
||||
"AllowHevcEncoding": "Allow encoding in HEVC format",
|
||||
"LabelAllowedAudioChannels": "Maximum Allowed Audio Channels",
|
||||
"LabelSelectAudioChannels": "Channels",
|
||||
"LabelSelectMono": "Mono",
|
||||
"LabelSelectStereo": "Stereo"
|
||||
}
|
||||
|
|
|
@ -1425,5 +1425,12 @@
|
|||
"OptionAllowContentDownload": "允许媒体下载",
|
||||
"HeaderDeleteDevices": "删除所有设备",
|
||||
"DeleteDevicesConfirmation": "您确定要删除所有设备吗?所有其他会话将被注销。用户下次登录时,设备会重新出现。",
|
||||
"DeleteAll": "删除全部"
|
||||
"DeleteAll": "删除全部",
|
||||
"PreferFmp4HlsContainer": "优先使用 fMP4-HLS 媒体容器",
|
||||
"PreferFmp4HlsContainerHelp": "优先使用 fMP4 作为 HLS 播放的默认容器,从而可以在支持的设备上直接串流 HEVC 格式的内容。",
|
||||
"AllowHevcEncoding": "允许以 HEVC 格式编码",
|
||||
"LabelAllowedAudioChannels": "允许的最大声道数量",
|
||||
"LabelSelectAudioChannels": "声道",
|
||||
"LabelSelectMono": "单声道",
|
||||
"LabelSelectStereo": "立体声"
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue