Merge pull request #156 from vexorian/20201006_dev
Channel resolution and bitrate settings.
This commit is contained in:
commit
8ccbef998a
@ -23,7 +23,35 @@ class FFMPEG extends events.EventEmitter {
|
||||
this.channel = channel
|
||||
this.ffmpegPath = opts.ffmpegPath
|
||||
|
||||
var parsed = parseResolutionString(opts.targetResolution);
|
||||
let resString = opts.targetResolution;
|
||||
if (
|
||||
(typeof(channel.transcoding) !== 'undefined')
|
||||
&& (channel.transcoding.targetResolution != null)
|
||||
&& (typeof(channel.transcoding.targetResolution) != 'undefined')
|
||||
&& (channel.transcoding.targetResolution != "")
|
||||
) {
|
||||
resString = channel.transcoding.targetResolution;
|
||||
}
|
||||
|
||||
if (
|
||||
(typeof(channel.transcoding) !== 'undefined')
|
||||
&& (channel.transcoding.videoBitrate != null)
|
||||
&& (typeof(channel.transcoding.videoBitrate) != 'undefined')
|
||||
&& (channel.transcoding.videoBitrate != 0)
|
||||
) {
|
||||
opts.videoBitrate = channel.transcoding.videoBitrate;
|
||||
}
|
||||
|
||||
if (
|
||||
(typeof(channel.transcoding.videoBufSize) !== 'undefined')
|
||||
&& (channel.transcoding.videoBufSize != null)
|
||||
&& (typeof(channel.transcoding.videoBufSize) != 'undefined')
|
||||
&& (channel.transcoding.videoBufSize != 0)
|
||||
) {
|
||||
opts.videoBufSize = channel.transcoding.videoBufSize;
|
||||
}
|
||||
|
||||
let parsed = parseResolutionString(resString);
|
||||
this.wantedW = parsed.w;
|
||||
this.wantedH = parsed.h;
|
||||
|
||||
|
||||
@ -287,11 +287,13 @@ function video( channelDB , fillerDB, db) {
|
||||
};
|
||||
}
|
||||
|
||||
let combinedChannel = JSON.parse( JSON.stringify(brandChannel) );
|
||||
combinedChannel.transcoding = channel.transcoding;
|
||||
|
||||
let playerContext = {
|
||||
lineupItem : lineupItem,
|
||||
ffmpegSettings : ffmpegSettings,
|
||||
channel: brandChannel,
|
||||
channel: combinedChannel,
|
||||
db: db,
|
||||
m3u8: m3u8,
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ var app = angular.module('myApp', ['ngRoute', 'vs-repeat', 'angularLazyImg', 'dn
|
||||
|
||||
app.service('plex', require('./services/plex'))
|
||||
app.service('dizquetv', require('./services/dizquetv'))
|
||||
app.service('resolutionOptions', require('./services/resolution-options'))
|
||||
|
||||
app.directive('plexSettings', require('./directives/plex-settings'))
|
||||
app.directive('ffmpegSettings', require('./directives/ffmpeg-settings'))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
module.exports = function ($timeout, $location, dizquetv) {
|
||||
module.exports = function ($timeout, $location, dizquetv, resolutionOptions) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'templates/channel-config.html',
|
||||
@ -62,6 +62,9 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
scope.channel.name = "Channel 1"
|
||||
}
|
||||
scope.showRotatedNote = false;
|
||||
scope.channel.transcoding = {
|
||||
targetResolution: "",
|
||||
}
|
||||
} else {
|
||||
scope.beforeEditChannelNumber = scope.channel.number
|
||||
|
||||
@ -95,6 +98,18 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
) {
|
||||
scope.channel.guideMinimumDurationSeconds = 5 * 60;
|
||||
}
|
||||
|
||||
if (typeof(scope.channel.transcoding) ==='undefined') {
|
||||
scope.channel.transcoding = {};
|
||||
}
|
||||
if (
|
||||
(scope.channel.transcoding.targetResolution == null)
|
||||
|| (typeof(scope.channel.transcoding.targetResolution) === 'undefined')
|
||||
|| (scope.channel.transcoding.targetResolution === '')
|
||||
) {
|
||||
scope.channel.transcoding.targetResolution = "";
|
||||
}
|
||||
|
||||
|
||||
adjustStartTimeToCurrentProgram();
|
||||
updateChannelDuration();
|
||||
@ -786,6 +801,7 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
updateChannelDuration();
|
||||
}
|
||||
scope.padTimes = (paddingMod, allow5) => {
|
||||
console.log(paddingMod, allow5) ;
|
||||
let mod = paddingMod * 60 * 1000;
|
||||
if (mod == 0) {
|
||||
mod = 60*60*1000;
|
||||
@ -1122,6 +1138,7 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
scope.showRotatedNote = false;
|
||||
scope.channel.duration = 0
|
||||
scope.hasFlex = false;
|
||||
|
||||
for (let i = 0, l = scope.channel.programs.length; i < l; i++) {
|
||||
scope.channel.programs[i].start = new Date(scope.channel.startTime.valueOf() + scope.channel.duration)
|
||||
scope.channel.programs[i].$index = i;
|
||||
@ -1133,6 +1150,7 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
}
|
||||
scope.maxSize = Math.max(scope.maxSize, scope.channel.programs.length);
|
||||
scope.libraryLimit = Math.max(0, scope.maxSize - scope.channel.programs.length );
|
||||
scope.endTime = new Date( scope.channel.startTime.valueOf() + scope.channel.duration );
|
||||
}
|
||||
scope.error = {}
|
||||
scope._onDone = async (channel) => {
|
||||
@ -1462,6 +1480,14 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
]
|
||||
}
|
||||
|
||||
scope.resolutionOptions = [
|
||||
{ id: "", description: "(Use global setting)" },
|
||||
];
|
||||
resolutionOptions.get()
|
||||
.forEach( (a) => {
|
||||
scope.resolutionOptions.push(a)
|
||||
} );
|
||||
|
||||
scope.nightStartHours = [ { id: -1, description: "Start" } ];
|
||||
scope.nightEndHours = [ { id: -1, description: "End" } ];
|
||||
scope.nightStart = -1;
|
||||
@ -1569,22 +1595,26 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
scope.refreshFillerStuff();
|
||||
refreshFillerOptions();
|
||||
|
||||
let refreshScreenResolution = async () => {
|
||||
|
||||
function parseResolutionString(s) {
|
||||
var i = s.indexOf('x');
|
||||
function parseResolutionString(s) {
|
||||
var i = s.indexOf('x');
|
||||
if (i == -1) {
|
||||
i = s.indexOf("×");
|
||||
if (i == -1) {
|
||||
i = s.indexOf("×");
|
||||
if (i == -1) {
|
||||
return {w:1920, h:1080}
|
||||
}
|
||||
}
|
||||
return {
|
||||
w: parseInt( s.substring(0,i) , 10 ),
|
||||
h: parseInt( s.substring(i+1) , 10 ),
|
||||
return {w:1920, h:1080}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
w: parseInt( s.substring(0,i) , 10 ),
|
||||
h: parseInt( s.substring(i+1) , 10 ),
|
||||
}
|
||||
}
|
||||
|
||||
scope.videoRateDefault = "(Use global setting)";
|
||||
scope.videoBufSizeDefault = "(Use global setting)";
|
||||
|
||||
let refreshScreenResolution = async () => {
|
||||
|
||||
|
||||
try {
|
||||
let ffmpegSettings = await dizquetv.getFfmpegSettings()
|
||||
if (
|
||||
@ -1593,8 +1623,16 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
&& (typeof(ffmpegSettings.targetResolution) !== '')
|
||||
) {
|
||||
let p = parseResolutionString( ffmpegSettings.targetResolution );
|
||||
scope.resolutionOptions[0] = {
|
||||
id: "",
|
||||
description: `Use global setting (${ffmpegSettings.targetResolution})`,
|
||||
}
|
||||
ffmpegSettings.targetResolution
|
||||
scope.screenW = p.w;
|
||||
scope.screenH = p.h;
|
||||
scope.videoRateDefault = `global setting=${ffmpegSettings.videoBitrate}`;
|
||||
scope.videoBufSizeDefault = `global setting=${ffmpegSettings.videoBufSize}`;
|
||||
|
||||
$timeout();
|
||||
}
|
||||
} catch(err) {
|
||||
@ -1622,6 +1660,9 @@ module.exports = function ($timeout, $location, dizquetv) {
|
||||
}
|
||||
|
||||
scope.getCurrentWH = () => {
|
||||
if (scope.channel.transcoding.targetResolution !== '') {
|
||||
return parseResolutionString( scope.channel.transcoding.targetResolution );
|
||||
}
|
||||
return {
|
||||
w: scope.screenW,
|
||||
h: scope.screenH
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
module.exports = function (dizquetv) {
|
||||
module.exports = function (dizquetv, resolutionOptions) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
templateUrl: 'templates/ffmpeg-settings.html',
|
||||
@ -26,18 +26,7 @@
|
||||
scope.hideIfNotAutoPlay = () => {
|
||||
return scope.settings.enableAutoPlay != true
|
||||
};
|
||||
scope.resolutionOptions=[
|
||||
{id:"420x420",description:"420x420 (1:1)"},
|
||||
{id:"480x270",description:"480x270 (HD1080/16 16:9)"},
|
||||
{id:"576x320",description:"576x320 (18:10)"},
|
||||
{id:"640x360",description:"640x360 (nHD 16:9)"},
|
||||
{id:"720x480",description:"720x480 (WVGA 3:2)"},
|
||||
{id:"800x600",description:"800x600 (SVGA 4:3)"},
|
||||
{id:"1024x768",description:"1024x768 (WXGA 4:3)"},
|
||||
{id:"1280x720",description:"1280x720 (HD 16:9)"},
|
||||
{id:"1920x1080",description:"1920x1080 (FHD 16:9)"},
|
||||
{id:"3840x2160",description:"3840x2160 (4K 16:9)"},
|
||||
];
|
||||
scope.resolutionOptions= resolutionOptions.get();
|
||||
scope.muxDelayOptions=[
|
||||
{id:"0",description:"0 Seconds"},
|
||||
{id:"1",description:"1 Seconds"},
|
||||
|
||||
@ -47,13 +47,21 @@
|
||||
<!--
|
||||
============= TAB: PROGRAMMING =========================
|
||||
-->
|
||||
<div ng-if="tab == 'programming'" class='modal-semi-body'>
|
||||
<div class='form-group form-row' >
|
||||
<div ng-show="tab == 'programming'" class='modal-semi-body'>
|
||||
<div class='form-group row' >
|
||||
<label for="channelStartTime" class="small col-form-label col-md-auto">Programming Start:</label>
|
||||
<div class='col'>
|
||||
<div class='col-md-auto'>
|
||||
<input id="channelStartTime" class="form-control form-control-sm col-md-auto" type="datetime-local" ng-model="channel.startTime" aria-describedby="startTimeHelp" />
|
||||
<small class="text-danger" id='startTimeHelp'>{{error.startTime}}</small>
|
||||
</div>
|
||||
<label for="channelEndTime" class="small col-form-label col-md-auto">Programming End:</label>
|
||||
<div class='col-md-auto'>
|
||||
<input id="channelEndTime" class="form-control form-control-sm col-md-auto" type="datetime-local" ng-model="endTime" ng-disabled="true" aria-describedby="endTimeHelp" />
|
||||
</div>
|
||||
<div class='col-md-auto'>
|
||||
<small class="text-muted form-text" id='endTimeHelp'>Programming will restart from the beginning.</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex-container">
|
||||
@ -109,9 +117,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-body programming-panes" ng-if="tab == 'programming'">
|
||||
<div class="modal-body programming-panes" ng-show="tab == 'programming'">
|
||||
<div class='row' ng-class="{'reverse': reverseTools }" >
|
||||
<div vs-repeat="options" ng-class="{'programming-pane': true, 'col':true, 'd-block': showShuffleOptions, 'd-sm-none': showShuffleOptions, 'd-md-block' : showShuffleOptions, container: true, 'list-group': true, 'list-group-root': true, 'programming-programs': true}" ng-if="hasPrograms()">
|
||||
<div vs-repeat="options" ng-class="{'programming-pane': true, 'col':true, 'd-block': showShuffleOptions, 'd-sm-none': showShuffleOptions, 'd-md-block' : showShuffleOptions, container: true, 'list-group': true, 'list-group-root': true, 'programming-programs': true}" ng-show="hasPrograms()">
|
||||
<div ng-repeat="x in channel.programs track by x.$index" ng-click="selectProgram(x.$index)" dnd-list="" dnd-drop="dropFunction(index , x.$index, item)"
|
||||
class="list-group-item flex-container program-row" dnd-draggable="x" dnd-moved="channel.programs.splice(x.$index, 1);" dnd-effect-allowed="move"
|
||||
>
|
||||
@ -137,7 +145,7 @@
|
||||
<small class='text-info'>There are no programs in the channel, use the <i class='fas fa-plus'></i> button to add programs from your media library or use the Tools to add Flex time or a Channel Redirect</small>
|
||||
</div>
|
||||
|
||||
<div class='col-md-4 col-sm-12 col-xl-6 col-lg-5 programming-pane tools-pane' ng-if="showShuffleOptions">
|
||||
<div class='col-md-4 col-sm-12 col-xl-6 col-lg-5 programming-pane tools-pane' ng-show="showShuffleOptions">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-6 col-md-12" style="padding: 5px;" ng-show="hasPrograms()">
|
||||
@ -368,6 +376,7 @@
|
||||
<div class="input-group-prepend">
|
||||
<button class='btn btn-sm btn-warning form-control' ng-click="slideAllPrograms(-slide.value)"
|
||||
ng-disabled="slide.value == -1"
|
||||
title="Rewind"
|
||||
>
|
||||
<i class='fas fa-backward'></i> Rewind
|
||||
</button>
|
||||
@ -377,6 +386,7 @@
|
||||
<div class="input-group-append">
|
||||
<button class='btn btn-sm btn-warning form-control' ng-click="slideAllPrograms(slide.value)"
|
||||
ng-disabled="slide.value == -1"
|
||||
title="Fast-Forward"
|
||||
>
|
||||
<i class='fas fa-forward'></i> Fast-Forward
|
||||
</button>
|
||||
@ -680,14 +690,14 @@
|
||||
<label class="form-check-label" for="overlayFixed">
|
||||
Disable Image Scaling
|
||||
</label>
|
||||
<small class='text-muted form-ext' >The image will be rendered at its actual size without applying any scaling to it.</small>
|
||||
<small class='text-muted form-text' >The image will be rendered at its actual size without applying any scaling to it.</small>
|
||||
</div>
|
||||
<div class='form-check col-sm-auto'>
|
||||
<input class="form-check-input" type="checkbox" ng-model="channel.watermark.animated" id="overlayAnimated"></input>
|
||||
<label class="form-check-label" for="overlayAnimated">
|
||||
Animated Image
|
||||
</label>
|
||||
<small class='text-muted form-ext' >Tick this if and only if the watermark is an animated GIF or PNG. It will make it loop or not loop according to the image's configuration. If the image is not animated, an error will be generated.</small>
|
||||
<small class='text-muted form-text' >Tick this if and only if the watermark is an animated GIF or PNG. It will make it loop or not loop according to the image's configuration. If the image is not animated, an error will be generated.</small>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
@ -703,6 +713,37 @@
|
||||
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<h6>Transcoding settings</h6>
|
||||
|
||||
|
||||
<div class='row'>
|
||||
<div class="form-group col-sm-auto">
|
||||
<label for="channelResolution">Channel Resolution:</label>
|
||||
<select class="form-control custom-select" id="channelResolution" ng-model="channel.transcoding.targetResolution"
|
||||
ng-options="o.id as o.description for o in resolutionOptions"
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group col-sm-auto">
|
||||
<label for="channelBitrate">Video Bitrate (k:</label>
|
||||
<input id='channelBitrate' class='form-control' type='number' ng-model='channel.transcoding.videoBitrate' min=0 placeholder='{{videoRateDefault}}'>
|
||||
</input>
|
||||
<small class='text-muted form-text'>Leave unassigned to use the global setting</small>
|
||||
</div>
|
||||
|
||||
<div class="form-group" col-sm-auto>
|
||||
<label for="channelBufsize">Video Buffer Size (k):</label>
|
||||
<input id='channelBufsize' class='form-control' type='number' ng-model='channel.transcoding.videoBufSize' min=0 placeholder='{{videoBufSizeDefault}}'>
|
||||
</input>
|
||||
<small class='text-muted form-text'>Leave unassigned to use the global setting</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
18
web/services/resolution-options.js
Normal file
18
web/services/resolution-options.js
Normal file
@ -0,0 +1,18 @@
|
||||
module.exports = function () {
|
||||
return {
|
||||
get: () => {
|
||||
return [
|
||||
{id:"420x420",description:"420x420 (1:1)"},
|
||||
{id:"480x270",description:"480x270 (HD1080/16 16:9)"},
|
||||
{id:"576x320",description:"576x320 (18:10)"},
|
||||
{id:"640x360",description:"640x360 (nHD 16:9)"},
|
||||
{id:"720x480",description:"720x480 (WVGA 3:2)"},
|
||||
{id:"800x600",description:"800x600 (SVGA 4:3)"},
|
||||
{id:"1024x768",description:"1024x768 (WXGA 4:3)"},
|
||||
{id:"1280x720",description:"1280x720 (HD 16:9)"},
|
||||
{id:"1920x1080",description:"1920x1080 (FHD 16:9)"},
|
||||
{id:"3840x2160",description:"3840x2160 (4K 16:9)"},
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user