前面几篇,我们已经分析了 Pixelle-Video 的文案生成、分镜规划、AI 配图、ComfyUI 工作流、RunningHub 云端工作流,以及直连 API 媒体模型。
到这里,Pixelle-Video 的前半段流程已经比较清楚了:
text
主题 / 固定文案
↓
生成或拆分 narration
↓
生成 image_prompt
↓
创建 StoryboardFrame
↓
生成图片或视频素材
但还有一个关键问题没有展开:
这些图片或 AI 视频素材,最后是怎么变成一个个可拼接的视频片段的?
这一篇我们就重点分析:
text
AI 视频片段生成
也就是 Pixelle-Video 如何从静态配图或动态视频素材,生成最终可以拼接的 segment.mp4。
一、Pixelle-Video 不是一次性生成完整视频
很多人以为 AI 视频生成流程是这样的:
text
输入主题
↓
生成完整视频
但 Pixelle-Video 的真实流程不是这样。
它是先把整条视频拆成多个 StoryboardFrame,然后每个 frame 单独处理,生成一个独立的视频片段,最后再把所有片段拼接成完整视频。
FrameProcessor 源码注释里明确写到,它负责处理单个 frame 的完整流程,包括 TTS、图像生成、画面合成和视频片段生成;它还特别强调一个关键特性:视频时长由 TTS 音频时长驱动,用来保证音频和视频同步。
所以 Pixelle-Video 的核心思路是:
text
完整短视频
=
frame 1 视频片段
+
frame 2 视频片段
+
frame 3 视频片段
+
...
这和传统剪辑也很像。
传统剪辑里,你会先得到很多镜头片段,再放到时间轴上拼接。
Pixelle-Video 只是把这个过程自动化了。
二、视频片段生成发生在哪里?
AI 视频片段生成主要发生在:
text
pixelle_video/services/frame_processor.py
FrameProcessor.__call__() 的流程非常清楚:
text
1. Generate audio
2. Generate media
3. Compose frame
4. Create video segment
源码中这四个步骤分别对应 _step_generate_audio()、_step_generate_media()、_step_compose_frame()、_step_create_video_segment()。
也就是说,一个 frame 从文本变成视频片段,要经过四步:
text
StoryboardFrame
↓
生成旁白音频 audio_path
↓
生成图片或视频素材 image_path / video_path
↓
HTML 模板合成 composed_image_path
↓
生成 video_segment_path
最终,每个 frame 都会得到一个:
text
frame.video_segment_path
后面的 post_production() 再把这些 segment 拼成最终视频。
三、第一步:先生成 TTS 音频
Pixelle-Video 的视频片段生成,第一步不是生成画面,而是生成音频。
在 _step_generate_audio() 中,系统会把当前 frame 的 narration 传给 TTS 服务,然后把生成后的音频路径写入:
text
frame.audio_path
接着,它会读取音频时长,并写入:
text
frame.duration
源码里正是这样处理:先构造 TTS 参数,调用 self.core.tts(),保存 frame.audio_path,然后通过 _get_audio_duration() 获取音频时长。
这一步很重要。
因为 Pixelle-Video 的每个视频片段,本质上是"旁白驱动"的:
text
旁白文本
↓
TTS 音频
↓
音频时长
↓
决定当前画面持续多久
如果旁白是 3 秒,那么这一段视频最好也是 3 秒。
如果旁白是 6 秒,那么画面也应该持续 6 秒。
这样最终视频的音画才不会错位。
四、第二步:判断当前 frame 是图片还是视频
生成音频后,Pixelle-Video 会进入 _step_generate_media()。
这里有一个关键判断:
python
workflow_name = config.media_workflow or ""
template_type = get_template_type(config.frame_template or "")
is_video_workflow = "video_" in workflow_name.lower() or template_type == "video"
media_type = "video" if is_video_workflow else "image"
源码逻辑说明,系统会根据 workflow 名称和模板类型判断当前要生成图片还是视频:如果 workflow 名称中包含 video_,或者模板类型是 video,就按视频素材处理;否则按图片素材处理。
这一步决定了后面的分支:
text
image 分支:
image_prompt → AI 图片 → 静态图片视频片段
video 分支:
image_prompt / video_prompt → AI 视频 → 动态视频片段
所以 Pixelle-Video 不是单纯的"图文视频生成器"。
它既能把图片变成视频片段,也能把 AI 视频素材继续加工成视频片段。
五、image 模板和 video 模板的区别
Pixelle-Video 的模板类型会影响媒体生成策略。
前面第 8、9、11 篇我们已经讲过,模板大致分为:
text
static 模板:
不需要 AI 图片或 AI 视频
image 模板:
每段旁白生成一张图片
video 模板:
每段旁白生成一段视频素材
在 StandardPipeline.plan_visuals() 中,如果模板需要媒体,系统会先生成 image prompts,并应用 prompt_prefix;如果是 static 模板,则直接把 ctx.image_prompts 设置成和 narration 数量一致的 None,跳过图片 prompt 和媒体生成。
这里有一个容易混淆的点:
即使字段名叫 image_prompt,在 video 模板里,它也可以作为"视觉提示词"使用。
也就是说:
text
image_prompt
不一定只服务于图片,也可能作为视频模型的 prompt 输入。
六、第三步:生成图片或视频素材
确定 media_type 后,FrameProcessor 会构造 media_params,然后调用:
python
media_result = await self.core.media(**media_params)
传入的参数包括:
text
prompt = frame.image_prompt
workflow = config.media_workflow
media_type = image 或 video
width = config.media_width
height = config.media_height
output_path = 当前 frame 的输出路径
image_path = frame.image_path
index = frame.index + 1
如果当前是视频 workflow,并且已经拿到了 TTS 音频时长,还会把 duration 传给媒体生成服务。源码注释里明确说明,这样做是为了让视频长度匹配音频长度。
这一步的调用链路是:
text
FrameProcessor
↓
MediaService
↓
ComfyUI / RunningHub / API Provider
↓
返回 MediaResult
MediaService 的参数也说明它支持 media_type="image" 或 "video",并支持 duration、width、height、negative_prompt、steps、seed、cfg、sampler 等媒体生成参数。
七、视频 workflow 为什么要传 duration?
这是 AI 视频片段生成中最关键的设计之一。
如果是静态图片生成,时长可以后面由 ffmpeg 根据音频决定。
但如果是 AI 视频生成,模型生成的视频本身就有时长。
例如:
text
旁白音频:6.2 秒
AI 视频素材:4 秒
这时如果直接合成,就会出现问题:
text
画面结束了,旁白还没说完
反过来:
text
旁白音频:3 秒
AI 视频素材:8 秒
也会出现:
text
旁白已经结束,画面还在继续
所以 Pixelle-Video 在视频 workflow 中会把 TTS 音频时长作为目标 duration 传下去。FrameProcessor 源码注释明确写到:对视频 workflow,会把音频时长作为目标视频时长传给媒体生成流程,从而让视频长度匹配音频长度。
这就是"旁白驱动视频时长"的核心。
八、API 视频模型会进一步修正 duration
如果媒体生成走的是 api/... 直连模型,duration 还会进入 APIProviderMediaService。
在 _generate_video() 中,源码会先计算 requested_duration,然后调用 _video_duration() 得到 safe_duration,再把这个安全时长传给具体的 VideoClient.generate_video()。最后返回 MediaResult(media_type="video", url=save_path, duration=safe_duration)。
为什么要修正?
因为不同视频模型支持的时长范围不同。
例如,有的模型只支持 5 秒或 10 秒。
有的模型支持 3 到 15 秒。
有的模型支持 2 到 15 秒。
所以 Pixelle-Video 的处理逻辑是:
text
TTS 得到原始音频时长
↓
作为 requested_duration 传给 API 视频模型
↓
根据 provider / model 能力修正成 safe_duration
↓
生成对应时长的视频
这说明 Pixelle-Video 尽量让视频素材匹配旁白,但也会尊重底层模型的能力边界。
九、图片素材和视频素材如何写回 frame?
媒体生成完成后,MediaService 会返回 MediaResult。
如果返回的是图片,FrameProcessor 会下载媒体并写入:
text
frame.image_path
如果返回的是视频,则写入:
text
frame.video_path
同时,系统会设置:
text
frame.media_type
如果是视频结果,源码还会优先使用 media_result.duration 更新 frame.duration;如果没有 duration,就通过 _get_video_duration() 读取视频文件时长。
所以一个 frame 的状态会这样变化:
text
生成前:
narration
image_prompt
audio_path = None
image_path = None
video_path = None
video_segment_path = None
生成媒体后:
audio_path = xxx.mp3
duration = 旁白或视频时长
image_path = xxx.png
或
video_path = xxx.mp4
media_type = image / video
这时还没有生成最终视频片段,只是有了素材。
十、第四步:HTML 模板合成画面
接下来是 _step_compose_frame()。
这一步会调用 HTML 模板,把标题、旁白字幕、图片或视频素材路径传进去,生成一个合成画面文件。
源码中 _compose_frame_html() 会解析模板路径,创建 HTMLFrameGenerator,并调用 generate_frame()。传入参数包括:
text
title = storyboard.title
text = frame.narration
image = media_path
ext = 模板扩展参数
output_path = composed 输出路径
其中 media_path 会根据 frame.media_type 选择:如果是视频,就用 frame.video_path;否则用 frame.image_path。
这里要注意:
对于 image 类型,HTML 模板生成的是"带图片背景、标题和字幕的完整画面"。
对于 video 类型,HTML 模板更多是生成"透明叠加层",后面会叠到视频素材上。
源码注释也写到:video 类型会把 HTML 渲染成透明 overlay image;image 类型则把图片作为背景渲染。
所以这一步可以理解为:
text
image 分支:
图片 + 标题 + 字幕 → composed_image
video 分支:
标题 + 字幕透明层 → composed_image
十一、第五步:真正生成 video_segment_path
最后进入 _step_create_video_segment()。
这是每个 frame 变成视频片段的最后一步。
源码里会先生成当前 frame 的 segment 输出路径,然后根据 frame.media_type 分支处理:如果是 video,就走视频素材叠加流程;如果是 image 或 None,就走静态图片转视频流程。
分支可以概括为:
text
frame.media_type == "video":
AI 视频 + HTML overlay + 旁白音频 → segment.mp4
frame.media_type == "image" or None:
composed image + 旁白音频 → segment.mp4
这就是 Pixelle-Video 从静态配图到动态短视频的关键分叉。
十二、image 分支:静态图片如何变成视频片段?
先看 image 分支。
如果 frame.media_type == "image" 或者 None,系统会调用:
python
video_service.create_video_from_image(
image=frame.composed_image_path,
audio=frame.audio_path,
output=output_path,
fps=config.video_fps
)
这一步会把一张合成图和旁白音频合成为一个视频片段。源码中 create_video_from_image() 的注释写得很清楚:图片会作为静态帧显示,持续时长等于音频时长,适合从 storyboard frame 创建视频片段。
也就是说,image 分支生成的视频本质是:
text
一张静态画面
+
一段旁白音频
=
一个短视频片段
这种方式适合:
text
知识类短视频
图文解说视频
故事旁白视频
情绪语录视频
健康科普视频
产品说明视频
它的优点是速度快、成本低、稳定性高。
缺点是画面本身不动,动态感弱。
十三、create_video_from_image 如何保证时长同步?
VideoService.create_video_from_image() 会先用 ffmpeg probe 读取音频时长,然后使用 -t 参数强制让输出视频时长等于音频时长。源码中也明确写到:t=audio_duration 用来强制视频持续时间精确匹配音频。
这意味着:
text
音频 3.5 秒 → 图片视频片段 3.5 秒
音频 6.8 秒 → 图片视频片段 6.8 秒
音频 10 秒 → 图片视频片段 10 秒
这就是静态图转视频时最重要的同步逻辑。
否则,如果图片视频默认只有 1 秒,而音频有 6 秒,最终合成就会出错。
十四、video 分支:AI 视频如何变成最终片段?
再看 video 分支。
如果 frame.media_type == "video",Pixelle-Video 不会直接把 AI 视频当成最终 segment。
它还要做两步:
text
1. 把 HTML 模板渲染出的透明 overlay 叠加到 AI 视频上
2. 把旁白音频合并进去,并替换原视频音频
源码中 _step_create_video_segment() 的 video 分支正是这样做的:
text
overlay_image_on_video(
video=frame.video_path,
overlay_image=frame.composed_image_path,
output=temp_video_with_overlay
)
merge_audio_video(
video=temp_video_with_overlay,
audio=frame.audio_path,
output=output_path,
replace_audio=True
)
overlay_image_on_video() 的注释说明,它会把透明图片叠加到视频上,支持 contain、cover、stretch 三种缩放方式,并且最终视频尺寸匹配 overlay image。
这一步非常关键。
因为 AI 视频素材通常只有画面,没有 Pixelle-Video 的标题、字幕、模板布局。
Pixelle-Video 需要把模板层叠上去,才能保持整条视频的统一风格。
十五、为什么 video 分支要替换原视频音频?
AI 视频模型有时会生成自带音频,有时是静音,有时声音不可控。
Pixelle-Video 的主线是 TTS 旁白驱动,所以最终 segment 需要使用当前 frame 的旁白音频。
在 video 分支中,merge_audio_video() 调用时设置了:
python
replace_audio=True
源码注释也说明:视频可能自带音频,也可能是静音;这里会用旁白替换视频音频。
这样做的好处是:
text
保证每个视频片段都有对应旁白
避免 AI 视频自带声音干扰
保持整条视频声音风格统一
方便后续再统一添加 BGM
最终结果就是:
text
AI 视频画面
+
HTML 标题 / 字幕 overlay
+
TTS 旁白
=
video_segment_path
十六、VideoService 在这里负责什么?
VideoService 是 Pixelle-Video 的底层视频处理服务。
源码注释中写明,它基于 ffmpeg-python,支持视频拼接、音视频合并、添加背景音乐、图片转视频,并要求系统安装 FFmpeg。
在 AI 视频片段生成中,它主要负责三类任务:
text
1. create_video_from_image()
静态图片 + 音频 → 视频片段
2. overlay_image_on_video()
视频素材 + 透明模板层 → 带模板的视频
3. merge_audio_video()
视频 + TTS 音频 → 带旁白的视频片段
也就是说,AI 模型生成素材,VideoService 负责把素材变成真正可播放、可拼接、可发布的视频片段。
十七、为什么最终还是离不开 ffmpeg?
即使 AI 可以生成图片、音频和视频,最终合成仍然离不开 ffmpeg。
原因很简单:AI 生成的是素材,不是完整剪辑工程。
Pixelle-Video 需要处理这些问题:
text
图片如何变成指定时长的视频?
视频和音频如何合并?
AI 视频自带音频要不要保留?
字幕层如何叠加到视频上?
多个片段格式不一致怎么办?
最终视频要用什么编码?
BGM 如何混音?
这些都不是 LLM 或图像模型擅长的事,而是音视频工程问题。
VideoService 中的 merge_audio_video() 会处理视频是否有音频流、是否替换音频或混音等情况;如果视频已有音频且 replace_audio=True,它会使用新音频替换原音频。
所以 Pixelle-Video 的视频片段生成,本质是:
text
AI 负责生成素材
ffmpeg 负责把素材变成视频工程结果
十八、segment 生成后,frame 状态变成什么?
当 _step_create_video_segment() 成功后,会把结果写入:
text
frame.video_segment_path
源码中最后一行就是:
python
frame.video_segment_path = segment_path
这意味着当前 frame 已经完成了从文本到视频片段的完整转换。
一个完整 frame 的状态大致是:
text
StoryboardFrame
index = 0
narration = "很多人越努力越焦虑..."
image_prompt = "A tired office worker..."
audio_path = "frame_0_audio.mp3"
media_type = "video"
video_path = "frame_0_video.mp4"
composed_image_path = "frame_0_composed.png"
video_segment_path = "frame_0_segment.mp4"
duration = 5.0
如果是图片模式,则是:
text
media_type = "image"
image_path = "frame_0_image.png"
composed_image_path = "frame_0_composed.png"
video_segment_path = "frame_0_segment.mp4"
最终 pipeline 只关心每个 frame 有没有 video_segment_path。
十九、多个 segment 如何变成完整视频?
每个 frame 都生成 segment 后,StandardPipeline.post_production() 会收集所有 video_segment_path,然后调用 VideoService.concat_videos() 拼接成完整视频。
VideoService 本身也支持视频拼接,并且有不同拼接方式:例如 concat filter 可以处理不同格式的视频片段。
完整流程可以理解为:
text
frame_0_segment.mp4
frame_1_segment.mp4
frame_2_segment.mp4
frame_3_segment.mp4
↓
concat_videos()
↓
final_video.mp4
如果用户选择了 BGM,后期阶段还会把背景音乐混入最终视频。
所以 segment 是 Pixelle-Video 的中间结果,不是最终结果。
但它是最终视频最重要的组成单位。
二十、静态图视频和 AI 视频片段的对比
到这里,我们可以把两条路线做个对比。
1. 静态配图路线
text
narration
↓
TTS 音频
↓
AI 图片
↓
HTML 模板合成图
↓
图片 + 音频
↓
segment.mp4
优点:
text
成本低
速度快
稳定性高
适合批量生成
对显卡和 API 要求较低
缺点:
text
画面动态感弱
更像图文视频
视觉冲击力有限
2. AI 视频路线
text
narration
↓
TTS 音频
↓
AI 视频素材
↓
HTML 透明 overlay
↓
视频 + overlay
↓
替换为 TTS 音频
↓
segment.mp4
优点:
text
画面有动态
更接近真实短视频
适合故事、氛围、产品展示、情绪类内容
缺点:
text
成本更高
耗时更长
模型限制更多
时长和画面可控性更难
失败率可能更高
所以实际使用时,不一定所有视频都要用 AI 视频。
知识类、口播类内容,用静态图路线可能更划算。
故事类、宣传片、氛围类内容,再考虑 AI 视频路线。
二十一、为什么 Pixelle-Video 要同时支持两条路线?
原因很简单:不同场景需要不同成本和效果。
如果只支持图片:
text
生成稳定,但动态感不足
如果只支持视频:
text
效果更强,但成本和失败率更高
Pixelle-Video 同时支持 image 和 video,就可以让用户按需求选择:
text
低成本批量号:
image 模板
高质感宣传片:
video 模板
不需要画面素材:
static 模板
已有素材剪辑:
asset_based 流程
这种设计更适合做工具,而不是只做 demo。
二十二、从源码看完整片段生成链路
把前面的内容串起来,一个 frame 变成 segment 的完整链路是:
text
StoryboardFrame
↓
_step_generate_audio()
↓
frame.audio_path
frame.duration
↓
_step_generate_media()
↓
根据 workflow / template 判断 media_type
↓
image:
frame.image_path
video:
frame.video_path
frame.duration
↓
_step_compose_frame()
↓
frame.composed_image_path
↓
_step_create_video_segment()
↓
image 分支:
create_video_from_image(
composed_image_path,
audio_path
)
video 分支:
overlay_image_on_video(
video_path,
composed_image_path
)
↓
merge_audio_video(
overlay_video,
audio_path,
replace_audio=True
)
↓
frame.video_segment_path
这就是 Pixelle-Video 从静态配图到动态短视频的源码主线。
二十三、这套设计的优点
Pixelle-Video 的视频片段生成设计有几个明显优点。
第一,职责清楚。
text
FrameProcessor 负责单帧流程
MediaService 负责素材生成
VideoService 负责视频合成
StoryboardFrame 负责保存中间状态
第二,图片和视频统一进入 segment。
无论前面生成的是图片还是视频,最终都要变成 video_segment_path。
第三,音频驱动时长。
TTS 生成后马上读取时长,图片视频直接匹配音频,AI 视频也尽量按音频时长生成。
第四,模板和素材分离。
AI 视频素材不是最终画面,模板层仍然可以叠加标题、字幕和统一样式。
第五,方便后期拼接。
每个 frame 输出独立 segment,后面只需要 concat。
二十四、这套设计的局限
当然,它也有一些局限。
1. AI 视频时长不一定完全匹配旁白
虽然 Pixelle-Video 会把音频时长传给视频模型,但底层模型可能只支持固定时长,比如 5 秒或 10 秒。
因此 API 视频路线中还需要根据模型能力修正 duration。
2. 视频 prompt 质量会直接影响素材质量
如果 prompt 只是静态画面描述,AI 视频可能缺乏动作。
例如:
text
A man at a desk
不如:
text
A man slowly closes his laptop, takes a deep breath, and looks out the window as the camera gently pushes in
视频 prompt 要强调动作、变化和镜头运动。
3. 透明 overlay 依赖模板设计
video 分支需要把 HTML 渲染成透明叠加层。
如果模板透明背景、尺寸、字幕位置没有处理好,叠加效果就会很差。
4. AI 视频素材和字幕可能冲突
如果 AI 视频主体正好出现在字幕区域,字幕可读性会下降。
这就需要模板留出安全区域,或者让 prompt 避开字幕区域。
5. 成本和速度压力更大
视频生成比图片生成慢得多。
如果每个 frame 都生成 AI 视频,整条短视频的生成成本会明显上升。
二十五、二次开发可以怎么优化?
如果你想基于 Pixelle-Video 做二次开发,AI 视频片段生成这一层有不少优化方向。
1. image prompt 和 video prompt 分开
现在很多流程里仍然复用 image_prompt 字段作为视觉 prompt。
如果要更好支持动态视频,可以增加:
text
video_prompt
camera_motion
action_description
duration_hint
这样视频模型能拿到更适合动态生成的提示词。
2. 增加单帧重生成
因为每个 frame 都有独立的 video_path 和 video_segment_path,可以实现:
text
只重生成第 3 段视频素材
只重新叠加字幕
只替换第 5 段音频
只重新生成最终 segment
这比整条视频重做更省成本。
3. 增加视频裁剪和补长策略
如果 AI 视频时长和 TTS 音频时长不一致,可以增加更细的策略:
text
视频短于音频:
慢放
freeze 最后一帧
循环播放
重新生成
视频长于音频:
裁剪
加快播放
选择精彩片段
4. 增加字幕安全区
在 video 模板里,可以明确设置字幕区域,让 AI 视频生成时避开底部或中间文字区。
例如 prompt 自动追加:
text
leave clean empty space at the bottom for subtitles
5. 增加视频片段预览
在最终拼接前,可以先让用户预览每个 segment:
text
第几帧
旁白
视频素材
字幕叠加效果
片段时长
是否需要重生成
这对实际做高质量视频很重要。
二十六、源码阅读建议
如果你要读 Pixelle-Video 的 AI 视频片段生成源码,建议按这个顺序:
text
1. pixelle_video/models/storyboard.py
看 StoryboardFrame 保存哪些中间字段。
2. pixelle_video/services/frame_processor.py
看单帧处理的四步:audio、media、compose、video。
3. pixelle_video/services/media.py
看 media_type=image/video 如何进入 ComfyUI、RunningHub 或 api/...。
4. pixelle_video/services/api_media.py
看直连 API 视频模型如何处理 duration、resolution、provider options。
5. pixelle_video/services/video.py
看 create_video_from_image、overlay_image_on_video、merge_audio_video、concat_videos。
6. pixelle_video/pipelines/standard.py
看所有 frame 处理完成后如何进入 post_production。
这条阅读路线可以完整串起:
text
frame → 素材 → 模板 → segment → final video
二十七、总结
这一篇我们分析了 Pixelle-Video 的 AI 视频片段生成流程。
它的核心不是直接生成最终 MP4,而是先把每个分镜变成一个独立 segment。
完整链路可以总结为:
text
narration
↓
TTS 生成 audio_path
↓
读取音频时长 frame.duration
↓
根据 workflow / template 判断 media_type
↓
image 分支:
生成图片 image_path
HTML 合成 composed_image_path
create_video_from_image()
得到 video_segment_path
video 分支:
生成视频 video_path
HTML 渲染透明 overlay
overlay_image_on_video()
merge_audio_video(replace_audio=True)
得到 video_segment_path
从设计上看,Pixelle-Video 有一个非常重要的思想:
不管前面是静态图片,还是 AI 视频素材,最终都要统一变成 video_segment_path。
这样后面的 pipeline 就简单了:
text
收集所有 video_segment_path
↓
concat_videos()
↓
添加 BGM
↓
输出最终视频
一句话总结:
Pixelle-Video 的 AI 视频片段生成,本质是以 TTS 旁白时长为节奏基准,把每个 StoryboardFrame 的图片或视频素材,通过 HTML 模板和 ffmpeg 合成为独立 segment,再交给后期流程拼接成完整短视频。