Compare commits
147 Commits
Datamosher
...
Datamosher
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66d12839b9 | ||
|
|
c78cea8890 | ||
|
|
b0940006b6 | ||
|
|
c6a7f9f67a | ||
|
|
08fb701a44 | ||
|
|
d99908cd76 | ||
|
|
9a17c42193 | ||
|
|
f8b45d5915 | ||
|
|
3c482daed5 | ||
|
|
c238444c77 | ||
|
|
6608f537e4 | ||
|
|
5296b793b6 | ||
|
|
7c7905394b | ||
|
|
90f22f9d05 | ||
|
|
a7b7afa8ac | ||
|
|
e44998010b | ||
|
|
3e3893fe11 | ||
|
|
c1988fc3bc | ||
|
|
89e847171c | ||
|
|
d4a6f6b676 | ||
|
|
334374ac07 | ||
|
|
189afe55ad | ||
|
|
16bb1c2623 | ||
|
|
242e3a4223 | ||
|
|
862a046c8f | ||
|
|
d1f2abecb1 | ||
|
|
e5dac2b259 | ||
|
|
c86b7850a5 | ||
|
|
5516265f5c | ||
|
|
bd998610cc | ||
|
|
f670491c3b | ||
|
|
cefde58f39 | ||
|
|
baca35ba19 | ||
|
|
a698cf6711 | ||
|
|
c2e9874876 | ||
|
|
2cc814d51a | ||
|
|
9a6c410cc9 | ||
|
|
f081a0d618 | ||
|
|
23037bd66e | ||
|
|
8050a2e433 | ||
|
|
330faed695 | ||
|
|
6e6063b8c8 | ||
|
|
af680ad11b | ||
|
|
99ae70e3b3 | ||
|
|
14d7e9889f | ||
|
|
d66b815437 | ||
|
|
efa683d705 | ||
|
|
d53c41f73c | ||
|
|
baad7caf85 | ||
|
|
555957203e | ||
|
|
688774932a | ||
|
|
ffb4187ace | ||
|
|
4c6375aef4 | ||
|
|
989a219c13 | ||
|
|
82e113151d | ||
|
|
547d1b567c | ||
|
|
c4e424df2e | ||
|
|
ddd40da62f | ||
|
|
7a9688b4e9 | ||
|
|
c0962ab503 | ||
|
|
f8f45e50af | ||
|
|
f8658c8a2a | ||
|
|
44f529073f | ||
|
|
11705e2415 | ||
|
|
3785a43930 | ||
|
|
1ede49a7bf | ||
|
|
5b1164e9a6 | ||
|
|
095b488f7d | ||
|
|
e521ddecc6 | ||
|
|
42104bae89 | ||
|
|
03d3a68ebb | ||
|
|
cd17d0b1c8 | ||
|
|
bb759fc366 | ||
|
|
a8e940dd9e | ||
|
|
734c92739f | ||
|
|
aef5426c84 | ||
|
|
b7ada09f76 | ||
|
|
21f57b3135 | ||
|
|
378e5270c1 | ||
|
|
bfda9fd0f1 | ||
|
|
4caf0a675c | ||
|
|
875eddf2b1 | ||
|
|
bac046c7d2 | ||
|
|
8b32637650 | ||
|
|
8b5e839c7f | ||
|
|
72c9b57b4e | ||
|
|
ce47280a18 | ||
|
|
c5d4e25764 | ||
|
|
a2f3af71f7 | ||
|
|
d68ea1569f | ||
|
|
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 |
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**Logs**
|
||||
Add your logs shown in the console (except the ffmpeg logs)
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Mode(s) used:
|
||||
2. Settings: [e.g default]
|
||||
3. Video used (metadata):
|
||||
|
||||
**Screenshots**
|
||||
If possible, add screenshots of console to help explain your problem.
|
||||
|
||||
**System:**
|
||||
- OS: [e.g. windows]
|
||||
- Datamosher Pro Version: [e.g. 2.6]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
14
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: 'Suggest an idea '
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Feature for which version?**
|
||||
Windows version or Python?
|
||||
|
||||
**Describe the feature you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
10
.github/ISSUE_TEMPLATE/other.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
---
|
||||
name: Other
|
||||
about: Discuss something with us
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Not exactly an issue, but you can describe your thoughts**
|
||||
26
Demos.md
@@ -1,26 +0,0 @@
|
||||
# This is the gallery page for Datamosher-Pro
|
||||
If you want your datamosh video to be listed here then tag datamosherpro on any social media website including youtube, reddit, vimeo etc. (Note: You must use datamosher-pro)
|
||||
<br>
|
||||
## Basic i-frame removal examples (bloom, classic, rise)
|
||||
<br> [](https://youtu.be/_YZ32Wvl3hk)
|
||||
## Different P-frame duplication effects (classic, glide, repeat, pulse)
|
||||
<br> [](https://youtu.be/fFhnV19fuzg)
|
||||
## Automated Shuffle effect example
|
||||
<br> [](https://youtu.be/26BJl87ksec)
|
||||
## The Beautiful Fluid effect
|
||||
<br> [](https://youtu.be/GJiP6R432D8)
|
||||
## The Vibrate effect that can be used to make backgrounds
|
||||
<br> [](https://youtu.be/DkIvfRSQ8bo)
|
||||
## The Rain effect
|
||||
<br> [](https://youtu.be/0mKZQopUUQg)
|
||||
## Classic datamoshing showreel
|
||||
<br> [](https://youtu.be/hYFEwL8Do_U)
|
||||
## Drone shot + Noise mode
|
||||
<br> [](https://youtu.be/IaD8yX2kXgE)
|
||||
## Showreel 2 (Sort & Shuffle mixed)
|
||||
<br> [](https://youtu.be/BWIK5gCt5ZA)
|
||||
# Read Online Guides:
|
||||
<br> [](https://akascape.gumroad.com/p/datamosher-pro-guide) [](https://akascape.gumroad.com/p/datamosher-pro-guide-2)
|
||||
## Fan Made Videos
|
||||
<br> [](https://youtu.be/qvOK6twezM8) [](https://youtu.be/ULH_AMqz56c)
|
||||
## More to be uploaded soon!
|
||||
2
LICENSE
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Akascape
|
||||
Copyright (c) 2025 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
|
||||
|
||||
9
Python Version/Assets/CTkRangeSlider/__init__.py
Normal file
@@ -0,0 +1,9 @@
|
||||
"""
|
||||
CTkRangeSlider
|
||||
Range slider for customtkinter
|
||||
Author: Akash Bora
|
||||
"""
|
||||
|
||||
__version__ = '0.3'
|
||||
|
||||
from .ctk_rangeslider import CTkRangeSlider
|
||||
1296
Python Version/Assets/CTkRangeSlider/ctk_rangeslider.py
Normal file
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/info.png
Normal file
|
After Width: | Height: | Size: 33 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/up_arrow.png
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
Python Version/Assets/Icons/video_icon.png
Normal file
|
After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 2.5 KiB |
BIN
Python Version/Assets/thumbnail_cache/offline_image.png
Normal file
|
After Width: | Height: | Size: 178 KiB |
243
Python Version/DatamoshLib/FFG_effects/basic_modes.py
Normal file
@@ -0,0 +1,243 @@
|
||||
#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 = os.path.join(str(DIRPATH.parent.parent),"FFglitch","ffgac")
|
||||
ffedit = os.path.join(str(DIRPATH.parent.parent),"FFglitch","ffedit")
|
||||
|
||||
def library(input_video, output, mode, extract_from="", fluidity=0, size=0, s=0, e=0, vh=0, gop=1000, r=0, f=0):
|
||||
|
||||
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_ffg"):
|
||||
shutil.rmtree("cache_ffg")
|
||||
os.mkdir("cache_ffg")
|
||||
base = os.path.basename(input_video)
|
||||
fin = os.path.join("cache_ffg",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}"', shell=True)
|
||||
os.mkdir(os.path.join("cache_ffg","raws"))
|
||||
framelist = []
|
||||
subprocess.call(f'"{ffgac}" -i "{fin}" -vcodec copy cache_ffg/raws/frames_%04d.raw', shell=True)
|
||||
frames = os.listdir(os.path.join("cache_ffg","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(os.path.join("cache_ffg","raws",fn), 'rb') as fp:
|
||||
out_data += fp.read()
|
||||
with open(output, 'wb+') as fp:
|
||||
fp.write(out_data)
|
||||
fp.close()
|
||||
shutil.rmtree("cache_ffg")
|
||||
|
||||
def rise(output):
|
||||
if os.path.isdir("cache_ffg"):
|
||||
shutil.rmtree("cache_ffg")
|
||||
os.mkdir("cache_ffg")
|
||||
base = os.path.basename(input_video)
|
||||
fin = os.path.join("cache_ffg",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}"', shell=True)
|
||||
os.mkdir(os.path.join("cache_ffg","raws"))
|
||||
framelist = []
|
||||
subprocess.call(f'"{ffgac}" -i "{fin}" -vcodec copy cache_ffg/raws/frames_%04d.raw', shell=True)
|
||||
kil = e
|
||||
po = s
|
||||
if po==0:
|
||||
po = 1
|
||||
frames=os.listdir(os.path.join("cache_ffg","raws"))
|
||||
for i in frames[po:(po+kil)]:
|
||||
os.remove(os.path.join("cache_ffg","raws",i))
|
||||
frames.clear()
|
||||
frames = os.listdir(os.path.join("cache_ffg","raws"))
|
||||
framelist.extend(frames)
|
||||
out_data = b''
|
||||
for fn in framelist:
|
||||
with open(os.path.join("cache_ffg","raws",fn), 'rb') as fp:
|
||||
out_data += fp.read()
|
||||
with open(output, 'wb') as fp:
|
||||
fp.write(out_data)
|
||||
fp.close()
|
||||
shutil.rmtree("cache_ffg")
|
||||
|
||||
def combine(output):
|
||||
if os.path.isdir("cache_ffg"):
|
||||
shutil.rmtree("cache_ffg")
|
||||
os.mkdir("cache_ffg")
|
||||
qua=''
|
||||
num = 0
|
||||
frames = []
|
||||
converted = {}
|
||||
for i in input_video:
|
||||
if i in list(converted.keys()):
|
||||
continue
|
||||
base=os.path.basename(i)
|
||||
num +=1
|
||||
fin=os.path.join("cache_ffg",base[:-4]+f"_{num}.mpg")
|
||||
os.mkdir(os.path.join("cache_ffg",f"raws_{num}"))
|
||||
|
||||
subprocess.call(f'"{ffgac}" -i "{i}" -an -vcodec mpeg2video -f rawvideo -mpv_flags +nopimb -qscale:v 6 -r 30 -s 1920x1080 -g "{gop}" -y "{fin}"', shell=True)
|
||||
|
||||
subprocess.call(f'"{ffgac}" -i "{fin}" -vcodec copy cache_ffg/raws_{num}/frames_%04d.raw', shell=True)
|
||||
converted.update({i:os.path.join("cache_ffg",f"raws_{num}")})
|
||||
|
||||
num = 0
|
||||
for i in input_video:
|
||||
num +=1
|
||||
raw_frames = os.listdir(converted[i])
|
||||
if num == 1:
|
||||
n = 0
|
||||
else:
|
||||
if len(raw_frames)>10:
|
||||
n=5
|
||||
else:
|
||||
n=1
|
||||
for frame in raw_frames[n:]:
|
||||
frames.append(os.path.join(converted[i],frame))
|
||||
|
||||
out_data = b''
|
||||
for fn in frames:
|
||||
with open(os.path.join(fn), 'rb') as fp:
|
||||
out_data += fp.read()
|
||||
with open(output, 'wb') as fp:
|
||||
fp.write(out_data)
|
||||
fp.close()
|
||||
try:
|
||||
if os.path.isdir("cache_ffg"):
|
||||
shutil.rmtree("cache_ffg")
|
||||
except: pass
|
||||
|
||||
def water_bloom(output):
|
||||
if os.path.isdir("cache_ffg"):
|
||||
shutil.rmtree("cache_ffg")
|
||||
os.mkdir("cache_ffg")
|
||||
base = os.path.basename(input_video)
|
||||
fin = os.path.join("cache_ffg",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}"', shell=True)
|
||||
os.mkdir(os.path.join("cache_ffg","raws"))
|
||||
framelist = []
|
||||
subprocess.call(f'"{ffgac}" -i "{fin}" -vcodec copy cache_ffg/raws/frames_%04d.raw', shell=True)
|
||||
repeat = r
|
||||
po = f-1
|
||||
frames=os.listdir(os.path.join("cache_ffg","raws"))
|
||||
for i in frames[:po]:
|
||||
framelist.append(i)
|
||||
for i in range(repeat):
|
||||
framelist.append(frames[po])
|
||||
for i in frames[po:]:
|
||||
framelist.append(i)
|
||||
out_data = b''
|
||||
for fn in framelist:
|
||||
with open(os.path.join("cache_ffg","raws",fn), 'rb') as fp:
|
||||
out_data += fp.read()
|
||||
with open(output, 'wb') as fp:
|
||||
fp.write(out_data)
|
||||
fp.close()
|
||||
shutil.rmtree("cache_ffg")
|
||||
|
||||
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)
|
||||
elif(mode==6):
|
||||
water_bloom(output)
|
||||
elif(mode==7):
|
||||
combine(output)
|
||||
19
Python Version/DatamoshLib/FFG_effects/external_script.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#Author: Akash Bora
|
||||
import os, subprocess
|
||||
from pathlib import Path
|
||||
|
||||
DIRPATH = Path(os.path.dirname(os.path.realpath(__file__)))
|
||||
ffgac = os.path.join(str(DIRPATH.parent.parent),"FFglitch","ffgac")
|
||||
ffedit = os.path.join(str(DIRPATH.parent.parent),"FFglitch","ffedit")
|
||||
|
||||
def mosh(input_video, output_video, mode, effect='', scriptfile='', gop=1000):
|
||||
|
||||
if mode==1:
|
||||
script_path = scriptfile
|
||||
elif mode==2:
|
||||
script_path = os.path.join(str(DIRPATH),"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')
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_ring_buffer.js
|
||||
// buffer.js
|
||||
// works kinda like an audio delay
|
||||
// stacks the previous n frames into a buffer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_delay.js
|
||||
// delay.js
|
||||
// works kinda like an audio delay
|
||||
// stacks the previous n frames into a buffer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_RandomDamage(invertRandomN).js
|
||||
// invertReverse.js
|
||||
// invert x and y component of mv for random number of frames if threshold met for frame
|
||||
|
||||
let threshold = 95;
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_mirror_X.js
|
||||
// mirror_X.js
|
||||
|
||||
// clean buffer :
|
||||
var buffer = [ ];
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_MultiplySlowest_50.js
|
||||
// noise.js
|
||||
// Multiply slowest moving mv's
|
||||
var LARGEST = 0;
|
||||
var SOME_PERCENTAGE = 0.5;
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_sheer.js
|
||||
// sheer.js
|
||||
|
||||
var ZOOM = -20;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// dd_RandomDamage(antiGrav).js
|
||||
// anitgravityify if threshold met for frame
|
||||
// shift.js
|
||||
// anitgravitify if threshold met for frame
|
||||
|
||||
let threshold = 98;
|
||||
// global variable holding forward motion vectors from previous frames
|
||||
@@ -1,5 +1,5 @@
|
||||
// dd_zero.js
|
||||
// only fuck things up if mv > movement_threshold
|
||||
// sink.js
|
||||
// only mess frames if mv > movement_threshold
|
||||
var movement_threshold = 3;
|
||||
function glitch_frame(frame)
|
||||
{
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_slam_zoom_in.js
|
||||
// slam_zoom.js
|
||||
|
||||
var ZOOM = 20;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_RandomDamage(progZoom).js
|
||||
// slice.js
|
||||
// progressive Zoom x and y components of mv if threshold met for frame
|
||||
|
||||
let threshold = 95;
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_RandomDamage(stopXY).js
|
||||
// stop.js
|
||||
// stop x and y component of mv for n framesif threshold met for frame
|
||||
|
||||
let threshold = 95;
|
||||
@@ -1,4 +1,4 @@
|
||||
// dd_zoom_in.js
|
||||
// zoom.js
|
||||
|
||||
var ZOOM = 20;
|
||||
|
||||
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)
|
||||
28
Python Version/DatamoshLib/Original/classic_new.py
Normal file
@@ -0,0 +1,28 @@
|
||||
#Author: Akash Bora
|
||||
def Datamosh(filename,outfile,s,e,fps):
|
||||
def mosh_iframe_removal():
|
||||
for index, frame in enumerate(frames):
|
||||
if index < start_frame or end_frame < index or frame[5:8] != iframe:
|
||||
out_file.write(frame_start + frame)
|
||||
|
||||
start_frame = s
|
||||
end_frame = e
|
||||
if end_frame==1:
|
||||
end_frame=1000
|
||||
input_avi = filename
|
||||
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_iframe_removal()
|
||||
in_file.close()
|
||||
out_file.close()
|
||||
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.
|
||||
245
Python Version/DatamoshLib/Tomato/tomato.py
Normal file
@@ -0,0 +1,245 @@
|
||||
#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 ("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:
|
||||
return
|
||||
|
||||
#define temp directory and files
|
||||
temp_nb = random.randint(10000, 99999)
|
||||
temp_dir = "temp-" + str(temp_nb)
|
||||
temp_hdrl = os.path.join(temp_dir,"hdrl.bin")
|
||||
temp_movi = os.path.join(temp_dir,"movi.bin")
|
||||
temp_idx1 = os.path.join(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:
|
||||
if mode == "bloom":
|
||||
if positframes==1:
|
||||
positframes=2
|
||||
for x in l[0:positframes]:
|
||||
if x[2] == 'video':
|
||||
clean.append(x)
|
||||
# clean the list by killing "big" frames
|
||||
for x in l[positframes:]:
|
||||
if x[1] <= (max_frame_size * kill) :
|
||||
clean.append(x)
|
||||
else:
|
||||
for x in l[0:10]:
|
||||
if x[2] == 'video':
|
||||
clean.append(x)
|
||||
# clean the list by killing "big" frames
|
||||
for x in l[10:]:
|
||||
if x[1] <= (max_frame_size * kill) :
|
||||
clean.append(x)
|
||||
else:
|
||||
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)))
|
||||
0
Python Version/FFglitch/FFglitch goes here
Normal file
@@ -1,19 +0,0 @@
|
||||
#Read this to use the python version.
|
||||
This version is comparitively lower in size and works the same inside python environment.
|
||||
Things to setup before running the python file:
|
||||
1) First setup ffglitch if you are using this repo only. (See readme.txt inside ffglitch folder to download ffglitch)
|
||||
Note: No need to do the ffglitch setup if you downloaded the release python version as all the versions are pre-provided there
|
||||
2) After doing that, run the datamosher-pro.py file and click yes if module error pops up and let the modules get downloaded.
|
||||
If it doesn't work then install the modules manually-
|
||||
Modules you need to install:
|
||||
-- tkinter
|
||||
If not installed then use-
|
||||
(pip install tk) or (sudo apt-get install python3-tk)
|
||||
-- numpy
|
||||
(pip install numpy)
|
||||
-- imageio
|
||||
(pip install imageio)
|
||||
-- imageio-ffmpeg
|
||||
(pip install imageio-ffmpeg)
|
||||
3) Do not delete or move any assets or folder that are linked with the main file or else it will show error.
|
||||
After the setup the application will open and you can try datamoshing.
|
||||
170
Python Version/Setup.py
Normal file
@@ -0,0 +1,170 @@
|
||||
#Automatic Setup for Datamosher-Pro
|
||||
#Author: Akash Bora
|
||||
|
||||
#Importing some built in modules
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import os
|
||||
from zipfile import ZipFile
|
||||
|
||||
print("Datamosher Pro Python Setup")
|
||||
try:
|
||||
import pkg_resources
|
||||
except ImportError:
|
||||
if sys.platform.startswith("win"):
|
||||
subprocess.call('python -m pip install setuptools', shell=True)
|
||||
else:
|
||||
subprocess.call('python3 -m pip install setuptools', shell=True)
|
||||
import pkg_resources
|
||||
|
||||
DIRPATH = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
#Set executable permissions for macOS
|
||||
def set_mac_permissions():
|
||||
if sys.platform.startswith("darwin"):
|
||||
print("Setting executable permissions for macOS...")
|
||||
ffgac = os.path.join(DIRPATH,"FFglitch","ffgac")
|
||||
ffedit = os.path.join(DIRPATH,"FFglitch","ffedit")
|
||||
|
||||
try:
|
||||
if os.path.exists(ffgac):
|
||||
os.chmod(ffgac, 0o755)
|
||||
print("Permissions set for ffgac")
|
||||
except Exception as e:
|
||||
print(f"Failed to set permissions for ffgac: {e} \nPlease go to System Settings -> Security & Privacy -> scroll down and give permission to the ffgac file")
|
||||
|
||||
try:
|
||||
if os.path.exists(ffedit):
|
||||
os.chmod(ffedit, 0o755)
|
||||
print("Permissions set for ffedit")
|
||||
except Exception as e:
|
||||
print(f"Failed to set permissions for ffedit: {e} \nPlease go to System Settings -> Security & Privacy -> scroll down and give permission to the ffedit 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 folders are not available: "+str(missingfolder))
|
||||
print("Download them from the repository properly")
|
||||
sys.exit()
|
||||
else:
|
||||
print("All required folders available!")
|
||||
|
||||
#Checking required modules
|
||||
required = {'imageio', 'imageio-ffmpeg', 'numpy', 'customtkinter', 'pillow', 'requests', 'packaging'}
|
||||
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 now? (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 now? (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 open this program. Please install them first! \nThis are the required one: "+str(required)
|
||||
+"\nUse 'pip install module_name' to download modules one by one manually.")
|
||||
time.sleep(3)
|
||||
sys.exit()
|
||||
else:
|
||||
print("All required modules installed!")
|
||||
|
||||
#Check FFglitch Status
|
||||
def checkffglitch():
|
||||
print("Checking FFglitch:")
|
||||
# Set permissions for macOS before running
|
||||
set_mac_permissions()
|
||||
print("Running ffgac...")
|
||||
ffgac = os.path.join(DIRPATH,"FFglitch","ffgac")
|
||||
ffedit = os.path.join(DIRPATH,"FFglitch","ffedit")
|
||||
|
||||
try:
|
||||
subprocess.Popen(f'"{ffgac}" -version', shell=True)
|
||||
except:
|
||||
print("permission denied! Please give permission to ffgac!")
|
||||
|
||||
time.sleep(1)
|
||||
print("Running ffedit...")
|
||||
try:
|
||||
subprocess.Popen(f'"{ffedit}" -version', shell=True)
|
||||
except:
|
||||
print("permission denied! Please give permission to ffedit!")
|
||||
time.sleep(1)
|
||||
print("Done...")
|
||||
|
||||
#Download ffglitch if not available
|
||||
if (os.path.exists(os.path.join("FFglitch","ffgac")) or
|
||||
os.path.exists(os.path.join("FFglitch","ffgac.exe"))) and (os.path.exists(os.path.join("FFglitch","ffedit"))
|
||||
or os.path.exists(os.path.join("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 modes? (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(os.path.join("FFglitch","ffglitch.zip"), "wb").write(response.content)
|
||||
except:
|
||||
print("Unable to download ffglitch from site, try again running this setup!")
|
||||
print("Check your connection or download it manually from: | https://github.com/Akascape/FFglitch-0.9.3-executables |")
|
||||
print("Then paste the files (ffgac and ffedit) inside FFglitch folder.")
|
||||
time.sleep(5)
|
||||
sys.exit()
|
||||
time.sleep(1)
|
||||
print("Exctracting the files...")
|
||||
try:
|
||||
with ZipFile(os.path.join('FFglitch','ffglitch.zip'), 'r') as zip:
|
||||
zip.extractall('FFglitch/')
|
||||
except:
|
||||
print("Failed to extract ffglitch.zip, please extract it manually inside the FFglitch folder.")
|
||||
time.sleep(3)
|
||||
sys.exit()
|
||||
if os.path.exists(os.path.join("FFglitch","ffgac")) or os.path.exists(os.path.join("FFglitch","ffgac.exe")):
|
||||
os.remove(os.path.join("FFglitch","ffglitch.zip"))
|
||||
time.sleep(1)
|
||||
|
||||
set_mac_permissions()
|
||||
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 packages, download them manually and paste them inside the FFglitch folder.")
|
||||
|
||||
#Everything done!
|
||||
time.sleep(1)
|
||||
print("Setup Complete!")
|
||||
time.sleep(5)
|
||||
sys.exit()
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
All ffglitch builds are given in the release python version, so download that directly
|
||||
For people downloading this repo,
|
||||
Download ffglitch from ffglitch.org or the direct links are given below:
|
||||
For windows:
|
||||
https://ffglitch.org/pub/bin/win64/ffglitch-0.9.3-win64.7z
|
||||
For linux:
|
||||
https://ffglitch.org/pub/bin/linux64/ffglitch-0.9.3-linux64.7z
|
||||
For mac:
|
||||
https://ffglitch.org/pub/bin/mac64/ffglitch-0.9.3-mac64.7z
|
||||
|
||||
After downloading, extract the files and move the ffedit and ffgac file in this ffglitch folder of datamosher pro.
|
||||
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 @@
|
||||
|
||||
|
||||
7
Python Version/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
imageio
|
||||
imageio-ffmpeg
|
||||
numpy
|
||||
customtkinter
|
||||
pillow
|
||||
requests
|
||||
packaging
|
||||
213
Readme.md
@@ -1,98 +1,123 @@
|
||||
# Datamosher Pro
|
||||
<b>Datamoshing is a cool video effect and if you also want to create this glitch with your videos, 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>With Datamosher Pro you can quickly and easily datamosh your videos!</b><br>
|
||||
### Why I made this?
|
||||
I was also looking for some good datamoshing software and I found that you have to either use those old softwares like Avidemux or have to look for some paid plugins, so I created my own python based application 'Datamosher Pro' which is an open source project. It contains `30+` different effects which can replicate any type of datamoshing style.
|
||||
# DOWNLOAD
|
||||
### Support Datamosher-Pro Development by buying datamosher-pro installer for windows on Gumroad. It will be really helpful!
|
||||
<br> <p align='center'> [<img alt="GitHub release (latest by date)" src="https://img.shields.io/github/v/release/Akascape/Datamosher-Pro?display_name=release&label=Windows&logo=Windows&logoColor=019df4&style=for-the-badge" width="500">](https://akascape.gumroad.com/l/Datamosher-Pro) </br>
|
||||
### Otherwise you can use the source code (python version)
|
||||
<br> <p align='center'> [<img alt="GitHub repo size" src="https://img.shields.io/github/repo-size/Akascape/Datamosher-Pro?color=9508e2&label=Source%20Code&logo=Python&logoColor=yellow&style=for-the-badge" width="300">](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Prov1.6/Datamosher_Pro-python_version.zip) <br> Don't forget to give a ⭐ :) </p>
|
||||
[](https://akascape.gumroad.com/l/Datamosher-Pro)
|
||||
|
||||
# How to Install?
|
||||
- For the Windows version, just extract the downloaded zip file and run the Datamosher_Pro.exe to open it.
|
||||
<br> Benefits of having the executable version:
|
||||
<br>• All the files are packed in one exe file
|
||||
<br>• No environment or setup problems
|
||||
<br>• Faster renders
|
||||
<br>• Get new updates earlier
|
||||
<br>• Custom Script mode is available
|
||||
- please use the python version for now if you are on any other OS. (Mac version is in development and will be avaialable soon)
|
||||
<br> Make sure you have python installed properly and then open the datamosher_pro-python 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. After that you will be asked to choose your OS, just follow the setup carefully and you are done. (No python skills needed)
|
||||
# How to Use?
|
||||
• Input the video file first (supported formats- mp4, gif, avi, mov, mkv, wmv)
|
||||
<br>• Choose the desired datamosh mode and the export format
|
||||
<br>• Use the advance options to get more accurate results
|
||||
<br>• Check/uncheck the highest quality box for quality adjustments
|
||||
<br>• Then simply click on the datamosh button and wait for a few seconds
|
||||
<br>• After conversions, your video will be moshed and saved in the same directory
|
||||
## Gallery & Demos
|
||||
[](https://github.com/Akascape/Datamosher-Pro/blob/Datamosher-Pro-v1.6/Demos.md)
|
||||
# Effects Info
|
||||
### Effects List:
|
||||
<br> TIP: Major effects used for datamoshing: Classic, Bloom, Glide, Repeat, Motion Transfer, Rise, Fluid
|
||||
<br>
|
||||
# Datamosher Pro
|
||||
<b> Datamosher Pro is an automatic, algorithm based video-glitching application for free! (python)
|
||||
<br><img align="right" src="https://user-images.githubusercontent.com/89206401/141642297-7c62cf6f-7024-430f-88a2-c9cbbf0dc655.png" width="300">
|
||||
|
||||
<br> It contains over `30+` different effects/algorithms/scripts that can emulate any style of datamoshing.
|
||||
<br> There are two versions available: a premium paid version for Windows/MacOS and a basic free version with source code.
|
||||
<br> If you’re aiming to easily create datamosh effects in your videos, you’re in the right spot!
|
||||
|
||||
### Story behind the Software
|
||||
I was also searching for some good datamoshing software and I noticed that we either have to use those outdated programs like Avidemux or look for some paid plugins.
|
||||
Then I found some scripts and algorithms available for datamoshing which gives accurate results, but not everyone knows how to run those scripts on their system, hence I developed this GUI application for those scripts and added lots of new features which make this datamoshing process super easy. Just import the video and click the mosh button.
|
||||
|
||||
# DOWNLOAD
|
||||
### <p align='center'> Support Datamosher-Pro Development by purchashing its premium version which include features like video player, conversion settings, themes, live mosh and more glitch effects.
|
||||
### <p align='center'> PREMIUM VERSION ⚡
|
||||
<br> <p align='center'> [<img src="https://custom-icon-badges.demolab.com/badge/WINDOWS/MAC-DATAMOSHER_PRO-informational?&logo=Datamosher_Pro&logoColor=blue&color=007ec6" width="500">](https://akascape.gumroad.com/l/Datamosher-Pro) </br>
|
||||
|
||||
### <p align='center'> FREE SOURCE CODE VERSION 🔻
|
||||
<br> <p align='center'> [<img src="https://img.shields.io/badge/Python_Version-informational?style=flat&logo=python&logoColor=blue&color=eaea4a" width=300 height=50>](https://github.com/Akascape/Datamosher-Pro/releases/download/Datamosher_Pro-v2.4/Datamosher-Pro_python-version_2.4.zip) <br> Don't forget to leave a ⭐ </p>
|
||||
|
||||
# Installation? ⚙️
|
||||
- For the premium version, just extract the downloaded zip file and run the "Datamosher Pro" application.
|
||||
- For Python version, you need to install some stuff, not so difficult, check this >[installation](https://github.com/Akascape/Datamosher-Pro/wiki/1.How-to-Install)< guide.
|
||||
|
||||
**Official Tutorial Videos**
|
||||
<br> [<img src="https://img.youtube.com/vi/TQIQ1TmHUBY/0.jpg" width=40% height=40%>](https://youtu.be/TQIQ1TmHUBY) [<img src="https://img.youtube.com/vi/eO-w-I-oCnc/0.jpg" width=40% height=40%>](https://www.youtube.com/watch?v=eO-w-I-oCnc)
|
||||
|
||||
# Documentation 📑
|
||||
- A detailed documentation of this software is available in the >[Wiki](https://github.com/Akascape/Datamosher-Pro/wiki)< page.
|
||||
|
||||
## Gallery 🖼️
|
||||
Find more Examples and Tutorial Videos here 👇
|
||||
|
||||
<br> [<img src="https://img.shields.io/badge/View-Gallery-informational?&color=darkblue&style=for-the-badge" width="200">](https://github.com/Akascape/Datamosher-Pro/blob/Datamosher-Pro-v1.7/Demos.md)
|
||||
|
||||
# UI (FREE VERSION)
|
||||

|
||||
|
||||
# UI (PREMIUM VERSION)
|
||||

|
||||

|
||||
|
||||
# Effects List
|
||||
### Effects available in the python version:
|
||||
**Main datamosh effects:**
|
||||
| Effect Name | Description |
|
||||
| ----------------| --------------------------------------------------------------------- |
|
||||
| Custom Script (NEW)| This mode is only available in paid version where you can use any ffglitch script|
|
||||
| Rise | another classic i frames removal effect|
|
||||
| Shuffle | randomly shuffles chunks of video frames with the classic ffglitch datamosh (unstable with short videos)|
|
||||
| Buffer | creates ring buffers to mosh|
|
||||
| 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|
|
||||
### How to use Advanced Options?
|
||||
The advanced tab is very useful to get accurate results. The options are:
|
||||
<br>• `Glitch Size` - tells how long/often to glitch
|
||||
<br>• `Frame Frequency` - tells how many frames to apply in the glitch
|
||||
<br>• `First Frame` - tells whether to keep the first video frames
|
||||
<br>• `Kill Frames` - tells max framesize to kill while cleaning
|
||||
<br>
|
||||
<br>NOTE:
|
||||
<br>- Some modes may not support all the 4 advanced options.
|
||||
<br>- You can try experimenting with the values and see the results but don't put huge values.
|
||||
<br>- Audio glitching is only available in few modes like classic and repeat.
|
||||
# UI
|
||||
<br><img src="https://user-images.githubusercontent.com/89206401/142208408-6970448d-fe9d-4e60-aac6-21809aefcfca.png">
|
||||
## How It Works?
|
||||
The main issue with datamoshing is conversion of corrupted files but with Datamosher Pro you can use any video file and get 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, 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 unneccesary temp files get deleted automatically.
|
||||
### Read these guides for more details:
|
||||
<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 videos :)
|
||||
<br>I hope there is no error in the program but if you find any bug then raise an issue. As it's a new piece of software some users may find errors but updates will be on their way. You can also help to make new datamosh effects.
|
||||
<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>Follow me : [`Akascape`](https://github.com/Akascape)
|
||||
<br>
|
||||
<br> DATAMOSHING MADE EASY!
|
||||
### Current Version-1.6.1
|
||||
<br> [](https://www.python.org/) [](https://github.com/Akascape/Datamosher-Pro) [](https://github.com/Akascape/Datamosher-Pro) [](https://github.com/Akascape/Datamosher-Pro)
|
||||
| Void | gives the standard datamosh cuts based on video vectors (automatic i-frame removal) |
|
||||
| Classic | gives the avidemux type datamosh within a range |
|
||||
| Classic2 | similar to classic mode, but more precise results (uses frame numbers) |
|
||||
| Combine | combine multiple videos and mosh them together |
|
||||
| Rise | gives you the ffglitch datamosh by manually removing a range of i frames |
|
||||
| Shuffle | randomly shuffles chunks of frames and then moshes them with the normal ffglitch datamosh |
|
||||
| Sort | sorts video frames by data size and merges them with the classic datamosh |
|
||||
| Motion Transfer | transfer the vector motion data from one video to another |
|
||||
|
||||
**Frame Repeatation datamosh:**
|
||||
| Effect Name | Description |
|
||||
| ----------------| --------------------------------------------------------------------- |
|
||||
| Bloom | duplicates a key-frame multiple times with void mode |
|
||||
| Water Bloom | duplicates any frame multiple times with ffglitch (more precise than bloom) |
|
||||
| Repeat | repeats a **series** of frames multiple times |
|
||||
| Glide | duplicates macroblocks multiple times in a continuos order |
|
||||
| Pulse | duplicates groups of some p-frames every n times (heavy to render) |
|
||||
|
||||
Other glitch/datamosh modes
|
||||
| Effect Name | Description |
|
||||
| ----------------| --------------------------------------------------------------------- |
|
||||
| Buffer | creates glitchy ring buffers in the video |
|
||||
| Delay | random delaying mosh effect |
|
||||
| Invert-Reverse | randomly applies both inverse and reverse datamosh |
|
||||
| Mirror | mosh with vertical mirrored part of the video|
|
||||
| Noise | makes large noisy buffers |
|
||||
| Shear | tilt and mosh the video clockwise |
|
||||
| Shift | shifts random blocks of the video againt the gravity |
|
||||
| Sink | drowns the next frame of the video with the previous one|
|
||||
| Slam Zoom | applies zoom with the sink effect |
|
||||
| Slice | randomly slices the video into multiple parts |
|
||||
| Stop | similar to sink but stops the XY values randomly |
|
||||
| Vibrate | randomize the pixels continuosly |
|
||||
| Zoom | simply zooms inside the moshed video |
|
||||
| Fluid | ffglitch's average motion effect which gives a smooth liquid type effect |
|
||||
| Stretch | stretches the macroblock of video both horizontally and vertically |
|
||||
| Echo | duplicates the single video and apply the mosh effect in the midpoint
|
||||
| Random | randomizes frame order |
|
||||
| Reverse | reverses frame order |
|
||||
| Invert | switches each consecutive frame witch each other |
|
||||
| Overlap | copy group of some frames taken from every nth position |
|
||||
| Jiggle | take frame from around current position |
|
||||
| Custom Script | You can experiment with your own ffglitch script with this mode |
|
||||
|
||||
### More effects and features are available in the paid version.
|
||||
|
||||
## Note from Author
|
||||
It took lots of effort and time while developing this app, hope this program can be your companion while editing cool glitchy videos :)
|
||||
<br> As it is a new piece of software some users may find bugs, but updates will be on their way. (You can report them through the issues tab)
|
||||
<br> The effects are inspired from the [tomato.py](https://github.com/itsKaspar/tomato) script, [pymosh](https://github.com/grampajoe/pymosh) and [FFglitch](https://ffglitch.org/).
|
||||
All the logos and ui designs are created by me.
|
||||
|
||||
<br>[<img src="https://img.shields.io/badge/-Follow_Akascape_on_Github-informational?style=flat&logo=github&logoColor=black&color=grey">](https://github.com/Akascape)
|
||||
<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-master/LICENSE)
|
||||
<br> Copyright (c) 2024 Akash Bora
|
||||
|
||||
The main app files written by the Author is MIT licensed
|
||||
|
||||
Note that **FFglitch** and **FFmpeg** are not provided in the *releases* directly and are not placed under this license, these binaries should be treated as external components because the library code remains totally separate from them (without doing any modification).
|
||||
|
||||
All the other required component licenses (mostly MIT) are provided in their folder/block respectively and it must be taken into account that multiple licenses are involved.
|
||||
<br>
|
||||
|
||||
## DATAMOSH MADE EASY
|
||||
|
||||
| Current Python Version: | 2.4 |
|
||||
| ----------------| --------- |
|
||||
| Current Premium Version: | 2.8 |
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||