总结的需求文档

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
# 视频剪切工具需求文档

## 1. 项目概述
开发一个基于PyQt6的视频剪切工具,提供简洁的图形界面和基本的视频剪切功能。

## 2. 界面布局需求

### 2.1 整体布局
- 窗口标题:视频剪切工具
- 最小窗口尺寸:1000x600
- 左右分栏设计(比例为3:2):
- 左侧:视频预览区域
- 右侧:控制面板(固定宽度400px)

### 2.2 左侧区域
- 视频预览窗口
- 固定尺寸:480x200
- 背景色:#1a1a1a
- 支持自适应缩放
- 进度条和时间显示
- 显示格式:当前时间 / 总时长(HH:MM:SS)
- 进度条支持拖拽定位

### 2.3 右侧控制面板(从上到下)
1. 文件选择区域
- "选择视频"按钮(左对齐)
- 文件路径显示(支持自动换行)

2. 播放控制区域
- 播放/暂停按钮
- "设为开始时间"按钮
- "设为结束时间"按钮
- 按钮组左对齐
- 上下内边距:0px,左右内边距:5px

3. 音量控制区域
- 静音按钮(30x30px)
- 音量滑块(宽度200px)
- 默认静音状态

4. 时间设置区域
- 开始时间和结束时间设置
- 每组包含时分秒三个下拉框
- 分隔符(:)宽度为5px
- 左对齐排列

5. 剪切控制
- "开始剪切"按钮
- 剪切时按钮禁用并显示"正在剪切..."

## 3. 功能需求

### 3.1 视频预览功能
- 支持mp4、avi、mkv、mov格式
- 视频播放/暂停控制
- 进度条拖拽定位
- 实时显示播放时间和总时长

### 3.2 时间控制功能
- 时分秒精确选择(下拉框)
- 支持通过播放进度快捷设置
- 时间范围:
- 小时:00-23
- 分钟:00-59
- 秒:00-59

### 3.3 剪切功能
- 使用ffmpeg进行视频剪切
- 保持原视频编码格式
- 输出文件命名规则:原文件名_年月日_时分秒.mp4
- 保存在原视频相同目录

## 4. 技术要求

### 4.1 开发环境
- Python 3.x
- PyQt6
- OpenCV-Python
- FFmpeg

### 4.2 项目文件结构

### 4.3 项目文件结构

## 5. 样式规范

### 5.1 颜色方案
- 主背景色:#f0f0f0
- 视频预览背景:#1a1a1a
- 按钮颜色:#3498db
- 按钮悬停:#2980b9
- 文字颜色:#2c3e50

### 5.2 控件样式
- 按钮圆角:4px
- 按钮内边距:8px 15px
- 面板圆角:8px
- 面板内边距:10px
- 统一的按钮样式和交互效果

## 6. 使用流程

1. 选择视频文件
- 点击"选择视频"按钮
- 选择支持的视频格式文件

2. 视频预览和时间设置
- 使用播放控制预览视频
- 通过进度条定位
- 设置开始和结束时间点

3. 执行剪切
- 点击"开始剪切"按钮
- 等待处理完成
- 在原目录生成剪切后的视频

## 7. 注意事项
- 确保正确安装所有依赖库
- 确保ffmpeg.exe存在于程序目录的ffmpeg文件夹中
- 剪切时会保持原视频的编码格式
- 剪切大文件时需要耐心等待

## 8. 资源管理
- 程序会自动管理视频资源
- 关闭时自动释放资源

安装插件

根据需求文档中的技术要求,需要安装以下Python包:
PyQt6 相关:

1
2
pip install PyQt6        # PyQt6基础包
pip install PyQt6-Qt6 # PyQt6多媒体支持

OpenCV-Python:

1
pip install opencv-python    # 视频处理和图像处理

FFmpeg:
这个不是Python包,而是需要下载可执行文件
需要将 ffmpeg.exe 放在项目目录的 ffmpeg 文件夹下
或者将FFmpeg添加到系统环境变量中
总结安装命令:

1
pip install PyQt6 PyQt6-Qt6 opencv-python

这些是项目运行所必需的依赖项。其中:
PyQt6:用于构建图形界面
PyQt6-Qt6:提供音频播放支持
OpenCV-Python:用于视频帧的读取和处理
FFmpeg:用于视频剪切功能
注意:如果使用清华源等国内镜像,安装命令可以是:

1
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt6 PyQt6-Qt6 opencv-python

脚本内容

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
import sys
import os
from datetime import datetime, timedelta
import subprocess
import cv2
from PIL import Image
from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QPushButton, QLabel, QFileDialog,
QComboBox, QFrame, QSlider, QMessageBox, QStyle,
QProgressDialog)
from PyQt6.QtCore import Qt, QTimer, QUrl
from PyQt6.QtGui import QPixmap, QImage, QPalette, QColor, QIcon
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput

def resource_path(relative_path):
"""获取资源的绝对路径"""
try:
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")
return os.path.join(base_path, relative_path)

class VideoClipper(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("视频剪切工具")
self.setMinimumSize(1000, 600)
self.setStyleSheet("""
QMainWindow {
background-color: #f0f0f0;
}
QLabel {
color: #2c3e50;
}
QPushButton {
background-color: #3498db;
color: white;
border: none;
padding: 8px 15px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #2980b9;
}
QPushButton:pressed {
background-color: #2574a9;
}
QFrame {
background-color: white;
border-radius: 8px;
padding: 10px;
}
QComboBox {
padding: 5px;
border: 1px solid #bdc3c7;
border-radius: 4px;
min-width: 50px;
background-color: white;
color: black;
}
QComboBox QAbstractItemView {
background-color: white;
selection-background-color: #3498db;
selection-color: white;
color: black;
border: 1px solid #bdc3c7;
}
QComboBox::drop-down {
border: none;
}
QComboBox::down-arrow {
image: none;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 5px solid #2c3e50;
margin-right: 5px;
}
QSlider::groove:horizontal {
border: 1px solid #bdc3c7;
height: 8px;
background: #e0e0e0;
margin: 2px 0;
border-radius: 4px;
}
QSlider::handle:horizontal {
background: #3498db;
border: none;
width: 18px;
margin: -6px 0;
border-radius: 9px;
}
QSlider::handle:horizontal:hover {
background: #2980b9;
}
""")

self.video_path = ""
self.cap = None
self.is_playing = False
self.current_frame = None
self.video_duration = 0
self.current_position = 0

# 添加媒体播放器
self.media_player = QMediaPlayer()
self.audio_output = QAudioOutput()
self.media_player.setAudioOutput(self.audio_output)
self.audio_output.setVolume(0) # 默认静音

self.setup_ui()

def setup_ui(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QHBoxLayout(central_widget)
main_layout.setSpacing(15)
main_layout.setContentsMargins(20, 20, 20, 20)

# 左侧视频预览和控制区域
left_frame = QFrame()
left_layout = QVBoxLayout(left_frame)
left_layout.setSpacing(10)

# 视频预览容器
video_container = QFrame()
video_container.setStyleSheet("background-color: #1a1a1a; border-radius: 4px;")
video_layout = QVBoxLayout(video_container)
video_layout.setContentsMargins(0, 0, 0, 0)

# 视频预览标签
self.video_label = QLabel()
self.video_label.setMinimumSize(480, 200)
self.video_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
video_layout.addWidget(self.video_label)

left_layout.addWidget(video_container, stretch=1) # 添加stretch=1使其自适应

# 进度条和时间显示
time_layout = QHBoxLayout()
self.time_label = QLabel("00:00:00 / 00:00:00")
time_layout.addWidget(self.time_label)

self.progress_slider = QSlider(Qt.Orientation.Horizontal)
self.progress_slider.setRange(0, 1000)
self.progress_slider.sliderPressed.connect(self.on_slider_pressed)
self.progress_slider.sliderReleased.connect(self.on_slider_released)
self.progress_slider.valueChanged.connect(self.on_slider_value_changed)
time_layout.addWidget(self.progress_slider)
left_layout.addLayout(time_layout)

main_layout.addWidget(left_frame, stretch=1)

# 右侧控制面板
right_frame = QFrame()
right_frame.setFixedWidth(400)
right_layout = QVBoxLayout(right_frame)
right_layout.setSpacing(15)
right_layout.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)

# 文件选择区域
file_group = QFrame()
file_layout = QHBoxLayout(file_group)
file_layout.setContentsMargins(5, 5, 5, 5)
file_layout.setAlignment(Qt.AlignmentFlag.AlignLeft)

select_btn = QPushButton("选择视频")
select_btn.setStyleSheet("""
QPushButton {
background-color: #3498db;
color: white;
border: none;
padding: 8px 15px;
border-radius: 4px;
}
QPushButton:hover {
background-color: #2980b9;
}
""")
select_btn.clicked.connect(self.select_video)
file_layout.addWidget(select_btn)

self.path_label = QLabel("未选择视频")
self.path_label.setWordWrap(True)
file_layout.addWidget(self.path_label)

right_layout.addWidget(file_group)

# 播放控制区域
play_group = QFrame()
play_layout = QHBoxLayout(play_group)
play_layout.setContentsMargins(5, 0, 5, 0) # 修改上下间距为0
play_layout.setAlignment(Qt.AlignmentFlag.AlignLeft)

# 修改play_group的样式,减小内边距
play_group.setStyleSheet("""
QFrame {
background-color: white;
border-radius: 8px;
padding: 5px; /* 减小内边距为5px */
}
""")

self.play_button = QPushButton("播放")
self.play_button.clicked.connect(self.toggle_play)
play_layout.addWidget(self.play_button)

set_start_btn = QPushButton("设为开始时间")
set_start_btn.clicked.connect(self.set_start_time)
play_layout.addWidget(set_start_btn)

set_end_btn = QPushButton("设为结束时间")
set_end_btn.clicked.connect(self.set_end_time)
play_layout.addWidget(set_end_btn)

right_layout.addWidget(play_group)

# 音量控制区域
volume_group = QFrame()
volume_layout = QHBoxLayout(volume_group)
volume_layout.setContentsMargins(5, 5, 5, 5)
volume_layout.setAlignment(Qt.AlignmentFlag.AlignLeft)

# 静音按钮
self.mute_button = QPushButton()
self.mute_button.setFixedSize(30, 30)
self.mute_button.clicked.connect(self.toggle_mute)
self.update_mute_button_icon()
volume_layout.addWidget(self.mute_button)

# 音量滑块
self.volume_slider = QSlider(Qt.Orientation.Horizontal)
self.volume_slider.setFixedWidth(200) # 增加音量滑块的宽度
self.volume_slider.setRange(0, 100)
self.volume_slider.setValue(0)
self.volume_slider.valueChanged.connect(self.set_volume)
volume_layout.addWidget(self.volume_slider)

right_layout.addWidget(volume_group)

# 时间设置区域
time_group = QFrame()
time_layout = QVBoxLayout(time_group)
time_layout.setSpacing(5)
time_layout.setContentsMargins(10, 5, 10, 5)
time_layout.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)

# 开始时间
start_layout = QHBoxLayout()
start_layout.setContentsMargins(0, 0, 0, 0)
start_layout.setAlignment(Qt.AlignmentFlag.AlignLeft)
start_layout.addWidget(QLabel("开始时间"))

start_time_layout = QHBoxLayout()
start_time_layout.setSpacing(5)
start_time_layout.setContentsMargins(0, 0, 0, 0)

self.start_hour = QComboBox()
self.start_hour.addItems([str(i).zfill(2) for i in range(24)])
start_time_layout.addWidget(self.start_hour)

colon_label = QLabel(":")
colon_label.setFixedWidth(5)
start_time_layout.addWidget(colon_label)

self.start_minute = QComboBox()
self.start_minute.addItems([str(i).zfill(2) for i in range(60)])
start_time_layout.addWidget(self.start_minute)

colon_label = QLabel(":")
colon_label.setFixedWidth(5)
start_time_layout.addWidget(colon_label)

self.start_second = QComboBox()
self.start_second.addItems([str(i).zfill(2) for i in range(60)])
start_time_layout.addWidget(self.start_second)

start_layout.addLayout(start_time_layout)
start_layout.addStretch()
time_layout.addLayout(start_layout)

# 结束时间
end_layout = QHBoxLayout()
end_layout.setContentsMargins(0, 0, 0, 0)
end_layout.setAlignment(Qt.AlignmentFlag.AlignLeft)
end_layout.addWidget(QLabel("结束时间"))

end_time_layout = QHBoxLayout()
end_time_layout.setSpacing(5)
end_time_layout.setContentsMargins(0, 0, 0, 0)

self.end_hour = QComboBox()
self.end_hour.addItems([str(i).zfill(2) for i in range(24)])
end_time_layout.addWidget(self.end_hour)

colon_label = QLabel(":")
colon_label.setFixedWidth(5)
end_time_layout.addWidget(colon_label)

self.end_minute = QComboBox()
self.end_minute.addItems([str(i).zfill(2) for i in range(60)])
end_time_layout.addWidget(self.end_minute)

colon_label = QLabel(":")
colon_label.setFixedWidth(5)
end_time_layout.addWidget(colon_label)

self.end_second = QComboBox()
self.end_second.addItems([str(i).zfill(2) for i in range(60)])
end_time_layout.addWidget(self.end_second)

end_layout.addLayout(end_time_layout)
end_layout.addStretch()
time_layout.addLayout(end_layout)

right_layout.addWidget(time_group)

# 剪切按钮
clip_btn = QPushButton("开始剪切")
clip_btn.setStyleSheet("""
QPushButton {
background-color: #27ae60;
font-weight: bold;
padding: 10px 20px;
}
QPushButton:hover {
background-color: #219a52;
}
""")
clip_btn.clicked.connect(self.clip_video)
right_layout.addWidget(clip_btn)

# 添加弹簧推动所有控件到顶部
right_layout.addStretch(1)

main_layout.addWidget(right_frame)

# 设置定时器
self.timer = QTimer()
self.timer.timeout.connect(self.update_video_frame)
self.timer.setInterval(30)

# 修改样式表设置部分
current_style = self.styleSheet()
self.setStyleSheet(current_style + """
QSlider::groove:horizontal {
height: 4px;
background: #bdc3c7;
margin: 0px;
border-radius: 2px;
}
QSlider::handle:horizontal {
background: #3498db;
border: none;
width: 12px;
height: 12px;
margin: -4px 0;
border-radius: 6px;
}
QSlider::handle:horizontal:hover {
background: #2980b9;
}
""")

def format_time(self, seconds):
return str(timedelta(seconds=int(seconds))).zfill(8)

def on_slider_pressed(self):
if self.timer.isActive():
self.timer.stop()
self.was_playing = True
else:
self.was_playing = False

def on_slider_released(self):
if hasattr(self, 'was_playing') and self.was_playing:
self.timer.start()

def on_slider_value_changed(self):
if not self.cap or not self.video_duration:
return

position = self.progress_slider.value() / 1000.0 * self.video_duration
self.current_position = position

# 更新视频帧和音频位置
self.cap.set(cv2.CAP_PROP_POS_FRAMES, position * self.cap.get(cv2.CAP_PROP_FPS))
self.media_player.setPosition(int(position * 1000)) # 设置音频位置(毫秒)

ret, frame = self.cap.read()
if ret:
self.display_frame(frame)

self.time_label.setText(
f"{self.format_time(position)} / {self.format_time(self.video_duration)}"
)

def toggle_play(self):
if not self.cap:
return

if self.timer.isActive():
self.timer.stop()
self.play_button.setText("播放")
self.media_player.pause()
else:
self.timer.start()
self.play_button.setText("暂停")
self.media_player.play()

def update_video_frame(self):
if not self.cap:
return

ret, frame = self.cap.read()
if ret:
self.current_position = self.cap.get(cv2.CAP_PROP_POS_FRAMES) / self.cap.get(cv2.CAP_PROP_FPS)
self.progress_slider.setValue(int(self.current_position * 1000 / self.video_duration))
self.time_label.setText(
f"{self.format_time(self.current_position)} / {self.format_time(self.video_duration)}"
)
self.display_frame(frame)
else:
self.cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
self.current_position = 0

def display_frame(self, frame):
"""调整视频帧大小以适应窗口"""
# 获取视频容器的大小
container_size = self.video_label.size()

# 计算保持宽高比的新尺寸
frame_height, frame_width = frame.shape[:2]
aspect_ratio = frame_width / frame_height

# 计算适合容器的新尺寸
if container_size.width() / container_size.height() > aspect_ratio:
# 以高度为基准
new_height = container_size.height()
new_width = int(new_height * aspect_ratio)
else:
# 以宽度为基准
new_width = container_size.width()
new_height = int(new_width / aspect_ratio)

# 调整帧大小
frame = cv2.resize(frame, (new_width, new_height))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

# 创建QImage
h, w, ch = frame.shape
bytes_per_line = ch * w
qt_image = QImage(frame.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)

# 创建并设置pixmap
pixmap = QPixmap.fromImage(qt_image)
self.video_label.setPixmap(pixmap)

def select_video(self):
file_path, _ = QFileDialog.getOpenFileName(
self,
"选择视频文件",
"",
"视频文件 (*.mp4 *.avi *.mkv *.mov)"
)

if file_path:
self.video_path = file_path
self.path_label.setText(file_path)

if self.cap is not None:
self.cap.release()

# 设置媒体播放器源
self.media_player.setSource(QUrl.fromLocalFile(file_path))

self.cap = cv2.VideoCapture(file_path)
self.video_duration = self.cap.get(cv2.CAP_PROP_FRAME_COUNT) / self.cap.get(cv2.CAP_PROP_FPS)

ret, frame = self.cap.read()
if ret:
self.display_frame(frame)
self.time_label.setText(f"00:00:00 / {self.format_time(self.video_duration)}")

def set_start_time(self):
if not self.cap:
return

current_time = self.format_time(self.current_position)
h, m, s = current_time.split(':')

self.start_hour.setCurrentText(h)
self.start_minute.setCurrentText(m)
self.start_second.setCurrentText(s)

def set_end_time(self):
if not self.cap:
return

current_time = self.format_time(self.current_position)
h, m, s = current_time.split(':')

self.end_hour.setCurrentText(h)
self.end_minute.setCurrentText(m)
self.end_second.setCurrentText(s)

def get_time_str(self, hour, minute, second):
return f"{hour.currentText()}:{minute.currentText()}:{second.currentText()}"

def clip_video(self):
if not self.video_path:
QMessageBox.critical(self, "错误", "请先选择视频文件!")
return

start = self.get_time_str(self.start_hour, self.start_minute, self.start_second)
end = self.get_time_str(self.end_hour, self.end_minute, self.end_second)

# 生成时间戳
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")

# 生成输出文件名:原名称_时间戳.mp4
file_name = os.path.splitext(os.path.basename(self.video_path))[0]
output_path = os.path.join(
os.path.dirname(self.video_path),
f"{file_name}_{timestamp}.mp4"
)

# 设置按钮状态
self.sender().setEnabled(False)
self.sender().setText("正在剪切...")
QApplication.processEvents() # 立即更新界面

try:
ffmpeg_path = resource_path(os.path.join("ffmpeg", "ffmpeg.exe"))
command = [
ffmpeg_path,
"-i", self.video_path,
"-ss", start,
"-to", end,
"-c", "copy",
output_path
]

# 执行剪切命令
subprocess.run(command, check=True)
QMessageBox.information(self, "成功", "视频剪切完成!")

except subprocess.CalledProcessError:
QMessageBox.critical(self, "错误", "视频剪切失败!")
except FileNotFoundError:
QMessageBox.critical(self, "错误", "找不到ffmpeg.exe,请确保程序完整!")
finally:
# 恢复按钮状态
self.sender().setEnabled(True)
self.sender().setText("开始剪切")

def update_mute_button_icon(self):
"""更新静音按钮图标"""
if self.audio_output.isMuted():
self.mute_button.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_MediaVolumeMuted))
else:
self.mute_button.setIcon(self.style().standardIcon(QStyle.StandardPixmap.SP_MediaVolume))

def toggle_mute(self):
"""切换静音状态"""
self.audio_output.setMuted(not self.audio_output.isMuted())
self.update_mute_button_icon()

def set_volume(self, value):
"""设置音量"""
self.audio_output.setVolume(value / 100)
if value > 0:
self.audio_output.setMuted(False)
self.update_mute_button_icon()

def closeEvent(self, event):
if self.cap is not None:
self.cap.release()
self.media_player.stop()
event.accept()

def resizeEvent(self, event):
"""窗口大小改变时重新显示当前帧"""
super().resizeEvent(event)
if hasattr(self, 'cap') and self.cap is not None:
# 获取当前帧
current_frame = self.cap.get(cv2.CAP_PROP_POS_FRAMES)
self.cap.set(cv2.CAP_PROP_POS_FRAMES, current_frame - 1)
ret, frame = self.cap.read()
if ret:
self.display_frame(frame)

if __name__ == "__main__":
app = QApplication(sys.argv)
window = VideoClipper()
window.show()
sys.exit(app.exec())