Ejemplo n.º 1
0
    def next(self):
        while True:
            self.get_playlist()

            if self.clip_nodes is None:
                self.eof_handling(
                    'No valid playlist:\n{}'.format(self.json_file), True, 30)
                yield self.src_cmd + self.filtergraph
                continue

            self.begin = self.init_time

            # loop through all clips in playlist and get correct clip in time
            for index, node in enumerate(self.clip_nodes["program"]):
                self.get_clip_in_out(node)

                # first time we end up here
                if self.first and \
                        self.last_time < self.begin + self.out - self.seek:

                    self.peperation_task(index, node)
                    self.first = False
                    break
                elif self.last_time < self.begin:
                    if index + 1 == len(self.clip_nodes["program"]):
                        self.last = True
                    else:
                        self.last = False

                    self.peperation_task(index, node)
                    break

                self.begin += self.out - self.seek
            else:
                if stdin_args.loop:
                    self.check_for_next_playlist()
                    self.init_time = self.last_time + 1
                    self.src_cmd = None
                elif not _playlist.length and not stdin_args.loop:
                    # when we reach playlist end, stop script
                    messenger.info('Playlist reached end!')
                    self.eof_handling('Playlist reached end!', True)
                    #return None
                elif self.begin == self.init_time:
                    # no clip was played, generate dummy
                    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:
                yield self.src_cmd + self.filtergraph
Ejemplo n.º 2
0
    def peperation_task(self, index, node):
        # call functions in order to prepare source and filter
        self.src = node["source"]
        self.probe.load(self.src)

        self.get_input()
        self.get_category(index, node)
        self.set_filtergraph()
        self.check_for_next_playlist()
        if _playout.on_track_change:
            command = _playout.on_track_change + " '" + json.dumps(node) + "'"
            messenger.info(command)
            os.system(command)
Ejemplo n.º 3
0
    def get_playlist(self):
        if stdin_args.playlist:
            self.json_file = stdin_args.playlist
        else:
            year, month, day = self.list_date.split('-')
            self.json_file = os.path.join(
             _playlist.path, year, month, self.list_date + '.json')

        if '://' in self.json_file:
            self.json_file = self.json_file.replace('\\', '/')

            try:
                req = request.urlopen(self.json_file,
                                      timeout=1,
                                      context=ssl._create_unverified_context())
                b_time = req.headers['last-modified']
                temp_time = time.strptime(b_time, "%a, %d %b %Y %H:%M:%S %Z")
                mod_time = time.mktime(temp_time)

                if mod_time > self.last_mod_time:
                    self.clip_nodes = valid_json(req)
                    self.last_mod_time = mod_time
                    messenger.info('Open: ' + self.json_file)
                    validate_thread(self.clip_nodes)
            except (request.URLError, socket.timeout):
                self.eof_handling('Get playlist from url failed!', False)

        elif os.path.isfile(self.json_file):
            # check last modification from playlist
            mod_time = os.path.getmtime(self.json_file)
            if mod_time > self.last_mod_time:
                with open(self.json_file, 'r', encoding='utf-8') as f:
                    self.clip_nodes = valid_json(f)

                self.last_mod_time = mod_time
                messenger.info('Open: ' + self.json_file)
                validate_thread(self.clip_nodes)
        else:
            # when we have no playlist for the current day,
            # then we generate a black clip
            # and calculate the seek in time, for when the playlist comes back
            self.eof_handling('Playlist not exist:', False)
Ejemplo n.º 4
0
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()
Ejemplo n.º 5
0
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()
Ejemplo n.º 6
0
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()
Ejemplo n.º 7
0
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()
Ejemplo n.º 8
0
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()