Converting mp4 files without frames into mp3 using python / moviepy - python

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.

Related

Downloading a YouTube clip at 1080p from a list of links

Problem Statement: Downloading a certain clip of a YouTube video at 1080p from a list of YouTube links
So I tried the PyTube library but it doesn't seem to support downloading a certain segment of the video.
There has been a question about the same, and the answer to that supports post-processing in the video to clip it out, but I want to download only that specific clip and not the entire video. Although I am looking for an option that supports downloading multiple videos from a set of links.
Below is the code I used for the same.
import time
import pytube
import os
from pytube import YouTube
YouTubeIDs = ['QC8iQqtG0hg']
StartSeg = [2]
EndSeg = [3]
for i in range(len(YouTubeIDs)):
print(f'Downloading Video {i} with ID {YouTubeIDs[i]}')
ID = YouTubeIDs[i]
StartSegment = StartSeg[i]
EndSegment = EndSeg[i]
YTLink = f'https://www.youtube.com/embed/{ID}?start={StartSegment}&end={EndSegment}'
print(f'Link to the YouTube Video - {YTLink}')
time.sleep(2)
yt = YouTube(YTLink)
yt.streams.filter(res="720p").first().download()
os.rename(yt.streams.filter(res="720p").first().download(), f'YouTube_{i}.mp4')
print(f'Finished Downloading Video {i}, renamed as YouTube_{i}.mp4')
Another approach was tried using youtube-dl, but it didn't work because the downloaded video was of 0 KBs. I also tried in a python environment even after the os import, but it gave the same error and I'd very much prefer a Python implementation and not use the bash script unless very necessary.
%%bash
ffmpeg $(youtube-dl -g 'https://www.youtube.com/watch?v=NnW5EjwtE2U' | sed "s/.*/-ss 10 -i &/") -t 60 -c copy test3.mp4
Sidenote: The idea is to be able to download a specific segment (of about 5-6 seconds) of YouTube video from a CSV file of approximately 2.6 million links. The CSV file contains columns like ['YouTube ID', 'start segment', 'end segment']
Would be grateful to get help in the same.
Please let me know if I need to clarify it more.
Thanks.
I have something different for you but i think it will help you!
pip install pytube
from pytube import YouTube
yt = YouTube("https://www.youtube.com/watch?v=n06H7OcPd-g")
yt = yt.get('mp4', '720p')
yt.download('/path/to/download/directory')
This my version of using youtube-dl not sure if it will work in your context and it is done without the use of a batch script.
def get_youtube_video(url):
ydl_opts = {'cachedir': False}
with youtube_dl.YoutubeDL(ydl_opts) as ydl:
ydl.download([url])

Video editing with python : adding a background music to a video with sound

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")

Making video from clips on moviepy only showing last image

I'm trying to make a video from a list of images using moviepy. I have issues using moviepy.editor since it does not like being frozen using PyInstaller, so I'm using moviepy.video.VideoClip.ImageClip for the images and moviepy.video.compositing.CompositeVideoClip.CompositeVideoClip for the clip. I have a list of .jpg images in a list called images:
from moviepy.video.VideoClip import ImageClip
from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
clips = [ImageClip(m).set_duration(1) for m in images]
concat_clip = CompositeVideoClip(clips))
concat_clip.write_videofile('VIDEO.mp4', fps=1)
It successfully makes an .mp4 but the video is only one second long and the last image in the list of images. I can check clips and it has the ~30 images that should be in the video. I can do this from using methods from moviepy.editor following this SO question and answer, but there doesn't seem to be an analogous parameter in CompositeVideoClip for method='compose' which is where I think the issue is.
using concatenate_videoclips might help. I use the code below and it works just fine.
clips = [ImageClip(m).set_duration(1/25)
for m in file_list_sorted]
concat_clip = concatenate_videoclips(clips, method="compose")
concat_clip.write_videofile("test.mp4", fps=25)

Mixing audio files in MoviePy

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

No audio when adding Mp3 to VideoFileClip MoviePy

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")

Categories

Resources