Pythonを使い、時間を合わせて音楽と動画ファイルを結合するGUIアプリを作ってみました。
アプリの目的
・気軽に撮影した短い動画に簡単に音楽をつけられるようにすること。
・AIなどで作成した音楽ファイルに合わせて、簡単に動画ファイルを結合させること。
※前回作成したスライドショー(GIFアニメ)に音楽をつけたら、時間が合わず、使い物になりませんでした。そこで今回は動画の再生時間に合わせて音楽ファイルを結合させるアプリを作ってみました。作成した後、AI(「Stable Audio」)でオリジナルの音楽を無料で作成できるという記事を読み、逆のパターンを付け加えました。45秒までなら無料で作成できるようです。
アプリの使い方
1.音楽ファイルを選択
MP3などの音楽ファイルを1つ選択します。
2.動画ファイルを選択
MP4などの動画ファイルを1つ選択します。
3.ボタンを押す
ボタンは3つ用意されています。
MP4(優先)ボタン
① MP4動画の再生時間に合わせてMP3の音楽ファイルをカットし、2つのファイルを結合させます。
例:60秒のMP4(音楽なし) + 120秒のMP3 → 60秒のMP4(音楽付き)
MP3(優先)ボタン
② MP3音楽の再生時間に合わせてMP4動画ファイルをカットし、2つのファイルを結合させます。
例: 120秒のMP4(音楽なし) + 45秒のMP3 → 45秒のMP4(音楽付き)
NOMALボタン
③ 時間を合わせないで、そのまま音楽MP3と動画MP4ファイルを結合させます。
例: 120秒のMP4(音楽なし) + 10秒のMP3 → 120秒のMP4(10秒だけ音楽が流れる)
用意するもの
・音楽ファイル・・・MP3など
・動画ファイル・・・MP4など
ライブラリをインストール
Pillowをインストール
pip install pillow
MoviePyをインストール
pip install moviepy
mutagenをインストール
pip install mutagen
OpenCVをインストール
pip install opencv-python
pip install opencv-contrib-python
pydubをインストール
pip install pydub
アプリのコード
アプリのコードを実行することで、GUIアプリが自動で起動します。
・MP4ボタンを押した場合→「out_movie.mp4」として保存されます。
・MP3ボタンを押した場合→「out_music.mp4」として保存されます。
・NOMALボタンを押した場合→「out_nomal.mp4」として保存されます。
※Windowsでexe化した場合は、(「dist」フォルダ内にある)アプリのフォルダ内にファイルが作成されています。
# coding: utf-8
# インポート
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
import os
from PIL import Image
#追加ライブラリインポート
import moviepy.editor as mp
from moviepy.editor import *
from mutagen.mp3 import MP3
import cv2
from pydub import AudioSegment
import moviepy.editor as mp
### 関数 ###
# Browse...MP3
def browse_func():
# グローバル変数の宣言
global fname
typ = [('', '*')]
dir = '/home/'
#複数ファイルを選択する
#fname = filedialog.askopenfilenames(filetypes = typ, initialdir = dir)
#print(fname)
#単数のファイルを選択する
fname = filedialog.askopenfilename(filetypes = typ, initialdir = dir)
# Browse...MP4
def browse_func2():
# グローバル変数の宣言
global fname2
typ = [('', '*')]
dir = '/home/'
#複数ファイルを選択する
#fname = filedialog.askopenfilenames(filetypes = typ, initialdir = dir)
#print(fname)
#単数のファイルを選択する
fname2 = filedialog.askopenfilename(filetypes = typ, initialdir = dir)
# RUN1 NORMAL
def run_func():
global fname
global fname2
try:
#MP4ファイルを読み込む
clip = mp.VideoFileClip(fname2).subclip()
#音楽MP3を付け足して保存
clip.write_videofile('out_nomal.mp4', audio= fname)
except:
# ステータスの更新
statusbar["text"] = " Error!!"
# RUN2 MP3
def run_func2():
global fname
global fname2
try:
audio = MP3(fname) #MP3ファイルのパス
print (audio.info.length)
file_path = fname2 # 編集したいMP4動画のパス
start = 0 # 切り出し開始時刻。秒で表現
end = audio.info.length # 切り出し終了時刻。同じく秒で表現
save_path = "out_music.mp4" # 編集後のファイル保存先のパス
video = VideoFileClip(file_path).subclip(start, end) # ビデオのカット開始
video.write_videofile(save_path,fps=29) # fpsは元の動画に合わせて29に設定
except:
# ステータスの更新
statusbar["text"] = " Error!!"
# RUN3 MP4
def run_func3():
global fname
global fname2
file = fname2
#音楽MP3ファイルのパス
audio_path = fname
#MP4ファイルのパス
image_path = fname2
try:
if __name__ == '__main__':
cap = cv2.VideoCapture(file) # MP4動画を読み込む
video_frame_count = cap.get(cv2.CAP_PROP_FRAME_COUNT) # フレーム数を取得する
video_fps = cap.get(cv2.CAP_PROP_FPS) # フレームレートを取得する
video_len_sec = video_frame_count / video_fps # 長さ(秒)を計算する
#print(video_len_sec) # 長さ(秒)を出力する
time = round(video_len_sec) * 1000
print(time)
# mp3ファイルの読み込み
sound = AudioSegment.from_file(audio_path, format="mp3")
# 5000ms~10000ms(1~10秒)を抽出
sound1 = sound[1000:time]
# 抽出した部分を出力
sound1.export("output1.mp3", format="mp3")
#MP4ファイルを読み込む
clip = mp.VideoFileClip(image_path).subclip()
#音楽ファイルを付け足して保存
clip.write_videofile('out_movie.mp4', audio= "output1.mp3")
except:
# ステータスの更新
statusbar["text"] = " Error!!"
### GUI ###
# ウインドウの作成
root = tk.Tk()
# ステータスバー設置
statusbar = tk.Label(root, text = " Here we go!!",
bd = 1, relief = tk.SUNKEN, anchor = tk.W)
statusbar.pack(side = tk.BOTTOM, fill = tk.X)
# 実行ボタン1
run_button = tk.Button(root, text = "NORMAL", command = run_func)
run_button.pack(pady = 10, ipadx = 20, side = tk.BOTTOM)
# 実行ボタン2
run_button = tk.Button(root, text = "MP3", command = run_func2)
run_button.pack(pady = 10, ipadx = 20, side = tk.BOTTOM)
# 実行ボタン3
run_button = tk.Button(root, text = "MP4", command = run_func3)
run_button.pack(pady = 10, ipadx = 20, side = tk.BOTTOM)
# ラベルフレーム
frame = ttk.Labelframe(root, text = "Select MP3", padding = 10)
frame.pack(padx = 20, pady = 5, side = tk.BOTTOM)
# コンボボックス
extensions = [".mp3", ".mp4", ".avi", ".wma"]
cb = ttk.Combobox(frame, values = extensions)
cb.pack(side = tk.LEFT)
# 参照ボタン
browse_button = tk.Button(frame, text = "Browse...",
command = browse_func)
browse_button.pack(padx = 10, side = tk.LEFT)
# ラベルフレーム2
frame2 = ttk.Labelframe(root, text = "Select MP4", padding = 10)
frame2.pack(padx = 20, pady = 5, side = tk.BOTTOM)
# コンボボックス2
extensions2 = [".mp4", ".avi", ".wma"]
cb2 = ttk.Combobox(frame2, values = extensions2)
cb2.pack(side = tk.LEFT)
# 参照ボタン2
browse_button2 = tk.Button(frame2, text = "Browse...",
command = browse_func2)
browse_button2.pack(padx = 10, side = tk.LEFT)
# ウインドウ状態の維持
root.mainloop()
作成したアプリをexe化する
pyinstallerを使って、アプリをexe化することができます。exe化すると、ボタンをダブルクリックするだけでアプリを起動できるようになります。
pip install pyinstaller
pyinstaller MP3+MP4.py
Linux Ubuntuだと非常に簡単にexe化できます。
Windowsはけっこう難しかったです。詳しい手順は以下の記事にまとめてあります。
Python デスクトップアプリ開発に挑戦してみた! https://zenn.dev/akibaburari/articles/32a89b19fcf889