19 Commits

Author SHA1 Message Date
Akash Bora
a964ecf891 added new UI for python version
Now python users can also enjoy the easy UI
2022-07-18 17:35:46 +05:30
Akash Bora
7933558b15 Delete Python Version directory 2022-07-18 17:25:32 +05:30
Akash Bora
ce394fcd90 Delete test 2022-07-18 17:14:46 +05:30
Akash Bora
2150cd6019 Add files via upload 2022-07-18 17:14:33 +05:30
Akash Bora
b368dfc9c7 Create test 2022-07-18 17:13:06 +05:30
Akash Bora
816d1150bd Removed older versions 2022-07-18 17:04:47 +05:30
Akash Bora
1d45e22e55 Update Readme.md 2022-07-02 13:36:10 +05:30
Akash Bora
9755263e6e Update Readme.md 2022-07-02 13:35:09 +05:30
Akash Bora
8e4ddc83e9 Update Readme.md 2022-06-24 12:12:25 +05:30
Akash Bora
cfdb269b1e Update Readme.md 2022-06-20 20:01:05 +05:30
Akash Bora
6c4823fe81 Update Readme.md 2022-06-20 19:58:17 +05:30
Akash Bora
2e45e67162 Update Readme.md 2022-06-19 23:31:53 +05:30
Akash Bora
f7c62a5944 Update Readme.md 2022-06-19 23:26:41 +05:30
Akash Bora
18b043f4be Update Readme.md 2022-06-19 23:24:51 +05:30
Akash Bora
684f036fc7 Update Readme.md 2022-06-19 23:23:04 +05:30
Akash Bora
4897db579b Delete Demos.md 2022-06-19 23:20:28 +05:30
Akash Bora
420ff634a6 Update Readme.md 2022-06-19 23:18:58 +05:30
Akash Bora
2dda202bf2 Update Readme.md 2022-06-19 23:09:52 +05:30
Akash Bora
5e0183ccdc Update Readme.md 2022-06-19 23:05:34 +05:30
41 changed files with 1452 additions and 1314 deletions

View File

@@ -1,37 +0,0 @@
[![header](https://capsule-render.vercel.app/api?type=waving&color=timeGradient&height=300&section=header&text=GALLERY&fontSize=90&fontAlignY=30&fontAlign=75&desc=Datamosher%20Pro&descAlign=80&descSize=30&animation=scaleIn)](https://akascape.gumroad.com/l/Datamosher-Pro)
# This is the gallery page for Datamosher-Pro
## Basic i-frame removal examples (bloom, classic, rise)
<br> [![Click to watch!](https://img.youtube.com/vi/_YZ32Wvl3hk/0.jpg)](https://youtu.be/_YZ32Wvl3hk)
## Different P-frame duplication effects (classic, glide, repeat, pulse)
<br> [![Click to watch!](https://img.youtube.com/vi/fFhnV19fuzg/0.jpg)](https://youtu.be/fFhnV19fuzg)
## Automated Shuffle effect example
<br> [![Click to watch!](https://img.youtube.com/vi/26BJl87ksec/0.jpg)](https://youtu.be/26BJl87ksec)
## The Beautiful Fluid effect
<br> [![Click to watch!](https://img.youtube.com/vi/GJiP6R432D8/0.jpg)](https://youtu.be/GJiP6R432D8)
## The Vibrate effect that can be used to make backgrounds
<br> [![Click to watch!](https://img.youtube.com/vi/DkIvfRSQ8bo/0.jpg)](https://youtu.be/DkIvfRSQ8bo)
## The Rain effect
<br> [![Click to watch!](https://img.youtube.com/vi/0mKZQopUUQg/0.jpg)](https://youtu.be/0mKZQopUUQg)
## Classic datamoshing showreel
<br> [![Click to watch!](https://img.youtube.com/vi/hYFEwL8Do_U/0.jpg)](https://youtu.be/hYFEwL8Do_U)
## Drone shot + Noise mode
<br> [![Click to watch!](https://img.youtube.com/vi/IaD8yX2kXgE/0.jpg)](https://youtu.be/IaD8yX2kXgE)
## Showreel 2 (Sort & Shuffle mixed)
<br> [![Click to watch!](https://img.youtube.com/vi/BWIK5gCt5ZA/0.jpg)](https://youtu.be/BWIK5gCt5ZA)
## Done shot + Different ffglitch modes (Mirror, buffer, zoom, stretch, sink, fluid)
<br> [![Click to watch!](https://img.youtube.com/vi/SCUkP1TfDDM/0.jpg)](https://youtu.be/SCUkP1TfDDM)
## Blooming Glide effect (classic mode used)
<br> [![Click to watch!](https://img.youtube.com/vi/z5Uc3vOfahw/0.jpg)](https://youtu.be/z5Uc3vOfahw)
## Trippy Showreel 1
<br> [![Click to feel!](https://img.youtube.com/vi/ovM0tKlzEDY/0.jpg)](https://youtu.be/ovM0tKlzEDY)
# Read Online Guides:
<br> [![Read](https://img.shields.io/badge/Guide-1-orange)](https://akascape.gumroad.com/p/datamosher-pro-guide) [![Read](https://img.shields.io/badge/Guide-2-green)](https://akascape.gumroad.com/p/datamosher-pro-guide-2)
## Fan Made Videos ❤️
<br> [![Click to watch!](https://img.youtube.com/vi/qvOK6twezM8/0.jpg)](https://youtu.be/qvOK6twezM8) [![Click to watch!](https://img.youtube.com/vi/ULH_AMqz56c/0.jpg)](https://youtu.be/ULH_AMqz56c) [![Click to watch!](https://user-images.githubusercontent.com/89206401/165247108-08b7d7d6-233a-4167-a3ce-ff474eb414c9.jpg)](https://www.reddit.com/r/glitch_art/comments/u1jjn6/what_is_going_on_with_these_skeletons/?utm_source=share&utm_medium=web2x&context=3) [![Click to watch!](https://img.youtube.com/vi/Rsrg3JupLXI/2.jpg)](https://youtu.be/Rsrg3JupLXI) [![Click to watch this short!](https://img.youtube.com/vi/XxFlon7_z9g/2.jpg)](https://youtu.be/XxFlon7_z9g) [![Click to watch!](https://img.youtube.com/vi/bA-QiGqMofA/2.jpg)](https://youtu.be/bA-QiGqMofA)
[![Click to watch!](https://img.youtube.com/vi/Mi0Lplsxq3Y/0.jpg)](https://youtu.be/Mi0Lplsxq3Y)
[![Click to watch!](https://user-images.githubusercontent.com/89206401/169638330-ebdbde2d-50ed-43ab-8d5f-4066c29318c1.png)
](https://www.reddit.com/r/datamoshing/comments/uuf50b/shifting_mountains/?utm_source=share&utm_medium=web2x&context=3)
[![Click to watch this short!](https://img.youtube.com/vi/EppD9SCVPQM/0.jpg)](https://youtube.com/shorts/EppD9SCVPQM?feature=share)
## More to be uploaded soon!

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

View File

@@ -0,0 +1 @@
1.8

View File

@@ -0,0 +1,154 @@
#Author: Akash Bora
import os, shutil, subprocess, random, json
from pathlib import Path
import numpy as np
DIRPATH = Path(os.path.dirname(os.path.realpath(__file__)))
ffgac=str(DIRPATH.parent.parent).replace(os.sep, '/')+"/FFglitch/ffgac"
ffedit=str(DIRPATH.parent.parent).replace(os.sep, '/')+"/FFglitch/ffedit"
def library(input_video, output, mode, extract_from="", fluidity=0, size=0, s=0, e=0, vh=0, gop=1000):
def get_vectors(input_video):
subprocess.call(f'"{ffgac}" -i "{input_video}" -an -mpv_flags +nopimb+forcemv -qscale:v 0 -g "{gop}"' +
' -vcodec mpeg2video -f rawvideo -y tmp.mpg', shell=True)
subprocess.call(f'"{ffedit}" -i tmp.mpg -f mv:0 -e tmp.json', shell=True)
os.remove('tmp.mpg')
f = open('tmp.json', 'r')
raw_data = json.load(f)
f.close()
os.remove('tmp.json')
frames = raw_data['streams'][0]['frames']
vectors = []
for frame in frames:
try:
vectors.append(frame['mv']['forward'])
except:
vectors.append([])
return vectors
def apply_vectors(vectors, input_video, output_video, method='add'):
subprocess.call(f'"{ffgac}" -i "{input_video}" -an -mpv_flags +nopimb+forcemv -qscale:v 0 -g "{gop}"' +
' -vcodec mpeg2video -f rawvideo -y tmp.mpg', shell=True)
to_add = '+' if method == 'add' else ''
script_path = 'apply_vectors.js'
script_contents = '''
var vectors = [];
var n_frames = 0;
function glitch_frame(frame) {
let fwd_mvs = frame["mv"]["forward"];
if (!fwd_mvs || !vectors[n_frames]) {
n_frames++;
return;
}
for ( let i = 0; i < fwd_mvs.length; i++ ) {
let row = fwd_mvs[i];
for ( let j = 0; j < row.length; j++ ) {
let mv = row[j];
try {
mv[0] ''' + to_add + '''= vectors[n_frames][i][j][0];
mv[1] ''' + to_add + '''= vectors[n_frames][i][j][1];
} catch {}
}
}
n_frames++;
}
'''
with open(script_path, 'w') as f:
f.write(script_contents.replace('var vectors = [];', f'var vectors = {json.dumps(vectors)};'))
subprocess.call(f'"{ffedit}" -i tmp.mpg -f mv -s "{script_path}" -o "{output_video}"', shell=True)
os.remove('apply_vectors.js')
os.remove('tmp.mpg')
def shuffle(output):
if os.path.isdir("cache"):
shutil.rmtree("cache")
os.mkdir("cache")
base=os.path.basename(input_video)
fin="cache/"+base[:-4]+".mpg"
subprocess.call(f'"{ffgac}" -i "{input_video}" -an -vcodec mpeg2video -f rawvideo -mpv_flags +nopimb -qscale:v 6 -r 30 -g "{gop}" -y "{fin}"')
os.mkdir("cache/raws")
framelist=[]
subprocess.call(f'"{ffgac}" -i "{fin}" -vcodec copy cache/raws/frames_%04d.raw')
frames=os.listdir("cache/raws")
siz=size
framelist.extend(frames)
chunked_list=[]
chunk_size=siz
for i in range(0, len(framelist), chunk_size):
chunked_list.append(framelist[i:i+chunk_size])
random.shuffle(chunked_list)
framelist.clear()
for k in frames[0:siz]:
framelist.append(k)
for i in chunked_list:
for j in i:
if not j in framelist:
framelist.append(j)
out_data = b''
for fn in framelist:
with open("cache/raws/"+fn, 'rb') as fp:
out_data += fp.read()
with open(output, 'wb+') as fp:
fp.write(out_data)
fp.close()
shutil.rmtree("cache")
def rise(output):
if os.path.isdir("cache"):
shutil.rmtree("cache")
os.mkdir("cache")
base=os.path.basename(input_video)
fin="cache/"+base[:-4]+".mpg"
qua=''
subprocess.call(f'"{ffgac}" -i "{input_video}" -an -vcodec mpeg2video -f rawvideo -mpv_flags +nopimb -qscale:v 6 -r 30 -g "{gop}" -y "{fin}"')
os.mkdir("cache/raws")
framelist=[]
subprocess.call(f'"{ffgac}" -i "{fin}" -vcodec copy cache/raws/frames_%04d.raw')
kil=e
po=s
if po==0:
po=1
frames=os.listdir("cache/raws")
for i in frames[po:(po+kil)]:
os.remove("cache/raws/"+i)
frames.clear()
frames=os.listdir("cache/raws")
framelist.extend(frames)
out_data = b''
for fn in framelist:
with open("cache/raws/"+fn, 'rb') as fp:
out_data += fp.read()
with open(output, 'wb') as fp:
fp.write(out_data)
fp.close()
shutil.rmtree("cache")
def average(frames):
if not frames:
return []
return np.mean(np.array([x for x in frames if x != []]), axis=0).tolist()
def fluid(frames):
average_length = fluidity
if average_length==1:
average_length=2
return [average(frames[i + 1 - average_length: i + 1]) for i in range(len(frames))]
def movement(frames):
for frame in frames:
if not frame:
continue
for row in frame:
for col in row:
col[vh] = 0
return frames
if(mode==1):
transfer_to=input_video
vectors = []
if extract_from:
vectors = get_vectors(extract_from)
if transfer_to == '':
with open(output, 'w') as f:
json.dump(vectors, f)
apply_vectors(vectors, transfer_to, output)
elif(mode==2):
apply_vectors(movement(get_vectors(input_video)), input_video, output, method='')
elif(mode==3):
apply_vectors(fluid(get_vectors(input_video)), input_video, output, method='')
elif(mode==4):
shuffle(output)
elif(mode==5):
rise(output)

View File

@@ -0,0 +1,15 @@
#Author: Akash Bora
import os, subprocess
from pathlib import Path
DIRPATH = Path(os.path.dirname(os.path.realpath(__file__)))
ffgac=str(DIRPATH.parent.parent).replace(os.sep, '/')+"/FFglitch/ffgac"
ffedit=str(DIRPATH.parent.parent).replace(os.sep, '/')+"/FFglitch/ffedit"
def mosh(input_video, output_video, mode, effect='', scriptfile='', gop=1000):
if mode==1:
script_path=scriptfile
elif mode==2:
script_path=str(DIRPATH).replace(os.sep, '/')+"/jscripts/"+effect+".js"
subprocess.call(f'"{ffgac}" -i "{input_video}" -an -mpv_flags +nopimb+forcemv -qscale:v 0 -b:v 20M -minrate 20M -maxrate 20M -bufsize 2M -g "{gop}"' +
' -vcodec mpeg2video -f rawvideo -y tmp.mpg', shell=True)
subprocess.call(f'"{ffedit}" -i tmp.mpg -f mv -s "{script_path}" -o "{output_video}"', shell=True)
os.remove('tmp.mpg')

View File

@@ -0,0 +1,35 @@
#Author: Akash Bora
import subprocess
def Datamosh(filename, outf, s, e, p, fps=30):
END_FRAME_HEX = b'00dc'
I_FRAME_HEX = b'\x00\x01\xb0'
def main(filename, effect_sec_list, p_frames_mult):
mosh(effect_sec_list, p_frames_mult)
def mosh(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=s
end=e
pf=p
main(filename,[(start,end)],pf)

View File

@@ -0,0 +1,64 @@
#Author: Akash Bora
from pymosh import Index
from pymosh.codec.mpeg4 import is_iframe
from itertools import islice
class library():
def glide(interval, filename, outfile):
f = Index.from_file(filename)
buf = [None]
def process_frame(frame):
if buf[0] == None or not is_iframe(frame):
buf[0] = frame
else:
frame = buf[0]
return frame
for stream in f.video:
newstream = []
newstream.append(stream[0])
ix = 0
jx = 0
for i in stream[1:]:
ix += 1
jx += 1
if ix < interval:
newstream.append(process_frame(stream[jx]))
else:
newstream.append(newstream[-1])
if ix > interval * 2:
ix = 0
stream.replace(newstream)
f.rebuild()
with open(outfile, 'wb') as out:
f.write(out)
def avi_sort(filename, outfile, mode, rev):
f = Index.from_file(filename)
for stream in f.video:
if mode==0:
sorted_stream = sorted(stream, key=len, reverse=rev)
else:
sorted_stream = sorted(stream, key=lambda s: s[len(s)-6], reverse=rev)
stream.replace(sorted_stream)
f.rebuild()
with open(outfile, 'wb') as out:
f.write(out)
def process_streams(in_filename, out_filename, mid=''):
def echo(stream, midpoint):
all_frames = list(stream)
pframes = [f for f in all_frames if not is_iframe(f)]
midpoint_idx = int(len(all_frames)*midpoint)
frames = all_frames[:midpoint_idx]
while len(frames) < len(all_frames):
frames += pframes[:(len(all_frames) - len(frames))]
return frames
mode=echo
f = Index.from_file(in_filename)
for stream in f.video:
midpoint=mid
drifted = list(mode(stream, midpoint))
stream.replace(drifted)
f.rebuild()
with open(out_filename, 'wb') as out:
f.write(out)

View File

@@ -0,0 +1,43 @@
#Author: Akash Bora
def Datamosh(filename,outfile,s,e,p,fps):
def write_frame(frame):
out_file.write(frame_start + frame)
def mosh_delta_repeat(n_repeat):
if n_repeat=="1":
n_repeat=2
repeat_frames = []
repeat_index = 0
for index, frame in enumerate(frames):
if (frame[5:8] != iframe and frame[5:8] != pframe) or not start_frame <= index < end_frame:
write_frame(frame)
continue
if len(repeat_frames) < n_repeat and frame[5:8] != iframe:
repeat_frames.append(frame)
write_frame(frame)
elif len(repeat_frames) == n_repeat:
write_frame(repeat_frames[repeat_index])
repeat_index = (repeat_index + 1) % n_repeat
else:
write_frame(frame)
start_frame = s
end_frame = e
if end_frame==1:
end_frame=1000
input_avi = filename
delta = p
in_file = open(input_avi, 'rb')
output_avi= outfile
in_file_bytes = in_file.read()
out_file = open(output_avi, 'wb')
frame_start = bytes.fromhex('30306463')
frames = in_file_bytes.split(frame_start)
out_file.write(frames[0])
frames = frames[1:]
iframe = bytes.fromhex('0001B0')
pframe = bytes.fromhex('0001B6')
n_video_frames = len([frame for frame in frames if frame[5:8] == iframe or frame[5:8] == pframe])
if end_frame < 0:
end_frame = n_video_frames
mosh_delta_repeat(delta)
in_file.close()
out_file.close()

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Kaspar RAVEL
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,234 @@
#Original Author: Kasper Ravel
#Modified by: Akash Bora
import os, re, random, struct
from itertools import chain
from itertools import repeat
def mosh(infile, outfile, m, c, n, a, f, k):
print (" _ _ ")
print ("| | | | ")
print ("| |_ ___ _ __ ___ __ _| |_ ___ ")
print ("| __/ _ \| '_ ` _ \ / _` | __/ _ \ ")
print ("| || (_) | | | | | | (_| | || (_) |")
print (" \__\___/|_| |_| |_|\__,_|\__\___/ ")
print ("Tomato Automosh v2.0")
print ("\\\\ Audio Video Interleave breaker")
print (" ")
print ("glitch tool made with love for the glitch art community <3")
print ("___________________________________")
filein = infile
mode = m
countframes = c
positframes = n
audio = a
firstframe = f
kill = k
if filein is None or os.path.exists(filein) == False:
print("> step 0/5: valid input file required!")
print("use -h to see help")
exit()
#define temp directory and files
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)
#Define constrain function for jiggle :3
def constrain(val, min_val, max_val):
return min(max_val, max(min_val, val))
######################################
### STREAM FILE INTO WORK DIR BINS ###
######################################
print("> step 1/5 : streaming into binary files")
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() # position is relative to buffer glitchedframes
marker_pos = marker_pos + pos # position should be absolute now
split = buffer.split(marker, 1)
wr.write(split[0])
return marker_pos
else:
wr.write(buffer)
else:
wr.write(buffer)
#make 3 files, 1 for each chunk
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)
####################################
### FUN STUFF WITH VIDEO CONTENT ###
####################################
print("> step 2/5 : constructing frame index")
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)
#build first list with all adresses
for m in (re.finditer(b'\x30\x31\x77\x62', buffer)): # find iframes
if audio : frame_table.append([m.start() + pos, 'sound'])
for m in (re.finditer(b'\x30\x30\x64\x63', buffer)): # find b frames
frame_table.append([m.start() + pos, 'video'])
#then remember to sort the list
frame_table.sort(key=lambda tup: tup[0])
l = []
l.append([0,0, 'void'])
max_frame_size = 0
#build tuples for each frame index with frame sizes
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]])
########################
### TIME FOR SOME FX ###
########################
# variables that make shit work
clean = []
final = []
# keep first video frame or not
if firstframe:
for x in l:
if x[2] == 'video':
clean.append(x)
break
# clean the list by killing "big" frames
for x in l:
if x[1] <= (max_frame_size * kill) :
clean.append(x)
# FX modes
if mode == "void":
print('> step 3/5 : mode void')
final = clean
if mode == "random":
print('> step 3/5 : mode random')
final = random.sample(clean,len(clean))
if mode == "reverse":
print('> step 3/5 : mode reverse')
final = sum(zip(clean[::-1], clean[:-1]), ())
if mode == "invert":
print('> step 3/5 : mode invert')
final = sum(zip(clean[1::2], clean[::2]), ())
if mode == 'bloom':
print('> step 3/5 : mode bloom')
repeat = int(countframes)
frame = int(positframes)
## split list
lista = clean[:frame]
listb = clean[frame:]
## rejoin list with bloom
final = lista + ([clean[frame]]*repeat) + listb
if mode == 'pulse':
print('> step 3/5 : mode pulse')
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":
print('> step 3/5 : mode jiggle')
#print('*needs debugging lol help thx*') # didn't pandy's branch fix this?
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":
print('> step 3/5 : mode overlap')
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]
if mode == 'exponential':#Ask Kasper to add these modes (Note by Akash)
print('> step 3/5 : mode exponential')
print('sorry, currently not implemented. using void..')
if mode == 'swap':
print('> step 3/5 : mode swap')
print('sorry, currently not implemented. using void..')
####################################
### PUT VIDEO FILE BACK TOGETHER ###
####################################
print("> step 4/5 : putting things back together")
#name new file
fileout = outfile
#delete old file
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)
#remove unnecessary temporary files and folders
os.remove(temp_hdrl)
os.remove(temp_movi)
os.remove(temp_idx1)
os.rmdir(temp_dir)
print("> step 5/5 : done - final idx size : " + str(len(final)))

View File

@@ -0,0 +1,725 @@
#Author: Akash Bora
#License: MIT | Copyright (c) 2022 Akash Bora
currentversion=1.8
#Import required modules
import tkinter
import tkinter.messagebox
import customtkinter
from tkinter import ttk, messagebox, filedialog
import sys
import os
import imageio_ffmpeg
import subprocess
import imageio
from PIL import Image, ImageTk #Upgrade pillow if you are facing any import error with PIL (pip install pillow --upgrade)
from RangeSlider.RangeSlider import RangeSliderH, RangeSliderV
import threading
import ctypes
import webbrowser
import requests
import time
#Import the local datamosh library
from DatamoshLib.Tomato import tomato
from DatamoshLib.Original import classic, repeat, pymodes
from DatamoshLib.FFG_effects import basic_modes, external_script
#Resource Finder
def resource(relative_path):
base_path = getattr(
sys,
'_MEIPASS',
os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
#Main Window
WIDTH = 780
HEIGHT = 520
try:
ctypes.windll.shcore.SetProcessDpiAwareness(0)
except:
pass
customtkinter.set_appearance_mode("Dark")
customtkinter.set_default_color_theme("blue")
self=customtkinter.CTk()
self.title("Datamosher Pro (python version)")
self.geometry(f"{WIDTH}x{HEIGHT}")
self.bind("<1>", lambda event: event.widget.focus_set())
self.grid_columnconfigure(1, weight=1)
self.grid_rowconfigure(0, weight=1)
self.resizable(width=False, height=False)
frame_left = customtkinter.CTkFrame(master=self,width=180,corner_radius=0)
frame_left.grid(row=0, column=0, sticky="nswe")
frame_right = customtkinter.CTkFrame(master=self)
frame_right.grid(row=0, column=1, sticky="nswe", padx=20, pady=20)
icopath=ImageTk.PhotoImage(file=resource("Assets/Icons/Program_icon.png"))
self.iconphoto(False, icopath)
#FFMPEG path (using the imageio ffmpeg plugin)
ffdir=os.path.dirname(imageio_ffmpeg.__file__).replace(os.sep, '/')+"/binaries/"
fileff=''.join([idx for idx in os.listdir(ffdir) if idx[0].lower()=='f'.lower()])
ffmpeg=resource(ffdir+fileff)
#Effect List
modelist=sorted(["Bloom", "Invert", "Jiggle", "Overlap", "Pulse", "Reverse",
"Random", "Classic", "Glide", "Sort", "Echo", "Void",
"Fluid", "Stretch", "Motion Transfer", "Repeat", "Shear", "Delay", "Sink",
"Mirror", "Vibrate", "Slam Zoom", "Zoom","Invert-Reverse", "Shift",
"Noise", "Stop", "Buffer", "Slice", "Shuffle", "Rise", "Custom Script"])
current=modelist[0]
#Making the top widgets for changing the modes dynamically
def ChangeModeRight():
global current
modelist.append(modelist.pop(0))
current=modelist[0]
mode_info.configure(text=current)
dynamic()
def ChangeModeLeft():
global current
modelist.insert(0, modelist.pop())
current=modelist[0]
mode_info.configure(text=current)
dynamic()
frame_info = customtkinter.CTkFrame(master=frame_right, width=520, height=100)
frame_info.place(x=20,y=20)
mode_info = customtkinter.CTkLabel(master=frame_info,text=current, corner_radius=10, width=320,
height=50,
fg_color=("white", "gray38"))
mode_info.place(x=100,y=25)
play_icon =Image.open(resource("Assets/Icons/right_icon.png")).resize((20, 20), Image.Resampling.LANCZOS)
left_but = customtkinter.CTkButton(master=frame_info, image=ImageTk.PhotoImage(play_icon.transpose(Image.Transpose.FLIP_LEFT_RIGHT)), text="", width=50, height=50,
corner_radius=10, fg_color="gray40", hover_color="gray25", command=ChangeModeLeft)
left_but.place(x=20,y=25)
right_but = customtkinter.CTkButton(master=frame_info, image=ImageTk.PhotoImage(play_icon), text="", width=50, height=50,
corner_radius=10, fg_color="gray40", hover_color="gray25", command=ChangeModeRight)
right_but.place(x=450,y=25)
#Open video function
previous=""
def open_function():
global ofile, vid_image2, previous, duration, vid
ofile=tkinter.filedialog.askopenfilename(filetypes =[('Video', ['*.mp4','*.avi','*.mov','*.mkv','*gif']),('All Files', '*.*')])
#Check the video type
supported=["mp4","avi","mov","gif","mkv","wmv","m4v"]
if ofile:
previous=ofile
pass
else:
ofile=previous
return
if ofile[-3:].lower() in supported:
pass
else:
print("This file type is not supported!")
return
if len(os.path.basename(ofile))>=20:
showinput=os.path.basename(ofile)[:10]+"..."+os.path.basename(ofile)[-3:]
else:
showinput=os.path.basename(ofile)[:20]
#Change the thumbnail
button_open.configure(fg_color='grey', text=showinput)
outpng="Assets/thumbnail_cache/vid_thumbnail.jpg"
button_thumbnail.configure(image=vid_image)
if os.path.exists("Assets/thumbnail_cache/vid_thumbnail.jpg"):
os.remove("Assets/thumbnail_cache/vid_thumbnail.jpg")
subprocess.call(f'"{ffmpeg}" -loglevel quiet -ss 00:00:01 -t 00:00:01 -i "{ofile}" -qscale:v 2 -r 10.0 "{outpng}"', shell=True)
vid_image2 = ImageTk.PhotoImage(Image.open(outpng).resize((167, 100), Image.Resampling.LANCZOS))
button_thumbnail.configure(image=vid_image2)
vid=imageio.get_reader(ofile, 'ffmpeg')
#Update the widget parameters
position_frame.configure(to=vid.count_frames(), number_of_steps=vid.count_frames())
duration= vid.get_meta_data()['duration']
rangebar.max_val=duration
label_seconds2.configure(text="End: "+str(int(duration))+"s")
rangebar2.max_val=vid.count_frames()
label_showframe2.configure(text="End: "+str(vid.count_frames()))
shuf_slider.configure(to=vid.count_frames(), number_of_steps=vid.count_frames())
end_mosh.set(duration)
end_frame_mosh.set(vid.count_frames())
#Left Frame Widgets
label_appname = customtkinter.CTkLabel(master=frame_left,text="DATAMOSHER PRO")
label_appname.place(x=20,y=10)
vid_image = ImageTk.PhotoImage(Image.open("Assets/thumbnail_cache/offline_image.png").resize((167, 100), Image.Resampling.LANCZOS))
button_thumbnail = tkinter.Label(master=frame_left, image=vid_image, width=167, height=100, text="", bg="grey")
button_thumbnail.place(x=5,y=40)
add_video_image = ImageTk.PhotoImage(Image.open(resource("Assets/Icons/video_icon.png")).resize((20, 15), Image.Resampling.LANCZOS))
button_open = customtkinter.CTkButton(master=frame_left, image=add_video_image, text="IMPORT VIDEO", width=160, height=35,
compound="right", command=open_function)
button_open.place(x=10,y=170)
label_export = customtkinter.CTkLabel(master=frame_left,anchor="w",text="Export Format")
label_export.place(x=12,y=215)
optionmenu_1 = customtkinter.CTkOptionMenu(master=frame_left, fg_color="#4d4d4d",width=160, height=35, values=["mp4","avi","mov","mkv"])
optionmenu_1.set("mp4")
optionmenu_1.place(x=10,y=250)
settingpng = ImageTk.PhotoImage(Image.open(resource("Assets/Icons/settings.png")).resize((20, 20), Image.Resampling.LANCZOS))
#Setting Window
def close_top3():
window_UI.destroy()
uisetting.configure(state=tkinter.NORMAL)
def changeUI():
global window_UI
window_UI = customtkinter.CTkToplevel(self)
window_UI.geometry("410x200")
window_UI.resizable(width=False, height=False)
window_UI.title("App Preferences")
window_UI.iconphoto(False, icopath)
uisetting.configure(state=tkinter.DISABLED)
window_UI.wm_transient(self)
def check():
URL = "https://raw.githubusercontent.com/Akascape/Datamosher-Pro/Miscellaneous/VERSIONPY.txt"
try:
response = requests.get(URL)
open("Assets\\version\\VERSIONPY.txt", "wb").write(response.content)
except:
tkinter.messagebox.showinfo("Unable to connect!", "Unable to get information, please check your internet connection or visit the github repository.")
return
time.sleep(2)
with open("Assets\\version\\VERSIONPY.txt", 'r') as uf:
nver=float(uf.read())
if nver>currentversion:
tkinter.messagebox.showinfo("New Version available!","A new version "+ str(nver) +
" is available, \nPlease visit the github repository or the original download page!")
else:
tkinter.messagebox.showinfo("No Updates!", "You are on the latest version!")
def docs():
webbrowser.open_new_tab("https://github.com/Akascape/Datamosher-Pro/wiki")
def repo():
webbrowser.open_new_tab("https://github.com/Akascape/Datamosher-Pro")
logo_image = ImageTk.PhotoImage(Image.open(resource("Assets/Icons/Logo.png")).resize((210, 200), Image.Resampling.LANCZOS))
logo=customtkinter.CTkButton(master=window_UI, image=logo_image, width=205, height=105, border_width=0,
corner_radius=1, border_color="grey20", text="",fg_color=customtkinter.ThemeManager.theme["color"]["frame_low"][1],
hover_color=customtkinter.ThemeManager.theme["color"]["frame_low"][1])
logo.place(x=200,y=0)
visit=customtkinter.CTkButton(window_UI, text="Visit Repo", width=150, height=35,
corner_radius=10, fg_color=customtkinter.ThemeManager.theme["color"]["button"][1], hover_color="gray25",command=repo)
visit.place(x=20,y=30)
checkupdate=customtkinter.CTkButton(window_UI, text="Check For Updates", width=150, height=35,
corner_radius=10, fg_color=customtkinter.ThemeManager.theme["color"]["button"][1], hover_color="gray25",command=check)
checkupdate.place(x=20,y=80)
helpbutton=customtkinter.CTkButton(window_UI, text="Help", width=150, height=35,
corner_radius=10, fg_color=customtkinter.ThemeManager.theme["color"]["button"][1], hover_color="gray25",command=docs)
helpbutton.place(x=20,y=130)
version_label=customtkinter.CTkLabel(window_UI,anchor="w",width=1,fg_color=customtkinter.ThemeManager.theme["color"]["frame_low"][1],
text="v"+str(currentversion), bg_color=customtkinter.ThemeManager.theme["color"]["frame_low"][1])
version_label.place(x=365, y=2)
dvname=customtkinter.CTkLabel(window_UI,anchor="w",width=1,fg_color=customtkinter.ThemeManager.theme["color"]["frame_low"][1],
text="Developer: Akash Bora", bg_color=customtkinter.ThemeManager.theme["color"]["frame_low"][1])
dvname.place(x=30,y=170)
window_UI.protocol("WM_DELETE_WINDOW", close_top3)
uisetting = customtkinter.CTkButton(master=frame_left, image=settingpng, text="", width=40, height=40,
corner_radius=10, fg_color=customtkinter.ThemeManager.theme["color"]["text_disabled"][1],
hover_color="gray25", command=changeUI)
uisetting.place(x=10,y=470)
#Validation for entries
def only_numbers(char):
if ((char.isdigit()) or (char=="")) and (len(char)<=6):
return True
else:
return False
validation = self.register(only_numbers)
### Dynamimc widgets that change with modes ###
#Kill Frame Widget
def changekill(value):
label_kill.configure(text="Kill Frame Size: "+str(round(value,4)))
label_kill = customtkinter.CTkLabel(master=frame_right,anchor="w",text="Kill Frame Size: 0.6")
slider_kill= customtkinter.CTkSlider(master=frame_right, width=500,
from_=1,
to=0,
number_of_steps=100, command=changekill)
slider_kill.set(0.6)
#N-frameWidget
varn=tkinter.IntVar()
label_ctime = customtkinter.CTkLabel(master=frame_right,anchor='w',text="Frame Count:",width=1)
ctime=customtkinter.CTkEntry(frame_right,textvariable=varn, validate='key', validatecommand=(validation, '%P'),
placeholder_text="1",
width=100,
placeholder_text_color="grey70",
height=30,
border_width=2,
corner_radius=10)
varn.set(1)
#Keep frame & Keep audio widgets
keepaudio = customtkinter.CTkCheckBox(master=frame_right, text="Keep Audio", onvalue=1, offvalue=0)
keepframe = customtkinter.CTkCheckBox(master=frame_right, text="Keep First Frame", onvalue=1, offvalue=0)
#Count Frame widget
label_frame1 = customtkinter.CTkLabel(master=frame_right,anchor='w',text="Position Frame: 1",width=1)
def framework(value):
try:
if ofile:
pass
except:
return
label_frame1.configure(text="Position Frame: "+str(int(value)))
position_frame=customtkinter.CTkSlider(master=frame_right, width=500,progress_color="black", fg_color="black",
from_=1,
to=0,
number_of_steps=1, command=framework)
position_frame.set(1)
#Classic Rangebar
start_mosh = tkinter.DoubleVar()
end_mosh = tkinter.DoubleVar()
rangebar = RangeSliderH(frame_right, [start_mosh, end_mosh], Width=510, Height=63,
bgColor=customtkinter.ThemeManager.theme["color"]["frame_low"][1],line_color="black",
bar_color_outer=customtkinter.ThemeManager.theme["color"]["button"][0],
bar_color_inner=customtkinter.ThemeManager.theme["color"]["checkmark"][1],min_val=0, max_val=1, show_value= False,
line_s_color=customtkinter.ThemeManager.theme["color"]["button"][0])
label_seconds1 = customtkinter.CTkLabel(master=frame_right,anchor='w',text="Start: 0s",width=1)
label_seconds2 = customtkinter.CTkLabel(master=frame_right,anchor='w',text="End: 0s",width=1)
label_segment= customtkinter.CTkLabel(master=frame_right,anchor='w',text="Choose Segment:",width=1)
def show2(*args):
try:
if ofile:
pass
except:
return
label_seconds2.configure(text="End: "+str(int(end_mosh.get()))+"s")
def show(*args):
try:
if ofile:
pass
except:
return
label_seconds1.configure(text="Start: "+str(int(start_mosh.get()))+"s")
start_mosh.trace_add('write', show)
end_mosh.trace_add('write', show2)
#Delta entry widget
label_p = customtkinter.CTkLabel(master=frame_right,anchor='w',text="P-frames (Delta):",width=1)
label_segment= customtkinter.CTkLabel(master=frame_right,anchor='w',text="Choose Segment:",width=1)
varp=tkinter.IntVar()
delta=customtkinter.CTkEntry(frame_right,
placeholder_text="1",validate='key', validatecommand=(validation, '%P'),
width=100, textvariable=varp,
placeholder_text_color="grey70",
height=30,
border_width=2,
corner_radius=10)
varp.set(1)
#Frame Rangebar for repeat and rise modes
start_frame_mosh = tkinter.DoubleVar()
end_frame_mosh = tkinter.DoubleVar()
rangebar2 = RangeSliderH(frame_right, [start_frame_mosh, end_frame_mosh], Width=510, Height=63,
bgColor=customtkinter.ThemeManager.theme["color"]["frame_low"][1],line_color="black",
bar_color_outer=customtkinter.ThemeManager.theme["color"]["button"][0],
bar_color_inner=customtkinter.ThemeManager.theme["color"]["checkmark"][1],min_val=0, max_val=1, show_value= False,
line_s_color=customtkinter.ThemeManager.theme["color"]["button"][0])
label_showframe1 = customtkinter.CTkLabel(master=frame_right,anchor='w',text="Start Frame: 0",width=1)
label_showframe2 = customtkinter.CTkLabel(master=frame_right,anchor='w',text="End: 0",width=1)
label_segment2= customtkinter.CTkLabel(master=frame_right,anchor='w',text="Choose Frame Segment:",width=1)
def show3(*args):
try:
if ofile:
pass
except:
return
label_showframe2.configure(text="End: "+str(int(end_frame_mosh.get())))
def show4(*args):
try:
if ofile:
pass
except:
return
label_showframe1.configure(text="Start Frame: "+str(int(start_frame_mosh.get())))
start_frame_mosh.trace_add('write', show4)
end_frame_mosh.trace_add('write', show3)
#slider for echo mode
def midwork(value):
label_mid.configure(text="Start Point: "+str(round(value,1)))
label_mid = customtkinter.CTkLabel(master=frame_right,anchor='w',text="Start Point: 0.5",width=1)
mid_point=customtkinter.CTkSlider(master=frame_right, width=500,progress_color="black", fg_color="black",
from_=0,
to=1,
number_of_steps=10,command=midwork)
mid_point.set(0.5)
#Some options for sort mode
keepsort = customtkinter.CTkCheckBox(master=frame_right, text="Keep First Frames", onvalue=0, offvalue=1)
reversesort=customtkinter.CTkCheckBox(master=frame_right, text="Reverse", onvalue=False, offvalue=True)
#Options for ffglitch modes
hw_auto=customtkinter.CTkSwitch(master=frame_right,text="HW Acceleration \n(Auto)",onvalue=1, offvalue=0)
labelk=customtkinter.CTkLabel(master=frame_right,anchor='w',text="Keyframes:",width=1)
kf=customtkinter.CTkComboBox(master=frame_right,height=30, width=150,
values=["1000","100","10", "1"])
#Widget for Shuffle mde
def changeshuf(value):
shuf_label.configure(text="Chunk Size: "+str(int(value)))
shuf_label=customtkinter.CTkLabel(master=frame_right,anchor='w',text="Chunk Size: 1",width=1)
shuf_slider=customtkinter.CTkSlider(master=frame_right, width=500,
from_=1,
to=0,
number_of_steps=1, command=changeshuf)
shuf_slider.set(1)
#Widget for Fluid mode
def changefluid(value):
fluid_label.configure(text="Amount: "+str(int(value)))
fluid_label=customtkinter.CTkLabel(master=frame_right,anchor='w',text="Amount: 5",width=1)
slider_fluid=customtkinter.CTkSlider(master=frame_right, width=500,
from_=1,
to=20,
number_of_steps=100, command=changefluid)
slider_fluid.set(5)
#Stretch mode widget
v_h=customtkinter.CTkSwitch(frame_right,text="Horizontal Stretch", onvalue=1, offvalue=0)
#Button for motion transfer mode
def open_MT():
global vfile
vfile=tkinter.filedialog.askopenfilename(filetypes =[('Vector File', ['*.mp4','*.avi','*.mov','*.mkv']),('All Files', '*.*')])
if vfile:
mt_button.configure(fg_color='grey', text=os.path.basename(vfile))
else:
return
mt_button=customtkinter.CTkButton(master=frame_right, text="OPEN VIDEO", width=520, height=30,
compound="right",command=open_MT)
#Button for custom script mode
scriptfile=''
def open_script():
global scriptfile
scriptfile=tkinter.filedialog.askopenfilename(filetypes =[('Script File', ['*.js','*.py']),('All Files', '*.*')])
if scriptfile:
scriptbutton.configure(fg_color='grey', text=os.path.basename(scriptfile))
else:
scriptbutton.configure(fg_color=customtkinter.ThemeManager.theme["color"]["button"], text='OPEN SCRIPT')
scriptfile=''
scriptbutton=customtkinter.CTkButton(master=frame_right, text="OPEN SCRIPT", width=520, height=30,
compound="right",command=open_script)
#Dynamic UI functions for each widget
def rangeslider(x):
if x==1:
rangebar.place(x=20,y=210)
label_seconds1.place(x=25,y=200)
label_seconds2.place(x=470,y=200)
label_segment.place(x=25,y=170)
else:
rangebar.place_forget()
label_segment.place_forget()
label_seconds1.place_forget()
label_seconds2.place_forget()
def rangeslider2(x):
if x==1:
if (current=="Rise"):
rangebar2.place(x=20,y=260)
label_showframe1.place(x=25,y=250)
label_showframe2.place(x=470,y=250)
label_segment2.place(x=25,y=220)
else:
rangebar2.place(x=20,y=210)
label_showframe1.place(x=25,y=200)
label_showframe2.place(x=470,y=200)
label_segment2.place(x=25,y=170)
else:
rangebar2.place_forget()
label_showframe1.place_forget()
label_showframe2.place_forget()
label_segment2.place_forget()
def mid(x):
if x==1:
mid_point.place(x=20,y=210)
label_mid.place(x=25,y=170)
else:
mid_point.place_forget()
label_mid.place_forget()
def killoption(x):
if x==1 or x==2 or x==3:
label_kill.place(x=25,y=170)
slider_kill.place(x=20,y=200)
else:
label_kill.place_forget()
slider_kill.place_forget()
def positionslider(x):
if x==1:
label_frame1.place(x=25,y=230)
position_frame.place(x=20,y=260)
else:
label_frame1.place_forget()
position_frame.place_forget()
def framekeep(x):
if x==1:
keepframe.place(x=250,y=300)
elif x==2:
keepframe.place(x=250,y=240)
else:
keepframe.place_forget()
def audiokeep(x):
if x==1:
keepaudio.place(x=400,y=300)
elif x==2:
keepaudio.place(x=400,y=240)
else:
keepaudio.place_forget()
def ctimes(x):
if x==1:
ctime.place(x=110,y=300)
label_ctime.place(x=25,y=300)
else:
ctime.place_forget()
label_ctime.place_forget()
def pdelta(x):
if x==1:
delta.place(x=135,y=275)
label_p.place(x=25,y=275)
if current=="Repeat":
varp.set(5)
elif x==2:
delta.place(x=135,y=170)
label_p.place(x=25,y=170)
if current=="Glide":
varp.set(5)
else:
delta.place_forget()
label_p.place_forget()
def sortoptions(x):
if x==1:
keepsort.place(x=30, y=170)
reversesort.place(x=300, y=170)
else:
keepsort.place_forget()
reversesort.place_forget()
def ffgassist(x):
if x==1:
hw_auto.place(x=25, y=170)
labelk.place(x=300,y=170)
kf.place(x=380,y=170)
else:
hw_auto.place_forget()
labelk.place_forget()
kf.place_forget()
def shuf(x):
if x==1:
shuf_label.place(x=25,y=220)
shuf_slider.place(x=20,y=250)
else:
shuf_label.place_forget()
shuf_slider.place_forget()
def fluidwidget(x):
if x==1:
fluid_label.place(x=25,y=220)
slider_fluid.place(x=20,y=250)
else:
fluid_label.place_forget()
slider_fluid.place_forget()
def h_v(x):
if x==1:
v_h.place(x=25,y=220)
else:
v_h.place_forget()
def mtwid(x):
if x==1:
mt_button.place(x=20,y=230)
else:
mt_button.place_forget()
def custom(x):
if x==1:
scriptbutton.place(x=20,y=230)
else:
scriptbutton.place_forget()
#Main Function to update the widgets
def dynamic():
global current, showwidgets
allwidgets=[audiokeep, positionslider, killoption, framekeep,
ctimes, pdelta, rangeslider, rangeslider2, mid, sortoptions, ffgassist, fluidwidget, h_v, custom, mtwid, shuf]
for i in allwidgets:
i(0)
showwidgets=[]
if (current=="Bloom") or (current=="Pulse") or (current=="Pulse") or(current=="Overlap"):
showwidgets=[audiokeep, positionslider, killoption, framekeep, ctimes]
u=1
elif (current=="Jiggle"):
showwidgets=[positionslider, audiokeep, killoption, framekeep]
u=1
elif (current=="Void") or (current=="Reverse") or (current=="Invert") or (current=="Random"):
showwidgets=[killoption,audiokeep, framekeep]
u=2
elif (current=="Classic"):
showwidgets=[rangeslider, pdelta]
u=1
elif (current=="Glide"):
showwidgets=[pdelta]
u=2
elif (current=="Repeat") or (current=="Rise"):
if (current=="Rise"):
showwidgets=[rangeslider2, ffgassist]
else:
showwidgets=[rangeslider2, pdelta]
u=1
elif (current=="Echo"):
showwidgets=[mid]
u=1
elif (current=="Sort"):
showwidgets=[sortoptions]
u=1
elif ((current=="Buffer") or (current=="Sink") or (current=="Mirror") or (current=="Shear") or (current=="Noise")
or (current=="Delay") or (current=="Slam Zoom") or (current=="Invert-Reverse") or (current=="Shift") or (current=="Zoom")
or (current=="Slice")or (current=="Vibrate") or (current=="Stop")):
showwidgets=[ffgassist]
u=1
elif (current=="Fluid"):
showwidgets=[ffgassist, fluidwidget]
u=1
elif (current=="Stretch"):
showwidgets=[ffgassist, h_v]
u=1
elif (current=="Motion Transfer"):
showwidgets=[ffgassist, mtwid]
u=1
elif (current=="Custom Script"):
showwidgets=[ffgassist, custom]
u=1
elif (current=="Shuffle"):
showwidgets=[ffgassist, shuf]
u=1
for widgets in showwidgets:
widgets(u)
dynamic()
keepframe.select()
#autosave video function
def savename():
global sfile
if ofile:
try:
sfile=ofile[:-4]+"_datamoshed_"+current+'.'+optionmenu_1.get()
nf=0
while os.path.exists(sfile):
nf=nf+1
sfile=ofile[:-4]+"_datamoshed_"+current+'('+str(nf)+')'+'.'+optionmenu_1.get()
except:
sfile=""
#A function that will thread the main mosh function to separate the processes
def Threadthis():
global varp, varn
if delta.get()=='' or delta.get()<'1':
varp.set(1)
if ctime.get()=='' or ctime.get()<'1':
varn.set(1)
threading.Thread(target=Do_the_mosh).start()
#Converter function
def ffmpeg_convert(inputpath, parameters, outputpath, extra=''):
subprocess.call(f'"{ffmpeg}" {extra} -i "{inputpath}" {parameters} -y "{outputpath}"', shell=True)
#Main Function of the whole program
def Do_the_mosh():
global ofile, sfile, param, param2
button_mosh.configure(state=tkinter.DISABLED)
if previous=="":
tkinter.messagebox.showinfo("No Video imported!","Please import a video file!")
button_mosh.configure(state=tkinter.NORMAL)
return
try:
savename()
ProcessLabel.configure(text='STEP 1/3 CONVERTING...')
param="-c:v libx264 -preset medium -b:v 2M -minrate 2M -maxrate 2M -bufsize 2M" #Add other ffmpeg parameters in this line only
if ((current=="Bloom") or (current=="Pulse") or (current=="Pulse") or(current=="Overlap")
or (current=="Void") or (current=="Reverse") or (current=="Invert") or (current=="Random") or (current=="Jiggle")):
ifile=sfile[:-4]+".avi"
ffmpeg_convert(ofile,param,ifile)
ProcessLabel.configure(text='STEP 2/3 MOSHING...')
mfile=sfile[:-4]+"_corrupted.avi"
tomato.mosh(infile=ifile, outfile=mfile, m=current.lower(), c=varn.get(), n=int(position_frame.get()), k=round(slider_kill.get(),4), a=keepaudio.get(), f=keepframe.get())
time.sleep(1)
os.remove(ifile)
ProcessLabel.configure(text='STEP 3/3 FIXING THE CORRUPTED FILE...')
ffmpeg_convert(mfile,param,sfile)
os.remove(mfile)
elif ((current=="Classic") or (current=="Repeat") or (current=="Glide") or (current=="Sort") or (current=="Echo")):
param="-bf 0 -b 10000k" #Add other ffmpeg parameters in this line only for the above modes
ifile=sfile[:-4]+".avi"
ffmpeg_convert(ofile,param,ifile)
ProcessLabel.configure(text='STEP 2/3 MOSHING...')
mfile=sfile[:-4]+"_corrupted.avi"
if current=="Classic":
classic.Datamosh(ifile, mfile,s=int(start_mosh.get()),e=int(end_mosh.get()),p=varp.get(), fps=vid.get_meta_data()['fps'])
elif current=="Repeat":
repeat.Datamosh(ifile, mfile, s=int(start_frame_mosh.get()), e=int(end_frame_mosh.get()), p=varp.get(), fps=vid.get_meta_data()['fps'])
elif current=="Glide":
pymodes.library.glide(varp.get(), ifile, mfile)
elif current=="Sort":
pymodes.library.avi_sort(ifile, mfile, mode=keepsort.get(), rev=reversesort.get())
elif current=="Echo":
pymodes.library.process_streams(ifile, mfile, mid=round(mid_point.get(),1))
os.remove(ifile)
ProcessLabel.configure(text='STEP 3/3 FIXING THE CORRUPTED FILE...')
ffmpeg_convert(mfile,param,sfile)
os.remove(mfile)
else:
time.sleep(1)
ProcessLabel.configure(text='STEP 2/3 MOSHING...')
mfile=sfile[:-4]+"_corrupted.mpg"
if current=="Fluid":
basic_modes.library(ofile, mfile, mode=3, fluidity=int(slider_fluid.get()), gop=kf.get())
elif current=="Stretch":
basic_modes.library(ofile, mfile, mode=2, vh=v_h.get(), gop=kf.get())
elif current=="Motion Transfer":
if vfile:
basic_modes.library(ofile, mfile, mode=1, extract_from=vfile, gop=kf.get())
else:
tkinter.messagebox.showinfo("No Vector File imported!", "Please choose the video from where you want to extract the vector motion.")
button_mosh.configure(state=tkinter.NORMAL)
ProcessLabel.configure(text='Choose any secondary video file for transfering the vectors!')
return
elif current=="Shuffle":
basic_modes.library(ofile, mfile, mode=4, size=int(shuf_slider.get()), gop=kf.get())
elif current=="Rise":
basic_modes.library(ofile, mfile, mode=5, s=int(start_frame_mosh.get()), e=int(end_frame_mosh.get()-start_frame_mosh.get()), gop=kf.get())
elif current=="Custom Script":
external_script.mosh(ofile, mfile, mode=1, scriptfile=scriptfile, gop=kf.get())
else:
external_script.mosh(ofile, mfile, mode=2, effect=current, gop=kf.get())
ProcessLabel.configure(text='STEP 3/3 FIXING THE CORRUPTED FILE...')
if hw_auto.get()==1:
hw_type=' -hwaccel auto '
else:
hw_type=''
ffmpeg_convert(mfile,param,sfile,extra=hw_type)
os.remove(mfile)
except:
pass
#Check the result and complete the task
if os.path.exists(sfile):
tkinter.messagebox.showinfo("Exported!", "File exported successfully, \nFile Location:" +str(sfile))
ProcessLabel.configure(text="Last used: "+current)
button_mosh.configure(state=tkinter.NORMAL)
else:
tkinter.messagebox.showerror("Oops!", "Something went wrong! \nPlease recheck the settings and try again.")
ProcessLabel.configure(text='Recheck the settings and try again!')
button_mosh.configure(state=tkinter.NORMAL)
#Bottom Part
ProcessLabel = customtkinter.CTkLabel(master=frame_right,
width=400, height=30,corner_radius=10,
text="START DATAMOSHING!", fg_color=("white", "gray38"))
ProcessLabel.place(x=20,y=430)
button_mosh = customtkinter.CTkButton(master=frame_right, height=30,width=110,corner_radius=10,
text="MOSH", command=Threadthis)
button_mosh.place(x=430,y=430)
self.mainloop()
#--------------------------------------------------------------------#

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +0,0 @@
#Read this to use the python version.
This version is comparitively lower in size and works the same inside python environment.
Things to setup before running the python file:
The GUI of Datamosher-Pro.py given in this source code version is optimised for Windows; for other OS, download the python version from release page.
1) First setup ffglitch if you are using this repo only. (See readme.txt inside ffglitch folder to download ffglitch)
(Make sure you make it Unix executable if you are on Mac and also give permission)
Note: No need to setup the ffglitch if you downloaded the python version from release page as all the versions are pre-provided there
2) After doing that, run the datamosher-pro.py file and click yes if module error pops up and let the modules get downloaded.
If it doesn't work then install the modules manually-
# Modules you need to install:
-- tkinter
If not installed then use-
(pip install tk) or (sudo apt-get install python3-tk)
-- numpy
(pip install numpy)
-- imageio
(pip install imageio)
-- imageio-ffmpeg
(pip install imageio-ffmpeg)
# For Mac, you need to install one more module:
-- tkmacosx
(pip install tkmacosx)
3) Do not delete or move any assets or folder that are linked with the main file or else it will show error.
After the setup the application will open and you can try datamoshing.

127
Python Version/Setup.py Normal file
View File

@@ -0,0 +1,127 @@
#Automatic Setup for Datamosher-Pro
#Author: Akash Bora
#Importing some built in modules
import subprocess
import pkg_resources
import sys
import time
import os
import shutil
from zipfile import ZipFile
DIRPATH = os.path.dirname(os.path.realpath(__file__))
#Checking the required folders
folders= ["Assets","FFglitch","DatamoshLib","pymosh"]
missingfolder=[]
for i in folders:
if not os.path.exists(i):
missingfolder.append(i)
if missingfolder:
print("These folder(s) not available: "+str(missingfolder))
print("Download them from the repository properly")
sys.exit()
else:
print("All folders available!")
#Checking required modules
required = {'imageio', 'imageio-ffmpeg', 'numpy', 'customtkinter', 'pillow', 'rangeslider', 'requests'}
installed = {pkg.key for pkg in pkg_resources.working_set}
missing = required - installed
missingset=[*missing,]
#Download the modules if not installed
if missing:
res=input("Some modules are not installed \n do you want to download and install them? (Y/N): ")
while not ((res=="Y") or (res=="y") or (res=="N") or (res=="n")):
print("Please choose a valid option!")
res=input("Some modules are not installed \n do you want to download and install them? (Y/N): ")
if res=="Y" or res=="y":
try:
print("Installing modules...")
for x in range(len(missingset)):
y=missingset[x]
if sys.platform.startswith("win"):
subprocess.call('python -m pip install '+y, shell=True)
else:
subprocess.call('python3 -m pip install '+y, shell=True)
except:
print("Unable to download! \nThis are the required ones: "+str(required)+"\nUse 'pip install module_name' to download the modules one by one")
time.sleep(3)
sys.exit()
elif res=="N" or res=="n":
print("Without the modules you can't use this program. Please install them first! \nThis are the required one: "+str(required)
+"\nUse 'pip install module_name' to download modules one by one")
time.sleep(3)
sys.exit()
else:
print("All modules installed!")
#Check FFglitch Status
def checkffglitch():
print("Checking FFglitch:")
print("Running ffgac...")
ffgac=str(DIRPATH).replace(os.sep, '/')+"/FFglitch/ffgac"
ffedit=str(DIRPATH).replace(os.sep, '/')+"/FFglitch/ffedit"
try:
subprocess.Popen(f'"{ffgac}" -version', shell=True)
except:
print("permission denied! Please give permission to ffgac to execute.")
time.sleep(1)
print("Running ffedit...")
try:
subprocess.Popen(f'"{ffedit}" -version', shell=True)
except:
print("permission denied! Please give permission to ffedit to execute.")
time.sleep(1)
print("Done...")
#Download ffglitch if not available
if (os.path.exists("FFglitch/ffgac") or os.path.exists("FFglitch/ffgac.exe")) and (os.path.exists("FFglitch/ffedit") or os.path.exists("FFglitch/ffedit.exe")):
checkffglitch()
else:
print("ffgac/ffedit not found inside ffglitch folder, you cannot run the ffglitch modes without these programs")
res2=input("Do you want to download ffglitch now? (Y/N): ")
while not ((res2=="Y") or (res2=="y") or (res2=="N") or (res2=="n")):
print("Please choose a valid option!")
res2=input("Do you want to download ffglitch now? (Y/N): ")
if res2=="Y" or res2=="y":
print("Downloading FFglitch...(size: approx 17MB)")
if sys.platform.startswith("win"): #download ffglitch for windows
URL = "https://github.com/Akascape/FFglitch-0.9.3-executables/releases/download/zip-packages/ffglitch-0.9.3-win64.zip"
elif sys.platform.startswith("linux"): #download ffglitch for linux
URL = "https://github.com/Akascape/FFglitch-0.9.3-executables/releases/download/zip-packages/ffglitch-0.9.3-linux64.zip"
else: #download ffglitch for mac
URL = "https://github.com/Akascape/FFglitch-0.9.3-executables/releases/download/zip-packages/ffglitch-0.9.3-mac64.zip"
try:
try:
import requests
response = requests.get(URL)
open("FFglitch//ffglitch.zip", "wb").write(response.content)
except:
print("Unable to download ffglitch from site! Check your connection or download it manually from https://github.com/Akascape/FFglitch-0.9.3-executables \nand paste the files (ffgac and ffedit) inside FFglitch folder.")
time.sleep(3)
sys.exit()
time.sleep(1)
print("Exctracting the files...")
try:
with ZipFile('FFglitch/ffglitch.zip', 'r') as zip:
zip.extractall('FFglitch/')
except:
print("Failed to extract ffglitch.zip, please extract it manually in the FFglitch folder.")
time.sleep(3)
sys.exit()
if os.path.exists("FFglitch/ffgac") or os.path.exists("FFglitch/ffgac.exe"):
os.remove("FFglitch//ffglitch.zip")
time.sleep(1)
checkffglitch()
print("FFglitch setup complete!")
except:
print("Something went wrong!")
elif res2=="N" or res2=="n":
print("ffglitch modes cannot run without ffgac and ffedit, download them manually and paste them inside the FFglitch folder.")
#Everything done!
print("Setup Complete!")
time.sleep(5)
sys.exit()

View File

@@ -1,11 +0,0 @@
All ffglitch builds are given in the release python version, so download that directly
For people downloading this repo,
Download ffglitch from ffglitch.org or the direct links are given below:
For windows:
https://ffglitch.org/pub/bin/win64/ffglitch-0.9.3-win64.7z
For linux:
https://ffglitch.org/pub/bin/linux64/ffglitch-0.9.3-linux64.7z
For mac:
https://ffglitch.org/pub/bin/mac64/ffglitch-0.9.3-mac64.7z
After downloading, extract the files and move the ffedit and ffgac file in this ffglitch folder of datamosher pro.

View File

@@ -0,0 +1,7 @@
Copyright (c) 2011 - 2014 Joe Friedl
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1 +0,0 @@

View File

@@ -1 +0,0 @@

View File

@@ -2,45 +2,45 @@
# Datamosher Pro
<b>Datamoshing is a cool video effect and if you want to achieve this glitch with your videos, then you are in the right place!
<br><img align="right" src="https://user-images.githubusercontent.com/89206401/141642297-7c62cf6f-7024-430f-88a2-c9cbbf0dc655.png" width="300">
<br> Datamosher Pro is an automated glitching application for free! With Datamosher Pro you can quickly and easily datamosh your videos! </b> <br>
<br> Datamosher Pro is an automated glitching application for free (python version)! With Datamosher Pro you can quickly and easily datamosh your videos! </b> <br>
### Why I made this?
I was also looking for some good datamoshing software and I found that you have to either use those old softwares like Avidemux or have to look for some paid plugins, so I created my own python based application 'Datamosher Pro' which is an open source project. It contains `30+` different effects which can replicate any type of datamoshing style.
I was also looking for some good datamoshing software and I found that you have to either use those old softwares like Avidemux or have to look for some paid plugins, so I created my own python based application 'Datamosher Pro'. It contains `30+` different effects which can replicate any type of datamoshing style.
It comes in two version, one paid and one basic free source code version.
# DOWNLOAD
### <p align='center'> Support Datamosher-Pro Development by purchashing its executable version for *windows* on Gumroad which have a modern UI and lots of other features. It will be really helpful!
### <p align='center'> EXECUTABLE VERSION
<br> <p align='center'> [<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Akascape/Datamosher-Pro?display_name=release&label=Windows&logo=Windows&logoColor=019df4&style=for-the-badge" width="500">](https://akascape.gumroad.com/l/Datamosher-Pro) </br>
### <p align='center'> MODERN VERSION (SEE DETAILS)
<br> <p align='center'> [<img src="https://img.shields.io/badge/WINDOWS-DATAMOSHER_PRO-informational?style=for-the-badge&logo=Microsoft&logoColor=blue&color=007ec6" width="500">](https://akascape.gumroad.com/l/Datamosher-Pro) </br>
<br>
### <p align='center'> FREE SOURCE CODE VERSIONS
### <p align='center'> FREE BASIC SOURCE CODE VERSIONS
<br> <p align='center'> [<img src="https://img.shields.io/badge/Python_Version-Windows-informational?style=flat&logo=Microsoft&logoColor=blue&color=1bdce3" width=300>](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Prov1.7/Datamosher_Pro-python_version-win.zip)
<br> <p align='center'> [<img src="https://img.shields.io/badge/Python_Version-MacOS-informational?style=flat&logo=apple&logoColor=b0b5b9&color=b2b7bb" width=300 height=35>](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Prov1.7/Datamosher_Pro-python_version-mac.zip)
<br> <p align='center'> [<img src="https://img.shields.io/badge/Python_Version-Linux-informational?style=flat&logo=linux&logoColor=black&color=eaea4a" width=300 height=35>](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Prov1.7/Datamosher_Pro-python_version-linux.zip) <br> Don't forget to give a ⭐ :) </p>
# How to Install?
- For the standalone/executable version, just extract the downloaded zip file and run the Datamosher_Pro.exe application.
<br> Benefits of having the executable version:
<br>• All the files are packed in one executable application
<br>• No environment or setup problems
<br>• Faster workflow
<br>• Earlier updates
<br>• Custom Script mode is available
- For those who are using the python-version,
<br> Download the correct python version and make sure you have python installed properly. Extract the zip file and open the "datamosher_pro-python_version" folder and just run that Datamosher-Pro.py file. If any module error pops up then just click on yes and the required modules will get downloaded automatically. You can also do that manually if it doesn't work. Then it is ready to use! (No python skills needed)
<br> Download the correct python version (3.10+ recomended) and make sure you have python installed properly. Extract the zip file and open the "datamosher_pro-python_version" folder and just run that Datamosher-Pro.py file. If any module error pops up then just click on yes and the required modules will get downloaded automatically. You can also do that manually if it doesn't work. Then it is ready to use! (No python skills needed)
- For the executable version, just extract the downloaded zip file and run the Datamosher_Pro.exe application.
# How to Use?
For the basic python version:
• Input the video file first (supported formats- mp4, gif, avi, mov, mkv, wmv)
<br>• Choose the desired datamosh mode and the export format (mp4 is recommended)
<br>• Use the advanced options to get more accurate results
<br>• Check/uncheck the highest quality box for quality adjustments
<br>• Then simply click on the datamosh button and wait for a few seconds
<br>• After conversions, your video will be moshed and saved in the same directory
## Gallery & Demos
**Important Tip: Press "q" key in the command line whenever you want to end a long running conversion process.**
### A documentation is also available in the [Wiki](https://github.com/Akascape/Datamosher-Pro/wiki) page
## Gallery
[![forthebadge](https://forthebadge.com/images/badges/check-it-out.svg)](https://github.com/Akascape/Datamosher-Pro/blob/Datamosher-Pro-v1.7/Demos.md)
# Effects Info
### Effects List:
### Effects List available in the python version:
<br> TIP: Major effects used for datamoshing are Classic, Bloom, Glide, Repeat, Motion Transfer, Rise, Fluid
<br>
| Effect Name | Description |
| ----------------| --------------------------------------------------------------------- |
| Custom Script (NEW)| This mode is only available in paid version where you can use any ffglitch script|
| Rise | another classic i frames removal effect|
| Shuffle | randomly shuffles chunks of video frames with the classic ffglitch datamosh (unstable with short videos)|
| Buffer | creates ring buffers to mosh|
@@ -73,7 +73,8 @@ I was also looking for some good datamoshing software and I found that you have
| Overlap | copy group of c frames taken from every nth position|
| Jiggle | take frame from around current position. n parameter is spread size|
| Void | gives a clean output but with distortion|
### How to use Advanced Options?
## More effects including these ones are all available in the paid version.
### How to use Advanced Options (Python version)?
The advanced tab is very useful if you want accurate results. The options are:
<br>• `Glitch Size` - tells how long/often to glitch per part (depends on the mode)
<br>• `Frame Frequency` - tells how many frames to apply/repeat in the glitch
@@ -89,14 +90,16 @@ The advanced tab is very useful if you want accurate results. The options are:
<br>- Some modes may not support all the 4 advanced options.
<br>- You can try experimenting with the options but don't put huge values.
<br>- Audio glitching is only available in few modes like classic and repeat.
# UI
# UI (BASIC PYTHON VERSION)
| Windows | Linux | MacOS |
| ---------| ------- | ------- |
| ![Windows UI](https://user-images.githubusercontent.com/89206401/142208408-6970448d-fe9d-4e60-aac6-21809aefcfca.png) | ![Linux UI](https://user-images.githubusercontent.com/89206401/168416728-fc9bc8e5-ce34-40c8-9222-bf9986dbb280.png) | ![Mac UI](https://user-images.githubusercontent.com/89206401/168416751-73658dcf-506f-4166-933b-e3f3cb43194c.png) |
### The new modern UI is available in the paid version.
# UI (PAID VERSION ONLY WINDOWS)
### This modern UI is available in the paid version only.
![newthemes](https://user-images.githubusercontent.com/89206401/174493211-febc4193-1090-4dbb-8eea-23d7d10e3741.png)
## How It Works?
The main issue with datamoshing is conversion of corrupted files but with Datamosher Pro you can use any video file and it will export an usable datamoshed file. But I still recomend everyone to use MP4 videos. The video is first converted to the required file format using ffmpeg (distributed **externally** with Imageio module) and then the effect is applied and the corrupted file is converted back to stable version using the same process so that the output video can directly be used in other editing softwares. All the unnecessary temp files are removed automatically.
### Read these guides for more details:
### Read these guides for more details about the python version:
<br> [![Read](https://img.shields.io/badge/Guide-1-orange)](https://akascape.gumroad.com/p/datamosher-pro-guide) [![Read](https://img.shields.io/badge/Guide-2-green)](https://akascape.gumroad.com/p/datamosher-pro-guide-2)
## Conclusion
You will not find this type of software anywhere with so many effects only for datamoshing. This program can be your companion while editing cool glitchy videos :)
@@ -107,7 +110,8 @@ All the logos and designs are created by me. <br>-Akash Bora
## License
[<img src="https://user-images.githubusercontent.com/89206401/168461242-884f25ce-eb67-406a-9d98-cf8d0f28cb43.png" width=100>](https://github.com/Akascape/Datamosher-Pro/blob/Datamosher-Pro-v1.7/LICENSE)
Note that the **FFglitch** part provided in the *releases* is not placed under this license. It is itself an independent program provided without any **modification**. When distributing an application with this package, it must be taken into account that multiple licenses are involved. See the [FFglitch's github page](https://github.com/ramiropolla/ffglitch-core/tree/master) for further details. (The source code is freely available there)
Only the python version is licensed under MIT. The executable windows version is different and closed source.
Note that the **FFglitch** part provided in the *releases* is not placed under this license. It is itself an independent program provided without any **modification**. When distributing an application with this package, it must be taken into account that multiple licenses are involved. See the [FFglitch's github page](https://github.com/ramiropolla/ffglitch-core/tree/master) for further details. (That source code is freely available there)
<br>
## Follow me
[<img src="https://img.shields.io/badge/-Github-informational?style=flat&logo=github&logoColor=black&color=grey">](https://github.com/Akascape)
@@ -116,5 +120,5 @@ Note that the **FFglitch** part provided in the *releases* is not placed under t
[<img src="https://img.shields.io/badge/-Twitter-informational?style=flat&logo=twitter&logoColor=black&color=blue">](https://twitter.com/Akascape)
<br> DATAMOSHING MADE EASY!
### Current Version-1.7
<br> [![forthebadge made-with-python](http://ForTheBadge.com/images/badges/made-with-python.svg)](https://www.python.org/) [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/Akascape/Datamosher-Pro) [![forthebadge](https://forthebadge.com/images/badges/open-source.svg)](https://github.com/Akascape/Datamosher-Pro) [![forthebadge](https://forthebadge.com/images/badges/not-a-bug-a-feature.svg)](https://github.com/Akascape/Datamosher-Pro)
<br> [![forthebadge made-with-python](http://ForTheBadge.com/images/badges/made-with-python.svg)](https://www.python.org/) [![forthebadge](https://forthebadge.com/images/badges/built-with-love.svg)](https://github.com/Akascape/Datamosher-Pro) [![forthebadge](https://forthebadge.com/images/badges/not-a-bug-a-feature.svg)](https://github.com/Akascape/Datamosher-Pro)
[![footer](https://capsule-render.vercel.app/api?type=rect&color=timeGradient&height=2)](https://opensourcelibs.com/lib/capsule-render)