kkroening / ffmpeg-python

Python bindings for FFmpeg - with complex filtering support
Apache License 2.0
10k stars 886 forks source link

Apostrophes are escaped a little too much #138

Open Baa14453 opened 5 years ago

Baa14453 commented 5 years ago

Hello, I'm not 100% sure this is an issue with this library or if it's something else, but basically I am attempting to use the 'subtitles' filter by feeding it an mkv file, ffmpeg always crashes and when I printed the stream arguments I got the below: ['-i', "tes't.mkv", '-filter_complex', "[0]subtitles=tes\\\\\\\\\\\\\\'t.mkv[s0]", '-map', '[s0]', "tes't.mkv2.mkv"]

This is for a file called tes't.mkv

This is a script I recreated this with:

import ffmpeg
import sys

file_path = "tes't.mkv"

def convert_video(file_path):
    #Create a stream
    stream = ffmpeg.input(file_path)
    #Apply subtitle filter
    stream = ffmpeg.filter_(stream,'subtitles',str(file_path))
    #Output file
    stream = ffmpeg.output(stream, file_path + '2.mkv')
    #Get to work
    print(ffmpeg.get_args(stream))

convert_video(file_path)

If I attempt to run this stream then ffmpeg crashes with the below error:

[Parsed_subtitles_0 @ 0x5591972f24a0] Unable to open tes\'t.mkv
[AVFilterGraph @ 0x5591972cd1c0] Error initializing filter 'subtitles' with args 'tes\\\'t.mkv'
Error initializing complex filters.
No such file or directory
Traceback (most recent call last):
  File "test.py", line 16, in <module>
    convert_video(file_path)
  File "test.py", line 14, in convert_video
    ffmpeg.run(stream)
  File "/home/baa/.local/lib/python3.6/site-packages/ffmpeg/_run.py", line 212, in run
    raise Error('ffmpeg', out, err)
ffmpeg._run.Error: ffmpeg error (see stderr output for detail)
153957 commented 5 years ago

Possibly relevant discussion: https://github.com/kkroening/ffmpeg-python/pull/25 (merged PR)

kkroening commented 5 years ago

It might be a bug in ffmpeg. Try running the same command from the command-line and do the escaping yourself. No matter how many or few \ characters you put in the command line, ffmpeg chokes.

Works(subtitles in sub.srt):

ffmpeg -i in.mp4 -filter_complex "[0]subtitles=sub.srt[s0]" -map "[s0]" out.mp4 -y

Doesn't work (subtitles in sub'tst.srt):

ffmpeg -i in.mp4 -filter_complex "[0]subtitles=sub'tst.srt[s0]" -map "[s0]" out.mp4 -y
ffmpeg -i in.mp4 -filter_complex "[0]subtitles=sub\'tst.srt[s0]" -map "[s0]" out.mp4 -y
ffmpeg -i in.mp4 -filter_complex "[0]subtitles=sub\\'tst.srt[s0]" -map "[s0]" out.mp4 -y
ffmpeg -i in.mp4 -filter_complex "[0]subtitles=sub\\\'tst.srt[s0]" -map "[s0]" out.mp4 -y
# (etc)

As 153957 mentioned above, ffmpeg escaping is weird/confusing. Having lots and lots of \ chars to escape a single input character is actually normal: multiple levels of unescaping happen in ffmpeg when parsing the command line, and each layer essentially multiplies the number of escapes characters by 2 (i.e. exponential amounts of escaping). We were equally surprised when figuring this out for the first time.

Also note that there's yet another level of escaping that happens as standard python when printing representations of python strings, e.g.:

>>> chr(92)
'\\'
JurgenDJ commented 5 years ago

Running against the same issue when trying to scale down. Simplified code example:

inputstream = ffmpeg.input(infile, ss='00:00:10.000', t='00:00:20.000')# start after 10s, sequence of 20s duration
# v0 = inputstream['v'].filter_('scale',"320:240") # this doesn't work, resulting in get_args item: '[0:v]scale=320\\\\\\\\\\\\:240[s0]'
v0 = inputstream['v'].filter_('scale',"320x240") # this works, resulting in get_args item '[0:v]scale=320x240[s0]'
a0 = inputstream['a']
outstream = ffmpeg.output(v0,a0, outfile, acodec='aac', audio_bitrate='96K',vcodec='libx265', crf='23' )

print(outstream.get_args())
outstream.run()

I'm actually trying to scale conditionally (only scale down for if source has bigger dimensions), for that I need to enter a more complex scaling value which involves expressions as found on https://trac.ffmpeg.org/wiki/Scaling

laurentchicoine commented 5 years ago

Running against the same issue when trying to scale down. Simplified code example:

inputstream = ffmpeg.input(infile, ss='00:00:10.000', t='00:00:20.000')# start after 10s, sequence of 20s duration
# v0 = inputstream['v'].filter_('scale',"320:240") # this doesn't work, resulting in get_args item: '[0:v]scale=320\\\\\\\\\\\\:240[s0]'
v0 = inputstream['v'].filter_('scale',"320x240") # this works, resulting in get_args item '[0:v]scale=320x240[s0]'
a0 = inputstream['a']
outstream = ffmpeg.output(v0,a0, outfile, acodec='aac', audio_bitrate='96K',vcodec='libx265', crf='23' )

print(outstream.get_args())
outstream.run()

I'm actually trying to scale conditionally (only scale down for if source has bigger dimensions), for that I need to enter a more complex scaling value which involves expressions as found on https://trac.ffmpeg.org/wiki/Scaling

I ran into the same issue with the crop filter using expressions that requires single quotes. In that case the single quotes should not be escaped for ffmpeg to work correctly. In my case I simply modified the FilterNode._get_filter option (nodes.py file) to remove the escaping of single quotes.

In my use cases I don't need that escaping, however it might be required in other use cases. I feel like fixing this and keep everything else working would require multiple modifications to the code therefore I don't plan on submitting a pull request.

If somebody else has a solution for this, let me know.

lzkzls commented 4 years ago

Hi, has this problem been solved? I have the same problem.