Difference between revisions of "LibVLC SampleCode Thumbnailer"
Jump to navigation
Jump to search
Line 1: | Line 1: | ||
This sample code will generate a thumbnail from any media. | This sample code will generate a thumbnail from any media. | ||
+ | |||
+ | Using VLC 1.2 API (libvlc 5.1.0), last updated 2010, October 25th. | ||
+ | |||
It can be used by nautilus instead of totem-video-thumbnailer | It can be used by nautilus instead of totem-video-thumbnailer | ||
/* 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 */ | /* A video thumbnailer compatible with nautilus */ | ||
− | /* Copyright © 2007- | + | /* Copyright © 2007-2010 Rafaël Carré <funman@videolanorg> */ |
+ | #include <assert.h> | ||
#include <stdio.h> | #include <stdio.h> | ||
− | |||
− | |||
− | |||
− | |||
#include <stdlib.h> | #include <stdlib.h> | ||
#include <string.h> | #include <string.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
#include <locale.h> | #include <locale.h> | ||
− | |||
− | |||
− | /* gcc - | + | #include <vlc/vlc.h> |
+ | |||
+ | /* gcc -pedantic -Wall -Werror -Wextra `pkg-config --cflags --libs libvlc` */ | ||
+ | |||
+ | /* position at which the snapshot is taken */ | ||
+ | #define VLC_THUMBNAIL_POSITION (30./100.) | ||
− | + | static void usage(const char *name, int ret) | |
− | + | { | |
− | + | fprintf(stderr, "Usage: %s [-w width] <video> <output.png>\n", name); | |
− | + | exit(ret); | |
− | + | } | |
− | /* | + | /* extracts options from command line */ |
− | + | static void cmdline(int argc, const char **argv, const char **in, | |
+ | char **out, char **out_with_ext, int *w) | ||
+ | { | ||
+ | int idx = 1; | ||
+ | size_t len; | ||
− | + | if (argc != 3 && argc != 5) | |
− | + | usage(argv[0], argc != 2 || strcmp(argv[1], "-h")); | |
− | + | *w = 0; | |
− | |||
− | + | if (argc == 5) { | |
− | + | if (strcmp(argv[1], "-w")) | |
+ | usage(argv[0], 1); | ||
− | /* " | + | idx += 2; /* skip "-w width" */ |
− | + | *w = atoi(argv[2]); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | ||
− | + | *in = argv[idx++]; | |
− | + | *out = strdup(argv[idx++]); | |
− | + | assert(*out); | |
− | + | ||
+ | len = strlen(*out); | ||
+ | if (len >= 4 && !strcmp(*out + len - 4, ".png")) { | ||
+ | *out_with_ext = *out; | ||
+ | return; | ||
} | } | ||
+ | |||
+ | /* We need to add .png extension to filename, | ||
+ | * VLC relies on it to detect output format, | ||
+ | * and nautilus doesn't give filenames ending in .png */ | ||
+ | |||
+ | *out_with_ext = malloc(len + sizeof ".png"); | ||
+ | assert(*out_with_ext); | ||
+ | strcpy(*out_with_ext, *out); | ||
+ | strcat(*out_with_ext, ".png"); | ||
} | } | ||
− | static | + | static libvlc_instance_t *create_libvlc(void) |
{ | { | ||
− | + | static const char* const args[] = { | |
− | + | "--intf", "dummy", /* no interface */ | |
− | + | "--vout", "dummy", /* we don't want video (output) */ | |
− | + | "--no-audio", /* we don't want audio (decoding) */ | |
− | } | + | "--no-video-title-show", /* nor the filename displayed */ |
+ | "--no-stats", /* no stats */ | ||
+ | "--no-sub-autodetect-file", /* we don't want subtitles */ | ||
+ | "--no-inhibit", /* we don't want interfaces */ | ||
+ | "--no-disable-screensaver", /* we don't want interfaces */ | ||
+ | #if 0 | ||
+ | "--verbose=2", /* full log */ | ||
+ | #endif | ||
+ | }; | ||
− | + | return libvlc_new(sizeof args / sizeof *args, args); | |
} | } | ||
− | + | static void callback(const libvlc_event_t *ev, void *param) | |
− | + | { | |
− | + | float new_position = ev->u.media_player_position_changed.new_position; | |
− | + | switch (ev->type) { | |
− | |||
− | |||
− | |||
− | |||
− | + | case libvlc_MediaPlayerPositionChanged: | |
− | { | + | if (new_position >= VLC_THUMBNAIL_POSITION * .9) { /* 90% margin */ |
− | + | *(int*)param = 1; | |
− | + | } | |
− | + | break; | |
− | + | case libvlc_MediaPlayerSnapshotTaken: | |
− | + | *(int*)param = 1; | |
− | + | break; | |
− | + | ||
+ | default: | ||
+ | assert(0); | ||
} | } | ||
+ | } | ||
− | + | /* FIXME: should use pthread notification */ | |
− | + | static void event_wait(const char *error, int *f) | |
+ | { | ||
+ | #define VLC_THUMBNAIL_TIMEOUT 5.0 /* 5 secs */ | ||
+ | #define VLC_THUMBNAIL_LOOP_STEP 0.2 /* 200 ms */ | ||
− | + | float max = VLC_THUMBNAIL_TIMEOUT; | |
− | + | while ((max -= VLC_THUMBNAIL_LOOP_STEP) > 0.) { | |
+ | if (*f) | ||
+ | return; | ||
− | + | usleep(VLC_THUMBNAIL_LOOP_STEP * 1000000); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
− | + | fprintf(stderr, | |
+ | "%s (timeout after %.2f secs!\n", error, VLC_THUMBNAIL_TIMEOUT); | ||
+ | exit(1); | ||
+ | } | ||
+ | |||
+ | static void set_position(libvlc_media_player_t *mp) | ||
+ | { | ||
+ | int f = 0; | ||
+ | libvlc_event_manager_t *em = libvlc_media_player_event_manager(mp); | ||
+ | assert(em); | ||
+ | |||
+ | libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, callback, &f); | ||
+ | libvlc_media_player_set_position(mp, VLC_THUMBNAIL_POSITION); | ||
+ | event_wait("Couldn't set position", &f); | ||
+ | libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, callback, &f); | ||
+ | } | ||
− | + | static void snapshot(libvlc_media_player_t *mp, int width, char *out_with_ext) | |
− | + | { | |
− | + | int f = 0; | |
− | + | libvlc_event_manager_t *em = libvlc_media_player_event_manager(mp); | |
− | + | assert(em); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | libvlc_event_attach(em, libvlc_MediaPlayerSnapshotTaken, callback, &f); | |
− | + | libvlc_video_take_snapshot(mp, 0, out_with_ext, width, 0); | |
− | + | event_wait("Snapshot has not been written", &f); | |
+ | libvlc_event_detach(em, libvlc_MediaPlayerSnapshotTaken, callback, &f); | ||
+ | } | ||
+ | int main(int argc, const char **argv) | ||
+ | { | ||
+ | const char *in; | ||
+ | char *out, *out_with_ext; | ||
+ | int width; | ||
+ | libvlc_instance_t *libvlc; | ||
libvlc_media_player_t *mp; | libvlc_media_player_t *mp; | ||
libvlc_media_t *m; | libvlc_media_t *m; | ||
+ | /* mandatory to support UTF-8 filenames (provided the locale is well set)*/ | ||
+ | setlocale(LC_ALL, getenv("LANG")); | ||
− | + | cmdline(argc, argv, &in, &out, &out_with_ext, &width); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | /* starts vlc */ | |
− | + | libvlc = create_libvlc(); | |
+ | assert(libvlc); | ||
− | + | m = libvlc_media_new_path(libvlc, in); | |
− | + | assert(m); | |
− | |||
− | + | mp = libvlc_media_player_new_from_media(m); | |
− | + | assert(mp); | |
− | |||
− | + | libvlc_media_player_play(mp); | |
− | |||
− | |||
− | + | /* takes snapshot */ | |
− | + | set_position(mp); | |
− | + | snapshot(mp, width, out_with_ext); | |
− | + | libvlc_media_player_stop(mp); | |
− | |||
− | |||
− | + | /* clean up */ | |
− | + | if (out != out_with_ext) { | |
− | + | rename(out_with_ext, out); | |
− | + | free(out_with_ext); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
} | } | ||
+ | free(out); | ||
− | + | libvlc_media_player_release(mp); | |
− | + | libvlc_media_release(m); | |
− | + | libvlc_release(libvlc); | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | libvlc_release( libvlc | ||
− | |||
return 0; | return 0; | ||
+ | } | ||
}</pre> | }</pre> |
Revision as of 12:18, 25 October 2010
This sample code will generate a thumbnail from any media.
Using VLC 1.2 API (libvlc 5.1.0), last updated 2010, October 25th.
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-2010 Rafaël Carré <funman@videolanorg> */ #include <assert.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <locale.h> #include <vlc/vlc.h> /* gcc -pedantic -Wall -Werror -Wextra `pkg-config --cflags --libs libvlc` */ /* position at which the snapshot is taken */ #define VLC_THUMBNAIL_POSITION (30./100.) static void usage(const char *name, int ret) { fprintf(stderr, "Usage: %s [-w width] <video> <output.png>\n", name); exit(ret); } /* extracts options from command line */ static void cmdline(int argc, const char **argv, const char **in, char **out, char **out_with_ext, int *w) { int idx = 1; size_t len; if (argc != 3 && argc != 5) usage(argv[0], argc != 2 || strcmp(argv[1], "-h")); *w = 0; if (argc == 5) { if (strcmp(argv[1], "-w")) usage(argv[0], 1); idx += 2; /* skip "-w width" */ *w = atoi(argv[2]); } *in = argv[idx++]; *out = strdup(argv[idx++]); assert(*out); len = strlen(*out); if (len >= 4 && !strcmp(*out + len - 4, ".png")) { *out_with_ext = *out; return; } /* We need to add .png extension to filename, * VLC relies on it to detect output format, * and nautilus doesn't give filenames ending in .png */ *out_with_ext = malloc(len + sizeof ".png"); assert(*out_with_ext); strcpy(*out_with_ext, *out); strcat(*out_with_ext, ".png"); } static libvlc_instance_t *create_libvlc(void) { static const char* const args[] = { "--intf", "dummy", /* no interface */ "--vout", "dummy", /* we don't want video (output) */ "--no-audio", /* we don't want audio (decoding) */ "--no-video-title-show", /* nor the filename displayed */ "--no-stats", /* no stats */ "--no-sub-autodetect-file", /* we don't want subtitles */ "--no-inhibit", /* we don't want interfaces */ "--no-disable-screensaver", /* we don't want interfaces */ #if 0 "--verbose=2", /* full log */ #endif }; return libvlc_new(sizeof args / sizeof *args, args); } static void callback(const libvlc_event_t *ev, void *param) { float new_position = ev->u.media_player_position_changed.new_position; switch (ev->type) { case libvlc_MediaPlayerPositionChanged: if (new_position >= VLC_THUMBNAIL_POSITION * .9) { /* 90% margin */ *(int*)param = 1; } break; case libvlc_MediaPlayerSnapshotTaken: *(int*)param = 1; break; default: assert(0); } } /* FIXME: should use pthread notification */ static void event_wait(const char *error, int *f) { #define VLC_THUMBNAIL_TIMEOUT 5.0 /* 5 secs */ #define VLC_THUMBNAIL_LOOP_STEP 0.2 /* 200 ms */ float max = VLC_THUMBNAIL_TIMEOUT; while ((max -= VLC_THUMBNAIL_LOOP_STEP) > 0.) { if (*f) return; usleep(VLC_THUMBNAIL_LOOP_STEP * 1000000); } fprintf(stderr, "%s (timeout after %.2f secs!\n", error, VLC_THUMBNAIL_TIMEOUT); exit(1); } static void set_position(libvlc_media_player_t *mp) { int f = 0; libvlc_event_manager_t *em = libvlc_media_player_event_manager(mp); assert(em); libvlc_event_attach(em, libvlc_MediaPlayerPositionChanged, callback, &f); libvlc_media_player_set_position(mp, VLC_THUMBNAIL_POSITION); event_wait("Couldn't set position", &f); libvlc_event_detach(em, libvlc_MediaPlayerPositionChanged, callback, &f); } static void snapshot(libvlc_media_player_t *mp, int width, char *out_with_ext) { int f = 0; libvlc_event_manager_t *em = libvlc_media_player_event_manager(mp); assert(em); libvlc_event_attach(em, libvlc_MediaPlayerSnapshotTaken, callback, &f); libvlc_video_take_snapshot(mp, 0, out_with_ext, width, 0); event_wait("Snapshot has not been written", &f); libvlc_event_detach(em, libvlc_MediaPlayerSnapshotTaken, callback, &f); } int main(int argc, const char **argv) { const char *in; char *out, *out_with_ext; int width; libvlc_instance_t *libvlc; libvlc_media_player_t *mp; libvlc_media_t *m; /* mandatory to support UTF-8 filenames (provided the locale is well set)*/ setlocale(LC_ALL, getenv("LANG")); cmdline(argc, argv, &in, &out, &out_with_ext, &width); /* starts vlc */ libvlc = create_libvlc(); assert(libvlc); m = libvlc_media_new_path(libvlc, in); assert(m); mp = libvlc_media_player_new_from_media(m); assert(mp); libvlc_media_player_play(mp); /* takes snapshot */ set_position(mp); snapshot(mp, width, out_with_ext); libvlc_media_player_stop(mp); /* clean up */ if (out != out_with_ext) { rename(out_with_ext, out); free(out_with_ext); } free(out); libvlc_media_player_release(mp); libvlc_media_release(m); libvlc_release(libvlc); return 0; } }