mp4ファイルに、チャプタを付加するスクリプト

2024年9月18日 Pythonによる付加するプログラムを追記


・シェルスクリプトによるプログラム

shotcutで動画編集を行っていた時に、shotcutでチャプタの付加を行うことができず(できるのか不明)編集後のファイルにチャプタを付加するためのシェルスクリプトを作成したので、覚書として記録します。
shotcutは素晴らしいですね。動画編集に使用させて頂いています。ありがとうございます。

shotcutでつけたマーカーを、ファイル、書き出し、マーカーとチャプターでテキストファイルに書き出すことができる。
  書き出し例
   00:00 Intro
   00:00:04;17 J1
   00:00:30;10 J2

この情報を利用して、編集後のmp4形式のファイルに、チャプタを挿入すればいいのだが、mp4のメタ情報の時刻表記が異なるため、変換する必要がある。
  mp4ファイルのメタ情報の例
   [CHAPTER]
   TIMEBASE=1/1000
   START=4000
   END=19000
   title=J1

この変換が面倒である。
スクリプトでは、START位置から1チャプタの長さを15秒にしている。長い動画で、頭出しができたら良いのでこのような処理にしている。
なお、mp4ファイルのメタデータの読み込み、書き込みには ffmpeg コマンドを利用している。

利用方法
 どこでもいいので、チャプタを付加する
   ・mp4ファイル
   ・shotcutで書き出したマーカー、チャプターのテキストファイル
   ・下記のシェルスクリプト
 を、同一のフォルダにセットし、端末でディレクトリを移動して実行。
 
 下記の、ファイル名をキーより入力すると処理が開始される
   ・チャプタを付加するファイル名
   ・shotcutで出力したチャプター情報のファイル名

 下記のファイルが、同一ディレクトリに存在すると処理が中断する。
 必要な時は、他へ退避させること。
   ・ffmetadata.ini(処理中に利用するメタ情報のファイル)
   ・out.mp4(チャプタを付加したファイル)

処理内容
 ・mp4ファイルのメタ情報を読み込む
 ・メタ情報にチャプタ情報を追記
 ・mp4ファイルにメタ情報を書き込み

作成した環境
 OS:BookwormPup64_10.0.6

 

#!/bin/bash

#-------------------------------------------------------------
# mp4ファイルにキャプチャを付加する処理 20240721 V1
# キャプチャ情報の構成(テキストファイル)
#      キャプチャを付加する時刻 キャプチャ名
# 
#       例)
#     00:00:04;17 J1   <-- 4秒17のところに J1 という名前のキャプチャをつける
#     00:00:30;10 J2
#
#                                   キャプチャ名は、半角5文字まで有効です
#
# mp4ファイルのメタ情報の読み込み、付加は ffmpeg コマンドを利用しています
# 出力は、カレントディレクトリに out.mp4 という名前のファイルを生成します
# メタ情報のファイル名は ffmetadata.ini としています
# カレントディレクトリに、ffmetadata.ini または out.mp4 が存在する時は終了します。ファイルを退避させてください
#-------------------------------------------------------------


# ディレクトリのファイル一覧を表示
ls
# 標準入力で受け付けて、変数に設定する。
read -p "チャプタを付加する動画ファイル名を入力してください:" mp4file_name
read -p "チャプタ情報のファイル名を入力してください:" chapterFile_name
# 確認
read -p $mp4file_name"に"$chapterFile_name"のチャプターを付加します。よろしいですか(y or n)" ck; case "$ck" in [yY]*) ;; *) exit 0;; esac


# メタ情報ファイル名の設定
inifile=ffmetadata.ini
# ffmetadata.ini の存在確認 ある時のエラー処理
if [ -e $inifile ]; then
  echo $inifile"ファイルが存在します。処理を終了しました"
  exit 0
fi

#  メタデータの読み込み
ffmpeg -i $mp4file_name -f ffmetadata $inifile

# チャプタ情報を読み込んで処理
while read line
do
  # 00:00 Intro 1行目をスキップさせる(未実装)
  # 1行分を変数に代入
  h=$line
  # 変数から部分文字列をとりだして、時分秒を秒に変換
  d=$((${h:0:2}*3600+${h:3:2}*60+${h:6:2}))
  d=$(($d*1000))
  # ファイルを追記
  echo  '[CHAPTER]' >> $inifile   
  echo  'TIMEBASE=1/1000' >> $inifile
  echo  'START='$d >> $inifile
  echo  'END='$(($d+15000)) >> $inifile 
  echo  'title='${h:12:5} >> $inifile
done < $chapterFile_name

# out.mp4 の存在確認 ある時のエラー処理
if [ -e out.mp4 ]; then
  echo "out.mp4ファイルが存在します。処理を終了しました"
  exit 0
fi

# チャプターを追加
ffmpeg -i $mp4file_name -i $inifile -map_metadata 1 -map_chapters 1 -c copy "out.mp4"


・Pythonによるチャプタを付加するプログラム(2024/9/18追記)

前述のシェルスクリプトで、10ヶ所のチャプタを付加させようとしたとき、一部のチャプタ(3ヶ所)しか設定できなかった。ffmetadata.iniファイルの生成で失敗している様であった。代用として、pythonスクリプトで作成したので記録しておきます。シェルスクリプトが失敗する原因は後日とします。
 
 ・スクリプトを実行すると、下記のファイルが生成されます。
   出力ファイル名:out.mp4 
   (同名のファイルは上書きします。必要な時は退避させてください)
   mp4ファイルに書き込んだメタファイル:ffmetadata.ini

 ・mp4ファイル、チャプタ情報のファイルはGUIで選択します。
   tkinter を利用

 ・mp4ファイルのメタ情報の読み込み、書き込み
   ffmpegコマンドを使用

# mp4ファイルにチャプタを付加する 2024/09/18
#   ffmpegコマンドを利用
#   チャプタの位置情報は、shotcutで書き出したマーカーの位置情報
#   出力は out.mp4

import subprocess

import os, tkinter, tkinter.filedialog, tkinter.messagebox

def selectFile(s):
    # ファイル選択ダイアログの表示
    root = tkinter.Tk()
    root.withdraw() # アプリウインド非表示

    if s=='mp4':
        fTyp = [('MP4ファイル','*.mp4 .MP4'),('チャプタ情報ファイル','*.txt .TXT'),('すべてのファイル','*')]
    else:
        fTyp = [('チャプタ情報ファイル','*.txt .TXT'),('MP4ファイル','*.mp4 .MP4'),('すべてのファイル','*')]
    
    iDir=os.path.dirname(os.path.abspath('__file__'))

    tkinter.messagebox.showinfo('ファイルの選択', s+'ファイルを選択してください!')
    file = tkinter.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir)

    return file

# ファイル名のセット
mp4file = selectFile('mp4')            # チャプタを付加するmp4ファイル(付加前のファイル)
chapfile = selectFile('チャプタ情報')    # shotcutで書き出したマーカーの位置情報
inifile = './ffmetadata.ini'           # ffmpegで取り出したmp4ファイルのメタ情報(これにチャプタ情報を追記して書き込む)
outfile = './out.mp4'                  # チャプタを付加したmp4ファイル(出力ファイル)

# mp4ファイルからメタデータを抽出する(File './ffmetadata.ini' already exists. Overwrite? [y/N]--> 'y')
cmd = ['ffmpeg' ,'-i', mp4file,'-f','ffmetadata',inifile]
result = subprocess.run(cmd, input='y',capture_output=True, text=True) #print(result.stdout,result.stderr)

# shotcutで書き出したチャプタファイルの読み込み
with open(chapfile) as f:
    lines = f.readlines()

# チャプタ用ファイルの作成(時刻表示の変換)
chap0 = '[CHAPTER]\nTIMEBASE=1/1000\n'
chap1 = 'START='
chap2 = 'END='
chap3 = 'title='
for l in lines:
    if l[6:11]=='Intro':
        out = chap0+chap1+'0\n'+chap2+'1000\n'+chap3+'start\n'
    else:
       t0 = float(l[0:2])*3600
       t1 = float(l[3:5]) *60
       t2 = float(l[6:8]) 
       t3 = float(l[9:11]) /30
       tt = int((t0+t1+t2+t3)*1000)
       t4 = l[12:].rstrip("\n")
       out = out+chap0+chap1+str(tt)+'\n'+chap2+str(1000+tt)+'\n'+chap3+t4+'\n'

# mp4ファイルのメタデータにチャプタ用データを追記
with open(inifile, mode="a") as f: # w: 新規書き込みモード(上書き) a: 追加書き込みモード
    f.write(out)

# メタデータの書き込み
cmd = ['ffmpeg' ,'-i', mp4file,'-i',inifile,'-map_metadata','1','-map_chapters','1','-c','copy',outfile]
result = subprocess.run(cmd, input='y',capture_output=True, text=True)

この記事が気に入ったらサポートをしてみませんか?