LibVLC SampleCode Thumbnailer: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| 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;
}
}