3

Hopefully an easy question for an ffmpeg expert!

I'm currently converting large (+6GB) mpeg video into an image sequence - which is working well using the below ffmpeg command:

ffmpeg -i "input.mpeg" -vf - fps=fps=2 -f image2 -qscale 1 -s 1026x768 "output%6d.jpg"

however i have to wait for the file to finish being written to disk before i kick off ffmpeg - but this takes a good hour or so to finish writing, but what i've noticed is that ffmpeg can start reading the file while its being written to disk - the only snag here is it gets to the end of the file and stops before the file has finished being written...

Question is, is there a way that ffmpeg can convert to an image sequence at the same pace the video is being written (and not exit out?)... or know to wait for the next frame to be written from the source. (unfortunately the input doesn't support streaming, I only get a network drive and file to work off.. ) I thought i read somewhere that ffmpeg can process at the video frame rate but cant seem to find this command for love or money in the doco!!

Thanks!

halfelf
  • 9,737
  • 13
  • 54
  • 63

1 Answers1

1

You need to replace the function call(s) ffmpeg uses to read the file with ones that will retry until the file is done being written.

First, you can write your own processor and provide a callback to ffio_init_context() that will retry reads until the file is completely written (you'd have to determine a method for your function to be able to tell that the file is done).

Second, you can determine what function calls ffmpeg uses to read the file (probably read() or fread()) and use LD_PRELOAD to interpose a replacement that will retry until the file is finished being written. It's a bit hackish but it can be made to work. Something like this (this is just off-the-cuff code to demonstrate how you could do it. If you're lucky this might even work...):

read.c:

// most libc implementations also provide another symbol
// for library functions that starts with "_"
extern ssize_t _read( int, void *, size-t );

ssize_t read( int fd, void *buffer, size_t bytes )
{
    ssize_t bytesRead;
    for ( ;; )
    {
        bytesRead = _read( fd, buffer, bytes );
        if ( bytesRead != 0 || fileIsComplete( fd ) )
        {
            break;
        }
    }

    return ( bytesRead );
}

You'd need to implement fileIsComplete() to check if the file has been completely written or not - and if the file isn't done, make it sleep for a short bit or you'll just spin like crazy. And if ffmpeg isn't using read(), you'll have to figure out what it is using, for example fread().

If libc doesn't have an alternate underscore-prefixed symbol for the function(s) ffmpeg uses to read the file, you'll have to do something like this (example is for fread():

fread.c:

// function pointer to the real fread() function
static size_t (*real_fread)( void *, size_t, size_t, FILE *) = NULL;

size_t fread( void *buffer, size_t size, size_t n, FILE *stream )
{
    // might need to mutex this for multithreaded apps
    if ( real_fread == NULL )
    {
        real_fread = dlsym( RTLD_NEXT, "fread" );
    }

    size_t result;

    for ( ;; )
    {
        result = real_fread( buffer, size, n, stream );
        if ( ( result != 0 ) || fileIsComplete( stream ) )
        {
            break;
        }
    }

    return( result );
}

Just compile your interposing C code into a shared object and use LD_PRELOAD to have ffmpeg use your interposed read() function. Note that in both cases you'll have to add the proper header files (or maybe skip them because you might get redeclaration errors - in which case you might have to provide proper definitions for values like RTLD_NEXT yourself).

Doing so can be tricky to get working right, as all calls to your interposing function(s) will go through your library for any process running with your LD_PRELOAD set. You'd probably do best with a wrapper script to set LD_PRELOAD and then run ffmpeg so only you only have to deal with making ffmpeg work with your interposing library.

And ffmpeg might not handle partial reads very well - you may have to modify your code to keep reading until the file is done or a certain number of bytes has been read, such as the requested number of bytes.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56