Last active
November 28, 2022 14:18
-
-
Save KumaTea/93506c6a6bec5f2fa0e1cea72e3d09a9 to your computer and use it in GitHub Desktop.
Python - MP4 / GIF to Telegram Video Sticker (VP9 Webm) Convertion Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import os | |
| import math | |
| import subprocess | |
| FFMPEG = r'D:\Tools\ffmpeg\bin\ffmpeg.exe' | |
| FFPROBE = r'D:\Tools\ffmpeg\bin\ffprobe.exe' | |
| save_to = 'webm' | |
| def ceil(num): | |
| return int(math.ceil(num)) | |
| def get_files(path='.'): | |
| files = [] | |
| for file in os.listdir(path): | |
| if os.path.isfile(file) and file.split('.')[-1] in ['gif', 'mp4']: | |
| files.append(os.path.join(path, file)) | |
| return files | |
| def get_media_info(file): | |
| info = {} | |
| command = [FFPROBE, '-hide_banner', '-loglevel', 'error', '-show_streams', file] | |
| print(' '.join(command)) | |
| info_raw = subprocess.run( | |
| command, | |
| stdout=subprocess.PIPE, | |
| text=True | |
| ) | |
| for item in info_raw.stdout.splitlines(): | |
| if item.count('=') == 1: | |
| info[item.split('=')[0]] = item.split('=')[1] | |
| elif item == '[/STREAM]': | |
| break | |
| return info | |
| def convert(file, slim=False): | |
| info = get_media_info(file) | |
| temp_file = '' | |
| # duration | |
| # if float(info['duration']) > 3.0: | |
| # command.extend('-t 3'.split()) | |
| too_long = False | |
| nb_frames = int(info['nb_frames']) | |
| if float(info['duration']) > 3.0: | |
| too_long = True | |
| print(f'{file} too long:', info['duration']) | |
| r = ceil(nb_frames / 3) | |
| # temp_file = '.'.join(file.split('.')[:-1]) + '_temp' + '.mp4' | |
| command = [FFMPEG, '-hide_banner', '-loglevel', 'error', '-r', str(r), '-i', file] | |
| # print(' ' + ' '.join(command)) | |
| # subprocess.run(command, stdout=subprocess.DEVNULL) | |
| # file = temp_file | |
| # info['r_frame_rate'] = str(r) | |
| # info = get_media_info(file) | |
| else: | |
| command = [FFMPEG, '-hide_banner', '-loglevel', 'error', '-i', file] | |
| # map | |
| command.extend('-map 0:0'.split()) | |
| # codec | |
| command.extend('-c:v libvpx-vp9'.split()) | |
| # slim | |
| ''' | |
| 3 seconds * 680 Kbps | |
| = 3 seconds * 85KB/s | |
| = 255KB | |
| ''' | |
| if slim != False: | |
| if too_long: | |
| d = nb_frames / ceil(nb_frames / 3) | |
| else: | |
| d = float(info['duration']) | |
| br = int(255*(8-slim)/d) | |
| command.extend(f'-b:v {br}k'.split()) | |
| # video filter | |
| filters = [] | |
| # resolution | |
| # w = int(info['width']) | |
| # h = int(info['height']) | |
| # if w >= h: | |
| # filters.append('scale=512:-1') | |
| # else: | |
| # filters.append('scale=-1:512') | |
| filters.append('scale=w=512:h=512:force_original_aspect_ratio=decrease') | |
| # fps | |
| if too_long: | |
| if r > 30: | |
| filters.append('fps=30') | |
| elif eval(info['r_frame_rate']) > 30.0: | |
| filters.append('fps=30') | |
| # duration | |
| if not too_long and float(info['duration']) > 3.0: | |
| command.extend('-t 3'.split()) | |
| filters_str = ', '.join(filters) | |
| command.extend(['-vf', filters_str]) | |
| # no audio | |
| command.append('-an') | |
| # output | |
| command.append(os.path.join(save_to, file.replace(file.split('.')[-1], 'webm').replace('_temp', ''))) | |
| print(' '.join(command)) | |
| subprocess.run(command, stdout=subprocess.DEVNULL) | |
| if temp_file: | |
| os.remove(temp_file) | |
| return True | |
| def slim(index=0): | |
| webm_files = os.listdir(save_to) | |
| need = 0 | |
| for i in webm_files: | |
| if os.stat(os.path.join(save_to, i)).st_size > 256*1024: | |
| need += 1 | |
| os.remove(os.path.join(save_to, i)) | |
| try: | |
| convert(i.replace('webm', 'mp4'), index) | |
| except: | |
| convert(i.replace('webm', 'gif'), index) | |
| return need | |
| if __name__ == '__main__': | |
| if not os.path.isdir(save_to): | |
| os.mkdir(save_to) | |
| files = get_files() | |
| if not files: | |
| exit(0) | |
| for file in files: | |
| if not os.path.isfile(os.path.join(save_to, file.replace(file.split('.')[-1], 'webm'))): | |
| print(file) | |
| convert(file) | |
| print('Slimming...') | |
| index = 0 | |
| while slim(index): | |
| index += 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment