Skip to content

Commit

Permalink
make it so
Browse files Browse the repository at this point in the history
  • Loading branch information
mannynotfound committed Aug 27, 2017
0 parents commit 4b10783
Show file tree
Hide file tree
Showing 81 changed files with 284 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
data/*
!data/sample.mp4
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# deep fryer

<p align="center">
<img width="80%" src="cover.png" />
</p>

Wrapper around `ffmpeg` to automatically give videos the [deep fried meme](http://knowyourmeme.com/memes/deep-fried-memes) effect.

## usage

```bash
python deep-fryer.py -i data/sample.mp4 -o data/deep_fried_sample.mp4
```

## dependencies

```bash
pip install -r requirements.txt
```
Binary file added cover.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added data/.gitkeep
Empty file.
Binary file added data/sample.mp4
Binary file not shown.
193 changes: 193 additions & 0 deletions deep-fryer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import os
import re
import sys
import random
import ffmpy
import argparse
from utils import line_break, make_random_value, get_total_seconds, get_dimensions
from collections import OrderedDict
from shutil import copyfile, rmtree


TMP_FOLDER = './tmp'


def create_base_args():
return [
'-y', # overwrite existing
'-c:a', 'copy', # copy input settings
'-vb', '2M', # shitty bit rate to create compression effect
]


def create_filter_args():
"""
Create randomized "deep fried" visual filters
returns command line args for ffmpeg's filter flag -vf
"""
saturation = make_random_value([2, 3])
contrast = make_random_value([1.5, 2])
noise = make_random_value([30, 60])

eq_str = 'eq=saturation={}:contrast={}'.format(saturation, contrast)
noise_str = 'noise=alls={}:allf=t'.format(noise)
filter_str = ', '.join([eq_str, noise_str])

return ['-vf', filter_str]


def get_random_emoji():
"""
Return a random emoji file from './emoji'. To avoid errors when using the
same file more than once, each file is given a random name and copied into './tmp'
"""
if not os.path.exists(TMP_FOLDER):
os.makedirs(TMP_FOLDER)

rand_emoji = None
while rand_emoji is None:
rand_choice = random.choice(os.listdir('./emoji'))
if 'DS_Store' not in rand_choice:
new_name = str(random.randint(0, 99999999)) + '.png'
new_dest = '{}/{}'.format(TMP_FOLDER, new_name)
copyfile('./emoji/{}'.format(rand_choice), new_dest)
rand_emoji = new_dest

return rand_emoji


def get_random_emojis(amt):
"""
Create emoji inputs, returning an OrderedDict where each key is the emoji
comp name and the value includes size and filter str. Filter string
example: [4:v]scale=30:30,rotate=12*PI/180:c=none[emoji_4]
"""
emojis = OrderedDict({})
for idx in xrange(1, amt + 1):
size = random.randint(50, 200)
rotation = random.randint(-180, 180)

emoji_name = 'emoji_{}'.format(idx)
filter_str = '[{}:v]scale={}:{},rotate={}*PI/180:c=none[{}]'.format(
idx, size, size, rotation, emoji_name
)

emojis[emoji_name] = {
'size': size,
'filter_str': filter_str,
}


return emojis

def create_emoji_filters(input_file):
comp_name = '0:v'
seconds = get_total_seconds(input_file)
width, height = get_dimensions(input_file)

emoji_filters = []
emoji_amt = make_random_value([0.75, 0.95])
random_emojis = get_random_emojis(int(seconds * emoji_amt))
emoji_keys = random_emojis.keys()

for idx, emoji in enumerate(emoji_keys):
size = random_emojis[emoji]['size']
filter_str = random_emojis[emoji]['filter_str']

max_x = width - size
max_y = height - size
pos_x = make_random_value([0, max_x])
pos_y = make_random_value([0, max_y])

dur = make_random_value([2, 5])
max_start = seconds - dur
start = make_random_value([0, max_start])
end = start + dur

new_comp = 'comp_{}'.format(idx)
emoji_str = ';'.join([
filter_str,
"[{}][{}]overlay={}:{}:enable='between(t, {}, {})'".format(
comp_name, emoji, pos_x, pos_y, start, end
),
])

if idx < (len(emoji_keys) - 1):
emoji_str += '[{}];'.format(new_comp)
comp_name = new_comp

emoji_filters.append(emoji_str)

return emoji_filters


def create_inputs(input_file, emoji_filters=[]):
"""
Special input creator with optional emoji_filters argument
that adds emoji input for every emoji filter passed
"""
inputs = [(input_file, None)]
# add an actual emoji file input for every filter created
for _ in emoji_filters:
emoji_input = get_random_emoji()
inputs.append((emoji_input, None))

return OrderedDict(inputs)


def create_outputs(output_file, output_args):
return OrderedDict([(output_file, output_args)])


def add_random_emojis(input_file):
"""
Overlays emojis at random angles, size, durations, and start frames over a
given input file. The amount of emojis is based on input file length.
"""
emoji_filters = create_emoji_filters(input_file)
inputs = create_inputs(input_file, emoji_filters)

output_args = create_base_args()
output_args += ['-filter_complex', ''.join(emoji_filters)]

tmp_output = '{}/emojied_video.mp4'.format(TMP_FOLDER)
outputs = create_outputs(tmp_output, output_args)

ff = ffmpy.FFmpeg(inputs=inputs, outputs=outputs)
try:
ff.run()
return tmp_output
except Exception as e:
line_break(3)
sys.exit('Failed to add emojis.\n{}'.format(e))


def main(input_file, output_file):
emojified_video = add_random_emojis(input_file)
inputs = create_inputs(emojified_video)

output_args = create_base_args() + create_filter_args()
outputs = create_outputs(output_file, output_args)

ff = ffmpy.FFmpeg(inputs=inputs, outputs=outputs)
try:
ff.run()
line_break(3)
print('Succesfully deep fried video at {}!'.format(output_file))
line_break(3)
except Exception as e:
line_break(3)
print('Failed to deep fry video.\n{}'.format(e))

rmtree(TMP_FOLDER)

if __name__ == '__main__':
ap = argparse.ArgumentParser()
ap.add_argument('-i', '--input_file', help='input file')
ap.add_argument('-o', '--output_file', help='output file', default=None)
args = ap.parse_args()

assert args.input_file is not None, 'No input file provided...'
assert args.output_file is not None, 'No output file provided...'

main(args.input_file, args.output_file)
Binary file added emoji/100_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Airplane_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Alien_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Angry_Devil_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Angry_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Anguished_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Astonished_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Athletic_Shoe_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Banana_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Blow_Kiss_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Cherry_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Confounded_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Diamond_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Disappointed_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Dizzy_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Eggplant_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Eyes_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Face_With_Rolling_Eyes_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Face_with_Cold_Sweat_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Fearful_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Fire_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Fist_Hand_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Flexing_Muscles_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Flushed_Face_Emoji.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added emoji/Ghost_Emoji.png
Binary file added emoji/Grinmacing_Face_Emoji.png
Binary file added emoji/Grinning_Emoji_with_Smiling_Eyes.png
Binary file added emoji/Heart_Eyes_Emoji.png
Binary file added emoji/High_Five_Emoji.png
Binary file added emoji/Hugging_Face_Emoji.png
Binary file added emoji/Loudly_Crying_Face_Emoji.png
Binary file added emoji/Man_Bowing_Emoji.png
Binary file added emoji/Middle_Finger_Emoji.png
Binary file added emoji/Money_Bag_Emoji.png
Binary file added emoji/Money_Face_Emoji.png
Binary file added emoji/Money_with_Wings_Emoji.png
Binary file added emoji/OMG_Face_Emoji.png
Binary file added emoji/Peach_Emoji.png
Binary file added emoji/Persevering_Face_Emoji.png
Binary file added emoji/Pink_Nail_Polish_Emoji.png
Binary file added emoji/Poop_Emoji.png
Binary file added emoji/Rainbow_emoji_icon_png.png
Binary file added emoji/Raised_Hand_Emoji.png
Binary file added emoji/Relieved_Emoji.png
Binary file added emoji/Sad_Face_Emoji.png
Binary file added emoji/Sail_Boat_Emoji.png
Binary file added emoji/Sick_Emoji.png
Binary file added emoji/Sign_of_the_Horns_Emoji.png
Binary file added emoji/Sleeping_with_Snoring_Emoji.png
Binary file added emoji/Slightly_Smiling_Face_Emoji.png
Binary file added emoji/Smiling_Devil_Emoji.png
Binary file added emoji/Smiling_Face_Emoji.png
Binary file added emoji/Smiling_Face_Emoji_with_Blushed_Cheeks.png
Binary file added emoji/Smiling_Face_with_Halo.png
Binary file added emoji/Smiling_Face_with_Tightly_Closed_eyes.png
Binary file added emoji/Smirk_Face_Emoji.png
Binary file added emoji/Sweat_Water_Emoji.png
Binary file added emoji/Tears_of_Joy_Emoji.png
Binary file added emoji/Thinking_Face_Emoji.png
Binary file added emoji/Tired_Face_Emoji.png
Binary file added emoji/Tongue_Emoji.png
Binary file added emoji/Tongue_Out_Emoji.png
Binary file added emoji/Tongue_Out_Emoji_with_Winking_Eye.png
Binary file added emoji/Unamused_Face_Emoji.png
Binary file added emoji/Upside-Down_Face_Emoji.png
Binary file added emoji/Very_Angry_Emoji.png
Binary file added emoji/Weary_Face_Emoji.png
Binary file added emoji/Woman_Saying_No_Emoji.png
Binary file added emoji/Worried_Face_Emoji.png
Binary file added emoji/Zipper-Mouth_Face_Emoji.png
Binary file added emoji/voltage_emoji_icon_png.png
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ffmpy==0.2.2
69 changes: 69 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import os
import re
import tempfile
import random


def get_dimensions(input_file):
"""
Parse a video's resolution (1024x720) and return width + height
"""
deets = get_video_details(input_file)
dimensions = deets['video']['resolution'].split('x')
width = int(dimensions[0])
height = int(dimensions[1])
return width, height


def get_total_seconds(input_file):
"""
Parse a video's duration (00:00:00) and convert to total seconds
"""
deets = get_video_details(input_file)
duration = deets['duration'].split(':')
hours = float(duration[0])
minutes = float(duration[1])
seconds = float(duration[2])
seconds += minutes * 60
seconds += hours * 60 * 60
return seconds


def make_random_value(val_range):
"""
Turn an array of 2 value ranges into float rounded to 2 decimal places
eg [2, 3] => 2.33
"""
return round(random.uniform(*val_range), 2)


def line_break(num):
for _ in range(num):
print('')


def get_video_details(input_file):
tmpf = tempfile.NamedTemporaryFile()
os.system('ffmpeg -i {} 2> {}'.format(input_file, tmpf.name))
lines = tmpf.readlines()
tmpf.close()
metadata = {}
for l in lines:
l = l.strip()
if l.startswith('Duration'):
metadata['duration'] = re.search('Duration: (.*?),', l).group(0).split(':',1)[1].strip(' ,')
metadata['bitrate'] = re.search("bitrate: (\d+ kb/s)", l).group(0).split(':')[1].strip()
if l.startswith('Stream #0:0'):
metadata['video'] = {}
metadata['video']['codec'], metadata['video']['profile'] = \
[e.strip(' ,()') for e in re.search('Video: (.*? \(.*?\)),? ', l).group(0).split(':')[1].split('(')]
metadata['video']['resolution'] = re.search('([1-9]\d+x\d+)', l).group(1)
metadata['video']['bitrate'] = re.search('(\d+ kb/s)', l).group(1)
metadata['video']['fps'] = re.search('(\d+ fps)', l).group(1)
if l.startswith('Stream #0:1'):
metadata['audio'] = {}
metadata['audio']['codec'] = re.search('Audio: (.*?) ', l).group(1)
metadata['audio']['frequency'] = re.search(', (.*? Hz),', l).group(1)
metadata['audio']['bitrate'] = re.search(', (\d+ kb/s)', l).group(1)

return metadata

0 comments on commit 4b10783

Please sign in to comment.