I am trying to speed up video using python. But the problem is that the duration of the video output is not reduced based on the speed we provide.
If the video is 30 seconds long, the output file is accelerated. But the duration of the video remains the same.
import subprocess
ffmpeg_path = r"ffmpeg\ffmpeg.exe"
speed_factor = 2
ffmpeg_args = [
"-i", "test.mp4",
"-loglevel", "quiet",
"-filter:v", "setpts=0.5/{}*PTS".format(speed_factor),
"speed.mp4"
]
subprocess.run([ffmpeg_path, *ffmpeg_args])
Can anyone help me with this?
For example: If I want speed up video by X2, for 30s duration video should reduced to 15s including audio and so on by itself without specify the timing.
Thanks
Example : I want to speed up the first 4 seconds of my video.
Cut your video
ffmpeg -i input.mp4 -t 4 slow.mp4
ffmpeg -i input.mp4 -ss 00:00:04 part-2.mp4
Speed up the part
ffmpeg -i slow.mp4 -filter:v "setpts=0.5PTS" part-1.mp4
Concatenate
ffmpeg -f concat -i <(for f in ./part-.mp4; do echo "file '$PWD/$f'"; done) -c
Related
I am working with python in a jupyter notebook, and I am trying to use ffmpeg to specify the start and end images and convert several images from a folder into a single video. I have a folder, 'images', with the images inside labeled, 'image0', 'image1', 'image2', etc. I would like to specify the start and end images in my video. For example, I would like to be able to make the video using 'image100', to 'image200'. Right now, I have:
!/home/jovyan/ffmpeg-dir/ffmpeg -i /home/jovyan/images/image%d.bmp -frames:v 1000 /home/jovyan/output.mp4
This is making the video correctly, but I believe it is just taking the first 1000 images.
Thanks!
Use -start_number.
Use the -start_number option to declare a starting number for the sequence. This is useful if your sequence does not start with img001.jpg but is still in a numerical order.
(source: https://ffmpeg.org/faq.html#toc-How-do-I-encode-single-pictures-into-movies_003f)
For example, I would like to be able to make the video using 'image100', to 'image200'.
You need to combine -start_number 100 and -frames:v 101 (101 frames from image100.jpg to image200.jpg).
You can try this:
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 cut.mp4
OR
ffmpeg -i movie.mp4 -ss 00:00:03 -t 00:00:08 -async 1 -c copy cut.mp4
The -t option specifies a duration, not an end time. The above command will encode 8s of video starting at 3s. To start at 3s and end at 8s use -t 5. If you are using a current version of ffmpeg you can also replace -t with -to in the above command to end at the specified time.
I have 2 separate webm files - video and audio part. Now I want to merge it. I use python and ffmpeg
input_video = ffmpeg.input(f'{title}-video.webm').output("out1.webm")
input_audio = ffmpeg.input(f'{title}-audio.webm').output("out2.webm")
ffmpeg.merge_outputs(input_video, input_audio).run()
Output file looks OK (it plays audio and video) but it takes time to merge it. I guess there's a needless conversion that I could avoid. Is it possible to do with the given API?
I googled a command
ffmpeg -i 12m.mp4 -i 6m.mp4 -c copy -map 1:v -map 0:a -shortest new.mp4
that should be run via command line, but I'd like to implement it by means of the API if it is possible.
Say I have a 30s video. I want to produce a 40s video that is just the first video but with an extra "freezed" frame (for say 10s) somewhere in the middle of it. (think of it as wanting to comment the video at a specific point)
I know I can do this easily with video editing software. However, I am looking for a command line tool that allows me to do this efficiently (I need to do this several times with variable points to freeze the video)
I am using Python
I thought of using ffmpeg, splitting the video into two, creating a third video composed of a given frame, and then concatenating the three videos.
But maybe there is a much simpler technique?
I found a way to do it
Let's say I have the original movie file: in.mp4
and I want to pause it for 10 seconds with the frame found at the 15s mark
#first extract the frame
ffmpeg -ss 00:00:15 -i in.mp4 -vframes 1 -q:v 2 -y static_frame.png
# Create the movie_aux1.mp4 of the first part of the original video
ffmpeg -t 00:00:15 -i in.mp4 movie_aux1.mp4
# Create the movie_aux2.mp4
ffmpeg -loop 1 -i static_frame.png -t 10 movie_aux2.mp4
# Create the movie_aux3.mp4
ffmpeg -ss 00:00:15 -i in.mp4 movie_aux3.mp4
# Create a list of the movies to concatenate. Dont forget to erase this file afterwards
echo "file 'movie_aux1.mp4'" >> mylist.txt
echo "file 'movie_aux2.mp4'" >> mylist.txt
echo "file 'movie_aux3.mp4'" >> mylist.txt
# Concatenate all three movies
ffmpeg -f concat -safe 0 -i mylist.txt out.mp4
I want to capture video from a webcam (saving to file), while occasionally getting the most recent still frame (from python code). Is there a way to do this on Linux?
What I've Tried:
# Capture Video:
ffmpeg -f v4l2 -framerate 30 -video_size 1024x576 -i /dev/video0 myvideo.mp4
...
# In another terminal, try to capture the latest still frame:
ffmpeg -sseof -3 -i myvideo.mp4 -update 1 -q:v 1 current_frame.jpg
But, I get varied responses from this last command, such as
Cannot use -sseof, duration of myvideo.mp4 not known
and
[matroska,webm # 0x55e1aae26900] Duplicate element
Last message repeated 2 times
Additional Notes/Constraints:
It must be possible to control the solution from python (e.g. calling ffmpeg via subprocess.Popen) to (a) start recording, (b) get frames at arbitrary points, (c) stop recording.
Frame timing doesn't have to be exact. A frame within the last couple seconds is fine.
Any container format is fine (mkv, mp4, etc.)
Other programs are fine, not just ffmpeg
You can have multiple outputs for FFmpeg. Combine your commands:
ffmpeg -f v4l2 -framerate 30 -video_size 1024x576 -i /dev/video0 myvideo.mp4 -r 1 -update 1 current_frame.jpg
Related:
How to extract audio from a video file using python?
Extract audio from video as wav
How to rip the audio from a video?
My question is how could I extract wav audio track from video file, say video.avi?
I read many articles and everywhere people suggest to use (from Python) ffmpeg as a subprocess (because there are no reliable python bindings to ffmpeg - the only hope was PyFFmpeg but i found it is unmaintaned now). I don't know if it is right solution and i am looking for good one.
I looked to gstreamer and found it nice but unable to satisfy my needs -- the only way I found to accomplish this from command line looks like
gst-launch-0.10 playbin2 uri=file://`pwd`/ex.mp4 audio-sink='identity single-segment=true ! audioconvert ! audio/x-raw-int, endianness=(int)1234, signed=(boolean)true, width=(int)16, depth=(int)16, rate=(int)16000, channels=(int)1 ! wavenc ! filesink location=foo.wav’
But it is not efficient because i need to wait ages while playing video and simultaneously writing to wav file.
ffmpeg is much better:
avconv -i foo.mp4 -ab 160k -ac 1 -ar 16000 -vn ffaudio.wav
But i am unable to launch it from python (not as a command line subprocess). Could you please point me out pros and cons of launching ffmpeg from python as a command line utility ? (I mean using python multiprocessing module or something similar).
And second question.
What is simple way to cut long wav file into pieces so that i don't break any words ? i mean pieces of 10-20 sec length with start and end during the pause in sentences/words ?
i know how to break them on arbitrary pieces:
import wave
win= wave.open('ffaudio.wav', 'rb')
wout= wave.open('ffsegment.wav', 'wb')
t0, t1= 2418, 2421 # cut audio between 2413, 2422 seconds
s0, s1= int(t0*win.getframerate()), int(t1*win.getframerate())
win.readframes(s0) # discard
frames= win.readframes(s1-s0)
wout.setparams(win.getparams())
wout.writeframes(frames)
win.close()
wout.close()
It is a very easy Task using ffmpeg with python subprocess and there is a reason why people are pointing to this solution as a good solution.
This is the basic command extracting audio from a given video File:
ffmpeg -i test.mp4 -ab 160k -ac 2 -ar 44100 -vn audio.wav
The Python Code is just wrapping this command:
import subprocess
command = "ffmpeg -i C:/test.mp4 -ab 160k -ac 2 -ar 44100 -vn audio.wav"
subprocess.call(command, shell=True)
You have to make sure that ffmpeg is a known task, so in your system environment variables, under path, the path to ffmpeg.exe should be listed, or you can just use the full path to the exe in your python code.
this could be better and easier to use than ffmpeg, it's called python-video converter, and can be used to extract the audio from video, https://github.com/senko/python-video-converter , it could be used in conjunction with mpg123, as follows
from converter import Converter
import os
c = Converter()
clip = 'clip.avi'
conv = c.convert(clip, 'audio.mp3', {'format':'mp3','audio':{'codec': 'mp3','bitrate':'22050','channels':1}})
for timecode in conv:
pass
os.system("mpg123 -w audio.wav audio.mp3")
the converter module extracts the audio from the video and saves it as an mp3 file, while mpg123 converts the mp3 file to mp4,
a different solution is as follows:
using moviepy module in python https://github.com/Zulko/moviepy
import moviepy.editor as mp
clip = mp.VideoFileClip("video.avi").subclip(0,20)
clip.audio.write_audiofile("theaudio.mp3")
the numbers within the subclip function specify start and end of audio, in seconds. you can then use mpg123 to change the audio to any other format
Audio clips can be created from an audio file or from the soundtrack of a video file
from moviepy.editor import *
audioclip = AudioFileClip("some_audiofile.mp3")
audioclip = AudioFileClip("some_video.avi")
https://zulko.github.io/moviepy/getting_started/audioclips.html
or example extract mp3 from
import os
VIDEOS_PATH = '/Users/****/videos'
VIDEOS_EXTENSION = '.webm' # for example
AUDIO_EXT = 'wav'
EXTRACT_VIDEO_COMMAND = ('ffmpeg -i "{from_video_path}" '
'-f {audio_ext} -ab 192000 '
'-vn "{to_audio_path}"')
os.chdir(VIDEOS_PATH)
files = os.listdir(VIDEOS_PATH)
for f in files:
if not f.endswith(VIDEOS_EXTENSION):
continue
audio_file_name = '{}.{}'.format(f, AUDIO_EXT)
command = EXTRACT_VIDEO_COMMAND.format(
from_video_path=f, audio_ext=AUDIO_EXT, to_audio_path=audio_file_name,
)
os.system(command)