Opened 19 months ago

Last modified 19 months ago

#8644 new enhancement

Demux multi-image TIFF beyond first image

Reported by: adaerr Owned by:
Priority: wish Component: undetermined
Version: git-master Keywords: tif
Cc: Blocked By:
Blocking: Reproduced by developer: no
Analyzed by developer: no

Description

I would like to create a video from a TIFF file containing a sequence
of images of the same size. However currently ffmpeg decodes only the first image from the TIFF input.

TIFF files containing multiple images are indeed possible, and used as
native format by software ranging from scan software to scientific
image processing software like ImageJ. It would be convenient if
ffmpeg could decode/demux/process the sequence of images as a video input
just as it can for a collection of image files. In other words, I
would expect

ffmpeg -i all-frames.tif video-from-tif.webm

to produce the same video as that obtained by splitting the TIFF into
separate files and running

ffmpeg -i single-frame-%03d.png video-from-png.webm

The observed behaviour (see full output below) is that ffmpeg only
reads a single image from TIFF input, so that video-from-tif.webm
contains only one frame, where video-from-png.webm contains the same
number of frames as there are PNG files in the input.

To reproduce, I attach[*] a sample TIFF with 20 frames:

20-frame-stack_416x160_grayscale-8bpp.tif

[*] Sorry, I failed to connect and upload the sample to the ftp server as specified in the instructions at http://www.ffmpeg.org/bugreports.html

A test stack can also easily be generated by the convert tool from the
ImageMagick software. The following command line for example produces
a TIFF containing 30 256x256 grayscale (8bpp) images showing a
gradient in varying orientation.

convert -size 256x256 gradient: -duplicate 29 -distort SRT '%[fx:360*t/n]' -depth 8 30-frame-stack_256x256_grayscale-8pp.tif

Here is the full log produced by a recent build from git sources:

Log level: 48
Command line:
/home/adrian/.local/bin/ffmpeg -report -i 20-frame-stack_416x160_grayscale-8bpp.tif -y out.webm
ffmpeg version N-97504-g1128aa8753 Copyright (c) 2000-2020 the FFmpeg developers
  built with gcc 9 (Debian 9.3.0-10)
  configuration: --prefix=/home/adrian/.local --enable-gpl --enable-version3 --enable-nonfree --enable-shared --enable-pthreads --enable-libfreetype --enable-fontconfig --enable-libass --enable-gnutls --enable-librtmp --enable-libxcb --enable-libmp3lame --enable-libvorbis --enable-libspeex --enable-libopus --enable-libgsm --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvo-amrwbenc --enable-libx264 --enable-libxvid --enable-libtheora --enable-libvpx --enable-libopenjpeg --enable-frei0r --enable-libmodplug --enable-libzmq --enable-ladspa --enable-libssh --enable-libzvbi --enable-libgme --enable-libwavpack --enable-libwebp --enable-libx265 --enable-opengl --enable-librubberband --enable-libxml2
  libavutil      56. 43.100 / 56. 43.100
  libavcodec     58. 82.100 / 58. 82.100
  libavformat    58. 42.101 / 58. 42.101
  libavdevice    58.  9.103 / 58.  9.103
  libavfilter     7. 79.100 /  7. 79.100
  libswscale      5.  6.101 /  5.  6.101
  libswresample   3.  6.100 /  3.  6.100
  libpostproc    55.  6.100 / 55.  6.100
Splitting the commandline.
Reading option '-report' ... matched as option 'report' (generate a report) with argument '1'.
Reading option '-i' ... matched as input url with argument '20-frame-stack_416x160_grayscale-8bpp.tif'.
Reading option '-y' ... matched as option 'y' (overwrite output files) with argument '1'.
Reading option 'out.webm' ... matched as output url.
Finished splitting the commandline.
Parsing a group of options: global .
Applying option report (generate a report) with argument 1.
Applying option y (overwrite output files) with argument 1.
Successfully parsed a group of options.
Parsing a group of options: input url 20-frame-stack_416x160_grayscale-8bpp.tif.
Successfully parsed a group of options.
Opening an input file: 20-frame-stack_416x160_grayscale-8bpp.tif.
[NULL @ 0x562105205440] Opening '20-frame-stack_416x160_grayscale-8bpp.tif' for reading
[file @ 0x562105205f00] Setting default whitelist 'file,crypto,data'
[tiff_pipe @ 0x562105205440] Format tiff_pipe probed with size=2048 and score=51
[tiff_pipe @ 0x562105205440] Before avformat_find_stream_info() pos: 0 bytes read:32768 seeks:0 nb_streams:1
[tiff_pipe @ 0x562105205440] parser not found for codec tiff, packets or times may be invalid.
[tiff_pipe @ 0x562105205440] parser not found for codec tiff, packets or times may be invalid.
[tiff_pipe @ 0x562105205440] After avformat_find_stream_info() pos: 1334978 bytes read:1334978 seeks:0 frames:1
Input #0, tiff_pipe, from '20-frame-stack_416x160_grayscale-8bpp.tif':
  Duration: N/A, bitrate: N/A
    Stream #0:0, 1, 1/25: Video: tiff, gray, 416x160 [SAR 1:1 DAR 13:5], 25 tbr, 25 tbn, 25 tbc
Successfully opened the file.
Parsing a group of options: output url out.webm.
Successfully parsed a group of options.
Opening an output file: out.webm.
[file @ 0x562105218540] Setting default whitelist 'file,crypto,data'
Successfully opened the file.
detected 4 logical cores
Stream mapping:
  Stream #0:0 -> #0:0 (tiff (native) -> vp9 (libvpx-vp9))
Press [q] to stop, [?] for help
cur_dts is invalid st:0 (0) [init:0 i_done:0 finish:0] (this is harmless if it occurs once at the start per stream)
cur_dts is invalid st:0 (0) [init:0 i_done:0 finish:0] (this is harmless if it occurs once at the start per stream)
[graph 0 input from stream 0:0 @ 0x562105355900] Setting 'video_size' to value '416x160'
[graph 0 input from stream 0:0 @ 0x562105355900] Setting 'pix_fmt' to value '8'
[graph 0 input from stream 0:0 @ 0x562105355900] Setting 'time_base' to value '1/25'
[graph 0 input from stream 0:0 @ 0x562105355900] Setting 'pixel_aspect' to value '1/1'
[graph 0 input from stream 0:0 @ 0x562105355900] Setting 'frame_rate' to value '25/1'
[graph 0 input from stream 0:0 @ 0x562105355900] w:416 h:160 pixfmt:gray tb:1/25 fr:25/1 sar:1/1
[format @ 0x562105355d00] Setting 'pix_fmts' to value 'yuv420p|yuva420p|yuv422p|yuv440p|yuv444p|gbrp'
[auto_scaler_0 @ 0x56210535de00] Setting 'flags' to value 'bicubic'
[auto_scaler_0 @ 0x56210535de00] w:iw h:ih flags:'bicubic' interl:0
[format @ 0x562105355d00] auto-inserting filter 'auto_scaler_0' between the filter 'Parsed_null_0' and the filter 'format'
[AVFilterGraph @ 0x56210532d440] query_formats: 4 queried, 2 merged, 1 already done, 0 delayed
[auto_scaler_0 @ 0x56210535de00] picking gbrp out of 6 ref:gray alpha:0
[swscaler @ 0x56210535f300] Forcing full internal H chroma due to input having non subsampled chroma
[auto_scaler_0 @ 0x56210535de00] w:416 h:160 fmt:gray sar:1/1 -> w:416 h:160 fmt:gbrp sar:1/1 flags:0x4
[libvpx-vp9 @ 0x56210521ac40] v1.8.2
[libvpx-vp9 @ 0x56210521ac40] --prefix=/usr --enable-pic --enable-shared --disable-install-bins --disable-install-srcs --size-limit=16384x16384 --enable-postproc --enable-multi-res-encoding --enable-temporal-denoising --enable-vp9-temporal-denoising --enable-vp9-postproc --target=x86_64-linux-gcc
[libvpx-vp9 @ 0x56210521ac40] vpx_codec_enc_cfg
[libvpx-vp9 @ 0x56210521ac40] generic settings
  g_usage:                      0
  g_threads:                    8
  g_profile:                    1
  g_w:                          320
  g_h:                          240
  g_bit_depth:                  8
  g_input_bit_depth:            8
  g_timebase:                   {1/30}
  g_error_resilient:            0
  g_pass:                       0
  g_lag_in_frames:              25
[libvpx-vp9 @ 0x56210521ac40] rate control settings
  rc_dropframe_thresh:          0
  rc_resize_allowed:            0
  rc_resize_up_thresh:          60
  rc_resize_down_thresh:        30
  rc_end_usage:                 0
  rc_twopass_stats_in:          (nil)(0)
  rc_target_bitrate:            256
[libvpx-vp9 @ 0x56210521ac40] quantizer settings
  rc_min_quantizer:             0
  rc_max_quantizer:             63
[libvpx-vp9 @ 0x56210521ac40] bitrate tolerance
  rc_undershoot_pct:            25
  rc_overshoot_pct:             25
[libvpx-vp9 @ 0x56210521ac40] temporal layering settings
  ts_number_layers:             1
[libvpx-vp9 @ 0x56210521ac40] 
  layer_target_bitrate:         0 0 0 0 0 
[libvpx-vp9 @ 0x56210521ac40] 
  ts_rate_decimator:            0 0 0 0 0 
[libvpx-vp9 @ 0x56210521ac40] 
  ts_periodicity:               0
[libvpx-vp9 @ 0x56210521ac40] 
  ts_layer_id:                  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
[libvpx-vp9 @ 0x56210521ac40] decoder buffer model
  rc_buf_sz:                    6000
  rc_buf_initial_sz:            4000
  rc_buf_optimal_sz:            5000
[libvpx-vp9 @ 0x56210521ac40] 2 pass rate control settings
  rc_2pass_vbr_bias_pct:        50
  rc_2pass_vbr_minsection_pct:  0
  rc_2pass_vbr_maxsection_pct:  2000
[libvpx-vp9 @ 0x56210521ac40]   rc_2pass_vbr_corpus_complexity:0
[libvpx-vp9 @ 0x56210521ac40] keyframing settings
  kf_mode:                      1
  kf_min_dist:                  0
  kf_max_dist:                  128
[libvpx-vp9 @ 0x56210521ac40] 
[libvpx-vp9 @ 0x56210521ac40] Neither bitrate nor constrained quality specified, using default CRF of 32
[libvpx-vp9 @ 0x56210521ac40] vpx_codec_enc_cfg
[libvpx-vp9 @ 0x56210521ac40] generic settings
  g_usage:                      0
  g_threads:                    4
  g_profile:                    1
  g_w:                          416
  g_h:                          160
  g_bit_depth:                  8
  g_input_bit_depth:            8
  g_timebase:                   {1/25}
  g_error_resilient:            0
  g_pass:                       0
  g_lag_in_frames:              25
[libvpx-vp9 @ 0x56210521ac40] rate control settings
  rc_dropframe_thresh:          0
  rc_resize_allowed:            0
  rc_resize_up_thresh:          60
  rc_resize_down_thresh:        30
  rc_end_usage:                 3
  rc_twopass_stats_in:          (nil)(0)
  rc_target_bitrate:            256
[libvpx-vp9 @ 0x56210521ac40] quantizer settings
  rc_min_quantizer:             0
  rc_max_quantizer:             63
[libvpx-vp9 @ 0x56210521ac40] bitrate tolerance
  rc_undershoot_pct:            25
  rc_overshoot_pct:             25
[libvpx-vp9 @ 0x56210521ac40] temporal layering settings
  ts_number_layers:             1
[libvpx-vp9 @ 0x56210521ac40] 
  layer_target_bitrate:         0 0 0 0 0 
[libvpx-vp9 @ 0x56210521ac40] 
  ts_rate_decimator:            0 0 0 0 0 
[libvpx-vp9 @ 0x56210521ac40] 
  ts_periodicity:               0
[libvpx-vp9 @ 0x56210521ac40] 
  ts_layer_id:                  0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
[libvpx-vp9 @ 0x56210521ac40] decoder buffer model
  rc_buf_sz:                    6000
  rc_buf_initial_sz:            4000
  rc_buf_optimal_sz:            5000
[libvpx-vp9 @ 0x56210521ac40] 2 pass rate control settings
  rc_2pass_vbr_bias_pct:        50
  rc_2pass_vbr_minsection_pct:  0
  rc_2pass_vbr_maxsection_pct:  2000
[libvpx-vp9 @ 0x56210521ac40]   rc_2pass_vbr_corpus_complexity:0
[libvpx-vp9 @ 0x56210521ac40] keyframing settings
  kf_mode:                      1
  kf_min_dist:                  0
  kf_max_dist:                  128
[libvpx-vp9 @ 0x56210521ac40] 
[libvpx-vp9 @ 0x56210521ac40] vpx_codec_control
[libvpx-vp9 @ 0x56210521ac40]   VP8E_SET_CPUUSED:             1
[libvpx-vp9 @ 0x56210521ac40]   VP8E_SET_ARNR_MAXFRAMES:      0
[libvpx-vp9 @ 0x56210521ac40]   VP8E_SET_ARNR_STRENGTH:       3
[libvpx-vp9 @ 0x56210521ac40]   VP8E_SET_ARNR_TYPE:           3
[libvpx-vp9 @ 0x56210521ac40]   VP8E_SET_STATIC_THRESHOLD:    0
[libvpx-vp9 @ 0x56210521ac40]   VP8E_SET_CQ_LEVEL:            32
[libvpx-vp9 @ 0x56210521ac40]   VP9E_SET_COLOR_SPACE:         7
[libvpx-vp9 @ 0x56210521ac40]   VP9E_SET_COLOR_RANGE:         0
[libvpx-vp9 @ 0x56210521ac40]   VP9E_SET_TARGET_LEVEL:        255
[libvpx-vp9 @ 0x56210521ac40] Using deadline: 1000000
[webm @ 0x562105216480] get_metadata_duration returned: 0
Output #0, webm, to 'out.webm':
  Metadata:
    encoder         : Lavf58.42.101
    Stream #0:0, 0, 1/1000: Video: vp9 (libvpx-vp9), gbrp, 416x160 [SAR 1:1 DAR 13:5], q=-1--1, 25 fps, 1k tbn, 25 tbc
    Metadata:
      encoder         : Lavc58.82.100 libvpx-vp9
    Side data:
      cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: N/A
Clipping frame in rate conversion by 0.000008
cur_dts is invalid st:0 (0) [init:1 i_done:0 finish:0] (this is harmless if it occurs once at the start per stream)
cur_dts is invalid st:0 (0) [init:1 i_done:0 finish:0] (this is harmless if it occurs once at the start per stream)
[out_0_0 @ 0x56210535bb00] EOF on sink link out_0_0:default.
No more output streams to write to, finishing.
Automatically inserted bitstream filter 'vp9_superframe'; args=''
[webm @ 0x562105216480] Starting new cluster with timestamp 0 at offset 478 bytes
[webm @ 0x562105216480] Writing block of size 8070 with pts 0, dts 0, duration 40 at relative offset 3 in cluster at offset 478. TrackNumber 1, keyframe 1
[webm @ 0x562105216480] end duration = 40
[webm @ 0x562105216480] stream 0 end duration = 40
frame=    1 fps=0.0 q=0.0 Lsize=       8kB time=00:00:00.00 bitrate=68688.0kbits/s speed=0.0109x    
video:8kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 6.394052%
Input file #0 (20-frame-stack_416x160_grayscale-8bpp.tif):
  Input stream #0:0 (video): 1 packets read (1334978 bytes); 1 frames decoded; 
  Total: 1 packets (1334978 bytes) demuxed
Output file #0 (out.webm):
  Output stream #0:0 (video): 1 frames encoded; 1 packets muxed (8070 bytes); 
  Total: 1 packets (8070 bytes) muxed
1 frames successfully decoded, 0 decoding errors
[AVIOContext @ 0x56210521b380] Statistics: 0 seeks, 1 writeouts
[AVIOContext @ 0x56210520e2c0] Statistics: 1334978 bytes read, 0 seeks

Attachments (2)

20-frame-stack_416x160_grayscale-8bpp.tif (1.3 MB ) - added by adaerr 19 months ago.
TIFF file containing a sequence of (416x160 8bpp grayscale) images.
20-frame-stack_416x160_grayscale-8bpp_README.md (455 bytes ) - added by adaerr 19 months ago.
Description for the attached TIFF file

Download all attachments as: .zip

Change History (6)

by adaerr, 19 months ago

TIFF file containing a sequence of (416x160 8bpp grayscale) images.

by adaerr, 19 months ago

Description for the attached TIFF file

comment:1 by Carl Eugen Hoyos, 19 months ago

Keywords: tif added; tiff removed
Priority: normalwish

comment:2 by pdr0, 19 months ago

A workaround is to pipe ImageMagick to FFmpeg

eg. 10fps FFV1, MKV container

"convert" "20-frame-stack_416x160_grayscale-8bpp.tif" gray:- | ffmpeg -f rawvideo -s 416x160 -pix_fmt gray -r 10 -i - -c:v ffv1 -an im_pipe_to_ffmpeg_ffv1.mkv


comment:3 by adaerr, 19 months ago

Thanks for the comment. Although using ImageMagick to pipe the images into ffmpeg is indeed a workaround I should have mentioned, it works only for not too large files. The variant I use is

convert foo.tif ppm:- | ffmpeg -f image2pipe -framerate 15 -i - [...]

ImageMagick was not designed for processing long image sequences - though it has some animation support for gif etc - so this is slow and fails for large files: convert loads images into memory (can be extended by use of tmp dir and tuning magick's configuration to some extent) before outputting data, so memory usage increases with file size. Note that the limit file size is a fraction of the available cache size: the internal representation of images may have 16bit depth per channel, so 8bit gray is stored as 64bpp RGBA in memory/cache.

comment:4 by adaerr, 19 months ago

And while we're mentionning workarounds: for large files that I cannot process via ImageMagick, my workaround consists in opening the TIFF in ImageJ and saving it as uncompressed AVI, that works like a charm with ffmpeg.

Still it would be more convenient if ffmpeg, which already has a TIFF decoder, could properly demux multiple images from a TIFF file. Whence this ticket.

Note: See TracTickets for help on using tickets.