I'm trying to add an mp3 audio file to a video clip that I'm creating out of images with MoviePy. When the script runs it creates the mp4 file and plays successfully, however there's no audio. I'm not really sure why and can't seem to find a ton of documentation around this in general. MoviePy is pretty new to me so any help would be appreciated - thank-you!
def make_video(images):
image_clips = []
for img in images:
if not os.path.exists(img):
raise FileNotFoundError(img)
ic = ImageClip(img).set_duration(3)
image_clips.append(ic)
video = concatenate(image_clips, method="compose")
video.set_audio(AudioFileClip("audio.mp3"))
video.write_videofile("mp4_with_audio.mp4", fps=60, codec="mpeg4")
This worked for me:
clip.write_videofile(out_path,
codec='libx264',
audio_codec='aac',
temp_audiofile='temp-audio.m4a',
remove_temp=True
)
Found it here: https://github.com/Zulko/moviepy/issues/51
Admittedly, this question is old but comes high in search results for the problem. I had the same issue and think the solution can be clarified.
The line:
video.set_audio(AudioFileClip("audio.mp3"))
actually does not change the audio track of the "video" object, but returns a copy of the object with the new AudioFileClip attached to it.
That means that the method:
video.write_videofile("mp4_with_audio.mp4", fps=60, codec="mpeg4")
does not write the final file with the new audio track, since the "video" object remains unchanged.
Changing the script as per the below solved the issue for me.
video_with_new_audio = video.set_audio(AudioFileClip("audio.mp3"))
video_with_new_audio.write_videofile("mp4_with_audio.mp4", fps=60, codec="mpeg4")
See also the docs
Check the video mp4_with_audio.mp4 with VLC media player, i also have same issue with quick player.
I run into this problem too. I found a solution, try
video = video.set_audio(AudioFileClip("audio.mp3"))
I was doing something similar and found that moviepy 1.0.1 did not call ffmpeg with the right arguments to combine the video and audio for mp4 video. I solved this through a workaround using ffmpeg directly. It uses the temp audio file and video file from moviepy to create a final file. This is a similar question: Output video has no sound
Since you are working with mp3, you may need to have ffmpeg convert to aac, so this code does that.
This link helped me with ffmpeg:https://superuser.com/questions/277642/how-to-merge-audio-and-video-file-in-ffmpeg
video_with_new_audio = video.set_audio(AudioFileClip("audio.mp3"))
video_with_new_audio.write_videofile("temp_moviepy.mp4", temp_audiofile="tempaudio.m4a",codec="libx264",remove_temp=False,audio_codec='aac')
import subprocess as sp
command = ['ffmpeg',
'-y', #approve output file overwite
'-i', "temp_moviepy.mp4",
'-i', "tempaudio.m4a",
'-c:v', 'copy',
'-c:a', 'aac', #to convert mp3 to aac
'-shortest',
"mp4_with_audio.mp4" ]
with open(ffmpeg_log, 'w') as f:
process = sp.Popen(command, stderr=f)
Use this:
video.write_videofile("output.mp4", fps=30, audio_codec="aac", audio_bitrate="192k")
Related
So what I'm trying to do is convert the mp4 files I get from downloading YouTube videos with pytube to mp3 files using moviepy. However, those mp4 files do not contain any frames which raises KeyError: 'video_fps' in the ffmpeg_reader.
Is it even possible to do that with moviepy or do I need to use a different tool? I guess I could also just download the mp4 files with video but that would waste resources especially for large playlists.
Here is the code I used:
from moviepy.video.io.VideoFileClip import VideoFileClip
import pytube
def downloadPlaylist(url):
playlist = pytube.Playlist(url)
for video in playlist.videos:
filename = video.streams.get_audio_only().download()
clip = VideoFileClip(filename)
clip.audio.write_audiofile(filename[:-4] + ".mp3")
clip.close()
So just changing VideoFileClip(filename) to AudioFileClip(filename) was the solution:
clip = AudioFileClip(filename)
clip.write_audiofile(filename[:-4] + ".mp3")
clip.close()
Refrain from using .get_audio_only()
Try downloading the whole video with .get_by_itag or something similar.
Worked for me after getting the whole video.
I have the following line to convert a .mp4 file to a .gif file using ffmpeg-python:
ffmpeg.input('test.mp4').trim(start=0, duration=3).output('output.gif').run()
It works well, but I wanted to reduce the frame rate. At this link, I could not find a way to do this. Does somebody know how to do it ?
ffmpeg
.input('test.mp4')
.trim(start=0, duration=3)
.filter('fps', fps=25, round='up')
.output('output.mp4')
.run()
I would like to add a background music to a video file (.mp4) in python.
I have looked the web and did some tricks with moviepy for python, but I did not found a single way to add background music to a video file that already contains music. Any ideas how to do that ?
Edit following Anil_M's comment :
Thanks, no I didn't look at this particular thread, althought I knew about ffmpeg but it looks like again, it is a way to merge a video without audio with an audio track.
So now I am going to try to extract audio from the video, merge with another audio file, then merge back with video. Maybe that's not the best way, but at least it is possile as questions about merging 2 audio tracks are answered.
You can do this with moviepy's CompositeAudioClip:
import moviepy.editor as mpe
my_clip = mpe.VideoFileClip('some_clip.mp4')
audio_background = mpe.AudioFileClip('some_background.mp3')
final_audio = mpe.CompositeAudioClip([my_clip.audio, audio_background])
final_clip = my_clip.set_audio(final_audio)
This code works on windows
import moviepy.editor as mp
audio = mp.AudioFileClip("theme.mp3")
video1 = mp.VideoFileClip(video_no_audio)
final = video1.set_audio(audio)
final.write_videofile("output/output.mp4",codec= 'mpeg4' ,audio_codec='libvorbis')
#This code is working Effectively.
import moviepy.editor as mp
audio = mp.AudioFileClip("ck3.mp3")
video1 = mp.VideoFileClip("ck1.mp4")
final = video1.set_audio(audio)
final.write_videofile("output.mp4")
I've been writing a script using MoviePy. So far I've been able to import videos, clip them, add text, replace the audio and write a new file. It's been a great learning experience. My question is this:
The movie that I'm editing has audio attached. I'd like to be able to import an audio track and add it to the movie without replacing the original audio. In other words, I'd like to mix the new audio file with the audio that's attached to the video so both can be heard.
Does anyone know how to do this?
Thanks in advance!
I wrote my own version, but then I found this here:
new_audioclip = CompositeAudioClip([videoclip.audio, audioclip])
videoclip.audio = new_audioclip
So, create a CompositeAudioClip with the audio of the video clip and the new audio clip, then set the old videoclip's audio to the composite audio track.
Full working code:
from moviepy.editor import *
videoclip = VideoFileClip("filename.mp4")
audioclip = AudioFileClip("audioname.mp3")
new_audioclip = CompositeAudioClip([videoclip.audio, audioclip])
videoclip.audio = new_audioclip
videoclip.write_videofile("new_filename.mp4")
If you want to change an individual audioclip's volume, refer to audio.fx.volumex.
Documentation
Source Code
I am using Python's Image module to load JPEGs and modify them. After I have a modified image, I want to load that image in to a video, using more modified images as frames in my video.
I have 3 programs written to do this:
ImEdit (My image editing module that I wrote)
VideoWriter (writes to an mp4 file using FFMPEG) and
VideoMaker (The file I'm using to do everything)
My VideoWriter looks like this...
import subprocess as sp
import os
import Image
FFMPEG_BIN = "ffmpeg"
class VideoWriter():
def __init__(self,xsize=480,ysize=360,FPS=29,
outDir=None,outFile=None):
if outDir is None:
print("No specified output directory. Using default.")
outDir = "./VideoOut"
if outFile is None:
print("No specified output file. Setting temporary.")
outFile = "temp.mp4"
if (outDir and outFile) is True:
if os.path.exists(outDir+outFile):
print("File path",outDir+outFile, "already exists:",
"change output filename or",
"overwriting will occur.")
self.outDir = outDir
self.outFile = outFile
self.xsize,self.ysize,self.FPS = xsize,ysize,FPS
self.buildWriter()
def setOutFile(self,fileName):
self.outFile = filename
def setOutDir(self,dirName):
self.outDir = dirName
def buildWriter(self):
commandWriter = [FFMPEG_BIN,
'-y',
'-f', 'rawvideo',
'-vcodec','mjpeg',
'-s', '480x360',#.format(480,
'-i', '-',
'-an', #No audio
'-r', str(29),
'./{}//{}'.format(self.outDir,self.outFile)]
self.pW = sp.Popen(commandWriter,
stdin = sp.PIPE)
def writeFrame(self,ImEditObj):
stringData = ImEditObj.getIm().tostring()
im = Image.fromstring("RGB",(309,424),stringData)
im.save(self.pW.stdin, "JPEG")
self.pW.stdin.flush()
def finish(self):
self.pW.communicate()
self.pW.stdin.close()
ImEditObj.getIm() returns an instance of a Python Image object
This code works to the extent that I can load one frame in to the video and no matter how many more calls to writeFrame that I do, the video only every ends up being one frame long. I have other code that works as far as making a video out of single frames and that code is nearly identical to this code. I don't know what difference there is though that makes this code not work as intended where the other code does work.
My question is...
How can I modify my VideoWriter class so that I can pass in an instance of an Python's Image object and write that frame to an output file? I also would like to be able to write more than one frame to the video.
I've spent 5 hours or more trying to debug this, having not found anything helpful on the internet, so if I missed any StackOverflow questions that would point me in the right direction, those would be appreciated...
EDIT:
After a bit more debugging, the issue may have been that I was trying to write to a file that already existed, however, this doesn't make much sense with the -y flag in my commandWriter. the -y flag should overwrite any file that already exists. Any thoughts on that?
I suggest that you follow the OpenCV tutorial in writing videos. This is a very common way of writing video files from Python, so you should find many answers on the internet, if you can't get certain things to work.
Note that the VideoWriter will discard (and won't write) any frames that are not in the exact same pixel size that you give it on initialization.