使用子进程从python执行ffmpeg命令

使用子进程从python执行ffmpeg命令,python,ffmpeg,Python,Ffmpeg,以下命令在命令行中可以正常工作: ffmpeg -y -threads 4 -i /dev/video0 -filter_complex "[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]" -c:v libx264 -b:v 2800k -maxrate:v 2996k -bufsize:v 4200k -c:a aac -b:a 128k -ac 2 -ar 48000 -preset veryfast -x264

以下命令在命令行中可以正常工作:

ffmpeg -y -threads 4 -i /dev/video0 -filter_complex "[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]" -c:v libx264 -b:v 2800k -maxrate:v 2996k -bufsize:v 4200k -c:a aac -b:a 128k -ac 2 -ar 48000 -preset veryfast -x264opts keyint=25:min-keyint=25:no-scenecut -sc_threshold 0 -r 25 -pix_fmt yuv420p -segment_list_flags +live -map [vout001] -f tee -var_stream_map 'v:0' "[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='segment_%%06d_%Y%m%d%H%M%S.ts']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"
但是,当我使用以下命令通过子流程从python代码执行它时,它会抛出错误:

cmd_ffmpeg=['ffmpeg','-y','-threads','4','-i','/dev/video0','-filter\u complex','[v:0]比例=-2:720:force\u original\u aspect\u ratio=减少[vout001]“,”,“-c:v”,“libx264',“-b:v”,“2800k',”-maxrate:v”,“2996k',“-bufsize:v”,“4200k',”-c:a”,“aac',“-b:a”,“128k',“-ac”,“2',“-ar”,“48000',”-预设”,“veryfast',“-x264opts”,“keyint=25:min keyint=25:无场景”,“sc_阈值”,“0',“,”-r”,“25',“pix U fmt”,“yuv420p',“,”,“,“,”-tee”,“现场地图”,“VOUT01',“,”[f=hls:hls\U time=1:hls\U playlist\u type=event:strftime=1:hls\u flags=independent\u segments+program\u date\u time+second\u level\u segment\u index:hls\u segment\u filename=\'segment%%06d\u%Y%m%d%H%m%S.ts\']playlist.m3u8|[f=hls:hls\U时间=1:hls\U播放列表\U类型=事件:strftime=1:hls\U标志=独立\U段+节目\U日期\U时间+二级\U段\U索引:hls\U段\U文件名=\'http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"']
错误如下:

No option found near "//X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts":method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"
从python代码执行时,它将“http”后面的“:”视为选项分隔符(转义不起作用),而直接从shell执行时,转义工作正常


如何解决此问题?

ffmpeg
看到命令行之前,长字符串周围的双引号被shell丢弃。您可以简单地用Python中的单引号替换它们。在单引号中包含文字双引号是丢弃
ffmpeg
选项解析器的原因。

双引号在
ffmpeg
看到命令行之前,长字符串周围的OTE被shell丢弃。您可以简单地用Python中的单引号替换它们。在单引号中包含文字双引号是抛出
ffmpeg
选项解析器的原因。

您是如何手动生成cmd\u ffmpeg的?这与
shlex.split
返回。例如,cmd\u ffmpeg在filter\u complex之后有双引号,而shlex.split返回的则没有

import shlex
shell_ffmpeg_cmd = r'''ffmpeg -y -threads 4 -i /dev/video0 -filter_complex "[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]" -c:v libx264 -b:v 2800k -maxrate:v 2996k -bufsize:v 4200k -c:a aac -b:a 128k -ac 2 -ar 48000 -preset veryfast -x264opts keyint=25:min-keyint=25:no-scenecut -sc_threshold 0 -r 25 -pix_fmt yuv420p -segment_list_flags +live -map [vout001] -f tee -var_stream_map 'v:0' "[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='segment_%%06d_%Y%m%d%H%M%S.ts']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"'''
popen_args = shlex.split(shell_ffmpeg_cmd)
print(" ".join(popen_args))
另外,值得一提的是,与shell调用相比,cmd\u ffmpeg中缺少这两个开关:
-var\u stream\u map
'v:0'

然而,您的问题似乎是列表中的最后一个元素。正如eatmeimadanish所建议的,尝试三重引用它。以下是您的cmd_ffmpeg,其中最后一个元素已更正并三重引用。它打印ffmpeg的stderr,根据我的经验,它很方便:

from subprocess import Popen, PIPE

cmd_ffmpeg = ['ffmpeg', '-y', '-threads', '4', '-i', '/dev/video0', '-filter_complex', '[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]', '-c:v', 'libx264', '-b:v', '2800k', '-maxrate:v', '2996k', '-bufsize:v', '4200k', '-c:a', 'aac', '-b:a', '128k', '-ac', '2', '-ar', '48000', '-preset', 'veryfast', '-x264opts', 'keyint=25:min-keyint=25:no-scenecut', '-sc_threshold', '0', '-r', '25', '-pix_fmt', 'yuv420p', '-segment_list_flags', '+live', '-map', '[vout001]', '-f', 'tee', '''"[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='segment_%%06d_%Y%m%d%H%M%S.ts']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"''']
with Popen(cmd_ffmpeg, text=True, stdout=PIPE, stderr=PIPE) as p:
    for line in p.stderr:
        print(line, end="") # stderr already includes a newline
您是如何手动生成cmd_ffmpeg的?它与shlex.split返回的内容不同。例如,cmd_ffmpeg在filter_complex之后有双引号,而shlex.split返回的内容没有双引号

import shlex
shell_ffmpeg_cmd = r'''ffmpeg -y -threads 4 -i /dev/video0 -filter_complex "[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]" -c:v libx264 -b:v 2800k -maxrate:v 2996k -bufsize:v 4200k -c:a aac -b:a 128k -ac 2 -ar 48000 -preset veryfast -x264opts keyint=25:min-keyint=25:no-scenecut -sc_threshold 0 -r 25 -pix_fmt yuv420p -segment_list_flags +live -map [vout001] -f tee -var_stream_map 'v:0' "[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='segment_%%06d_%Y%m%d%H%M%S.ts']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"'''
popen_args = shlex.split(shell_ffmpeg_cmd)
print(" ".join(popen_args))
另外,值得一提的是,与shell调用相比,cmd\u ffmpeg中缺少这两个开关:
-var\u stream\u map
'v:0'

然而,您的问题似乎是列表中的最后一个元素。正如eatmeimadanish所建议的,尝试三重引用它。以下是您的cmd_ffmpeg,其中最后一个元素已更正并三重引用。它打印ffmpeg的stderr,根据我的经验,它很方便:

from subprocess import Popen, PIPE

cmd_ffmpeg = ['ffmpeg', '-y', '-threads', '4', '-i', '/dev/video0', '-filter_complex', '[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]', '-c:v', 'libx264', '-b:v', '2800k', '-maxrate:v', '2996k', '-bufsize:v', '4200k', '-c:a', 'aac', '-b:a', '128k', '-ac', '2', '-ar', '48000', '-preset', 'veryfast', '-x264opts', 'keyint=25:min-keyint=25:no-scenecut', '-sc_threshold', '0', '-r', '25', '-pix_fmt', 'yuv420p', '-segment_list_flags', '+live', '-map', '[vout001]', '-f', 'tee', '''"[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='segment_%%06d_%Y%m%d%H%M%S.ts']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename='http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8"''']
with Popen(cmd_ffmpeg, text=True, stdout=PIPE, stderr=PIPE) as p:
    for line in p.stderr:
        print(line, end="") # stderr already includes a newline

谢谢你们的建议和帮助。我已经尝试了建议的三重引号,但它会产生另一个问题,包括具有以下文件名的视频片段/播放列表:

"f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=segment_%%06d_%Y%m%d%H%M%S.ts]playlist.m3u8

"f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=segment_%%06d_%Y%m0%H%M%S.ts]playlist0.ts

"f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=segment_%%06d_%Y%m11%H%M%S.ts]playlist11.ts

因此,它将参数列表视为段/播放列表文件名。此外,它生成一个输出,而不是两个输出(一个本地输出,另一个到远程服务器)

事实上,解决方案是保留相同的命令,并且只在远程服务器url中的“:”之前添加“\”。因此,python代码中运行良好的最后一个命令是:

cmd_ffmpeg = ['ffmpeg', '-y', '-threads', '4', '-i', '/dev/video0', '-filter_complex', '[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]', '-c:v', 'libx264', '-b:v', '2800k', '-maxrate:v', '2996k', '-bufsize:v', '4200k', '-c:a', 'aac', '-b:a', '128k', '-ac', '2', '-ar', '48000', '-preset', 'veryfast', '-x264opts', 'keyint=25:min-keyint=25:no-scenecut', '-sc_threshold', '0', '-r', '25', '-pix_fmt', 'yuv420p', '-segment_list_flags', '+live', '-map', '[vout001]', '-f', 'tee', '-var_stream_map', 'v:0', '[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'segment_%%06d_%Y%m%d%H%M%S.ts\']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http\\://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\']http://X.X.X.X:pppp/ABCD/playlist.m3u8']
关于选项/值:'-var_stream_map'和'v:0',我只是错过了它。它可以被忽略,因为我们只有一个输入


谢谢。

谢谢大家的建议和帮助。我已经尝试了建议的三重引号,但它会产生另一个问题,包括具有以下文件名的视频片段/播放列表:

"f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=segment_%%06d_%Y%m%d%H%M%S.ts]playlist.m3u8

"f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=segment_%%06d_%Y%m0%H%M%S.ts]playlist0.ts

"f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=segment_%%06d_%Y%m11%H%M%S.ts]playlist11.ts

因此,它将参数列表视为段/播放列表文件名。此外,它生成一个输出,而不是两个输出(一个本地输出,另一个到远程服务器)

事实上,解决方案是保留相同的命令,并且只在远程服务器url中的“:”之前添加“\”。因此,python代码中运行良好的最后一个命令是:

cmd_ffmpeg = ['ffmpeg', '-y', '-threads', '4', '-i', '/dev/video0', '-filter_complex', '[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]', '-c:v', 'libx264', '-b:v', '2800k', '-maxrate:v', '2996k', '-bufsize:v', '4200k', '-c:a', 'aac', '-b:a', '128k', '-ac', '2', '-ar', '48000', '-preset', 'veryfast', '-x264opts', 'keyint=25:min-keyint=25:no-scenecut', '-sc_threshold', '0', '-r', '25', '-pix_fmt', 'yuv420p', '-segment_list_flags', '+live', '-map', '[vout001]', '-f', 'tee', '-var_stream_map', 'v:0', '[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'segment_%%06d_%Y%m%d%H%M%S.ts\']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http\\://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\']http://X.X.X.X:pppp/ABCD/playlist.m3u8']
关于选项/值:'-var_stream_map'和'v:0',我只是错过了它。它可以被忽略,因为我们只有一个输入


谢谢。

如果您想在python代码中运行ffmpeg命令,可以尝试以下方法:

import os
cmd_ffmpeg = """ffmpeg -y -threads 4 -i /dev/video0 -filter_complex \"[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]\" -c:v libx264 -b:v 2800k -maxrate:v 2996k -bufsize:v 4200k -c:a aac -b:a 128k -ac 2 -ar 48000 -preset veryfast -x264opts keyint=25:min-keyint=25:no-scenecut -sc_threshold 0 -r 25 -pix_fmt yuv420p -segment_list_flags +live -map [vout001] -f tee -var_stream_map \'v:0\' \"[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'segment_%%06d_%Y%m%d%H%M%S.ts\']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8\""""
print(cmd_ffmpeg)
os.system(cmd_ffmpeg)

如果要在python代码中运行ffmpeg命令,可以尝试以下操作:

import os
cmd_ffmpeg = """ffmpeg -y -threads 4 -i /dev/video0 -filter_complex \"[v:0]scale=-2:720:force_original_aspect_ratio=decrease[vout001]\" -c:v libx264 -b:v 2800k -maxrate:v 2996k -bufsize:v 4200k -c:a aac -b:a 128k -ac 2 -ar 48000 -preset veryfast -x264opts keyint=25:min-keyint=25:no-scenecut -sc_threshold 0 -r 25 -pix_fmt yuv420p -segment_list_flags +live -map [vout001] -f tee -var_stream_map \'v:0\' \"[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'segment_%%06d_%Y%m%d%H%M%S.ts\']playlist.m3u8|[f=hls:hls_time=1:hls_playlist_type=event:strftime=1:hls_flags=independent_segments+program_date_time+second_level_segment_index:hls_segment_filename=\'http://X.X.X.X:pppp/ABCD/segment_%%06d_%Y%m%d%H%M%S.ts\':method=PUT]http://X.X.X.X:pppp/ABCD/playlist.m3u8\""""
print(cmd_ffmpeg)
os.system(cmd_ffmpeg)

你试过三次引用它吗?如果你能把两条语句分成多行(每个选项一行)就好了,这样我们就更容易阅读了。在shell语句中,你可以在每行末尾加上一个尾随的反斜杠,在python语句中,你只需在列表中的每个逗号后将其拆分。但是apar我想说,从最后一个列表项中去掉双引号可能会解决你的问题。考虑使用。你试过三次引用吗?如果你能把这两个语句分成多行一行,那就好了。在每一行的结尾,在Python语句中,您可以在列表中的每个逗号之后将其分解。但是,除此之外,我认为从最后一个列表项中删除双引号可能会解决您的问题。请考虑使用。如果从 > SLEX.SPLIT()/代码>检查结果,您应该注意到它。