loop filler clip, when playlist is not 24 hours long
This commit is contained in:
parent
457383ec83
commit
21a7b9e08d
@ -18,6 +18,7 @@ Features
|
|||||||
- overlay a logo
|
- overlay a logo
|
||||||
- overlay scrolling text
|
- overlay scrolling text
|
||||||
- trim and fade the last clip, to get full 24 hours
|
- trim and fade the last clip, to get full 24 hours
|
||||||
|
- when playlist is not 24 hours long, loop filler clip until time is full
|
||||||
- set custom day start, so you can have playlist for example: from 6am to 6am, instate of 0am to 12pm
|
- set custom day start, so you can have playlist for example: from 6am to 6am, instate of 0am to 12pm
|
||||||
- copy mode, for more info's take a look in the [Wiki](https://github.com/ffplayout/ffplayout-engine/wiki/Copy-Mode)
|
- copy mode, for more info's take a look in the [Wiki](https://github.com/ffplayout/ffplayout-engine/wiki/Copy-Mode)
|
||||||
- normal system requirements and no special tools
|
- normal system requirements and no special tools
|
||||||
|
64
ffplayout.py
64
ffplayout.py
@ -23,6 +23,7 @@ import configparser
|
|||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import math
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import smtplib
|
import smtplib
|
||||||
@ -30,6 +31,7 @@ import signal
|
|||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
@ -441,6 +443,41 @@ def gen_dummy(duration):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# when playlist is not 24 hours long, we generate a loop from filler clip
|
||||||
|
def gen_filler_loop(duration):
|
||||||
|
if not _playlist.filler:
|
||||||
|
# when no filler is set, generate a dummy
|
||||||
|
logger.warning('No filler is set!')
|
||||||
|
return gen_dummy(duration)
|
||||||
|
else:
|
||||||
|
# get duration from filler
|
||||||
|
cmd = [
|
||||||
|
'ffprobe', '-v', 'error', '-show_entries', 'format=duration',
|
||||||
|
'-of', 'default=noprint_wrappers=1:nokey=1', _playlist.filler]
|
||||||
|
|
||||||
|
try:
|
||||||
|
f_dur = float(check_output(cmd).decode('utf-8'))
|
||||||
|
except (CalledProcessError, ValueError):
|
||||||
|
f_dur = None
|
||||||
|
|
||||||
|
if f_dur:
|
||||||
|
if f_dur > duration:
|
||||||
|
# cut filler
|
||||||
|
logger.info('Generate filler with {} seconds'.format(duration))
|
||||||
|
return ['-i', _playlist.filler] + set_length(
|
||||||
|
f_dur, 0, duration)
|
||||||
|
else:
|
||||||
|
# loop filles n times
|
||||||
|
loop_count = math.ceil(duration / f_dur)
|
||||||
|
logger.info('Loop filler {} times, total duration: {}'.format(
|
||||||
|
loop_count, duration))
|
||||||
|
return ['-stream_loop', str(loop_count),
|
||||||
|
'-i', _playlist.filler, '-t', str(duration)]
|
||||||
|
else:
|
||||||
|
logger.error("Can't get filler length, generate dummy!")
|
||||||
|
return gen_dummy(duration)
|
||||||
|
|
||||||
|
|
||||||
# when source path exist, generate input with seek and out time
|
# when source path exist, generate input with seek and out time
|
||||||
# when path not exist, generate dummy clip
|
# when path not exist, generate dummy clip
|
||||||
def src_or_dummy(src, dur, seek, out):
|
def src_or_dummy(src, dur, seek, out):
|
||||||
@ -763,7 +800,7 @@ class GetSourceIter(object):
|
|||||||
# when we have no playlist for the current day,
|
# when we have no playlist for the current day,
|
||||||
# then we generate a black clip
|
# then we generate a black clip
|
||||||
# and calculate the seek in time, for when the playlist comes back
|
# and calculate the seek in time, for when the playlist comes back
|
||||||
self.error_handling('Playlist not exist:')
|
self.eof_handling('Playlist not exist:', False)
|
||||||
|
|
||||||
# when _playlist.start is set, use start time
|
# when _playlist.start is set, use start time
|
||||||
if self.clip_nodes and _playlist.start:
|
if self.clip_nodes and _playlist.start:
|
||||||
@ -861,7 +898,7 @@ class GetSourceIter(object):
|
|||||||
self.first, self.duration, self.seek, self.out,
|
self.first, self.duration, self.seek, self.out,
|
||||||
self.ad, self.ad_last, self.ad_next, self.is_dummy)
|
self.ad, self.ad_last, self.ad_next, self.is_dummy)
|
||||||
|
|
||||||
def error_handling(self, message):
|
def eof_handling(self, message, filler):
|
||||||
self.seek = 0.0
|
self.seek = 0.0
|
||||||
self.out = 20
|
self.out = 20
|
||||||
self.duration = 20
|
self.duration = 20
|
||||||
@ -892,6 +929,13 @@ class GetSourceIter(object):
|
|||||||
self.list_date = get_date(True)
|
self.list_date = get_date(True)
|
||||||
self.last_time += self.out - self.seek
|
self.last_time += self.out - self.seek
|
||||||
|
|
||||||
|
if filler:
|
||||||
|
self.src_cmd = gen_filler_loop(self.out - self.seek)
|
||||||
|
|
||||||
|
if _playlist.filler:
|
||||||
|
self.is_dummy = False
|
||||||
|
self.duration += 1
|
||||||
|
else:
|
||||||
self.src_cmd = gen_dummy(self.out - self.seek)
|
self.src_cmd = gen_dummy(self.out - self.seek)
|
||||||
self.is_dummy = True
|
self.is_dummy = True
|
||||||
self.set_filtergraph()
|
self.set_filtergraph()
|
||||||
@ -966,7 +1010,8 @@ class GetSourceIter(object):
|
|||||||
self.last_time = self.begin
|
self.last_time = self.begin
|
||||||
self.out = self.time_left
|
self.out = self.time_left
|
||||||
|
|
||||||
self.error_handling('Playlist is not valid!')
|
self.eof_handling(
|
||||||
|
'Playlist is not long enough!', False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# when there is no time left and we are in time,
|
# when there is no time left and we are in time,
|
||||||
@ -979,16 +1024,17 @@ class GetSourceIter(object):
|
|||||||
|
|
||||||
self.begin += self.out - self.seek
|
self.begin += self.out - self.seek
|
||||||
else:
|
else:
|
||||||
|
if not _playlist.start or 'length' not in self.clip_nodes:
|
||||||
# when we reach currect end, stop script
|
# when we reach currect end, stop script
|
||||||
if 'begin' not in self.clip_nodes or \
|
|
||||||
'length' not in self.clip_nodes and \
|
|
||||||
self.begin < get_time('full_sec'):
|
|
||||||
logger.info('Playlist reach End!')
|
logger.info('Playlist reach End!')
|
||||||
return
|
return
|
||||||
|
|
||||||
# when playlist exist but is empty, or not long enough,
|
elif self.begin == self.init_time:
|
||||||
# generate dummy and send log
|
# no clip was played, generate dummy
|
||||||
self.error_handling('Playlist is not valid!')
|
self.eof_handling('Playlist is empty!', False)
|
||||||
|
else:
|
||||||
|
# playlist is not long enough, play filler
|
||||||
|
self.eof_handling('Playlist is not long enough!', True)
|
||||||
|
|
||||||
if self.src_cmd is not None:
|
if self.src_cmd is not None:
|
||||||
yield self.src_cmd + self.filtergraph
|
yield self.src_cmd + self.filtergraph
|
||||||
|
Loading…
x
Reference in New Issue
Block a user