使用子进程从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语句中,您可以在列表中的每个逗号之后将其分解。但是,除此之外,我认为从最后一个列表项中删除双引号可能会解决您的问题。请考虑使用。如果从