Difference between revisions of "LibVLC SampleCode Thumbnailer"

From VideoLAN Wiki
Jump to navigation Jump to search
(use libvlc events)
Line 3: Line 3:
 
   /* Copyright [[User:Funman|Rafaël Carré]] (licence [http://en.wikipedia.org/wiki/WTFPL WTFPL]) */
 
   /* Copyright [[User:Funman|Rafaël Carré]] (licence [http://en.wikipedia.org/wiki/WTFPL WTFPL]) */
 
<pre>
 
<pre>
 +
/* A video thumbnailer compatible with nautilus */
 +
/* Copyright © 2007-2008 Rafaël Carré <funman@videolanorg> */
 +
 
#include <stdio.h>
 
#include <stdio.h>
 
#include <vlc/libvlc.h>
 
#include <vlc/libvlc.h>
Line 8: Line 11:
 
#include <string.h>
 
#include <string.h>
 
#include <unistd.h>
 
#include <unistd.h>
 +
#include <locale.h>
 +
#include <sys/types.h>
 +
#include <sys/stat.h>
 +
 +
/* gcc -ansi -Wall -Werror -lvlc-control vlc-video-thumbnailer.c */
 +
 +
#if 1
 +
#  define DEBUG( s ) fprintf( stderr, s"\n" );
 +
#else
 +
#  define DEBUG( s )
 +
#endif
  
 
/* position to seek to (out of 1.) */
 
/* position to seek to (out of 1.) */
 
#define POS 0.3
 
#define POS 0.3
 +
 +
/* delay before aborting ( real delay will be * 2 ) */
 +
#define MAX_DELAY 5.0
  
 
/* for the callback to notify the main thread that the position changed */
 
/* for the callback to notify the main thread that the position changed */
Line 23: Line 40:
 
     if( ev->type == libvlc_MediaInstancePositionChanged )
 
     if( ev->type == libvlc_MediaInstancePositionChanged )
 
     {
 
     {
         /* XXX: add a tolerance ? (POS +/- 10%) */
+
         float new_pos;
         if( ev->u.media_instance_position_changed.new_position >= POS )
+
         new_pos = ev->u.media_instance_position_changed.new_position;
             fini = 1;
+
        if( new_pos >= POS - ( POS / 10 ) )
 +
        {
 +
            DEBUG( "Position set" );
 +
             fini = 1; /* now we can take the snapshot */
 +
        }
 
     }
 
     }
 
     else
 
     else
Line 31: Line 52:
 
         fprintf( stderr, "Error: catched event %s\n",  
 
         fprintf( stderr, "Error: catched event %s\n",  
 
                 libvlc_event_type_name( ev->type ) );
 
                 libvlc_event_type_name( ev->type ) );
 +
        exit(1);
 
     }
 
     }
 
}
 
}
Line 46: Line 68:
 
}
 
}
  
 +
/* nautilus doesn't use .png extension, and vlc detects the filetype with the
 +
* extension, so we use a temporary file to be sure we'll use png */
 
#define TEMP "/tmp/vlc-video-thumbnailer.png"
 
#define TEMP "/tmp/vlc-video-thumbnailer.png"
  
Line 65: Line 89:
 
     }
 
     }
  
     const char *input = argv[1];
+
     /* mandatory to support UTF-8 filenames (provided the locale is well set)*/
     const char *output = argv[2];
+
    setlocale( LC_ALL, getenv( "LANG" ) );
     int i_width = 0;
+
 
    int i_height = 0;
+
     const char const *input, *output;
 +
     int i_width, i_height = 0;
  
 
     if( argc == 5 )
 
     if( argc == 5 )
 
     {
 
     {
         if( strncmp( argv[1], "-s", 3 ) )
+
         if( strcmp( argv[1], "-s" ) )
 
         {
 
         {
 
             usage();
 
             usage();
Line 80: Line 105:
 
         input = argv[3];
 
         input = argv[3];
 
         output = argv[4];
 
         output = argv[4];
 +
    }
 +
    else
 +
    {
 +
        input = argv[1];
 +
        output = argv[2];
 +
        i_width = 0;
 
     }
 
     }
  
 
     libvlc_exception_init( &ex );
 
     libvlc_exception_init( &ex );
  
 +
    /* libvlc settings */
 
     const char* const args[] = {
 
     const char* const args[] = {
 
         "-I", "dummy",                      /* no interface */
 
         "-I", "dummy",                      /* no interface */
 
         "--vout", "dummy",                  /* we don't want video (output) */
 
         "--vout", "dummy",                  /* we don't want video (output) */
 
         "--no-audio",                      /* we don't want audio */
 
         "--no-audio",                      /* we don't want audio */
         "--verbose=1",                      /* show only errors & warnings */
+
         "--verbose=0",                      /* show only errors */
 
         "--no-media-library",              /* don't want that */
 
         "--no-media-library",              /* don't want that */
 
         "--services-discovery", "",        /* nor that */
 
         "--services-discovery", "",        /* nor that */
 
         "--no-video-title-show",            /* nor the filename displayed */
 
         "--no-video-title-show",            /* nor the filename displayed */
 
         "--no-stats",                      /* no stats */
 
         "--no-stats",                      /* no stats */
 +
        "--config", "/dev/null",            /* don't overwrite the config */
 
         "--no-sub-autodetect",              /* don't want subtitles */
 
         "--no-sub-autodetect",              /* don't want subtitles */
 
         "--control", "",                    /* don't want interface (again) */
 
         "--control", "",                    /* don't want interface (again) */
Line 106: Line 139:
 
     libvlc_media_instance_t *mi;
 
     libvlc_media_instance_t *mi;
 
     libvlc_media_descriptor_t *md;
 
     libvlc_media_descriptor_t *md;
 +
  
 
     md = libvlc_media_descriptor_new( libvlc, input, &ex );
 
     md = libvlc_media_descriptor_new( libvlc, input, &ex );
Line 112: Line 146:
 
     mi = libvlc_media_instance_new_from_media_descriptor( md, &ex );
 
     mi = libvlc_media_instance_new_from_media_descriptor( md, &ex );
 
     catch();
 
     catch();
   
+
 
 
     libvlc_media_descriptor_release( md );
 
     libvlc_media_descriptor_release( md );
  
Line 130: Line 164:
 
     catch();
 
     catch();
  
     int max = 10;  /* don't wait more than 10s */
+
     float max = MAX_DELAY;  /* don't wait more MAX_DELAY seconds */
     while( !fini && max-- )  /* wait for the event */
+
     while( !fini && ( max -= .2 ) > 0 )  /* wait for the position changed event */
         sleep( 1 );
+
         usleep( 200000 );
  
 
     libvlc_event_detach( em, libvlc_MediaInstancePositionChanged,
 
     libvlc_event_detach( em, libvlc_MediaInstancePositionChanged,
Line 138: Line 172:
 
     catch();
 
     catch();
  
 +
    DEBUG( "Taking snapshot" );
 
     libvlc_video_take_snapshot( mi, TEMP, i_width, i_height, &ex );
 
     libvlc_video_take_snapshot( mi, TEMP, i_width, i_height, &ex );
 
     catch();
 
     catch();
  
     sleep( 1 ); /* wait for the snapshot to be written */
+
     sleep( 1 ); /* be sure that the snapshot has been written */
 +
 
 +
    DEBUG( "Stopping" );
 +
    libvlc_media_instance_stop( mi, &ex );
 +
    catch();
 +
 
 +
    max = MAX_DELAY;
 +
    while( ( max -= .2 ) > 0 )
 +
    {
 +
        struct stat st;
 +
        if( stat( TEMP, &st ) == 0 )
 +
            break;
 +
        DEBUG( TEMP" doesn't exist" );
 +
        if( max <= .2 )
 +
        {
 +
            DEBUG( "Snapshot has not been written :(" );
 +
            goto end;
 +
        }
 +
        usleep( 200000 );
 +
    }
  
 +
    DEBUG( "Moving snapshot" );
 
     char *mv;
 
     char *mv;
     if( asprintf( &mv, "mv %s %s", TEMP, output ) == -1 )
+
     if( asprintf( &mv, "mv \"%s\" \"%s\"", TEMP, output ) == -1 )
 
         return 1;
 
         return 1;
 
     system( mv );
 
     system( mv );
 
     free( mv );
 
     free( mv );
  
    libvlc_media_instance_stop( mi, &ex );
+
end:
    catch();
 
 
 
 
     libvlc_media_instance_release( mi );
 
     libvlc_media_instance_release( mi );
  

Revision as of 15:20, 17 January 2008

This sample code will generate a thumbnail from any media. It can be used by nautilus instead of totem-video-thumbnailer

 /* Copyright Rafaël Carré (licence WTFPL) */
/* A video thumbnailer compatible with nautilus */
/* Copyright © 2007-2008 Rafaël Carré <funman@videolanorg> */

#include <stdio.h>
#include <vlc/libvlc.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <locale.h>
#include <sys/types.h>
#include <sys/stat.h>

/* gcc -ansi -Wall -Werror -lvlc-control vlc-video-thumbnailer.c */

#if 1
#   define DEBUG( s ) fprintf( stderr, s"\n" );
#else
#   define DEBUG( s )
#endif

/* position to seek to (out of 1.) */
#define POS 0.3

/* delay before aborting ( real delay will be * 2 ) */
#define MAX_DELAY 5.0

/* for the callback to notify the main thread that the position changed */
static int fini = 0;

/* to catch problems */
static libvlc_exception_t ex;

/* "position changed" callback */
static void callback( const libvlc_event_t *ev, void *param )
{
    if( ev->type == libvlc_MediaInstancePositionChanged )
    {
        float new_pos;
        new_pos = ev->u.media_instance_position_changed.new_position;
        if( new_pos >= POS - ( POS / 10 ) )
        {
            DEBUG( "Position set" );
            fini = 1; /* now we can take the snapshot */
        }
    }
    else
    {
        fprintf( stderr, "Error: catched event %s\n", 
                libvlc_event_type_name( ev->type ) );
        exit(1);
    }
}

static void catch (void)
{
    if (libvlc_exception_raised (&ex))
    {
        fprintf (stderr, "Exception: %s\n",
                 libvlc_exception_get_message (&ex));
        exit(1);
    }

    libvlc_exception_clear (&ex);
}

/* nautilus doesn't use .png extension, and vlc detects the filetype with the
 * extension, so we use a temporary file to be sure we'll use png */
#define TEMP "/tmp/vlc-video-thumbnailer.png"

#define usage() \
        fprintf( stderr, \
            "Usage: %s input output\n" \
            "input being any video VLC can read, and output a png file\n" \
            , argv[0] )

int main( int argc, const char **argv )
{
    if( argc != 3 && argc != 5 )
    {
        usage();
        if( argc == 2 && ( !strcmp( argv[1], "-h" ) || strcmp( argv[1], "--help") ) )
            return 0;
        else
            return 1;
    }

    /* mandatory to support UTF-8 filenames (provided the locale is well set)*/
    setlocale( LC_ALL, getenv( "LANG" ) );

    const char const *input, *output;
    int i_width, i_height = 0;

    if( argc == 5 )
    {
        if( strcmp( argv[1], "-s" ) )
        {
            usage();
            return 1;
        }
        i_width = atoi( argv[2] );
        input = argv[3];
        output = argv[4];
    }
    else
    {
        input = argv[1];
        output = argv[2];
        i_width = 0;
    }

    libvlc_exception_init( &ex );

    /* libvlc settings */
    const char* const args[] = {
        "-I", "dummy",                      /* no interface */
        "--vout", "dummy",                  /* we don't want video (output) */
        "--no-audio",                       /* we don't want audio */
        "--verbose=0",                      /* show only errors */
        "--no-media-library",               /* don't want that */
        "--services-discovery", "",         /* nor that */
        "--no-video-title-show",            /* nor the filename displayed */
        "--no-stats",                       /* no stats */
        "--config", "/dev/null",            /* don't overwrite the config */
        "--no-sub-autodetect",              /* don't want subtitles */
        "--control", "",                    /* don't want interface (again) */
        "--no-inhibit",                     /* i say no interface ! */
        "--no-disable-screensaver",         /* wanna fight ? */
        "--extraintf", ""                   /* ok, it will be a piece of cake */
    };

    int nargs = sizeof(args) / sizeof(args[0]);
    libvlc_instance_t *libvlc = libvlc_new( nargs, args, &ex );
    catch();

    libvlc_media_instance_t *mi;
    libvlc_media_descriptor_t *md;


    md = libvlc_media_descriptor_new( libvlc, input, &ex );
    catch();
   
    mi = libvlc_media_instance_new_from_media_descriptor( md, &ex );
    catch();

    libvlc_media_descriptor_release( md );

    libvlc_media_instance_play( mi, &ex );
    catch();

    /* avoid introduction */
    libvlc_media_instance_set_position( mi, POS, &ex );
    catch();

    libvlc_event_manager_t *em;
    em = libvlc_media_instance_event_manager( mi, &ex );
    catch();

    libvlc_event_attach( em, libvlc_MediaInstancePositionChanged,
                         callback, NULL, &ex );
    catch();

    float max = MAX_DELAY;   /* don't wait more MAX_DELAY seconds */
    while( !fini && ( max -= .2 ) > 0 )  /* wait for the position changed event */
        usleep( 200000 );

    libvlc_event_detach( em, libvlc_MediaInstancePositionChanged,
                         callback, NULL, &ex );
    catch();

    DEBUG( "Taking snapshot" );
    libvlc_video_take_snapshot( mi, TEMP, i_width, i_height, &ex );
    catch();

    sleep( 1 ); /* be sure that the snapshot has been written */

    DEBUG( "Stopping" );
    libvlc_media_instance_stop( mi, &ex );
    catch();

    max = MAX_DELAY;
    while( ( max -= .2 ) > 0 )
    {
        struct stat st;
        if( stat( TEMP, &st ) == 0 )
            break;
        DEBUG( TEMP" doesn't exist" );
        if( max <= .2 )
        {
            DEBUG( "Snapshot has not been written :(" );
            goto end;
        }
        usleep( 200000 );
    }

    DEBUG( "Moving snapshot" );
    char *mv;
    if( asprintf( &mv, "mv \"%s\" \"%s\"", TEMP, output ) == -1 )
        return 1;
    system( mv );
    free( mv );

end:
    libvlc_media_instance_release( mi );

    libvlc_release( libvlc, &ex );
    catch();

    return 0;
}