import os import subprocess import shutil import platform segment = ' -init_seg_name chunks/init-stream$RepresentationID$.m4s -media_seg_name chunks/chunk-stream$RepresentationID$-$Number%05d$.m4s' if platform.system() == 'Linux': segment = ' -init_seg_name chunks/init-stream\$RepresentationID\$.m4s -media_seg_name chunks/chunk-stream\$RepresentationID\$-\$Number%05d\$.m4s' def changeM4SToHTML(mpdpath, chunkspath): for filename in os.listdir(chunkspath): infilename = os.path.join(chunkspath, filename) if not os.path.isfile(infilename): continue newname = infilename.replace('.m4s', '.webp') _ = os.rename(infilename, newname) # Modify manifest with open(mpdpath, 'r') as file : filedata = file.read() # Replace the target string filedata = filedata.replace('.m4s', '.webp') # Write the file out again with open(mpdpath, 'w') as file: file.write(filedata) def createFolder(cdnFolder, resolution): if platform.system() == 'Linux': if not os.path.exists(os.path.join(cdnFolder, resolution, 'chunks')): os.makedirs(os.path.join(cdnFolder, resolution, 'chunks')) else: if not os.path.exists('chunks'): os.makedirs('chunks') if not os.path.exists(os.path.join(cdnFolder, resolution)): os.makedirs(os.path.join(cdnFolder, resolution)) def create_sprites(cdn_folder): """ Creates video player sprites """ video_file = os.path.join(cdn_folder, 'x264.720p.mp4') # Generating Sprites if not os.path.exists(os.path.join(cdn_folder, 'thumbs.vtt')) and os.path.exists(video_file): os.system(f'python makesprites.py "{video_file}"') os.rename("thumbs.vtt", os.path.join(cdn_folder, 'thumbs.vtt')) os.rename("sprite.jpg", os.path.join(cdn_folder, 'sprite.jpg')) shutil.rmtree('thumbs') shutil.rmtree('logs') return print('Skipped Sprites') def encode_720p_fallback(cdn_folder, video_source, upscale_output, aspect_ratio): """ Fallback video stream for apple devices """ output = os.path.join(cdn_folder, 'x264.720p.mp4') if os.path.exists(output): print('Skipped 720p Encode') return command = ( f'ffmpeg -v quiet -stats -i "{upscale_output}" -i "{video_source}" ' '-map 0:v:0 -map 1:a:0 ' '-c:v libx264 -crf 22 -pix_fmt yuv420p ' f'-vf scale=1280:720,setsar=1:1 -aspect {aspect_ratio} ' '-c:a aac -b:a 128k ' f'-sn -map_metadata -1 -movflags +faststart "{output}"' ) subprocess.call(command, shell=True) def encode_720p(cdn_folder, video_source, upscale_output, aspect_ratio): output = os.path.join(cdn_folder, '720', 'manifest.mpd') if os.path.exists(output): print('Skipped 720p DASH Encode') return print('Encoding 720p') createFolder(cdn_folder, '720') command = ( f'ffmpeg -v quiet -stats -i "{upscale_output}" -i "{video_source}" ' '-map 0:v:0 -map 1:a:0 ' '-c:v libx264 -crf 22 -preset medium -pix_fmt yuv420p -g 24 -keyint_min 24 -sc_threshold 0 -x264-params keyint=24:min-keyint=24:scenecut=0 ' f'-vf scale=1280:720,setsar=1:1 -aspect {aspect_ratio} ' f'{segment} "{output}"' ) subprocess.call(command, shell=True) if platform.system() != 'Linux': shutil.move('chunks', os.path.join(cdn_folder, '720', 'chunks')) changeM4SToHTML(output, os.path.join(cdn_folder, '720', 'chunks')) def EncodeCDN(f, cdnFolder, inputAspect, upscaleOut, interpolateOut, INTERPOLATE_4K, interpolate_4k_output): out1080mpd = os.path.join(cdnFolder, '1080', 'manifest.mpd') out1080mpd48 = os.path.join(cdnFolder, '1080i', 'manifest.mpd') out2160mpd = os.path.join(cdnFolder, '2160', 'manifest.mpd') out2160mpd48 = os.path.join(cdnFolder, '2160i', 'manifest.mpd') # 720p encode_720p(cdnFolder, f, upscaleOut, inputAspect) encode_720p_fallback(cdnFolder, f, upscaleOut, inputAspect) create_sprites(cdnFolder) # 1080p if not os.path.exists(out1080mpd): print('Encoding 1080p') createFolder(cdnFolder, '1080') subprocess.call('ffmpeg -v quiet -stats -i "' + upscaleOut + '" -i "' + f + '" -map 0:v:0 -map 1:a:0' + ' -c:v libsvtav1 -preset 6 -crf 26 -pix_fmt yuv420p -svtav1-params keyint=1s:tune=0 -vf scale=1920:1080,setsar=1:1 -aspect ' + inputAspect + ' -c:a aac -b:a 128k -ac 2 -sn -map_metadata -1 -seg_duration 10 -use_template 1 -use_timeline 1' + segment + ' "' + out1080mpd + '"', shell=True) if platform.system() != 'Linux': shutil.move('chunks', os.path.join(cdnFolder, '1080', 'chunks')) changeM4SToHTML(out1080mpd, os.path.join(cdnFolder, '1080', 'chunks')) else: print('Skipped 1080p Encode') # 1080p 48fps if not os.path.exists(out1080mpd48): print('Encoding 1080p 48fps') createFolder(cdnFolder, '1080i') # DASH av1 1080p subprocess.call('ffmpeg -v quiet -stats -i "' + interpolateOut + '" -i "' + f + '" -map 0:v:0 -map 1:a:0' + ' -c:v libsvtav1 -preset 6 -crf 26 -pix_fmt yuv420p -svtav1-params keyint=1s:tune=0 -vf scale=1920:1080,setsar=1:1 -aspect ' + inputAspect + ' -c:a aac -b:a 128k -ac 2 -sn -map_metadata -1 -seg_duration 10 -use_template 1 -use_timeline 1' + segment + ' "' + out1080mpd48 + '"', shell=True) if platform.system() != 'Linux': shutil.move('chunks', os.path.join(cdnFolder, '1080i', 'chunks')) changeM4SToHTML(out1080mpd48, os.path.join(cdnFolder, '1080i', 'chunks')) else: print('Skipped 1080p 48fps Encode') # 2160p if not os.path.exists(out2160mpd): print('Encoding 2160p') createFolder(cdnFolder, '2160') subprocess.call('ffmpeg -v quiet -stats -i "' + upscaleOut + '" -i "' + f + '" -map 0:v:0 -map 1:a:0' + ' -c:v libsvtav1 -preset 6 -crf 26 -pix_fmt yuv420p -svtav1-params keyint=1s:tune=0 -vf "scale=\'min(3840,iw)\':-2,setsar=1:1" -aspect ' + inputAspect + ' -c:a aac -b:a 128k -ac 2 -sn -map_metadata -1 -seg_duration 10 -use_template 1 -use_timeline 1' + segment + ' "' + out2160mpd + '"', shell=True) if platform.system() != 'Linux': shutil.move('chunks', os.path.join(cdnFolder, '2160', 'chunks')) changeM4SToHTML(out2160mpd, os.path.join(cdnFolder, '2160', 'chunks')) else: print('Skipped 2160p Encode') # 2160p 48fps if not os.path.exists(out2160mpd48) and INTERPOLATE_4K: print('Encoding 2160p 48fps') createFolder(cdnFolder, '2160i') subprocess.call('ffmpeg -v quiet -stats -i "' + interpolate_4k_output + '" -i "' + f + '" -map 0:v:0 -map 1:a:0' + ' -c:v libsvtav1 -preset 6 -crf 26 -pix_fmt yuv420p -svtav1-params keyint=1s:tune=0 -vf "scale=\'min(3840,iw)\':-2,setsar=1:1" -aspect ' + inputAspect + ' -c:a aac -b:a 128k -ac 2 -sn -map_metadata -1 -seg_duration 10 -use_template 1 -use_timeline 1' + segment + ' "' + out2160mpd48 + '"', shell=True) if platform.system() != 'Linux': shutil.move('chunks', os.path.join(cdnFolder, '2160i', 'chunks')) changeM4SToHTML(out2160mpd48, os.path.join(cdnFolder, '2160i', 'chunks')) else: print('Skipped 2160p 48fps Encode')