1 /*****************************************************************************
2 * thumbnailer.c: Thumbnailing API
3 *****************************************************************************
4 * Copyright (C) 2018 VLC authors and VideoLAN
6 * Authors: Hugo Beauzée-Luyssen <hugo@beauzee.fr>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU Lesser General Public License as published by
10 * the Free Software Foundation; either version 2.1 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this program; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 *****************************************************************************/
27 #include <vlc_thumbnailer.h>
28 #include <vlc_input.h>
29 #include "misc/background_worker.h"
31 struct vlc_thumbnailer_t
34 struct background_worker
* worker
;
37 typedef struct vlc_thumbnailer_params_t
46 VLC_THUMBNAILER_SEEK_TIME
,
47 VLC_THUMBNAILER_SEEK_POS
,
50 input_item_t
* input_item
;
52 * A positive value will be used as the timeout duration
53 * VLC_TICK_INVALID means no timeout
56 vlc_thumbnailer_cb cb
;
58 } vlc_thumbnailer_params_t
;
60 struct vlc_thumbnailer_request_t
62 vlc_thumbnailer_t
*thumbnailer
;
63 input_thread_t
*input_thread
;
65 vlc_thumbnailer_params_t params
;
72 on_thumbnailer_input_event( input_thread_t
*input
,
73 const struct vlc_input_event
*event
, void *userdata
)
76 if ( event
->type
!= INPUT_EVENT_THUMBNAIL_READY
&&
77 ( event
->type
!= INPUT_EVENT_STATE
|| ( event
->state
!= ERROR_S
&&
78 event
->state
!= END_S
) ) )
81 vlc_thumbnailer_request_t
* request
= userdata
;
82 picture_t
*pic
= NULL
;
84 if ( event
->type
== INPUT_EVENT_THUMBNAIL_READY
)
87 * Stop the input thread ASAP, delegate its release to
88 * thumbnailer_request_Release
90 input_Stop( request
->input_thread
);
91 pic
= event
->thumbnail
;
93 vlc_mutex_lock( &request
->lock
);
96 * If the request has not been cancelled, we can invoke the completion
99 if ( request
->params
.cb
)
101 request
->params
.cb( request
->params
.user_data
, pic
);
102 request
->params
.cb
= NULL
;
104 vlc_mutex_unlock( &request
->lock
);
105 background_worker_RequestProbe( request
->thumbnailer
->worker
);
108 static void thumbnailer_request_Hold( void* data
)
113 static void thumbnailer_request_Release( void* data
)
115 vlc_thumbnailer_request_t
* request
= data
;
116 if ( request
->input_thread
)
117 input_Close( request
->input_thread
);
119 input_item_Release( request
->params
.input_item
);
120 vlc_mutex_destroy( &request
->lock
);
124 static int thumbnailer_request_Start( void* owner
, void* entity
, void** out
)
126 vlc_thumbnailer_t
* thumbnailer
= owner
;
127 vlc_thumbnailer_request_t
* request
= entity
;
128 input_thread_t
* input
= request
->input_thread
=
129 input_CreateThumbnailer( thumbnailer
->parent
,
130 on_thumbnailer_input_event
, request
,
131 request
->params
.input_item
);
132 if ( unlikely( input
== NULL
) )
134 if ( request
->params
.type
== VLC_THUMBNAILER_SEEK_TIME
)
136 input_SetTime( input
, request
->params
.time
,
137 request
->params
.fast_seek
);
141 assert( request
->params
.type
== VLC_THUMBNAILER_SEEK_POS
);
142 input_SetPosition( input
, request
->params
.pos
,
143 request
->params
.fast_seek
);
145 if ( input_Start( input
) != VLC_SUCCESS
)
151 static void thumbnailer_request_Stop( void* owner
, void* handle
)
155 vlc_thumbnailer_request_t
*request
= handle
;
156 vlc_mutex_lock( &request
->lock
);
158 * If the callback hasn't been invoked yet, we assume a timeout and
159 * signal it back to the user
161 if ( request
->params
.cb
!= NULL
)
163 request
->params
.cb( request
->params
.user_data
, NULL
);
164 request
->params
.cb
= NULL
;
166 vlc_mutex_unlock( &request
->lock
);
167 assert( request
->input_thread
!= NULL
);
168 input_Stop( request
->input_thread
);
171 static int thumbnailer_request_Probe( void* owner
, void* handle
)
174 vlc_thumbnailer_request_t
*request
= handle
;
175 vlc_mutex_lock( &request
->lock
);
176 int res
= request
->done
;
177 vlc_mutex_unlock( &request
->lock
);
181 static vlc_thumbnailer_request_t
*
182 thumbnailer_RequestCommon( vlc_thumbnailer_t
* thumbnailer
,
183 const vlc_thumbnailer_params_t
* params
)
185 vlc_thumbnailer_request_t
*request
= malloc( sizeof( *request
) );
186 if ( unlikely( request
== NULL
) )
188 request
->thumbnailer
= thumbnailer
;
189 request
->input_thread
= NULL
;
190 request
->params
= *(vlc_thumbnailer_params_t
*)params
;
191 request
->done
= false;
192 input_item_Hold( request
->params
.input_item
);
193 vlc_mutex_init( &request
->lock
);
195 int timeout
= params
->timeout
== VLC_TICK_INVALID
?
196 0 : MS_FROM_VLC_TICK( params
->timeout
);
197 if ( background_worker_Push( thumbnailer
->worker
, request
, request
,
198 timeout
) != VLC_SUCCESS
)
200 thumbnailer_request_Release( request
);
206 vlc_thumbnailer_request_t
*
207 vlc_thumbnailer_RequestByTime( vlc_thumbnailer_t
*thumbnailer
,
209 enum vlc_thumbnailer_seek_speed speed
,
210 input_item_t
*input_item
, vlc_tick_t timeout
,
211 vlc_thumbnailer_cb cb
, void* user_data
)
213 return thumbnailer_RequestCommon( thumbnailer
,
214 &(const vlc_thumbnailer_params_t
){
216 .type
= VLC_THUMBNAILER_SEEK_TIME
,
217 .fast_seek
= speed
== VLC_THUMBNAILER_SEEK_FAST
,
218 .input_item
= input_item
,
221 .user_data
= user_data
,
225 vlc_thumbnailer_request_t
*
226 vlc_thumbnailer_RequestByPos( vlc_thumbnailer_t
*thumbnailer
,
227 float pos
, enum vlc_thumbnailer_seek_speed speed
,
228 input_item_t
*input_item
, vlc_tick_t timeout
,
229 vlc_thumbnailer_cb cb
, void* user_data
)
231 return thumbnailer_RequestCommon( thumbnailer
,
232 &(const vlc_thumbnailer_params_t
){
234 .type
= VLC_THUMBNAILER_SEEK_POS
,
235 .fast_seek
= speed
== VLC_THUMBNAILER_SEEK_FAST
,
236 .input_item
= input_item
,
239 .user_data
= user_data
,
243 void vlc_thumbnailer_Cancel( vlc_thumbnailer_t
* thumbnailer
,
244 vlc_thumbnailer_request_t
* req
)
246 vlc_mutex_lock( &req
->lock
);
247 /* Ensure we won't invoke the callback if the input was running. */
248 req
->params
.cb
= NULL
;
249 vlc_mutex_unlock( &req
->lock
);
250 background_worker_Cancel( thumbnailer
->worker
, req
);
253 vlc_thumbnailer_t
*vlc_thumbnailer_Create( vlc_object_t
* parent
)
255 vlc_thumbnailer_t
*thumbnailer
= malloc( sizeof( *thumbnailer
) );
256 if ( unlikely( thumbnailer
== NULL
) )
258 thumbnailer
->parent
= parent
;
259 struct background_worker_config cfg
= {
260 .default_timeout
= -1,
262 .pf_release
= thumbnailer_request_Release
,
263 .pf_hold
= thumbnailer_request_Hold
,
264 .pf_start
= thumbnailer_request_Start
,
265 .pf_probe
= thumbnailer_request_Probe
,
266 .pf_stop
= thumbnailer_request_Stop
,
268 thumbnailer
->worker
= background_worker_New( thumbnailer
, &cfg
);
269 if ( unlikely( thumbnailer
->worker
== NULL
) )
277 void vlc_thumbnailer_Release( vlc_thumbnailer_t
*thumbnailer
)
279 background_worker_Delete( thumbnailer
->worker
);