You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Cloud Functions中调用FFmpeg转MP4为HLS遇路径错误求助

解决Cloud Functions中FFmpeg转码HLS的问题

先拆解你的核心错误

你碰到的[Errno 2] No such file or directory错误,和/tmp目录权限无关,问题出在subprocess.Popen的调用逻辑上:默认情况下shell参数为False,此时你传入的整串命令会被当成一个完整的"命令名"去查找,系统自然找不到这个超长名字的"命令",而不是识别出ffmpeg和它的参数。


第一步:修复subprocess调用方式

推荐两种安全的修复方案:

方案1:拆分命令为参数列表(最优,避免shell注入风险)

把FFmpeg命令拆分成列表,每个参数单独作为列表元素,这是subprocess的标准安全用法:

cmd = [
    'ffmpeg', '-y', '-i', input_path,
    '-preset', 'ultrafast', '-g', '60', '-sc_threshold', '0',
    '-map', '0:0', '-map', '0:1', '-map', '0:0', '-map', '0:1',
    '-s:v:0', '360x640', '-c:v:0', 'libx264', '-b:v:0', '365k',
    '-s:v:1', '720x1280', '-c:v:1', 'libx264', '-b:v:1', '3000k',
    '-c:a', 'copy',
    '-var_stream_map', 'v:0,a:0 v:1,a:1',
    '-master_pl_name', 'master.m3u8',
    '-f', 'hls', '-hls_time', '6', '-hls_list_size', '0',
    '-hls_segment_filename', f"{outdir_path}/%v_fileSequence%d.ts",
    '-hls_playlist_type', 'vod',
    f"{outdir_path}/%v_prog_index.m3u8"
]
# 捕获输出方便排查问题
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process.communicate()
print("FFmpeg输出日志:", stdout.decode())
print("FFmpeg错误日志:", stderr.decode())

方案2:启用shell=True(不推荐,有安全风险)

如果一定要用字符串形式的命令,需要设置shell=True,但如果输入文件名来自用户上传,可能存在shell注入风险:

process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

第二步:解决Cloud Functions的FFmpeg依赖问题

本地运行正常是因为你本地装了FFmpeg,但Google Cloud Functions的默认Python运行时没有预装FFmpeg,这是你大概率会遇到的下一个问题,解决方式:

  • 使用Cloud Functions层(Layer):把FFmpeg二进制文件打包成层挂载到函数上,你可以自行编译适配环境的FFmpeg,或者用社区现成的FFmpeg层。
  • 函数启动时自动下载:在函数开头加代码,从可靠源下载FFmpeg到/tmp目录并赋予执行权限,但这种方式会增加函数启动耗时。

替代方案:用ffmpeg-python库实现转码

如果想改用Python封装的FFmpeg库,下面是对应你原命令的实现代码:
首先要在requirements.txt中添加ffmpeg-python依赖。

import ffmpeg

# 初始化输入流
input_stream = ffmpeg.input(input_path)

# 定义两个分辨率的视频流
stream_360p = input_stream.video.filter('scale', 360, 640).output(
    'pipe:', vcodec='libx264', b='365k', preset='ultrafast', g=60, sc_threshold=0
)
stream_720p = input_stream.video.filter('scale', 720, 1280).output(
    'pipe:', vcodec='libx264', b='3000k', preset='ultrafast', g=60, sc_threshold=0
)
# 音频流直接复制
audio_stream = input_stream.audio.output('pipe:', acodec='copy')

# 组合流并输出HLS格式
(
    ffmpeg
    .concat(stream_360p, audio_stream, stream_720p, audio_stream, v=1, a=1)
    .output(
        f"{outdir_path}/%v_prog_index.m3u8",
        format='hls',
        hls_time=6,
        hls_list_size=0,
        hls_segment_filename=f"{outdir_path}/%v_fileSequence%d.ts",
        hls_playlist_type='vod',
        master_pl_name='master.m3u8',
        var_stream_map='v:0,a:0 v:1,a:1'
    )
    .overwrite_output()
    .run(capture_stdout=True, capture_stderr=True)
)

⚠️ 注意:用ffmpeg-python仍然需要环境中有FFmpeg二进制文件,所以还是要解决上面提到的FFmpeg安装问题。


额外排查小技巧

  • 调用FFmpeg前后,可以用os.path.exists(input_path)确认输入文件存在,用os.listdir(outdir_path)检查输出目录的生成情况
  • 确保upload_local_directory_to_gcs函数能正确遍历/tmp/output下的所有.m3u8和.ts文件并上传到GCS

内容的提问来源于stack exchange,提问作者João Abrantes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 12:12:43