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
相关产品推荐
相关产品推荐

