• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

EsupPortail / Esup-Pod / 6377635546

02 Oct 2023 08:21AM UTC coverage: 70.396% (-1.6%) from 71.99%
6377635546

push

github

web-flow
Merge pull request #900 from EsupPortail/develop

[DONE] #3.4.0

1509 of 1509 new or added lines in 58 files covered. (100.0%)

9288 of 13194 relevant lines covered (70.4%)

0.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

23.26
/pod/video_encode_transcript/encoding_studio.py
1
"""This module handles studio encoding with CPU."""
2
from django.conf import settings
1✔
3
from .utils import check_file, send_email_recording
1✔
4
from . import encode
1✔
5

6
import time
1✔
7
import subprocess
1✔
8
import json
1✔
9

10
from .encoding_settings import (
1✔
11
    FFMPEG_CMD,
12
    FFPROBE_CMD,
13
    FFMPEG_CRF,
14
    FFMPEG_NB_THREADS,
15
    FFPROBE_GET_INFO,
16
    FFMPEG_STUDIO_COMMAND,
17
)
18

19
FFMPEG_CMD = getattr(settings, "FFMPEG_CMD", FFMPEG_CMD)
1✔
20
FFPROBE_CMD = getattr(settings, "FFPROBE_CMD", FFPROBE_CMD)
1✔
21
FFMPEG_CRF = getattr(settings, "FFMPEG_CRF", FFMPEG_CRF)
1✔
22
FFMPEG_NB_THREADS = getattr(settings, "FFMPEG_NB_THREADS", FFMPEG_NB_THREADS)
1✔
23
FFPROBE_GET_INFO = getattr(settings, "FFPROBE_GET_INFO", FFPROBE_GET_INFO)
1✔
24
FFMPEG_STUDIO_COMMAND = getattr(settings, "FFMPEG_STUDIO_COMMAND", FFMPEG_STUDIO_COMMAND)
1✔
25

26
DEBUG = getattr(settings, "DEBUG", True)
1✔
27

28
ENCODE_VIDEO = getattr(settings, "ENCODE_VIDEO", "start_encode")
1✔
29

30
# ##########################################################################
31
# ENCODE VIDEO STUDIO: MAIN ENCODE
32
# ##########################################################################
33

34

35
def get_video_info(command):
1✔
36
    """Get ffprobe video info."""
37
    ffproberesult = subprocess.run(
×
38
        command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
39
    )
40
    return json.loads(ffproberesult.stdout.decode("utf-8"))
×
41

42

43
def encode_video_studio(recording_id, video_output, videos, subtime, presenter):
1✔
44
    """Encode video from studio."""
45
    presenter_source = None
×
46
    presentation_source = None
×
47
    input_video = ""
×
48
    for video in videos:
×
49
        if video.get("type") == "presenter/source":
×
50
            presenter_source = video.get("src")
×
51
            input_video = '-i "' + presenter_source + '" '
×
52
        if video.get("type") == "presentation/source":
×
53
            presentation_source = video.get("src")
×
54
            input_video = '-i "' + presentation_source + '" '
×
55
    info_presenter_video = {}
×
56
    info_presentation_video = {}
×
57
    if presenter_source and presentation_source:
×
58
        # to put it in the right order
59
        input_video = '-i "' + presentation_source + '" -i "' + presenter_source + '" '
×
60
        command = FFPROBE_GET_INFO % {
×
61
            "ffprobe": FFPROBE_CMD,
62
            "select_streams": "-select_streams v:0 ",
63
            "source": '"' + presentation_source + '" ',
64
        }
65
        info_presentation_video = get_video_info(command)
×
66
        command = FFPROBE_GET_INFO % {
×
67
            "ffprobe": FFPROBE_CMD,
68
            "select_streams": "-select_streams v:0 ",
69
            "source": '"' + presenter_source + '" ',
70
        }
71
        info_presenter_video = get_video_info(command)
×
72
        subcmd = get_sub_cmd(
×
73
            get_height(info_presentation_video),
74
            get_height(info_presenter_video),
75
            presenter,
76
        )
77

78
    else:
79
        subcmd = " -vsync 0 "
×
80
    subcmd += " -movflags +faststart -f mp4 "
×
81

82
    msg = launch_encode_video_studio(input_video, subtime, subcmd, video_output)
×
83
    from pod.recorder.models import Recording
×
84

85
    recording = Recording.objects.get(id=recording_id)
×
86
    recording.comment += msg
×
87
    recording.save()
×
88
    if check_file(video_output):
×
89
        from pod.recorder.plugins.type_studio import save_basic_video
×
90

91
        video = save_basic_video(recording, video_output)
×
92
        encode_video = getattr(encode, ENCODE_VIDEO)
×
93
        encode_video(video.id, False)
×
94
    else:
95
        msg = "Wrong file or path:" + "\n%s" % video_output
×
96
        send_email_recording(msg, recording_id)
×
97

98

99
def get_sub_cmd(height_presentation_video, height_presenter_video, presenter):
1✔
100
    min_height = min([height_presentation_video, height_presenter_video])
×
101
    subcmd = ""
×
102
    if presenter == "pipb":
×
103
        # trouver la bonne hauteur en fonction de la video de presentation
104
        height = (
×
105
            height_presentation_video
106
            if (height_presentation_video % 2) == 0
107
            else height_presentation_video + 1
108
        )
109
        # ffmpeg -y -i presentation_source.webm -i presenter_source.webm \
110
        # -c:v libx264 -filter_complex "[0:v]scale=-2:720[pres];[1:v]scale=-2:180[pip];\
111
        # [pres][pip]overlay=W-w-10:H-h-10:shortest=1" \
112
        # -vsync 0 outputVideo.mp4
113
        subcmd = (
×
114
            " -filter_complex "
115
            + '"[0:v]scale=-2:%(height)s[pres];[1:v]scale=-2:%(sh)s[pip];'
116
            % {"height": height, "sh": height / 4}
117
            + '[pres][pip]overlay=W-w-10:H-h-10:shortest=1" -vsync 0 '
118
        )
119
    if presenter == "piph":
×
120
        # trouver la bonne hauteur en fonction de la video de presentation
121
        height = (
×
122
            height_presentation_video
123
            if (height_presentation_video % 2) == 0
124
            else height_presentation_video + 1
125
        )
126
        # ffmpeg -y -i presentation_source.webm -i presenter_source.webm \
127
        # -c:v libx264 -filter_complex "[0:v]scale=-2:720[pres];[1:v]scale=-2:180[pip];\
128
        # [pres][pip]overlay=W-w-10:H-h-10:shortest=1" \
129
        # -vsync 0 outputVideo.mp4
130
        subcmd = (
×
131
            " -filter_complex "
132
            + '"[0:v]scale=-2:%(height)s[pres];[1:v]scale=-2:%(sh)s[pip];'
133
            % {"height": height, "sh": height / 4}
134
            + '[pres][pip]overlay=W-w-10:10:shortest=1" -vsync 0 '
135
        )
136
    if presenter == "mid":
×
137
        height = min_height if (min_height % 2) == 0 else min_height + 1
×
138
        # ffmpeg -i presentation.webm -i presenter.webm \
139
        # -c:v libx264 -filter_complex "[0:v]scale=-2:720[left];[left][1:v]hstack" \
140
        # outputVideo.mp4
141
        subcmd = (
×
142
            " -filter_complex "
143
            + '"[0:v]scale=-2:%(height)s[left];[1:v]scale=-2:%(height)s[right];'
144
            % {"height": height}
145
            + '[left][right]hstack" -vsync 0 '
146
        )
147

148
    return subcmd
×
149

150

151
def get_height(info):
1✔
152
    """Get the height value from the given video information dictionary."""
153
    in_height = 0
×
154
    if len(info["streams"]) > 0 and info["streams"][0].get("height"):
×
155
        in_height = info["streams"][0]["height"]
×
156
    return in_height
×
157

158

159
def launch_encode_video_studio(input_video, subtime, subcmd, video_output):
1✔
160
    """Encode video for studio."""
161
    msg = ""
×
162
    partial_command = FFMPEG_STUDIO_COMMAND % {
×
163
        "nb_threads": FFMPEG_NB_THREADS,
164
        "input": input_video,
165
        "subtime": subtime,
166
        "crf": FFMPEG_CRF,
167
    }
168
    ffmpegStudioCommand = "%s %s %s %s" % (
×
169
        FFMPEG_CMD,
170
        partial_command,
171
        subcmd,
172
        video_output,
173
    )
174
    msg += "- %s\n" % ffmpegStudioCommand
×
175
    logfile = video_output.replace(".mp4", ".log")
×
176
    ffmpegstudio = subprocess.run(
×
177
        ffmpegStudioCommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
178
    )
179
    with open(logfile, "ab") as f:
×
180
        f.write(b"\n\ffmpegstudio:\n\n")
×
181
        f.write(ffmpegstudio.stdout)
×
182
    msg += "\n- Encoding Mp4: %s" % time.ctime()
×
183
    if DEBUG:
×
184
        print(msg)
×
185
        print(ffmpegstudio.stdout)
×
186
        print(ffmpegstudio.stderr)
×
187
    return msg
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc