import os from tkinter import * from tkinter import ttk, messagebox, filedialog import tkinter import sys import imageio import random import re import struct import time import webbrowser from itertools import chain, repeat import subprocess import pkg_resources #Note that this program is optimised for only windows, for other systems you have to change the ffmpeg path. required = {'imageio', 'imageio-ffmpeg'} installed = {pkg.key for pkg in pkg_resources.working_set} missing = required - installed missingset=[*missing,] if missing: res=messagebox.askquestion("Module Error","Some modules are not installed, do you want to download and install them?") if res=="yes": for x in range(len(missingset)): y=missingset[x] subprocess.Popen('python -m pip install '+y) pass elif res=="no": print("Error: Required modules not available! \nWithout the modules you can't use this program. Please install them first!") sys.exit() def resource_path0(relative_path): base_path = getattr( sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) return os.path.join(base_path, relative_path) #ffmpeg path: python_folder=os.path.dirname(sys.executable) path=python_folder.replace(os.sep, '/') global resource resource=resource_path0(path+"/Lib/site-packages/imageio_ffmpeg/binaries/ffmpeg-win64-v4.2.2.exe") def openfile(): global file file=tkinter.filedialog.askopenfilename(filetypes =[('Video', ['*.mp4','*.gif','*.avi','*.gif','*.mov','*.mkv','*wmv']),('All Files', '*.*')]) if(len(file)>1): LocationError.config(text=file, fg="green") OpeningFile['text']='Open Again' OpeningFile['bg']='#D0CECE' else: LocationError.config(text="Choose Video To Datamosh", fg="red") OpeningFile['text']='OPEN' OpeningFile['bg']='#82CC6C' def convertffmpeg(inputpath): Wait.config(text="Converting the Video...", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() fps=30 targetformat='.avi' os.path.dirname(sys.executable) outputpath=os.path.splitext(inputpath)[0]+'_datamoshed'+targetformat subprocess.call(f'"{resource}" -loglevel error -y -i "{inputpath}" -crf 0 -bf 0 -r {fps} "{outputpath}"', shell=True) try: Wait.config(text="Applying Effect: Classic", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() Datamoshclassic(outputpath,inputpath) except: messagebox.showerror("FAILED","The video file or the input data have \n some issues!") Wait.place_forget() os.remove(outputpath) datamoshbtn['state']=NORMAL root.config(cursor="") def convert(inputpath,targetformat): global outputpath try: Wait.config(text="Converting the Video...", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() outputpath=os.path.splitext(inputpath)[0]+'_datamoshed'+targetformat reader=imageio.get_reader(inputpath) fps=reader.get_meta_data()['fps'] writer= imageio.get_writer(outputpath, fps=fps) for frames in reader: writer.append_data(frames) #to get detailed logs of conversions, remove the comment in the next 2 lines #print(f'Frame {frames}') #print("Converted") writer.close() try: Datamosh(outputpath) except: pass except: messagebox.showerror("FAILED","The video file or the input data have \n some issues!") Wait.place_forget() os.remove(outputpath) datamoshbtn['state']=NORMAL root.config(cursor="") def validate(): try: float(Countframe.get()) float(Positframe.get()) int(firstframes.get()) float(killframe.get()) x=float(killframe.get()) if x>1: var4.set(1) except ValueError: messagebox.showerror("Invalid Input","Please enter valid data") sys.exit() def checkexist(file): mode = modechoices.get() tformat=exportbox.get() f=os.path.splitext(file)[0] exfile=f+"_datamoshed"+"-"+mode+"_datamoshed."+tformat exfile2=f+"_datamoshed"+"-classic_datamoshed.avi" if os.path.exists(exfile): warn=messagebox.askquestion("Warning","Do you want to replace the old file?") if warn=='yes': os.remove(exfile) pass elif warn=='no': os.kill(checkesist()) elif os.path.exists(exfile2): warn2=messagebox.askquestion("Warning","Do you want to replace the avi file?") if warn2=='yes': pass os.remove(exfile2) elif warn2=='no': os.kill(checkesist()) pass def Step1(): try: if (len(file)>=1): Wait.place(relx=0.5,rely=0.85,anchor='center') root.update() extension=os.path.splitext(file)[1] validate() checkexist(file) datamoshbtn['state']=DISABLED root.config(cursor="") choice = modechoices.get() if(choice==modes[7]): if extension==".mp4": convertffmpeg(file) else: targetformat=".mp4" convert(file,targetformat) convertffmpeg(file) else: targetformat=".avi" convert(file,targetformat) else: messagebox.showerror("","Please choose the video again!") except: datamoshbtn['state']=NORMAL root.config(cursor="") Wait.place_forget() messagebox.showerror("","Please choose the video file again!") def Datamoshclassic(filename,mainfile): global outf END_FRAME_HEX = b'00dc' I_FRAME_HEX = b'\x00\x01\xb0' fps=30 outx=os.path.basename(filename).split('.')[0] outpath=os.path.dirname(mainfile) outf=outpath+"/"+outx+"-classic_datamoshed.avi" def main2(filename, effect_sec_list, p_frames_mult): magic(effect_sec_list, p_frames_mult) out=outpath+"/"+outx+"-classic.mp4" subprocess.call(f'"{resource}" -loglevel error -y -i "{outf}" "{out}"', shell=True) os.remove(filename) export(out) export2=exportbox.get() if(export2==exportchoices[0]): pass else: os.remove(outf) def magic(effect_sec_list, p_frames_mult): with open(filename, 'rb') as in_file, open(outf, 'wb') as out_file: frames = split_file(in_file, END_FRAME_HEX) for index, frame in enumerate(frames): if not is_need_effect_here(index / fps, effect_sec_list): out_file.write(frame + END_FRAME_HEX) continue if not is_iframe(frame): out_file.write((frame + END_FRAME_HEX) * p_frames_mult) def split_file(fp, marker, blocksize=4096): buffer = b'' for block in iter(lambda: fp.read(blocksize), b''): buffer += block while True: markerpos = buffer.find(marker) if markerpos == -1: break yield buffer[:markerpos] buffer = buffer[markerpos + len(marker):] yield buffer def is_need_effect_here(curr_sec, effect_sec_list): return any(start < curr_sec < end for start, end in effect_sec_list) def is_iframe(frame): return frame[5:8] == I_FRAME_HEX start=float(firstframes.get()) make=float(Countframe.get()) timer=int(Positframe.get()) main2(filename,[(start,make)],timer) def Datamosh(Inputfile): global fileout checkinput=os.path.splitext(file)[0]+"_datamoshed.avi" if os.path.exists(checkinput): filein = Inputfile countframes = int(Countframe.get()) positframes = int(Positframe.get()) firstframe = int(firstframes.get()) choice = modechoices.get() kill = float(killframe.get()) if(choice==modes[0]): mode="bloom" elif(choice==modes[1]): mode="invert" elif(choice==modes[2]): mode="jiggle" elif(choice==modes[3]): mode="overlap" elif(choice==modes[4]): mode="pulse" elif(choice==modes[5]): mode="reverse" elif(choice==modes[6]): mode="random" else: messagebox.showerror("Error!","Please Select the Correct Mode!") os.remove(outputpath) Wait.place_forget() datamoshbtn['state']=NORMAL root.config(cursor="") os.kill(Datamosh()) if filein is None or os.path.exists(filein) == False: messagebox.showerror("Internal Error!","Input File is Missing!") Wait.place_forget() os.remove(outputpath) datamoshbtn['state']=NORMAL os.kill(Datamosh()) root.config(cursor="") temp_nb = random.randint(10000, 99999) temp_dir = "temp-" + str(temp_nb) temp_hdrl = temp_dir +"/hdrl.bin" temp_movi = temp_dir +"/movi.bin" temp_idx1 = temp_dir +"/idx1.bin" os.mkdir(temp_dir) def constrain(val, min_val, max_val): return min(max_val, max(min_val, val)) def bstream_until_marker(bfilein, bfileout, marker=0, startpos=0): chunk = 1024 filesize = os.path.getsize(bfilein) if marker : marker = str.encode(marker) with open(bfilein,'rb') as rd: with open(bfileout,'ab') as wr: for pos in range(startpos, filesize, chunk): rd.seek(pos) buffer = rd.read(chunk) if marker: if buffer.find(marker) > 0 : marker_pos = re.search(marker, buffer).start() marker_pos = marker_pos + pos split = buffer.split(marker, 1) wr.write(split[0]) return marker_pos else: wr.write(buffer) else: wr.write(buffer) movi_marker_pos = bstream_until_marker(filein, temp_hdrl, "movi") idx1_marker_pos = bstream_until_marker(filein, temp_movi, "idx1", movi_marker_pos) bstream_until_marker(filein, temp_idx1, 0, idx1_marker_pos) with open(temp_movi,'rb') as rd: chunk = 1024 filesize = os.path.getsize(temp_movi) frame_table = [] for pos in range(0, filesize, chunk): rd.seek(pos) buffer = rd.read(chunk) for m in (re.finditer(b'\x30\x31\x77\x62', buffer)): if audio : frame_table.append([m.start() + pos, 'sound']) for m in (re.finditer(b'\x30\x30\x64\x63', buffer)): frame_table.append([m.start() + pos, 'video']) frame_table.sort(key=lambda tup: tup[0]) l = [] l.append([0,0, 'void']) max_frame_size = 0 for n in range(len(frame_table)): if n + 1 < len(frame_table): frame_size = frame_table[n + 1][0] - frame_table[n][0] else: frame_size = filesize - frame_table[n][0] max_frame_size = max(max_frame_size, frame_size) l.append([frame_table[n][0],frame_size, frame_table[n][1]]) clean = [] final = [] if firstframe : for x in l : if x[2] == 'video': clean.append(x) break for x in l: if x[1] <= (max_frame_size * kill) : clean.append(x) if mode == "random": Wait.config(text="Applying Effect: Random", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() final = random.sample(clean,len(clean)) if mode == "reverse": Wait.config(text="Applying Effect: Reverse", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() final = sum(zip(clean[::-1], clean[:-1]), ()) if mode == "invert": Wait.config(text="Applying Effect: Invert", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() final = sum(zip(clean[1::2], clean[::2]), ()) if mode == 'bloom': Wait.config(text="Applying Effect: Bloom", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() repeat = int(countframes) frame = int(positframes) lista = clean[:frame] listb = clean[frame:] final = lista + ([clean[frame]]*repeat) + listb if mode == 'pulse': Wait.config(text="Applying Effect: Pulse", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() pulselen = int(countframes) pulseryt = int(positframes) j = 0 for x in clean: i = 0 if(j % pulselen == 0): while i < pulselen : final.append(x) i = i + 1 else: final.append(x) j = j + 1 if mode == "jiggle": Wait.config(text="Applying Effect: Jiggle", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() amount = int(positframes) final = [clean[constrain(x+int(random.gauss(0,amount)),0,len(clean)-1)] for x in range(0,len(clean))] if mode == "overlap": Wait.config(text="Applying Effect: Overlap", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() pulselen = int(countframes) pulseryt = int(positframes) clean = [clean[i:i+pulselen] for i in range(0,len(clean),pulseryt)] final = [item for sublist in clean for item in sublist] time.sleep(2) cname = '-c' + str(countframes) if int(countframes) > 1 else '' pname = '-n' + str(positframes) if int(positframes) > 1 else '' fileout= filein[:-4] + '-' + mode + '.avi' if os.path.exists(fileout): os.remove(fileout) bstream_until_marker(temp_hdrl, fileout) with open(temp_movi,'rb') as rd: filesize = os.path.getsize(temp_movi) with open(fileout,'ab') as wr: wr.write(struct.pack('<4s', b'movi')) for x in final: if x[0] != 0 and x[1] != 0: rd.seek(x[0]) wr.write(rd.read(x[1])) bstream_until_marker(temp_idx1, fileout) if os.path.exists(outputpath): os.remove(outputpath) else: pass os.remove(temp_hdrl) os.remove(temp_movi) os.remove(temp_idx1) os.rmdir(temp_dir) export(fileout) else: Wait.config(text="Moshed Video is Ready!", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() def export(fileout): def removefileout(): if os.path.exists(fileout): os.remove(fileout) Wait.place_forget() datamoshbtn['state']=NORMAL root.config(cursor="") messagebox.showinfo("DONE","Datamoshed video is ready!") else: pass export=exportbox.get() if(export==exportchoices[0]): ask=messagebox.askquestion("?","Do you want the Raw moshed version?") if ask=='yes': choice = modechoices.get() if(choice==modes[7]): Wait.config(text="Moshed Video is Ready!", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() os.remove(fileout) messagebox.showinfo("DONE","Datamoshed video is ready!") Wait.place_forget() datamoshbtn['state']=NORMAL root.config(cursor="") else: file2=os.path.splitext(fileout)[0] os.rename(fileout,file2+"_datamoshed.avi") Wait.config(text="Moshed Video is Ready!", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() messagebox.showinfo("DONE","Datamoshed video is ready!") root.config(cursor="") Wait.place_forget() datamoshbtn['state']=NORMAL elif ask=='no': targetformat=".avi" convert(fileout,targetformat) removefileout() elif(export==exportchoices[1]): choice = modechoices.get() if(choice==modes[7]): nfile=os.path.splitext(fileout)[0] os.rename(fileout,nfile+"_datamoshed.mp4") Wait.config(text="Moshed Video is Ready!", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) root.update() messagebox.showinfo("DONE","Datamoshed video is ready!") Wait.place_forget() root.config(cursor="") datamoshbtn['state']=NORMAL else: targetformat=".mp4" convert(fileout,targetformat) removefileout() elif(export==exportchoices[2]): targetformat=".gif" convert(fileout,targetformat) removefileout() elif(export==exportchoices[3]): targetformat=".mov" convert(fileout,targetformat) removefileout() elif(export==exportchoices[4]): targetformat=".mkv" convert(fileout,targetformat) removefileout() elif(export==exportchoices[5]): targetformat=".wmv" convert(fileout,targetformat) removefileout() else: messagebox.showerror("Error!","Please select the correct video format!") os.remove(fileout) os.kill(Datamosh()) Wait.place_forget() datamoshbtn['state']=NORMAL root.config(cursor="") def toggle(): if var.get()==0: Disableadvanced() else: Enableadvanced() def Enableadvanced(): choice = modechoices.get() if(choice==modes[7]): var1.set("5") countlabel['fg']="green" positlabel['fg']="green" firstflabel['fg']="green" killlabel['fg']="grey" Countframe['state']=NORMAL Positframe['state']=NORMAL firstframes['state']=NORMAL killframe['state']=DISABLED elif(choice==modes[6]): countlabel['fg']="grey" positlabel['fg']="grey" firstflabel['fg']="green" killlabel['fg']="green" Countframe['state']=DISABLED Positframe['state']=DISABLED firstframes['state']=NORMAL killframe['state']=NORMAL elif(choice==modes[5]): countlabel['fg']="grey" positlabel['fg']="grey" firstflabel['fg']="green" killlabel['fg']="grey" Countframe['state']=DISABLED Positframe['state']=DISABLED firstframes['state']=NORMAL killframe['state']=DISABLED elif(choice==modes[1]): countlabel['fg']="grey" positlabel['fg']="grey" firstflabel['fg']="green" killlabel['fg']="grey" Countframe['state']=DISABLED Positframe['state']=DISABLED firstframes['state']=NORMAL killframe['state']=DISABLED elif(choice==modes[2]): countlabel['fg']="grey" positlabel['fg']="green" firstflabel['fg']="green" killlabel['fg']="green" Countframe['state']=DISABLED Positframe['state']=NORMAL firstframes['state']=NORMAL killframe['state']=NORMAL else: var1.set("1") countlabel['fg']="green" positlabel['fg']="green" firstflabel['fg']="green" killlabel['fg']="green" Countframe['state']=NORMAL Positframe['state']=NORMAL firstframes['state']=NORMAL killframe['state']=NORMAL def Disableadvanced(): var1.set("1") countlabel['fg']="grey" positlabel['fg']="grey" firstflabel['fg']="grey" killlabel['fg']="grey" Countframe['state']=DISABLED Positframe['state']=DISABLED firstframes['state']=DISABLED killframe['state']=DISABLED def info(): messagebox.showinfo("Help", "Datamosher Pro is made for those who want to datamosh their video files and achieve that glitch effect." "\nHow To Use:\n➤First input the video you want to datamosh." "\n➤Choose the desired datamosh mode, then select the export format." "\n➤Use advance options for different modes (For more details about the advanced options, visit our Github page)." "\n➤Then just click on the datamosh button, then wait for a few seconds." "\n➤After conversion, your video will be ready and you can find the video in the directory." "\n\nDeveloper: Akash Bora (a.k.a. Akascape)\nIf you have any issue then contact me on Github.") def callback(url): webbrowser.open_new_tab("https://github.com/Akascape/Datamosher-Pro-GUI-.git") root=Tk() root.title("Datamosher Pro") root.resizable(width=False, height=False) root.geometry("500x450") root.configure(bg='#FFFFFF') root.columnconfigure(0,weight=1) icopath=resource_path0("icon.ico") root.wm_iconbitmap(icopath) path=resource_path0("label.png") LabelIMG=PhotoImage(file=path) headlabel=Label(root,image=LabelIMG,borderwidth=0, highlightthickness=0, padx=0,pady=0) headlabel.grid() LocationError=Label(root,text="Choose Video To Datamosh",fg="red",bg='#FFFFFF') LocationError.grid() OpeningFile= Button(root, width=61,bg="#82CC6C",fg="white", text="OPEN",highlightthickness=1,borderwidth=0.2,relief="groove",command=openfile) OpeningFile.grid() chooselabel=Label(root,text="Select Mode:",font="Aharoni",bg='#FFFFFF') chooselabel.place(x=80,y=115,anchor='center') modes=["Bloom", "Invert", "Jiggle", "Overlap","Pulse", "Reverse", "Random", "Classic"] modechoices=ttk.Combobox(root,values=modes, font="Verdana 12", width=7) modechoices.current(0) modechoices.place(x=130,y=104) exportchoices=["AVI","MP4","GIF","MOV","MKV","WMV"] exportlabel=Label(root,text="Export Format:",font="Aharoni",bg='#FFFFFF') exportlabel.place(x=270,y=105) exportbox=ttk.Combobox(root,values=exportchoices, font="Verdana 10", width=8) exportbox.current(1) exportbox.place(x=380,y=106) var = IntVar() var.set(0) advancedbox=Checkbutton(root, text="Advanced",bg="#FFFFFF", command=toggle,variable=var,onvalue=1, offvalue=0) advancedbox.place(x=70,y=150, anchor='center') var1=DoubleVar() var1.set(1) countlabel=Label(root,text="Glitch Freqency",fg="grey",bg='#FFFFFF') countlabel.place(x=40,y=165) Countframe=Entry(root,bg="#00D2FF",width=10,borderwidth=3, textvariable=var1,state=DISABLED) Countframe.place(x=140,y=165) var2=DoubleVar() var2.set(1) positlabel=Label(root,text="Frames Frequency",fg="grey",bg='#FFFFFF') positlabel.place(x=270,y=165) Positframe=Entry(root,bg="#00D2FF",width=10,borderwidth=3, textvariable=var2, state=DISABLED) Positframe.place(x=380,y=165) var3=IntVar() var3.set(1) firstflabel=Label(root,text="Ignored Frames",fg="grey",bg='#FFFFFF') firstflabel.place(x=40,y=200) firstframes=Entry(root,bg="#00D2FF",width=10,borderwidth=3, textvariable=var3, state=DISABLED) firstframes.place(x=140,y=200) var4=DoubleVar() var4.set(0.7) killlabel=Label(root,text="Kill Frames",fg="grey",bg='#FFFFFF') killlabel.place(x=270,y=200) killframe=Entry(root,bg="#00D2FF",width=10,borderwidth=3, textvariable=var4, state=DISABLED) killframe.place(x=380,y=200) global Wait Wait=Label(root,text="",fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15)) infobtn=Button(root, width=2,bg="#FFFFFF",fg="black", text="ⓘ",font=(10),relief="sunken",cursor='hand2', highlightthickness=0,borderwidth=0,padx=0,pady=0,command=info) infobtn.place(x=475,y=425) dev=Label(root, text='Developed by Akascape | For more info, visit:',bg='#FFFFFF',fg="#6D76CD", font=("Impact",10)) dev.place(x=5,y=430) link=Label(root, text="Datamosher Pro Github",font=('Impact',10),bg='#FFFFFF',fg="#6D76CD", cursor="hand2") link.place(x=245,y=430) link.bind("", lambda e: callback("https://github.com/Akascape/Datamosher-Pro-GUI-.git")) path0=resource_path0("button.png") buttonIMG=PhotoImage(file=path0) datamoshbtn=Button(root,image=buttonIMG,borderwidth=0, highlightthickness=0, padx=0,pady=0,command=Step1) datamoshbtn.place(x=100,y=270) root.mainloop() #DEVELOPER: AKASH BORA (a.k.a Akascape) #Version=1.2