윈도우 CMD 에서 이미지, 동영상 변환하기
윈도우에서 자체 사진 서버를 만들다 보니 아이폰의 사진과 동영상 파일이 너무 커서 변환 과정이 필요했습니다. 필요한 작업들을 cmd 스크립트로 작성하고 내용을 정리합니다.
영화와 사진 관리를 위해 TrueNAS 를 구형 PC에 운영하고 있었다. 오래된 장비라서 문제가 생기는 것도 있지만, 간만에 건드리면 익숙치 않아서 문제가 생기면 쉽게 해결하기가 어려웠다.
이럴 바에는 윈도우 PC 에다가 Immich 를 설치하고 늘상 쓰면서 관리하는게 낫겠다 싶어서 재구축 작업을 시작했다.
윈도우 PC의 디스크 용량이 앞으로 몇년간이나 걱정없이 쌓을 정도로 충분한 정도는 아니었기 때문에, 덩치만 큰 mov 파일들을 mp4 포맷으로 변환할 필요가 생겼다.
윈도우에서 동영상 변환을 하려니 ffmpeg 을 쉽게 다루기 위한 스크립트가 필요했고, 하다보니 겸사겸사 사진 파일도 변환하는 스크립트도 작성하게 되었다.
아래 내용은 윈도우 11 환경에서 작업한 내용들을 정리한 것이다.
0. 개요
기본적인 골격이 되는 스크립트이다.
@echo off
:: CMD 창의 코드 페이지를 UTF-8(65001)로 변경
chcp 65001 > nul
echo.
setlocal enabledelayedexpansion
set /a total_count=0
:: 현재 폴더의 모든 파일을 순회
for /f "delims=" %%A in ('dir /b /s *.jpg *.png 2^>nul') do (
set /a total_count+=1
:: 각 파일의 바이트 크기를 가져와 MB 계산
for /f %%I in ('powershell -Command "[math]::Round(%%~zA / 1MB, 2)"') do (
echo [!total_count!] %%~nxA ^(%%I MB^)
)
)
goto :eof
chcp 65001: echo 명령으로 한글을 출력할 때 깨지는 문제를 해결setlocal enabledelayedexpansion: for, if 문 등의 블록 않에서 변수가 계속 초기화 되는 경우에 필요하다set /a: 숫자 변수의 계산값 저장시 필요powershell -Command "": 수학 함수 등의 기능을 사용하려면 powershell 인라인 실행이 필요하다- echo 명령에서 특수문자는 오류를 일으킨다. 이 때
^기호로 출력 문자임을 알려준다.
1. JPG 를 Webp 로 변환하기
아이폰의 jpg 파일을 webp 로 변환하면 1/3~1/4 까지 크게 줄어든다. 이미지의 용량 줄이기는 블로그나 웹서비스에도 필수적인 부분이다.
윈도우 winget 패키지 매니저로 설치할 수 있다.
1
2
3
winget install Google.Libwebp
winget install --id=OliverBetz.ExifTool -e
cwebp 의 metadata 복사 옵션이 제기능을 못한다. 그래서 exiftool 로 메타데이터를 복사하는 작업을 추가했다.
1
2
3
cwebp -quiet -metadata all <입력파일> -o <출력파일>
exiftool -TagsFromFile <원본파일> <복사파일> -overwrite_original
사진 파일에 더러 png 포맷도 있어서 jpg 와 함께 변환하도록 스크립트를 작성했다.
@echo off
:: CMD 창의 코드 페이지를 UTF-8(65001)로 변경
chcp 65001 > nul
echo.
:: 카운트 변수 초기화
setlocal enabledelayedexpansion
set /a total_count=0
set /a success_count=0
set /a skip_count=0
set /a fail_count=0
:: 현재 위치의 모든 jpg 파일에 대해 실행
for /f "delims=" %%i in ('dir /b /s *.jpg *.png 2^>nul') do (
set /a total_count+=1
if exist "%%~ni.webp" (
echo [skip] "%%~ni.webp" 이미 존재하므로 건너뜁니다.
set /a skip_count+=1
) else (
:: 각 파일의 바이트 크기를 가져와 소수점 버림(MB) 계산
for /f %%j in ('powershell -Command "[math]::Round(%%~zi / 1MB, 2)"') do (
echo [!total_count!] %%~nxi ^(%%j MB^)
)
:: 원본 품질 그대로 변환 (-q 80 생략)
cwebp.exe -quiet -metadata all "%%i" -o "%%~ni.webp" 2>nul
:: 정상적으로 출력 파일이 생성되었는지 확인
if not exist "%%~ni.webp" (
echo . . . fail!!
set /a fail_count+=1
) else (
:: 원본 사진의 Exif 정보를 모두 복사
exiftool -TagsFromFile "%%i" "%%~ni.webp" -overwrite_original >nul 2>&1
set /a success_count+=1
)
)
)
:: 최종 결과 출력
echo.
echo ========================================
echo [jpg-to-webp]
echo - total: !total_count!
echo - success: !success_count! (skip: !skip_count!)
echo - fail: !fail_count!
echo ========================================
echo.
2. MOV 를 MP4 로 변환하기
아이폰은 mov 포맷을 사용하는데, 품질에 비해 용량이 어마무지하게 크다. mp4 는 다음 장면과 비교해 변경된 픽셀 데이터를 저장하게 때문에 큰 폭으로 용량을 줄일 수 있다.
FFmpeg 을 이용하면 그래픽 카드의 가속기 기능을 쓸 수 있다.
- 기본 코덱 : libx264, libx265
- Nvidia NVENC : h264_nvenc, hevc_nvenc
- Intel QuickSync : h264_qsv, hevc_qsv
윈도우 winget 으로 설치할 수 있다.
1
winget install -e --id Gyan.FFmpeg
비디오와 오디오 코덱 지정 외에도 메타데이터 복사라던지, 출력 메시지 숨기는 옵션 등을 사용했다.
1
2
3
4
5
# 가속기 사용
ffmpeg -hwaccel qsv -hwaccel_output_format qsv -c:v h264_qsv -i "%%i" -c:v h264_qsv -global_quality 23 -c:a aac -b:a 192k -map_metadata 0 -movflags use_metadata_tags "%%~ni.mp4" -y -loglevel quiet
# 기본 코덱 사용, 오류 무시 (첫번째 실패시 재시도용)
ffmpeg -err_detect ignore_err -i "%%i" -c:v libx264 -crf 23 -c:a aac -map_metadata 0 -movflags use_metadata_tags "%%~ni.mp4" -y -loglevel quiet
현재 위치의 모든 mov 파일을 mp4(h264) 로 변환한다.
@echo off
:: CMD 창의 코드 페이지를 UTF-8(65001)로 변경
chcp 65001 > nul
echo.
:: 카운트 변수 초기화
setlocal enabledelayedexpansion
set /a total_count=0
set /a success_count=0
set /a skip_count=0
set /a fail_count=0
:: 현재 위치의 모든 mov 파일에 대해 실행
for %%i in (*.mov) do (
set /a total_count+=1
if exist "%%~ni.mp4" (
echo [skip] "%%~ni.mp4" 이미 존재하므로 건너뜁니다.
set /a skip_count+=1
) else (
:: 각 파일의 바이트 크기를 가져와 소수점 버림(MB) 계산
for /f %%j in ('powershell -Command "[math]::Round(%%~zi / 1MB, 2)"') do (
echo [!total_count!] %%~nxi ^(%%j MB^) with h264_qsv
)
:: intel QuickSync 그래픽 가속기 사용
ffmpeg -hwaccel qsv -hwaccel_output_format qsv -c:v h264_qsv -i "%%i" -c:v h264_qsv -global_quality 23 -c:a aac -b:a 192k -map_metadata 0 -movflags use_metadata_tags "%%~ni.mp4" -y -loglevel quiet
:: 정상적으로 출력 파일이 생성되었는지 확인
if not exist "%%~ni.mp4" (
:: 실패시 재시도
echo . . . retry with libx264
ffmpeg -err_detect ignore_err -i "%%i" -c:v libx264 -crf 23 -c:a aac -map_metadata 0 -movflags use_metadata_tags "%%~ni.mp4" -y -loglevel quiet
:: 다시 확인
if not exist "%%~ni.mp4" (
echo . . . fail!!
set /a fail_count+=1
) else (
set /a success_count+=1
)
) else (
set /a success_count+=1
)
)
)
:: 최종 결과 출력
echo.
echo ========================================
echo [mov-to-mp4]
echo - total: !total_count!
echo - success: !success_count! (skip: !skip_count!)
echo - fail: !fail_count!
echo ========================================
echo.
9. Review
- TrueNAS 쓸 때, 하드 드라이브 하나를 부트용으로 쓰는게 아까워서 SD 드라이브를 썼더니 업그레이드 할 때마다 SD 카드에 쓰기를 반복해서 오류가 잦아졌다.
- 아~, 푼돈 아끼려다가 큰돈 나가는 격이다.
- 윈도우 cmd 는 쉑~ 이다. 한글 때문이든 무슨 특수문자 때문이든 영문모를 오류가 있었다. 다음에는 powershell 로 해보자.
- 윈도우 WSL 은 여전히 불안정하다. 윈도우도 아니고 리눅스도 아닌 것이 불편한 점이 때때로 튀어나온다. 클라우드에 비해 운영체제에는 신경을 덜 쓰는 것 같다.
- WSL 설정에는
WSL Settings앱을 사용해 설정하자
- WSL 설정에는
끝! 읽어주셔서 감사합니다.
