Automatised post-processing of video using image compression algorithm glitches.
Die Antwoord, Banana brain
Lorn, Acid Rain
Bhad Bhabie, I got it
For jpg codec, the process is recompressing each frame with 1% less quality than previous compression. In the videos above, we start at 40% and gradually decrease the quality to 1%.
For gif codec, it is much more straight-forward, as we do the process in one pass, specifying the number of colors in the palette.
Python script
try: from cStringIO import StringIO as BytesIO except ImportError: from io import BytesIO from PIL import Image import os import shutil import subprocess ------------- GLOBAL ------------- # set to true if the source video has not been extracted already regenarate_video_frames = False recompress_video_frames = True regenarate_output_video = True # source video path video = 'source.mv' # folder path to export source video frames folder_frames = 'frames' # folder path to store compressed video frames folder_compressed = 'compressed' # type of compressor - JPG or GIF compressor = 'JPG' # jpg compressor settings jpg_from = 40 jpg_to = 1 jpg_steps = 1 # gif compressor settings gif_colors = 4 # output frames limits limit_from = 1800 limit_to = 3125 # output frame rate fps = 25 fprefix = 'output_' ------------- FUNCTIONS ------------- def create_folder(p): if not os.path.exists(p): os.makedirs(p) else: clear_folder(p) def clear_folder(p): for root, dirs, files in os.walk( p ): for f in files: os.unlink(os.path.join( root, f )) for d in dirs: shutil.rmtree(os.path.join( root, d )) def jpg_compress( src_path, dst_path ): jpg_q = jpg_from while jpg_q >= jpg_to: src = Image.open( src_path ) buffer = BytesIO() src.save( buffer, "JPEG", quality = jpg_q, optimize=True, progressive=True ) jpg_q -= jpg_steps buffer.seek(0) with open( dst_path, "w") as handle: handle.write(buffer.read()) src_path = dst_path def gif_compress( src_path, dst_path ): src = Image.open( src_path ) buffer = BytesIO() src = src.convert('P', palette=Image.ADAPTIVE, colors=gif_colors) src.save( buffer, "PNG" ) buffer.seek(0) with open( dst_path, "w") as handle: handle.write(buffer.read()) ------------- PROCESS ------------- if regenarate_video_frames == True: create_folder( folder_frames ) subprocess.call(['ffmpeg', '-i', video, '-vcodec', 'png', folder_frames + '/' + fprefix + '%05d.png' ]) if recompress_video_frames == True: create_folder( folder_compressed ) ext = '.jpg' if compressor == 'GIF': ext = '.png' for root, dirs, files in os.walk( folder_frames ): files.sort() i = 0 outi = 0 for f in files: if limit_from > -1 and i >= limit_from and i < limit_to: outf = folder_compressed + '/' + fprefix if outi < 10: outf += '0000' elif outi < 100: outf += '000' elif outi < 1000: outf += '00' elif outi < 10000: outf += '0' outf += str(outi) + ext outi += 1 if compressor == 'JPG': jpg_compress( folder_frames + '/' + f, outf ) elif compressor == 'GIF': gif_compress( folder_frames + '/' + f, outf ) print( str( outi ) + '/' + str( ( limit_to - limit_from ) ) + ' frame (' + ext + ')' ) i += 1 if regenarate_output_video == True: movie_path = 'movie_' + fps + 'fps_' + limit_from + '-' + limit_to im_path = folder_compressed + '/' + fprefix + '%5d' if compressor == 'JPG': movie_path += '_' + jpg_from + '-' + jpg_to + '-' + jpg_steps + 'jpg' im_path += '.jpg' elif compressor == 'GIF': movie_path += '_' + gif_colors + 'gif' im_path += '.png' else: pass movie_path += '.mkv' subprocess.call(['ffmpeg', '-f', 'image2', '-framerate', str(fps), '-r', str(fps), '-i', im_path, '-an', '-vcodec', 'mjpeg', '-q:v', '1', folder_compressed + '/' + movie_path ])
First attempt using lame, File:I got it 3.mp3
try: from cStringIO import StringIO as BytesIO except ImportError: from io import BytesIO from PIL import Image import os import shutil import subprocess source = 'source.wav' swap_file1 = 'output.mp3' swap_file2 = 'output2.wav' passes = 27 freq = 20001 freq_gap = 300 scale = 1.03 compression = 20 compression_gap = 1.3 FNULL = open(os.devnull, 'w') subprocess.call(['lame', '--quiet', '-q', '9', source, swap_file1 ]) for i in range( 0, passes ): print( '>>>>>>>>>>> pass: ' + str( i ) + ', freq: ' + str(freq) + ', compression: ' + str(compression) ) subprocess.call(['ffmpeg', '-i', swap_file1, '-ar', str(freq), '-loglevel', 'panic', '-y', swap_file2 ]) subprocess.call(['lame', '--scale', str(scale), '--quiet', '-q', '9', '--comp', str(compression), swap_file2, swap_file1 ]) if i%2 == 1: freq -= freq_gap else: freq += freq_gap compression += compression_gap # preview subprocess.call(['xplayer', swap_file1], stdout=FNULL, stderr=subprocess.STDOUT)
online identity ∋ [ social ∋ [mastodon♥, twitter®, facebook®, diaspora, linkedin®]
∥ repos ∋ [github®, gitlab♥, bitbucket®, sourceforge] ∥ media ∋ [itch.io®, vimeo®, peertube♥, twitch.tv®, tumblr®] ∥ communities ∋ [godotengine♥, openprocessing, stackoverflow, threejs]]