File size: 3,909 Bytes
8718761
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import os
import subprocess as sp
import warnings
from typing import List

__all__ = ['encode_video_comparison']


def encode_video_comparison(
        audiofile: str,
        subtitle_files: List[str],
        output_videopath: str = None,
        *,
        labels: List[str] = None,
        height: int = 90,
        width: int = 720,
        color: str = 'black',
        fontsize: int = 70,
        border_color: str = 'white',
        label_color: str = 'white',
        label_size: int = 14,
        fps: int = 25,
        video_codec: str = None,
        audio_codec: str = None,
        overwrite=False,
        only_cmd: bool = False,
        verbose=True
) -> (str, None):
    """
    Encode multiple subtitle files into one video with the subtitles vertically stacked.

    Parameters
    ----------
    audiofile : str
        Path of audio file.
    subtitle_files : list of str
        List of paths for subtitle file.
    output_videopath : str, optional
        Output video path.
    labels : list of str, default, None, meaning use ``subtitle_files`` as labels
        List of labels for ``subtitle_files``.
    height : int, default 90
        Height for each subtitle section.
    width : int, default 720
        Width for each subtitle section.
    color : str, default 'black'
        Background color of the video.
    fontsize: int, default 70
        Font size for subtitles.
    border_color : str, default 'white'
        Border color for separating the sections of subtitle.
    label_color : str, default 'white'
        Color of labels.
    label_size : int, default 14
        Font size of labels.
    fps : int, default 25
        Frame-rate of the video.
    video_codec : str, optional
        Video codec opf the video.
    audio_codec : str, optional
        Audio codec opf the video.
    overwrite : bool, default False
        Whether to overwrite existing video files with the same path as the output video.
    only_cmd : bool, default False
        Whether to skip encoding and only return the full command generate from the specified options.
    verbose : bool, default True
        Whether to display ffmpeg processing info.

    Returns
    -------
    str or None
        Encoding command as a string if ``only_cmd = True``.
    """
    vc = '' if video_codec is None else f' -c:v {video_codec}'
    ac = '' if audio_codec is None else f' -c:a {audio_codec}'
    background = f'-f lavfi -i color=size={width}x{height}:rate={fps}:color={color}'
    border = f'-f lavfi -i color=size={width}x3:rate={fps}:color={border_color}'
    audio = f'-i "{audiofile}"'
    cfilters0 = []
    assert labels is None or len(labels) == len(subtitle_files)
    for i, sub in enumerate(subtitle_files):
        label = sub if labels is None else labels[i]
        label = label.replace("'", '"')
        fil = f"[0]drawtext=text='{label}':fontcolor={label_color}:fontsize={label_size}:x=10:y=10[a{i}]," \
              f"[a{i}]subtitles='{sub}':force_style='Fontsize={fontsize}'[b{i}]"
        cfilters0.append(fil)
    cfilters1 = (
            '[1]'.join(
                f'[b{i}]' for i in range(len(cfilters0))
            )
            +
            f'vstack=inputs={len(cfilters0) * 2 - 1}'
    )
    final_fil = ','.join(cfilters0) + f';{cfilters1}'
    ow = '-y' if overwrite else '-n'
    if output_videopath is None:
        name = os.path.split(os.path.splitext(audiofile)[0])[1]
        output_videopath = f'{name}_sub_comparison.mp4'
    cmd = (f'ffmpeg {ow} {background} {border} {audio} '
           f'-filter_complex "{final_fil}"{vc}{ac} -shortest "{output_videopath}"')
    if only_cmd:
        return cmd
    if verbose:
        print(cmd)
    rc = sp.run(cmd, capture_output=not verbose).returncode
    if rc == 0:
        if verbose:
            print(f'Encoded: {output_videopath}')
    else:
        warnings.warn(f'Failed to encode {output_videopath}')