diff --git a/.gitignore b/.gitignore
index 697c0f8..55446bb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,10 @@
*.exe
*.DS_store
*.spec
+*.rc
+*.ico
+.gitignore
+.gitattributes
build
dist
__pycache__
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index f08fa3b..6b12e9c 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2021 Guillermo-Hidalgo-Gadea
+Copyright (c) 2022 Guillermo-Hidalgo-Gadea
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index 6f98836..640e046 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
# VideoPyToolbox [](https://guillermohidalgogadea.com/)
-Play, compress, trim and concatenate videos in python using FFmpeg
-
+Play, compress, trim and concatenate videos using ffmpeg
## What it is
This Toolbox is a python wrapper for a bunch of useful ffmpeg commands to play, compress and edit videos using ffmpeg.
@@ -11,15 +10,12 @@ When it comes to video compression, FFmpeg can be challenging to use over comman
## How to use it
-The Toolbox is built as an interactive terminal prompt to guide you step by step through the process of concatenating, compressing, spliting and playing videos. You can either use the `VideoPyToolbox.py` script in your IDE, or run it from the terminal. You can find a compiled version of VideoPyToolbox [here](https://gitlab.ruhr-uni-bochum.de/ikn/syncflir/-/blob/master/PostProcessing/VideoPyToolbox.exe).
+The Toolbox is built as an interactive terminal prompt to guide you step by step through the process of concatenating, compressing, spliting and playing videos. You can either use the `VideoPyToolbox.py` script in your IDE, or run it from the terminal. You can find a compiled version of VideoPyToolbox [here](https://gitlab.ruhr-uni-bochum.de/ikn/syncflir/-/blob/master/PostProcessing/VideoPyToolbox.exe). Compiled in Windows with pyinstaller v5.1 using `pyinstaller --add-binary ffmpeg.exe;. --add-binary ffplay.exe;. --onefile --icon=logo.ico VideoPyToolbox.py`.
## Features
The video player allows to stream up to 9 files at the same time, for example to check for synchronizity. Video compression is set to `hevc/h.265`, but could be expanded in future releases. GPU mode uses hardware acceleration for encoding with `hevc_nvenc`. The trim/split function to extract video snippets between timestamps needs to re-encode the video with `h.265 cfr 0` or `hevc_nvenc cq 0` respectively, to achieve "frame-accurate" splits. Lossless splits are not accurate enough if the chosen timestamp does not happen to contain a keyframe, which can result in timeshifts of up to several seconds (depending on framerate).
## Next release
-* enhanced batch processing for split from multiple directories
-* choice between losless and re-encoded trim/split
-* choose from wider variety of compression codecs
* play audio from video with waveform and timestamp
-* create mosaic video
+* scrap all files in directory and subdirectory
* tbd
diff --git a/VideoPyToolbox.py b/VideoPyToolbox.py
index c81ba70..f929ea3 100644
--- a/VideoPyToolbox.py
+++ b/VideoPyToolbox.py
@@ -5,9 +5,7 @@
to play a video recording, compress it using h265 codec, or to concatenate and trim clips from
timestamps. Use the custom pipeline to compress and concat at once.
-'conda install ffmpeg' if not already installed
-
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
====================================================================================================
@@ -22,11 +20,11 @@
# import functions
from toolbox.function_ffplay import ffplay
-from toolbox.function_compress import compress_h265, compress_hevc_nvenc
+from toolbox.function_compress import compress_h265, compress_h264, compress_hevc_nvenc
from toolbox.function_concatenate import concat_videos
-from toolbox.function_custom import the_usual_h265, the_usual_hevc_nvenc
-from toolbox.function_rename import batch_rename
+from toolbox.function_custom import the_usual_h265
from toolbox.function_split import trim_split_h265, trim_split_hevc_nvenc
+from toolbox.function_mosaic import mosaic_video
from toolbox.logo import ascii_logo, width, height
# Helper functions
@@ -58,6 +56,7 @@ def check_gpu():
# Terminal print colors
RESET = "\033[0;0m"
MATRIX = "\033[0;32m"
+YELLOW = "\033[0;33m"
CYAN = "\033[0;36m"
RED = "\033[0;31m"
@@ -73,11 +72,11 @@ def check_gpu():
# header
print("#"*width + "\n")
- print("MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com\n".center(width))
+ print("MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com\n".center(width))
print("#"*width)
#logo in ascii here
- sys.stdout.write(MATRIX)
+ sys.stdout.write(YELLOW)
print(ascii_logo.center(width))
sys.stdout.write(RESET)
instructions = "VideoPy is a FFMPEG wrapper to play videos, to compress and change codecs, as well as to append and split raw videos."
@@ -86,11 +85,11 @@ def check_gpu():
# function help format
help = '''
'p' Play audio or video file
- 'c' Compress video to h.265/h.264
+ 'c' Compress video with h265/h264
'a' Append or Concatenate multiple files
's' Split or Trim files by timestamp
- 'r' Rename files in batches
'u' Custom pipeline to compress and concatenate
+ 'm' Create multi-view mosaic video
'gpu' Check for hardware acceleration
'q' Quit
'''
@@ -104,7 +103,7 @@ def check_gpu():
# header
print("#"*width + "\n")
- print("MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com\n".center(width))
+ print("MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com\n".center(width))
print("#"*width)
#logo in ascii here
@@ -117,11 +116,11 @@ def check_gpu():
# function help format
help = '''
'p' Play audio or video file
- 'c' Compress video to h.265/h.264
+ 'c' Compress video with h265/h264
'a' Append or Concatenate multiple files
's' Split or Trim files by timestamp
- 'r' Rename files in batches
'u' Custom pipeline to compress and concatenate
+ 'm' Create multi-view mosaic video
'gpu' Check for hardware acceleration
'q' Quit
'''
@@ -150,10 +149,17 @@ def check_gpu():
# start compression
print("\nStart compression with ffmpeg... \n")
if "y" not in gpu_use:
- compress_h265()
- input("\nCompressing ended!\n")
- # reset while loop
- choice = 'main'
+ encoder = input("\n(CPU mode) Choose video encoder [h264/h265]: ")
+ if "4" in encoder:
+ compress_h264()
+ input("\nCompressing ended!\n")
+ # reset while loop
+ choice = 'main'
+ elif "5" in encoder:
+ compress_h265()
+ input("\nCompressing ended!\n")
+ # reset while loop
+ choice = 'main'
else:
compress_hevc_nvenc()
input("\nCompressing ended!\n")
@@ -173,15 +179,25 @@ def check_gpu():
elif choice.startswith("s"):
print("\nStart trimming videos in ffmpeg... \n")
if "y" not in gpu_use:
- trim_split_h265()
- input("\nTrimming ended!\n")
- # reset while loop
- choice = 'main'
+ try:
+ trim_split_h265()
+ input("\nTrimming ended!\n")
+ # reset while loop
+ choice = 'main'
+ except:
+ input("\nTrimming ended!\n")
+ # reset while loop
+ choice = 'main'
else:
- trim_split_hevc_nvenc()
- input("\nTrimming ended!\n")
- # reset while loop
- choice = 'acc_main'
+ try:
+ trim_split_hevc_nvenc()
+ input("\nTrimming ended!\n")
+ # reset while loop
+ choice = 'acc_main'
+ except:
+ input("\nTrimming ended!\n")
+ # reset while loop
+ choice = 'acc_main'
elif choice.startswith("u"):
print("\nAh, the usual. Comming right up... \n")
@@ -191,20 +207,23 @@ def check_gpu():
# reset while loop
choice = 'main'
else:
- the_usual_hevc_nvenc()
+ the_usual_h265()
input("\nPipeline ended!\n")
# reset while loop
choice = 'acc_main'
- elif choice.startswith("r"):
- print("\nStart renaming files... \n")
- batch_rename()
- input("\nRenaming ended!\n")
- # reset while loop
- if "y" in gpu_use:
- choice = 'acc_main'
- else:
+ elif choice.startswith("m"):
+ print("\nStart creating mosaic video... \n")
+ if "y" not in gpu_use:
+ mosaic_video()
+ input("\nMosaic video created!\n")
+ # reset while loop
choice = 'main'
+ else:
+ mosaic_video()
+ input("\nMosaic video created!\n")
+ # reset while loop
+ choice = 'acc_main'
elif choice.startswith("q"):
break
diff --git a/VideoPyToolbox.spec b/VideoPyToolbox.spec
index 8b274be..5369fdb 100644
--- a/VideoPyToolbox.spec
+++ b/VideoPyToolbox.spec
@@ -4,41 +4,42 @@
block_cipher = None
-a = Analysis(['VideoPyToolbox.py'],
- pathex=[],
- binaries=[],
- datas=[],
- hiddenimports=[],
- hookspath=[],
- hooksconfig={},
- runtime_hooks=[],
- excludes=[],
- win_no_prefer_redirects=False,
- win_private_assemblies=False,
- cipher=block_cipher,
- noarchive=False)
-pyz = PYZ(a.pure, a.zipped_data,
- cipher=block_cipher)
+a = Analysis(
+ ['VideoPyToolbox.py'],
+ pathex=[],
+ binaries=[('ffmpeg.exe', '.'), ('ffplay.exe', '.')],
+ datas=[],
+ hiddenimports=[],
+ hookspath=[],
+ hooksconfig={},
+ runtime_hooks=[],
+ excludes=[],
+ win_no_prefer_redirects=False,
+ win_private_assemblies=False,
+ cipher=block_cipher,
+ noarchive=False,
+)
+pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
-exe = EXE(pyz,
- a.scripts,
- a.binaries,
- a.zipfiles,
- a.datas,
- [],
- name='VideoPyToolbox',
- debug=False,
- bootloader_ignore_signals=False,
- strip=False,
- upx=True,
- upx_exclude=[],
- runtime_tmpdir=None,
- console=False,
- disable_windowed_traceback=False,
- target_arch=None,
- codesign_identity=None,
- entitlements_file=None , icon='logo.ico')
-app = BUNDLE(exe,
- name='VideoPyToolbox.app',
- icon='logo.ico',
- bundle_identifier=None)
+exe = EXE(
+ pyz,
+ a.scripts,
+ a.binaries,
+ a.zipfiles,
+ a.datas,
+ [],
+ name='VideoPyToolbox',
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=True,
+ upx_exclude=[],
+ runtime_tmpdir=None,
+ console=True,
+ disable_windowed_traceback=False,
+ argv_emulation=False,
+ target_arch=None,
+ codesign_identity=None,
+ entitlements_file=None,
+ icon='logo.ico', version='version.rc',
+)
diff --git a/logo.ico b/logo.ico
index 3fe5ef2..51eeb50 100644
Binary files a/logo.ico and b/logo.ico differ
diff --git a/screen.PNG b/screen.PNG
index 67932ae..6ffbb7b 100644
Binary files a/screen.PNG and b/screen.PNG differ
diff --git a/toolbox/function_compress.py b/toolbox/function_compress.py
index 40aa454..8fd6dc4 100644
--- a/toolbox/function_compress.py
+++ b/toolbox/function_compress.py
@@ -2,16 +2,14 @@
====================================================================================================
Helper function for the VideoPyToolbox
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
====================================================================================================
'''
import os # paths and terminal commands
-import pandas as pd # data frames for metadata
-from tkinter import filedialog # interactive interface to selet files
-from datetime import datetime # get timestamp for filenames
+from tkinter import filedialog # interactive interface to selet files
def compress_h265():
'''
@@ -31,43 +29,53 @@ def compress_h265():
else:
outputdir = secondtry
- # set output directory
- path = outputdir + '/compressed/'
- try:
- os.mkdir(path)
- except:
- pass
-
- outputs = [path + 'h265_' + os.path.basename(filename) for filename in videofile]
-
# compress videos with libx265 encoder
-
- # crf from 0 to 51, 18 recommended lossless average
print("HEVC/H265 compression...")
- crf = input("Choose constant rate factor between 0-50: ") or 18
+ # crf from 0 to 51, 12 recommended for lossless average
+ crf = input("Choose constant rate factor between 0-50: ") or 12
- starttime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
+ # set output filenames
+ path = outputdir
+ outputs = [path + 'h265_crf{crf}_' + os.path.basename(filename) for filename in videofile]
for i, video in enumerate(videofile):
- output = outputs[i]
+ output = outputs[i].split('.')[0] # strip video container
- ffmpeg_command = f"ffmpeg -y -i {video} -an -vcodec libx265 -crf {crf} {output}"
+ ffmpeg_command = f"ffmpeg -y -i {video} -an -dn -vcodec libx265 -crf {crf} {output}.mp4"
os.system(ffmpeg_command)
- endtime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
+def compress_h264():
+ '''
+ Video Compression with H264: This function reads video filenames from a list and compresses with H264 codec. Audio is removed.
+ '''
+ # select batch to compress multiple
+ videofile = list(filedialog.askopenfilenames(title='Choose Video Files you want to compress'))
+ if not videofile:
+ return
+
+ outputdir = filedialog.askdirectory(title='Choose Output Directory for Compression')
+ if not outputdir:
+ print('Please select a valid output directory')
+ secondtry = filedialog.askdirectory(title='Choose Output Directory for Concatenation')
+ if not secondtry:
+ return
+ else:
+ outputdir = secondtry
+
+ # compress videos with libx265 encoder
+ print("AVC/H264 compression...")
+ # crf from 0 to 51, 12 recommended for lossless average
+ crf = input("Choose constant rate factor between 0-50: ") or 12
+
+ # set output filenames
+ path = outputdir
+ outputs = [path + 'h264_crf{crf}_' + os.path.basename(filename) for filename in videofile]
- # save metadata
- metadata = path + '/' + 'h265_compression_' + starttime + '.txt'
- filelist = pd.DataFrame({'input': videofile, 'output': outputs}, index=None)
- filelist.to_csv(metadata, sep ='\t', index=False)
- # add header
- title = f"# VideoPyToolbox compression with libx265 crf={crf} \n # started: {starttime} ended: {endtime} \n"
- with open(metadata, "r+") as textfile:
- original = textfile.read()
- textfile.seek(0)
- textfile.write(title + original)
- textfile.close()
+ for i, video in enumerate(videofile):
+ output = outputs[i].split('.')[0] # strip video container
+ ffmpeg_command = f"ffmpeg -y -i {video} -an -dn -vcodec libx264 -crf {crf} {output}.mp4"
+ os.system(ffmpeg_command)
def compress_hevc_nvenc():
'''
@@ -87,37 +95,16 @@ def compress_hevc_nvenc():
else:
outputdir = secondtry
- # set output directory
- path = outputdir + '/compressed/'
- try:
- os.mkdir(path)
- except:
- pass
-
- outputs = [path + 'hevc_nvenc_' + os.path.basename(filename) for filename in videofile]
-
# compress videos with hevc_nvenc encoder
print("HEVC_NVENC compression...")
- cq = input("Choose constant quantization parameter between 0-50: ") or 18
+ cq = input("Choose constant quantization parameter between 0-50: ") or 12
- starttime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
+ # set output directory
+ path = outputdir
+ outputs = [path + 'hevc_nvenc_cq{cq}_' + os.path.basename(filename) for filename in videofile]
for i, video in enumerate(videofile):
- output = outputs[i]
+ output = outputs[i].split('.')[0] # strip video container
- ffmpeg_command = f"ffmpeg -y -i {video} -an -vcodec hevc_nvenc -preset p7 -rc vbr -cq {cq} {output}"
+ ffmpeg_command = f"ffmpeg -y -i {video} -an -vcodec hevc_nvenc -preset p7 -rc vbr -cq {cq} {output}.mp4"
os.system(ffmpeg_command)
-
- endtime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
-
- # save metadata
- metadata = path + '/' + 'hevc_nvenc_compression_' + starttime + '.txt'
- filelist = pd.DataFrame({'input': videofile, 'output': outputs}, index=None)
- filelist.to_csv(metadata, sep ='\t', index=False)
- # add header
- title = f"# VideoPyToolbox compression with hevc_nvenc preset=p7, rc=vbr, cq={cq} \n # started: {starttime} ended: {endtime}"
- with open(metadata, "r+") as textfile:
- original = textfile.read()
- textfile.seek(0)
- textfile.write(title + original)
- textfile.close()
\ No newline at end of file
diff --git a/toolbox/function_concatenate.py b/toolbox/function_concatenate.py
index a25ce0f..ac38f05 100644
--- a/toolbox/function_concatenate.py
+++ b/toolbox/function_concatenate.py
@@ -2,7 +2,7 @@
====================================================================================================
Helper function for the VideoPyToolbox
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
====================================================================================================
@@ -63,12 +63,7 @@ def concat_videos():
# set output directory
#output = os.path.join(videopath , "concatenated", outputfile)
- output = os.path.join(outputdir , "concatenated", outputfile)
-
- try:
- os.mkdir(os.path.dirname(output))
- except:
- pass
+ output = os.path.join(outputdir, outputfile)
# write mylist.txt for ffmpeg
path, _ = os.path.split(filenames[0])
@@ -94,4 +89,4 @@ def concat_videos():
np.savetxt(metadata, concats, fmt = "%s")
#break while loop
- break
+ break
\ No newline at end of file
diff --git a/toolbox/function_custom.py b/toolbox/function_custom.py
index bdb8521..d397d19 100644
--- a/toolbox/function_custom.py
+++ b/toolbox/function_custom.py
@@ -2,7 +2,7 @@
====================================================================================================
Helper function for the VideoPyToolbox
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
====================================================================================================
@@ -12,7 +12,6 @@
import numpy as np # use arrays in concat
from tkinter import filedialog # interactive interface to selet files
from natsort import natsorted, ns # natural sorting of strings with numbers
-from datetime import datetime # get timestamp for filenames
def the_usual_h265():
@@ -37,7 +36,7 @@ def the_usual_h265():
_, name1 = os.path.split(filenames[0])
_, name2 = os.path.split(filenames[-1])
output = input(f"Output filename for {name1} to {name2}: ")
- output = [output + '_h265.mp4'] * len(filenames)
+ output = ['h265_crf12_' + output + '.mp4'] * len(filenames)
# append or create concatenation dataset
try:
@@ -50,18 +49,16 @@ def the_usual_h265():
if next =='n':
# ask output directory
- outputdir =filedialog.askdirectory(title='Choose Output Directory for Concatenation')
+ outputdir =filedialog.askdirectory(title='Choose Output Directory:')
if not outputdir:
print('Please select a valid output directory')
- secondtry = filedialog.askdirectory(title='Choose Output Directory for Concatenation')
+ secondtry = filedialog.askdirectory(title='Choose Output Directory:')
if not secondtry:
return
# set compression
print("HEVC/H265 compression...")
- crf = input("Choose constant rate factor between 0-50: ") or 18
-
- starttime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
+ crf = 12 # recommended lossless
# find unique output names in concats
for outputfile in np.unique(concats[:,1]):
@@ -69,12 +66,7 @@ def the_usual_h265():
filenames = concats[concats[:,1]==outputfile][:,0]
# set output directory
- output = os.path.join(outputdir , "concatenated", outputfile)
-
- try:
- os.mkdir(os.path.dirname(output))
- except:
- pass
+ output = os.path.join(outputdir, outputfile)
# write mylist.txt for ffmpeg
path, _ = os.path.split(filenames[0])
@@ -89,112 +81,6 @@ def the_usual_h265():
ffmpeg_command = f"ffmpeg -y -f concat -safe 0 -i {myfile} -an -vcodec libx265 -crf {crf} {output}"
os.system(ffmpeg_command)
os.remove(myfile)
-
- endtime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
-
- # save metadata
- metadata = outputdir + '/' + 'concat_compression_' + starttime + '.txt'
- np.savetxt(metadata, concats, fmt = "%s")
-
- # add header
- title = f"# VideoPyToolbox concat_compression with libx265 crf={crf} \n # started: {starttime} ended: {endtime}\n "
- with open(metadata, "r+") as textfile:
- original = textfile.read()
- textfile.seek(0)
- textfile.write(title + original)
- textfile.close()
-
- #break while loop
- break
-
-def the_usual_hevc_nvenc():
- '''
- The usual is a custom pipeline to concat and compress video snippets at once. See concat_videos and compress_hevc_nvenc for doing the processing in separate steps.
- '''
-
- next = 'y'
-
- while True:
-
- if next == 'y':
- # select videos to append
- concatlist= filedialog.askopenfilenames(title='Choose Video Files you want to concatenate')
- if not concatlist:
- return
-
- # maintain natural order of strings with numbers
- filenames = list(natsorted(concatlist, alg=ns.IGNORECASE))
-
- # give common output filename
- _, name1 = os.path.split(filenames[0])
- _, name2 = os.path.split(filenames[-1])
- output = input(f"Output filename for {name1} to {name2}: ")
- output = [output + '_h265.mp4'] * len(filenames)
-
- # append or create concatenation dataset
- try:
- concats = np.vstack((concats, np.column_stack((filenames, output))))
- except:
- concats = np.column_stack((filenames, output))
-
- # repeat for other sessions...
- next = input(f"Concatenate more sessions [y/N]: ")
-
- if next =='n':
- # ask output directory
- outputdir =filedialog.askdirectory(title='Choose Output Directory for Concatenation')
- if not outputdir:
- print('Please select a valid output directory')
- secondtry = filedialog.askdirectory(title='Choose Output Directory for Concatenation')
- if not secondtry:
- return
-
- # set compression
- print("HEVC_NVENC compression...")
- cq = input("Choose constant quantization parameter between 0-50: ") or 18
-
- starttime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
-
- # find unique output names in concats
- for outputfile in np.unique(concats[:,1]):
- # get all filenames that correspond to output
- filenames = concats[concats[:,1]==outputfile][:,0]
-
- # set output directory
- output = os.path.join(outputdir , "concatenated", outputfile)
-
- try:
- os.mkdir(os.path.dirname(output))
- except:
- pass
-
- # write mylist.txt for ffmpeg
- path, _ = os.path.split(filenames[0])
- myfile = path + "/mylist.txt"
- with open(myfile, "w+") as textfile:
- for element in filenames:
- _, name = os.path.split(element)
- textfile.write("file " +"'"+ name + "'\n")
- textfile.close()
-
- # concatenate file with re-encoding
- ffmpeg_command = f"ffmpeg -y -f concat -safe 0 -i {myfile} -an -vcodec hevc_nvenc -preset p7 -rc vbr -cq {cq} {output}"
- os.system(ffmpeg_command)
- os.remove(myfile)
-
- endtime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
-
- # save metadata
- metadata = outputdir + '/' + 'concat_compression_' + starttime + '.txt'
- np.savetxt(metadata, concats, fmt = "%s")
-
- # add header
- title = f"# VideoPyToolbox concat_compression with hevc_nvenc preset=p7, rc=vbr, cq={cq}\n # started: {starttime} ended: {endtime}\n"
- with open(metadata, "r+") as textfile:
- original = textfile.read()
- textfile.seek(0)
- textfile.write(title + original)
- textfile.close()
-
+
#break while loop
break
\ No newline at end of file
diff --git a/toolbox/function_ffplay.py b/toolbox/function_ffplay.py
index 4d6196f..96e6225 100644
--- a/toolbox/function_ffplay.py
+++ b/toolbox/function_ffplay.py
@@ -2,7 +2,7 @@
====================================================================================================
Helper function for the VideoPyToolbox
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
====================================================================================================
@@ -16,7 +16,6 @@ def ffplay():
Video player with ffplay and mosaic display
'''
# Choose Video File from Dialog Box
-
videofiles = list(filedialog.askopenfilenames(title='Choose the Video Files you want to play'))
if not videofiles:
return
diff --git a/toolbox/function_mosaic.py b/toolbox/function_mosaic.py
new file mode 100644
index 0000000..71eaa22
--- /dev/null
+++ b/toolbox/function_mosaic.py
@@ -0,0 +1,60 @@
+'''
+====================================================================================================
+Helper function for the VideoPyToolbox
+
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
+
+Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
+====================================================================================================
+'''
+
+import os
+from tkinter import filedialog
+
+def mosaic_video():
+ '''
+ Create Mosaic Videos
+ '''
+ # Choose Video File from Dialog Box
+ videofiles = list(filedialog.askopenfilenames(title='Choose the Video Files to combine'))
+ if not videofiles:
+ return
+
+ outputdir = filedialog.askdirectory(title='Choose Output Directory for Compression')
+ if not outputdir:
+ print('Please select a valid output directory')
+ secondtry = filedialog.askdirectory(title='Choose Output Directory for Concatenation')
+ if not secondtry:
+ return
+ else:
+ outputdir = secondtry
+
+ output = os.path.join(outputdir, 'mosaic_' + os.path.basename(videofiles[0]).split('.')[0])
+
+ if len(videofiles) == 2:
+ ffmpeg_command = f'ffmpeg -i {videofiles[0]} -i {videofiles[1]} -filter_complex "[0:v][1:v]hstack=inputs=2[v];[v]scale=w=1440:h=-1[scaled]" -map "[scaled]" {output}.mp4'
+ os.system(ffmpeg_command)
+
+ elif len(videofiles) == 3:
+ ffmpeg_command = f'ffmpeg -i {videofiles[0]} -i {videofiles[1]} -i {videofiles[2]} -filter_complex "[0:v][1:v][2:v]hstack=inputs=3[v];[v]scale=w=1440:h=-1[scaled]" -map "[scaled]" {output}.mp4'
+ os.system(ffmpeg_command)
+
+ elif len(videofiles) == 4:
+ ffmpeg_command = f'ffmpeg -i {videofiles[0]} -i {videofiles[1]} -i {videofiles[2]} -i {videofiles[3]} -filter_complex ' \
+ f'"[0:v][1:v]hstack=inputs=2[top];[2:v][3:v]hstack=inputs=2[bottom];[top][bottom]vstack=inputs=2[v];[v]scale=w=1440:h=-1[scaled]" -map "[scaled]" {output}.mp4'
+ os.system(ffmpeg_command)
+
+ elif len(videofiles) == 6:
+ ffmpeg_command = f'ffmpeg '\
+ f'-i {videofiles[0]} -i {videofiles[1]} -i {videofiles[2]} -i {videofiles[3]} -i {videofiles[4]} -i {videofiles[5]} '\
+ f'-filter_complex "[0:v][1:v][2:v]hstack=inputs=3[top];[3:v][4:v][5:v]hstack=inputs=3[bottom];[top][bottom]vstack=inputs=2[v];[v]scale=w=1440:h=-1[scaled]" -map "[scaled]" {output}.mp4'
+ os.system(ffmpeg_command)
+
+ elif len(videofiles) == 8:
+ ffmpeg_command = f'ffmpeg '\
+ f'-i {videofiles[0]} -i {videofiles[1]} -i {videofiles[2]} -i {videofiles[3]} -i {videofiles[4]} -i {videofiles[5]} -i {videofiles[6]} -i {videofiles[7]} '\
+ f'-filter_complex "[0:v][1:v][2:v][3:v]hstack=inputs=4[top];[4:v][5:v][6:v][7:v]hstack=inputs=4[bottom];[top][bottom]vstack=inputs=2[v];[v]scale=w=1440:h=-1[scaled]" -map "[scaled]" {output}.mp4'
+ os.system(ffmpeg_command)
+
+ else:
+ print("Invalid number of videos! (valid: 2, 3, 4, 6 or 8")
diff --git a/toolbox/function_rename.py b/toolbox/function_rename.py
deleted file mode 100644
index 1f91e04..0000000
--- a/toolbox/function_rename.py
+++ /dev/null
@@ -1,49 +0,0 @@
-'''
-====================================================================================================
-Helper function for the VideoPyToolbox
-
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
-
-Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
-====================================================================================================
-'''
-
-import os # paths and terminal commands
-from tkinter import filedialog # interactive interface to selet files
-
-def batch_rename():
- '''
- This function reads a list of files and appends/prepends string filename
- '''
-
- choice = 'y'
-
- while True:
- if choice == 'y':
- # choose batch of files to rename
- renamelist = filedialog.askopenfilenames(title='Choose Video Batch to rename')
- if not renamelist:
- return
-
- batch = list(renamelist)
- dir_list = [os.path.dirname(file)for file in batch]
- name_list = [os.path.basename(file).split('.')[0] for file in batch]
- suffix_list = [os.path.basename(file).split('.')[1] for file in batch]
-
- # ask for
- prepend = input(f"Prepend string for videos ..._{name_list[0]}: ")
- append = input(f"Append string for videos {name_list[0]}_... : ")
-
- #edit new file names
- newnames = [prepend+'_'+name+'_'+append+'.'+suffix for name, suffix in zip(name_list, suffix_list)]
- newbatch = [dir+'/'+file for dir,file in zip(dir_list,newnames)]
-
- # rename files
- for i in range(len(batch)):
- os.rename(batch[i], newbatch[i])
-
- # reset loop
- choice = input(f"Rename another Video Batch [y/N]: ")
-
- else:
- break
\ No newline at end of file
diff --git a/toolbox/function_split.py b/toolbox/function_split.py
index 8053355..b4ac4d0 100644
--- a/toolbox/function_split.py
+++ b/toolbox/function_split.py
@@ -2,7 +2,7 @@
====================================================================================================
Helper function for the VideoPyToolbox
-MIT License Copyright (c) 2021 GuillermoHidalgoGadea.com
+MIT License Copyright (c) 2022 GuillermoHidalgoGadea.com
Sourcecode: https://github.com/Guillermo-Hidalgo-Gadea/VideoPyToolbox
====================================================================================================
@@ -32,7 +32,7 @@ def trim_split_h265():
splitlist = [os.path.basename(filename) for filename in splitlist]
# placeholders
- output = ['trim_' + filename for filename in splitlist]
+ output = ['trim_' + filename.split('.')[0] + '.mp4' for filename in splitlist]
start = ['00:00:00.000'] * len(splitlist)
end = ['00:00:00.000'] * len(splitlist)
@@ -71,8 +71,9 @@ def trim_split_h265():
open_file(filename)
second_check = input('Is the format correct? [y/n] ')
if "n" in second_check:
- return
+ splitlist = []
else:
+ crf = input("Choose constant rate factor between 0-50: ") or 0
starttime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
# loop over cases in file
for case in range(len(splitlist)):
@@ -84,12 +85,12 @@ def trim_split_h265():
end = row[3]
# split with re-encoding
- ffmpeg_command = f"ffmpeg -y -i {original} -ss {start} -to {end} -vcodec libx265 -crf 0 {output}"
+ ffmpeg_command = f"ffmpeg -y -i {original} -ss {start} -to {end} -vcodec libx265 -crf {crf} {output}"
os.system(ffmpeg_command)
endtime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
# add instructions
- header = f"# started: {starttime} ended: {endtime}, re-encoded libx265 crf=0\n"
+ header = f"# started: {starttime} ended: {endtime}, re-encoded libx265 crf={crf}\n"
with open(filename, "r+") as textfile:
original = textfile.read()
textfile.seek(0)
@@ -146,7 +147,7 @@ def trim_split_hevc_nvenc():
open_file(filename)
second_check = input('Is the format correct? [y/n] ')
if "n" in second_check:
- return
+ splitlist = []
else:
starttime = datetime.now().strftime("%Y_%m_%d-%I-%M-%S")
# loop over cases in file