调教 GPT 实现多流合一定时轮播

昨天接到一个需求,要实现4-6路流合一,做定时切换的需求,由于没有现成的云导播台,于是首先想到使用 FFMPEG 命令实现。

由于需要添加台标、背景音乐之的类,各种 Filter 写到手软,第一时间想偷懒,就想用GPT 协助实现。

我用的是白嫖 GPT 3.5,Prompt 是 `我有3路直播流,分别是rtmp://x/sz-live/20230615-s01, rtmp://x/sz-live/20230615-s02, rtmp://x/sz-live/20230615-s03
我想将这3路流合并成一路流,按30秒的时间进行切换输出,请给我一个命令

GPT 飞快的给出了一系列命令,经过几个回合的调教,最终 GPT 认输了。
期间经历了 FFMPEG 版本的问题,GPU 版本的问题,以及 Docker 中运行FFMPEG 的问题。

总的来说,按 GPT 生成的命令执行以后,遇到报错,发给 GPT 以后可以正确识别到报错的原因,并能给出相应的解决办法。

最后遇到了 FFMPEG 多路信号平滑切换的问题,GPT 给出的命令如下:

要实现流切换过程中的平滑过渡,避免出现断流情况,你可以考虑使用FFmpeg的动态画面转换(Dynamic Picture Resizing)功能。该功能允许在切换流时动态调整输出流的分辨率和比特率,以实现平滑过渡。

以下是一个示例命令,结合了动态画面转换和流切换的功能:

ffmpeg -i rtmp://play.baidu.com/sz-live/20230615-s01 -i rtmp://play.baidu.com/sz-live/20230615-s02 -i rtmp://play.baidu.com/sz-live/20230615-s03 -filter_complex "[0:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1[v0]; [1:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1[v1]; [2:v]scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2,setsar=1[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[outv]" -map "[outv]" -c:v libx264 -preset veryfast -crf 18 -f flv rtmp://output-url

在上述命令中,我们在每个输入流的处理链中添加了setsar=1过滤器,用于设置输出流的样纵横比(Sample Aspect Ratio)为1:1,以避免在切换流时出现变形。

此外,我们还指定了-c:v libx264 -preset veryfast -crf 18等参数,用于指定输出流的视频编码器和相关设置。你可以根据需要调整这些参数。

请确保替换示例命令中的输入和输出URL,并运行命令。这样修改后的命令应该能够实现流切换过程中的平滑过渡,避免出现断流情况,并且输出流的分辨率为1920×1080。

后来我又想到,如果使用 OBS 实现的话,如何实现,GPT 根据指引,一步步生成了 Python 版本的Script

import obspython as obs

timer_interval = 10  # 切换场景的时间间隔(秒)
scenes = []  # 场景列表
current_scene_index = 0  # 当前场景索引
timer_id = None  # 定时器ID

def switch_scene():
    global current_scene_index

    scene_count = len(scenes)
    if scene_count == 0:
        return

    scene_name = scenes[current_scene_index]
    obs.script_log(obs.LOG_INFO, "切换场景:" + scene_name)

    if obs.obs_frontend_streaming_active():
        obs_frontend_set_current_scene(scene_name)
    else:
        obs_frontend_set_current_preview_scene(scene_name)

    current_scene_index = (current_scene_index + 1) % scene_count

def timer_callback():
    switch_scene()

def obs_frontend_set_current_scene(scene_name):
    scene = obs.obs_get_source_by_name(scene_name)
    obs.obs_frontend_set_current_scene(scene)
    obs.obs_source_release(scene)

def obs_frontend_set_current_preview_scene(scene_name):
    scene = obs.obs_get_source_by_name(scene_name)
    obs.obs_frontend_set_current_preview_scene(scene)
    obs.obs_source_release(scene)

def script_description():
    return "定时切换场景脚本"

def script_update(settings):
    global timer_interval

    timer_interval = obs.obs_data_get_int(settings, "timer_interval")

    # 停止旧定时器
    if timer_id is not None:
        obs.timer_remove(timer_id)
        timer_id = None

    if timer_interval > 0:
        # 启动新定时器
        timer_id = obs.timer_add(timer_callback, timer_interval * 1000)

def script_load(settings):
    global scenes

    scene_list = obs.obs_frontend_get_scene_names()
    scenes = [scene for scene in scene_list]
    obs.source_list_release(scene_list)

def script_properties():
    props = obs.obs_properties_create()

    # 添加定时参数
    obs.obs_properties_add_int(props, "timer_interval", "切换间隔(秒)", 1, 3600, 1)

    return props

调教过程中的几个体验

  1. GPT 对各种最新的文档,索引速度是非常快的,我用的 OBS 29.1版本,GPT可以准确提示哪些 API 是过期的
  2. GPT的代码还是无法完整运行,需要经过指引,进行针对性的优化
  3. 有几个地方有问题,我按 GPT 生成的代码中的关键接口,google 到原始出处以后,告诉 GPT 有问题,进行多次修改
  4. 基本代码有了以后,最终还是在自己的修改和调试下验证通过
  5. 遇到了两次睁眼说瞎话和上下文混乱
  6. 整体上没有任何 OBS 的开发经验,可以在 GPT 的引导下找到思路,减少了很多不必要的学习时间。

最后的成果