[vlc-commits] core: Add a thumbnailing API
Hugo Beauzée-Luyssen
git at videolan.org
Mon Nov 12 17:12:19 CET 2018
vlc | branch: master | Hugo Beauzée-Luyssen <hugo at beauzee.fr> | Thu Oct 4 17:10:16 2018 +0200| [946b67f964396056caba8cb3b62bdf9a976abfae] | committer: Hugo Beauzée-Luyssen
core: Add a thumbnailing API
ref #17368
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=946b67f964396056caba8cb3b62bdf9a976abfae
---
include/vlc_input.h | 11 ++
include/vlc_thumbnailer.h | 133 +++++++++++++++++++++
src/Makefile.am | 2 +
src/input/decoder.c | 45 +++++++-
src/input/es_out.c | 5 +-
src/input/input.c | 19 ++-
src/input/input_internal.h | 1 +
src/input/thumbnailer.c | 281 +++++++++++++++++++++++++++++++++++++++++++++
src/input/var.c | 2 +
src/libvlc.c | 5 +
src/libvlccore.sym | 6 +
11 files changed, 502 insertions(+), 8 deletions(-)
diff --git a/include/vlc_input.h b/include/vlc_input.h
index 5d9fd5fadf..713066d962 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -395,6 +395,9 @@ typedef enum input_event_type_e
/* subs_fps has changed */
INPUT_EVENT_SUBS_FPS,
+
+ /* Thumbnail generation */
+ INPUT_EVENT_THUMBNAIL_READY,
} input_event_type_e;
#define VLC_INPUT_CAPABILITIES_SEEKABLE (1<<0)
@@ -528,6 +531,8 @@ struct vlc_input_event
bool vbi_transparent;
/* INPUT_EVENT_SUBS_FPS */
float subs_fps;
+ /* INPUT_EVENT_THUMBNAIL_READY */
+ picture_t *thumbnail;
};
};
@@ -621,6 +626,12 @@ VLC_API input_thread_t *input_CreatePreparser(vlc_object_t *obj,
void *events_data, input_item_t *item)
VLC_USED;
+VLC_API
+input_thread_t *input_CreateThumbnailer(vlc_object_t *obj,
+ input_thread_events_cb events_cb,
+ void *events_data, input_item_t *item)
+VLC_USED;
+
VLC_API int input_Start( input_thread_t * );
VLC_API void input_Stop( input_thread_t * );
diff --git a/include/vlc_thumbnailer.h b/include/vlc_thumbnailer.h
new file mode 100644
index 0000000000..39c23cd727
--- /dev/null
+++ b/include/vlc_thumbnailer.h
@@ -0,0 +1,133 @@
+/*****************************************************************************
+ * vlc_thumbnailer.h: Thumbnailing API
+ *****************************************************************************
+ * Copyright (C) 2018 VLC authors and VideoLAN
+ *
+ * Authors: Hugo Beauzée-Luyssen <hugo at beauzee.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_THUMBNAILER_H
+#define VLC_THUMBNAILER_H
+
+#include <vlc_common.h>
+
+typedef struct vlc_thumbnailer_t vlc_thumbnailer_t;
+typedef struct vlc_thumbnailer_request_t vlc_thumbnailer_request_t;
+
+/**
+ * \brief vlc_thumbnailer_cb defines a callback invoked on thumbnailing completion or error
+ *
+ * This callback will always be called, provided vlc_thumbnailer_Request returned
+ * a non NULL request, and provided the request is not cancelled before its
+ * completion.
+ * In case of failure, p_thumbnail will be NULL.
+ * The picture, if any, is owned by the thumbnailer, and must be acquired by using
+ * \link picture_Hold \endlink to use it pass the callback's scope.
+ *
+ * \param data Is the opaque pointer passed as vlc_thumbnailer_Request last parameter
+ * \param thumbnail The generated thumbnail, or NULL in case of failure or timeout
+ */
+typedef void(*vlc_thumbnailer_cb)( void* data, picture_t* thumbnail );
+
+
+/**
+ * \brief vlc_thumbnailer_Create Creates a thumbnailer object
+ * \param parent A VLC object
+ * \return A thumbnailer object, or NULL in case of failure
+ */
+VLC_API vlc_thumbnailer_t*
+vlc_thumbnailer_Create( vlc_object_t* p_parent )
+VLC_USED;
+
+enum vlc_thumbnailer_seek_speed
+{
+ /** Precise, but potentially slow */
+ VLC_THUMBNAILER_SEEK_PRECISE,
+ /** Fast, but potentially imprecise */
+ VLC_THUMBNAILER_SEEK_FAST,
+};
+
+/**
+ * \brief vlc_thumbnailer_RequestByTime Requests a thumbnailer at a given time
+ * \param thumbnailer A thumbnailer object
+ * \param time The time at which the thumbnail should be taken
+ * \param speed The seeking speed \sa{enum vlc_thumbnailer_seek_speed}
+ * \param input_item The input item to generate the thumbnail for
+ * \param timeout A timeout value, or VLC_TICK_INVALID to disable timeout
+ * \param cb A user callback to be called on completion (success & error)
+ * \param user_data An opaque value, provided as pf_cb's first parameter
+ * \return An opaque request object, or NULL in case of failure
+ *
+ * If this function returns a valid request object, the callback is guaranteed
+ * to be called, even in case of later failure.
+ * The returned request object must not be used after the callback has been
+ * invoked. That request object is owned by the thumbnailer, and must not be
+ * released.
+ * The provided input_item will be held by the thumbnailer and can safely be
+ * released safely after calling this function.
+ */
+VLC_API vlc_thumbnailer_request_t*
+vlc_thumbnailer_RequestByTime( vlc_thumbnailer_t *thumbnailer,
+ vlc_tick_t time,
+ enum vlc_thumbnailer_seek_speed speed,
+ input_item_t *input_item, vlc_tick_t timeout,
+ vlc_thumbnailer_cb cb, void* user_data );
+/**
+ * \brief vlc_thumbnailer_RequestByTime Requests a thumbnailer at a given time
+ * \param thumbnailer A thumbnailer object
+ * \param pos The position at which the thumbnail should be taken
+ * \param speed The seeking speed \sa{enum vlc_thumbnailer_seek_speed}
+ * \param input_item The input item to generate the thumbnail for
+ * \param timeout A timeout value, or VLC_TICK_INVALID to disable timeout
+ * \param cb A user callback to be called on completion (success & error)
+ * \param user_data An opaque value, provided as pf_cb's first parameter
+ * \return An opaque request object, or NULL in case of failure
+ *
+ * If this function returns a valid request object, the callback is guaranteed
+ * to be called, even in case of later failure.
+ * The returned request object must not be used after the callback has been
+ * invoked. That request object is owned by the thumbnailer, and must not be
+ * released.
+ * The provided input_item will be held by the thumbnailer and can safely be
+ * released after calling this function.
+ */
+VLC_API vlc_thumbnailer_request_t*
+vlc_thumbnailer_RequestByPos( vlc_thumbnailer_t *thumbnailer,
+ float pos,
+ enum vlc_thumbnailer_seek_speed speed,
+ input_item_t *input_item, vlc_tick_t timeout,
+ vlc_thumbnailer_cb cb, void* user_data );
+
+/**
+ * \brief vlc_thumbnailer_Cancel Cancel a thumbnail request
+ * \param thumbnailer A thumbnailer object
+ * \param request An opaque thumbnail request object
+ *
+ * Cancelling a request will *not* invoke the completion callback.
+ * The behavior is undefined if the request is cancelled after its completion.
+ */
+VLC_API void
+vlc_thumbnailer_Cancel( vlc_thumbnailer_t* thumbnailer,
+ vlc_thumbnailer_request_t* request );
+
+/**
+ * \brief vlc_thumbnailer_Release releases a thumbnailer and cancel all pending requests
+ * \param thumbnailer A thumbnailer object
+ */
+VLC_API void vlc_thumbnailer_Release( vlc_thumbnailer_t* thumbnailer );
+
+#endif // VLC_THUMBNAILER_H
diff --git a/src/Makefile.am b/src/Makefile.am
index c64592a11b..4c7f7a6f98 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -94,6 +94,7 @@ pluginsinclude_HEADERS = \
../include/vlc_threads.h \
../include/vlc_tick.h \
../include/vlc_timestamp_helper.h \
+ ../include/vlc_thumbnailer.h \
../include/vlc_tls.h \
../include/vlc_url.h \
../include/vlc_variables.h \
@@ -267,6 +268,7 @@ libvlccore_la_SOURCES = \
input/stream_filter.c \
input/stream_memory.c \
input/subtitles.c \
+ input/thumbnailer.c \
input/var.c \
audio_output/aout_internal.h \
audio_output/common.c \
diff --git a/src/input/decoder.c b/src/input/decoder.c
index 7ca4c87fcf..5ce154678e 100644
--- a/src/input/decoder.c
+++ b/src/input/decoder.c
@@ -1210,6 +1210,37 @@ static void DecoderQueueVideo( decoder_t *p_dec, picture_t *p_pic )
p_owner->pf_update_stat( p_owner, 1, i_lost );
}
+static int thumbnailer_update_format( decoder_t *p_dec )
+{
+ VLC_UNUSED(p_dec);
+ return 0;
+}
+
+static picture_t *thumbnailer_buffer_new( decoder_t *p_dec )
+{
+ struct decoder_owner *p_owner = dec_get_owner( p_dec );
+ /* Avoid decoding more than one frame when a thumbnail was
+ * already generated */
+ if( !p_owner->b_first )
+ return NULL;
+ return picture_NewFromFormat( &p_dec->fmt_out.video );
+}
+
+static void DecoderQueueThumbnail( decoder_t *p_dec, picture_t *p_pic )
+{
+ struct decoder_owner *p_owner = dec_get_owner( p_dec );
+ if( p_owner->b_first )
+ {
+ input_SendEvent(p_owner->p_input, &(struct vlc_input_event) {
+ .type = INPUT_EVENT_THUMBNAIL_READY,
+ .thumbnail = p_pic
+ });
+ p_owner->b_first = false;
+ }
+ picture_Release( p_pic );
+
+}
+
static void DecoderPlayAudio( decoder_t *p_dec, block_t *p_audio,
unsigned *restrict pi_lost_sum )
{
@@ -1779,6 +1810,15 @@ static const struct decoder_owner_callbacks dec_video_cbs =
},
.get_attachments = DecoderGetInputAttachments,
};
+static const struct decoder_owner_callbacks dec_thumbnailer_cbs =
+{
+ .video = {
+ .format_update = thumbnailer_update_format,
+ .buffer_new = thumbnailer_buffer_new,
+ .queue = DecoderQueueThumbnail,
+ },
+ .get_attachments = DecoderGetInputAttachments,
+};
static const struct decoder_owner_callbacks dec_audio_cbs =
{
.audio = {
@@ -1894,7 +1934,10 @@ static decoder_t * CreateDecoder( vlc_object_t *p_parent,
switch( fmt->i_cat )
{
case VIDEO_ES:
- p_dec->cbs = &dec_video_cbs;
+ if( !input_priv( p_input )->b_thumbnailing )
+ p_dec->cbs = &dec_video_cbs;
+ else
+ p_dec->cbs = &dec_thumbnailer_cbs;
p_owner->pf_update_stat = DecoderUpdateStatVideo;
break;
case AUDIO_ES:
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 21ba6137eb..0cdd08cfe2 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -1821,6 +1821,7 @@ static void EsOutSelectEs( es_out_t *out, es_out_id_t *es )
{
es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
input_thread_t *p_input = p_sys->p_input;
+ bool b_thumbnailing = input_priv(p_input)->b_thumbnailing;
if( EsIsSelected( es ) )
{
@@ -1859,7 +1860,7 @@ static void EsOutSelectEs( es_out_t *out, es_out_id_t *es )
}
else if( es->fmt.i_cat == AUDIO_ES )
{
- if( !var_GetBool( p_input, b_sout ? "sout-audio" : "audio" ) )
+ if( !var_GetBool( p_input, b_sout ? "sout-audio" : "audio" ) || b_thumbnailing )
{
msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
es->fmt.i_id );
@@ -1868,7 +1869,7 @@ static void EsOutSelectEs( es_out_t *out, es_out_id_t *es )
}
if( es->fmt.i_cat == SPU_ES )
{
- if( !var_GetBool( p_input, b_sout ? "sout-spu" : "spu" ) )
+ if( !var_GetBool( p_input, b_sout ? "sout-spu" : "spu" ) || b_thumbnailing )
{
msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
es->fmt.i_id );
diff --git a/src/input/input.c b/src/input/input.c
index 7265ac6cd6..6999d75eb5 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -63,7 +63,7 @@ static void *Run( void * );
static void *Preparse( void * );
static input_thread_t * Create ( vlc_object_t *, input_thread_events_cb, void *,
- input_item_t *, const char *, bool,
+ input_item_t *, const char *, bool, bool,
input_resource_t *, vlc_renderer_item_t * );
static int Init ( input_thread_t *p_input );
static void End ( input_thread_t *p_input );
@@ -132,7 +132,7 @@ input_thread_t *input_Create( vlc_object_t *p_parent,
vlc_renderer_item_t *p_renderer )
{
return Create( p_parent, events_cb, events_data, p_item, psz_log, false,
- p_resource, p_renderer );
+ false, p_resource, p_renderer );
}
#undef input_Read
@@ -147,7 +147,7 @@ int input_Read( vlc_object_t *p_parent, input_item_t *p_item,
input_thread_events_cb events_cb, void *events_data )
{
input_thread_t *p_input = Create( p_parent, events_cb, events_data, p_item,
- NULL, false, NULL, NULL );
+ NULL, false, false, NULL, NULL );
if( !p_input )
return VLC_EGENERIC;
@@ -165,7 +165,14 @@ input_thread_t *input_CreatePreparser( vlc_object_t *parent,
input_thread_events_cb events_cb,
void *events_data, input_item_t *item )
{
- return Create( parent, events_cb, events_data, item, NULL, true, NULL, NULL );
+ return Create( parent, events_cb, events_data, item, NULL, true, false, NULL, NULL );
+}
+
+input_thread_t *input_CreateThumbnailer(vlc_object_t *obj,
+ input_thread_events_cb events_cb,
+ void *events_data, input_item_t *item)
+{
+ return Create( obj, events_cb, events_data, item, NULL, false, true, NULL, NULL );
}
/**
@@ -308,7 +315,8 @@ input_item_t *input_GetItem( input_thread_t *p_input )
static input_thread_t *Create( vlc_object_t *p_parent,
input_thread_events_cb events_cb, void *events_data,
input_item_t *p_item, const char *psz_header,
- bool b_preparsing, input_resource_t *p_resource,
+ bool b_preparsing, bool b_thumbnailing,
+ input_resource_t *p_resource,
vlc_renderer_item_t *p_renderer )
{
/* Allocate descriptor */
@@ -345,6 +353,7 @@ static input_thread_t *Create( vlc_object_t *p_parent,
priv->is_running = false;
priv->is_stopped = false;
priv->b_recording = false;
+ priv->b_thumbnailing = b_thumbnailing;
priv->i_rate = INPUT_RATE_DEFAULT;
memset( &priv->bookmark, 0, sizeof(priv->bookmark) );
TAB_INIT( priv->i_bookmark, priv->pp_bookmark );
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index 95d09528cf..82eb5f64bd 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -132,6 +132,7 @@ typedef struct input_thread_private_t
bool is_running;
bool is_stopped;
bool b_recording;
+ bool b_thumbnailing;
int i_rate;
/* Playtime configuration and state */
diff --git a/src/input/thumbnailer.c b/src/input/thumbnailer.c
new file mode 100644
index 0000000000..bd10032d53
--- /dev/null
+++ b/src/input/thumbnailer.c
@@ -0,0 +1,281 @@
+/*****************************************************************************
+ * thumbnailer.c: Thumbnailing API
+ *****************************************************************************
+ * Copyright (C) 2018 VLC authors and VideoLAN
+ *
+ * Authors: Hugo Beauzée-Luyssen <hugo at beauzee.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_thumbnailer.h>
+#include <vlc_input.h>
+#include "misc/background_worker.h"
+
+struct vlc_thumbnailer_t
+{
+ vlc_object_t* parent;
+ struct background_worker* worker;
+};
+
+typedef struct vlc_thumbnailer_params_t
+{
+ union
+ {
+ vlc_tick_t time;
+ float pos;
+ };
+ enum
+ {
+ VLC_THUMBNAILER_SEEK_TIME,
+ VLC_THUMBNAILER_SEEK_POS,
+ } type;
+ bool fast_seek;
+ input_item_t* input_item;
+ /**
+ * A positive value will be used as the timeout duration
+ * VLC_TICK_INVALID means no timeout
+ */
+ vlc_tick_t timeout;
+ vlc_thumbnailer_cb cb;
+ void* user_data;
+} vlc_thumbnailer_params_t;
+
+struct vlc_thumbnailer_request_t
+{
+ vlc_thumbnailer_t *thumbnailer;
+ input_thread_t *input_thread;
+
+ vlc_thumbnailer_params_t params;
+
+ vlc_mutex_t lock;
+ bool done;
+};
+
+static void
+on_thumbnailer_input_event( input_thread_t *input,
+ const struct vlc_input_event *event, void *userdata )
+{
+ VLC_UNUSED(input);
+ if ( event->type != INPUT_EVENT_THUMBNAIL_READY &&
+ ( event->type != INPUT_EVENT_STATE || ( event->state != ERROR_S &&
+ event->state != END_S ) ) )
+ return;
+
+ vlc_thumbnailer_request_t* request = userdata;
+ picture_t *pic = NULL;
+
+ if ( event->type == INPUT_EVENT_THUMBNAIL_READY )
+ {
+ /*
+ * Stop the input thread ASAP, delegate its release to
+ * thumbnailer_request_Release
+ */
+ input_Stop( request->input_thread );
+ pic = event->thumbnail;
+ }
+ vlc_mutex_lock( &request->lock );
+ request->done = true;
+ /*
+ * If the request has not been cancelled, we can invoke the completion
+ * callback.
+ */
+ if ( request->params.cb )
+ {
+ request->params.cb( request->params.user_data, pic );
+ request->params.cb = NULL;
+ }
+ vlc_mutex_unlock( &request->lock );
+ background_worker_RequestProbe( request->thumbnailer->worker );
+}
+
+static void thumbnailer_request_Hold( void* data )
+{
+ VLC_UNUSED(data);
+}
+
+static void thumbnailer_request_Release( void* data )
+{
+ vlc_thumbnailer_request_t* request = data;
+ if ( request->input_thread )
+ input_Close( request->input_thread );
+
+ input_item_Release( request->params.input_item );
+ vlc_mutex_destroy( &request->lock );
+ free( request );
+}
+
+static int thumbnailer_request_Start( void* owner, void* entity, void** out )
+{
+ vlc_thumbnailer_t* thumbnailer = owner;
+ vlc_thumbnailer_request_t* request = entity;
+ input_thread_t* input = request->input_thread =
+ input_CreateThumbnailer( thumbnailer->parent,
+ on_thumbnailer_input_event, request,
+ request->params.input_item );
+ if ( unlikely( input == NULL ) )
+ return VLC_EGENERIC;
+ if ( request->params.type == VLC_THUMBNAILER_SEEK_TIME )
+ {
+ input_SetTime( input, request->params.time,
+ request->params.fast_seek );
+ }
+ else
+ {
+ assert( request->params.type == VLC_THUMBNAILER_SEEK_POS );
+ input_SetPosition( input, request->params.pos,
+ request->params.fast_seek );
+ }
+ if ( input_Start( input ) != VLC_SUCCESS )
+ return VLC_EGENERIC;
+ *out = request;
+ return VLC_SUCCESS;
+}
+
+static void thumbnailer_request_Stop( void* owner, void* handle )
+{
+ VLC_UNUSED(owner);
+
+ vlc_thumbnailer_request_t *request = handle;
+ vlc_mutex_lock( &request->lock );
+ /*
+ * If the callback hasn't been invoked yet, we assume a timeout and
+ * signal it back to the user
+ */
+ if ( request->params.cb != NULL )
+ {
+ request->params.cb( request->params.user_data, NULL );
+ request->params.cb = NULL;
+ }
+ vlc_mutex_unlock( &request->lock );
+ assert( request->input_thread != NULL );
+ input_Stop( request->input_thread );
+}
+
+static int thumbnailer_request_Probe( void* owner, void* handle )
+{
+ VLC_UNUSED(owner);
+ vlc_thumbnailer_request_t *request = handle;
+ vlc_mutex_lock( &request->lock );
+ int res = request->done;
+ vlc_mutex_unlock( &request->lock );
+ return res;
+}
+
+static vlc_thumbnailer_request_t*
+thumbnailer_RequestCommon( vlc_thumbnailer_t* thumbnailer,
+ const vlc_thumbnailer_params_t* params )
+{
+ vlc_thumbnailer_request_t *request = malloc( sizeof( *request ) );
+ if ( unlikely( request == NULL ) )
+ return NULL;
+ request->thumbnailer = thumbnailer;
+ request->input_thread = NULL;
+ request->params = *(vlc_thumbnailer_params_t*)params;
+ request->done = false;
+ input_item_Hold( request->params.input_item );
+ vlc_mutex_init( &request->lock );
+
+ int timeout = params->timeout == VLC_TICK_INVALID ?
+ 0 : MS_FROM_VLC_TICK( params->timeout );
+ if ( background_worker_Push( thumbnailer->worker, request, request,
+ timeout ) != VLC_SUCCESS )
+ {
+ thumbnailer_request_Release( request );
+ return NULL;
+ }
+ return request;
+}
+
+vlc_thumbnailer_request_t*
+vlc_thumbnailer_RequestByTime( vlc_thumbnailer_t *thumbnailer,
+ vlc_tick_t time,
+ enum vlc_thumbnailer_seek_speed speed,
+ input_item_t *input_item, vlc_tick_t timeout,
+ vlc_thumbnailer_cb cb, void* user_data )
+{
+ return thumbnailer_RequestCommon( thumbnailer,
+ &(const vlc_thumbnailer_params_t){
+ .time = time,
+ .type = VLC_THUMBNAILER_SEEK_TIME,
+ .fast_seek = speed == VLC_THUMBNAILER_SEEK_FAST,
+ .input_item = input_item,
+ .timeout = timeout,
+ .cb = cb,
+ .user_data = user_data,
+ });
+}
+
+vlc_thumbnailer_request_t*
+vlc_thumbnailer_RequestByPos( vlc_thumbnailer_t *thumbnailer,
+ float pos, enum vlc_thumbnailer_seek_speed speed,
+ input_item_t *input_item, vlc_tick_t timeout,
+ vlc_thumbnailer_cb cb, void* user_data )
+{
+ return thumbnailer_RequestCommon( thumbnailer,
+ &(const vlc_thumbnailer_params_t){
+ .pos = pos,
+ .type = VLC_THUMBNAILER_SEEK_POS,
+ .fast_seek = speed == VLC_THUMBNAILER_SEEK_FAST,
+ .input_item = input_item,
+ .timeout = timeout,
+ .cb = cb,
+ .user_data = user_data,
+ });
+}
+
+void vlc_thumbnailer_Cancel( vlc_thumbnailer_t* thumbnailer,
+ vlc_thumbnailer_request_t* req )
+{
+ vlc_mutex_lock( &req->lock );
+ /* Ensure we won't invoke the callback if the input was running. */
+ req->params.cb = NULL;
+ vlc_mutex_unlock( &req->lock );
+ background_worker_Cancel( thumbnailer->worker, req );
+}
+
+vlc_thumbnailer_t *vlc_thumbnailer_Create( vlc_object_t* parent)
+{
+ vlc_thumbnailer_t *thumbnailer = malloc( sizeof( *thumbnailer ) );
+ if ( unlikely( thumbnailer == NULL ) )
+ return NULL;
+ thumbnailer->parent = parent;
+ struct background_worker_config cfg = {
+ .default_timeout = -1,
+ .max_threads = 1,
+ .pf_release = thumbnailer_request_Release,
+ .pf_hold = thumbnailer_request_Hold,
+ .pf_start = thumbnailer_request_Start,
+ .pf_probe = thumbnailer_request_Probe,
+ .pf_stop = thumbnailer_request_Stop,
+ };
+ thumbnailer->worker = background_worker_New( thumbnailer, &cfg );
+ if ( unlikely( thumbnailer->worker == NULL ) )
+ {
+ free( thumbnailer );
+ return NULL;
+ }
+ return thumbnailer;
+}
+
+void vlc_thumbnailer_Release( vlc_thumbnailer_t *thumbnailer )
+{
+ background_worker_Delete( thumbnailer->worker );
+ free( thumbnailer );
+}
diff --git a/src/input/var.c b/src/input/var.c
index 895e373b23..6038c883c1 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -425,6 +425,8 @@ void input_LegacyEvents( input_thread_t *p_input,
break;
case INPUT_EVENT_SUBITEMS:
break;
+ case INPUT_EVENT_THUMBNAIL_READY:
+ break;
}
Trigger( p_input, event->type );
}
diff --git a/src/libvlc.c b/src/libvlc.c
index f12f980936..18d55004d1 100644
--- a/src/libvlc.c
+++ b/src/libvlc.c
@@ -63,6 +63,7 @@
#include <vlc_url.h>
#include <vlc_modules.h>
#include <vlc_media_library.h>
+#include <vlc_thumbnailer.h>
#include "libvlc.h"
#include "playlist/playlist_internal.h"
@@ -225,6 +226,10 @@ int libvlc_InternalInit( libvlc_int_t *p_libvlc, int i_argc,
msg_Warn( p_libvlc, "Media library initialization failed" );
}
+ priv->p_thumbnailer = vlc_thumbnailer_Create( VLC_OBJECT( p_libvlc ) );
+ if ( priv->p_thumbnailer == NULL )
+ msg_Warn( p_libvlc, "Failed to instantiate VLC thumbnailer" );
+
/*
* Initialize hotkey handling
*/
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index c1b2b1ea7b..c87f11c69f 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -155,6 +155,7 @@ input_Control
input_Create
input_CreateFilename
input_CreatePreparser
+input_CreateThumbnailer
input_DecoderCreate
input_DecoderDelete
input_DecoderDecode
@@ -786,3 +787,8 @@ vlc_es_id_Hold
vlc_es_id_Release
vlc_es_id_GetInputId
vlc_es_id_GetCat
+vlc_thumbnailer_Create
+vlc_thumbnailer_RequestByTime
+vlc_thumbnailer_RequestByPos
+vlc_thumbnailer_Cancel
+vlc_thumbnailer_Release
More information about the vlc-commits
mailing list