labunix's blog

labunixのラボUnix

mp4の秒数/字幕の行数で、等間隔に字幕を表示するsrtファイルのためのスクリプトを作ってみる。

■mp4の秒数/字幕の行数で、等間隔に字幕を表示するsrtファイルのためのスクリプトを作ってみる。
 エディタで一から書くのは大変。時間の編集する程度ならというときのために。

■無音、画像からも動画は作れるので、以下を参考にtarget.mp4を作ったものとする。

 ■ffmpegで無音、静止画からsrtを埋め込んだ動画を生成する。
 http://labunix.hateblo.jp/entry/20170821/1503254189

 ■動画作成、変換時によく使うffmpegコマンドをまとめてみる。
 http://labunix.hateblo.jp/entry/20171118/1511011436

 ■debian stretch+ffmpegで字幕ファイルsrt/assをなるべく簡単に作成してみる。
 http://labunix.hateblo.jp/entry/20170816/1502892640

■今回のtarget.mp4は約204(0324)のmp4ファイル。

$ ffprobe -hide_banner -show_entries format=duration target.mp4 2>&1 | awk -F = '/duration/{print $2}'
204.821667

$ echo 204 | awk '{printf "00:%02d:%02d.000\n",($1-$1%60)/60,$1%60}'
00:03:24.000

■簡単に以下のような27行のsrtファイルの元となる字幕ファイルを作成。
 一応ランダムに空行が入るように調整。

$ seq 1 27 | awk 'BEGIN{srand('"$RANDOM"')} \
                  {a=substr(rand(),3)%27; \
                   if($0==$a) \
                       {printf "%03d\n\n",$0} \
                   else{printf "%03d\n",$0}}' > source.txt 

■「.」には空白もマッチするので、else文の空行は単に「print "\n"」でも良いのだけど今回は「print $0」を使う。

$ echo " " | awk '{if(/./){print $0"x"}else{print "y"}}'
 x

$ echo "" | awk '{if(/./){print $0"x"}else{print "y"}}'
y

■メインとなる字幕の処理の変数は、連番をcnt、(a-a%60)/60で分、a%60で秒数を得る。
 ただし、はじめは「00:00:00.000」の行があるので、cnt-1としている。
 字幕行の後に空行をつけるために、「print $0"\n";」としている。

print cnt; \
printf "00:%02d:%02d.000 -> 00:%02d:%02d.000\n",(a-a%60)/60,a%60,(b-b%60)/60,b%60; \
print $0"\n";
a=b;b+=num;cnt++

■target.mp4から秒数(整数値)を取り出して、source.txtの空行以外の行数を取得、
 初期値と増分となる$((秒数/行数))の結果は割り切れなくても整数値となる。
 ただしtarget.mp4が0秒だったり、source.txtが空行しか無いとかの面倒は見ない。

$ cat lyric.sh 
#!/bin/bash

MOVIE=target.mp4
SOURCE=source.txt
LYRIC=target.srt

if [ ! -f $MOVIE ];then
  echo "Not Found:$MOVIE" >&2
  exit 1
fi
if [ ! -f $SOURCE ];then
  echo "Not Found:$SOURCE" >&2
  exit 2
fi
if [ -f $LYRIC ];then
  echo "Found:$LYRIC" >&2
  exit 3
fi


# 秒数の取得(整数値)
totaltime=$(ffprobe -hide_banner -show_entries format=duration $MOVIE 2>&1 | \
              awk -F = '/duration/{printf "%d\n",$2}')

# 行数の取得
allline=$(awk '/./{cnt+=1}END{print cnt-1}' $SOURCE)

# 初期値と増分
num=$(($totaltime/$allline))

awk -v num=$num \
     'BEGIN{cnt=1;a=0;b=num} \
           {if($0 ~ /./) \
             {print cnt; \
              printf "00:%02d:%02d.000 --> 00:%02d:%02d.000\n",(a-a%60)/60,a%60,(b-b%60)/60,b%60; \
              print $0"\n"; \
              a=b;b+=num;cnt++} \
      else{print $0}}' $SOURCE > $LYRIC

unset MOVIE SOURCE LYRIC
# 次のタスクとヒントを表示
awk '$0 ~ /^##/' $0

##
## ass ファイルを作るならコメントアウトを外す
##ffmpeg -i target.srt output.ass 2>&1 | awk '!/built with|configuration/'
##
## ffmpeg -i target.mp4 -i target.srt -c copy -c:s mov_text  output_cp.mp4
## test -f target.srt.org || cp target.{srt,srt.org};vlc output_cp.mp4
## ffmpeg -i target.mp4 -vf subtitles=target.srt output.mp4
## ffmpeg -i target.mp4 -vf subtitles=target.srt:force_style='FontSize=20' output.mp4



■実行してみる。

$ ./lyric.sh 
##
## ass ファイルを作るならコメントアウトを外す
##ffmpeg -i target.srt output.ass 2>&1 | awk '!/built with|configuration/'
##
## ffmpeg -i target.mp4 -i target.srt -c copy -c:s mov_text  output_cp.mp4
## test -f target.srt.org || cp target.{srt,srt.org};vlc output_cp.mp4
## ffmpeg -i target.mp4 -vf subtitles=target.srt output.mp4
## ffmpeg -i target.mp4 -vf subtitles=target.srt:force_style='FontSize=20' output.mp4source.txtは以下。

$ cat source.txt 
001
002
003
004
005
006
007

008
009
010
011
012
013
014
015
016
017
018
019

020
021
022
023
024
025
026
027

■target.srtはsource.txtの空行はそのままに、等間隔時間で進む字幕ファイルができる。
 最後15秒は字幕無しだけど、この後エディタで編集する想定なので気にしない。

$ cat target.srt 
1
00:00:00.000 --> 00:00:07.000
001

2
00:00:07.000 --> 00:00:14.000
002

3
00:00:14.000 --> 00:00:21.000
003

4
00:00:21.000 --> 00:00:28.000
004

5
00:00:28.000 --> 00:00:35.000
005

6
00:00:35.000 --> 00:00:42.000
006

7
00:00:42.000 --> 00:00:49.000
007


8
00:00:49.000 --> 00:00:56.000
008

9
00:00:56.000 --> 00:01:03.000
009

10
00:01:03.000 --> 00:01:10.000
010

11
00:01:10.000 --> 00:01:17.000
011

12
00:01:17.000 --> 00:01:24.000
012

13
00:01:24.000 --> 00:01:31.000
013

14
00:01:31.000 --> 00:01:38.000
014

15
00:01:38.000 --> 00:01:45.000
015

16
00:01:45.000 --> 00:01:52.000
016

17
00:01:52.000 --> 00:01:59.000
017

18
00:01:59.000 --> 00:02:06.000
018

19
00:02:06.000 --> 00:02:13.000
019


20
00:02:13.000 --> 00:02:20.000
020

21
00:02:20.000 --> 00:02:27.000
021

22
00:02:27.000 --> 00:02:34.000
022

23
00:02:34.000 --> 00:02:41.000
023

24
00:02:41.000 --> 00:02:48.000
024

25
00:02:48.000 --> 00:02:55.000
025

26
00:02:55.000 --> 00:03:02.000
026

27
00:03:02.000 --> 00:03:09.000
027