Merge pull request #156 from vexorian/20201006_dev

Channel resolution and bitrate settings.
This commit is contained in:
vexorian 2020-10-06 23:35:58 -04:00 committed by GitHub
commit 8ccbef998a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 157 additions and 37 deletions

View File

@ -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;

View File

@ -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,
}

View File

@ -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'))

View File

@ -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

View File

@ -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"},

View File

@ -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&apos;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&apos;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>

View 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)"},
];
}
}
}