Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pipe PIL images to ffmpeg stdin - Python

I'm trying to convert an html5 video to mp4 video and am doing so by screen shooting through PhantomJS over time

I'm also cropping the images using PIL so eventually my code is roughly:

while time() < end_time:
    screenshot_list.append(phantom.get_screenshot_as_base64())
.
.
for screenshot in screenshot_list:
    im = Image.open(BytesIO(base64.b64decode(screenshot)))
    im = im.crop((left, top, right, bottom))

Right now I'm saving to disc all those images and using ffmpeg from saved files:

os.system('ffmpeg -r {fps} -f image2 -s {width}x{height} -i {screenshots_dir}%04d.png -vf scale={width}:-2 '
      '-vcodec libx264 -crf 25 -vb 20M -pix_fmt yuv420p {output}'.format(fps=fps, width=width,
                                                                  screenshots_dir=screenshots_dir,
                                                                  height=height, output=output))

But I want instead of using those saved files, to be able to pipe the PIL.Images directy to ffmpeg, how can I do that?

like image 715
bluesummers Avatar asked Apr 27 '17 07:04

bluesummers


1 Answers

Bounty is gone, but I found the solution.

After acquiring all of the screenshots as base64 strings I write them into a subprocess with the following code

import subprocess as sp

# Generating all of the screenshots as base64 
# in a variable called screenshot_list

cmd_out = ['ffmpeg',
           '-f', 'image2pipe',
           '-vcodec', 'png',
           '-r', '30',  # FPS 
           '-i', '-',  # Indicated input comes from pipe 
           '-vcodec', 'png',
           '-qscale', '0',
           '/home/user1/output_dir/video.mp4']

pipe = sp.Popen(cmd_out, stdin=sp.PIPE)

for screenshot in screenshot_list:
    im = Image.open(BytesIO(base64.b64decode(screenshot)))
    im.save(pipe.stdin, 'PNG')

pipe.stdin.close()
pipe.wait()

# Make sure all went well
if pipe.returncode != 0:
    raise sp.CalledProcessError(pipe.returncode, cmd_out)

If execution time is an issue, you can save the images as JPEGs instead, and use appropriate codecs for that, but the highest quality I managed to achieve was with these settings

like image 136
bluesummers Avatar answered Oct 15 '22 04:10

bluesummers