Audio problems when resizing video - moviepy - python

I am resizing an mp4 video with this code (moviepy):
video_clip = VideoFileClip(url)
resized = video_clip.resize(width=720)
d = tempfile.mkdtemp()
video_path = os.path.join(d, 'output.mp4')
resized.write_videofile(video_path)
The resized clip's audio works when I play it on my pc, but not on an iPhone. (The original clip's audio does work on my iPhone.)
How can I fix this?
First image: Codec of resized video
Second image: Codec of original video

Here is how I got it working:
resized.write_videofile(video_path, temp_audiofile='temp-audio.m4a', remove_temp=True, codec="libx264", audio_codec="aac")

Related

MoviePy Audio doesn't exist on iPhone

I have produced a video using MoviePy and the audio works perfectly fine on PC, but when I try watch it on iPhone it has no audio. I played the uploaded clip on my PC too so it's not the platform where the video is. Also got a friend to listen on iPhone and it also has no audio so not my device. Edit: also tried playing on samsung tablet (android) and it also plays the audio fine.
This is the outputted video files properties:
This is my code:
from moviepy.editor import ImageClip, AudioFileClip, VideoFileClip, CompositeVideoClip
clips = [] # list of clips to be composited
current_duration = 0 # how long the total clip is
bg = VideoFileClip("background.MOV", audio=False) # remove audio from the background
title_audio = AudioFileClip("audio/title.mp3") # title audio
title_clip = ImageClip("screenshots/post.png", duration=title_audio.duration).set_audio(title_audio) # image + audio
clips.append(title_clip.resize(width=bg.w).set_position("center")) # append the resized centred clip
current_duration += title_audio.duration # increase the duration
# loop through clips 1-5 doing the same thing
for comment in range(1, 6):
com_audio = AudioFileClip("audio/voice" + str(comment) + ".mp3")
com_clip = ImageClip("screenshots/comment" + str(comment) + ".png", duration=com_audio.duration).set_audio(com_audio)
clips.append(com_clip.set_start(current_duration).resize(width=bg.w).set_position("center")) # start at current end
current_duration += com_audio.duration
final = CompositeVideoClip([bg.subclip(0, current_duration)] + clips) # composite the clips on top of the background
final.write_videofile("test.mp4", fps=24) # output the file
Based on this, you produced a video file that's (probably) h264/mp3, which isn't a supported format for iPhone - your video file needs to be h264/aac to work on iPhones (and probably any Mac device via Quicktime).
This is also an open issue for moviepy: https://github.com/Zulko/moviepy/issues/1709
You can specify an audio_codec when writing your file to make this work:
final.write_videofile("test.mp4", fps=24, audio_codec='aac') # output the file

JPEG images converted to png - PIL.UnidentifiedImageError: cannot identify image file with

I'm working on a project where I receive a stream of JPEG images over WiFi, convert them to a bytearray, save them as PNG images and read them. The PIL.UnidentifiedImageError occurs when I attempt to open an saved PNG image.
This is how I save the bytearray of JPEG images into PNG images:
idx = random.randint(0,300)
image = Image.open(io.BytesIO(imgdata))
image.save(os.getcwd() + '/Frames/%d.png' % idx)
This is how I open the saved PNG images:
for file in os.listdir('/home/bitcraze/Desktop/AIdeck_examples/NINA/Frames/.'):
print (file)
if file.endswith(".png"):
full_file_path = '/home/Desktop/Frames/' + file
img_file = Image.open(full_file_path)
I checked other posts related to PIL.UnidentifiedImageError and it seems like it could be because the image is corrupted. The picture below shows how I receive the JPEG images:
EDIT: someone suggested I should include how I show the image.
img_loader = GdkPixbuf.PixbufLoader()
img_loader.write(imgdata)
img_loader.close()
pix = img_loader.get_pixbuf()
GLib.idle_add(self._update_image, pix)

Combining mp4 with wav in python

I am trying to combine a .mp4 file with a .wav file. I am rendering my mp4 with cv2 videowriter, and I don't think it has anyway of incorporating audio with it. I have tried moviepy.editor, and ffmpeg. moviepy.editor kept messing up the video file and ffmpeg repeatedly kept giving me an error that it couldn't edit existing files in-place. Combining .mp4 with another audio file type is also fine, but if so it would be nice to also answer how to convert midi files to the file type you answered with. Thanks for the help!
moviepy.editor workflow:
video = mpe.VideoFileClip(mp4_path)
os.system(f"timidity {midi_path} -Ow -o {wav_path)}") # Convert .mid to .wav
video = video.set_audio(mpe.AudioFileClip(wav_path))
video.write_videofile(mp4_path, fps=fps)
ffmpeg workflow:
video = ffmpeg.input(mp4_path)
os.system(f"timidity {midi_path} -Ow -o {wav_path)}") # Convert .mid to .wav
audio = ffmpeg.input(wav_path)
video = ffmpeg.output(video, audio, path, vcodec='copy', acodec='aac', strict='experimental')
ffmpeg.run(video)
I tested both modules and for moviepy I get correct output video with audio even if I use the same name as output. So I don't know what can mess with output.
For ffmpeg I had to use different name for output file to resolve problem with couldn't edit existing files in-place
I had to also use object.video and object.audio to replace audio in output file.
video = ffmpeg.input(video_path).video # get only video channel
audio = ffmpeg.input(audio_path).audio # get only audio channel
My testing code
def test_moviepy(video_path, audio_path, output_path='output-moviepy.mp4', fps=24):
import moviepy.editor as mpe
print('--- moviepy ---')
video = mpe.VideoFileClip(video_path)
video = video.set_audio(mpe.AudioFileClip(audio_path))
video.write_videofile(output_path, fps=fps)
def test_ffmpeg(video_path, audio_path, output_path='output-ffmpeg.mp4', fps=24):
import ffmpeg
print('--- ffmpeg ---')
video = ffmpeg.input(video_path).video # get only video channel
audio = ffmpeg.input(audio_path).audio # get only audio channel
output = ffmpeg.output(video, audio, output_path, vcodec='copy', acodec='aac', strict='experimental')
ffmpeg.run(output)
# --- main ---
video_path = 'movie.mp4'
audio_path = 'sound.wav'
output_path = 'output.mp4'
test_moviepy(video_path, audio_path)#, output_path)
test_ffmpeg(video_path, audio_path)#, output_path)
EDIT:
After installing python module graphviz and program graphviz I could run
ffmpeg.view(output, filename='output-ffmpeg.png')
to get image

Video is much faster than audio moviepy

I am trying to merge audio with video using MoviePy.
Audio has larger duration than video, so I've changed it to the duration of video.
This is my code:
from moviepy.editor import AudioFileClip, VideoFileClip
video = 'youtube.mp4'
audio = 'voice.mp3'
nName = 'youtube2.mp4'
vClip = VideoFileClip(video)
aClip = AudioFileClip(audio)
print(vClip.duration)
print(aClip.duration)
fAudioClip = aClip.subclip(0.000, vClip.duration)
fVideoClip = vClip.set_audio(fAudioClip)
fVideoClip.write_videofile(nName, codec='libx264',audio_codec='aac')
Output-
*424.96
428.92
Moviepy - Building video youtube2.mp4.
MoviePy - Writing audio in youtube2TEMP_MPY_wvf_snd.mp4
MoviePy - Done.
Moviepy - Writing video youtube2.mp4
Moviepy - Done !
Moviepy - video ready youtube2.mp4*
But still, the video runs much faster than audio & gets over quickly. What can I do to fix this?
I think that you should replace :
fAudioClip = aClip.subclip(0.000, vClip.duration)
fVideoClip = vClip.set_audio(fAudioClip)
by this :
fVideoClip = CompositeAudioClip([vClip.audio, aClip])

Finding Video Dimentions of Online Video without Downloading

I want to ensure that an online video at example.com/video.mp4 wasn't filed on a smartphone and will have video dimensions similar to 1920 x 1080.
Its easy to get dimensions with the video downloaded,
import cv2
vcap = cv2.VideoCapture('video.mp4') # 0=camera
width = vcap.get(cv2.cv.CV_CAP_PROP_FRAME_WIDTH)
height = vcap.get(cv2.cv.CV_CAP_PROP_FRAME_HEIGHT)
But I don't want to download the mp4 file PLUS I want to quickly find the file size -- which I can't do if I download the file.
I've managed to get dimensions by downloading 100KB piece of video file:
import cv2
import requests
def get_dimensions(url):
r = requests.get(url, stream=True)
with open('output', 'wb') as f:
for chunk in r.iter_content(chunk_size=100000):
if chunk:
f.write(chunk)
break
vcap = cv2.VideoCapture('output')
return int(vcap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(vcap.get(cv2.CAP_PROP_FRAME_HEIGHT))
I've tested it on several files from internet and here what I've got:
>> get_dimensions('http://file-examples.com/wp-content/uploads/2017/04/file_example_MP4_1920_18MG.mp4')
(1920, 1080)
>> get_dimensions('http://file-examples.com/wp-content/uploads/2018/04/file_example_AVI_640_800kB.avi')
(640, 360)
>> get_dimensions('https://www.sample-videos.com/video123/mkv/720/big_buck_bunny_720p_1mb.mkv')
(1280, 720)

Categories

Resources