2016년 1월 30일 토요일

SMI, SRT 자막 파일 시간 조정 방법 (Excel 이용)

한국에선 SMI를 많이 쓰는데 어쩔 수 없이 SMI 자막 싱크가 맞지 않을 때는?

  1. 보통 곰 플레이어의 싱크 조정 기능 사용한다. 전체적으로 밀고 당기기.
  2. 이게 안 되면 인터넷에서 자막만 따로 검색하는 것이 빠르다. 그래도 없다면?
  3. 동영상을 다시 인코딩할 때 시간 간격을 약간 늘리거나 줄이면 자막을 전체적으로 밀고 당기는 것으론 해결 안 된다. 일정한 비율을 곱해서 늘리고 줄여야 한다. 
  4. 앞부분은 싱크가 맞다가 뒷부분은 일정 간격 밀리는 경우도 있다. 이건 원래 2개의 다른 자막을 하나로 조립한 경우이다.

3과 4번 문제를 Excel로 간단하게 해결하기 위해 시간과 자막을 뽑는 프로그램이다.

  1. Sheet 이름 하나를 “자막”이라고 바꾼다.
  2. 개발 도구 창에서 간단한 폼(버튼 1개, 텍스트상자 1개)을 하나 만든다.
  3. 개발 도구 창에서 모듈을 하나 만들어 코드를 복사해 넣는다.


아래는 "자막 추출 버튼"에 넣는 이벤트 처리 루틴이다.


Private Sub CommandButton1_Click()
    subtitles
    UserForm1.Hide
End Sub


아래는 모듈 창의 서브루틴, 함수이다. "자막 뽑기 실행 버튼"에는 아래 run() 루틴이 연결 되어 있다.


'자막 뽑기 매크로 실행
Public Sub run()
    UserForm1.Show
End Sub

'시분초 문자열을 msec로 바꾸는 함수
Public Function time2msec(a)
    h = Left(a, 2)
    m = Mid(a, 4, 2)
    s = Mid(a, 7, 6) / 1000
    time2msec = 1000 * s + 60000 * m + 3600000 * h
End Function

'msec를 시분초 문자열로 바꾸는 함수
Public Function msec2time(msec)
    msec2time = Int(msec / 3600000) & ":" & Int((msec Mod 3600000) / 60000) & ":" & Int((msec Mod 60000) / 1000) & "," & (msec Mod 1000)
End Function

'자막 처리 서브루틴
Public Sub subtitles()
    '-------------------자막정리=불필요 공백/개행문자 제거 + 소문자화
    buff1 = UserForm1.TextBox1.Text
    buff2 = ""
    Length = Len(buff1)
    For i = 1 To Length
        c = Mid(buff1, i, 1)
        Select Case c
        Case Chr(10), Chr(13) 'FF, CR 문자면 무시하라
        Case " " '공백이라면
            Select Case Right(buff2, 1)
            Case " ", "<", "=" '그 이전 문자가 공백, <, = 라면 무시
            Case Else
                If i < Length Then
                    Select Case Mid(buff1, i + 1, 1)
                    Case ">", "=", " "  '그 다음 문자가 공백, >, = 라면 무시
                    Case Else
                        buff2 = buff2 + c
                    End Select
                End If
            End Select
        Case Else
            buff2 = buff2 + c
        End Select
    Next i
    buff1 = LCase(buff2)  '소문자화
    UserForm1.TextBox1.Text = buff1
    '-------------------시간 자막 분리 추출
    r = 1
    counter = 0
    finish = False
    X = 1
    Do
        counter = counter + 1
        X = InStr(X, buff1, "<sync start=", vbTextCompare)
        If X = 0 Then
            finish = True
        Else
            X = X + Len("<sync start=")
            Y = InStr(X, buff1, ">", vbTextCompare)
            If Y > X Then
                msec_buff = Mid(buff1, X, Y - X)
                Worksheets("자막").Cells(r, 2).Value = "<sync start="
                Worksheets("자막").Cells(r, 3).Value = msec_buff
                msec = Val(msec_buff)
                Worksheets("자막").Cells(r, 1).Value = msec2time(msec)
                X = Y + 1
                Y = InStr(X, buff1, "<sync start=", vbTextCompare)
                If Y > X Then
                    Worksheets("자막").Cells(r, 4).Value = ">" & Mid(buff2, X, Y - X)
                    r = r + 1
                    X = Y
                Else
                    Y = InStr(X, buff1, "</body", vbTextCompare)
                    If Y > X Then
                        Worksheets("자막").Cells(r, 4).Value = ">" & Mid(buff2, X, Y - X)
                    Else
                        Y = InStr(X, buff1, "</sami", vbTextCompare)
                        If Y > X Then
                            Worksheets("자막").Cells(r, 4).Value = ">" & Mid(buff2, X, Y - X)
                        Else
                            Worksheets("자막").Cells(r, 4).Value = ">" & Mid(buff2, X, Len(buff2))
                        End If
                    End If
                    finish = True
                End If
            Else
                finish = True
            End If
        End If
    Loop Until counter1 > 10000 Or finish
End Sub



SMI 자막 파일 구조 이해


간단하다. 이 프로그램에선 <~> 괄호를 인식하기 때문에 이런 것들 중에 중요한 것만 본다.

<SAMI>
<HEAD>
<Title>영화 제목</Title>
<Style TYPE="text/css">스타일 정의</Style>
<!-- 주석 처리 -->
</HEAD>
<BODY>
<SYNC Start=밀리초><P Class=KRCC> 자막 출현
<SYNC Start=밀리초><P Class=KRCC>&nbsp;
<!-- 위의 내용 반복 -->
</BODY>
</SAMI>

전체는 이 괄호로 둘러싼다.
<SAMI>~</SAMI>

대가리 부분이다.
<HEAD><Title></Title><Style TYPE="text/css"></Style><!-- --></HEAD>

몸통 부분이다.
<BODY><SYNC Start=밀리초><P Class=KRCC>내용</BODY>

이건 HTML, XML 문법과 비슷하지만 정확하게 같지 않다. 이상하게 <SYNC>와 <P>는 열기만 하고 닫지 않는다. </SYNC>나 </P>가 없다. 자막 속에 포함된 Tag는 HTML과 같은 동작을 한다. 고로 자막을 꾸미고 싶다면 HTML과 CSS를 참고하라. 자막을 없앨 때는 공백 문자(&nbsp;)를 출력한다. 이거 없으면 다음 자막이 나타날 때까지 이전 자막이 계속 보인다.

OK! 이제 자막 파일에서 <Body> ~ </Body> 안의 시간과 자막 쌍만 뽑는 것이 필요하다. <SYNC>는 싱크(타이밍)를 맞추는 것이다. <P>는 문단이란 의미인데 자막을 언어별로 구분한다. Class=KRCC는 한국어 자막이란 얘기다. 고로 이 <SYNC> Tag만 인식하면 된다.

실행 결과는 아래와 같이 나와야 한다.



여기서 C 열의 시간만 조절해 준 후에 B + C + D의 내용을 조립 복사하여 자막 파일 <body> Tag 사이에 다시 삽입해 넣으면 된다.


참고 : SRT 자막 파일 구조 이해


개인적으로는 SMI 파일보다는 SRT 파일이 더 깔끔해서 좋다. SMI 파일은 기계 친화적이라면 SRT는 인간 친화적이다. 시간 표현이 시분초 형식이고, SMI처럼 예쁘게 치장도 할 수 있다. SMI에 비해서 가독성도 좋고, 오류 파악도 쉽고, 컴퓨터로 처리하기도 좋다. 자막 확장자는 *.srt이고 자막 언어는 파일 이름에 *.eng.srt *.kor.srt 형태로 붙인다.

  1. 순서 번호 (가독성에 도움)
  2. 출력시작시간 --> 출력종료시간 (시분초 형식, 오류 파악이 쉽다)
  3. 표시할 자막, HTML Tag도 통하고 보이는 그대로 출력 (편집이 편하다)
  4. 빈 줄로 마무리 (아주 중요하다)

이 형태의 반복인데 순서 번호, 표시 시간, 마지막 빈 줄이 중요한 형식이다. SRT는 진짜 자막 순서와 표시 시간 순서가 맞지 않으면 오류가 있는 것임을 쉽게 찾을 수 있다. SMI는 진짜 자막 순서가 나오지 않아서 오직 시간 순서에 의지해서 순서를 정해야 해서 뒤죽박죽이 될 수 있다.


1
00:00:35,468 --> 00:00:39,802
<font color=red>Presented by iPICTURES</font>

2
00:00:51,684 --> 00:00:56,986
<i>A Chungeorahm Film production</i>

3
00:00:58,391 --> 00:01:01,417
The characters & events featured
in this story are fictitious


순서 1에선 HTML Tag로 색을 넣은 것이고, 순서 2에선 HTML Tag로 글꼴을 이탤릭으로 변형한 것이고, 순서 3에선 쉽게 엔터만 치면 다음 줄로 넘어가는 걸 보인 것이다. 귀찮게 <BR>을 넣을 필요가 없다.



SMI 파일 시간 계산 & 조정


이제 남은 것은 시간 조정이다. 자막이 너무 짧게 나오는 경우가 있다. 상당히 긴 문장이 잠깐 보이다가 사라지는 경우이다. 이 경우 다음 방법으로 처리한다.


  1. 시간 순서로 정렬한다. 자막 파일의 순서가 뒤죽박죽일 수도 있다.
  2. 공백 문자의 시간을 늘린다. 공백 문자의 출력을 늦춘다는 말이다.
  3. 공백 자막 없으면 다음 자막이 나오면서 덮어 버린다.
  4. 표시 시간이 짧은 2개 자막을 1개로 합친다.


이런 시간 조정은 VB Macro 말고 Excel 계산 기능으로 쉽게 해결 가능하다. 주의할 점은 시간 순서로 정렬을 먼저 해야 한다. 시간 순서로 자막이 나열되어 있지 않을 수도 있다. 특정 부분만 시간 조정을 해야 할 경우는 동영상 재생 시간을 보고 계산해야 한다. 동영상 재생기의 시간은 “시:분:초”로 표시된다. 이걸 msec로 바꾸는 작업이 필요하다. 시분초를 msec로 바꾸는 공식은 다음과 같다. 매크로 함수에 이미 넣어 놓았다.

※ 문자열 형식 : 시:분:초,밀리초 = 00:00:00,000

  • msec = 1000 * (초 + 60*(분 + 60*시)) 
  • msec = 1000*초 + 60000*분 + 3600000*시

반대 공식은 다음과 같다. 역시 매크로 함수에 이미 넣어 놓았다. 그냥 사용하면 된다.

  • 시 = int(msec / 3600000)
  • 분 = int(mod(msec, 3600000)/60000)
  • 초 = int(mod(msec, 60000)/1000)
  • 밀리초 = mod(msec, 1000)

※ int(~)는 소수점 아래를 버려 정수 부분만 취하는 함수다. 예) 123.456 → 123
※ mod(~)는 나누기에서 나머지를 구하는 함수다. 예) mod(5,2) → 2*2+1 → 1


아래는 대화 길이에 따라 시간 간격을 정하는 기준이다. 대사를 읽는 시간은 대사를 말하는 시간보다 10배나 빠를 수 있으나 동영상을 감상하면서 대사를 읽는 2중 작업 때문에 시간 여유를 많이 주어야 한다. 거의 대사가 시작하기 바로 전에 표시되어 대사가 끝난 후에도 잠시 남아 있어야 한다.

  • 1초 : Yes, No, 예, 아니요 등 한 단어
  • 3초 : 1줄 정도 내용, 6초 : 2줄 정도 내용, 9초 : 3줄 정도 내용
  • 대화가 아닌 설명인 경우는 공간 절약을 위해 한 줄에 이어 붙인다.


아래는 실제 동영상과 자막의 시작과 끝을 맞추는 공식이다. 단순히 시간이 빠르거나 느리면 문제는 간단한데 점점 느려지거나 빨라지는 경우는 비율을 조절해야 한다.

  • 원본 자막 시간 A = As ~ Ae, s = 시작, e = 끝
  • 목표 자막 시간 B = Bs ~ Be, s = 시작, e = 끝
  • 보정 비율 R = (Be - Bs)/(Ae - As)
  • A to B 변환 공식 B = (A - As)*R + Bs

추출한 자막에서 조절할 영역의 시작과 끝 부분을 표시하고 그 구간의 보정 비율을 계산한 후에 Excel Sheet에 간단한 수식을 입력하여 계산하면 된다.




언론과 교육이 여러분들 눈과 귀를 속이니 정치, 경제, 역사, 종교에 관한 얘기는 그대로 믿지 말고 스스로 공부하고 찾아보라. 그리고 잠지 조심하라. 국세충이 감시한다. 나중에 그대 좆에 좆쇄 찰 수도 있다. 그들은 우릴 보지만, 우린 그들을 볼 수 없다. 복수 하고 싶다면 반대편에 투표해라. 후보자 중에 1명만 뽑아야 하는 경우 1등 먹을 가능성 없는 3등 이하 말고 2등에게 말이다. 3등 이하에 투표하는 것은 표를 쓰레기통에 버리는 짓이다. 단, 정당 투표는 마음대로 해도 된다. 비례대표제/정당명부제일 경우이다. 3, 4등도 살려 두면 나중에 2등 잡을 때 쓸 수 있다.

댓글 없음:

댓글 쓰기