mkvmerge: lseek fails when -o is given a FIFO file
Created by: tfiskgul
First off, thanks for a great application! =) I have used mkvmerge GUI on Windows for some time, and I am now using mkvmerge on Linux in a slightly more non-standard way.
I am running mkvmerge with a FIFO file as output; $ mkfifo test.mkv $ mkvmerge -o test.mkv input.mkv
The reason for this is two-fold:
- I want the mkvmerge to block, and write the output file at the speed of the reader (think streaming).
- I want to consume little/no disk or memory space (except any buffers and the mkvmerge process itself of course).
I get the following warning: "Warning: kax_reader_c::read(): an unknown exception occurred. This usually indicates a damaged file structure. The file will not be processed further."
And very much like the warning says, I get an mkv without the video stream.
Running the same command via strace shows a seek operation (which always fails on FIFOs due to their nature):
$ strace mkvmerge -o test.mkv input.mkv [...] stat("test.mkv", {st_mode=S_IFIFO|0644, st_size=0, ...}) = 0 open("test.mkv", O_RDWR|O_CREAT|O_TRUNC, 0666) = 5 brk(0x278b000) = 0x278b000 write(1, "The file 'test.mkv' has been ope"..., 49The file 'test.mkv' has been opened for writing. ) = 49 [...] fstat(5, {st_mode=S_IFIFO|0644, st_size=0, ...}) = 0 fstat(5, {st_mode=S_IFIFO|0644, st_size=0, ...}) = 0 lseek(5, 0, SEEK_END) = -1 ESPIPE (Illegal seek) write(1, "Warning: kax_reader_c::read(): a"..., 151Warning: kax_reader_c::read(): an unknown exception occurred. This usually indicates a damaged file structure. The file will not be processed further. ) = 151
The problem is lseek(5, 0, SEEK_END)
Which fails with ESPIPE (Illegal seek). This SEEK_END flag, according to the man page, means "The file offset is set to the size of the file plus offset bytes."
The problem is caught in the function kax_reader_c::read in r_matroska.cpp: https://github.com/mbunkus/mkvtoolnix/blob/3c9ae0ce98116f5e08b0806fdb29b7fd785814fc/src/input/r_matroska.cpp#L2195
So it seems it seeks to the end of the file, +0 bytes. This is fine for normal files, but for streams (like FIFOs and stdout) it is problematic.
Is there any possibility we can add a command line flag, for example --no-output-seek, to avoid this behavior?
If --no-output-seek is specified, it would not do the lseek syscall, and only require the fstat to return 0 size, and simply start writing to the file from the start.