demux: heif: refactor pic setup
[vlc.git] / src / input / thumbnailer.c
blobbd10032d53f6dcecd8d63ff461be5856c6aba448
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 *****************************************************************************/
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
27 #include <vlc_thumbnailer.h>
28 #include <vlc_input.h>
29 #include "misc/background_worker.h"
31 struct vlc_thumbnailer_t
33 vlc_object_t* parent;
34 struct background_worker* worker;
37 typedef struct vlc_thumbnailer_params_t
39 union
41 vlc_tick_t time;
42 float pos;
44 enum
46 VLC_THUMBNAILER_SEEK_TIME,
47 VLC_THUMBNAILER_SEEK_POS,
48 } type;
49 bool fast_seek;
50 input_item_t* input_item;
51 /**
52 * A positive value will be used as the timeout duration
53 * VLC_TICK_INVALID means no timeout
55 vlc_tick_t timeout;
56 vlc_thumbnailer_cb cb;
57 void* user_data;
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;
67 vlc_mutex_t lock;
68 bool done;
71 static void
72 on_thumbnailer_input_event( input_thread_t *input,
73 const struct vlc_input_event *event, void *userdata )
75 VLC_UNUSED(input);
76 if ( event->type != INPUT_EVENT_THUMBNAIL_READY &&
77 ( event->type != INPUT_EVENT_STATE || ( event->state != ERROR_S &&
78 event->state != END_S ) ) )
79 return;
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 );
94 request->done = true;
96 * If the request has not been cancelled, we can invoke the completion
97 * callback.
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 )
110 VLC_UNUSED(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 );
121 free( request );
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 ) )
133 return VLC_EGENERIC;
134 if ( request->params.type == VLC_THUMBNAILER_SEEK_TIME )
136 input_SetTime( input, request->params.time,
137 request->params.fast_seek );
139 else
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 )
146 return VLC_EGENERIC;
147 *out = request;
148 return VLC_SUCCESS;
151 static void thumbnailer_request_Stop( void* owner, void* handle )
153 VLC_UNUSED(owner);
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 )
173 VLC_UNUSED(owner);
174 vlc_thumbnailer_request_t *request = handle;
175 vlc_mutex_lock( &request->lock );
176 int res = request->done;
177 vlc_mutex_unlock( &request->lock );
178 return res;
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 ) )
187 return 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 );
201 return NULL;
203 return request;
206 vlc_thumbnailer_request_t*
207 vlc_thumbnailer_RequestByTime( vlc_thumbnailer_t *thumbnailer,
208 vlc_tick_t time,
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){
215 .time = time,
216 .type = VLC_THUMBNAILER_SEEK_TIME,
217 .fast_seek = speed == VLC_THUMBNAILER_SEEK_FAST,
218 .input_item = input_item,
219 .timeout = timeout,
220 .cb = cb,
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){
233 .pos = pos,
234 .type = VLC_THUMBNAILER_SEEK_POS,
235 .fast_seek = speed == VLC_THUMBNAILER_SEEK_FAST,
236 .input_item = input_item,
237 .timeout = timeout,
238 .cb = cb,
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 ) )
257 return NULL;
258 thumbnailer->parent = parent;
259 struct background_worker_config cfg = {
260 .default_timeout = -1,
261 .max_threads = 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 ) )
271 free( thumbnailer );
272 return NULL;
274 return thumbnailer;
277 void vlc_thumbnailer_Release( vlc_thumbnailer_t *thumbnailer )
279 background_worker_Delete( thumbnailer->worker );
280 free( thumbnailer );