5

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()

se7en
  • 671
  • 4
  • 18

1 Answers1

3

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()
Rotem
  • 30,366
  • 4
  • 32
  • 65
  • The second option is giving me a BrokenPipeError. `BrokenPipeError: [Errno 32] Broken pipe` – se7en Apr 22 '21 at 10:13
  • I can't tell why... Make sure that all the input images in the list are valid JPEG images. Try using full path for the input images and for the output video file (just for testing). – Rotem Apr 22 '21 at 10:56
  • 1
    somehow removing `f='jpeg_pipe'` fixed it. – se7en Apr 22 '21 at 20:53
  • I guess FFmpeg is smart enough to automatically identify the input format. `f='jpeg_pipe'` should have worked - it's working in my machine (it could be FFmpeg version differences and it could also be input images difference). `f='image2pipe'` should also work. – Rotem Apr 22 '21 at 22:07