Search code examples
pythonvideoffmpegpyffmpeg

Can I pass a list of image into the input method of ffmpeg-python


My task involves using ffmpeg to create video from image sequence. the code belows solves the problem.

import ffmpeg

video = ffmpeg.input('/path/to/images/*.jpg', pattern_type='glob',framerate=20).output(video.mp4).run()

However since the image data we are getting follows the pattern

1.jpg,
2.jpg,
3.jpg
.
.
20.jpg
.
.
100.jpg

the video get created with the glob pattern 1.jpg, 100.jpg, 11.jpg, 12.jpg, ... 2.jpg, 20.jpg, 21.jpg ... which is very unpleasant to watch.

Is there anyway I can pass a list or anything else aside a path/glob pattern where the images are sorted in order. Also as a bonus I will be happy if I can choose which files to add as an the input method input()


Solution

  • You may use Concat demuxer:

    • Create a file mylist.txt with all the image files in the following format:

       file '/path/to/images/1.jpg'
       file '/path/to/images/2.jpg'
       file '/path/to/images/3.jpg'
       file '/path/to/images/20.jpg'
       file '/path/to/images/100.jpg'
      

      You may create mylist.txt manually, or create the text file using Python code.

    • Use the following command (you may select different codec):

       ffmpeg.input('mylist.txt', r='20', f='concat', safe='0').output('video.mp4', vcodec='libx264').run()
      

    Second option:
    Writing JPEG data into stdin PIPE of FFmpeg sub-process.

    • Create a list of JPEG file names (Python list).
    • Execute FFmpeg sub-process, with stdin PIPE as input, and jpeg_pipe input format.
    • Iterate the list, read the content of each file and write it to stdin PIPE.
    • Close stdin PIPE.

    Here is a code sample:

    import ffmpeg
    
    # List of JPEG files
    jpeg_files = ['/tmp/0001.jpg', '/tmp/0002.jpg', '/tmp/0003.jpg', '/tmp/0004.jpg', '/tmp/0005.jpg']
    
    # Execute FFmpeg sub-process, with stdin pipe as input, and jpeg_pipe input format
    process = ffmpeg.input('pipe:', r='20', f='jpeg_pipe').output('/tmp/video.mp4', vcodec='libx264').overwrite_output().run_async(pipe_stdin=True)
    
    # Iterate jpeg_files, read the content of each file and write it to stdin
    for in_file in jpeg_files:
        with open(in_file, 'rb') as f:
            # Read the JPEG file content to jpeg_data (bytes array)
            jpeg_data = f.read()
    
            # Write JPEG data to stdin pipe of FFmpeg process
            process.stdin.write(jpeg_data)
    
    # Close stdin pipe - FFmpeg fininsh encoding the output file.
    process.stdin.close()
    process.wait()