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)
Related
Hi i want to make a video using images. Lets say i have an audio of 60 seconds and 6 images and i want my video to show images with equal durations i.e 10 second per image
but i couldn't figure it out how to do it
here is my code
import ffmpeg
input_audio = ffmpeg.input('./SARS/SARS.mp3')
input_still = ffmpeg.input('./SARS/*.jpg',t=20, pattern_type='glob', framerate=24)
(
ffmpeg
.concat(input_still, input_audio, v=1, a=1)
.filter('scale', size='hd1080', force_original_aspect_ratio='increase')
.output('./SARS/output.mp4')
.run(overwrite_output=True)
)
any help is appriciated
I'm sure you can achieve this with ffmpeg-python but you can try one of the following:
Plain CLI
ffmpeg \
-y \
-i './SARS/SARS.mp3' \
-pattern_type glob -framerate 0.1 -i './SARS/*.jpg' \
-vf scale=size=hd1080:force_original_aspect_ratio=increase \
'./SARS/output.mp4'
You can run this in Python using subprocess.run(['ffmpeg','-y',...])
ffmpegio Package
For a one-time pure transcoding need, ffmpegio is actually an overkill and directly calling ffmpeg via subprocess is more than sufficient and faster, but if you do this kind of operations often you can give it a try.
pip install ffmpegio-core
from ffmpegio.ffmpegprocess import run
run({'inputs': [
('./SARS/SARS.mp3', None)
('./SARS/*.jpg', {'pattern_type':'glob','framerate': 0.1})],
'outputs': [
('./SARS/output.mp4', {'vf':'scale=size=hd1080:force_original_aspect_ratio=increase'})],
overwrite=True)
Essentially, it's like subprocess counterpart but takes a dict of parameters.
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.
So I am creating multiple video clips in Python using FFMPEG, I am then trying to concat these together. I create multiple videos named result1000, result1001 etc, then I create a transition effect I want to layer between these videos. The result1000, result1001... etc concat together perfectly fine, however inserting the transition effect between them causes every clip after the first transition to lose audio.
Creating the transiton
ffmpeg -loop 1 -y -i media/templates/bg.png -i media/swoosh_sound.mp3 -shortest -acodec copy -vcodec libx264rgb output/swoosh.mp4
Creating video clips
ffmpeg -loop1 -y -i image_files/image+str(1000+i)+.png -i audio_files/audio+str(1000+i)+.mp3 -shortest -acodec copy -vcodec libx264rgb output/result+str(1000+i)+.mp4
The ffmpeg_files.txt then looks something like this
file 'output/result1000.mp4'
file 'output/result1001.mp4'
file 'output/result1002.mp4'
file 'output/result1003.mp4'
file 'output/result1004.mp4'
file 'output/swoosh.mp4'
file 'output/result1005.mp4'
file 'output/result1006.mp4'
and the concat command im using is
ffmpeg -f concat -safe 0 -i ffmpeg_files.txt output/no_bg_out.mp4
In console on running the concat comment it will say
[mov,mp4,m4a,3gp,3g2,mj2 # 000001f289b44c40] Auto-inserting h264_mp4toannexb bitstream filter
for each resultXXXX clip, then as soon as it reaches a transition clip it starts spamming
[mp4 # 000001aa093ad100] Non-monotonous DTS in output stream 0:1; previous: 13619623, current: 8777816; changing to 13619624. This may result in incorrect timestamps in the output file.
I have read over the solutions mentioned Here but none of them seem to solve my issue. It should be noted that all video clips are created from .mp3 audio files and .png image files.
All attributes must match, but swoosh.mp4 varies from the rest with a different audio sample rate and channel layout. Re-encode the audio and try again:
ffmpeg -i swoosh.mp4 -c:v copy -c:a libmp3lame -ar 24000 -ac 1 -b:a 32k swoosh2.mp4
I have 4 movie files that I am trying to overlay and concatenate:
Intro file with an empty audio channel (generated using lavfi)
Main movie file(s) that need to be concatenated and trimmed
Watermark that needs to be overlaid on top of 2
An outro movie that also has an empty channel.
Here is the command I am using to do all this:
ffmpeg -i temp_intro.mp4 -f concat -i tempFile.txt -i scoreboard.mp4 -i temp_outro.mp4 \
-filter_complex "[1]trim=end=24:start=12[s0];[s0]setpts=PTS-STARTPTS[s1];[1]atrim=end=24:start=12[s2];[s2]asetpts=PTS-STARTPTS[s3];\
[s1][s3]concat=a=1:n=1:v=1[s4];\
[2]format=yuva444p[s5];[s5]colorchannelmixer=aa=0.5[s6];\
[s4][s6]overlay=eof_action=repeat:x=(main_w-overlay_w)/2:y=main_h-overlay_h-20[s7];\
[0][s7][3]concat=n=3[s8]" test.mp4
Despite how ugly it looks, it mostly works - except for the audio. The audio starts playing as soon as the intro clip starts. I cannot create an output file with the overlaid movie because I also need to add fade-out and fade-in effects for the intro and outro. I can only re-encode once since I will be doing this over multiple large files every night.
Please suggest how I might be able to fix the audio issue.
Solution is easy - just need to concatenate audio and video for the file explicitly in the second concat. Here is the command:
ffmpeg -i temp_intro.mp4 -f concat -i tempFile.txt -i scoreboard.mp4 -i temp_outro.mp4 \
-filter_complex "[1]trim=end=24:start=12[s0];[s0]setpts=PTS-STARTPTS[s1];[1]atrim=end=24:start=12[s2];[s2]asetpts=PTS-STARTPTS[s3]; \
[2]format=yuva444p[s4];[s4]colorchannelmixer=aa=0.5[s5]; \
[s1][s5]overlay=eof_action=repeat:x=(main_w-overlay_w)/2:y=main_h-overlay_h-20[s7]; \
[0:v:0][0:a:0] [s7][s3] [3:v:0][3:a:0]concat=n=3:v=1:a=1[s8]" -map [s8] test.mp4
I have a video file and I want to get the list of streams from it. I can see the needed result by for example executing a simple `ffprobe video.mp4:
....
Stream #0:0(eng): Video: h264 (High) (avc1 / 0x31637661) ......
Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), ......
....
But I need to use python and code that will work both on Windows and Ubuntu, without executing an external process.
My real goal is to check whether there is ANY audio stream within the video (a simple yes/no would suffice), but I think getting extra information can be helpful for my problem, so I'm asking about the entire streams
EDIT: Clarifying that I need to avoid executing some external process, but looking for some python code/library to do it within the process.
import os
import json
import subprocess
file_path = os.listdir("path to your videos folder")
audio_flag = False
for file in file_path:
ffprobe_cmd = "ffprobe -hide_banner -show_streams -print_format json "+file
process = subprocess.Popen(ffprobe_cmd,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True)
output = json.loads(process.communicate()[0])
for stream in output["streams"]:
if(stream['codec_type'] == 'audio'):
audio_flag = True
break;
if(audio_flag):
print("audio present in the file")
else:
print("audio not present in the file")
# loop through the output streams for more detailed output
for stream in output["streams"]:
for k,v in stream.items():
print(k, ":", v)
Note: Make sure that your videos folder path consist of only valid video files as i didn't include any file validation in the above code snippet. Also, I have tested this code for a video file that contains one video stream and one audio stream.