← 返回文章列表

把一首歌做成会转的唱片,全程没打开剪辑软件

一张底图、一个会转的黑胶、一首歌,在手机上用 ffmpeg 凑出一条竖屏 MV。

前几天我盯着一首歌发愁。

歌是《We Never(若如初见)》的氛围版,三分零五秒,深夜、雨、错过的那种调子。我想把它做成一条竖屏视频,发出去。可我既不想开剪辑软件,也不想在手机上装一堆 App —— 一个能正常工作的对付三分钟的视频编辑器,占的存储比我三个月拍的素材还多。

后来想明白一件事:一条这样的 MV,本质上只有三样东西 —— 一张底图、一个会转的唱片、一首歌。前两样是图片,第三样是音频,中间没有任何"剪辑"动作。只要能把两张图和一个声音合成一块儿,我就根本不需要剪辑软件。

于是就有了下面这套东西。整条流水线跑在我的手机上,终端里敲命令,产出 1080×1920、三分零五秒、55MB 的 MP4。第一次从头到尾大约十二分钟,其中一半时间在等 AI 出图。

成品的一帧:黑胶唱片浮在模糊的雨夜背景上,下面是歌名
成品就是这样:上面一张会转的唱片,下面三行字,别的什么都没有

动手之前,先想清楚这首歌该是什么颜色

这一步最容易被跳过,也最影响成败。别看歌名猜风格,去搜 —— 搜"歌名 歌手 氛围",翻翻弹幕和评论,看别人听这首歌时脑子里是什么画面。

要定的只有三件事:

一是情绪,怀旧、热血、孤独、甜、还是躁。
二是场景,雨夜、海边、房间、公路、还是舞台。
三是配色,冷调偏靛蓝紫,暖调偏橙金,或者干脆上霓虹。

这三件事定下来,后面所有提示词都是从它们派生出来的。我这首歌在视频平台上被一堆人当成深夜氛围 BGM 用,评论区全是"听哭了""想起某个人"这类话 —— 那就是雨夜、霓虹、背影、透明伞。定了这个之后,图基本一遍就过。

扁平插画:深夜房间,人戴着耳机歪在沙发上,旁边一部手机在放歌
这张画的其实就是我听这首歌的样子,只不过我那条毯子没这么干净

两张图,一张铺在底下,一张塞进唱片

需要两张图,用途完全不同,千万别混着用。

第一张是封面底图,竖构图,铺满整个画面。它最后会被严重虚化,所以它不需要细节,只需要氛围。提示词里除了场景配色情绪,还得压一条硬要求:画面上不要出现任何文字。

python3 sensenova_gen.py -s 9:16 -o cover_r1.png \
  -p "电影感氛围插画,竖构图:雨夜街头,霓虹在湿地面反光,一个人的背影撑着透明伞;
      色调冷偏紫,胶片颗粒感、柔和光晕、浅景深;情绪克制、怀旧;
      画面上不要出现任何文字。Negative: no text, no letters, no numbers, no watermark, no logo, no crowd"

第二张是唱片面板,正方形,只做转起来的那张圆盘。

这里是我第一版翻车的地方。第一版我直接把带人物的封面图裁圆塞进唱片里,结果一转起来,人脸跟着旋转,五官糊成一团扭动的色块,假的没法看。唱片面板必须是抽象的 —— 虚焦的光斑、雨滴、拉丝的光晕,转起来才对味。

python3 sensenova_gen.py -s 1:1 -o disc_art.png \
  -p "抽象氛围画面,正方形:雨夜霓虹的虚焦光斑与雨滴特写,紫蓝与暖橙光晕在深色背景交织,
      柔和斜向雨丝与光的拉丝,细小的水珠反光,胶片颗粒与柔光晕,构图抽象、无具体主体;
      画面里不要出现任何人物、文字。Negative: no text, no letters, no person, no face, no bright background"

两个实操提醒。生图要串行跑,并发会静默丢任务 —— 不发报错,就是不出图,你会以为自己提示词写错了。另外模型写字必糊,所有文字一律最后用代码烧上去,别指望它。

把一张圆图做旧成黑胶

有了面板图,还得让它看起来像张唱片,而不是一块彩色玻璃。用 PIL 一层层叠:

1. 面板图 resize 到 760×760
2. 圆形 mask 裁圆
3. 同心沟槽:r 从 120 到 378,步长 6,深色 alpha 72,线宽 3
                 r 从 123 到 378,步长 12,白色 alpha 22,线宽 1(这是高光沟)
4. 左上到右下的柔光高光(多边形 + 高斯模糊 40)
5. 中心标签环:半径 96,深色 alpha 200,加细描边
6. 中心孔:半径 46,纯黑 + 描边
7. 外圈描边:白色 alpha 120,宽 3
8. 最后一步:再用圆形 mask 把圆外的 alpha 清零

关键就是第 8 步。沟槽和高光这些层是按整张方形画布画的,如果最后不把圆外部分清掉,合成时你会看到唱片外面套着一圈方方正正的黑影 —— 而且因为背景也是暗的,这个错误在预览里不明显,等传上视频平台才被看出来。我在这上面白等了半小时。

同一条思路用在背景上。底图铺满、裁到 1080×1920、高斯模糊 26、亮度压到 0.42,再叠一层竖向渐深(中间亮、上下暗,做出聚光感)。然后在唱片位置画一个紫色椭圆、模糊 58 当外发光,唱片下方画一个黑色椭圆、模糊 36 当投影。这两下之后,唱片才像"浮"在画面上,而不是被贴上去的。

扁平插画:黑胶唱片和手机并排放在木桌上
左边那个东西是黑胶,右边那个才是真正播放它的设备

文字就四行,位置是调死的

文字全部用 PIL 烧进底图,字体就用系统自带的思源黑(/system/fonts/NotoSansCJK-Regular.ttc)。四行东西,位置固定:

元素 y 坐标 字号 颜色
主标题(英文) 1206 116 纯白,字距拉开 6px
副标题(中文) 1340 46 淡紫灰
分隔线 1466 宽 2,长 180px 灰紫
说明文字 1496 44,描边 1px 米白

三条规矩:所有文字的 y 坐标不许超过 1550,再低会被竖屏平台底部的按钮区吃掉;文字不能压到唱片;"图片 AI 生成 · 视频自动合成"这一行必须留、字号不能小于 42,否则手机屏上根本看不清 —— 这条不是排版偏好,是得让人知道画面是怎么来的。

让它在转,只需要一行滤镜

渲染是整件事里最轻松的部分。用 ffmpeg,两路图片一路音频,画面用一个公式就能转起来:

DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$AUDIO")

ffmpeg -y -loop 1 -framerate 30 -i bg.jpg \
       -loop 1 -framerate 30 -i disc.png \
       -i "$AUDIO" \
  -filter_complex "\
[1:v]format=rgba,fade=t=in:st=0:d=1.2:alpha=1,rotate='2*PI*t/14':c=none:ow=iw:oh=ih[disc];\
[0:v][disc]overlay=160:320[v]" \
  -map "[v]" -map 2:a -t "$DUR" -r 30 \
  -c:v libx264 -preset veryfast -crf 23 -pix_fmt yuv420p -profile:v high -level 4.1 \
  -c:a aac -b:a 192k -ar 44100 -movflags +faststart out.mp4

几个数字的来历,最好别乱改:

2*PI*t/14 是十四秒转一圈。这是试出来的 —— 十秒一圈已经有点晕,二十秒一圈又像卡住了,十四秒慢得刚好能看清纹理,又不至于让人看出它其实只是一张平涂的图。

overlay=160:320 是唱片的位置,(1080-760)/2=160,垂直方向 320。竖屏构图里唱片放在偏上一点,下面留给文字。

fade=t=in:st=0:d=1.2:alpha=1 让唱片淡入。前面那个 format=rgba 千万别省 —— 少了它,RGBA 层会被当成不透明黑块,画面上直接糊一个黑圆。

-t "$DUR" 让视频长度等于音频长度,不需要手动数秒。三分钟的歌,手机上渲染大约三分钟,输出 55MB 左右。

唱臂那一版,我做完就删了

本来我以为加个唱臂会更好看 —— 开头唱针缓缓落下,结尾抬起来,像真的在放唱片。我认真做了一版:支点、臂长、角度曲线全算好了,落针三点五秒从负四十五度到零度,抬臂再回去,做了完整的一条片子。

然后自己看了两遍,删了。

原因是唱臂是静态贴图。它和背景那种柔和的插画质感根本不是一个世界的东西,一看就是"贴上去的"。更麻烦的是,落针动作越顺,越暴露整个画面是平的 —— 机械动作需要一个真实的三维空间去支撑,而我这里没有。它还挡住了画面右上角,把原本干净的构图破了。最后我想明白了:观众看的是歌名和那点氛围,没人在意唱机是怎么工作的。

我在这里多花了差不多两个小时。这段写出来就是提醒一句:这类"再加一点细节会更真"的直觉,在纯图形合成里通常是反的,加越多越假。

做完先别急着发,检查这几条

ffprobe -v error -select_streams v:0 \
  -show_entries stream=width,height,r_frame_rate,nb_frames -of default=nw=1 out.mp4
ffmpeg -y -ss 3 -i out.mp4 -frames:v 1 chk.jpg

对着清单过一遍:分辨率 1080×1920、30fps、时长和音频一致;唱片上有沟槽和中心标签,不是一块纯色玻璃;隔三秒抽两帧对比,纹理位置不一样(说明真的在转);文字没被遮挡,说明文字看得清;画面没有方框黑影,没有元素溢出边界;体积在 50 到 60MB 之间,太小说明码率掉了。

换一首歌,要改的其实只有五处

这套参数调好之后就是模板了,换歌只动这几个地方:封面提示词的场景配色情绪、重新生成一张抽象唱片面板图、主副标题文字、要不要加署名(我默认不加)、以及转速里那个分母 —— 慢歌用 16 到 18 秒一圈。剩下的尺寸、坐标、字号、沟槽参数全都不用碰。

一首歌一首歌做下来,最快的一次十二分钟,其中七分钟在等图。这大概就是我愿意为一条竖屏 MV 付的最大时间成本:够慢,让它看起来像手工做的;也够快,快到我想做第二首。

▍ 本文由自建 Agent 调度内容流水线自动完成:写稿 → 模型 API 生图 → R2 图床 → 排版 → MCP 落站。

▍ 配图由模型 API 生成、托管在对象存储上;内容仅供参考。