Compare commits
401 Commits
Datamosher
...
Datamosher
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a964ecf891 | ||
|
|
7933558b15 | ||
|
|
ce394fcd90 | ||
|
|
2150cd6019 | ||
|
|
b368dfc9c7 | ||
|
|
816d1150bd | ||
|
|
1d45e22e55 | ||
|
|
9755263e6e | ||
|
|
8e4ddc83e9 | ||
|
|
cfdb269b1e | ||
|
|
6c4823fe81 | ||
|
|
2e45e67162 | ||
|
|
f7c62a5944 | ||
|
|
18b043f4be | ||
|
|
684f036fc7 | ||
|
|
4897db579b | ||
|
|
420ff634a6 | ||
|
|
2dda202bf2 | ||
|
|
5e0183ccdc | ||
|
|
f4dddd98be | ||
|
|
3ce6cfdbc7 | ||
|
|
6ef19a1abc | ||
|
|
e9506e15d9 | ||
|
|
ad210e74d5 | ||
|
|
227edad13b | ||
|
|
c815190585 | ||
|
|
95181d47ca | ||
|
|
7e4d5f7de2 | ||
|
|
a22762a278 | ||
|
|
4c079e9082 | ||
|
|
68729edfce | ||
|
|
e7deabc4f9 | ||
|
|
0d55f2e986 | ||
|
|
32fef121c2 | ||
|
|
5698e82263 | ||
|
|
4eff80cb69 | ||
|
|
b010bbbcf7 | ||
|
|
17ad34dc0b | ||
|
|
e3d0d4b7fd | ||
|
|
742d2e2d07 | ||
|
|
eb17df87a9 | ||
|
|
b998857839 | ||
|
|
b2e1c09d9f | ||
|
|
80eb097737 | ||
|
|
ab0210218a | ||
|
|
6a59545302 | ||
|
|
f3cf028196 | ||
|
|
cc61e38c44 | ||
|
|
ef73387c3f | ||
|
|
245b677b36 | ||
|
|
3d73ad05e2 | ||
|
|
d3f1decbc1 | ||
|
|
13f136ece5 | ||
|
|
dfab621710 | ||
|
|
391d5320ca | ||
|
|
b771ce2b8f | ||
|
|
f5cfb2499a | ||
|
|
969d2d4a57 | ||
|
|
69afe9c5d3 | ||
|
|
6d745b8c06 | ||
|
|
4d91f7751a | ||
|
|
f42675f9d2 | ||
|
|
b1f1b895c5 | ||
|
|
fbd9bdafc2 | ||
|
|
f2681f2618 | ||
|
|
61972e7c57 | ||
|
|
ce2b1ae6bd | ||
|
|
1f17293186 | ||
|
|
3d9caefb43 | ||
|
|
83375c7434 | ||
|
|
93880013fa | ||
|
|
f2d234ec11 | ||
|
|
e6c55b9044 | ||
|
|
9327dd8d97 | ||
|
|
74d7be4780 | ||
|
|
34a09f838a | ||
|
|
909f58cc7d | ||
|
|
2eaed8f637 | ||
|
|
60ae44dda2 | ||
|
|
09665d4de3 | ||
|
|
2e54e9c591 | ||
|
|
ca0ccf77a1 | ||
|
|
24ff4160c3 | ||
|
|
78c9ef647e | ||
|
|
cf6f49037e | ||
|
|
98f40a5911 | ||
|
|
f6958a7e9b | ||
|
|
e05a97d6e3 | ||
|
|
598289a895 | ||
|
|
73544c5b3f | ||
|
|
9414d2b946 | ||
|
|
e0ffc33e26 | ||
|
|
4546ecee13 | ||
|
|
7e06b2f124 | ||
|
|
2d09c8bac8 | ||
|
|
9e8dd3d285 | ||
|
|
e65d30f2a5 | ||
|
|
497a9f7d99 | ||
|
|
1ed2d4aab5 | ||
|
|
3bde81d967 | ||
|
|
6f30e45057 | ||
|
|
73e2b59ff2 | ||
|
|
c5629a73e2 | ||
|
|
ea51fd9900 | ||
|
|
5989c8653f | ||
|
|
3b3de85fa2 | ||
|
|
b440b215de | ||
|
|
74a9bf8336 | ||
|
|
a1a54dbf7e | ||
|
|
b552c1ce54 | ||
|
|
21ca9e6fea | ||
|
|
d53a745704 | ||
|
|
a36f132bbf | ||
|
|
2ecd7a8162 | ||
|
|
725f9d74e4 | ||
|
|
1d1d5998a8 | ||
|
|
5184fc62bc | ||
|
|
7921cdb4ab | ||
|
|
7dd5d4b746 | ||
|
|
80c206a5e0 | ||
|
|
68907f3685 | ||
|
|
4de266155a | ||
|
|
c8a6506875 | ||
|
|
2c9749bd77 | ||
|
|
9dccaf17b6 | ||
|
|
663ecf03df | ||
|
|
914d93c238 | ||
|
|
dced83ea8a | ||
|
|
38ea10e4ac | ||
|
|
55e0d418e3 | ||
|
|
67303a840f | ||
|
|
1d6b6e8cdd | ||
|
|
a022842f28 | ||
|
|
c4cf92f9e0 | ||
|
|
0898daa4d5 | ||
|
|
8cdc874866 | ||
|
|
941238f4c2 | ||
|
|
66f70f65aa | ||
|
|
d658464ff0 | ||
|
|
e477751d4d | ||
|
|
6b4e16bf2b | ||
|
|
cb84fe98c8 | ||
|
|
b3c6e53217 | ||
|
|
d22922cc9b | ||
|
|
2c38299b99 | ||
|
|
f41b8f164f | ||
|
|
10a6ac81de | ||
|
|
a6ed78aab2 | ||
|
|
dd651efb44 | ||
|
|
5c3185c8a4 | ||
|
|
3ced022980 | ||
|
|
bd7e2a76ef | ||
|
|
8c5df70e86 | ||
|
|
6667576e18 | ||
|
|
a67bde6ddc | ||
|
|
67e690433f | ||
|
|
dab12e581c | ||
|
|
12f053cc88 | ||
|
|
2f1addb3d0 | ||
|
|
631bc45b16 | ||
|
|
372bad379c | ||
|
|
e21e642363 | ||
|
|
296ba5972a | ||
|
|
b1903c20e3 | ||
|
|
c4ce269ceb | ||
|
|
1d47f11bcc | ||
|
|
0d54c810a2 | ||
|
|
b61235313f | ||
|
|
38e0759c8d | ||
|
|
fdc3ee232a | ||
|
|
6fc14f240c | ||
|
|
7a7e40bdc0 | ||
|
|
1bab4ca73b | ||
|
|
45e7191482 | ||
|
|
2261882d4d | ||
|
|
e0cd9ae593 | ||
|
|
d3580a3e95 | ||
|
|
63fa5736c7 | ||
|
|
60129a0c58 | ||
|
|
b839cdd0e3 | ||
|
|
b0d9407839 | ||
|
|
7a4a3cae3b | ||
|
|
fb83ced395 | ||
|
|
e5034fa829 | ||
|
|
118c0c31cd | ||
|
|
9b9a99ccc0 | ||
|
|
86b52c0ade | ||
|
|
ac7fc06c91 | ||
|
|
65e9762904 | ||
|
|
a62ca393bb | ||
|
|
432444bb54 | ||
|
|
fbe3095197 | ||
|
|
bae79d26a2 | ||
|
|
72db4853b1 | ||
|
|
14d49ebf49 | ||
|
|
242dbdf2ca | ||
|
|
4ba7019504 | ||
|
|
7452e5f25b | ||
|
|
85cdf9ce83 | ||
|
|
f318f209aa | ||
|
|
955c4649f5 | ||
|
|
9af1f75d09 | ||
|
|
e37d32940d | ||
|
|
e9645dd93f | ||
|
|
d8c9daee78 | ||
|
|
d9eedaa6dd | ||
|
|
4ea1a79983 | ||
|
|
c00e7c6da5 | ||
|
|
404c4daeb7 | ||
|
|
f487b45e6c | ||
|
|
75008bb731 | ||
|
|
091ffce77e | ||
|
|
0fcb9f94a3 | ||
|
|
e8331d0cda | ||
|
|
23ecb5dd17 | ||
|
|
46ffc00a9b | ||
|
|
3152afc610 | ||
|
|
c45e9108fb | ||
|
|
a27e4f1389 | ||
|
|
b8a192336f | ||
|
|
6a1247c108 | ||
|
|
ece8f5b2f0 | ||
|
|
721125045e | ||
|
|
690af0c2a0 | ||
|
|
4b8f1892fa | ||
|
|
1193b576e1 | ||
|
|
94560f774e | ||
|
|
63076e5312 | ||
|
|
de0e5d19dc | ||
|
|
777a269a39 | ||
|
|
f47fd83c62 | ||
|
|
43a3a8248e | ||
|
|
89e614a106 | ||
|
|
b0f496a9cb | ||
|
|
3d41bd09d0 | ||
|
|
0855485798 | ||
|
|
0481cd8837 | ||
|
|
4cdd5cbea0 | ||
|
|
8dfb2f0376 | ||
|
|
8ec7a3491c | ||
|
|
ca201e79b1 | ||
|
|
a315b0591e | ||
|
|
33002cae22 | ||
|
|
6845c5c238 | ||
|
|
da23ee6ba9 | ||
|
|
59a17f4e90 | ||
|
|
f5887de50a | ||
|
|
4fcf04b6d7 | ||
|
|
146b5622e0 | ||
|
|
dfb4fc123f | ||
|
|
7f16b44b5d | ||
|
|
c6eaa2c9ae | ||
|
|
c393df510e | ||
|
|
a6fa8335c4 | ||
|
|
b042077895 | ||
|
|
784ae26471 | ||
|
|
2cbe7e46c2 | ||
|
|
8dbb97b8a1 | ||
|
|
de1b4119e8 | ||
|
|
cdf76fc39c | ||
|
|
888ad565a3 | ||
|
|
c7e07c0657 | ||
|
|
bd178ed811 | ||
|
|
73920b751e | ||
|
|
e068834c98 | ||
|
|
40ee09903a | ||
|
|
fb4e72791b | ||
|
|
0be779eb72 | ||
|
|
6b444f6b32 | ||
|
|
568ecd2f6f | ||
|
|
3fea9fd251 | ||
|
|
13497e6898 | ||
|
|
c84d8624cc | ||
|
|
3d310828fb | ||
|
|
1ccb289ced | ||
|
|
76df62de23 | ||
|
|
2a7fe5a557 | ||
|
|
d4cb468c37 | ||
|
|
ce01397a9d | ||
|
|
45ddf02c07 | ||
|
|
292c592b71 | ||
|
|
ee6f6b888e | ||
|
|
fd9c509568 | ||
|
|
5b1b29f4d7 | ||
|
|
76824887b3 | ||
|
|
f6861ffaca | ||
|
|
323039c372 | ||
|
|
89af07fffc | ||
|
|
ba4482d847 | ||
|
|
35061a45f0 | ||
|
|
cddfd13876 | ||
|
|
6997be3222 | ||
|
|
4c75c57702 | ||
|
|
889296e843 | ||
|
|
465f1f9f70 | ||
|
|
1a6801b8dc | ||
|
|
fa9c3ec524 | ||
|
|
4124085855 | ||
|
|
5c5c08709e | ||
|
|
9b4be683bb | ||
|
|
e151d35141 | ||
|
|
c304307290 | ||
|
|
567a418565 | ||
|
|
6adaff1c3e | ||
|
|
e8bfa4cff1 | ||
|
|
c71290d3f7 | ||
|
|
5c735ab872 | ||
|
|
ae2aa0ac22 | ||
|
|
32a49881c8 | ||
|
|
3b73fc1e1e | ||
|
|
b29e3de661 | ||
|
|
8bd8d2bfe5 | ||
|
|
a0878a4d58 | ||
|
|
30d5ff4a18 | ||
|
|
b4b5017cbb | ||
|
|
bb3b473ed4 | ||
|
|
20cbc47dd2 | ||
|
|
bd80ab5abd | ||
|
|
7fbe8154b3 | ||
|
|
e4151cb699 | ||
|
|
d3bbddaecd | ||
|
|
0cf4780339 | ||
|
|
6fb9b76ba6 | ||
|
|
f2ed355c28 | ||
|
|
9d95636384 | ||
|
|
00a046d5d6 | ||
|
|
b50cf4d8a2 | ||
|
|
d62e227eb2 | ||
|
|
5accc347b7 | ||
|
|
7d93d7f5be | ||
|
|
133cda7f6b | ||
|
|
5ab58962da | ||
|
|
7f417425e8 | ||
|
|
d9cc58a8be | ||
|
|
718d5bbf63 | ||
|
|
a26a070c25 | ||
|
|
f956caefaf | ||
|
|
385c8ed9b6 | ||
|
|
79c2d535e1 | ||
|
|
8ac13ec9e3 | ||
|
|
e56ebe748c | ||
|
|
7d72a63073 | ||
|
|
8555a1fe29 | ||
|
|
415ba0fc40 | ||
|
|
b4e93ea104 | ||
|
|
d46cdc86df | ||
|
|
dd21904f46 | ||
|
|
0090d1e8f1 | ||
|
|
b402e87f06 | ||
|
|
8c93d5cd8c | ||
|
|
c52e497b3e | ||
|
|
b394070e7a | ||
|
|
628054648a | ||
|
|
e8868946ba | ||
|
|
87898fe269 | ||
|
|
0b2a54d236 | ||
|
|
4c19db188b | ||
|
|
3ed4a0e746 | ||
|
|
de9ecf5539 | ||
|
|
8ac2af9d2b | ||
|
|
3922a6272e | ||
|
|
51591d1e62 | ||
|
|
9f3050ebc9 | ||
|
|
5c78c3a632 | ||
|
|
0b36988881 | ||
|
|
52aedf2721 | ||
|
|
06205faac0 | ||
|
|
af89678db5 | ||
|
|
a126cf68b1 | ||
|
|
386c5d8973 | ||
|
|
d1d0ad47dd | ||
|
|
33e1278333 | ||
|
|
2b854a09d2 | ||
|
|
4567c8042e | ||
|
|
183fb198fb | ||
|
|
f4e301a6b5 | ||
|
|
e670021e04 | ||
|
|
c1098c960b | ||
|
|
6f44d65b13 | ||
|
|
f8b10aa523 | ||
|
|
f865c42f98 | ||
|
|
e3df5d9812 | ||
|
|
f6f9848213 | ||
|
|
e5574256b9 | ||
|
|
648f374869 | ||
|
|
f57b0959f7 | ||
|
|
2de6ccfd7d | ||
|
|
713b273e48 | ||
|
|
7ef337c060 | ||
|
|
b05dadee5e | ||
|
|
8a441e96b9 | ||
|
|
9e623c505c | ||
|
|
835b537aa8 | ||
|
|
d0e6a68abb | ||
|
|
ed79147f9f | ||
|
|
418e2eb89c | ||
|
|
3cf14faf8d | ||
|
|
cf324ee4d4 | ||
|
|
a694f25d3a | ||
|
|
37e3b59a27 | ||
|
|
1609143b12 |
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Akascape
|
||||
Copyright (c) 2022 Akash Bora
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
BIN
Python Version/Assets/Icons/Logo.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
Python Version/Assets/Icons/Program_icon.png
Normal file
|
After Width: | Height: | Size: 372 KiB |
BIN
Python Version/Assets/Icons/right_icon.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
Python Version/Assets/Icons/settings.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
Python Version/Assets/Icons/video_icon.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
BIN
Python Version/Assets/thumbnail_cache/offline_image.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
1
Python Version/Assets/version/VERSIONPY.txt
Normal file
@@ -0,0 +1 @@
|
||||
1.8
|
||||
154
Python Version/DatamoshLib/FFG_effects/basic_modes.py
Normal 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)
|
||||
15
Python Version/DatamoshLib/FFG_effects/external_script.py
Normal 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')
|
||||
75
Python Version/DatamoshLib/FFG_effects/jscripts/Buffer.js
Normal file
@@ -0,0 +1,75 @@
|
||||
// dd_ring_buffer.js
|
||||
// works kinda like an audio delay
|
||||
// stacks the previous n frames into a buffer
|
||||
|
||||
// global variable holding forward motion vectors from previous frames
|
||||
var prev_fwd_mvs = [ ];
|
||||
|
||||
// change these values to use a smaller or greater number of frames to
|
||||
// perform the average of motion vectors
|
||||
|
||||
// try making the delay long enough to overlap an edit in the content ...
|
||||
var delay = 10;
|
||||
// divisor controls "feedback" ... or "feedforward" which ever is a better description ...
|
||||
var feedback = 0.5; // a number between 0.000001 and .... yeah - controls how much of the buffered mv gets into the next pass
|
||||
|
||||
var divisor = 1.0/feedback;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// update variable holding forward motion vectors from previous
|
||||
// frames. note that we perform a deep copy of the clean motion
|
||||
// vector values before modifying them.
|
||||
let json_str = JSON.stringify(fwd_mvs);
|
||||
let deep_copy = JSON.parse(json_str);
|
||||
// push to the end of array
|
||||
prev_fwd_mvs.push(deep_copy);
|
||||
// drop values from earliest frames to always keep the same tail
|
||||
// length
|
||||
if ( prev_fwd_mvs.length > delay )
|
||||
prev_fwd_mvs = prev_fwd_mvs.slice(1);
|
||||
|
||||
// bail out if we still don't have enough frames
|
||||
if ( prev_fwd_mvs.length != delay )
|
||||
return;
|
||||
|
||||
// replace all motion vectors of current frame with an average
|
||||
// of the motion vectors from the previous 10 frames
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
let delay_row = prev_fwd_mvs[0][i];
|
||||
let insert_row = prev_fwd_mvs[delay-1][i];
|
||||
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
let dmv = delay_row[j];
|
||||
let imv = insert_row[j];
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
|
||||
// temp copy of the incoming vectors
|
||||
let x = mv[0];
|
||||
let y = mv[1];
|
||||
// pull their replacements out of the buffer
|
||||
mv[0] = dmv[0];
|
||||
mv[1] = dmv[1];
|
||||
// feedback the 'old' with the 'new' for next time
|
||||
imv[0] = (dmv[0] / divisor) + x;
|
||||
imv[1] = (dmv[1] / divisor) + y;
|
||||
// rinse and repeat
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
71
Python Version/DatamoshLib/FFG_effects/jscripts/Delay.js
Normal file
@@ -0,0 +1,71 @@
|
||||
// dd_delay.js
|
||||
// works kinda like an audio delay
|
||||
// stacks the previous n frames into a buffer
|
||||
|
||||
// global variable holding forward motion vectors from previous frames
|
||||
var prev_fwd_mvs = [ ];
|
||||
|
||||
// change these values to use a smaller or greater number of frames to
|
||||
// perform the average of motion vectors
|
||||
|
||||
// try making the delay long enough to overlap an edit in the content ...
|
||||
var delay = 20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// update variable holding forward motion vectors from previous
|
||||
// frames. note that we perform a deep copy of the clean motion
|
||||
// vector values before modifying them.
|
||||
let json_str = JSON.stringify(fwd_mvs);
|
||||
let deep_copy = JSON.parse(json_str);
|
||||
// push to the end of array
|
||||
prev_fwd_mvs.push(deep_copy);
|
||||
// drop values from earliest frames to always keep the same tail
|
||||
// length
|
||||
if ( prev_fwd_mvs.length > delay )
|
||||
prev_fwd_mvs = prev_fwd_mvs.slice(1);
|
||||
|
||||
// bail out if we still don't have enough frames
|
||||
if ( prev_fwd_mvs.length != delay )
|
||||
return;
|
||||
|
||||
// replace all motion vectors of current frame with an average
|
||||
// of the motion vectors from the previous 10 frames
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
let delay_row = prev_fwd_mvs[0][i];
|
||||
let insert_row = prev_fwd_mvs[delay-1][i];
|
||||
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
let dmv = delay_row[j];
|
||||
let imv = insert_row[j];
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
|
||||
// temp copy of the incoming vectors
|
||||
let x = mv[0];
|
||||
let y = mv[1];
|
||||
// pull their replacements out of the buffer
|
||||
mv[0] = dmv[0];
|
||||
mv[1] = dmv[1];
|
||||
// feedback the 'old' with the 'new' for next time
|
||||
imv[0] = x;
|
||||
imv[1] = y;
|
||||
// rinse and repeat
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
// dd_RandomDamage(invertRandomN).js
|
||||
// invert x and y component of mv for random number of frames if threshold met for frame
|
||||
|
||||
let threshold = 95;
|
||||
var TRIGGERED = 0;
|
||||
var nFrames = 10;
|
||||
var frameCount = 0;
|
||||
var MAGNITUDE = 20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
|
||||
var do_or_not = Math.random() * 100;
|
||||
if(do_or_not > threshold){
|
||||
if(TRIGGERED > 0){
|
||||
|
||||
}else{
|
||||
TRIGGERED = 1;
|
||||
frameCount = 0;
|
||||
nFrames = Math.random() * MAGNITUDE;
|
||||
}
|
||||
}
|
||||
// only do the glitch if our random number crosses the threshold
|
||||
if(TRIGGERED > 0 & frameCount <= nFrames){
|
||||
frameCount++;
|
||||
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
var M_W = row.length/2;
|
||||
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
// STOP XY
|
||||
mv[0] = 0 - mv[0];
|
||||
mv[1] = 0 - mv[1];
|
||||
}
|
||||
}
|
||||
}else{
|
||||
TRIGGERED = 0;
|
||||
}
|
||||
}
|
||||
52
Python Version/DatamoshLib/FFG_effects/jscripts/Mirror.js
Normal file
@@ -0,0 +1,52 @@
|
||||
// dd_mirror_X.js
|
||||
|
||||
// clean buffer :
|
||||
var buffer = [ ];
|
||||
|
||||
var ZOOM = -20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// note that we perform a deep copy of the clean motion
|
||||
// vector values before modifying them.
|
||||
let json_str = JSON.stringify(fwd_mvs);
|
||||
let deep_copy = JSON.parse(json_str);
|
||||
// stick em in the buffer
|
||||
buffer = deep_copy;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// VERTICALLY
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
|
||||
// loop through all rows
|
||||
|
||||
let row = fwd_mvs[i];
|
||||
var row2 = buffer[i];
|
||||
//var row2 = fwd_mvs[(fwd_mvs.length-1)-i];
|
||||
|
||||
var M_W = row.length/2;
|
||||
|
||||
// HORIZONTALLY
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
var mv2 = row2[(row.length - 1) - j];
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
//if(i>M_W){
|
||||
mv[0] = 0-mv2[0];
|
||||
mv[1] = mv2[1];
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
67
Python Version/DatamoshLib/FFG_effects/jscripts/Noise.js
Normal file
@@ -0,0 +1,67 @@
|
||||
// dd_MultiplySlowest_50.js
|
||||
// Multiply slowest moving mv's
|
||||
var LARGEST = 0;
|
||||
var SOME_PERCENTAGE = 0.5;
|
||||
var MULTIPLE = 10;
|
||||
|
||||
// global variable holding forward motion vectors from previous frames
|
||||
var prev_fwd_mvs = [ ];
|
||||
|
||||
// change this value to use a smaller or greater number of frmes to average
|
||||
var tail_length = 20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
LARGEST = 0;
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// 1st loop - find the fastest mv
|
||||
// this ends-up in LARGEST as the square of the hypotenuse (mv[0]*mv[0]) + (mv[1]*mv[1])
|
||||
let W = fwd_mvs.length;
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
let row = fwd_mvs[i];
|
||||
// rows
|
||||
let H = row.length;
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MEASUREMENT HAPPENS
|
||||
var this_mv = (mv[0] * mv[0])+(mv[1] * mv[1]);
|
||||
if ( this_mv > LARGEST){
|
||||
LARGEST = this_mv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// then find those mv's which are bigger than SOME_PERCENTAGE of LARGEST
|
||||
// and then replace them with the average mv from the last n frames
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
let row = fwd_mvs[i];
|
||||
// rows
|
||||
let H = row.length;
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
var this_mv = (mv[0] * mv[0])+(mv[1] * mv[1]);
|
||||
if (this_mv < (LARGEST * SOME_PERCENTAGE)){
|
||||
|
||||
mv[0] = mv[0] * MULTIPLE;
|
||||
mv[1] = mv[1] * MULTIPLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Python Version/DatamoshLib/FFG_effects/jscripts/Shear.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// dd_sheer.js
|
||||
|
||||
var ZOOM = -20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
|
||||
// loop through all rows
|
||||
|
||||
let row = fwd_mvs[i];
|
||||
var M_W = row.length/2;
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
//if(i>M_W){
|
||||
mv[0] = mv[0] + ((i - M_W) / 100)*ZOOM;
|
||||
mv[1] = mv[1] + ((j - M_H) / 100)*ZOOM;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
74
Python Version/DatamoshLib/FFG_effects/jscripts/Shift.js
Normal file
@@ -0,0 +1,74 @@
|
||||
// dd_RandomDamage(antiGrav).js
|
||||
// anitgravityify if threshold met for frame
|
||||
|
||||
let threshold = 98;
|
||||
// global variable holding forward motion vectors from previous frames
|
||||
var old_mvs = [ ];
|
||||
// a variable for gravity
|
||||
var rt = 0;
|
||||
var gravity = 0
|
||||
var orig_gravity = 5;
|
||||
var TRIGGERED = 0;
|
||||
var frameCount = 10;
|
||||
var count = 0;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
var do_or_not = Math.random() * 100;
|
||||
// only do the glitch if our random number crosses the threshold
|
||||
if(do_or_not > threshold | TRIGGERED == 1){
|
||||
if(TRIGGERED == 0){
|
||||
gravity = orig_gravity;
|
||||
TRIGGERED = 1;
|
||||
rt = 0;
|
||||
}
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// buffer first set of vectors. . .
|
||||
if(rt == 0){
|
||||
let json_str = JSON.stringify(fwd_mvs);
|
||||
let deep_copy = JSON.parse(json_str);
|
||||
// push to the end of array
|
||||
old_mvs[0] = (deep_copy);
|
||||
rt = 1;
|
||||
}
|
||||
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
let old_row = old_mvs[0][i];
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
let omv = old_row[j];
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
|
||||
mv[0] = mv[0];
|
||||
//if(mv[1] < 0){
|
||||
var nmv = mv[1];
|
||||
mv[1] = omv[1];
|
||||
omv[1] = nmv + omv[1] + gravity;
|
||||
//gravity++;
|
||||
//}else{
|
||||
// mv[1] = mv[1];
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
count++;
|
||||
if(count >= frameCount){
|
||||
TRIGGERED = 0;
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Python Version/DatamoshLib/FFG_effects/jscripts/Sink.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// dd_zero.js
|
||||
// only fuck things up if mv > movement_threshold
|
||||
var movement_threshold = 3;
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// columns
|
||||
let W = fwd_mvs.length;
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
|
||||
let row = fwd_mvs[i];
|
||||
|
||||
// rows
|
||||
let H = row.length;
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
if ( (mv[0] * mv[0])+(mv[1] * mv[1]) > movement_threshold*movement_threshold){
|
||||
//mv[0] = Math.sin(i/W*Math.PI*2)*mv[0];
|
||||
//mv[1] = Math.cos(j/H*Math.PI*2)*mv[1];
|
||||
mv[0] = 0;//mv[0] * 10;
|
||||
mv[1] = 0;//mv[1] * 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Python Version/DatamoshLib/FFG_effects/jscripts/Slam Zoom.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// dd_slam_zoom_in.js
|
||||
|
||||
var ZOOM = 20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
|
||||
// loop through all rows
|
||||
|
||||
let row = fwd_mvs[i];
|
||||
var M_W = row.length/2;
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
//if(i>M_W){
|
||||
mv[0] = ((M_W - j) / 100)*ZOOM;
|
||||
mv[1] = ((M_H - i) / 100)*ZOOM;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Python Version/DatamoshLib/FFG_effects/jscripts/Slice.js
Normal file
@@ -0,0 +1,68 @@
|
||||
// dd_RandomDamage(progZoom).js
|
||||
// progressive Zoom x and y components of mv if threshold met for frame
|
||||
|
||||
let threshold = 95;
|
||||
|
||||
var ZOOM = 0;
|
||||
var doZOOM = 0;
|
||||
var TRIGGERED = 0;
|
||||
var nFrames = 5;
|
||||
var frameCount = 0;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
|
||||
var do_or_not = Math.random() * 100;
|
||||
if(do_or_not > threshold){
|
||||
if(TRIGGERED > 0){
|
||||
|
||||
}else{
|
||||
TRIGGERED = 1;
|
||||
frameCount = 0;
|
||||
ZOOM = 0;
|
||||
}
|
||||
}
|
||||
// only do the glitch if our random number crosses the threshold
|
||||
if(TRIGGERED > 0 & frameCount <= nFrames){
|
||||
frameCount++;
|
||||
ZOOM+= 10
|
||||
|
||||
var do_dir = Math.random() * 100;
|
||||
if(do_dir > 50){
|
||||
doZOOM = 0 - ZOOM;
|
||||
}else{
|
||||
doZOOM = ZOOM
|
||||
}
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
var M_W = row.length/2;
|
||||
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
// ZOOM X & Y VECTORS
|
||||
mv[0] = mv[0] + ((M_W - j) / 10)*doZOOM;
|
||||
mv[1] = mv[1] + ((M_H - i) / 10)*doZOOM;
|
||||
|
||||
}
|
||||
}
|
||||
}else{
|
||||
TRIGGERED = 0;
|
||||
}
|
||||
}
|
||||
56
Python Version/DatamoshLib/FFG_effects/jscripts/Stop.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// dd_RandomDamage(stopXY).js
|
||||
// stop x and y component of mv for n framesif threshold met for frame
|
||||
|
||||
let threshold = 95;
|
||||
var TRIGGERED = 0;
|
||||
var nFrames = 10;
|
||||
var frameCount = 0;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
|
||||
var do_or_not = Math.random() * 100;
|
||||
if(do_or_not > threshold){
|
||||
if(TRIGGERED > 0){
|
||||
|
||||
}else{
|
||||
TRIGGERED = 1;
|
||||
frameCount = 0;
|
||||
}
|
||||
}
|
||||
// only do the glitch if our random number crosses the threshold
|
||||
if(TRIGGERED > 0 & frameCount <= nFrames){
|
||||
frameCount++;
|
||||
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
var M_W = row.length/2;
|
||||
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
// STOP XY
|
||||
mv[0] = 0;
|
||||
mv[1] = 0;
|
||||
}
|
||||
}
|
||||
}else{
|
||||
TRIGGERED = 0;
|
||||
}
|
||||
}
|
||||
29
Python Version/DatamoshLib/FFG_effects/jscripts/Vibrate.js
Normal file
@@ -0,0 +1,29 @@
|
||||
var randomness = 10;
|
||||
var bias = (randomness/2);
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
// loop through all rows
|
||||
let row = fwd_mvs[i];
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
mv[0] = mv[0] + (Math.floor((Math.random() * randomness) -bias));
|
||||
mv[1] = mv[1] + (Math.floor((Math.random() * randomness) -bias));
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Python Version/DatamoshLib/FFG_effects/jscripts/Zoom.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// dd_zoom_in.js
|
||||
|
||||
var ZOOM = 20;
|
||||
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
// bail out if we have no motion vectors
|
||||
let mvs = frame["mv"];
|
||||
if ( !mvs )
|
||||
return;
|
||||
// bail out if we have no forward motion vectors
|
||||
let fwd_mvs = mvs["forward"];
|
||||
if ( !fwd_mvs )
|
||||
return;
|
||||
|
||||
var M_H = fwd_mvs.length/2;
|
||||
// clear horizontal element of all motion vectors
|
||||
for ( let i = 0; i < fwd_mvs.length; i++ )
|
||||
{
|
||||
|
||||
// loop through all rows
|
||||
|
||||
let row = fwd_mvs[i];
|
||||
var M_W = row.length/2;
|
||||
|
||||
for ( let j = 0; j < row.length; j++ )
|
||||
{
|
||||
// loop through all macroblocks
|
||||
let mv = row[j];
|
||||
|
||||
// THIS IS WHERE THE MAGIC HAPPENS
|
||||
//if(i>M_W){
|
||||
mv[0] = mv[0] + ((M_W - j) / 100)*ZOOM;
|
||||
mv[1] = mv[1] + ((M_H - i) / 100)*ZOOM;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Python Version/DatamoshLib/Original/classic.py
Normal 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)
|
||||
64
Python Version/DatamoshLib/Original/pymodes.py
Normal 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)
|
||||
|
||||
43
Python Version/DatamoshLib/Original/repeat.py
Normal 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()
|
||||
21
Python Version/DatamoshLib/Tomato/LICENSE.txt
Normal 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.
|
||||
234
Python Version/DatamoshLib/Tomato/tomato.py
Normal 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)))
|
||||
@@ -1,812 +0,0 @@
|
||||
import os
|
||||
from tkinter import *
|
||||
from tkinter import ttk, messagebox, filedialog
|
||||
import tkinter
|
||||
import sys
|
||||
import random
|
||||
import re
|
||||
import struct
|
||||
import time
|
||||
import webbrowser
|
||||
from itertools import chain, repeat, islice
|
||||
import subprocess
|
||||
import pkg_resources
|
||||
#Note that this program is optimised for only windows, for other systems you have to change the ffmpeg path(line 48).
|
||||
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 \n 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)
|
||||
messagebox.showinfo("Module Installed","Please restart the program!")
|
||||
sys.exit()
|
||||
elif res=="no":
|
||||
messagebox.showerror("Error","Required modules not available!\nWithout the modules you can't use this program. Please install them first!")
|
||||
sys.exit()
|
||||
else:
|
||||
import imageio
|
||||
if os.path.isdir("pymosh"):
|
||||
from pymosh import Index
|
||||
from pymosh.codec.mpeg4 import is_iframe
|
||||
else:
|
||||
messagebox.showerror("Missing Folder!","Pymosh folder is not available! Please download it from our github page.")
|
||||
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','*.avi','*.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'
|
||||
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
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['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
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['state']=NORMAL
|
||||
root.config(cursor="")
|
||||
def validate():
|
||||
try:
|
||||
float(Countframe.get())
|
||||
float(Positframe.get())
|
||||
float(firstframes.get())
|
||||
float(killframe.get())
|
||||
x=float(killframe.get())
|
||||
if x>1:
|
||||
var4.set(1)
|
||||
except ValueError:
|
||||
messagebox.showerror("Invalid Input","Please enter some 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
|
||||
if os.path.exists(exfile):
|
||||
warn=messagebox.askquestion("Warning","Do you want to replace the old file?")
|
||||
if warn=='yes':
|
||||
os.remove(exfile)
|
||||
elif warn=='no':
|
||||
os.kill(checkesist())
|
||||
pass
|
||||
def Step1():
|
||||
try:
|
||||
if (len(file)>=1):
|
||||
Wait.place(relx=0.5,rely=0.85,anchor='center')
|
||||
root.update()
|
||||
datamoshbtn['state']=DISABLED
|
||||
extension=os.path.splitext(file)[1]
|
||||
modechoices['state']=DISABLED
|
||||
exportbox['state']=DISABLED
|
||||
OpeningFile['state']=DISABLED
|
||||
validate()
|
||||
checkexist(file)
|
||||
root.config(cursor="")
|
||||
choice = modechoices.get()
|
||||
if(choice==modes[7]):
|
||||
if extension==".mp4":
|
||||
convertffmpeg(file)
|
||||
else:
|
||||
targetformat=".mp4"
|
||||
convert(file,targetformat)
|
||||
convertffmpeg(file)
|
||||
elif(choice==modes[8]) or (choice==modes[9]) or (choice==modes[11]):
|
||||
pymosh_library(file)
|
||||
else:
|
||||
targetformat=".avi"
|
||||
convert(file,targetformat)
|
||||
else:
|
||||
messagebox.showerror("","Please choose the video again!")
|
||||
except:
|
||||
datamoshbtn['state']=NORMAL
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['state']=NORMAL
|
||||
root.config(cursor="")
|
||||
Wait.place_forget()
|
||||
messagebox.showerror("","Please choose the video file again!")
|
||||
def pymosh_library(file):
|
||||
global final
|
||||
outpath=os.path.dirname(file)
|
||||
outx=os.path.basename(file).split('.')[0]
|
||||
infile=os.path.dirname(file)+"/"+outx+"_datamoshed.avi"
|
||||
if os.path.exists(infile):
|
||||
os.remove(infile)
|
||||
fps=30
|
||||
subprocess.call(f'"{resource}" -loglevel error -y -i "{file}" -crf 0 -bf 0 -r {fps} "{infile}"', shell=True)
|
||||
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):
|
||||
f = Index.from_file(filename)
|
||||
for stream in f.video:
|
||||
sorted_stream = sorted(stream, key=len, reverse=True)
|
||||
stream.replace(sorted_stream)
|
||||
f.rebuild()
|
||||
with open(outfile, 'wb') as out:
|
||||
f.write(out)
|
||||
def process_streams(in_filename, out_filename, func, *args, **kwargs):
|
||||
f = Index.from_file(in_filename)
|
||||
for stream in f.video:
|
||||
midpoint=float(firstframes.get())
|
||||
if midpoint>1:
|
||||
midpoint=1
|
||||
drifted = list(func(stream, midpoint,*args, **kwargs))
|
||||
stream.replace(drifted)
|
||||
f.rebuild()
|
||||
with open(out_filename, 'wb') as out:
|
||||
f.write(out)
|
||||
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
|
||||
choice = modechoices.get()
|
||||
if(choice==modes[8]):
|
||||
Wait.config(text="Applying Effect: Glide", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15))
|
||||
root.update()
|
||||
time.sleep(2)
|
||||
interval=int(Positframe.get())
|
||||
if (interval==1):
|
||||
interval=2
|
||||
outfile=outpath+"/"+os.path.basename(infile).split('.')[0]+"-glide.avi"
|
||||
if os.path.exists(outfile):
|
||||
os.remove(outfile)
|
||||
glide(interval, infile, outfile)
|
||||
elif (choice==modes[9]):
|
||||
Wait.config(text="Applying Effect: Sort", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15))
|
||||
root.update()
|
||||
time.sleep(2)
|
||||
outfile=outpath+"/"+os.path.basename(infile).split('.')[0]+"-sort.avi"
|
||||
if os.path.exists(outfile):
|
||||
os.remove(outfile)
|
||||
avi_sort(infile, outfile)
|
||||
elif (choice==modes[11]):
|
||||
Wait.config(text="Applying Effect: Echo", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15))
|
||||
root.update()
|
||||
time.sleep(2)
|
||||
outfile=outpath+"/"+os.path.basename(infile).split('.')[0]+"-echo.avi"
|
||||
if os.path.exists(outfile):
|
||||
os.remove(outfile)
|
||||
process_streams(infile, outfile, echo)
|
||||
final=outpath+"/"+os.path.basename(outfile).split('.')[0]+".mp4"
|
||||
if os.path.exists(final):
|
||||
os.remove(final)
|
||||
subprocess.call(f'"{resource}" -loglevel error -y -i "{outfile}" "{final}"', shell=True)
|
||||
export2=exportbox.get()
|
||||
os.remove(infile)
|
||||
export(final)
|
||||
os.remove(outfile)
|
||||
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"
|
||||
elif(choice==modes[10]):
|
||||
mode="shake"
|
||||
elif(choice==modes[12]):
|
||||
mode="void"
|
||||
else:
|
||||
messagebox.showerror("Error!","Please select a valid mode!")
|
||||
os.remove(outputpath)
|
||||
Wait.place_forget()
|
||||
datamoshbtn['state']=NORMAL
|
||||
root.config(cursor="")
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['state']=NORMAL
|
||||
os.kill(Datamosh())
|
||||
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 == "void":
|
||||
final = clean
|
||||
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]
|
||||
if mode == "shake":
|
||||
Wait.config(text="Applying Effect: Shake", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15))
|
||||
root.update()
|
||||
def process_streams(in_filename, out_filename, func, *args, **kwargs):
|
||||
f = Index.from_file(in_filename)
|
||||
for stream in f.video:
|
||||
drifted = list(func(stream, *args, **kwargs))
|
||||
stream.replace(drifted)
|
||||
f.rebuild()
|
||||
with open(out_filename, 'wb') as out:
|
||||
f.write(out)
|
||||
def shake(stream):
|
||||
def glitch(stream):
|
||||
all_frames = iter(stream)
|
||||
yield next(all_frames)
|
||||
while True:
|
||||
frame = next(all_frames)
|
||||
if not is_iframe(frame):
|
||||
yield frame
|
||||
yield frame
|
||||
return islice(glitch(stream), len(stream))
|
||||
fileout= filein[:-4] + '-' + mode + '.avi'
|
||||
process_streams(filein, fileout, shake)
|
||||
fps=30
|
||||
output= fileout[:-9]+"shake.mp4"
|
||||
subprocess.call(f'"{resource}" -loglevel error -y -i "{fileout}" -crf 0 -bf 0 -r {fps} "{output}"', shell=True)
|
||||
time.sleep(2)
|
||||
os.remove(fileout)
|
||||
os.remove(filein)
|
||||
os.remove(temp_hdrl)
|
||||
os.remove(temp_movi)
|
||||
os.remove(temp_idx1)
|
||||
os.rmdir(temp_dir)
|
||||
export(output)
|
||||
os.kill(datamosh)
|
||||
time.sleep(2)
|
||||
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
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['state']=NORMAL
|
||||
root.config(cursor="")
|
||||
messagebox.showinfo("DONE","Datamoshed video is ready!")
|
||||
Wait.config(text="", fg="#6D76CD",bg='#FFFFFF', font=("Aharoni",15))
|
||||
root.update()
|
||||
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
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['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
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['state']=NORMAL
|
||||
elif ask=='no':
|
||||
targetformat=".avi"
|
||||
convert(fileout,targetformat)
|
||||
removefileout()
|
||||
elif(export==exportchoices[1]):
|
||||
choice = modechoices.get()
|
||||
if(choice==modes[7]) or (choice==modes[8]) or (choice==modes[9]):
|
||||
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
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['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 a valid video format!")
|
||||
os.remove(fileout)
|
||||
Wait.place_forget()
|
||||
datamoshbtn['state']=NORMAL
|
||||
modechoices['state']=NORMAL
|
||||
exportbox['state']=NORMAL
|
||||
OpeningFile['state']=NORMAL
|
||||
root.config(cursor="")
|
||||
os.kill(Datamosh())
|
||||
def toggle():
|
||||
if var.get()==0:
|
||||
Disableadvanced()
|
||||
else:
|
||||
Enableadvanced()
|
||||
def Enableadvanced():
|
||||
choice = modechoices.get()
|
||||
if(choice==modes[8]):
|
||||
var2.set(6)
|
||||
var4.set(0.7)
|
||||
countlabel['fg']="grey"
|
||||
positlabel['fg']="green"
|
||||
firstflabel['fg']="grey"
|
||||
killlabel['fg']="grey"
|
||||
Countframe['state']=DISABLED
|
||||
Positframe['state']=NORMAL
|
||||
firstframes['state']=DISABLED
|
||||
killframe['state']=DISABLED
|
||||
if(choice==modes[7]):
|
||||
var2.set(1)
|
||||
var1.set(100)
|
||||
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]) or (choice==modes[10]) or (choice==modes[12]):
|
||||
var2.set(1)
|
||||
if (choice==modes[12]):
|
||||
var4.set(0.2)
|
||||
else:
|
||||
var4.set(0.7)
|
||||
var3.set(1)
|
||||
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]):
|
||||
var2.set(1)
|
||||
var4.set(0.7)
|
||||
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]) or (choice==modes[11]):
|
||||
var2.set(1)
|
||||
if (choice==modes[11]):
|
||||
var3.set(0.5)
|
||||
else:
|
||||
var3.set(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]):
|
||||
var2.set(1)
|
||||
var4.set(0.7)
|
||||
countlabel['fg']="grey"
|
||||
positlabel['fg']="green"
|
||||
firstflabel['fg']="green"
|
||||
killlabel['fg']="green"
|
||||
Countframe['state']=DISABLED
|
||||
Positframe['state']=NORMAL
|
||||
firstframes['state']=NORMAL
|
||||
killframe['state']=NORMAL
|
||||
elif(choice==modes[0]) or (choice==modes[3]) or (choice==modes[4]):
|
||||
var2.set(1)
|
||||
var4.set(0.7)
|
||||
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 refresh(event):
|
||||
if var=="0":
|
||||
pass
|
||||
else:
|
||||
modechoices['values']=toggle()
|
||||
def info():
|
||||
messagebox.showinfo("Help",
|
||||
"Datamosher Pro is a tool that can mosh and corrupt video files and returns an awesome glitched video"
|
||||
"\nHow To Use:\n➤First open 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➤Click on the datamosh button, then wait for a few seconds."
|
||||
"\n➤After conversion, your video will be ready and you can view the datamoshed video inside its directory."
|
||||
"\n\nDeveloper: Akash Bora (a.k.a. Akascape)\nIf you are facing any issue then contact me on Github."
|
||||
"\nVersion-1.3")
|
||||
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", "Glide", "Sort", "Shake", "Echo", "Void"]
|
||||
modechoices=ttk.Combobox(root,values=modes, font="Verdana 12", width=7, height=13)
|
||||
modechoices.current(0)
|
||||
modechoices.bind('<FocusIn>', lambda event: refresh(event))
|
||||
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)
|
||||
global var
|
||||
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 Size",fg="grey",bg='#FFFFFF')
|
||||
countlabel.place(x=50,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="First Frame",fg="grey",bg='#FFFFFF')
|
||||
firstflabel.place(x=50,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("<Button-1>", 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.3
|
||||
725
Python Version/Datamosher Pro.py
Normal 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()
|
||||
|
||||
#--------------------------------------------------------------------#
|
||||
0
Python Version/FFglitch/FFglitch goes here
Normal file
@@ -1,9 +0,0 @@
|
||||
#Read this to use the python version.
|
||||
This version is comparitively lower in size and works the same inside python environment.
|
||||
To use this version, just download the zip file and extract this folder and then double
|
||||
click on the Datamosher Pro v1.2.py to open the program, then use the software as describes in the Readme.md
|
||||
or click the "i" button inside the software.
|
||||
In this version, the modules will be automatically downloaded and ffmpeg path will be pre-specified, so no need to worry about modules and stuff
|
||||
(specially for windows user). Make sure to restart the program after completing the automatic module installation.
|
||||
Do not delete or move any assets or folder that are linked with the main file or else it will show error.
|
||||
This is all about the python version, you can now Datamosh your videos!
|
||||
127
Python Version/Setup.py
Normal 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()
|
||||
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
7
Python Version/pymosh/LICENSE.txt
Normal 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.
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
|
||||
164
Readme.md
@@ -1,50 +1,124 @@
|
||||
[](https://akascape.gumroad.com/l/Datamosher-Pro)
|
||||
# Datamosher Pro
|
||||
<br><b>Datamoshing is a cool video effect and if you also want to create this glitch effect with your videos, you are in the right place!</b>
|
||||
<br><p align='center'><img src="https://user-images.githubusercontent.com/89206401/141642297-7c62cf6f-7024-430f-88a2-c9cbbf0dc655.png"></p>
|
||||
<br>➤Why I made this?
|
||||
<br>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 GUI based application that is Datamosher Pro which is a free project. It contains 13 different effects which can replicate any type of datamoshing style. With Datamosher Pro, you can quickly and easily datamosh your videos (supports mp4, gif, avi, mkv etc).
|
||||
<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 (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'. 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'> 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 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?
|
||||
You can either use the python based version for viewing logs and changing source code if you want, but if you are looking for faster renders then download the windows executable version of Datamosher Pro from the release page:
|
||||
<br>[⬇️DOWNLOAD⬇️](https://github.com/Akascape/Datamosher-Pro/releases/tag/Datamosher_Prov1.3.exe)
|
||||
<br>There is no malware or difference in the exe version as the same python version is converted to .exe using Auto-Py-To-Exe Converter.
|
||||
<br>Note: For python users, make sure you have all the assets saved in the same folder. Modules will be automatically downloaded if not installed, so no need to worry.
|
||||
- For those who are using the python-version,
|
||||
<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?
|
||||
•Input the video file first (supported formats- mp4, gif, avi + more will be added if you demand")
|
||||
<br>•Choose the desired datamosh mode, then select the export format"
|
||||
<br>•Use advance options to get more accurate results"
|
||||
<br>•Click on the datamosh button, then wait for a few seconds"
|
||||
<br>•Then your video will be moshed, see the video in the directory"
|
||||
<br>NOTE: audio glitching is not available for all modes!
|
||||
# Effects Info:
|
||||
c=Glitch Size; n=Frame Frequency
|
||||
<b>
|
||||
<br>All effects:
|
||||
<br>•Glide - duplicates number of n frames and show it as a flow before reaching the p-frame (NEW)
|
||||
<br>•Sort - sorts video frames by data size in a rapid movement (NEW)
|
||||
<br>•Echo - duplicates the single video and apply the mosh in the midpoint (NEW)
|
||||
<br>•Shake - shakes the pixel movement throughout the video (NEW)
|
||||
<br>•Classic - uses the traditional ffmpeg way to change the files and then remove the i-frames
|
||||
<br>•Random - randomizes frame order
|
||||
<br>•Reverse - reverse frame order
|
||||
<br>•Invert - switches each consecutive frame witch each other
|
||||
<br>•Bloom - duplicates c times p-frame number n
|
||||
<br>•Pulse - duplicates groups of c p-frames every n frames
|
||||
<br>•Overlap - copy group of c frames taken from every nth position
|
||||
<br>•Jiggle - take frame from around current position. n parameter is spread size.
|
||||
<br>•Void - gives a clean output but with distorted pixels
|
||||
</b>
|
||||
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
|
||||
|
||||
**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
|
||||
[](https://github.com/Akascape/Datamosher-Pro/blob/Datamosher-Pro-v1.7/Demos.md)
|
||||
# Effects Info
|
||||
### Effects List available in the python version:
|
||||
<br> TIP: Major effects used for datamoshing are Classic, Bloom, Glide, Repeat, Motion Transfer, Rise, Fluid
|
||||
<br>
|
||||
<br>➤How to use Advanced Options?
|
||||
<br>The advanced tab is very useful and you can use it to get accurate results.
|
||||
<br>•Glitch Size - tells how often to glitch (for modes that support it)
|
||||
<br>•Frame Frequency - tells how many frames to apply in the glitch (for modes that support it)
|
||||
<br>•First Frame - tells whether to keep first video frames
|
||||
<br>•Kill frames - tells max framesize to kill while cleaning
|
||||
<br>You can try experimenting with the values and see the results.
|
||||
# User Interface:
|
||||
<br><img src="https://user-images.githubusercontent.com/89206401/141643709-73b68644-5697-4c39-8be0-5384dc391fa4.png">
|
||||
<br>➤More Info about this project:
|
||||
<br>The effects are inspired from ItsKaspar's [tomato.py](https://github.com/itsKaspar/tomato) and Joe Friedl's [pymosh](https://github.com/grampajoe/pymosh) which can only handle .avi file structures, but in Datamosher Pro you can use any video file type including mp4, avi, gif, mov, mkv +more. The files are first converted to avi file using Imageio-ffmpeg without losing much quality and then the effect is applied and then again the corrupted file is converted to stable version using the same process so that the output video can be directly used in other softwares for editing without any error. A raw file option is also available if needed. You will not find this type of GUI program anywhere with so many free effects, I hope there is no error in the program but if you find any bug then raise an issue. You can also help to make new datamosh effects. All the logo and designs are created by me. <br>Thanks! Made by Akash Bora (a.k.a Akascape).
|
||||
| Effect Name | Description |
|
||||
| ----------------| --------------------------------------------------------------------- |
|
||||
| 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|
|
||||
| Delay | another delaying ffglitch effect|
|
||||
| Invert-Reverse | applies both inverse and reverse mode|
|
||||
| Mirror | does the mosh with ffglitch but with mirrored X|
|
||||
| Noise | makes large noisy mosh|
|
||||
| Shear | tilt the video clockwise and merges the mosh|
|
||||
| Shift | shifts random blocks of the video upwards|
|
||||
| Sink | drowns the next frame of the video in the previous one|
|
||||
| Slam Zoom | applies zoom with the sink effect|
|
||||
| Slice | randomly zooms and slices the video in parts|
|
||||
| Stop | similar to sink but stops the XY values|
|
||||
| Vibrate | works as a randomizer|
|
||||
| Zoom | simply zooms inside the moshed video|
|
||||
| Fluid | this is a ffglitch's average effect which gives a smooth liquid type motion in the video|
|
||||
| Repeat | repeats a series of p frames which gives the melting effect|
|
||||
| Motion Transfer | a powerful ffglitch feature that can transfer the vector motion data from one video to another. Make sure both videos have the same resolution, this effect is also known as style transfer/swap motion.|
|
||||
| Stretch | stretches the p-frames horizontally and vertically|
|
||||
| Glide | duplicates number of n frames and show it as a flow before reaching the p-frame|
|
||||
| Sort | sorts video frames by data size in a rapid movement|
|
||||
| Echo | duplicates the single video and apply the mosh effect in the midpoint|
|
||||
| Shake | randomly shakes the pixels/blocks throughout the video|
|
||||
| Classic | uses the traditional ffmpeg way to convert and corrupt the video by removing the i-frames|
|
||||
| Random | randomizes frame order|
|
||||
| Reverse | reverses frame order|
|
||||
| Invert | switches each consecutive frame witch each other|
|
||||
| Bloom | duplicates c times p-frame number n (c=Glitch Size; n=Frame Frequency)|
|
||||
| Pulse | duplicates groups of c p-frames every n frames|
|
||||
| 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|
|
||||
## 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
|
||||
<br>• `Ignore Frame` - tells whether to keep the first video frame
|
||||
<br>• `Kill Frames` - tells max framesize to kill while cleaning (For shuffle/rise mode the kill frame is number of frames that will be deleted)
|
||||
<br>• `First Frame` - tells the starting frame for the glitch
|
||||
<br>• `Last Frame` - tells the ending frame for the glitch
|
||||
<br>• `Start(sec)` - tells the starting time (in seconds) for the glitch
|
||||
<br>• `End(sec)` - tells the ending time (in seconds) for the glitch
|
||||
<br>• `Mid Point (Echo mode only)` - tells the point from where the video to repeat(echo)
|
||||
<br>
|
||||
<br>DATAMOSH MADE EASY!
|
||||
<br>Current Version=1.3
|
||||
<br>NOTE:
|
||||
<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 (BASIC PYTHON VERSION)
|
||||
| Windows | Linux | MacOS |
|
||||
| ---------| ------- | ------- |
|
||||
|  |  |  |
|
||||
# UI (PAID VERSION ONLY WINDOWS)
|
||||
### This modern UI is available in the paid version only.
|
||||

|
||||
## 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 about the python version:
|
||||
<br> [](https://akascape.gumroad.com/p/datamosher-pro-guide) [](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 :)
|
||||
<br> As it is a new piece of software some users may find some errors and bugs (specially in the python version), but updates will be on their way.
|
||||
<br>The effects are all inspired from ItsKaspar's [tomato.py](https://github.com/itsKaspar/tomato), Joe Friedl's [pymosh](https://github.com/grampajoe/pymosh) and [FFglitch](https://ffglitch.org/).
|
||||
All the logos and designs are created by me. <br>-Akash Bora
|
||||
<br>
|
||||
## 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)
|
||||
|
||||
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)
|
||||
[<img src="https://img.shields.io/badge/-Reddit-informational?style=flat&logo=reddit&logoColor=black&color=orange">](https://www.reddit.com/user/Akascape)
|
||||
[<img src="https://img.shields.io/badge/-YouTube-informational?style=flat&logo=youtube&logoColor=black&color=red">](https://www.youtube.com/channel/UC7naboenYq9FAo80aPUkqSw)
|
||||
[<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> [](https://www.python.org/) [](https://github.com/Akascape/Datamosher-Pro) [](https://github.com/Akascape/Datamosher-Pro)
|
||||
[](https://opensourcelibs.com/lib/capsule-render)
|
||||
|
||||