Code Monkey home page Code Monkey logo

hclivess / videer Goto Github PK

View Code? Open in Web Editor NEW
17.0 3.0 0.0 117.92 MB

FFmpeg GUI with AviSynth support for deinterlacing and profile configuration that can be used in frameserving. Created as a replacement for inflexible batch files that do not allow multiple encodings at the same time easily and make configuration complicated.

License: MIT License

Python 98.20% Batchfile 1.80%
ffmpeg avisynth gui video encoding editing frameserving x264 x265 aac

videer's Introduction

videer

FFmpeg batch GUI with AviSynth support for deinterlacing and profile configuration that can be used in frameserving. Created as a replacement for inflexible batch files that do not allow multiple encodings at the same time easily. Videer integrates QTGMC, which provides much smoother results than ffmpeg's yadif, see for yourself. QTGMC is the best deinterlacer in existence. Including AI and DaVinci Studio.

Why

FFmpeg is a superior command line video encoding tool. Videer serves as a GUI for it.

Notice

If you want to deinterlace AVC (x264) video of a matroska file, running Videer with raw transcode first and ffms2 on is optimal.

New features:

  • Multithreading using SetFilterMTMode
  • AviSynth+
  • 64bit Implementation
  • Matroska format as it is the only one to support pgssub
  • CUDA GPU acceleration support

Requirements:

  • FFmpeg (in system path)
  • To use AviSynth+ or deinterlacing, you will need AviSynth+ installed
  • No need to install plugins, all are bundled
  • pip install -r requirements.txt

Preview:

thumb

videer's People

Contributors

hclivess avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

videer's Issues

Not working

Just tried to run the exe from the .zip version and get this -

Traceback (most recent call last):
  File "g:\-----N~1\TONYSA~1\videer\videer.py", line 619, in <module>
  File "g:\-----N~1\TONYSA~1\videer\tkinter\__init__.py", line 2071, in wm_iconbitmap
_tkinter.TclError: bitmap "icon.ico" not defined

Anything come to mind?

[REQ] FFMPEG's video capture (as input) support

Hi there,
1st of all thanks for your work !

Even if it probably don't falls within the project scope, it would be extremely interesting to implement FFMPEG video capture as input.

We've got inspired by How to capture, deinterlace, and encode analog video git which proposes an interesting method on how to set FFMPEG for video capture through dedicated hardware.

The most interesting (and recently made) resource is probably Video Capture wrapper for FFMPEG with Software/Hardware decoding and there's also vcr or - a bit dated - git where "video capture, live feed display, and recording to an AVI file when recording activated"_ where implemented through FFMPEG in Video capture and archiving utility for Linux.

If it helps to let you implement it easier, here are some simple FFMPEG capture scripts to get inspiration from:

Last but not least capture-device-list or ffmpeg-devices may also help.

Hope that inspires !

Can you provide a full process tutorial?

I don't have any experience in deinterlacing.I followed the online AviSynth+tutorial successfully, but the speed was too slow and it didn't use the current computer resources at all.

After countless searches, I found your VIDEER project, but I have no idea how to use it.
So when you have time,plerse!

mpeg-4 import code (ffmpeg wrapper)

import threading
import tkinter as tk
import tkinter.messagebox as messagebox
import tkinter.filedialog as fd
import logging.handlers
import subprocess


class CreateAvs():
    def __init__(self, infile):
        with open("parameters.avs", "w") as avsfile:
            avsfile.write('Loadplugin("plugins/masktools2.dll")')
            avsfile.write('\n')
            avsfile.write('Loadplugin("plugins/mvtools2.dll")')
            avsfile.write('\n')
            avsfile.write('Loadplugin("plugins/nnedi3.dll")')
            avsfile.write('\n')
            avsfile.write('Loadplugin("plugins/ffms2.dll")')
            avsfile.write('\n')
            avsfile.write('Loadplugin("plugins/RgTools.dll")')
            avsfile.write('\n')
            avsfile.write('Import("plugins/QTGMC.avsi")')
            avsfile.write('\n')
            avsfile.write('Import("plugins/Zs_RF_Shared.avsi")')
            avsfile.write('\n')
            avsfile.write(f'FFmpegSource2("{infile}", vtrack = -1, atrack = -1)')
            avsfile.write('\n')
            avsfile.write('ConvertToYV24(matrix="rec709")')

            if app.avisynth_extras.get("1.0", tk.END).strip():
                avsfile.write('\n')
                avsfile.write(app.avisynth_extras.get("1.0", tk.END))

            if app.deinterlace_var.get():
                avsfile.write('\n')
                avsfile.write('QTGMC(Preset="Slower")')

class Application(tk.Frame):
    def __init__(self, master=None):

        super().__init__(master)
        self.master = master

        self.grid()
        self.create_widgets()
        self.file_queue = []

    def do_files(self, files, info_box):

        def create_command(file):
            command = []
            command.append(f'ffmpeg.exe -hide_banner')
            if self.use_avisynth_var.get():
                command.append(f'-i "parameters.avs" -y')
                CreateAvs(infile=file)
            else:
                command.append(f'-i "{file}" -y')

            command.append(f'-c:v {self.codec_var.get()}')
            command.append(f'-preset {self.preset_get(self.speed.get())}')
            command.append(f'-crf {self.crf.get()}')
            command.append(f'-c:a {self.audio_codec_var.get()}')
            command.append(f'-b:a {self.abr.get()}k')
            command.append('-movflags')
            command.append('+faststart')
            command.append('-bf 2')
            command.append('-flags')
            command.append('+cgop')
            command.append('-pix_fmt yuv420p')
            command.append(f'-f mp4 "{file}_{self.crf.get()}{self.codec_var.get()}_{self.audio_codec_var.get()}{self.abr.get()}.mp4"')
            command.append(f'{self.extras_value.get()}')
            return " ".join(command)

        for file in files:
            info_box.configure(state='normal')
            info_box.insert(tk.INSERT, f"Processing {file.split('/')[-1]}\n")
            info_box.configure(state='disabled')

            command_line = create_command(file)
            print(f"Executing {command_line}")

            rootLogger.info(f"Working on {file}")
            pipe = subprocess.Popen(command_line, shell=True, stdout=subprocess.PIPE).stdout
            output = pipe.read().decode()
            pipe.close()
            rootLogger.info(output)

            info_box.configure(state='normal')
            info_box.insert(tk.INSERT, f"Finished {file}\n")
            info_box.configure(state='disabled')

        messagebox.showinfo(title="Info", message="Queue finished")


    def runfx(self):

        top = tk.Toplevel()
        top.title("Info")
        info_box = tk.Text(top, width=100)
        info_box.grid(row=0, pady=0)
        info_box.configure(state='disabled')

        file_thread = threading.Thread(target=self.do_files, args=(self.file_queue, info_box, ))
        file_thread.start()

    def select_file(self, var):
        files = fd.askopenfilename(multiple=True, initialdir="", title="Select file")
        del self.file_queue[:]
        for file in files:
            self.file_queue.append(file)
        var.set(self.file_queue)

    def set_avisynth_true(self,click):
        if not self.deinterlace_var.get():
            self.use_avisynth_var.set(True)

    def set_deinterlace_false(self,click):
        if self.use_avisynth_var.get():
            self.deinterlace_var.set(False)

    def exit(self):
        self.stop_process()
        self.master.destroy()

    def stop_process(self, announce=False):
        pipe = subprocess.Popen("Taskkill /IM ffmpeg.exe /F", shell=True, stdout=subprocess.PIPE).stdout
        print("Stop signal sent")
        output = pipe.read().decode()
        if not output:
            output = "No relevant process found"
        if announce:
            messagebox.showinfo(title="Info", message=output)
        pipe.close()

    def preset_get(self, number: int):

        if number == 0:
            preset = "veryslow"
        elif number == 1:
            preset = "slower"
        elif number == 2:
            preset = "slow"
        elif number == 4:
            preset = "faster"
        elif number == 5:
            preset = "fast"
        elif number == 6:
            preset = "fastest"
        else:
            preset = "medium"

        return preset

    def create_widgets(self):

        self.deinterlace_var = tk.BooleanVar()
        self.deinterlace_var.set(False)
        self.deinterlace_button = tk.Checkbutton(self, text="Deinterlace", variable=self.deinterlace_var)
        self.deinterlace_button.bind("<Button-1>", self.set_avisynth_true)
        self.deinterlace_button.grid(row=0, column=1, sticky='w', pady=5, padx=5)

        self.use_avisynth_var = tk.BooleanVar()
        self.use_avisynth_var.set(False)
        self.use_avisynth_button = tk.Checkbutton(self, text="Use AviSynth", variable=self.use_avisynth_var)
        self.use_avisynth_button.bind("<Button-1>", self.set_deinterlace_false)
        self.use_avisynth_button.grid(row=1, column=1, sticky='w', pady=5, padx=5)

        self.audio_codec_label = tk.Label(self)
        self.audio_codec_label["text"] = "Audio Codec: "
        self.audio_codec_var = tk.StringVar()
        self.audio_codec_var.set("aac")
        self.audio_codec_label.grid(row=3, column=0, sticky='', pady=5, padx=5)

        self.audio_codec_button = tk.Radiobutton(self, text="LAME MP3", variable=self.audio_codec_var, value="libmp3lame")
        self.audio_codec_button.grid(row=3, column=1, sticky='w', pady=5, padx=5)
        self.audio_codec_button = tk.Radiobutton(self, text="AAC", variable=self.audio_codec_var, value="aac")
        self.audio_codec_button.grid(row=4, column=1, sticky='w', pady=5, padx=5)
        self.audio_codec_button = tk.Radiobutton(self, text="Opus", variable=self.audio_codec_var, value="libopus")
        self.audio_codec_button.grid(row=5, column=1, sticky='w', pady=5, padx=5)

        self.codec_label = tk.Label(self)
        self.codec_label["text"] = "Video Codec: "
        self.codec_var = tk.StringVar()
        self.codec_var.set("libx265")
        self.codec_label.grid(row=6, column=0, sticky='', pady=5, padx=5)

        self.codec_button = tk.Radiobutton(self, text="x264", variable=self.codec_var, value="libx264")
        self.codec_button.grid(row=6, column=1, sticky='w', pady=5, padx=5)
        self.codec_button = tk.Radiobutton(self, text="x265", variable=self.codec_var, value="libx265")
        self.codec_button.grid(row=7, column=1, sticky='w', pady=5, padx=5)
        self.codec_button = tk.Radiobutton(self, text="V9", variable=self.codec_var, value="libvpx-vp9")
        self.codec_button.grid(row=8, column=1, sticky='w', pady=5, padx=5)

        self.speed = tk.Scale(self, from_=0, to=6, orient=tk.HORIZONTAL, label="Encoding Speed")
        self.speed.grid(row=9, column=1, sticky='WE', pady=5, padx=5)
        self.speed.set(3)

        self.infile_value = tk.StringVar()
        self.infile_value.set("c:/test.avi")

        self.infile_label = tk.Label(self)
        self.infile_label["text"] = "Input File(s): "
        self.infile_label.grid(row=15, column=0, sticky='', pady=5, padx=5)
        self.infile_button = tk.Button(self, text="Select", fg="green", command=lambda: self.select_file(self.infile_value))
        self.infile_button.grid(row=15, column=2, sticky='WE', padx=5, pady=(5))

        self.infile = tk.Entry(self, textvariable=self.infile_value, width=70)
        self.infile.grid(row=15, column=1, sticky='W', padx=5)

        self.crf = tk.Scale(self, from_=0, to=51, orient=tk.HORIZONTAL, label="Video CRF")
        self.crf.grid(row=16, column=1, sticky='WE', pady=5, padx=5)
        self.crf.set(24)

        self.abr = tk.Scale(self, from_=0, to=384, orient=tk.HORIZONTAL, label="Audio ABR", resolution=16)
        self.abr.grid(row=17, column=1, sticky='WE', pady=5, padx=5)
        self.abr.set(128)

        self.extras_label = tk.Label(self)
        self.extras_label["text"] = "FFmpeg Extras: "
        self.extras_label.grid(row=18, column=0, sticky='', padx=5)
        self.extras_value = tk.StringVar()
        self.extras_value.set("")
        self.extras = tk.Entry(self, textvariable=self.extras_value, width=70)
        self.extras.grid(row=18, column=1, sticky='W', pady=5, padx=5)

        self.avisynth_extras_label = tk.Label(self)
        self.avisynth_extras_label["text"] = "AviSynth Extras: "
        self.avisynth_extras_label.grid(row=19, column=0, sticky='', padx=5)
        self.avisynth_extras = tk.Text(self, height=2, width=30)
        self.avisynth_extras.grid(row=19, column=1, sticky='WE', pady=5, padx=5)
        #self.avisynth_extras.insert(tk.END, "Just a text Widget\nin two lines\n")

        self.run = tk.Button(self, text="Run", fg="green", command=lambda: self.runfx())
        self.run.grid(row=20, column=1, sticky='WE', padx=5)

        self.stop = tk.Button(self, text="Stop", fg="red", command=lambda: self.stop_process(True))
        self.stop.grid(row=21, column=1, sticky='WE', padx=5)

        self.quit = tk.Button(self, text="Quit", fg="red", command=self.exit)
        self.quit.grid(row=22, column=1, sticky='WE', padx=5, pady=(0,5))


if __name__ == "__main__":
    root = tk.Tk()
    root.wm_title("videer")
    #operations = Operations()

    logFormatter = logging.Formatter("%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s]  %(message)s")
    rootLogger = logging.getLogger()
    rootLogger.setLevel(logging.INFO)
    fileHandler = logging.FileHandler(f"log.log")
    fileHandler.setFormatter(logFormatter)
    rootLogger.addHandler(fileHandler)
    consoleHandler = logging.StreamHandler()
    consoleHandler.setFormatter(logFormatter)
    rootLogger.addHandler(consoleHandler)

    app = Application(master=root)
    app.mainloop()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.