Downloading a video from youtube and convert to MP4 - python

I created a script to download a youtube video and extract an images from it for each period
screenshotvideo
def screenshotvideo(url, interval, id, fullduration, title, quality):
interval = int(interval)
parsed_t = isodate.parse_duration(fullduration)
durationseconds=parsed_t.total_seconds()
iterat=int(durationseconds/int(interval))
for i in range(0, iterat):
print(str(id))
print(str(i))
print(str(i*interval))
part(url, time.strftime('%H:%M:%S', time.gmtime(int(i*interval))), "00:00:01", title+"-"+str(id), quality)
part
def part(url, starttime, duration, name, quality):
f = os.popen("ffmpeg $(youtube-dl -f "+quality+" -g '"+url+"' | sed 's/.*/-ss "+starttime+" -i &/') -t "+duration+" -c copy "+name+".mp4")
now = f.read()
print(now)
f = os.popen("ffmpeg -i "+name+".mp4 -ss 00:00:00 -vframes 1 "+name+".jpg")
now = f.read()
print(now)
f = os.popen("rm -rf "+name+".mp4")
now = f.read()
print(now)
so i got the folowing error in the first ffmpeg command
[mp4 # 0x55d537f64240] Could not find tag for codec vp8 in stream #0, codec not currently supported in container.
Could not write header for output file #0 (incorrect codec parameters ?): Invalid argument

The error is pretty clear:
codec not currently supported in container.
Use a different container that supports vp8, like webm or mkv.

The answer is close to szatmary answer but i need to download video in mp4 format, so all i neet to do is to edit the first command
ffmpeg $(youtube-dl -f "+quality+" -g '"+url+"' | sed 's/.*/-ss "+starttime+" -i &/') -t "+duration+" -c:v libx264 "+name+".mp4
after that i got other error for the images file name that i want to saved each time from the video.
So this is the final solution i found:
def screenshotvideo(url, interval, id, fullduration, title, quality):
interval = int(interval)
parsed_t = isodate.parse_duration(fullduration)
durationseconds=parsed_t.total_seconds()
iterat=int(durationseconds/int(interval))
for i in range(0, iterat):
print(str(id))
print(str(i))
print(str(i*interval))
part(url, time.strftime('%H:%M:%S', time.gmtime(int(i*interval))), "00:00:01", title+"-"+str(id), quality, i)
def part(url, starttime, duration, name, quality, i):
f = os.popen("ffmpeg $(youtube-dl -f "+quality+" -g '"+url+"' | sed 's/.*/-ss "+starttime+" -i &/') -t "+duration+" -c:v libx264 "+name+".mp4")
now = f.read()
print(now)
f = os.popen("ffmpeg -i "+name+".mp4 -ss 00:00:00 -vframes 1 "+name+"_"+str(i)+".jpg")
now = f.read()
print(now)
f = os.popen("rm -rf "+name+".mp4")
now = f.read()
print(now)

Related

How does FFMPEG command works in the following code?

How does FFMPEG working here?
import sys, os, pdb
import numpy as np
import subprocess
from tqdm import tqdm
def extract(vid_dir, frame_dir, start, end, redo=False):
class_list = sorted(os.listdir(vid_dir))[start:end]
print("Classes =", class_list)
for ic,cls in enumerate(class_list):
vlist = sorted(os.listdir(vid_dir + cls))
print("")
print(ic+1, len(class_list), cls, len(vlist))
print("")
for v in tqdm(vlist):
outdir = os.path.join(frame_dir, cls, v[:-4])
# Checking if frames already extracted
if os.path.isfile( os.path.join(outdir, 'done') ) and not redo: continue
try:
os.system('mkdir -p "%s"'%(outdir))
# check if horizontal or vertical scaling factor
o = subprocess.check_output('ffprobe -v error -show_entries stream=width,height -of default=noprint_wrappers=1 "%s"'%(os.path.join(vid_dir, cls, v)), shell=True).decode('utf-8')
lines = o.splitlines()
width = int(lines[0].split('=')[1])
height = int(lines[1].split('=')[1])
resize_str = '-1:256' if width>height else '256:-1'
# extract frames
os.system('ffmpeg -i "%s" -r 25 -q:v 2 -vf "scale=%s" "%s" > /dev/null 2>&1'%( os.path.join(vid_dir, cls, v), resize_str, os.path.join(outdir, '%05d.jpg')))
nframes = len([ fname for fname in os.listdir(outdir) if fname.endswith('.jpg') and len(fname)==9])
if nframes==0: raise Exception
os.system('touch "%s"'%(os.path.join(outdir, 'done') ))
except:
print("ERROR", cls, v)
if __name__ == '__main__':
vid_dir = sys.argv[1]
frame_dir = sys.argv[2]
start = int(sys.argv[3])
end = int(sys.argv[4])
extract(vid_dir, frame_dir, start, end, redo=True)
os.system('ffmpeg -i "%s" -r 25 -q:v 2 -vf "scale=%s" "%s" > /dev/null 2>&1'%( os.path.join(vid_dir, cls, v), resize_str, os.path.join(outdir, '%05d.jpg')))
-i --> Input_file (320x240)
-r --> frame rate (it will extract 25 frame of every video)
-q --> what does this mean?
"scale=%s --> Unable to understand this? how does this work for -1:256 ratio [will it resize the video to 256x256 dimension]?
Can anyone explain me this?

Run ANSYS Mechanical APDL from Python in an efficient manner

I have the following code, which writes an Input file and executes ANSYS Mechanical APDL using a Windows command. My issue is the execution time is much longer (15 minutes inside the software, upwards of 1 hour when calling from Python). I need it to be faster because I am varying as many as 'all' the input parameters.
def RunAPDL(E,t,w,p,aa,bb,lz,alpha,delta):
ansyspath = r'C:\Program Files\ANSYS.Inc\v181\ansys\bin\winx64\MAPDL.exe'
directory = r'C:\Users\Erik\Documents\ANSYS'
jobname = 'file'
memory = '4096'
reserve = '1024'
inputfile = r'C:\Users\Erik\Documents\ANSYS\ShellBucklingInput.inp'
outputfile = r'C:\Users\Erik\Documents\ANSYS\OutputFile.txt'
resultsfile = r'C:\Users\Erik\Documents\ANSYS\ShellBuckling.csv'
# Start time count
start = time.clock()
# Write input file
input_parameters = ('/NERR,200,10000,,OFF,0 \n'
'pi = acos(-1) \n'
'E = {:6.0f} ! N/mm2 Young\'s modulus\n'
't = {:4.2f} ! mm thickness\n'
'w = {:3.2f} ! Poisson\'s ratio\n'
'p = {:7.2f} ! N/mm2 external pressure\n'
'aa = {:6.2f} ! mm horizontal radius at u = 0\n'
'bb = {:6.2f} ! mm vertical radius\n'
'lz = {:6.2f} ! mm model height\n'
'lu = 2*asin(lz/2/bb) !mm \n'
'lv = 2*pi ! model perimeter at u = 0 \n'
'nu = 2*NINT(ABS(aa)/SQRT(ABS(aa)*t)) \n'
'nv = 3*nu ! number of elements along v-axis \n'
'alpha = {:4.2f} ! ratio of lu that is not loaded by p \n'
'delta = {:4.2f}*t ! prescribed imperfection magnitude \n'
'*ULIB,ShellBucklingLibrary,mac \n'
'*USE,ShellBuckling,pi,E,t,w,p,aa,bb,lz,lu,nu,nv,alpha,delta \n'
'/CLEAR'
).format(E,t,w,p,aa,bb,lz,alpha,delta)
with open(inputfile,'w') as f:
f.write(input_parameters)
# Call ANSYS
callstring = ('\"{}\" -p aa_t_a -dir \"{}\" -j \"{}\" -s read'
' -m {} -db {} -t -d win32 -b -i \"{}\" -o \"{}\"'
).format(ansyspath,directory,jobname,memory,reserve,inputfile,outputfile)
print('Invoking ANSYS with', callstring)
proc = subprocess.Popen(callstring).wait()
# Update pressure field for next analysis
with open(resultsfile,'r') as f:
lambdaS = float(list(csv.reader(f))[-1][16])
p = 1.2*lambdaS*p
print('Updated pressure is',p,' N/mm2.')
# Stop time count
stop = time.clock()
print('Elapsed time is ',stop-start,' seconds.')
return(p)
I execute it by pressing F5 on the Python shell, then messages appear in the shell:
Invoking ANSYS with "C:\Program Files\ANSYS
Inc\v181\ansys\bin\winx64\MAPDL.exe" -p aa_t_a -dir
"C:\Users\Erik\Documents\ANSYS" -j "file" -s read -m 4096 -db 1024 -t -d
win32 -b -i "C:\Users\Erik\Documents\ANSYS\ShellBucklingInput.inp" -o
"C:\Users\Erik\Documents\ANSYS\OutputFile.txt"
Updated pressure is -0.0046478399999999994 N/mm2.
Elapsed time is 4016.59094467131 seconds.
I don't know why your code is slower in Python but I suggest you to use PyAnsys package from PyPI. It offers a robust infrastructure to combine Python and APDL.

bash variables in Python

I have a python script conve_cal.py which take 7 arguments as follow:
enter code here
import numpy as np
import sys
def read_file(filename1,filename2):
Input1 = np.loadtxt(filename1)
Input2 = np.loadtxt(filename2)
#print type(Input1)
#print Input1
return Input1,Input2
def NU_calc(T_avg,Trght,Ttop,rmv,argv1,argv2,arg3):
....
if __name__ == "__main__":
T_avg = sys.argv[1]
Trght = sys.argv[2]
Ttop = sys.argv[3]
rmv = sys.argv[4]
arg3 = sys.argv[5]
file1 = sys.argv[6]
file2 = sys.argv[7]
print (sys.argv)
In1,In2 = read_file(file1,file2)
#print type(arg3)
NU_calc(T_avg,Trght,Ttop,rmv,In1,In2,arg3)
If I run the code stand alone in the Terminal as
python2 conve_calc.py 285 282 300 0 noclip Input1.dat Input2.dat
the code give the output as desired. But If i use the same syntax with bash variables in the bash script as follows;
#!/bin/bash
...
...
t_avg=`grep "Average" test.avg |cut -f6 -d" "`
t_right=`grep "Tright" ./0/Input_conditions|cut -f 3 |cut -f 1 -d';'`
t_top=`grep "Ttop" ./0/Input_conditions|cut -f 3 |cut -f 1 -d';'`
echo "$t_right $t_top $Hr $Ht" >> $start_path/post_process_data/'HT_stat.dat'
rm test.avg tmp.dat test_fl.txt
# Call
# Arg-1; Average Temp
## Arg-2; Temp of right wall
## Arg-3; Temp of top wall
## Arg-4; # of faces to remove (0:None ,1...upto max of no. of faces)
## Arg-5; Right GradT file
## Arg-6; Top GradT file
rv0="0" # Change this to Remove the faces
rv1="1"
c1="noclip"
c2="middle"
i1="Input1.dat"
i2="Input2.dat"
python2 $start_path/conve_calc.py $t_avg $t_right $t_top $rv1 $c1 $i1 $i2 >> $start_path/post_process_data/\
'Common_out.dat'
But with this bash script input I am getting Following error I am unable to find why these inputs are getting wrong.
Traceback (most recent call last):
File "/home/meisu/OpenFOAM/meisu-2.4.0/Cyence_data/foam_adagio/conve_calc.py", line 69, in <module>
file2 = sys.argv[7]
IndexError: list index out of range
I have looked into various stack solutions but none of them worked.
Your problem is that one of the variables is empty. The shell expands the variables and then parses the command so it thinks there are only 6 parameters for the command. You could add two types of defensive coding. First, for the derived variables likely to fail, test them before you use them. Second, enclose your parameters in quotes so that empty parameters, or parameters with characters such as spaces that will mess up the command parsing, will be handed down properly.
#!/bin/bash
...
...
t_avg=`grep "Average" test.avg |cut -f6 -d" "`
if [ -z "$t_avg" ]; then
echo t_avg failed >&2
exit 2
fi
t_right=`grep "Tright" ./0/Input_conditions|cut -f 3 |cut -f 1 -d';'`
if [ -z "$t_right" ]; then
echo t_right failed >&2
exit 2
fi
t_top=`grep "Ttop" ./0/Input_conditions|cut -f 3 |cut -f 1 -d';'`
if [ -z "$t_top" ]; then
echo t_top failed >&2
exit 2
fi
echo "$t_right $t_top $Hr $Ht" >> $start_path/post_process_data/'HT_stat.dat'
rm test.avg tmp.dat test_fl.txt
# Call
# Arg-1; Average Temp
## Arg-2; Temp of right wall
## Arg-3; Temp of top wall
## Arg-4; # of faces to remove (0:None ,1...upto max of no. of faces)
## Arg-5; Right GradT file
## Arg-6; Top GradT file
rv0="0" # Change this to Remove the faces
rv1="1"
c1="noclip"
c2="middle"
i1="Input1.dat"
i2="Input2.dat"
python2 $start_path/conve_calc.py "$t_avg" "$t_right" "$t_top" "$rv1" "$c1" "$i1" "$i2" >> "$start_path/post_process_data/Common_out.dat"
You can see exactly what is sent to your python script with a toy script that just prints its arguments and exits
!#/usr/bin/env python
import sys
for i, arg in enumerate(sys.argv):
print i, arg
print '---- end ----'

How to get a online video's duration without downloading the full video?

To get a video's duration and resolution, I've got this function:
def getvideosize(url, verbose=False):
try:
if url.startswith('http:') or url.startswith('https:'):
ffprobe_command = ['ffprobe', '-icy', '0', '-loglevel', 'repeat+warning' if verbose else 'repeat+error', '-print_format', 'json', '-select_streams', 'v', '-show_streams', '-timeout', '60000000', '-user-agent', BILIGRAB_UA, url]
else:
ffprobe_command = ['ffprobe', '-loglevel', 'repeat+warning' if verbose else 'repeat+error', '-print_format', 'json', '-select_streams', 'v', '-show_streams', url]
logcommand(ffprobe_command)
ffprobe_process = subprocess.Popen(ffprobe_command, stdout=subprocess.PIPE)
try:
ffprobe_output = json.loads(ffprobe_process.communicate()[0].decode('utf-8', 'replace'))
except KeyboardInterrupt:
logging.warning('Cancelling getting video size, press Ctrl-C again to terminate.')
ffprobe_process.terminate()
return 0, 0
width, height, widthxheight, duration = 0, 0, 0, 0
for stream in dict.get(ffprobe_output, 'streams') or []:
if dict.get(stream, 'duration') > duration:
duration = dict.get(stream, 'duration')
if dict.get(stream, 'width')*dict.get(stream, 'height') > widthxheight:
width, height = dict.get(stream, 'width'), dict.get(stream, 'height')
if duration == 0:
duration = 1800
return [[int(width), int(height)], int(float(duration))+1]
except Exception as e:
logorraise(e)
return [[0, 0], 0]
But some online videos comes without duration tag. Can we do something to get its duration?
If you have direct link to the video itself, like http://www.dl.com/xxx.mp4, you can direct use ffprobe to get the duration of this video by using:
ffprobe -i some_video_direct_link -show_entries format=duration -v quiet -of csv="p=0"
import cv2
data = cv2.VideoCapture('https://v.buddyku.id/ugc/m3YXvl-61837b3d8a0706e1ee0ab139.mp4')
frames = data.get(cv2.CAP_PROP_FRAME_COUNT)
fps = int(data.get(cv2.CAP_PROP_FPS))
seconds = int(frames / fps)
print("duration in seconds:", seconds)
I know this question is old, but there's a better way to do this.
By combining einverne's answer with some actual Python (Python 3.5 in this case) we can create a short function that returns the number of seconds (duration) in a video.
import subprocess
def get_duration(file):
"""Get the duration of a video using ffprobe."""
cmd = ['ffprobe', '-i', file, '-show_entries', 'format=duration',
'-v', 'quiet', '-of', 'csv="p=0"']
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
output = float(output)
return round(output)
And to call this function:
video_length_in_seconds = get_duration('/path/to/your/file') # mp4, avi, etc
This will give you the total seconds, rounded to the closest full second. So if your video is 30.6 seconds, this will return 31.
The FFMpeg command ffprobe -i video_file_here -show_entries format=duration -v quiet -of csv="p=0" will get your video duration for you and shouldn't download the entire video.

How to add audio to video?

I record a video with no sound. I save a snapshots and then I compile them to .avi with 25FPS. Now I want to record audio (instead time.sleep(0.04) between following snapshots I will record audio in this time) and compile it wits video. Now I have avi file, and wave file, and I find a solution to mix them.
Python, Win32
It is my "video recorder" which use 'mencoder':
import os
import re
from VideoCapture import *
import time
def makeVideo(device, ftime):
folder = 'foto/forVideo/'
mencoder = "C:\mencoder.exe"
for i in range(ftime * 25) :
FN = "foto\\forVideo\\ola-%(#)04d.jpg" % {"#" : i}
device.saveSnapshot(FN, quality=100, timestamp=0, boldfont=0)
time.sleep(0.04)
# Set up regular expressions for later
RE = re.compile('.*-(\d*)\.jpg')
fbRE = re.compile('(.*)-.*\.jpg')
# How many frames to use per movie
framestep = 2000
print '\n\n\tlisting contents of %s . . .'%folder
files = os.listdir(folder)
print '%s files found.\n\n' % len(files)
# If a file is called "asdf-003.jpg", the basename will be 'asdf'.
basenames = [fbRE.match(i).groups()[0] for i in files if fbRE.match(i)]
# Get the set of unique basenames. In the
basenames = list(set(basenames))
print '\t***There are %s different runs here.***' % len(basenames)
# This loop will only execute once if there was only a single experiment
# in the folder.
for j,bn in enumerate(basenames):
these_files = [i for i in files if bn in i]
# Sort using the "decorate-sort-undecorate" approach
these_sorted_files = [(int(RE.match(i).groups()[0]),i) for i in these_files if RE.match(i)]
these_sorted_files.sort()
these_sorted_files = [i[1] for i in these_sorted_files]
# these_sorted_files is now a list of the filenames a_001.jpg, a_002.jpg, etc.
for k in range(0, len(these_sorted_files), framestep):
frame1 = k
frame2 = k+framestep
this_output_name = 'C:\_%s_%s_%s-%s.avi' % (bn,j,frame1,frame2)
print '\n\n\toutput will be %s.' % this_output_name
f = open('temp.txt','w')
filenames = [os.path.join(folder,i)+'\n' \
for i in these_sorted_files[frame1:frame2]]
f.writelines(filenames)
f.close()
# Finally! Now execute the command to create the video.
cmd = '%s "mf://#temp.txt" -mf fps=25 -o %s -ovc lavc\
-lavcopts vcodec=mpeg4' % (mencoder,this_output_name)
os.system(cmd)
print '\n\nDONE with %s' % this_output_name
print 'Done with all marked folders.'
I think the best bet would be to use an external program to mux them. ffmpeg is a perennial favorite -- quality Windows builds are available at http://ffmpeg.arrozcru.org/autobuilds/ . With ffmpeg, just do ffmpeg -i your_video_file.avi -i your_audio_file.wav -vcodec copy -acodec copy muxed_file.avi and you're done.

Categories

Resources