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
| import subprocess
| import os
|
| def split_video_by_pipe(video_path, frame_segments, width, height, output_dir):
| """
| 使用 FFmpeg 的管道方式,将视频拆分成指定的帧切片,输出为多个视频文件。
|
| 参数:
| - video_path: 输入视频路径
| - frame_segments: 切片帧段,例如:[0, M1, M2, ..., Mlast]
| - width, height: 视频分辨率,用于计算帧大小
| - output_dir: 输出文件目录
| """
| # 视频帧格式假设 RGB(每像素 3 字节)
| bytes_per_pixel = 3
| frame_size = width * height * bytes_per_pixel # 单帧的字节大小
|
| # 创建输出子目录
| os.makedirs(output_dir, exist_ok=True)
|
| # 打开视频解码管道,用于帧提取
| ffmpeg_extract = [
| "ffmpeg", "-i", video_path, "-vf", "fps=30", "-f", "image2pipe", "-vcodec", "rawvideo", "-"
| ]
| process_extract = subprocess.Popen(ffmpeg_extract, stdout=subprocess.PIPE, bufsize=frame_size * 1)
|
| # 创建多个帧分段管道
| slice_pipes = []
| for i, _ in enumerate(frame_segments[:-1]):
| output_file = os.path.join(output_dir, f"slice_{i+1}.mp4")
| ffmpeg_encode = [
| "ffmpeg", "-framerate", "30", "-f", "rawvideo", "-vcodec", "rawvideo", "-s", f"{width}x{height}", "-pix_fmt", "rgb24", "-i", "-",
| "-c:v", "libx264", "-preset", "slow", "-crf", "18", "-pix_fmt", "yuv420p", output_file
| ]
| slice_pipes.append(subprocess.Popen(ffmpeg_encode, stdin=subprocess.PIPE, bufsize=frame_size * 1))
|
| # 读取帧并分配到对应的切片管道
| current_frame = 0
| while True:
| frame_data = process_extract.stdout.read(frame_size)
| if len(frame_data) < frame_size:
| break # 读取结束
|
| # 找到当前帧所属的切片段
| for i, (start_frame, end_frame) in enumerate(zip(frame_segments[:-1], frame_segments[1:])):
| if start_frame <= current_frame < end_frame:
| print(i)
| slice_pipes[i].stdin.write(frame_data)
| break
|
| current_frame += 1
|
| # 关闭所有管道
| process_extract.stdout.close()
| process_extract.wait()
| for pipe in slice_pipes:
| pipe.stdin.close()
| pipe.wait()
|
| print(f"视频分段完成,切片存储在:{output_dir}")
|
|
|
| # 示例使用
| video_path = "E:/抖音-AI风景/Test/demo.mp4"
| frame_segments = [0, 60, 69, 305]
| fps = 30
| width, height = 1080, 1440
| output_dir = "output"
|
| split_video_by_pipe(video_path, frame_segments, width,height, output_dir)
|
|