0.記事の編集予定について
この記事の内容を執筆時から長い間研究?していたため、その結果を使ってもう一度書き直します。
公開まで今しばらくお待ちください....
1.動作確認環境
python3(python2での動作は未確認です。 2020/5/21追記)
linux(debian 64bit)
cpu: intel core i7
2.この記事のコード実行に必要なもの
5/20追記:
pip3 install tkmedia
とffmpegとportaudioのインストール(5/30追記)でインストールできるようになりました。
(翌年1月21追記)困ったことに、コードがおかしなことになっていて、pipの方が使えなさそうです。
修復しますので、今しばらくお待ちを...
あと、portaudioは、linuxを除き、sounddeviceにくっついてくるので、win and mac ではインストール要りません。
間違えた情報を投稿してしまい、すみませんでした。
linux(debian(ubuntu))ではlibportaudio0って名前で配布されてます。
sudo apt inatall libportaudio0で入ります。
python モジュール
tkinter(pythonに付属,linuxの場合python3-tkをインストール
imageio
pillow
pydub
sounddevice
numpy
あと、いくつかのpython付属モジュール
(全て"pip3 install [モジュール名]"でインストールできます。)
その他ソフトウェア
ffmpeg
(あと、そこそこの性能のPC(iから始まる会社の鉄腕OOOやセレOOは非推奨)
3.この記事のコードの利用方法
次のようにファイルを配置する。
media
|-__init__.py(空)
|-audio.py
|-video.py
"play_video" があるディレクトリで次を実行:
import media.video
import media.audio
import tkinter
video = video.Video()
audio = audio.Audio()
root = tkinter.Tk()
root.frame = tkinter.Label(root)
root.frame.pack()
video.openfile("[videofile_path]")
audio.openfile("[videofile_path]")
audio.play()
video.play()
root.mainloop()
ライセンスはフリーにしておきます。
編集、再配布、営利目的での使用等どうぞご自由に。(使う人がいるのか知りませんが)
できれば、コメントかメール(marusoftware@outlook.jp)にご一報いただけると幸いです。
あと、使用しているライブラリとソフトウェアのライセンスはよーくご確認ください。
ただし、筆者は一切責任を取りませんのでよろしくおねがいします。
4.音声の再生
pydubとsounddevice(とnumpy)を使う
import sounddevice
import pydub
import time
import numpy
class Audio():
def __init__(self):
pass
def openfile(self, filepath):
if ".mp3" in filepath:
self.segment = pydub.AudioSegment.from_file(filepath,codec="mp3")
elif ".wav" in filepath:
self.segment = pydub.AudioSegment.from_file(filepath,codec="wav")
elif ".mp4" in filepath:
self.segment = pydub.AudioSegment.from_file(filepath)
else:
self.segment = pydub.AudioSegment.from_file(filepath)
def play(self, place=0):
if self.segment.channels != 1:
self.samples = numpy.array(self.segment.get_array_of_samples().tolist(),dtype="int16").reshape(-1,self.segment.channels)
else:
self.samples = numpy.array(self.segment.get_array_of_samples().tolist(),dtype='int16')
sounddevice.play(self.samples,self.segment.frame_rate)
def stop(self):
sounddevice.stop()
5.映像の再生
imageio で読み込んでPILを介してtkinterのフレームに表示する(っていうのをマルチスレッドで行う)。
import tkinter
from tkinter import ttk
import imageio
from PIL import ImageTk, Image
import time
import threading
from imageio.plugins.ffmpeg import FfmpegFormat
class Video():
def __init__(self):
format = FfmpegFormat(
"ffmpeg",
"Many video formats and cameras (via ffmpeg)",
".mov .avi .mpg .mpeg .mp4 .mkv .wmv .webm",
"I",
)
imageio.formats.add_format(format,True)#webm に対応させる。(だいぶ強引に)
def openfile(self, file_path,frame):
self.frame = frame
try:
self.video = imageio.get_reader(file_path)
except imageio.core.fetching.NeedDownloadError:
imageio.plugins.avbin.download()
self.video = imageio.get_reader(file_path)
def play(self):
self.video_thread = threading.Thread(target=self._stream)
self.video_thread.start()
def stop(self):
self.video_thread.stop()
def _stream(self):
start_time=time.time()
sleeptime = 1/self.video.get_meta_data()["fps"]
frame_now = 0
for image in self.video.iter_data():
frame_now = frame_now + 1
if frame_now*sleeptime >= time.time()-start_time:
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
self.frame.config(image=frame_image)
self.frame.image = frame_image
time.sleep(sleeptime)
else:
pass