-
Notifications
You must be signed in to change notification settings - Fork 282
/
QuickCut.py
7628 lines (6605 loc) · 387 KB
/
QuickCut.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# -*- coding: UTF-8 -*-
import datetime
from functools import wraps
import json
import math
import os
import re
import sqlite3
import srt
import subprocess
import sys
import time
from traceback import format_exception
import urllib.parse
import webbrowser
import pyaudio
import keyboard
import threading
import platform
import signal
import auditok
import pymediainfo
import io
from shutil import rmtree, move
try:
os.chdir(os.path.dirname(__file__))
except:
print('更改工作目录失败,关系不大,不用管它')
import numpy as np
import oss2
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtSql import *
from PyQt5.QtWidgets import *
import requests
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
import ali_speech
from ali_speech.callbacks import SpeechRecognizerCallback
from ali_speech.constant import ASRFormat
from ali_speech.constant import ASRSampleRate
from audiotsm import phasevocoder
from audiotsm.io.wav import WavReader, WavWriter
from qcloud_cos import CosConfig
from qcloud_cos import CosS3Client
from scipy.io import wavfile
from tencentcloud.asr.v20190614 import asr_client, models
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
# from PyQt5.QtWidgets import QListWidget, QWidget, QApplication, QFileDialog, QMainWindow, QDialog, QLabel, QLineEdit, QTextEdit, QPlainTextEdit, QTabWidget, QVBoxLayout, QHBoxLayout, QFormLayout, QGridLayout, QPushButton, QCheckBox, QSplitter
# from PyQt5.QtGui import QCloseEvent
# from PyQt5.QtCore import Qt
# print('开始运行')
dbname = './database.db' # 存储预设的数据库名字
presetTableName = 'commandPreset' # 存储预设的表单名字
ossTableName = 'oss'
apiTableName = 'api'
preferenceTableName = 'preference'
styleFile = './style.css' # 样式表的路径
finalCommand = ''
version = 'V1.6.10'
############# 主窗口和托盘 ################
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self._update_checker = None
self.initGui()
self.loadStyleSheet()
self.status = self.statusBar()
self._start_checker()
# self.setWindowState(Qt.WindowMaximized)
# sys.stdout = Stream(newText=self.onUpdateText)
def initGui(self):
# 定义中心控件为多 tab 页面
self.tabs = QTabWidget()
self.setCentralWidget(self.tabs)
# 定义多个不同功能的 tab
self.ffmpegMainTab = FFmpegMainTab() # 主要功能的 tab
self.ffmpegSplitVideoTab = FFmpegSplitVideoTab() # 分割视频 tab
# self.ffmpegCutVideoTab = FFmpegCutVideoTab() # 剪切视频的 tab
self.ffmpegConcatTab = FFmpegConcatTab() # 合并视频的 tab
# self.ffmpegBurnCaptionTab = FFmpegBurnCaptionTab() # 烧字幕的 tab
self.downloadVidwoTab = DownLoadVideoTab() # 下载视频的 tab
self.ConfigTab = ConfigTab() # 配置 Api 的 tab 这个要放在前面儿初始化, 因为他要创建数据库
self.ffmpegAutoEditTab = FFmpegAutoEditTab() # 自动剪辑的 tab
self.ffmpegAutoSrtTab = FFmpegAutoSrtTab() # 自动转字幕的 tab
self.capsWriterTab = CapsWriterTab()
# 创建一个可以发送信号的对象,用于告知其他界面 api列表已经更新
# self.consoleTab = ConsoleTab() # 新的控制台输出 tab
self.helpTab = HelpTab() # 帮助
# self.aboutTab = AboutTab() # 关于
# 将不同功能的 tab 添加到主 tabWidget
self.tabs.addTab(self.ffmpegMainTab, self.tr('FFmpeg'))
self.tabs.addTab(self.ffmpegSplitVideoTab, self.tr('分割视频'))
# self.tabs.addTab(self.ffmpegCutVideoTab, '截取片段')
self.tabs.addTab(self.ffmpegConcatTab, self.tr('合并片段'))
# self.downloadTabScroll = QScrollArea()
# self.downloadTabScroll.setWidget(self.downloadVidwoTab)
# self.downloadVidwoTab.setObjectName('widget')
# self.downloadVidwoTab.setStyleSheet("QWidget#widget{background-color:transparent;}")
# self.downloadTabScroll.setStyleSheet("QScrollArea{background-color:transparent;}")
# self.tabs.addTab(self.downloadTabScroll, '下载视频')
self.tabs.addTab(self.downloadVidwoTab, self.tr('下载视频'))
# self.tabs.addTab(self.ffmpegBurnCaptionTab, '嵌入字幕')
self.tabs.addTab(self.ffmpegAutoEditTab, self.tr('自动剪辑'))
self.tabs.addTab(self.ffmpegAutoSrtTab, self.tr('自动字幕'))
self.tabs.addTab(self.capsWriterTab, self.tr('语音输入'))
self.tabs.addTab(self.ConfigTab, self.tr('设置'))
# self.tabs.addTab(self.consoleTab, '控制台')
self.tabs.addTab(self.helpTab, self.tr('帮助'))
# self.tabs.addTab(self.aboutTab, '关于')
self.adjustSize()
if platfm == 'Darwin':
self.setWindowIcon(QIcon('misc/icon.icns'))
else:
self.setWindowIcon(QIcon('misc/icon.ico'))
self.setWindowTitle('Quick Cut')
# self.setWindowFlag(Qt.WindowStaysOnTopHint) # 始终在前台
self.show()
def loadStyleSheet(self):
global styleFile
try:
try:
with open(styleFile, 'r', encoding='utf-8') as style:
self.setStyleSheet(style.read())
except:
with open(styleFile, 'r', encoding='gbk') as style:
self.setStyleSheet(style.read())
except:
QMessageBox.warning(self, self.tr('主题载入错误'), self.tr('未能成功载入主题,请确保软件根目录有 "style.css" 文件存在。'))
def keyPressEvent(self, event) -> None:
# 在按下 F5 的时候重载 style.css 主题
if (event.key() == Qt.Key_F5):
self.loadStyleSheet()
self.status.showMessage('已成功更新主题', 800)
def onUpdateText(self, text):
"""Write console output to text widget."""
cursor = self.consoleTab.consoleEditBox.textCursor()
cursor.movePosition(QTextCursor.End)
cursor.insertText(text)
self.consoleTab.consoleEditBox.setTextCursor(cursor)
self.consoleTab.consoleEditBox.ensureCursorVisible()
def closeEvent(self, event):
"""Shuts down application on close."""
# Return stdout to defaults.
if mainWindow.ConfigTab.hideToSystemTraySwitch.isChecked():
event.ignore()
self.hide()
else:
sys.stdout = sys.__stdout__
super().closeEvent(event)
def _start_checker(self):
self._update_checker = UpdateChecker()
self._update_checker.check_for_update()
self._update_checker.update_dialog.setParent(self)
# Setting the dialog's parent resets its flags
# See https://forum.qt.io/topic/10477
self._update_checker.update_dialog.setWindowFlags(
Qt.WindowTitleHint | Qt.WindowCloseButtonHint | Qt.Dialog)
class SystemTray(QSystemTrayIcon):
def __init__(self, icon, window):
super(SystemTray, self).__init__()
self.window = window
self.setIcon(icon)
self.setParent(window)
self.activated.connect(self.trayEvent) # 设置托盘点击事件处理函数
self.tray_menu = QMenu(QApplication.desktop()) # 创建菜单
# self.RestoreAction = QAction(u'还原 ', self, triggered=self.showWindow) # 添加一级菜单动作选项(还原主窗口)
self.QuitAction = QAction(self.tr('退出'), self, triggered=self.quit) # 添加一级菜单动作选项(退出程序)
# self.StyleAction = QAction(self.tr('更新主题'), self, triggered=mainWindow.loadStyleSheet) # 添加一级菜单动作选项(更新 QSS)
# self.tray_menu.addAction(self.RestoreAction) # 为菜单添加动作
self.tray_menu.addAction(self.QuitAction)
# self.tray_menu.addAction(self.StyleAction)
self.setContextMenu(self.tray_menu) # 设置系统托盘菜单
self.show()
def showWindow(self):
self.window.showNormal()
self.window.activateWindow()
self.window.setWindowFlags(Qt.Window)
self.window.show()
def quit(self):
sys.stdout = sys.__stdout__
self.hide()
qApp.quit()
def trayEvent(self, reason):
# 鼠标点击icon传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键,4是用鼠标中键点击
if reason == 2 or reason == 3:
if mainWindow.isMinimized() or not mainWindow.isVisible():
# 若是最小化或者最小化到托盘,则先正常显示窗口,再变为活动窗口(暂时显示在最前面)
self.window.showNormal()
self.window.activateWindow()
self.window.setWindowFlags(Qt.Window)
self.window.show()
else:
# 若不是最小化,则最小化
# self.window.showMinimized()
# self.window.show()
pass
############# 不同功能的 Tab ################
class FFmpegMainTab(QWidget):
def __init__(self):
super().__init__()
self.initGui()
self.initValue()
def initGui(self):
self.输入输出vbox = QVBoxLayout()
# 构造输入一、输入二和输出选项
if True:
# 输入1
if True:
self.输入1标签 = QLabel(self.tr('输入1路径:'))
self.输入1路径框 = MyQLine()
self.输入1路径框.setPlaceholderText(self.tr('这里输入要处理的视频、音频文件'))
self.输入1路径框.signal.connect(self.lineEditHasDrop)
self.输入1路径框.setToolTip(self.tr('这里输入要处理的视频、音频文件'))
self.输入1路径框.textChanged.connect(self.generateFinalCommand)
self.输入1选择文件按钮 = QPushButton(self.tr('选择文件'))
self.输入1选择文件按钮.clicked.connect(self.chooseFile1ButtonClicked)
self.输入1路径hbox = QHBoxLayout()
self.输入1路径hbox.addWidget(self.输入1标签, 0)
self.输入1路径hbox.addWidget(self.输入1路径框, 1)
self.输入1路径hbox.addWidget(self.输入1选择文件按钮, 0)
self.输入1截取时间hbox = QHBoxLayout()
self.输入1截取时间勾选框 = QCheckBox(self.tr('截取片段'))
self.输入1截取时间勾选框.clicked.connect(self.inputOneCutCheckboxClicked)
self.输入1截取时间勾选框.clicked.connect(self.generateFinalCommand)
self.输入1截取时间start标签 = QLabel(self.tr('起始时间:'))
self.输入1截取时间start输入框 = self.CutTimeEdit()
self.输入1截取时间start输入框.textChanged.connect(self.generateFinalCommand)
self.输入1截取时间start输入框.setAlignment(Qt.AlignCenter)
self.输入1截取时间end标签 = self.ClickableEndTimeLable()
# self.输入1截取时间end标签.mousePressEvent.connect(self.generateFinalCommand)
self.输入1截取时间end输入框 = self.CutTimeEdit()
self.输入1截取时间end输入框.textChanged.connect(self.generateFinalCommand)
self.输入1截取时间end输入框.setAlignment(Qt.AlignCenter)
self.输入1截取时间hbox.addWidget(self.输入1截取时间勾选框)
self.输入1截取时间hbox.addWidget(self.输入1截取时间start标签)
self.输入1截取时间hbox.addWidget(self.输入1截取时间start输入框)
self.输入1截取时间hbox.addWidget(self.输入1截取时间end标签)
self.输入1截取时间hbox.addWidget(self.输入1截取时间end输入框)
self.输入1截取时间start标签.setVisible(False)
self.输入1截取时间start输入框.setVisible(False)
self.输入1截取时间end标签.setVisible(False)
self.输入1截取时间end输入框.setVisible(False)
self.输入1选项hbox = QHBoxLayout()
self.输入1选项标签 = QLabel(self.tr('输入1选项:'))
self.输入1选项输入框 = MyQLine()
self.输入1选项输入框.textChanged.connect(self.generateFinalCommand)
self.输入1选项hbox.addWidget(self.输入1选项标签)
self.输入1选项hbox.addWidget(self.输入1选项输入框)
self.输入1vbox = QVBoxLayout()
self.输入1vbox.addLayout(self.输入1路径hbox)
self.输入1vbox.addLayout(self.输入1选项hbox)
self.输入1vbox.addLayout(self.输入1截取时间hbox)
# 输入2
if True:
self.输入2标签 = QLabel(self.tr('输入2路径:'))
self.输入2路径框 = MyQLine()
self.输入2路径框.setPlaceholderText(self.tr('输入2是选填的,只有涉及同时处理两个文件的操作才需要输入2'))
self.输入2路径框.setToolTip(self.tr('输入2是选填的,只有涉及同时处理两个文件的操作才需要输入2'))
self.输入2路径框.textChanged.connect(self.generateFinalCommand)
self.输入2选择文件按钮 = QPushButton(self.tr('选择文件'))
self.输入2选择文件按钮.clicked.connect(self.chooseFile2ButtonClicked)
self.输入2路径hbox = QHBoxLayout()
self.输入2路径hbox.addWidget(self.输入2标签, 0)
self.输入2路径hbox.addWidget(self.输入2路径框, 1)
self.输入2路径hbox.addWidget(self.输入2选择文件按钮, 0)
self.输入2截取时间hbox = QHBoxLayout()
self.输入2截取时间勾选框 = QCheckBox(self.tr('截取片段'))
self.输入2截取时间勾选框.clicked.connect(self.inputTwoCutCheckboxClicked)
self.输入2截取时间勾选框.clicked.connect(self.generateFinalCommand)
self.输入2截取时间start标签 = QLabel(self.tr('起始时间:'))
self.输入2截取时间start输入框 = self.CutTimeEdit()
self.输入2截取时间start输入框.setAlignment(Qt.AlignCenter)
self.输入2截取时间start输入框.textChanged.connect(self.generateFinalCommand)
self.输入2截取时间end标签 = self.ClickableEndTimeLable()
self.输入2截取时间end输入框 = self.CutTimeEdit()
self.输入2截取时间end输入框.setAlignment(Qt.AlignCenter)
self.输入2截取时间end输入框.textChanged.connect(self.generateFinalCommand)
self.输入2截取时间hbox.addWidget(self.输入2截取时间勾选框)
self.输入2截取时间hbox.addWidget(self.输入2截取时间start标签)
self.输入2截取时间hbox.addWidget(self.输入2截取时间start输入框)
self.输入2截取时间hbox.addWidget(self.输入2截取时间end标签)
self.输入2截取时间hbox.addWidget(self.输入2截取时间end输入框)
self.输入2截取时间start标签.setVisible(False)
self.输入2截取时间start输入框.setVisible(False)
self.输入2截取时间end标签.setVisible(False)
self.输入2截取时间end输入框.setVisible(False)
self.输入2选项hbox = QHBoxLayout()
self.输入2选项标签 = QLabel(self.tr('输入2选项:'))
self.输入2选项输入框 = MyQLine()
self.输入2选项输入框.textChanged.connect(self.generateFinalCommand)
self.输入2选项hbox.addWidget(self.输入2选项标签)
self.输入2选项hbox.addWidget(self.输入2选项输入框)
self.输入2vbox = QVBoxLayout()
self.输入2vbox.addLayout(self.输入2路径hbox)
self.输入2vbox.addLayout(self.输入2选项hbox)
self.输入2vbox.addLayout(self.输入2截取时间hbox)
self.timeValidator = QRegExpValidator(self)
self.timeValidator.setRegExp(QRegExp(r'[0-9]{0,2}:?[0-9]{0,2}:?[0-9]{0,2}\.?[0-9]{0,2}'))
self.输入1截取时间start输入框.setValidator(self.timeValidator)
self.输入1截取时间end输入框.setValidator(self.timeValidator)
self.输入2截取时间start输入框.setValidator(self.timeValidator)
self.输入2截取时间end输入框.setValidator(self.timeValidator)
# 输出
if True:
self.输出标签 = QLabel(self.tr('输出:'))
self.输出路径框 = MyQLine()
self.输出路径框.setPlaceholderText(self.tr('文件名填什么后缀,就会输出什么格式'))
self.输出路径框.setToolTip(self.tr('这里填写输出文件保存路径'))
self.输出路径框.textChanged.connect(self.generateFinalCommand)
self.输出选择文件按钮 = QPushButton(self.tr('选择保存位置'))
self.输出选择文件按钮.clicked.connect(self.chooseOutputFileButtonClicked)
self.输出路径hbox = QHBoxLayout()
self.输出路径hbox.addWidget(self.输出标签, 0)
self.输出路径hbox.addWidget(self.输出路径框, 1)
self.输出路径hbox.addWidget(self.输出选择文件按钮, 0)
self.输出分辨率hbox = QHBoxLayout()
self.输出分辨率勾选框 = QCheckBox(self.tr('新分辨率'))
self.输出分辨率勾选框.clicked.connect(self.outputResolutionCheckboxClicked)
self.输出分辨率勾选框.clicked.connect(self.generateFinalCommand)
self.X轴分辨率输入框 = self.ResolutionEdit()
self.X轴分辨率输入框.setAlignment(Qt.AlignCenter)
self.X轴分辨率输入框.textChanged.connect(self.generateFinalCommand)
self.分辨率乘号标签 = self.ClickableResolutionTimesLable()
self.Y轴分辨率输入框 = self.ResolutionEdit()
self.Y轴分辨率输入框.setAlignment(Qt.AlignCenter)
self.Y轴分辨率输入框.textChanged.connect(self.generateFinalCommand)
self.分辨率预设按钮 = QPushButton(self.tr('分辨率预设'))
self.分辨率预设按钮.clicked.connect(self.resolutionPresetButtonClicked)
self.X轴分辨率输入框.setVisible(False)
self.分辨率乘号标签.setVisible(False)
self.Y轴分辨率输入框.setVisible(False)
self.分辨率预设按钮.setVisible(False)
self.输出分辨率hbox.addWidget(self.输出分辨率勾选框, 0)
self.输出分辨率hbox.addWidget(self.X轴分辨率输入框, 1)
self.输出分辨率hbox.addWidget(self.分辨率乘号标签, 0)
self.输出分辨率hbox.addWidget(self.Y轴分辨率输入框, 1)
self.输出分辨率hbox.addWidget(self.分辨率预设按钮, 0)
self.输出选项标签 = QLabel(self.tr('输出选项:'))
self.输出选项输入框 = QPlainTextEdit()
self.输出选项输入框.textChanged.connect(self.generateFinalCommand)
self.输出选项输入框.setMaximumHeight(100)
self.输出选项hbox = QHBoxLayout()
self.输出选项hbox.addWidget(self.输出选项标签)
self.输出选项hbox.addWidget(self.输出选项输入框)
self.输出vbox = QVBoxLayout()
self.输出vbox.addLayout(self.输出路径hbox)
self.输出vbox.addLayout(self.输出分辨率hbox)
self.输出vbox.addLayout(self.输出选项hbox)
# 输入输出放到一个布局
if True:
self.主布局 = QVBoxLayout()
self.主布局.addLayout(self.输入1vbox)
self.主布局.addSpacing(30)
self.主布局.addLayout(self.输入2vbox)
self.主布局.addSpacing(30)
self.主布局.addLayout(self.输出vbox)
# 输入输出布局放到一个控件
self.主布局控件 = QWidget()
self.主布局控件.setLayout(self.主布局)
# 预设列表
if True:
self.预设列表提示标签 = QLabel(self.tr('选择预设:'))
self.预设列表 = QListWidget()
self.预设列表.itemClicked.connect(self.presetItemSelected)
self.预设列表.itemDoubleClicked.connect(self.addPresetButtonClicked)
self.添加预设按钮 = QPushButton('+')
self.删除预设按钮 = QPushButton('-')
# self.修改预设按钮 = QPushButton('修改选中预设')
self.上移预设按钮 = QPushButton('↑')
self.下移预设按钮 = QPushButton('↓')
self.查看预设帮助按钮 = QPushButton(self.tr('查看该预设帮助'))
self.预设vbox = QGridLayout()
self.预设vbox.addWidget(self.预设列表提示标签, 0, 0, 1, 1)
self.预设vbox.addWidget(self.预设列表, 1, 0, 1, 2)
self.预设vbox.addWidget(self.上移预设按钮, 2, 0, 1, 1)
self.预设vbox.addWidget(self.下移预设按钮, 2, 1, 1, 1)
self.预设vbox.addWidget(self.添加预设按钮, 3, 0, 1, 1)
self.预设vbox.addWidget(self.删除预设按钮, 3, 1, 1, 1)
# self.预设vbox.addWidget(self.修改预设按钮, 3, 0, 1, 1)
self.预设vbox.addWidget(self.查看预设帮助按钮, 4, 0, 1, 2)
self.预设vbox控件 = QWidget()
self.预设vbox控件.setLayout(self.预设vbox)
self.上移预设按钮.clicked.connect(self.upwardButtonClicked)
self.下移预设按钮.clicked.connect(self.downwardButtonClicked)
self.添加预设按钮.clicked.connect(self.addPresetButtonClicked)
self.删除预设按钮.clicked.connect(self.delPresetButtonClicked)
# self.修改预设按钮.clicked.connect(self.modifyPresetButtonClicked)
self.查看预设帮助按钮.clicked.connect(self.checkPresetHelpButtonClicked)
# 总命令编辑框
if True:
self.总命令编辑框 = QPlainTextEdit()
self.总命令编辑框.setPlaceholderText(self.tr('这里是自动生成的总命令'))
self.总命令编辑框.setMaximumHeight(200)
self.总命令执行按钮 = QPushButton(self.tr('运行'))
self.总命令执行按钮.clicked.connect(self.runFinalCommandButtonClicked)
self.总命令部分vbox = QVBoxLayout()
self.总命令部分vbox.addWidget(self.总命令编辑框)
self.总命令部分vbox.addWidget(self.总命令执行按钮)
self.总命令部分vbox控件 = QWidget()
self.总命令部分vbox控件.setLayout(self.总命令部分vbox)
# 放置三个主要部件
if True:
# 分割线左边放输入输出布局,右边放列表
self.竖分割线 = QSplitter(Qt.Horizontal)
self.竖分割线.addWidget(self.主布局控件)
self.竖分割线.addWidget(self.预设vbox控件)
self.横分割线 = QSplitter(Qt.Vertical)
self.横分割线.addWidget(self.竖分割线)
self.横分割线.addWidget(self.总命令部分vbox控件)
# 用一个横向布局,将分割线放入
self.最顶层布局hbox = QHBoxLayout()
self.最顶层布局hbox.addWidget(self.横分割线)
# 将本页面的布局设为上面的横向布局
self.setLayout(self.最顶层布局hbox)
def initValue(self):
# 检查杂项文件夹是否存在
self.createMiscFolder()
# 检查数据库是否存在
self.createDB()
# 刷新预设列表
self.refreshList()
# 定义一个变量,用于判断输入文件,输出文件的选项是否有被手工修改过
self.commandOptionsChanged = False
# 如果输入文件是拖进去的
def lineEditHasDrop(self, path):
outputName = os.path.splitext(path)[0] + '_out' + os.path.splitext(path)[1]
self.输出路径框.setText(outputName)
return True
# 选择输入文件1
def chooseFile1ButtonClicked(self):
filename = QFileDialog().getOpenFileName(self, '打开文件', None, '所有文件(*)')
if filename[0] != '':
self.输入1路径框.setText(filename[0])
outputName = re.sub(r'(\.[^\.]+)$', r'_out\1', filename[0])
self.输出路径框.setText(outputName)
self.commandOptionsChanged = False
return True
# 选择输入文件2
def chooseFile2ButtonClicked(self):
filename = QFileDialog().getOpenFileName(self, '打开文件', None, '所有文件(*)')
if filename[0] != '':
self.输入2路径框.setText(filename[0])
self.commandOptionsChanged = False
return True
# 选择输出文件
def chooseOutputFileButtonClicked(self):
filename = QFileDialog().getSaveFileName(self, '设置输出保存的文件名', '输出视频.mp4', '所有文件(*)')
self.输出路径框.setText(filename[0])
self.commandOptionsChanged = False
return True
# 输出一截取勾选框
def inputOneCutCheckboxClicked(self):
if self.输入1截取时间勾选框.isChecked():
self.输入1截取时间start标签.setVisible(True)
self.输入1截取时间start输入框.setVisible(True)
self.输入1截取时间end标签.setVisible(True)
self.输入1截取时间end输入框.setVisible(True)
else:
self.输入1截取时间start标签.setVisible(False)
self.输入1截取时间start输入框.setVisible(False)
self.输入1截取时间end标签.setVisible(False)
self.输入1截取时间end输入框.setVisible(False)
return True
# 输出2截取勾选框
def inputTwoCutCheckboxClicked(self):
if self.输入2截取时间勾选框.isChecked():
self.输入2截取时间start标签.setVisible(True)
self.输入2截取时间start输入框.setVisible(True)
self.输入2截取时间end标签.setVisible(True)
self.输入2截取时间end输入框.setVisible(True)
else:
self.输入2截取时间start标签.setVisible(False)
self.输入2截取时间start输入框.setVisible(False)
self.输入2截取时间end标签.setVisible(False)
self.输入2截取时间end输入框.setVisible(False)
return True
# 输出分辨率勾选框
# 输出分辨率勾选框
def outputResolutionCheckboxClicked(self):
if self.输出分辨率勾选框.isChecked():
self.X轴分辨率输入框.setVisible(True)
self.分辨率乘号标签.setVisible(True)
self.Y轴分辨率输入框.setVisible(True)
self.分辨率预设按钮.setVisible(True)
else:
self.X轴分辨率输入框.setVisible(False)
self.分辨率乘号标签.setVisible(False)
self.Y轴分辨率输入框.setVisible(False)
self.分辨率预设按钮.setVisible(False)
return True
def resolutionPresetButtonClicked(self):
self.ResolutionDialog()
return True
# 自动生成总命令
def generateFinalCommand(self):
self.finalCommand = 'ffmpeg -y -hide_banner'
inputOnePath = self.输入1路径框.text()
if inputOnePath != '': # 只有有输入文件1时才会继续生成命令
self.commandOptionsChanged = True
inputOneCutSwitch = self.输入1截取时间勾选框.isChecked()
if inputOneCutSwitch != 0:
inputOneStartTime = self.输入1截取时间start输入框.text()
if inputOneStartTime != '':
self.finalCommand = self.finalCommand + ' ' + '-ss %s' % (inputOneStartTime)
inputOneEndTime = self.输入1截取时间end输入框.text()
if inputOneEndTime != '':
if self.输入1截取时间end标签.text() == '截取时长:':
self.finalCommand = self.finalCommand + ' ' + '-t %s' % (inputOneEndTime)
elif self.输入1截取时间end标签.text() == '截止时刻:':
self.finalCommand = self.finalCommand + ' ' + '-to %s' % (inputOneEndTime)
inputOneOption = self.输入1选项输入框.text()
if inputOneOption != '':
self.finalCommand = self.finalCommand + ' ' + inputOneOption
self.finalCommand = self.finalCommand + ' ' + '-i "%s"' % (inputOnePath)
inputTwoPath = self.输入2路径框.text()
if inputTwoPath != '': # 只有有输入文件2时才会继续生成命令
inputTwoCutSwitch = self.输入2截取时间勾选框.isChecked()
if inputTwoCutSwitch != 0:
inputTwoStartTime = self.输入2截取时间start输入框.text()
if inputTwoStartTime != '':
self.finalCommand = self.finalCommand + ' ' + '-ss %s' % (inputTwoStartTime)
inputTwoEndTime = self.输入2截取时间end输入框.text()
if inputTwoEndTime != '':
if self.输入2截取时间end标签.text() == '截取时长:':
self.finalCommand = self.finalCommand + ' ' + '-t %s' % (inputTwoEndTime)
elif self.输入2截取时间end标签.text() == '截止时刻:':
self.finalCommand = self.finalCommand + ' ' + '-to %s' % (inputTwoEndTime)
inputTwoOption = self.输入2选项输入框.text()
if inputTwoOption != '':
self.finalCommand = self.finalCommand + ' ' + inputTwoOption
self.finalCommand = self.finalCommand + ' ' + '-i "%s"' % (inputTwoPath)
outputOption = self.输出选项输入框.toPlainText()
if self.输出分辨率勾选框.isChecked() != 0:
outputResizeX = self.X轴分辨率输入框.text()
if outputResizeX == '':
outputResizeX = '-2'
outputResizeY = self.Y轴分辨率输入框.text()
if outputResizeY == '':
outputResizeY = '-2'
if '-vf' not in self.finalCommand and 'scale' not in outputOption and 'filter' not in outputOption:
# print(False)
self.finalCommand = self.finalCommand + ' ' + '-vf "scale=%s:%s"' % (outputResizeX, outputResizeY)
elif 'scale' in outputOption:
# print(True)
outputOption = re.sub('[-0-9]+:[-0-9]+', '%s:%s' % (outputResizeX, outputResizeY), outputOption)
if outputOption != '':
self.finalCommand = self.finalCommand + ' ' + outputOption
outputPath = self.输出路径框.text()
if outputPath != '':
self.finalCommand = self.finalCommand + ' ' + '"%s"' % (outputPath)
if self.预设列表.currentRow() > -1:
if self.extraCode != '' and self.extraCode != None:
try:
exec(self.extraCode)
except:
pass
self.总命令编辑框.setPlainText(self.finalCommand)
return True
# 点击运行按钮
def runFinalCommandButtonClicked(self):
finalCommand = self.总命令编辑框.toPlainText()
outputPath = self.输出路径框.text()
if os.path.exists(outputPath):
overwrite = QMessageBox.information(
self, self.tr('覆盖确认'), self.tr('输出路径对应的文件已存在,是否要覆盖?'),
QMessageBox.Yes | QMessageBox.Cancel, QMessageBox.Cancel)
if overwrite != QMessageBox.Yes:
return
if finalCommand != '':
execute(finalCommand)
# 检查杂项文件夹是否存在
def createMiscFolder(self):
if not os.path.exists('./misc'):
os.mkdir('./misc')
# 检查数据库是否存在
def createDB(self):
########改用主数据库
cursor = conn.cursor()
result = cursor.execute('select * from sqlite_master where name = "%s";' % (presetTableName))
# 将初始预设写入数据库
if result.fetchone() == None:
cursor.execute('''create table %s (
id integer primary key autoincrement,
name text,
inputOneOption TEXT,
inputTwoOption TEXT,
outputExt TEXT,
outputOption TEXT,
extraCode TEXT,
description TEXT
)''' % (presetTableName))
# print('新建了表单')
# 新建一个空预设
# 不使用预设
presetName = self.tr('不使用预设')
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'-c copy'
);'''
% (presetTableName, presetName))
# h264 压制
presetName = self.tr('H264压制')
description = '''<body><h4>H264压制视频</h4><p>输入文件一,模板中选择 Video ( h264 ) ,输出选项会自动设置好,点击 Run ,粘贴编码,等待压制完成即可。</p><p> </p><h4>选项帮助:</h4><h5>输出文件选项:</h5><p>-c:v 设置视频编码器</p><p>-crf 恒定视频质量的参数</p><p>-preset 压制速度,可选项:ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo</p><p>-qcomp 量化曲线压缩因子(Quantizer curve compression factor)</p><p>-psy-rd 用 psy-rd:psy-trellis 的格式设置 心理视觉优化强度( strength of psychovisual optimization, in psy-rd:psy-trellis format)</p><p>-aq-mode 设置 AQ 方法,可选值为:</p><ul><li>none (<em>0</em>) 帧内宏块全部使用同一或者固定的表</li><li>variance (<em>1</em>) 使用方差动态计算每个宏块的</li><li>autovariance (<em>2</em>) 方差自适应模式,会先遍历一次全部宏块,统计出一些中间参数,之后利用这些参数,对每个宏块计算 </li></ul><p>-aq-strength 设置 AQ 强度,在平面和纹理区域 减少 方块和模糊。</p><p> </p><p> </p><h4>注意事项</h4><p>注意,压制视频的话,输入文件放一个就行了哈,别放两个输入,FFmpeg 会自动把最高分辨率的视频流和声道数最多的音频流合并输出的。</p><p> </p><h4>相关科普</h4><p>压制过程中你可以从命令行看到实时压制速度、总码率、体积、压制到视频几分几秒了。</p><p>相关解释:H264是一个很成熟的视频编码格式,兼容性也很好,一般你所见到的视频多数都是这个编码,小白压制视频无脑选这个就行了。</p><p>这个参数下,画质和体积能得到较好的平衡,一般能把手机相机拍摄的视频压制到原来体积的1/3左右,甚至更小,画质也没有明显的损失。</p><p>控制视频大小有两种方法:</p><ul><li><p>恒定画面质量,可变码率。也就是 crf 方式</p></li><p>这时,编码器会根据你要求的画面质量,自动分配码率,给复杂的画面部分多分配点码率,给简单的画面少分配点码率,可以得到画面质量均一的输出视频,这是最推荐的压制方式。不过无法准确预测输出文件的大小。假如你的视频全程都是非常复杂、包含大量背景运动的画面,那么可能压制出来的视频,比原视频还要大。这里的压制方式用的就是 恒定画面质量 的方式。</p><li><p>恒定码率</p></li></ul><p>这时,编码器会根据你的要求,给每一秒都分配相同的码率,可以准确预测输出文件的大小。但是,由于码率恒定,可能有些复杂的片段,你分配的码率不够用,就会画质下降,有些静态部分多的画面,就浪费了很多码率,所以一般不推荐用。如果你想用这个方案,请参阅 <a href='#控制码率压制视频'>控制码率压制视频</a> </p><p>针对恒定码率的缺点,有个改进方案就是 2-pass (二压),详见 <a href='#h264 二压视频(两次操作)'>h264 二压视频(两次操作)</a> </p><p>此处输出选项里的 -crf 23 是画质控制参数。取值 0 - 51 ,越小画质越高,同时体积越大。 0 代表无损画质,体积超大。一般认为, -crf 18 的时候,人眼就几乎无法看出画质有损失了,大于 -crf 28 的时候,人眼就开始看到比较明显的画质损失。没有特殊要求的话,默认用 -crf 23 就行了。压制画质要求很高的视频就用 -crf 18 。</p><p>此处输出选项里的 -preset medium 代表压制编码速度适中,可选值有 ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow, placebo ,设置越慢,压制时间越长,画质控制越出色,设置越快,信息丢失就越严重,图像质量越差。</p><p>为什么 placebo 是纯粹的浪费时间? </p><p>相同码率下,相比于 veryslow,placebo 只提升不到 1% 的视频质量(同样码率下),但消耗非常多的时间。veryslow 比 slower 提升 3% ; slower 比 slow 提升 5% ,slow 比 medium 提升 5%-10% 。</p><p>相同码率下,相较于 medium:slow 编码所需时间增加大约 40% ;到 slower 增加大约 100% ,到 veryslow 增加大约 280% 。</p><p>相同码率下,相较于 medium : fast 节约 10% 编码时间; faster 节约 25% ; ultrafast 节约 55%(但代价是更低的画质)</p><p>如果你的原视频是 rgb 像素格式的,建议使用 -c:v libx264rgb ,来避免转化成 yuv420 时的画质损失。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
'%s',
'-c:v libx264 -crf 23 -preset slow -qcomp 0.5 -psy-rd 0.3:0 -aq-mode 2 -aq-strength 0.8 -b:a 256k',
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h264 压制 Intel 硬件加速
presetName = self.tr('H264压制 Intel 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
'%s',
'-c:v h264_qsv -qscale 15 -b:a 256k',
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h264 压制 AMD 硬件加速
presetName = self.tr('H264压制 AMD 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
'%s',
'-c:v h264_amf -qscale 15 -b:a 256k',
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h264 压制 Nvidia 硬件加速
presetName = self.tr('H264压制 Nvidia 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
'%s',
'-c:v h264_nvenc -qscale 15 -b:a 256k',
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h264 压制 Mac 硬件加速
presetName = self.tr('H264压制 Mac 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
'%s',
'-c:v h264_videotoolbox -qscale 15 -b:a 256k',
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h265压制
presetName = self.tr('H265压制')
description = '''h265 编码'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
"%s",
"-c:v libx265 -crf 28 -b:a 256k",
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h265压制 Intel 硬件加速
presetName = self.tr('H265压制 Intel 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
"%s",
"-c:v hevc_qsv -qscale 15 -b:a 256k",
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h265压制 AMD 硬件加速
presetName = self.tr('H265压制 AMD 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
"%s",
"-c:v hevc_amf -qscale 15 -b:a 256k",
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h265压制 Nvidia 硬件加速
presetName = self.tr('H265压制 Nvidia 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
"%s",
"-c:v hevc_nvenc -qscale 15 -b:a 256k",
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h265压制 Mac 硬件加速
presetName = self.tr('H265压制 Mac 硬件加速')
description = '''<body><p>关于使用硬件加速:</p><p>目前硬件加速支持两种编码格式:H264 和 H265</p><p>有3种加速方法,分别对应三家的硬件:Inter、AMD、Nvidia</p><p>不过在苹果电脑上,不管你用的哪家的硬件,都是使用 videotoolbox 编码器。</p><p>需要注意的是,即便你的电脑拥有 Nvidia 显卡,可能也用不了 Nvidia 的硬件加速编码,因为 Nvidia 硬件加速依赖于显卡内部的一种特定的 GPU 的物理部分,专用于编码。只有在 GTX10 和 RTX20 以上的显卡才搭载有这个物理部分。</p><p>使用硬件编码器进行编码,只需要将输出选项中的编码器改成硬件编码器即可,其中:</p><ul><li><code>-c:v h264_qsv</code> 对应 Intel H264 编码</li><li><code>-c:v h264_amf</code> 对应 AMD H264 编码</li><li><code>-c:v h264_nvenc</code> 对应 Nvidia H264 编码</li><li><code>-c:v h264_videotoolbox</code> 对应苹果电脑的 H264 编码</li><li><code>-c:v hevc_qsv</code> 对应 Intel H265 编码</li><li><code>-c:v hevc_amf</code> 对应 AMDH265 编码</li><li><code>-c:v hevc_nvenc</code> 对应 Nvidia H265 编码</li><li><code>-c:v hevc_videotoolbox</code> 对应苹果电脑的 H265 编码</li></ul><p><code>-c:v</code> 表示视频(Video)的编码器(codec)</p><p>在使用硬件加速编码器的时候,控制输出视频的质量是使用 <code>qscale</code> 参数,他的数值可以从 <code>0.1 - 255</code> 不等,数值越小,画质越高,码率越大,输出文件体积越大。同一个数值对于不同的编码器画质的影响效果不同。所以你需要自己测试,在玛律大小和视频画质之间找到一个平衡的 <code>qscale</code> 数值。</p><p>目前所有的硬件加速选项都是类似这样的:<code>-c:v h264_qsv -qscale 15</code> ,这表示使用英特尔 h264 硬件加速编码器,视频质量参数为15。你可以更改里面的数值,以达到你期望的画质效果。</p></body>'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
"%s",
"-c:v hevc_videotoolbox -qscale 15 -b:a 256k",
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h264 恒定比特率压制
presetName = self.tr('H264压制目标比特率6000k')
description = '''h264恒定比特率压制'''
cursor.execute('''
insert into %s
(name, outputOption, description)
values (
"%s",
"-b:a 256k -b:v 6000k",
'%s'
);'''
% (presetTableName, presetName, description.replace("'", "''")))
# h264 恒定比特率二压
presetName = self.tr('H264 二压 目标比特率2000k')
description = '''h264恒定比特率二压'''
extraCode = r"""nullPath = '/dev/null'
connector = '&&'
print(1)
platfm = platform.system()
print(2)
removeCommand = 'rm'
if platfm == 'Windows':
nullPath = 'NUL'
removeCommand = 'del'
print(3)
inputOne = self.输入1路径框.text()
inputOneWithoutExt = os.path.splitext(inputOne)[0]
outFile = self.输出路径框.text()
outFileWithoutExt = os.path.splitext(outFile)[0]
logFileName = outFileWithoutExt + r'-0.log'
print(logFileName)
if platfm == 'Windows':
logFileName = logFileName.replace('/', '\\')
logTreeFileName = outFileWithoutExt + r'-0.log.mbtree'
if platfm == 'Windows':
logTreeFileName = logTreeFileName.replace('/', '\\')
tempCommand = self.finalCommand.replace('"' + outFile + '"', r'-passlogfile "%s"' % (outFileWithoutExt) + ' "' + outFile + '"')
self.finalCommand = r'''ffmpeg -y -hide_banner -i "%s" -passlogfile "%s" -c:v libx264 -pass 1 -an -f rawvideo "%s" %s %s %s %s "%s" %s %s "%s"''' % (inputOne, outFileWithoutExt, nullPath, connector, tempCommand, connector, removeCommand, logFileName, connector, removeCommand,logTreeFileName)
"""
extraCode = extraCode.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption, extraCode, description)
values (
"%s",
"-c:v libx264 -pass 2 -b:v 2000k -preset slow -b:a 256k",
'%s',
'%s'
);''' % (presetTableName, presetName, extraCode, description.replace("'", "''")))
# 复制视频流到mp4容器
presetName = self.tr('复制视频流到mp4容器')
cursor.execute('''
insert into %s
(name, outputExt, outputOption)
values (
'%s',
'mp4',
'-c:v copy -b:a 256k'
);''' % (presetTableName, presetName))
# 将输入文件打包到mkv格式容器
presetName = self.tr('将输入文件打包到mkv格式容器')
cursor.execute('''
insert into %s
(name, outputExt, outputOption)
values (
'%s',
'mkv',
'-c copy'
);'''
% (presetTableName, presetName))
# 转码到mp3格式
presetName = self.tr('转码到mp3格式')
cursor.execute('''
insert into %s
(name, outputExt, outputOption)
values (
'%s',
'mp3',
'-vn -b:a 256k'
);''' % (presetTableName, presetName))
# GIF (15fps 480p)
presetName = self.tr('GIF (15fps 480p)')
description = '''GIF (15fps 480p)'''
cursor.execute('''
insert into %s
(name, outputExt, outputOption, description)
values (
'%s',
'gif',
'-filter_complex "[0:v] scale=480:-1, fps=15, split [a][b];[a] palettegen [p];[b][p] paletteuse"',
'%s'
);''' % (presetTableName, presetName, description.replace("'", "''")))
# 区域模糊
presetName = self.tr('区域模糊')
outputOption = '''-vf "split [main][tmp]; [tmp] crop=宽:高:X轴位置:Y轴位置, boxblur=luma_radius=25:luma_power=2:enable='between(t,第几秒开始,第几秒结束)'[tmp]; [main][tmp] overlay=X轴位置:Y轴位置"'''
outputOption = outputOption.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'%s'
);''' % (presetTableName, presetName, outputOption))
# 视频两倍速
presetName = self.tr('视频两倍速')
outputOption = '''-filter_complex "[0:v]setpts=1/2*PTS[v];[0:a]atempo=2 [a]" -map "[v]" -map "[a]" '''
outputOption = outputOption.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'%s'
);''' % (presetTableName, presetName, outputOption))
# 音频两倍速
presetName = self.tr('音频两倍速')
outputOption = '''-filter_complex "[0:a]atempo=2.0[a]" -map "[a]"'''
outputOption = outputOption.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'%s'
);''' % (presetTableName, presetName, outputOption))
# 视频0.5倍速 + 光流法补帧到60帧
presetName = self.tr('视频0.5倍速 + 光流法补帧到60帧')
outputOption = '''-filter_complex "[0:v]setpts=2*PTS[v];[0:a]atempo=1/2 [a];[v]minterpolate='mi_mode=mci:mc_mode=aobmc:me_mode=bidir:mb_size=16:vsbmc=1:fps=60'[v]" -map "[v]" -map "[a]" -max_muxing_queue_size 1024'''
outputOption = outputOption.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'%s'
);''' % (presetTableName, presetName, outputOption))
# 光流法补帧到60帧
presetName = self.tr('光流法补帧到60帧')
outputOption = '''-filter_complex "[0:v]scale=-2:-2[v];[v]minterpolate='mi_mode=mci:mc_mode=aobmc:me_mode=bidir:mb_size=16:vsbmc=1:fps=60'" -max_muxing_queue_size 1024'''
outputOption = outputOption.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'%s'
);''' % (presetTableName, presetName, outputOption))
# 视频倒放
presetName = self.tr('视频倒放')
outputOption = '''-vf reverse -af areverse'''
outputOption = outputOption.replace("'", "''")
cursor.execute('''
insert into %s
(name, outputOption)
values (
'%s',
'%s'
);''' % (presetTableName, presetName, outputOption))
# 音频倒放
presetName = self.tr('音频倒放')