1

ffmpeg can convert sequences of images to movies and is capable of producing lossless output. Is it possible to directly produce a movie from a multi-page tiff file? If I try one of my multipage tiffs ffmpeg only processes the first frame.

Marius
  • 121
  • 1
  • 5

2 Answers2

3

Workaround

FFmpeg does not support multipage tiff yet, even in 2021! In the actual FFmpeg feature ticket, I found a workaround: use convert (from ImageMagick) to pipe individual images to FFmpeg.
Ref: https://trac.ffmpeg.org/ticket/8644

In my case, the file format is gray16le (16bits grayscale LE, from a thermal IR camera):

convert sample.tif gray:- | ffmpeg -f rawvideo -s 1280x1024 -pix_fmt gray16le -r 30 -i - -vcodec ffv1 sample-ffv1.mkv

The ffv1 is a lossless format, but it is still compressed. In my case it was about 30% of the original size.

I used the -r 30 to set the output framerate.

Note

Some may wonder why we need lossless 16bit format: I needed to simulate a 16bit grayscale V4L source using V4L-loopback:

ffmpeg -stream_loop -1 -re -i sample-ffv1.mkv -map 0:v -f v4l2 /dev/video0
1

What about this trick. It will create a stream process that receives image binaries from a tiff file:

import subprocess
from PIL import Image
import numpy as np

Define the input TIFF file and output video file

tiff_file = 'output.tiff' # Input multi-page TIFF file video_file = 'output.mp4' # Output video file

Open the multi-page TIFF file

with Image.open(tiff_file) as img: # Prepare the FFmpeg command command = [ 'ffmpeg', '-y', # Overwrite output files without asking '-f', 'rawvideo', # Input format '-pixel_format', 'rgba', # Set the pixel format to RGBA '-video_size', f'{img.width}x{img.height}', # Set video size '-framerate', '25', # Set frame rate '-i', '-', # Input from stdin '-c:v', 'libx264', # Video codec '-pix_fmt', 'yuv420p', # Pixel format for compatibility video_file ]

# Start the FFmpeg process
process = subprocess.Popen(command, stdin=subprocess.PIPE)

# Iterate over each frame in the TIFF
for i in range(img.n_frames):
    img.seek(i)  # Move to the next frame
    # Convert the image to a raw byte array and write to the FFmpeg stdin
    process.stdin.write(img.tobytes())

# Close the input stream and wait for the process to finish
process.stdin.close()
process.wait()

print("Video created successfully!")