def process(self, dc, astr=''): set_title = self.set_title2 input_list = dc["list"] output_dir = dc["output_dir"] + os.sep utils.make_dir(output_dir) temp_dir = output_dir + 'tempDir' + os.sep utils.make_dir(temp_dir) utils.hide_file(temp_dir) keep_parent_select = dc["keep_parent_select"] final_png = "" total = len(input_list) count = 0 msg_str = " {0}/{1} {2}" for i in range(total): count = count + 1 input_file = input_list[i] p = Path(input_file) # 保留上层目录结构 # 排除根目录 path_root = "{0}{1}".format(p.drive, os.sep) path_parent = str(Path(p.parent).name) if keep_parent_select and not path_root == path_parent: output_sub_dir = "{0}{1}{2}".format(output_dir, path_parent, os.sep) utils.make_dir(output_sub_dir) output_file = "{0}{1}{2}".format(output_sub_dir, p.stem, ".jpg") else: output_file = "{0}{1}{2}".format(output_dir, p.stem, ".jpg") # 任务信息 mstr = msg_str.format(count, total, p.name) set_title(mstr) # 拼接 ffmpeg 参数 arr = [ "ffmpeg -y -i", '"{}"'.format(input_file), '-hide_banner', '"{}"'.format(output_file) ] ff.execute(" ".join(arr)) final_png = output_file set_title("操作结束!") # 自动打开目录 if final_png: utils.open_dir(output_dir) self.t1 = "" self.lock_btn(False)
def processConcat(self, dc, astr=''): setTitle = self.setTitle2 list1 = dc["list1"] list2 = dc["list2"] fast_mode_select = dc["fast_mode_select"] outputDir = dc["output_dir"] + os.sep tempDir = outputDir + 'tempDir' + os.sep # 保持长度一致 minLen = min(len(list1), len(list2)) list1 = list1[0:minLen] list2 = list2[0:minLen] finalMP4 = "" pStr = "" # set param=-c:v libx264 -s 1920x1080 -r 24 -b:v 6144k -b:a 128k -ar 44100 -ac 2 -preset slower -threads 8 FFStr = '''ffmpeg -y -i "{input}" -c:v libx264 -s {v_size} -crf 18 -r {fps} -b:a 128k -ar 44100 -ac 2 -threads 8 "{output}"''' FFConcat = '''ffmpeg -y -f concat -safe 0 -i "{0}" -c copy "{1}"''' seq = ('input', 'output', 'v_size', 'fps') utils.make_dir(tempDir) utils.hide_file(tempDir) total = len(list1) count = 0 msgStr = " ({0}/{1}) {2}" print(list1) status = [] for i in range(len(list1)): count = count + 1 status.append('') fileA = list1[i] fileB = list2[i] arr = utils.get_file_names(fileA) fnameA = arr[1] # ftypeA = arr[2] ftempA = tempDir + "-" + fnameA + ".mp4" arr = utils.get_file_names(fileB) fnameB = arr[1] # ftypeB = arr[2] ftempB = tempDir + "-" + fnameB + ".mp4" fullName = fnameA + '__' + fnameB finalMP4 = outputDir + fullName + ".mp4" subTxt = tempDir + "concat_" + fullName + ".txt" # 任务信息 mstr = msgStr.format(count, total, fullName) setTitle(mstr) # 读取第一个视频的 尺寸和帧频作为基准 # !!!所有的视频都会进行一次转码 dc = dict.fromkeys(seq, "") dcinfo = ff.get_video_info(fileA, False) dc['fps'] = dcinfo['fps'] if dcinfo['fps'] else '24' dc['v_size'] = dcinfo['v_size'] if dcinfo['v_size'] else '1920x1080' # 检查视频参数是否相同 isSame = False if fast_mode_select: isSame = ff.compare_video(fileA, fileB) # 生成concat.txt, 并转换片头/片尾 subs = [] sub = "file '{0}'\n" if not isSame: # 转第一个视频 mstr = msgStr.format(count, total, "转换 第一个视频……") setTitle(mstr) status[i] = '10%' self.updateCenter(status) dc['input'] = fileA dc['output'] = ftempA pStr = FFStr.format(**dc) ff.execute(pStr) # 转第二个视频 mstr = msgStr.format(count, total, "转换 第二个视频……") setTitle(mstr) status[i] = '50%' self.updateCenter(status) dc['input'] = fileB dc['output'] = ftempB pStr = FFStr.format(**dc) ff.execute(pStr) subs.append(sub.format(ftempA)) subs.append(sub.format(ftempB)) else: mstr = msgStr.format(count, total, "参数相同,跳过转换,直接拼接!") setTitle(mstr) subs.append(sub.format(fileA)) subs.append(sub.format(fileB)) # 写入concat文件 utils.write_txt(subTxt, subs) # 拼接视频 mstr = msgStr.format(count, total, "拼接中……") setTitle(mstr) status[i] = '90%' self.updateCenter(status) pStr = FFConcat.format(subTxt, finalMP4) ff.execute(pStr) # print(pStr) sstr = '成功' if os.path.exists(finalMP4) else '失败' status[i] = sstr self.updateCenter(status) # 移除 concat.txt 和 mp4 utils.remove_file(subTxt) utils.remove_file(ftempA) utils.remove_file(ftempB) setTitle("操作结束!") setTitle("") # 自动打开目录 if finalMP4: utils.open_dir(outputDir) self.t1 = "" self.lockBtn(False)
def encode_china_mobile_ts(self, input_file, output_dir, tune_str='animation', png_select=False, png_path='', size='1920x1080', t=15, keep_ratio=False, double_fix_select=False): format_str = 'ffmpeg -hide_banner -y -i "{in_file}" {param} "{out_ts}"' param = "-c:v libx264 " \ "-b:v 3.8m " \ "-minrate 2.5m " \ "-maxrate 4m " \ "-profile:v high -level 4.1 " \ "-s 1280x720 " \ "-r 25 " \ "-coder cabac " \ "-refs:v 3 " \ "-x264opts b-pyramid=0 " \ "-c:a aac " \ "-profile:a aac_low " \ "-b:a 128k " \ "-ar 48000 " \ "-ac 2 " \ "-map_metadata -1 " \ "-preset slower" # 创建输出目录 p = Path(input_file) # save_dir = output_dir + str(p.stem) # save_dir += os.sep # utils.remove_file(save_dir, False) # utils.make_dir(save_dir) # 双倍时长修正 if double_fix_select: tdc = ff.get_video_info(input_file, False) # 匹配 尺寸和fps duration = tdc['duration'] if tdc["duration"] else '0' duration = float(duration) if duration: ss = duration if isinstance(ss, int) or isinstance(ss, float): ss = ss * 1000 ss = int(ss) ss = ff.millisecond_to_str(ss) param += ' -to {}'.format(ss) set_title = self.start_btn.update_query duration_string = ff.millisecond_to_str( int(duration * 1000)) set_title("*[双倍时长修正]该视频时长:" + duration_string) # 输出文件名 save_dir = output_dir + "移动/" ts_file = save_dir + p.stem + ".ts" utils.make_dir(save_dir) if keep_ratio: w = 1280 h = 720 # 获取当前视频的分辨率和缩放比 v_dc = ff.get_video_info(input_file) v_size = v_dc['v_size'] v_arr = v_size.split("x") vw = int(v_arr[0]) vh = int(v_arr[1]) scale = min(w / vw, h / vh) w_real = round(vw * scale) h_real = round(vh * scale) x = round((w - w_real) / 2) y = round((h - h_real) / 2) con_vf = 'scale={w_real}:{h_real},pad={w}:{h}:{x}:{y}:black' con_vf = con_vf.format(w=w, h=h, x=x, y=y, w_real=w_real, h_real=h_real) else: con_vf = '' # 拼接参数 param_final = '{param} -tune {tune}'.format(param=param, tune=tune_str) # 添加水印参数 水印图片作为输入管道 需参数之前 pngs = ['/Users/qinbaomac-mini/Library/Mobile # Documents/com~apple~CloudDocs/Dev/python/py_pack/res/备案号-爱奇艺.png'] sizes = ["1920x1080"] times = [15] if png_select: if os.path.exists(png_path): param_final = ' -i "{0}" {1}'.format(png_path, param_final) param_overlay = ff.get_overlay([png_path], [size], [t], [], True) if con_vf: param_overlay = param_overlay.replace( '-filter_complex "', '-filter_complex "' + con_vf + ',') con_vf = '' param_final = '{0} {1} '.format(param_final, param_overlay) else: if png_path: print('水印图片地址不正确 "{}"'.format(png_path)) # 黑边视频参数 if con_vf: con_vf = '-filter_complex "{}"'.format(con_vf) param_final = '{0} {1} '.format(param_final, con_vf) final_str = format_str.format(in_file=input_file, param=param_final, out_ts=ts_file) print(final_str) ff.execute(final_str) return ts_file
def process(self, dc, a_str=''): set_title = self.start.update_query input_list = dc["list"] output_dir = dc["output_dir"] + os.sep temp_dir = output_dir + 'tempDir' + os.sep utils.make_dir(temp_dir) utils.hide_file(temp_dir) s2bool = utils.str_to_bool keep_parent_select = s2bool(dc["keep_parent_select"]) keep_meta_select = s2bool(dc["keep_meta_select"]) # format1_select = s2bool(dc["format1_select"]) format2_select = s2bool(dc["format2_select"]) format3_select = s2bool(dc["format3_select"]) pt_select = dc["pt_select"] pw_select = dc["pw_select"] pt_second = dc["pt_second"] / 1000 pw_second = dc["pw_second"] / 1000 need_remain = dc["need_remain"] if format2_select: ext = ".m4a" param_a = "" elif format3_select: ext = ".wav" param_a = "" else: ext = ".mp3" param_a = " -acodec libmp3lame -ac 2 -ar 44100 -b:a 128k" final_mp4 = "" total = len(input_list) count = 0 msg_str = " {0}/{1} {2}" for i in range(total): count = count + 1 input_file = input_list[i] p = Path(input_file) # 保留上层目录结构 # 排除根目录 path_root = "{0}{1}".format(p.drive, os.sep) path_parent = str(Path(p.parent).name) if keep_parent_select and not path_root == path_parent: output_sub_dir = "{0}{1}{2}".format(output_dir, path_parent, os.sep) utils.make_dir(output_sub_dir) output_file = "{0}{1}{2}".format(output_sub_dir, p.stem, ext) else: output_file = "{0}{1}{2}".format(output_dir, p.stem, ext) # 任务信息 set_title(msg_str.format(count, total, p.name)) # 读取视频参数 tdc = ff.get_video_info(input_file, False) # v_size = tdc["v_size"] if tdc["v_size"] else "1920x1080" # fps = tdc["fps"] if tdc["fps"] else "24" # tdc["fps"] = fps duration = float(tdc['duration']) if tdc["duration"] else 0 duration = float(duration) second = duration if not duration: set_title('读取视频参数失败,不处理该视频') continue need_execute = False time_start = 0 time_to = 0 if pt_select and pt_second != 0: if pt_second < second: time_start = pt_second need_execute = True else: set_title('片头时长超过视频时长,不进行片头修剪!!!') if pw_select and pw_second != 0: if need_remain: time_to = second - pw_second else: time_to = pw_second if time_to > time_start: need_execute = True else: time_to = 0 set_title('片尾时长在起始时间之前,不进行片尾修剪!!!') if need_execute: set_title('正在转换 修剪部分……') if time_start != 0: ss = ' -ss {}'.format(time_start) else: ss = '' if time_to != 0: to = ' -to {}'.format(time_to) else: to = '' # 拼接 ffmpeg 参数 if keep_meta_select: param = 'ffmpeg -y -i "{in_file}"{param_a}{ss}{to} ' \ '-vn -hide_banner "{out_file}"' else: param = 'ffmpeg -y -i "{in_file}"{param_a}{ss}{to} -map_metadata -1 ' \ '-vn -hide_banner "{out_file}"' param = param.format(in_file=input_file, out_file=output_file, param_a=param_a, ss=ss, to=to) ff.execute(param) final_mp4 = output_file set_title("操作结束!") # 自动打开目录 if final_mp4: utils.open_dir(output_dir) self.t1 = "" self.lock_btn(False)
def encode_m3u8(input_file, output_dir, is_640=False, tune_str='animation'): s = 'ffmpeg -hide_banner -re -y -i "{in_file}" {param} "{out_ts}" "{out_m3u8}"' param_640 = "-c:v libx264 " \ "-s 640x360 " \ "-crf 28 " \ "-r 15 " \ "-g 60 " \ "-b:a 96k " \ "-ar 44100 " \ "-ac 2 " \ "-preset slower " \ "-threads 8" param_1280 = "-c:v libx264 " \ "-s 1280x720 " \ "-crf 26 " \ "-r 24 " \ "-g 48 " \ "-b:a 128k " \ "-ar 44100 " \ "-ac 2 " \ "-preset slower " \ "-threads 8" # param_hls = "-map 0 -f hls -hls_time 10 -hls_list_size 0 -use_localtime_mkdir 1 -hls_segment_filename" param_segment = '-map 0 ' \ '-f hls ' \ '-bsf:v h264_mp4toannexb ' \ '-hls_time 10 ' \ '-hls_flags split_by_time ' \ '-hls_list_size 0 ' \ '-hls_allow_cache 1 ' \ '-hls_segment_filename' # 创建输出目录 p = Path(input_file) save_dir = output_dir + str(p.stem) save_dir += '_640' if is_640 else '_1280' save_dir += '_m3u8' + os.sep utils.remove_file(save_dir, False) utils.make_dir(save_dir) # 输出文件名 m3u8_file = save_dir + 'playlist.m3u8' ts_file = save_dir + '%06d.ts' # 拼接参数 param_video = param_640 if is_640 else param_1280 param_final = '{param_video} -tune {tune} {param_segment}' param_final = param_final.format(param_video=param_video, tune=tune_str, param_segment=param_segment) s = s.format(in_file=input_file, param=param_final, out_m3u8=m3u8_file, out_ts=ts_file) ff.execute(s) return save_dir