def clean_ts(): """ this function get all *.m3u8 playlists from config, read lines from them until it founds first *.ts file, then it checks if files on hard drive are older then this first *.ts and if so delete them """ m3u8_files = [p for p in playout.hls_output if 'm3u8' in p] for m3u8_file in m3u8_files: messenger.debug(f'cleanup *.ts files from: "{m3u8_file}"') test_num = 0 hls_path = os.path.dirname(m3u8_file) if os.path.isfile(m3u8_file): with open(m3u8_file, 'r') as m3u8: for line in m3u8: if '.ts' in line: test_num = int(re.findall(r'(\d+).ts', line)[0]) break for ts_file in iglob(os.path.join(hls_path, '*.ts')): ts_num = int(re.findall(r'(\d+).ts', ts_file)[0]) if test_num > ts_num: try: os.remove(ts_file) except OSError: pass
def output(): """ this output is for streaming to a target address, like rtmp, rtp, svt, etc. """ year = get_date(False).split('-')[0] overlay = [] ff_pre_settings = [ '-pix_fmt', 'yuv420p', '-r', str(_pre.fps), '-c:v', 'mpeg2video', '-intra', '-b:v', '{}k'.format( _pre.v_bitrate), '-minrate', '{}k'.format(_pre.v_bitrate), '-maxrate', '{}k'.format(_pre.v_bitrate), '-bufsize', '{}k'.format( _pre.v_bufsize) ] + pre_audio_codec() + ['-f', 'mpegts', '-'] if _text.add_text and not _text.over_pre: messenger.info('Using drawtext node, listening on address: {}'.format( _text.address)) overlay = [ '-vf', "null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format( _text.address.replace(':', '\\:'), _text.fontfile) ] try: _ff.encoder = Popen([ 'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner', '-nostats', '-re', '-thread_queue_size', '256', '-i', 'pipe:0' ] + overlay + [ '-metadata', 'service_name=' + _playout.name, '-metadata', 'service_provider=' + _playout.provider, '-metadata', 'year={}'.format(year) ] + _playout.ffmpeg_param + _playout.stream_output, stdin=PIPE, stderr=PIPE) enc_err_thread = Thread(target=ffmpeg_stderr_reader, args=(_ff.encoder.stderr, False)) enc_err_thread.daemon = True enc_err_thread.start() if _playlist.mode and not stdin_args.folder: watcher = None get_source = GetSourceFromPlaylist() else: messenger.info('Start folder mode') media = MediaStore() watcher = MediaWatcher(media) get_source = GetSourceFromFolder(media) try: for src_cmd in get_source.next(): messenger.debug('src_cmd: "{}"'.format(src_cmd)) if src_cmd[0] == '-i': current_file = src_cmd[1] else: current_file = src_cmd[3] _current.clip = current_file messenger.info('Play: "{}"'.format(current_file)) with Popen([ 'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner', '-nostats' ] + src_cmd + ff_pre_settings, stdout=PIPE, stderr=PIPE) as _ff.decoder: dec_err_thread = Thread(target=ffmpeg_stderr_reader, args=(_ff.decoder.stderr, True)) dec_err_thread.daemon = True dec_err_thread.start() while True: buf = _ff.decoder.stdout.read(COPY_BUFSIZE) if not buf: break _ff.encoder.stdin.write(buf) except BrokenPipeError: messenger.error('Broken Pipe!') terminate_processes(watcher) except SystemExit: messenger.info('Got close command') terminate_processes(watcher) except KeyboardInterrupt: messenger.warning('Program terminated') terminate_processes(watcher) # close encoder when nothing is to do anymore if _ff.encoder.poll() is None: _ff.encoder.terminate() finally: if _ff.encoder.poll() is None: _ff.encoder.terminate() _ff.encoder.wait()
def output(): """ this output is for playing on desktop with ffplay """ overlay = [] ff_pre_settings = [ '-pix_fmt', 'yuv420p', '-r', str(_pre.fps), '-c:v', 'mpeg2video', '-intra', '-b:v', f'{_pre.v_bitrate}k', '-minrate', f'{_pre.v_bitrate}k', '-maxrate', f'{_pre.v_bitrate}k', '-bufsize', f'{_pre.v_bufsize}k' ] + pre_audio_codec() + ['-f', 'mpegts', '-'] if _text.add_text and not _text.over_pre: messenger.info( f'Using drawtext node, listening on address: {_text.address}') overlay = [ '-vf', "null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format( _text.address.replace(':', '\\:'), _text.fontfile) ] try: enc_cmd = ['ffplay', '-hide_banner', '-nostats', '-i', 'pipe:0' ] + overlay messenger.debug(f'Encoder CMD: "{" ".join(enc_cmd)}"') _ff.encoder = Popen(enc_cmd, stderr=PIPE, stdin=PIPE, stdout=None) enc_err_thread = Thread(target=ffmpeg_stderr_reader, args=(_ff.encoder.stderr, False)) enc_err_thread.daemon = True enc_err_thread.start() if _playlist.mode and not stdin_args.folder: watcher = None get_source = GetSourceFromPlaylist() else: messenger.info('Start folder mode') media = MediaStore() watcher = MediaWatcher(media) get_source = GetSourceFromFolder(media) try: for node in get_source.next(): if watcher is not None: watcher.current_clip = node.get('source') messenger.info(f'Play for {node["out"] - node["seek"]:.2f} ' f'seconds: {node.get("source")}') dec_cmd = [ 'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner', '-nostats' ] + node['src_cmd'] + node['filter'] + ff_pre_settings messenger.debug(f'Decoder CMD: "{" ".join(dec_cmd)}"') with Popen(dec_cmd, stdout=PIPE, stderr=PIPE) as _ff.decoder: dec_err_thread = Thread(target=ffmpeg_stderr_reader, args=(_ff.decoder.stderr, True)) dec_err_thread.daemon = True dec_err_thread.start() while True: buf = _ff.decoder.stdout.read(COPY_BUFSIZE) if not buf: break _ff.encoder.stdin.write(buf) except BrokenPipeError: messenger.error('Broken Pipe!') terminate_processes(watcher) except SystemExit: messenger.info('Got close command') terminate_processes(watcher) except KeyboardInterrupt: messenger.warning('Program terminated') terminate_processes(watcher) # close encoder when nothing is to do anymore if _ff.encoder.poll() is None: _ff.encoder.terminate() finally: if _ff.encoder.poll() is None: _ff.encoder.terminate() _ff.encoder.wait()
def output(): """ this output is hls output, no pre-process is needed. """ year = get_date(False).split('-')[0] sync_op.realtime = True try: if playlist.mode and not stdin_args.folder: watcher = None get_source = GetSourceFromPlaylist() else: messenger.info('Start folder mode') media = MediaStore() watcher = MediaWatcher(media) get_source = GetSourceFromFolder(media) try: for node in get_source.next(): if watcher is not None: watcher.current_clip = node.get('source') messenger.info(f'Play: {node.get("source")}') cmd = [ 'ffmpeg', '-v', log.ff_level.lower(), '-hide_banner', '-nostats' ] + node['src_cmd'] + node['filter'] + [ '-metadata', 'service_name=' + playout.name, '-metadata', 'service_provider=' + playout.provider, '-metadata', 'year={}'.format(year) ] + playout.ffmpeg_param + playout.hls_output messenger.debug(f'Encoder CMD: "{" ".join(cmd)}"') ff_proc.encoder = Popen(cmd, stdin=PIPE, stderr=PIPE) stderr_reader_thread = Thread(target=ffmpeg_stderr_reader, args=(ff_proc.encoder.stderr, False)) stderr_reader_thread.daemon = True stderr_reader_thread.start() stderr_reader_thread.join() ts_cleaning_thread = Thread(target=clean_ts) ts_cleaning_thread.daemon = True ts_cleaning_thread.start() except BrokenPipeError: messenger.error('Broken Pipe!') terminate_processes(watcher) except SystemExit: messenger.info('Got close command') terminate_processes(watcher) except KeyboardInterrupt: messenger.warning('Program terminated') terminate_processes(watcher) # close encoder when nothing is to do anymore if ff_proc.encoder.poll() is None: ff_proc.encoder.terminate() finally: if ff_proc.encoder.poll() is None: ff_proc.encoder.terminate() ff_proc.encoder.wait()
def output(): """ this output is hls output, no preprocess is needed. """ year = get_date(False).split('-')[0] try: if _playlist.mode and not stdin_args.folder: watcher = None get_source = GetSourceFromPlaylist() else: messenger.info('Start folder mode') media = MediaStore() watcher = MediaWatcher(media) get_source = GetSourceFromFolder(media) try: for src_cmd in get_source.next(): messenger.debug('src_cmd: "{}"'.format(src_cmd)) if src_cmd[0] == '-i': current_file = src_cmd[1] else: current_file = src_cmd[3] messenger.info('Play: "{}"'.format(current_file)) cmd = [ 'ffmpeg', '-v', _log.ff_level.lower(), '-hide_banner', '-nostats' ] + src_cmd + [ '-metadata', 'service_name=' + _playout.name, '-metadata', 'service_provider=' + _playout.provider, '-metadata', 'year={}'.format(year) ] + _playout.ffmpeg_param + _playout.hls_output _ff.encoder = Popen(cmd, stdin=PIPE, stderr=PIPE) stderr_reader_thread = Thread(target=ffmpeg_stderr_reader, args=(_ff.encoder.stderr, False)) stderr_reader_thread.daemon = True stderr_reader_thread.start() stderr_reader_thread.join() ts_cleaning_thread = Thread(target=clean_ts) ts_cleaning_thread.daemon = True ts_cleaning_thread.start() except BrokenPipeError: messenger.error('Broken Pipe!') terminate_processes(watcher) except SystemExit: messenger.info('Got close command') terminate_processes(watcher) except KeyboardInterrupt: messenger.warning('Program terminated') terminate_processes(watcher) # close encoder when nothing is to do anymore if _ff.encoder.poll() is None: _ff.encoder.terminate() finally: if _ff.encoder.poll() is None: _ff.encoder.terminate() _ff.encoder.wait()
def output(): """ this output is for streaming to a target address, like rtmp, rtp, svt, etc. """ year = get_date(False).split('-')[0] overlay = [] ff_pre_settings = [ '-pix_fmt', 'yuv420p', '-r', str(pre.fps), '-c:v', 'mpeg2video', '-intra', '-b:v', f'{pre.v_bitrate}k', '-minrate', f'{pre.v_bitrate}k', '-maxrate', f'{pre.v_bitrate}k', '-bufsize', f'{pre.v_bufsize}k' ] + pre_audio_codec() + ['-f', 'mpegts', '-'] if lower_third.add_text and not lower_third.over_pre: messenger.info( f'Using drawtext node, listening on address: {lower_third.address}' ) overlay = [ '-vf', "null,zmq=b=tcp\\\\://'{}',drawtext=text='':fontfile='{}'".format( lower_third.address.replace(':', '\\:'), lower_third.fontfile) ] try: enc_cmd = [ 'ffmpeg', '-v', log.ff_level.lower(), '-hide_banner', '-nostats', '-re', '-thread_queue_size', '160', '-i', 'pipe:0' ] + overlay + [ '-metadata', 'service_name=' + playout.name, '-metadata', 'service_provider=' + playout.provider, '-metadata', f'year={year}' ] + playout.ffmpeg_param + playout.stream_output messenger.debug(f'Encoder CMD: "{" ".join(enc_cmd)}"') ff_proc.encoder = Popen(enc_cmd, stdin=PIPE, stderr=PIPE) enc_err_thread = Thread(target=ffmpeg_stderr_reader, args=(ff_proc.encoder.stderr, False)) enc_err_thread.daemon = True enc_err_thread.start() if playlist.mode and not stdin_args.folder: watcher = None get_source = GetSourceFromPlaylist() else: messenger.info('Start folder mode') media = MediaStore() watcher = MediaWatcher(media) get_source = GetSourceFromFolder(media) try: for node in get_source.next(): if watcher is not None: watcher.current_clip = node.get('source') messenger.info(f'Play: {node.get("source")}') dec_cmd = [ 'ffmpeg', '-v', log.ff_level.lower(), '-hide_banner', '-nostats' ] + node['src_cmd'] + node['filter'] + ff_pre_settings messenger.debug(f'Decoder CMD: "{" ".join(dec_cmd)}"') with Popen(dec_cmd, stdout=PIPE, stderr=PIPE) as ff_proc.decoder: dec_err_thread = Thread(target=ffmpeg_stderr_reader, args=(ff_proc.decoder.stderr, True)) dec_err_thread.daemon = True dec_err_thread.start() while True: buf = ff_proc.decoder.stdout.read(COPY_BUFSIZE) if not buf: break ff_proc.encoder.stdin.write(buf) except BrokenPipeError: messenger.error('Broken Pipe!') terminate_processes(watcher) except SystemExit: messenger.info('Got close command') terminate_processes(watcher) except KeyboardInterrupt: messenger.warning('Program terminated') terminate_processes(watcher) # close encoder when nothing is to do anymore if ff_proc.encoder.poll() is None: ff_proc.encoder.terminate() finally: if ff_proc.encoder.poll() is None: ff_proc.encoder.terminate() ff_proc.encoder.wait()