[게임해도 100% 안도는 CPU를


지난 인왕 2편을 쓸 때 Nvidia Highlights로 녹화한 하이라이트 영상(*.mp4)을 GIF 형식(*.gif/webp)으로 변환해야 했습니다.



인왕2를 켠 상태로 이 글을 쓰고 있는데도 CPU가 100% 안돌아가네요.

요즘 CPU로는 1게임+멀티태스킹이면 충분합니다 참고로 제가 사용하고 있는 CPU는 라이젠 5600X 입니다 ㅎㅎ


주요 주제로 돌아가서… mp4를 gif 또는 webp로 변환하는 가장 저렴하고 빠른 방법은 FFmpeg를 사용하는 것입니다.
웹의 변환기는 정보를 수집하는 과정에서 속도가 느리고 조금 불편했습니다(웹에 비디오 파일을 업로드해야 했습니다).

FFmpeg는 모든 비디오, 음악 및 사진 형식을 디코딩하고 인코딩하는 것을 목표로 하는 오픈 소스 프로젝트입니다!

이 프로그램을 사용하면 비디오를 특정 해상도로 쉽게 다시 인코딩하거나 형식을 변경할 수 있습니다.

이번에는 mp4 비디오를 webp 또는 gif 형식으로 변환해야 하므로 ffmpeg를 사용합니다.

ffmpeg를 사용하는 것은 매우 간단합니다.
깃허브다운로드 후 ffmpeg.exe를 실행하면 동영상 경로(mp4 경로)와 변환 옵션을 지정하여 실행합니다.

이 경우 당연히 많은 수의 mp4 파일을 gif/webp로 한번에 변환해야 하는 상황에 처하게 됩니다.

어떻게 해야 하나요?


비디오에 따라 ffmpeg.exe를 여러 번 실행하십시오. ffmpeg 자체는 실행 파일(*.exe)일 뿐이니까요… 우리가 사용하는 운영체제는 같은 프로그램을 여러 번 실행할 수 있고, ㅎㅎ 노트패드 프로그램을 5~10개까지 열 수 있습니다.
같은 방식으로 여러 ffmpeg를 실행하고 CPU를 한 번에 100%로 설정해 봅시다!

파이썬 스크립트

이 프로젝트의 목적은 AppData\Local\Temp\Highlights\Nioh 2 The Complete Edition에 저장된 모든 Nvidia Highlight 녹음 mp4 파일을 gif/webp로 한 번에 변환하는 것입니다.

mp4 파일에 따라 ffmpeg.exe를 실행해야 하는데 윈도우 배치파일로 해도 되지만 파이썬 프로그래밍 언어의 도움을 받아보도록 하겠습니다.

Python으로 프로그래밍하여 AppData\Local\Temp\Highlights\Nioh 2 The Complete Edition에서 모든 *.mp4 파일을 찾아 즉시 ffmpeg를 사용하여 gif/webp로 변환합니다.


다만, 코드 작성이 번거롭기 때문에 ChatGPT 코드를 생성해보자.

다음은 폴더에서 모든 mp4 파일을 찾고 그에 따라 ffmpeg.exe를 실행하여 gif/webp로 변환하는 Python 코드의 예입니다.

#MP4 -> GIF 일괄 변환

import os
import subprocess
from concurrent.futures import ProcessPoolExecutor

# ffmpeg_path = r"C:\ffmpeg\bin\ffmpeg.exe"
ffmpeg_path = "ffmpeg"
source_folder = r"원본 경로"
destination_folder = r"저장 경로"

# 용량에 큰 영향을 끼치는 값 = fps
width = "800"
height = "400"
fps = "10"

def convert_to_gif(file_path):
    output_path = os.path.join(destination_folder, os.path.relpath(file_path, source_folder))
    output_path = os.path.splitext(output_path)(0) + ".gif"
    command = (ffmpeg_path, "-i", file_path, "-vf", f"fps={fps},scale={width}:{height}:flags=lanczos,split(s0)(s1);(s0)palettegen(p);(s1)(p)paletteuse", "-loop", "0", output_path)
    # command = (ffmpeg_path, "-i", file_path, "-vf", f"fps={fps},scale={width}:{height}:flags=lanczos,split(s0)(s1);(s0)palettegen(p);(s1)(p)paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle", "-loop", "0", "-f", "gif", "- | gifsicle --optimize=3 --delay=10 > " + output_path)
    subprocess.run(command, check=True)

if __name__ == "__main__":
    with ProcessPoolExecutor() as executor:
        for root, _, files in os.walk(source_folder):
            for file in files:
                if file.endswith(".mp4"):
                    file_path = os.path.join(root, file)
                    executor.submit(convert_to_gif, file_path)

    print("Task Finished :D")

#MP4 -> webp 일괄 변환

import os
import subprocess
from concurrent.futures import ProcessPoolExecutor

# ffmpeg_path = r"C:\ffmpeg\bin\ffmpeg.exe"
ffmpeg_path = "ffmpeg"
source_folder = r"원본 경로"
destination_folder = r"저장 경로"

width = "800"
height = "400"
quality = "50" #default : 75

def convert_to_webp(file_path):
    output_path = os.path.join(destination_folder, os.path.relpath(file_path, source_folder))
    output_path = os.path.splitext(output_path)(0) + ".webp"
    command = (ffmpeg_path, "-i", file_path, "-vcodec", "libwebp", f"-quality {quality}", "-filter:v", "fps=fps=30", "-lossless", "1", "-loop", "0", "-preset", "default", "-an", "-vsync", "0", "-s", f"{width}:{height}", output_path)
    subprocess.run(command, check=True)

if __name__ == "__main__":
    with ProcessPoolExecutor() as executor:
        for root, _, files in os.walk(source_folder):
            for file in files:
                if file.endswith(".mp4"):
                    file_path = os.path.join(root, file)
                    executor.submit(convert_to_webp, file_path)
    print("Task Finished :D")

위의 두 코드는 모두 ChatGPT 형제가 작성한 mp4 -> webp, gif의 변환 파이썬 코드입니다.

mp4가 source_folder에 있는 경로 위치,

대상 폴더는 출력을 저장할 폴더 위치를 지정합니다(webp/gif).

그리고 ffmpeg_path는 ffmpeg.exe 파일의 위치를 ​​결정하고 이미 환경 변수에 ffmpeg를 등록하고 전역으로 사용할 수 있으므로 ffmpeg를 작성했습니다.
ffmpeg를 따로 받아 환경변수에 등록하지 않은 경우 받은 ffmpeg.exe의 절대경로를 입력합니다.

또한 변환할 GIF의 크기(너비, 높이), 품질, fps 등을 사용자 정의할 수 있습니다.

참고로 webp는 압축률이 높아서 상관없지만 예전 gif 확장자 크기를 줄이고 싶다면 gif 크기를 줄이는 것보다 fps를 줄여서 gif로 변환하는 것을 강력 추천합니다.
해상도가 낮으면 100MB를 초과합니다.

스토리 업로드 제한은 30MB입니다.
fps를 약 10으로 설정하면 GIF 파일의 크기가 크게 줄어듭니다.

아무튼 위의 코드에서 변수 값을 변경할 값으로 변경하고 실행하면…?

참고로 티스토리는 webp 업로드를 차단하기 때문에 부득이하게 webp 대신 GIF로 변환하겠습니다.




게임을 실행하고도 100%까지 발사에 실패한 CPU는 모든 코어(스레드)를 갈망하면서 그래프를 채우는 모습을 잘 보여준다.

최신 시분할 운영 체제인 컨텍스트 전환의 아름다움


아무튼 기다리면 다음과 같이 폴더에 gif로 변환된 파일이 나타나는 것을 볼 수 있습니다.

참고로 압축의 경우 gifsicle이라는 프로그램을 이용해서 다시 압축을 했습니다.

(기프시클은 여기 얻어 질 수있는. 또는 Windows 패키지 관리자 초코를 통해 설치할 수도 있습니다.
)

import os
import subprocess
from concurrent.futures import ProcessPoolExecutor

# ffmpeg_path = r"C:\ffmpeg\bin\ffmpeg.exe"
gifsicle_path = "gifsicle"
source_folder = r"source"
destination_folder = r"dest"

# 용량에 큰 영향을 끼치는 값 = fps
width = "800"
height = "400"
fps = "10"

def convert_to_gif(file_path):
    output_path = os.path.join(destination_folder, os.path.relpath(file_path, source_folder))
    output_path = os.path.splitext(output_path)(0) + "_compressed" + ".gif"
    command = (gifsicle_path, "-O3", "--lossy=80", file_path, "-o", output_path)
    subprocess.run(command, check=True)

if __name__ == "__main__":
    with ProcessPoolExecutor() as executor:
        for root, _, files in os.walk(source_folder):
            for file in files:
                if file.endswith(".gif"):
                    file_path = os.path.join(root, file)
                    executor.submit(convert_to_gif, file_path)

    print("Task Finished :D")

참고로 Gifsicle을 이용하여 Gifsicle의 모든 폴더에 있는 GIF 파일을 압축하는 코드는 다음과 같습니다.

또한 chatgpt로 추출됩니다.


20MB 내외에서 잘 추출된 인왕 게임 gif를 포스팅에 활용한 방법입니다!
!