# FFMPEG 스크립트 작성

### 스크립트 작성의 필요성

FFMPEG을 명령줄에서 반복적으로 사용해야 할 경우, 매번 동일한 명령어를 입력하는 것은 비효율적일 수 있다. 특히 여러 파일을 변환하거나 복잡한 파라미터를 사용하는 경우, 스크립트로 작업을 자동화하면 시간과 노력을 절약할 수 있다. 스크립트 작성은 FFMPEG의 강력한 기능을 효율적으로 사용할 수 있게 해주는 중요한 도구이다.

### 스크립트 작성의 기본 개념

스크립트는 단순히 여러 명령을 한 번에 실행할 수 있도록 미리 작성한 명령어 모음이다. 스크립트는 다양한 운영체제에서 사용할 수 있으며, 주로 셸 스크립트(bash), 배치 파일(batch file), 파이썬 스크립트 등이 사용된다.

#### 셸 스크립트에서 FFMPEG 사용

리눅스 및 macOS에서 주로 사용되는 셸 스크립트를 활용해 FFMPEG 명령어를 자동화할 수 있다. 예를 들어, 다음과 같은 간단한 스크립트를 작성하여 여러 비디오 파일을 일괄 변환할 수 있다.

```bash
#!/bin/bash
for file in *.mp4; do
    ffmpeg -i "$file" -c:v libx264 "${file%.mp4}.mkv"
done
```

이 스크립트는 디렉토리 내에 있는 모든 `.mp4` 파일을 `.mkv` 파일로 변환한다. 여기서 `for` 루프는 디렉토리 내의 모든 파일을 순차적으로 처리하며, `ffmpeg` 명령을 통해 비디오 변환 작업을 수행한다.

### 스크립트 내 변수 사용

스크립트 내에서 변수를 사용하면 코드의 재사용성을 높일 수 있다. 특히 FFMPEG 명령어는 다양한 파라미터를 사용하는 경우가 많기 때문에, 변수를 활용하면 코드를 더 효율적으로 관리할 수 있다.

#### 변수 설정 예시

```bash
#!/bin/bash
input_format="mp4"
output_format="mkv"
codec="libx264"

for file in *.$input_format; do
    ffmpeg -i "$file" -c:v$codec "${file%.$input_format}.$output_format"
done
```

여기서 `input_format`, `output_format`, 그리고 `codec` 변수를 사용하여 입력 파일 형식, 출력 파일 형식, 코덱을 설정하였다. 이러한 방식을 사용하면 간단한 변수 변경만으로도 여러 파일을 쉽게 변환할 수 있다.

### 조건문 사용

스크립트에서 조건문을 사용하여 특정 조건에 따라 FFMPEG 명령을 다르게 실행할 수 있다. 이를 통해 더 복잡한 변환 작업을 자동화할 수 있다.

#### 조건문 예시

```bash
#!/bin/bash
input_format="mp4"
output_format="mkv"
codec="libx264"

for file in *.$input_format; do
    if [ "${file: -4}" == ".mp4" ]; then
        ffmpeg -i "$file" -c:v$codec "${file%.$input_format}.$output_format"
    else
        echo "Skipping non-mp4 file: $file"
    fi
done
```

위 예시에서는 `.mp4` 파일만 변환하며, 다른 형식의 파일은 변환하지 않고 건너뛰게 된다. `if` 조건문을 사용하여 파일 확장자를 검사하며, 조건을 만족하는 경우에만 FFMPEG 명령어를 실행한다.

### 파일 경로 처리

스크립트를 작성할 때 파일 경로를 처리하는 방법도 중요하다. 특히 여러 디렉토리에 분산된 파일을 처리해야 하는 경우 파일 경로를 적절히 관리해야 한다.

#### 파일 경로 처리 예시

```bash
#!/bin/bash
input_dir="/path/to/input/"
output_dir="/path/to/output/"
codec="libx264"

for file in "$input_dir"*.mp4; do
    filename=$(basename "$file")
    ffmpeg -i "$file" -c:v$codec "$output_dir${filename%.mp4}.mkv"
done
```

이 스크립트에서는 `basename` 명령어를 사용하여 파일 이름만 추출한 후, 출력 디렉토리 경로와 함께 출력 파일을 생성한다. `input_dir`과 `output_dir` 변수를 사용하여 입력 및 출력 파일의 디렉토리를 각각 설정한다.

### 배치 파일에서 FFMPEG 사용

윈도우 환경에서는 배치 파일을 사용하여 FFMPEG 명령어를 자동화할 수 있다. 배치 파일 역시 반복적인 작업을 자동화하는 데 유용하며, 셸 스크립트와 유사한 방식으로 작동한다.

#### 배치 파일 예시

```batch
@echo off
set input_format=mp4
set output_format=mkv
set codec=libx264

for %%f in (*.%input_format%) do (
    ffmpeg -i "%%f" -c:v %codec% "%%~nf.%output_format%"
)
```

위 배치 파일은 현재 디렉토리 내의 모든 `.mp4` 파일을 `.mkv` 파일로 변환한다. `set` 명령어를 통해 변수를 설정하며, `for` 루프를 사용하여 파일을 순차적으로 처리한다.

### 파이썬 스크립트에서 FFMPEG 사용

FFMPEG은 파이썬과 같은 프로그래밍 언어에서도 쉽게 호출할 수 있다. 파이썬 스크립트를 통해 FFMPEG 명령어를 실행하는 것은 더 복잡한 작업을 자동화하거나, GUI를 통해 작업을 제어하고자 할 때 매우 유용하다.

#### 파이썬에서 FFMPEG 호출

파이썬의 `subprocess` 모듈을 사용하여 FFMPEG 명령어를 실행할 수 있다. 예를 들어, 다음과 같은 파이썬 스크립트는 여러 파일을 변환하는 작업을 수행할 수 있다.

```python
import subprocess
import os

input_dir = "/path/to/input/"
output_dir = "/path/to/output/"
codec = "libx264"

for filename in os.listdir(input_dir):
    if filename.endswith(".mp4"):
        input_path = os.path.join(input_dir, filename)
        output_filename = filename.replace(".mp4", ".mkv")
        output_path = os.path.join(output_dir, output_filename)
        subprocess.run(["ffmpeg", "-i", input_path, "-c:v", codec, output_path])
```

이 파이썬 스크립트는 주어진 디렉토리 내에서 `.mp4` 파일을 찾아 `.mkv` 형식으로 변환한다. `subprocess.run`을 사용하여 FFMPEG 명령어를 실행하며, `os.path.join`을 통해 파일 경로를 처리한다.

### 스크립트의 실행 및 디버깅

스크립트를 작성한 후에는 실행 결과를 확인하고, 필요한 경우 디버깅 작업을 수행해야 한다. 특히 복잡한 FFMPEG 명령어를 사용할 때는 예상치 못한 오류가 발생할 수 있으므로, 스크립트의 각 부분을 꼼꼼히 확인해야 한다.

#### 디버깅 기법

* **에러 출력 확인:** FFMPEG은 명령어 실행 중 발생한 오류를 상세히 출력하므로, 이를 활용하여 문제를 해결할 수 있다.
* **로그 파일 저장:** 스크립트 실행 시 로그 파일에 출력을 저장하여, 이후에 오류를 추적하고 분석할 수 있다.

```bash
ffmpeg -i input.mp4 output.mkv 2> error.log
```

위 명령어는 오류 메시지를 `error.log` 파일에 저장한다. 스크립트에서 이 방법을 사용하면, 변환 중 발생한 모든 오류를 한눈에 확인할 수 있다.

### 루프와 반복 처리

FFMPEG 작업을 자동화할 때, 반복 처리 루프를 활용하면 효율성을 극대화할 수 있다. 여러 파일을 처리하거나, 동일한 작업을 반복해야 할 때 유용하다.

#### 루프 구조의 활용

반복적으로 동일한 작업을 수행해야 할 경우, 루프를 사용하여 각 파일에 대해 FFMPEG 명령을 실행할 수 있다. 예를 들어, 아래의 예시는 셸 스크립트에서 다양한 파일 형식을 순차적으로 변환하는 방법을 보여준다.

```bash
#!/bin/bash
for ext in mp4 mov avi; do
    for file in *.$ext; do
        ffmpeg -i "$file" -c:v libx264 "${file%.$ext}.mkv"
    done
done
```

이 스크립트는 `.mp4`, `.mov`, 그리고 `.avi` 형식의 파일을 순차적으로 변환한다. `for` 루프를 사용하여 각 파일 형식을 처리하며, 하나의 스크립트로 여러 형식의 파일을 자동으로 변환할 수 있다.

### 오류 처리 및 예외 처리

스크립트를 작성할 때 오류 처리 및 예외 처리는 필수적인 부분이다. 특히 FFMPEG은 다양한 미디어 파일을 처리하는 과정에서 파일 형식, 코덱, 해상도 등 여러 가지 이유로 오류가 발생할 수 있다. 스크립트 내에서 이러한 오류를 감지하고 처리할 수 있도록 해야 한다.

#### 셸 스크립트에서의 오류 처리

셸 스크립트에서는 명령어가 실패했을 경우, 그에 대한 적절한 처리를 추가할 수 있다. `if` 문과 `$?` 변수를 활용하여 오류 발생 여부를 확인할 수 있다. `$?` 변수는 마지막 명령어의 종료 상태를 나타내며, 0이면 성공, 1 이상이면 실패를 의미한다.

**오류 처리 예시**

```bash
#!/bin/bash
input_file="input.mp4"
output_file="output.mkv"

ffmpeg -i "$input_file" -c:v libx264 "$output_file"
if [ $? -ne 0 ]; then
    echo "FFMPEG 변환에 실패하였다. 파일: $input_file"
    exit 1
else
    echo "FFMPEG 변환이 성공적으로 완료되었다. 파일: $output_file"
fi
```

위 스크립트는 FFMPEG 변환이 성공했는지 여부를 확인하고, 실패한 경우 에러 메시지를 출력한다. 성공적으로 변환이 완료되면 그 결과를 사용자에게 알려준다.

### 파이썬에서의 예외 처리

파이썬에서는 `try-except` 블록을 사용하여 예외 처리를 할 수 있다. 특히 FFMPEG 명령어가 실패할 경우, 이를 예외로 처리하여 오류 메시지를 출력하고 스크립트가 비정상적으로 종료되지 않도록 할 수 있다.

#### 파이썬 예외 처리 예시

```python
import subprocess
import os

input_file = "input.mp4"
output_file = "output.mkv"
codec = "libx264"

try:
    subprocess.run(["ffmpeg", "-i", input_file, "-c:v", codec, output_file], check=True)
    print(f"변환 성공: {output_file}")
except subprocess.CalledProcessError as e:
    print(f"FFMPEG 변환 실패: {e}")
```

이 예시에서 `subprocess.run` 함수는 `check=True` 옵션을 사용하여 명령어가 실패하면 `CalledProcessError` 예외를 발생시킨다. `try-except` 블록을 사용하여 이러한 예외를 처리하고, 오류가 발생했을 때 사용자에게 적절한 메시지를 출력한다.

### 로그 파일 관리

스크립트 작성 시 변환 작업의 진행 상황과 오류 로그를 파일로 저장하면, 이후 문제를 분석할 때 유용하다. FFMPEG은 기본적으로 명령어 실행 중 발생하는 모든 출력과 오류 메시지를 출력하는데, 이를 파일로 저장할 수 있다.

#### 로그 파일 저장 예시

셸 스크립트에서는 표준 출력과 표준 오류 출력을 각각 다른 파일에 저장할 수 있다.

```bash
#!/bin/bash
input_file="input.mp4"
output_file="output.mkv"
log_file="output.log"
error_log_file="error.log"

ffmpeg -i "$input_file" -c:v libx264 "$output_file" > "$log_file" 2> "$error_log_file"
```

이 스크립트는 FFMPEG 명령어 실행 결과를 `output.log` 파일에 저장하고, 오류는 `error.log` 파일에 저장한다. 이렇게 하면, 스크립트를 실행한 후 로그 파일을 통해 변환 과정에서 발생한 문제를 쉽게 확인할 수 있다.

### 병렬 처리

FFMPEG 작업이 대량의 파일을 처리하거나 고화질 영상을 인코딩할 경우, 작업 시간이 길어질 수 있다. 이때 병렬 처리를 통해 작업 시간을 단축할 수 있다. 셸 스크립트와 파이썬 모두에서 병렬 처리를 적용할 수 있다.

#### 셸 스크립트에서의 병렬 처리

리눅스 셸에서는 `&` 기호를 사용하여 백그라운드에서 명령어를 실행할 수 있다. 이를 활용하면 여러 FFMPEG 변환 작업을 병렬로 실행할 수 있다.

```bash
#!/bin/bash
for file in *.mp4; do
    ffmpeg -i "$file" -c:v libx264 "${file%.mp4}.mkv" &
done
wait
```

위 스크립트는 `.mp4` 파일을 병렬로 변환한 후, 모든 작업이 완료될 때까지 `wait` 명령어를 사용하여 대기한다. 이렇게 하면 여러 파일을 동시에 처리할 수 있어 작업 시간이 크게 단축된다.

#### 파이썬에서의 병렬 처리

파이썬에서는 `concurrent.futures` 모듈을 사용하여 병렬 처리를 구현할 수 있다. `ThreadPoolExecutor`나 `ProcessPoolExecutor`를 사용하여 여러 작업을 동시에 실행할 수 있다.

**파이썬 병렬 처리 예시**

```python
import subprocess
import os
from concurrent.futures import ThreadPoolExecutor

input_dir = "/path/to/input/"
output_dir = "/path/to/output/"
codec = "libx264"

def convert_video(filename):
    input_path = os.path.join(input_dir, filename)
    output_filename = filename.replace(".mp4", ".mkv")
    output_path = os.path.join(output_dir, output_filename)
    subprocess.run(["ffmpeg", "-i", input_path, "-c:v", codec, output_path])

with ThreadPoolExecutor() as executor:
    files = [f for f in os.listdir(input_dir) if f.endswith(".mp4")]
    executor.map(convert_video, files)
```

이 파이썬 스크립트는 `ThreadPoolExecutor`를 사용하여 `.mp4` 파일을 병렬로 변환한다. `executor.map`을 사용하여 파일 리스트를 순회하며 변환 작업을 동시에 처리한다.

### 스크립트에서 사용자 입력 받기

스크립트를 작성할 때, 사용자가 입력할 수 있는 옵션을 제공하면 더욱 유연한 스크립트를 만들 수 있다. 사용자는 파일 경로, 출력 형식, 코덱 등의 파라미터를 직접 입력할 수 있으며, 이를 통해 스크립트의 재사용성을 높일 수 있다.

#### 셸 스크립트에서 사용자 입력 받기

셸 스크립트에서는 `read` 명령어를 사용하여 사용자로부터 입력을 받을 수 있다. 이를 통해 FFMPEG의 인코딩 설정이나 출력 파일 형식을 동적으로 설정할 수 있다.

**사용자 입력 처리 예시**

```bash
#!/bin/bash
echo "변환할 파일의 경로를 입력하라:"
read input_file
echo "출력 파일의 경로를 입력하라:"
read output_file
echo "사용할 코덱을 입력하라 (예: libx264, libx265):"
read codec

ffmpeg -i "$input_file" -c:v$codec "$output_file"
```

이 스크립트는 사용자로부터 입력 파일, 출력 파일, 그리고 사용할 코덱을 입력받아 FFMPEG 명령을 실행한다. 이를 통해 스크립트가 다양한 파일 변환 작업에 사용할 수 있도록 유연성을 제공한다.

#### 파이썬에서 사용자 입력 받기

파이썬에서는 `input()` 함수를 사용하여 사용자 입력을 처리할 수 있다. 이를 통해 스크립트 실행 중에 변환할 파일이나 출력 형식 등을 사용자가 입력하도록 할 수 있다.

**파이썬 사용자 입력 예시**

```python
import subprocess

input_file = input("변환할 파일의 경로를 입력하라: ")
output_file = input("출력 파일의 경로를 입력하라: ")
codec = input("사용할 코덱을 입력하라 (예: libx264, libx265): ")

subprocess.run(["ffmpeg", "-i", input_file, "-c:v", codec, output_file])
```

이 파이썬 스크립트는 사용자로부터 입력을 받아 FFMPEG 명령을 동적으로 실행한다. 이를 통해 다양한 파일을 변환하는 작업을 효율적으로 처리할 수 있다.

### 환경 변수 사용

스크립트에서 환경 변수를 활용하면 시스템의 다양한 설정을 스크립트 내에서 손쉽게 사용할 수 있다. 환경 변수는 스크립트 외부에서 설정된 값들을 참조하거나, 스크립트 실행 시 동적으로 설정할 수 있다.

#### 환경 변수 설정 예시 (셸 스크립트)

셸 스크립트에서 환경 변수를 사용하려면 `export` 명령어를 사용하여 변수를 설정할 수 있다.

```bash
#!/bin/bash
export INPUT_DIR="/path/to/input"
export OUTPUT_DIR="/path/to/output"

for file in "$INPUT_DIR"/*.mp4; do
    ffmpeg -i "$file" -c:v libx264 "$OUTPUT_DIR/${file%.mp4}.mkv"
done
```

위 스크립트는 `INPUT_DIR`과 `OUTPUT_DIR` 환경 변수를 사용하여 입력 및 출력 파일의 디렉토리를 설정한다. `export` 명령어를 사용하여 설정된 환경 변수는 스크립트 내에서 사용할 수 있으며, 외부에서도 참조할 수 있다.

#### 환경 변수 설정 예시 (파이썬)

파이썬에서 환경 변수를 사용하는 방법은 `os` 모듈의 `environ`을 사용하여 접근할 수 있다.

```python
import os
import subprocess

input_dir = os.environ.get("INPUT_DIR", "/path/to/input/")
output_dir = os.environ.get("OUTPUT_DIR", "/path/to/output/")
codec = "libx264"

for filename in os.listdir(input_dir):
    if filename.endswith(".mp4"):
        input_path = os.path.join(input_dir, filename)
        output_filename = filename.replace(".mp4", ".mkv")
        output_path = os.path.join(output_dir, output_filename)
        subprocess.run(["ffmpeg", "-i", input_path, "-c:v", codec, output_path])
```

이 파이썬 스크립트는 환경 변수를 사용하여 입력 및 출력 디렉토리를 설정한다. `os.environ.get`을 사용하여 환경 변수 값을 가져오며, 환경 변수가 설정되지 않은 경우 기본 값을 사용할 수 있도록 처리한다.

### 배치 파일에서의 사용자 입력

윈도우 배치 파일에서도 사용자의 입력을 받아 FFMPEG 명령어를 동적으로 실행할 수 있다. `set /p` 명령어를 사용하여 사용자의 입력을 변수에 저장한 후 이를 FFMPEG 명령어에 사용할 수 있다.

**배치 파일 사용자 입력 예시**

```batch
@echo off
set /p input_file="변환할 파일의 경로를 입력하라: "
set /p output_file="출력 파일의 경로를 입력하라: "
set /p codec="사용할 코덱을 입력하라 (예: libx264, libx265): "

ffmpeg -i "%input_file%" -c:v %codec% "%output_file%"
```

이 배치 파일은 사용자로부터 입력을 받아 FFMPEG 명령어를 실행한다. 이를 통해 윈도우 환경에서도 스크립트를 유연하게 작성할 수 있다.

### 작업 자동화와 크론탭 사용

리눅스 환경에서는 `cron`을 사용하여 스크립트를 일정한 시간 간격으로 자동 실행할 수 있다. 이를 통해 FFMPEG 작업을 특정 시간마다 실행하도록 자동화할 수 있다.

#### 크론탭 설정 예시

크론탭(crontab)은 리눅스의 예약 작업 관리 도구이다. FFMPEG 스크립트를 매일 일정한 시간에 실행하도록 설정할 수 있다.

1. 터미널에서 크론탭 편집기를 엽니다.

   ```bash
   crontab -e
   ```
2. 다음과 같은 크론탭 항목을 추가하여 매일 오전 3시에 FFMPEG 스크립트를 실행하도록 설정한다.

   ```bash
   0 3 * * * /path/to/ffmpeg_script.sh
   ```

이 설정은 매일 오전 3시에 `ffmpeg_script.sh` 스크립트를 실행한다. 이를 통해 주기적인 비디오 파일 변환 작업을 자동화할 수 있다.
