Create an animated image feature for the video editing application

It seems like there are lots of people reading this video editing project and share this project with their friends which has really encouraged me to continue developing this project. There are a few of you that ask me to include a few new features into this application and I will do that but for now, do allow me to tidy up the user interface for this project first before we proceed further.

In this chapter, we will create the input box which will receive the time duration input which then will be used to extract an animated image from a video. The user will enter the starting time where he wants the program to start recording the animated image and the total second he wants the animated image to play from that starting time. Besides that, I have also included a counter which will be used to name the new video or the animated image file. If you have entered a valid digit inside the time input box under the animated image part of the application then only the animated image with the selected size will be created. Otherwise the new video will be created as usual. Below is the entire program.

from tkinter import *
from tkinter import filedialog
import os
import subprocess
import tkinter.ttk as tk

win = Tk() # Create tk instance
win.title("NeW Vid") # Add a title
win.resizable(0, 0) # Disable resizing the GUI
win.configure(background='white') # change background color

mainframe = Frame(win) # create a frame
mainframe.pack()

eqFrame = Frame(win) # create eq frame
eqFrame.pack(side = TOP, fill=X)

animatedFrame = Frame(win) # create animated frame
animatedFrame.pack(side = TOP, fill=X)

buttonFrame = Frame(win) # create a button frame
buttonFrame.pack(side = BOTTOM, fill=X, pady = 6)

# Create a label and scale box for eq
contrast_variable = DoubleVar()
contrast = Scale(eqFrame, from_=float(-2.00), to=float(2.00), orient=HORIZONTAL, label="CONTRAST", digits=3, resolution=0.01, variable=contrast_variable)
contrast.set(1)
contrast.pack(side = LEFT)
brightness_variable = DoubleVar()
brightness = Scale(eqFrame, from_=float(-1.00), to=float(1.00), orient=HORIZONTAL, label="BRIGHTNESS", digits=3, resolution=0.01, variable=brightness_variable)
brightness.pack(side = LEFT)
saturation_variable = DoubleVar()
saturation = Scale(eqFrame, from_=float(0.00), to=float(3.00), orient=HORIZONTAL, label="SATURATION", digits=3, resolution=0.01, variable=saturation_variable)
saturation.set(1)
saturation.pack(side = LEFT)
gamma_variable = DoubleVar()
gamma = Scale(eqFrame, from_=float(0.10), to=float(10.00), orient=HORIZONTAL, label="GAMMA", digits=4, resolution=0.01, variable=gamma_variable)
gamma.set(1)
gamma.pack(side = LEFT)
loop_variable = DoubleVar()
loop = Scale(eqFrame, from_=float(0), to=float(10), orient=HORIZONTAL, label="REPEAT", digits=2, resolution=1, variable=loop_variable)
loop.pack(side = LEFT)
fr_variable = DoubleVar()
fr = Scale(eqFrame, from_=float(9), to=float(60), orient=HORIZONTAL, label="FPS", digits=2, resolution=1, variable=fr_variable)
fr.set(24)
fr.pack(side = LEFT)

#create animated gif
anime = Label(animatedFrame, text="Create Animated Image from Video   ")
anime.pack(side = TOP)
anime.pack(side = LEFT)

from_ = Label(animatedFrame, text="Start From (hour : minute : second)  ")
from_.pack(side = BOTTOM)
from_.pack(side = LEFT)
from_t_h_varable = StringVar()
from_t_h = Entry(animatedFrame, width=3, textvariable=from_t_h_varable)
from_t_h.pack(side=BOTTOM)
from_t_h.pack(side=LEFT)
from_m = Label(animatedFrame, text=" : ")
from_m.pack(side = BOTTOM)
from_m.pack(side = LEFT)
from_t_m_varable = StringVar()
from_t_m = Entry(animatedFrame, width=3,textvariable=from_t_m_varable)
from_t_m.pack(side=BOTTOM)
from_t_m.pack(side=LEFT)
from_s = Label(animatedFrame, text=" : ")
from_s.pack(side = BOTTOM)
from_s.pack(side = LEFT)
from_t_s_varable = StringVar()
from_t_s = Entry(animatedFrame, width=3,textvariable=from_t_s_varable)
from_t_s.pack(side=BOTTOM)
from_t_s.pack(side=LEFT)

to_ = Label(animatedFrame, text="  To (in second)  ")
to_.pack(side = BOTTOM)
to_.pack(side = LEFT)
#to_t_h_varable = StringVar()
#to_t_h = Entry(animatedFrame, width=3,textvariable=to_t_h_varable)
#to_t_h.pack(side=BOTTOM)
#to_t_h.pack(side=LEFT)
#to_m = Label(animatedFrame, text=" : ")
#to_m.pack(side = BOTTOM)
#to_m.pack(side = LEFT)
#to_t_m_varable = StringVar()
#to_t_m = Entry(animatedFrame, width=3,textvariable=to_t_m_varable)
#to_t_m.pack(side=BOTTOM)
#to_t_m.pack(side=LEFT)
#to_s = Label(animatedFrame, text=" : ")
#to_s.pack(side = BOTTOM)
#to_s.pack(side = LEFT)
to_t_s_varable = StringVar()
to_t_s = Entry(animatedFrame, width=3,textvariable=to_t_s_varable)
to_t_s.pack(side=BOTTOM)
to_t_s.pack(side=LEFT)

# Create a combo box
vid_size = StringVar() # create a string variable
preferSize = tk.Combobox(mainframe, textvariable=vid_size) 
preferSize['values'] = (1920, 1280, 854, 640) # video width in pixels
preferSize.current(0) # select item one 
preferSize.pack(side = LEFT)

# Create a combo box
vid_format = StringVar() # create a string variable
preferFormat = tk.Combobox(mainframe, textvariable=vid_format) 
preferFormat['values'] = ('.mp4', '.webm', '.avi', '.wmv', '.mpg', '.ogv') # video format
preferFormat.current(0) # select item one 
preferFormat.pack(side = LEFT)

removeAudioVal = IntVar()
removeAudio = tk.Checkbutton(mainframe, text="Remove Audio", variable=removeAudioVal)
removeAudio.pack(side = LEFT, padx=3)

newAudio = IntVar()
aNewAudio = tk.Checkbutton(mainframe, text="New Audio", variable=newAudio)
aNewAudio.pack(side = LEFT, padx=2)

count = 0 # counter uses to create multiple videos

# Open a video file
def openVideo():
        
        fullfilename = filedialog.askopenfilename(initialdir="/", title="Select a file", filetypes=[("Video file", "*.mp4; *.avi ")]) # select a video file from the hard drive
        audiofilename = ''
        if(newAudio.get() == 1):
                audiofilename = filedialog.askopenfilename(initialdir="/", title="Select a file", filetypes=[("Audio file", "*.wav; *.ogg ")]) # select a new audio file from the hard drive
            
        if(fullfilename != ''): 
                global count # access the global count variable
                scale_vid = preferSize.get() # retrieve value from the comno box
                new_size = str(scale_vid)
                dir_path = os.path.dirname(os.path.realpath(fullfilename))

                file_extension = fullfilename.split('.')[-1] # extract the video format from the original video

                os.chdir(dir_path) # change the directory to the original file's directory

                f = '_new_vid_' + new_size  + '.' + file_extension # the new output file name
                f2 = str(count)+f # second video
                f_gif = str(count) + f + '.gif' # create animated gif

                count += 1 # increase video counter for new video

                # create animated image from vieo
                animi_from_hour = from_t_h_varable.get()
                animi_from_minute = from_t_m_varable.get()
                animi_from_second = from_t_s_varable.get()

                #animi_to_hour = to_t_h_varable.get()
                #animi_to_minute = to_t_m_varable.get()
                animi_to_second = to_t_s_varable.get()

                # if the time areas are not empty and they have a digit then only the animated gif will be created 
                if((animi_from_hour != '' and animi_from_hour.isdigit()) and (animi_from_minute != '' and animi_from_minute.isdigit()) and (animi_from_second != '' and animi_from_second.isdigit()) and (animi_to_second != '' and animi_to_second.isdigit())):
                        subprocess.call(['ffmpeg', '-i', fullfilename, '-vf', 'scale=' + new_size + ':-1', '-y', f]) # resize video
                        subprocess.call(['ffmpeg', '-i', f, '-ss', animi_from_hour + ':' + animi_from_minute + ':' + animi_from_second, '-t',  animi_to_second, '-y', f_gif]) # create animated gif starting from 2 minutes and 30 seconds to the end
                        os.remove(f)
                        return 0

                # video editing part start here
                noAudio = removeAudioVal.get() # get the checkbox state for audio 

                subprocess.call(['ffmpeg', '-stream_loop', str(loop_variable.get()), '-i', fullfilename, '-vf', 'scale=' + new_size + ':-1', '-y', '-r', str(fr_variable.get()), f]) # resize, speedup and loop the video with ffmpeg
               
                if(noAudio == 1):
                        subprocess.call(['ffmpeg', '-i', f, '-c', 'copy', '-y', '-an', f2]) # remove audio from the original video
                
                if(audiofilename != '' and noAudio == 1 and newAudio.get() == 1):
                        subprocess.call(['ffmpeg', '-i', f2, '-i', audiofilename, '-shortest', '-c:v', 'copy', '-c:a', 'aac', '-b:a', '256k', '-y', f]) # add audio to the original video, trim either the audio or video depends on which one is longer

                subprocess.call(['ffmpeg', '-i', f, '-vf', 'eq=contrast=' + str(contrast_variable.get()) +':brightness='+ str(brightness_variable.get()) +':saturation=' + str(saturation_variable.get()) +':gamma='+ str(gamma_variable.get()), '-y', f2]) # adjust the saturation, gamma, contrast and brightness of video
                f3 = f + vid_format.get() # The final video format

                if(f3.split('.')[-1] != f2.split('.')[-1]):
                        subprocess.call(['ffmpeg', '-i', f2, '-y', f3]) # converting the video with ffmpeg
                        os.remove(f2) # remove two videos
                        os.remove(f)
                else:
                        os.remove(f) # remove a video

action_vid = tk.Button(buttonFrame, text="Open Video", command=openVideo)
action_vid.pack(fill=X)

win.mainloop()

Below is the new user interface of the video editing software.

The animated image user interface

Here is the animated image from part of the wild life video.

http://islandstropicalman.tumblr.com/post/182216728822/animated-gif

The gif file created from the video can be very large so be very very careful and try to reduce the duration of the animated image as much as possible.

Leave a Reply

avatar
  Subscribe  
Notify of