Python code to concat images and ts files using ffmpeg - python-3.x

I have a folder with multiple ts files in it and I want to join the files by inserting an image for n number of duration between videos. Below is the list with the duration for which an image needs to be inserted for.
['00:00:06:17', '00:00:00:16', '00:00:01:05', '00:00:00:31', '00:00:01:01']
For example, if the folder has 5 ts files (this number might change so the folder needs to be iterable) then,
video1 + image for 00:00:06:17 + video2 + image for 00:00:00:16 + video 3, etc...
Any pointers will be much appreciated.
UPDATE:
for i in new_ts3:
for m in filename[:-1]:
p1 = subprocess.Popen (['ffmpeg', '-loop', '1', '-i', sys.argv[2], '-c:v', 'libx264', '-profile:v', 'high', '-t', i, '-pix_fmt', 'yuvj420p', '-vf', 'scale=1280:720', '-f', 'mpegts', '{}{}_.ts'.format((os.path.splitext(sys.argv[1]) [0]), m)], stdout=subprocess.PIPE)
out1 = p1.communicate()
break
where new_ts3 is ['00:00:06:17', '00:00:00:16', '00:00:01:05', '00:00:00:31', '00:00:01:01'] and
filename is ['file1', 'file2', 'file3', 'file4', 'file5', 'file6']
With the above, I am getting 5 files with different filenames but each file is of duration 00:00:06:17

import os
i = 0
image_list = ['img1.jpeg', 'img2.jpeg']
duration = ['1200', '1300']
## First we make loops of images to videos with given duration
for i in range(len(image_list)):
# change name according to whatever order you want to save the files format
outname = image_list[i] + str(i) + '.mp4'
dur = duration[i]
os.system(f'ffmpeg -loop 1 -i {images_list[i]} -c:v libx264 -t {dur} -pix_fmt yuv420p -vf scale=320:240 {outname}')
# Then we onvert .mp4 files to .mpeg if not in .mpeg format as .mp4 files have headers
for file_name in os.listdir(path):
if (filename.endswith(".mp4")):
out_name = filename.split(".")[0] + str(.ts)
os.system(f'ffmpeg -i filename -c copy -bsf:v h264_mp4toannexb -f mpegts {out_name}')
## create a list of the order in which you want to combine files here
order_list = [] # create with your own logic
new_out = 'out.ts'
file_list = os.listdir(path)
for i in range(len(file_list)-1):
new_out = 'out' + str(i) + '.ts'
os.system(f'ffmpeg -i "concat:{file_list[i]}|{file_list[i+1]}" -c copy {new_out}')
if (i+1 < len(file_list))
file_list[i+1] = new_out
else:
continue
## finally convert it to mp4 at the last step
the flags used in commands are mostly self explanatory such as scale of output.
In case of the last loop , we're simply updating the output file name every time by adding that to our file list and combining it with the next item in the list and pushing the output
You can convert the final .ts file to any format of your choice. Look for FFMPEG documentation and to execute it in python use the os.system

Related

How to write binary stream as an opus file - python

I'm trying to write an opus file out of a binary stream using the code below, but the resulting files are unplayable. It seems that dumping it into the container won't work. Any ideas as to how to go about writing these audio files?
audio_start.append(start_audio + name[2])
audio_end.append(start_audio + name[2] + name[3])
count = 0
for i, j in zip(audio_start, audio_end):
in_file.seek(0)
count += 1
audio_output_path = input[:-4] + "audio_" + str(count) + ".opus"
with open(audio_output_path, 'wb') as out_audio:
out_audio.write(in_file.read()[i:j])
out_audio.close()

files are saved repeatedly with single name, no looping, no ranging

My codes runs well, but have one flaw. They are not saving accordingly. For example, Let's say I caught 3 jpeg files, when I ran the codes, it saves 3 times on slot 1, 3 times on slot 2, and 3 times on slot 3. So I ended up with 3 same files.
I think there is something wrong with my looping logic?
If I changed for n in range(len(soup_imgs)): to for n in range(len(src)):, the operation saves infinitely of the last jpeg files.
soup_imgs = soup.find(name='div', attrs={'class':'t_msgfont'}).find_all('img', alt="", src=re.compile(".jpg"))
for i in soup_imgs:
src = i['src']
print(src)
dirPath = "C:\\__SPublication__\\"
img_folder = dirPath + '/' + soup_title + '/'
if (os.path.exists(img_folder)):
pass
else:
os.mkdir(img_folder)
for n in range(len(src)):
n += 1
img_name = dirPath + '/' + soup_title + '/' + str({}).format(n) + '.jpg'
img_files = open(img_name, 'wb')
img_files.write(requests.get(src).content)
print("Outputs:" + img_name)
I am amateur in coding, just started not long ago as a hobby of mine. Please give me some guidance, chiefs.
Try this when you are writing your image files:
from os import path
for i, img in enumerate(soup_imgs):
src = img['src']
img_name = path.join(dirPath, soup_title, "{}.jpg".format(i))
with open(img_name, 'wb') as f:
f.write(requests.get(src).content)
print("Outputs:{}".format(img_name))
You need to loop over all image sources, rather than using the last src value from a previous for block.
I've also added a safer method for joining directory and file paths that should be OS independent. Finally, when opening a file, always use the with open() as f: construct - this way Python will automatically close the filehandle for you.

How to read video file from directory to use file name into program

I want to read video file from the directory which might be in .MOV, mp4 ect. then convert it into audio file. When i giving manual input to the video file name it working correctly, but i want my code to read it from directory which contain only one video file.
for vid in glob.glob('/home/qwickbit/Desktop/Qwickbit/Tennis_OpenCV/*.MOV'):
cap = cv2.VideoCapture(vid)
ret, video = cap.read()
# video = input ("Inter the Input Video File Name:")
minLength = 50
minBF = 1
audio = "Audio_file%d%d.wav" % (minLength,minBF)
audio_convert = "ffmpeg -i {video} -ac 1 -f wav -vn {audio}".format(video=video, audio= audio)
subprocess.call(audio_convert,shell=True)

Run code on specific files in a directory separately (by the name of file)

I have N files in the same folder with different index numbers like
Fe_1Sec_1_.txt
Fe_1Sec_2_.txt
Fe_1Sec_3_.txt
Fe_2Sec_1_.txt
Fe_2Sec_2_.txt
Fe_2Sec_3_.txt
.
.
.
and so on
Ex: If I need to run my code with only the files with time = 1 Sec, I can make it manually as follow:
path = "input/*_1Sec_*.txt"
files = glob.glob(path)
print(files)
which gave me:
Out[103]: ['input\\Fe_1Sec_1_.txt', 'input\\Fe_1Sec_2_.txt', 'input\\Fe_1Sec_3_.txt']
In case of I need to run my code for all files separately (depending on the measurement time in seconds, i.e. the name of file)
I tried this code to get the path for each time of measurement:
time = 0
while time < 4:
time += 1
t = str(time)
path = ('"input/*_'+t+'Sec_*.txt"')
which gives me:
"input/*_1Sec_*.txt"
"input/*_2Sec_*.txt"
"input/*_3Sec_*.txt"
"input/*_4Sec_*.txt"
After that I tried to use this path as follow:
files = glob.glob(path)
print(files)
But it doesn't import the wanted files and give me :
"input/*_1Sec_*.txt"
[]
"input/*_2Sec_*.txt"
[]
"input/*_3Sec_*.txt"
[]
"input/*_4Sec_*.txt"
[]
Any suggestions, please??
I think the best way would be to simply do
for time in range(1, 5): # 1,2,3,4
glob_path = 'input/*_{}Sec_*.txt'.format(time)
for file_path in glob.glob(glob_path):
do_something(file_path, measurement) # or whatever

Pydub audio export has silence at the start?

I wrote a python script to take audio in 30 minute mp3's and slice it into unix timestamped, second long files. The source audio files are 192kbps, 441000Hz, stero mp3 files.
I want it that way for a service that archives audio from a radio station (where I work) and can deliver it to a user over a given start and end time, to the second. We had the server shut down for an hour for maintenance (we try not to but it happens) and we recorded it over that time using a different computer that saved our audio in 30-minute chunks. Normally this archive server saves the second-long chunks itself without issue.
The function that does the conversion, given a 30 minute input audio file, the directory to save the output chunks in, and the start time of the file as a unix timestamp:
def slice_file( infile, workingdir, start ):
#find the duration of the input clip in millliseconds
duration_in_milliseconds = len(infile)
print ("Converting " + working_file + " (", end="", flush=True)
song = infile
#grab each one second slice and save it from the first second to the last whole second in the file
for i in range(0,duration_in_milliseconds,1*one_second):
#get the folder where this second goes:
arr = datefolderfromtimestamp( int(start) + (int(i/1000)))
#print ("Second number: %s \n" % (int(i/1000)) )
offset = (i + one_second)
current_second = song[i:offset]
ensure_dir(working_directory + "/" + arr[0] + "/" + arr[1] + "/" + arr[2] + "/")
filename = os.path.normpath(working_directory + "/" + arr[0] + "/" + arr[1] + "/" + arr[2] + "/" + str(int(start) + (int(i/1000))) + "-second.mp3")
current_second.export(filename, format="mp3")
#indicate some sort of progress is happening by printing a dot every three minutes processed
if( i % (3*60*one_second) == 0 ):
print ('.', end="", flush=True)
print (")")
My issue is that all the second files converted by this script seem to be longer than a second with on average 70 ms of silence at the start of them. When I download files from my archiver server it gives me all the files concatenated together, so it sounds terrible and glitchy.
Can someone help me out? I'm not sure where this error is coming from.
My full script if you're curious:
http://pastebin.com/fy8EkVSz
Update: Found out the source of this - LAME adds buffers to the start of the file.
See: http://lame.sourceforge.net/tech-FAQ.txt

Resources