我的python3.10.14,moviepy 1.0.3
代码为:
from moviepy.editor import VideoFileClip, AudioFileClip
import numpy as np
import os
def read_audio(
dir_name: str,
file_name: str = "movie.mp4"
) -> np.ndarray:
"""Read the audio from behavioral video"""
f_dir = os.path.join(dir_name, file_name)
# Read audio from video
with VideoFileClip(f_dir) as video:
audio = video.audio
# 也可以直接 video = VideoFileClip(f_dir)
# audio = video.audio
# Convert to array
audio_array = audio.to_soundarray(fps = audio.fps)
print(type(audio_array))
# Get time from duration and convert it to milisecond
audio_time = np.linspace(0, audio.duration, audio_array.shape[0]) * 1000
return np.vstack((audio_array, audio_time)).T
if __name__ == "__main__":
dir_name = r"E:\HelloWorld"
audio = read_audio(dir_name)
报错信息:
File "c:\ProgramData\anaconda3\envs\replaypy\Lib\site-packages\replay\preprocess\frequency.py", line 27, in <module>
audio = read_audio(dir_name)
File "c:\ProgramData\anaconda3\envs\replaypy\Lib\site-packages\replay\preprocess\frequency.py", line 17, in read_audio
audio_array = audio.to_soundarray(fps = audio.fps)
File "<decorator-gen-44>", line 2, in to_soundarray
File "C:\ProgramData\anaconda3\envs\replaypy\lib\site-packages\moviepy\decorators.py", line 54, in requires_duration
return f(clip, *a, **k)
File "C:\ProgramData\anaconda3\envs\replaypy\lib\site-packages\moviepy\audio\AudioClip.py", line 113, in to_soundarray
return stacker(self.iter_chunks(fps=fps, quantize=quantize,
File "C:\ProgramData\anaconda3\envs\replaypy\lib\site-packages\numpy\core\shape_base.py", line 216, in _vhstack_dispatcher
return _arrays_for_stack_dispatcher(tup)
File "C:\ProgramData\anaconda3\envs\replaypy\lib\site-packages\numpy\core\shape_base.py", line 209, in _arrays_for_stack_dispatcher
raise TypeError('arrays to stack must be passed as a "sequence" type '
TypeError: arrays to stack must be passed as a "sequence" type such as list or tuple.
观察了下问题出在to_soundarray函数内的这一部分:
class AudioClip(Clip):
...
@requires_duration
def to_soundarray(self, tt=None, fps=None, quantize=False, nbytes=2, buffersize=50000):
...
stacker = np.vstack if self.nchannels == 2 else np.hstack
max_duration = 1.0 * buffersize / fps
if tt is None:
if self.duration > max_duration:
return stacker(self.iter_chunks(fps=fps, quantize=quantize,
nbytes=2, chunksize=buffersize))
else:
tt = np.arange(0, self.duration, 1.0/fps)
...
其中stacker,如果声道数为2(立体声),则用numpy的vstack函数,其他的则为hstack
而新的numpy环境已经不支持iter_chunks直接作为输入参数,因此报错。
据说更改python版本至3.8可以解决这一问题,也可以将moviepy更换为2.0.0dev0版本,参考:https://github.com/Zulko/moviepy/issues/1338
我觉得最直接的方式 参考Github issue: https://github.com/Zulko/moviepy/pull/1443和https://github.com/Zulko/moviepy/pull/1443/commits/49536feea593c031e584975c010337d804eec560
显式的将self.iter_chunks转化为tuple数据类型。问题解决。