평범한 SRT 자막은 이제 그만! Python으로 영상 퀄리티를 높이는 ASS 자동 변환 비법

2026. 1. 14.

 

영상 콘텐츠의 몰입감을 결정하는 중요한 요소 중 하나는 바로 '자막'입니다. 많은 분들이 간단한 SRT(SubRip Text) 파일로 자막 작업을 시작하지만, 밋밋한 텍스트만으로는 영상의 매력을 100% 끌어올리기 어렵습니다.

 

오늘은 자막 포맷의 끝판왕이라 불리는 ASS(Advanced SubStation Alpha) 포맷을 활용하여, 여러분의 기본 SRT 자막을 전문가 수준의 동적 자막으로 자동 변환하는 비법을 A부터 Z까지 자세히 알려드리고자 합니다.

 

부드러운 페이드 효과는 물론, 화면을 닦아내듯 나타나고 사라지는 와이프(Wipe) 효과, 그리고 이 모든 것을 자동화하는 Python 코드까지 모두 담았으니 끝까지 함께해주세요!


1. 기본의 미학: 완벽한 자막 타이밍의 비밀 (ms 단위)

모든 효과의 시작은 정확한 타이밍입니다. 자막이 오디오보다 너무 빠르거나 느리면 시청자는 큰 불편함을 느낍니다.

작동 원리

  • 자막이 음성보다 빠를 때 (Negative Delay): 시청자는 내용을 듣기 전에 읽게 되어 스포일러처럼 느끼고 몰입감이 깨집니다. 인간은 약 22ms의 미세한 차이도 감지할 수 있으므로, 가급적 음성보다 자막이 먼저 나오지 않도록 해야 합니다.
  • 자막이 음성보다 느릴 때 (Positive Delay): 음성이 끝난 후 자막이 잠시 남아있는 것은 시청자가 내용을 소화할 시간을 주어 긍정적인 경험을 제공합니다.

최적의 적용 예시

  • 시작 시간: 음성 시작과 거의 동시에 (0ms) 표시되도록 설정합니다.
  • 종료 시간: 음성이 끝난 후, 최소 300ms에서 500ms 정도 더 화면에 머물도록 설정합니다. 이렇게 하면 시청자가 편안하게 자막을 읽고 다음 내용으로 넘어갈 수 있습니다.

2. 부드러움의 시작: 페이드인 & 페이드아웃 (\fad)

자막이 갑자기 툭 나타나고 사라지는 것보다, 부드럽게 나타나고 사라지는 것만으로도 영상은 훨씬 세련되어 보입니다.

작동 원리

ASS 자막에서는 {\fad(t1, t2)} 태그를 사용합니다.

  • t1: 페이드인에 걸리는 시간 (밀리초, ms)
  • t2: 페이드아웃에 걸리는 시간 (밀리초, ms)

⚠️ 여기서 가장 중요한 함정이 있습니다!
페이드아웃(t2)은 자막의 '종료 시간'을 기준으로 역산하여 시작됩니다.

잘못된 적용 예시

  • 음성 종료: 00:00:10.000
  • 자막 설정: 종료 시간을 00:00:10.000으로 맞추고, {\fad(200, 500)} 적용
  • 결과: 자막은 10초에 완전히 사라져야 하므로, 그보다 0.5초 전인 9.5초부터 흐려지기 시작합니다. 음성이 아직 끝나지 않았는데 자막이 사라지는 느낌을 주게 됩니다.

올바른 적용 예시

  • 목표: 음성이 10초에 끝난 후, 0.5초 동안 부드럽게 사라지게 하고 싶다.
  • 올바른 설정:
    1. 자막의 종료 시간을 00:00:10.500으로 설정 (원래 종료 시간 + 페이드아웃 시간)
    2. {\fad(200, 500)} 태그 적용
  • 결과: 자막은 10.5초에 사라지도록 설정되었으므로, 페이드아웃은 10.0초에 시작됩니다. 즉, 음성이 끝나는 시점과 정확히 동일한 시점부터 사라지기 시작하여 우리가 의도한 완벽한 효과를 구현할 수 있습니다.

3. 동적 효과의 완성: 와이프 인/아웃 (\clip)과 조합

글자 단위 효과는 매우 복잡하므로, 자막 줄 전체에 적용하는 동적 효과를 사용하는 것이 훨씬 효율적이고 강력합니다.

작동 원리: 와이프 효과 (\clip)

\clip 태그는 자막이 보여지는 영역을 사각형으로 제한하는 '마스크'를 만드는 기능입니다. 이 사각형의 크기와 위치를 애니메이션 태그 \t로 조절하면 자막이 '쓱' 나타나거나 사라지는 효과(와이프 효과)를 만들 수 있습니다.

적용 예시: 와이프 인/아웃 + 페이드인/아웃 조합

모든 효과를 함께 사용하면 시각적으로 매우 부드럽고 전문적인 느낌을 줄 수 있습니다. 페이드는 투명도를, 클립은 영역을 제어하므로 서로 충돌하지 않고 아름다운 조화를 이룹니다.

  • 와이프-인 (Wipe-in): \clip(0,0,0,H) -> \clip(0,0,W,H) 애니메이션. 가려진 영역을 화면 전체로 넓혀 자막이 나타나게 합니다.
  • 와이프-아웃 (Wipe-out): \clip(0,0,W,H) -> \clip(W,0,W,H) 애니메이션. 보이는 영역의 왼쪽 경계를 오른쪽으로 밀어내 자막이 사라지게 합니다.

4. Python으로 SRT를 전문가용 ASS 자막으로 자동 변환하기

이제 대망의 자동화 시간입니다. 평범한 SRT 파일을 불러와 위에서 설명한 모든 효과를 적용한 뒤, 멋진 ASS 파일로 변환하는 Python 코드를 소개합니다.

준비: 라이브러리 설치

pip install pysubs2

작동 원리

  1. SRT 파일 불러오기: pysubs2.load() 함수는 SRT 형식임을 자동으로 인지하여 데이터를 불러옵니다.
  2. 효과 적용 및 시간 보정: 모든 자막 라인을 순회하며, 페이드아웃을 위해 종료 시간을 늘려주고(line.end += FADE_OUT_MS), 원하는 효과 태그를 생성하여 텍스트에 삽입합니다.
  3. ASS 파일로 저장: subs.save() 함수에 .ass 확장자를 가진 파일명을 넘겨주기만 하면, 라이브러리가 알아서 모든 데이터를 ASS 형식에 맞게 변환하여 저장해 줍니다.

Python 적용 코드 예시

아래 코드는 original_srt 폴더 안의 모든 .srt 파일을 읽어, 페이드인/아웃와이프-인/아웃 효과를 일괄 적용하고, styled_ass 폴더에 결과물을 저장합니다.

import pysubs2
import os

# --- 설정 값 ---
# 원본 SRT 자막 파일이 있는 폴더
INPUT_FOLDER = "original_srt"
# 스타일이 적용된 ASS 자막을 저장할 폴더
OUTPUT_FOLDER = "styled_ass"

# 적용할 효과 시간 (밀리초 단위)
FADE_IN_MS = 300
FADE_OUT_MS = 500
WIPE_IN_MS = 400
WIPE_OUT_MS = 400  # 와이프 아웃 효과 시간 추가

# 화면 해상도 (와이프 효과에 사용)
WIDTH = 1920
HEIGHT = 1080
# --- 설정 끝 ---

def convert_and_style_srt(srt_path, ass_path):
    """하나의 SRT 파일을 불러와 효과를 적용하고 ASS 파일로 저장합니다."""
    try:
        # 1. SRT 파일 불러오기 (인코딩 명시는 안정성을 높여줍니다)
        subs = pysubs2.load(srt_path, encoding="utf-8")

        for line in subs:
            # 2. 와이프-아웃 타이밍 계산을 위해 원래 길이 저장
            original_duration = line.end - line.start

            # 3. 페이드아웃 시간을 보상하기 위해 종료 시간 늘리기
            # 이것이 '음성보다 빨리 사라지는 느낌'을 없애는 핵심입니다.
            line.end += FADE_OUT_MS

            # 4. 기존 텍스트에서 태그 제거
            clean_text = line.plaintext

            # 5. 적용할 효과 태그 문자열 생성
            # 페이드 효과
            fade_tag = f"\\fad({FADE_IN_MS},{FADE_OUT_MS})"

            # 와이프-인 효과 (Clip + Transform)
            wipe_in_tag = (f"\\clip(0,0,0,{HEIGHT})"
                           f"\\t(0, {WIPE_IN_MS}, \\clip(0,0,{WIDTH},{HEIGHT}))")

            # 와이프-아웃 효과 (애니메이션 타이밍 계산)
            # \t 태그 시간은 자막 시작 시간 기준 상대값이므로 원래 길이를 사용
            wipe_out_start_time = original_duration - WIPE_OUT_MS
            if wipe_out_start_time < WIPE_IN_MS: # 와이프 인/아웃이 겹치지 않도록
                wipe_out_start_time = WIPE_IN_MS

            wipe_out_tag = (f"\\t({wipe_out_start_time}, {original_duration}, "
                            f"\\clip({WIDTH},0,{WIDTH},{HEIGHT}))")

            # 6. 태그와 텍스트를 조합하여 라인 업데이트
            line.text = f"{{{fade_tag}{wipe_in_tag}{wipe_out_tag}}}{clean_text}"

        # 7. ASS 포맷으로 저장 (라이브러리가 자동으로 변환)
        subs.save(ass_path)
        print(f"성공: SRT -> ASS 변환 및 스타일 적용 완료! '{srt_path}' -> '{ass_path}'")

    except Exception as e:
        print(f"오류 발생 '{srt_path}': {e}")

if __name__ == "__main__":
    if not os.path.exists(OUTPUT_FOLDER):
        os.makedirs(OUTPUT_FOLDER)
        print(f"'{OUTPUT_FOLDER}' 폴더를 생성했습니다.")

    if not os.path.exists(INPUT_FOLDER):
        os.makedirs(INPUT_FOLDER)
        print(f"'{INPUT_FOLDER}' 폴더를 생성했습니다. 이 폴더에 원본 SRT 파일을 넣어주세요.")

    for filename in os.listdir(INPUT_FOLDER):
        if filename.endswith(".srt"):
            input_filepath = os.path.join(INPUT_FOLDER, filename)

            # 출력 파일명 생성 (예: my_video.srt -> styled_my_video.ass)
            base_name = os.path.splitext(filename)[0]
            output_filename = f"styled_{base_name}.ass"
            output_filepath = os.path.join(OUTPUT_FOLDER, output_filename)

            convert_and_style_srt(input_filepath, output_filepath)

사용 방법:

  1. 위 코드를 convert_style.py 같은 이름으로 저장합니다.
  2. 스크립트와 같은 위치에 original_srt 폴더를 만들고 원본 SRT 자막 파일들을 넣습니다.
  3. 터미널에서 python convert_style.py를 실행합니다.
  4. styled_ass 폴더에 페이드와 와이프 인/아웃 효과가 완벽하게 적용된 새로운 ASS 자막 파일들이 생성됩니다!

마치며

오늘 우리는 간단한 SRT 자막을 전문가 수준의 ASS 자막으로 손쉽게 업그레이드하는 방법을 알아보았습니다. ASS 자막의 강력한 기능과 Python 자동화의 편리함을 결합하면, 누구나 자신의 영상을 전문가 수준으로 꾸밀 수 있습니다.

 

단순한 텍스트의 나열을 넘어, 자막을 영상의 일부로 만드는 이 기법들을 활용하여 시청자의 눈을 사로잡는 멋진 콘텐츠를 만들어보세요

댓글