Commit 9e44c185 authored by Mickaël Desfrênes's avatar Mickaël Desfrênes
Browse files

support HLS conversion of videos without audio

parent aec93b22
Loading
Loading
Loading
Loading
+68 −61
Original line number Diff line number Diff line
import shutil
import exiftool
import hashlib
import json
from django.core.files.base import File
from jama import settings
from resources import models
@@ -182,12 +183,35 @@ def make_hls(f: Union[models.File, int], force: bool = False):
    or if conversion already exists, except if force is True.
    """

    def has_audio(path):
        result = subprocess.run(
            [
                "ffprobe",
                "-v",
                "error",
                "-select_streams",
                "a",
                "-show_entries",
                "stream=index",
                "-of",
                "json",
                path,
            ],
            capture_output=True,
            text=True,
        )
        streams = json.loads(result.stdout).get("streams", [])
        return len(streams) > 0

    if type(f) is int:
        f = models.File.objects.get(pk=f)
    if f.should_have_hls:
        hls_destination_dir = hls_destination_dir_from_hash(f.hash)
        if force or not os.path.exists(hls_destination_dir):
            os.makedirs(hls_destination_dir, exist_ok=True)

            audio_present = has_audio(f.local_path())

            ffmpeg_cmd = [
                "ffmpeg",
                "-y",
@@ -196,91 +220,70 @@ def make_hls(f: Union[models.File, int], force: bool = False):
                "-filter_complex",
                (
                    "[0:v]split=4[v1][v2][v3][v4];"
                    "[v1]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black[v1out];"
                    "[v2]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2:black[v2out];"
                    "[v3]scale=854:480:force_original_aspect_ratio=decrease,pad=854:480:(ow-iw)/2:(oh-ih)/2:black[v3out];"
                    "[v4]scale=426:240:force_original_aspect_ratio=decrease,pad=426:240:(ow-iw)/2:(oh-ih)/2:black[v4out]"
                    "[v1]scale=1920:1080:force_original_aspect_ratio=decrease,"
                    "pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black[v1out];"
                    "[v2]scale=1280:720:force_original_aspect_ratio=decrease,"
                    "pad=1280:720:(ow-iw)/2:(oh-ih)/2:black[v2out];"
                    "[v3]scale=854:480:force_original_aspect_ratio=decrease,"
                    "pad=854:480:(ow-iw)/2:(oh-ih)/2:black[v3out];"
                    "[v4]scale=426:240:force_original_aspect_ratio=decrease,"
                    "pad=426:240:(ow-iw)/2:(oh-ih)/2:black[v4out]"
                ),
                "-map",
                "[v1out]",
                "-c:v:0",
                "libx264",
                "-pix_fmt",
                "yuv420p",
                "-b:v:0",
                "5000k",
                "-maxrate:v:0",
                "5350k",
                "-bufsize:v:0",
                "7500k",
                "-map",
                "[v2out]",
                "-c:v:1",
                "libx264",
                "-pix_fmt",
                "yuv420p",
                "-b:v:1",
                "2800k",
                "-maxrate:v:1",
                "2996k",
                "-bufsize:v:1",
                "4200k",
                "-map",
                "[v3out]",
                "-c:v:2",
                "libx264",
                "-pix_fmt",
                "yuv420p",
                "-b:v:2",
                "1400k",
                "-maxrate:v:2",
                "1498k",
                "-bufsize:v:2",
                "2100k",
                "-map",
                "[v4out]",
                "-c:v:3",
                "libx264",
                "-pix_fmt",
                "yuv420p",
                "-b:v:3",
                "700k",
                "-maxrate:v:3",
                "749k",
                "-bufsize:v:3",
                "1050k",
            ]

            if audio_present:
                ffmpeg_cmd += [
                    "-map",
                    "a:0",
                    "-c:a:0",
                    "aac",
                    "-b:a:0",
                    "192k",
                "-ac",
                "2",
                    "-map",
                    "a:0",
                    "-c:a:1",
                    "aac",
                    "-b:a:1",
                    "128k",
                "-ac",
                "2",
                    "-map",
                    "a:0",
                    "-c:a:2",
                    "aac",
                    "-b:a:2",
                    "96k",
                "-ac",
                "2",
                    "-map",
                    "a:0",
                    "-c:a:3",
                    "aac",
                    "-b:a:3",
                    "64k",
                "-ac",
                "2",
                ]

            ffmpeg_cmd += [
                "-f",
                "hls",
                "-hls_time",
@@ -296,7 +299,11 @@ def make_hls(f: Union[models.File, int], force: bool = False):
                "-master_pl_name",
                "master.m3u8",
                "-var_stream_map",
                "v:0,a:0 v:1,a:1 v:2,a:2 v:3,a:3",
                (
                    "v:0,a:0 v:1,a:1 v:2,a:2 v:3,a:3"
                    if audio_present
                    else "v:0 v:1 v:2 v:3"
                ),
                f"{hls_destination_dir}stream_%v{os.path.sep}playlist.m3u8",
            ]