UI and config for normalization changes. Audio Volume Boost. Error streams.

Various fixes. Fix bug where normalize codecs logic to pick when to transcode was the reverse of what we wanted. Beep and white noise are less loud, which prevent issues with ac3 encoder. Channel Icon Overlay doesn't appear during error screen.
This commit is contained in:
vexorian 2020-06-27 11:43:19 -04:00
parent 70da29a243
commit 94aa908e0b
11 changed files with 1159 additions and 112 deletions

View File

@ -1,6 +1,42 @@
FROM node:12.18-alpine3.12
# Should be ffmpeg v4.2.3
RUN apk add --no-cache ffmpeg && ffmpeg -version
# Remove the previous line and uncommenting the following lines will allow the
# ffmpeg version to support draw_text filter, but it makes the docker build take
# a long time and it's only used for minor features at the moment.
#RUN apk add --update \
# curl yasm build-base gcc zlib-dev libc-dev openssl-dev yasm-dev lame-dev libogg-dev x264-dev libvpx-dev libvorbis-dev x265-dev freetype-dev libass-dev libwebp-dev rtmpdump-dev libtheora-dev opus-dev && \
# DIR=$(mktemp -d) && cd ${DIR} && \
# curl -s http://ffmpeg.org/releases/ffmpeg-4.2.3.tar.gz | tar zxvf - -C . && \
# cd ffmpeg-4.2.3 && \
# ./configure \
# --enable-version3 \
# --enable-gpl \
# --enable-nonfree \
# --enable-small \
# --enable-libmp3lame \
# --enable-libx264 \
# --enable-libx265 \
# --enable-libvpx \
# --enable-libtheora \
# --enable-libvorbis \
# --enable-libopus \
# --enable-libass \
# --enable-libwebp \
# --enable-librtmp \
# --enable-postproc \
# --enable-avresample \
# --enable-libfreetype \
# --enable-openssl \
# --enable-filter=drawtext \
# --disable-debug && \
# make && \
# make install && \
# make distclean && \
# rm -rf ${DIR} && \
# mv /usr/local/bin/ffmpeg /usr/bin/ffmpeg && \
# apk del build-base curl tar bzip2 x264 openssl nasm openssl xz gnupg && rm -rf /v
WORKDIR /home/node/app
COPY package*.json ./
RUN npm install

View File

@ -7,6 +7,7 @@ const express = require('express')
const bodyParser = require('body-parser')
const api = require('./src/api')
const defaultSettings = require('./src/defaultSettings')
const video = require('./src/video')
const HDHR = require('./src/hdhr')
@ -103,19 +104,13 @@ function initDB(db) {
let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/pseudotv.png')))
fs.writeFileSync(process.env.DATABASE + '/images/pseudotv.png', data)
}
if (!fs.existsSync(process.env.DATABASE + '/images/generic-error-screen.png')) {
let data = fs.readFileSync(path.resolve(path.join(__dirname, 'resources/generic-error-screen.png')))
fs.writeFileSync(process.env.DATABASE + '/images/generic-error-screen.png', data)
}
if (ffmpegSettings.length === 0) {
db['ffmpeg-settings'].save({
ffmpegPath: '/usr/bin/ffmpeg',
enableChannelOverlay: false,
threads: 4,
videoEncoder: 'mpeg2video',
videoResolutionHeight: 'unchanged',
videoBitrate: 10000,
videoBufSize: 2000,
concatMuxDelay: '0',
logFfmpeg: true
})
if ( (ffmpegSettings.length === 0) || typeof(ffmpegSettings.configVersion) === 'undefined' ) {
db['ffmpeg-settings'].save( defaultSettings.ffmpeg() )
}
if (plexSettings.length === 0) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -1,6 +1,7 @@
const express = require('express')
const fs = require('fs')
const defaultSettings = require('./defaultSettings')
module.exports = { router: api }
function api(db, xmltvInterval) {
@ -62,18 +63,10 @@ function api(db, xmltvInterval) {
res.send(ffmpeg)
})
router.post('/api/ffmpeg-settings', (req, res) => { // RESET
db['ffmpeg-settings'].update({ _id: req.body._id }, {
ffmpegPath: req.body.ffmpegPath,
enableChannelOverlay: false,
threads: 4,
videoEncoder: 'mpeg2video',
videoResolutionHeight: 'unchanged',
videoBitrate: 10000,
videoBufSize: 2000,
concatMuxDelay: '0',
logFfmpeg: true
})
let ffmpeg = db['ffmpeg-settings'].find()[0]
let ffmpeg = defaultSettings.ffmpeg();
ffmpeg.ffmpegPath = req.body.ffmpegPath;
db['ffmpeg-settings'].update({ _id: req.body._id }, ffmpeg)
ffmpeg = db['ffmpeg-settings'].find()[0]
res.send(ffmpeg)
})

31
src/defaultSettings.js Normal file
View File

@ -0,0 +1,31 @@
module.exports = {
ffmpeg: () => {
return {
//a record of the config version will help migrating between versions
// in the future. Always increase the version when new ffmpeg configs
// are added.
//
// configVersion 3: First versioned config.
//
configVersion: 3,
ffmpegPath: "/usr/bin/ffmpeg",
threads: 4,
concatMuxDelay: "0",
logFfmpeg: false,
enableFFMPEGTranscoding: false,
audioVolumePercent: 100,
videoEncoder: "mpeg2video",
audioEncoder: "ac3",
targetResolution: "1920x1080",
videoBitrate: 10000,
videoBufSize: 2000,
errorScreen: "pic",
errorAudio: "silent",
normalizeVideoCodec: false,
normalizeAudioCodec: false,
normalizeResolution: false,
alignAudio: false,
}
}
}

View File

@ -1,31 +1,26 @@
const spawn = require('child_process').spawn
const events = require('events')
const fs = require('fs')
// For now these options can be enabled with constants, must also enable overlay in settings:
// Normalize resoltion to WxH:
const FIX_RESOLUTION = false;
const W = 1920;
const H = 1080;
// Normalize codecs, video codec is in ffmpeg settings:
const FIX_CODECS = false;
// Align audio and video channels
const ALIGN_AUDIO = false;
// What audio encoder to use:
const AUDIO_ENCODER = 'aac';
//they can customize this by modifying the picture in .pseudotv folder
const ERROR_PICTURE_PATH = 'http://localhost:8000/images/generic-error-screen.png'
const MAXIMUM_ERROR_DURATION_MS = 60000;
class FFMPEG extends events.EventEmitter {
constructor(opts, channel) {
super()
this.opts = opts
this.channel = channel
this.ffmpegPath = opts.ffmpegPath
this.alignAudio = ALIGN_AUDIO;
var parsed = parseResolutionString(opts.targetResolution);
this.wantedW = parsed.w;
this.wantedH = parsed.h;
this.sentData = false;
this.alignAudio = this.opts.alignAudio;
this.ensureResolution = this.opts.normalizeResolution;
this.volumePercent = this.opts.audioVolumePercent;
}
async spawnConcat(streamUrl) {
this.spawn(streamUrl, undefined, undefined, undefined, false, false, undefined, true)
@ -34,13 +29,27 @@ class FFMPEG extends events.EventEmitter {
this.spawn(streamUrl, streamStats, startTime, duration, true, enableIcon, type, false);
}
async spawnError(title, subtitle, streamStats, enableIcon, type) {
// currently the error stream feature is not implemented
if (! this.opts.enableFFMPEGTranscoding || this.opts.errorScreen == 'kill') {
console.log("error: " + title + " ; " + subtitle);
this.emit('error', { code: -1, cmd: `error stream disabled` })
return;
}
// since this is from an error situation, streamStats may have issues.
if ( (streamStats == null) || (typeof(streamStats) === 'undefined') ) {
streamStats = {};
}
streamStats.videoWidth = this.wantedW;
streamStats.videoHeight = this.wantedH;
if ( (typeof(streamStats.duration) === 'undefined') || isNaN(streamStats.duration) || (streamStats.duration > MAXIMUM_ERROR_DURATION_MS) ) {
// it's possible that whatever issue there was when attempting to download the video from plex
// could be temporary, so it'd be better to retry after a minute
streamStats.duration = MAXIMUM_ERROR_DURATION_MS;
}
this.spawn({ errorTitle: title , subtitle: subtitle }, streamStats, undefined, `${streamStats.duration}ms`, true, enableIcon, type, false)
}
async spawn(streamUrl, streamStats, startTime, duration, limitRead, enableIcon, type, isConcatPlaylist) {
let ffmpegArgs = [`-threads`, this.opts.threads,
let ffmpegArgs = [
`-threads`, this.opts.threads,
`-fflags`, `+genpts+discardcorrupt+igndts`];
if (limitRead === true)
@ -73,8 +82,9 @@ class FFMPEG extends events.EventEmitter {
var currentAudio = "[audio]";
// Initially, videoComplex does nothing besides assigning the label
// to the input stream
var videoIndex = 'v';
var audioComplex = `;[0:${audioIndex}]anull[audio]`;
var videoComplex = `;[0:v]null[video]`;
var videoComplex = `;[0:${videoIndex}]null[video]`;
// Depending on the options we will apply multiple filters
// each filter modifies the current video stream. Adds a filter to
// the videoComplex variable. The result of the filter becomes the
@ -83,17 +93,83 @@ class FFMPEG extends events.EventEmitter {
// When adding filters, make sure that
// videoComplex always begins wiht ; and doesn't end with ;
// prepare input files, overlay adds another input file
ffmpegArgs.push(`-i`, streamUrl);
// prepare input streams
if ( typeof(streamUrl.errorTitle) !== 'undefined') {
doOverlay = false; //never show icon in the error screen
// for error stream, we have to generate the input as well
this.alignAudio = false; //all of these generate audio correctly-aligned to video so there is no need for apad
if (this.ensureResolution) {
//all of the error strings already choose the resolution to
//match iW x iH , so with this we save ourselves a second
// scale filter
iW = this.wantedW;
iH = this.wantedH;
}
ffmpegArgs.push("-r" , "24");
if (this.opts.errorScreen == 'static') {
ffmpegArgs.push(
'-f', 'lavfi',
'-i', `nullsrc=s=64x36`);
videoComplex = `;geq=random(1)*255:128:128[videoz];[videoz]scale=${iW}:${iH}[videoy];[videoy]realtime[videox]`;
} else if (this.opts.errorScreen == 'testsrc') {
ffmpegArgs.push(
'-f', 'lavfi',
'-i', `testsrc=size=${iW}x${iH}`,
'-pix_fmt' , 'yuv420p'
);
videoComplex = `;realtime[videox]`;
} else if (this.opts.errorScreen == 'text') {
var sz2 = Math.ceil( (iH) / 33.0);
var sz1 = Math.ceil( sz2 * 3. / 2. );
var sz3 = 2*sz2;
ffmpegArgs.push(
'-f', 'lavfi',
'-i', `color=c=black:s=${iW}x${iH}`
);
videoComplex = `;drawtext=fontfile=${process.env.DATABASE}/font.ttf:fontsize=${sz1}:fontcolor=white:x=(w-text_w)/2:y=(h-text_h)/2:text='${streamUrl.errorTitle}',drawtext=fontfile=${process.env.DATABASE}/font.ttf:fontsize=${sz2}:fontcolor=white:x=(w-text_w)/2:y=(h+text_h+${sz3})/2:text='${streamUrl.subtitle}'[videoy];[videoy]realtime[videox]`;
} else if (this.opts.errorScreen == 'blank') {
ffmpegArgs.push(
'-f', 'lavfi',
'-i', `color=c=black:s=${iW}x${iH}`
);
videoComplex = `;realtime[videox]`;
} else {//'pic'
ffmpegArgs.push(
'-loop', '1',
'-i', `${ERROR_PICTURE_PATH}`,
'-pix_fmt' , 'yuv420p'
);
videoComplex = `;[0:0]scale=${iW}:${iH}[videoy];[videoy]realtime[videox]`;
}
let durstr = `duration=${streamStats.duration}ms`;
if (this.opts.errorAudio == 'whitenoise') {
audioComplex = `;aevalsrc=-2+0.1*random(0):${durstr}[audioy]`;
} else if (this.opts.errorAudio == 'sine') {
audioComplex = `;sine=f=440:${durstr}[audiox];[audiox]volume=-65dB[audioy]`;
} else { //silent
audioComplex = `;aevalsrc=0:${durstr}[audioy]`;
}
audioComplex += ';[audioy]arealtime[audiox]';
currentVideo = "[videox]";
currentAudio = "[audiox]";
} else {
ffmpegArgs.push(`-i`, streamUrl);
}
if (doOverlay) {
ffmpegArgs.push(`-i`, `${this.channel.icon}` );
}
// Resolution fix: Add scale filter, current stream becomes [siz]
if (FIX_RESOLUTION && (iW != W || iH != H) ) {
if (this.ensureResolution && (iW != this.wantedW || iH != this.wantedH) ) {
//Maybe the scaling algorithm could be configurable. bicubic seems good though
videoComplex += `;${currentVideo}scale=${W}:${H}:flags=bicubic:force_original_aspect_ratio=decrease,pad=${W}:${H}:(ow-iw)/2:(oh-ih)/2[siz]`
videoComplex += `;${currentVideo}scale=${this.wantedW}:${this.wantedH}:flags=bicubic:force_original_aspect_ratio=decrease,pad=${this.wantedW}:${this.wantedH}:(ow-iw)/2:(oh-ih)/2[siz]`
currentVideo = "[siz]";
iW = this.wantedW;
iH = this.wantedH;
}
// Channel overlay:
@ -110,6 +186,11 @@ class FFMPEG extends events.EventEmitter {
currentVideo = '[comb]';
}
if (this.volumePercent != 100) {
var f = this.volumePercent / 100.0;
audioComplex += `;${currentAudio}volume=${f}[boosted]`;
currentAudio = '[boosted]';
}
// Align audio is just the apad filter applied to audio stream
if (this.alignAudio) {
audioComplex += `;${currentAudio}apad=whole_dur=${streamStats.duration}ms[padded]`;
@ -119,18 +200,18 @@ class FFMPEG extends events.EventEmitter {
// If no filters have been applied, then the stream will still be
// [video] , in that case, we do not actually add the video stuff to
// filter_complex and this allows us to avoid transcoding.
var changeVideoCodec = FIX_CODECS;
var changeAudioCodec = FIX_CODECS;
var changeVideoCodec = (this.opts.normalizeVideoCodec && isDifferentVideoCodec( streamStats.videoCodec, this.opts.videoEncoder) );
var changeAudioCodec = (this.opts.normalizeAudioCodec && isDifferentAudioCodec( streamStats.audioCodec, this.opts.audioEncoder) );
var filterComplex = '';
if (currentVideo != '[video]') {
changeVideoCodec = true;
changeVideoCodec = true; //this is useful so that it adds some lines below
filterComplex += videoComplex;
} else {
currentVideo = '0:v';
currentVideo = `0:${videoIndex}`;
}
// same with audi:
// same with audio:
if (currentAudio != '[audio]') {
changeAudioCodec = true; //this is useful for some more flags later
changeAudioCodec = true;
filterComplex += audioComplex;
} else {
currentAudio = `0:${audioIndex}`;
@ -161,13 +242,14 @@ class FFMPEG extends events.EventEmitter {
);
}
ffmpegArgs.push(
`-c:a`, (changeAudioCodec ? AUDIO_ENCODER : 'copy'),
`-c:a`, (changeAudioCodec ? this.opts.audioEncoder : 'copy'),
`-muxdelay`, `0`,
`-muxpreload`, `0`
);
} else {
//Concat stream is simpler and should always copy the codec
ffmpegArgs.push(
`-probesize`, `25000000`,
`-i`, streamUrl,
`-map`, `0:v`,
`-map`, `0:${audioIndex}`,
@ -191,6 +273,7 @@ class FFMPEG extends events.EventEmitter {
this.ffmpeg = spawn(this.ffmpegPath, ffmpegArgs)
this.ffmpeg.stdout.on('data', (chunk) => {
this.sentData = true;
this.emit('data', chunk)
})
if (this.opts.logFfmpeg) {
@ -199,14 +282,18 @@ class FFMPEG extends events.EventEmitter {
})
}
this.ffmpeg.on('close', (code) => {
if (code === null)
if (code === null) {
this.emit('close', code)
else if (code === 0)
} else if (code === 0) {
this.emit('end')
else if (code === 255)
} else if (code === 255) {
if (! this.sentData) {
this.emit('error', { code: code, cmd: `${this.opts.ffmpegPath} ${ffmpegArgs.join(' ')}` })
}
this.emit('close', code)
else
} else {
this.emit('error', { code: code, cmd: `${this.opts.ffmpegPath} ${ffmpegArgs.join(' ')}` })
}
})
}
kill() {
@ -216,4 +303,42 @@ class FFMPEG extends events.EventEmitter {
}
}
function isDifferentVideoCodec(codec, encoder) {
if (codec == 'mpeg2video') {
return ! encoder.includes("mpeg2");
} else if (codec == 'h264') {
return ! encoder.includes("264");
} else if (codec == 'hevc') {
return !( encoder.includes("265") || encoder.includes("hevc") );
}
// if the encoder/codec combinations are unknown, always encode, just in case
return true;
}
function isDifferentAudioCodec(codec, encoder) {
if (codec == 'mp3') {
return !( encoder.includes("mp3") || encoder.includes("lame") );
} else if (codec == 'aac') {
return !encoder.includes("aac");
} else if (codec == 'ac3') {
return !encoder.includes("ac3");
} else if (codec == 'flac') {
return !encoder.includes("flac");
}
// if the encoder/codec combinations are unknown, always encode, just in case
return true;
}
function parseResolutionString(s) {
var i = s.indexOf('x');
if (i == -1) {
return {w:1920, h:1080}
}
return {
w: parseInt( s.substring(0,i) , 10 ),
h: parseInt( s.substring(i+1) , 10 ),
}
}
module.exports = FFMPEG

View File

@ -113,8 +113,15 @@ function createLineup(obj) {
return lineup
}
function isChannelIconEnabled(enableChannelOverlay, icon, overlayIcon, type) {
if (typeof type === `undefined`)
return enableChannelOverlay == true && icon !== '' && overlayIcon
return enableChannelOverlay == true && icon !== '' && overlayIcon
function isChannelIconEnabled( ffmpegSettings, channel, type) {
if (! ffmpegSettings.enableFFMPEGTranscoding || ffmpegSettings.disableChannelOverlay ) {
return false;
}
if ( (typeof type !== `undefined`) && (type == 'commercial') ) {
return false;
}
if (channel.icon === '' || !channel.overlayIcon) {
return false;
}
return true;
}

View File

@ -0,0 +1,731 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="1920"
height="1080"
viewBox="0 0 507.99999 285.75001"
version="1.1"
id="svg8"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="generic-error-screen.svg"
inkscape:export-filename="/home/vx/dev/pseudotv/resources/generic-error-screen.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.43386034"
inkscape:cx="1327.3621"
inkscape:cy="796.69727"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1056"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
units="px" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Capa 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-11.249983)">
<rect
style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;stroke-width:3.20000029;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect836"
width="508"
height="285.75"
x="0"
y="11.24997" />
<image
y="81.529213"
x="214.88797"
id="image1079"
xlink:href="data:image/png;base64,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
d038AAAAAElFTkSuQmCC
"
preserveAspectRatio="none"
height="86.535645"
width="86.851501"
style="stroke-width:1.52597129" />
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:11.11943626px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458335px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
x="81.721901"
y="199.92511"
id="text1105"
transform="scale(1.0018233,0.99818001)"><tspan
sodipodi:role="line"
id="tspan1103"
x="81.721901"
y="199.92511"
style="font-size:20.75628471px;fill:#ffffff;stroke-width:0.26458335px">This stream is facing technical issues.</tspan><tspan
sodipodi:role="line"
x="81.721901"
y="213.8244"
style="font-size:20.75628471px;fill:#ffffff;stroke-width:0.26458335px"
id="tspan1109" /><tspan
sodipodi:role="line"
x="81.721901"
y="230.46899"
style="font-size:20.75628471px;fill:#ffffff;stroke-width:0.26458335px"
id="tspan1107">Try again later.</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 51 KiB

View File

@ -31,7 +31,7 @@ function video(db) {
return
})
ffmpeg.on('close', () => {
res.send()
res.end()
})
res.on('close', () => { // on HTTP close, kill ffmpeg
@ -80,7 +80,7 @@ function video(db) {
})
ffmpeg.on('close', () => {
res.send();
res.end();
})
res.on('close', () => { // on HTTP close, kill ffmpeg
@ -129,25 +129,38 @@ function video(db) {
let lineup = helperFuncs.createLineup(prog)
let lineupItem = lineup.shift()
let streamDuration = lineupItem.streamDuration / 1000;
// Only episode in this lineup, or item is a commercial, let stream end naturally
if (lineup.length === 0 || lineupItem.type === 'commercial' || lineup.length === 1 && lineup[0].type === 'commercial')
streamDuration = undefined
let deinterlace = enableChannelIcon = helperFuncs.isChannelIconEnabled(ffmpegSettings.enableChannelOverlay, channel.icon, channel.overlayIcon)
let enableChannelIcon = helperFuncs.isChannelIconEnabled( ffmpegSettings, channel, lineupItem.type);
let deinterlace = ffmpegSettings.enableFFMPEGTranscoding; //for now it will always deinterlace when transcoding is enabled but this is sub-optimal
let plexTranscoder = new PlexTranscoder(plexSettings, lineupItem);
let ffmpeg = new FFMPEG(ffmpegSettings, channel); // Set the transcoder options
var ffmpeg1Ended = false;
ffmpeg.on('data', (data) => { res.write(data) })
ffmpeg.on('error', (err) => {
if (ffmpeg1Ended) {
return;
}
ffmpeg1Ended = true;
plexTranscoder.stopUpdatingPlex();
if (typeof(this.backup) !== 'undefined') {
let ffmpeg2 = new FFMPEG(ffmpegSettings, channel); // Set the transcoder options
ffmpeg2.spawnError('Source error', `ffmpeg returned code ${err.code}`, this.backup.stream.streamStats, this.backup.enableChannelIcon, this.backup.type); // Spawn the ffmpeg process, fire this bitch up
ffmpeg2.on('data', (data) => { res.write(data) } );
ffmpeg2.on('data', (data) => {
try {
res.write(data)
} catch (err) {
console.log("err="+err);
}
} );
ffmpeg2.on('error', (err) => { res.end() } );
ffmpeg2.on('close', () => { res.send() } );
ffmpeg2.on('end', () => { res.end() } );
@ -160,11 +173,17 @@ function video(db) {
})
ffmpeg.on('close', () => {
if (ffmpeg1Ended) {
return;
}
plexTranscoder.stopUpdatingPlex();
res.send();
res.end();
})
ffmpeg.on('end', () => { // On finish transcode - END of program or commercial...
if (ffmpeg1Ended) {
return;
}
plexTranscoder.stopUpdatingPlex();
res.end()
})
@ -178,14 +197,13 @@ function video(db) {
let streamStart = (stream.directPlay) ? plexTranscoder.currTimeS : undefined;
let streamStats = stream.streamStats
let streamStats = stream.streamStats;
streamStats.duration = lineupItem.streamDuration;
console.log("timeElapsed=" + prog.timeElapsed );
streamStats.duration = streamStats.duration - prog.timeElapsed;
this.backup = {
stream: stream,
streamStart: streamStart,
streamDuration: streamDuration,
enableChannelIcon: enableChannelIcon,
type: lineupItem.type
};
@ -214,7 +232,7 @@ function video(db) {
// If someone passes this number then they probably watch too much television
let maxStreamsToPlayInARow = 100;
var data = "#ffconcat version 1.0\n"
var data = "ffconcat version 1.0\n"
for (var i = 0; i < maxStreamsToPlayInARow; i++)
data += `file 'http://localhost:${process.env.PORT}/stream?channel=${channelNum}'\n`

View File

@ -19,21 +19,22 @@
scope.settings = _settings
})
}
scope.hideIfNotEnableChannelOverlay = () => {
return scope.settings.enableChannelOverlay != true
scope.isTranscodingNotNeeded = () => {
return ! (scope.settings.enableFFMPEGTranscoding)
};
scope.hideIfNotAutoPlay = () => {
return scope.settings.enableAutoPlay != true
};
scope.resolutionOptions=[
{id:"420",description:"420x420"},
{id:"320",description:"576x320"},
{id:"480",description:"720x480"},
{id:"768",description:"1024x768"},
{id:"720",description:"1280x720"},
{id:"1080",description:"1920x1080"},
{id:"2160",description:"3840x2160"},
{id:"unchanged",description:"Same as source"}
{id:"420x420",description:"420x420 (1:1)"},
{id:"576x320",description:"576x320 (18:10)"},
{id:"640×360",description:"640×360 (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.muxDelayOptions=[
{id:"0",description:"0 Seconds"},
@ -41,8 +42,22 @@
{id:"2",description:"2 Seconds"},
{id:"3",description:"3 Seconds"},
{id:"4",description:"4 Seconds"},
{id:"5",description:"5 Seconds"}
{id:"5",description:"5 Seconds"},
{id:"10",description:"10 Seconds"},
];
scope.errorScreens = [
{value:"pic", description:"images/generic-error-screen.png"},
{value:"blank", description:"Blank Screen"},
{value:"static", description:"Static"},
{value:"testsrc", description:"Test Pattern (color bars + timer)"},
{value:"text", description:"Detailed error (requires ffmpeg with drawtext)"},
{value:"kill", description:"Stop stream, show errors in logs"},
]
scope.errorAudios = [
{value:"whitenoise", description:"White Noise"},
{value:"sine", description:"Beep"},
{value:"silent", description:"No Audio"},
]
}
}
}

View File

@ -31,14 +31,8 @@
</div>
</div>
</div>
<hr/>
<div class="row">
<div class="col-sm-6">
<div class="form-group">
<input id="enableChannelOverlay" type="checkbox" ng-model="settings.enableChannelOverlay" ria-describedby="enableChannelOverlayHelp"/>
<label for="enableChannelOverlay">Enable Channel Overlay (Requires Transcoding)</label>
<small id="enableChannelOverlayHelp" class="form-text text-muted">Note: This transcoding is done by PseudoTV, not Plex.</small>
</div>
<div class="form-group">
<label>Video Buffer</label>
<select ng-model="settings.concatMuxDelay" ria-describedby="concatMuxDelayHelp"
@ -46,32 +40,134 @@
<small id="concatMuxDelayHelp" class="form-text text-muted">Note: If you experience playback issues upon stream start, try increasing this.</small>
</div>
</div>
<div class="col-sm-6">
<div ng-hide="hideIfNotEnableChannelOverlay()">
</div>
<hr/>
<h6>Transcoding Features</h6>
<div class="row">
<div class="col-sm-9">
<input id=enableFFMPEGTranscoding" type="checkbox" ng-model="settings.enableFFMPEGTranscoding" />
<label for="enableFFMPEGTranscoding">Enable FFMPEG Transcoding</label>
<small class="form-text text-muted">Transcoding is required for some features like channel overlay and measures to prevent issues when switching episodes. The trade-off is quality loss and additional computing resource requirements.
</small>
</div>
</div>
<br />
<div class="form-group" ng-hide="isTranscodingNotNeeded()" >
<div class="row">
<div class="col-sm-9">
<label>Preferred Resolution</label>
<select ng-model="settings.targetResolution" ria-describedby="concatMuxDelayHelp" ng-options="o.id as o.description for o in resolutionOptions" />
</div>
</div>
<div class="row">
<div class="col-sm-4">
<label>Video Encoder</label>
<input type="text" class="form-control form-control-sm" ng-model="settings.videoEncoder" ria-describedby="videoEncoderHelp"/>
<small id="videoEncoderHelp" class="form-text text-muted">Some possible values are:</small>
<small id="videoEncoderHelp" class="form-text text-muted">Intel Quick Sync: h264_qsv, mpeg2_qsv</small>
<small id="videoEncoderHelp" class="form-text text-muted">NVIDIA: GPU: h264_nvenc</small>
<small id="videoEncoderHelp" class="form-text text-muted">MPEG2: mpeg2video (default)</small>
<small id="videoEncoderHelp" class="form-text text-muted">H264: libx264</small>
<small id="videoEncoderHelp" class="form-text text-muted">MacOS: h264_videotoolbox</small>
</div>
<div class="col-sm-1" />
<div class="col-sm-4">
<label>Audio Encoder</label>
<input type="text" class="form-control form-control-sm" ng-model="settings.audioEncoder" ria-describedby="audioEncoderHelp"/>
<small id="audioEncoderHelp" class="form-text text-muted">Some possible values are:</small>
<small id="audioEncoderHelp" class="form-text text-muted">aac</small>
<small id="audioEncoderHelp" class="form-text text-muted">ac3 (default), ac3_fixed</small>
<small id="audioEncoderHelp" class="form-text text-muted">flac</small>
<small id="audioEncoderHelp" class="form-text text-muted">libmp3lame</small>
</div>
</div>
<br />
<div class="form-group">
<label>Video Bitrate (k)</label>
<input type="number" class="form-control form-control-sm" ng-model="settings.videoBitrate"/>
<br />
<label>Video Buffer Size (k)</label>
<input type="number" class="form-control form-control-sm" ng-model="settings.videoBufSize"/>
</div>
<div class="form-group">
<label>Audio Volume (%)</label>
<input type="number" ria-describedby="volumeHelp" class="form-control form-control-sm" ng-model="settings.audioVolumePercent"/>
<small id="volumeHelp" class="form-text text-muted">Values higher than 100 will boost the audio.</small>
</div>
<div class="form-group">
<div>
<label>Error Screen:</label>
<select ng-model="settings.errorScreen" ria-describedby="errorHelp"
ng-options="o.value as o.description for o in errorScreens" />
<label>Audio:</label>
<select ng-model="settings.errorAudio" ria-describedby="errorHelp"
ng-options="o.value as o.description for o in errorAudios" />
</div>
<small id="errorHelp" class="form-text text-muted">If there are issues playing a video, pseudoTV will try to use an error screen as a placeholder while retrying loading the video every 60 seconds.</small>
</div>
<div class="row">
<div class="col-sm-9">
<div class="form-group">
<label>Video Encoder</label>
<input type="text" class="form-control form-control-sm" ng-model="settings.videoEncoder" ria-describedby="videoEncoderHelp"/>
<small id="videoEncoderHelp" class="form-text text-muted">Some possible values are:</small>
<small id="videoEncoderHelp" class="form-text text-muted">Intel Quick Sync: h264_qsv, mpeg2_qsv</small>
<small id="videoEncoderHelp" class="form-text text-muted">NVIDIA: GPU: h264_nvenc</small>
<small id="videoEncoderHelp" class="form-text text-muted">MPEG2: mpeg2video (default)</small>
<small id="videoEncoderHelp" class="form-text text-muted">H264: libx264</small>
<small id="videoEncoderHelp" class="form-text text-muted">MacOS: h264_videotoolbox</small>
</div>
<div class="form-group">
<label>Video Bitrate (k)</label>
<input type="number" class="form-control form-control-sm" ng-model="settings.videoBitrate"/>
</div>
<div class="form-group">
<label>Max Video Resolution</label>
<select ng-model="settings.videoResolutionHeight"
ng-options="o.id as o.description for o in resolutionOptions" />
</div>
<div class="form-group">
<label>Video Buffer Size (k)</label>
<input type="number" class="form-control form-control-sm" ng-model="settings.videoBufSize"/>
<input id="enableNormalizeResolution" type="checkbox" ng-model="settings.normalizeResolution" ng-disabled="isTranscodingNotNeeded()" />
<label for="enableNormalizeResolution">Normalize Resolution</label>
<small class="form-text text-muted">Some clients experience issues when the video stream changes resolution. This option will make pseudoTV convert all videos to the preferred resolution selected above.
</small>
</div>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-9">
<div class="form-group row">
<div class="col-sm-4">
<input id="enableNormalizeVideoCodec" type="checkbox" ng-model="settings.normalizeVideoCodec" ng-disabled="isTranscodingNotNeeded()" />
<label for="enableNormalizeVideoCodec">Normalize Video Codec</label>
</div>
<div class="col-sm-4">
<input id="enableNormalizeAudioCodec" type="checkbox" ng-model="settings.normalizeAudioCodec" ng-disabled="isTranscodingNotNeeded()" />
<label for="enableNormalizeAudioCodec">Normalize Audio Codec</label>
</div>
</div>
<small class="form-text text-muted">Some clients experience issues when the stream's codecs change. Enable these so that any videos with different codecs than the ones specified above are forcefully transcoded.
</small>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-9">
<div class="form-group">
<input id="enableAlignAudio" type="checkbox" ng-model="settings.alignAudio" ng-disabled="isTranscodingNotNeeded()" />
<label for="enableAlignAudio">Align Audio and Video lengths</label>
<small class="form-text text-muted">In rare situations, video and audio streams in a video may have different lengths. This can cause desync issues in some clients. This transcodes audio in all videos to ensure the lengths stay the same.
</small>
</div>
</div>
</div>
<br />
<div class="row">
<div class="col-sm-9">
<div class="form-group">
<input id="disableOverlay" type="checkbox" ng-model="settings.disableChannelOverlay" ng-disabled="isTranscodingNotNeeded()" />
<label for="disableOverlay">Disable Channel Overlay Globally</label>
<small class="form-text text-muted">Toggling this option will disable channel overlays regardless of channel settings.
</small>
</div>
</div>
</div>
</div>
</div>