Browse Source

preparser: add vlc_preparser_req_Release API

Explicit API to release vlc_preparser_req* from user side.
Safe to call this from within the on_ended callback.
pull/188/head
Ayush Dey 10 months ago
committed by Steve Lhomme
parent
commit
52c61546c2
  1. 26
      include/vlc_preparser.h
  2. 5
      lib/media.c
  3. 1
      modules/gui/qt/player/player_controller.cpp
  4. 3
      modules/misc/medialibrary/Thumbnailer.cpp
  5. 1
      src/libvlccore.sym
  6. 1
      src/media_source/media_tree.c
  7. 1
      src/playlist/preparse.c
  8. 37
      src/preparser/preparser.c
  9. 4
      test/libvlc/media.c
  10. 4
      test/src/preparser/thumbnail.c
  11. 3
      test/src/preparser/thumbnail_to_files.c

26
include/vlc_preparser.h

@ -49,6 +49,13 @@ typedef struct vlc_preparser_t vlc_preparser_t;
* Identifies a request submitted via vlc_preparser_Push(), * Identifies a request submitted via vlc_preparser_Push(),
* vlc_preparser_GenerateThumbnail(), or vlc_preparser_GenerateThumbnailToFiles(). * vlc_preparser_GenerateThumbnail(), or vlc_preparser_GenerateThumbnailToFiles().
* It can be passed to vlc_preparser_Cancel() to cancel that request. * It can be passed to vlc_preparser_Cancel() to cancel that request.
*
* @note
* - Validity starts when a submit function returns a non-NULL handle and ends
* with vlc_preparser_req_Release().
*
* - The user must ensure that callbacks and their context remain valid
* until request termination.
*/ */
typedef struct vlc_preparser_req vlc_preparser_req; typedef struct vlc_preparser_req vlc_preparser_req;
@ -426,6 +433,25 @@ VLC_API size_t vlc_preparser_Cancel( vlc_preparser_t *preparser,
*/ */
VLC_API input_item_t *vlc_preparser_req_GetItem(vlc_preparser_req *req); VLC_API input_item_t *vlc_preparser_req_GetItem(vlc_preparser_req *req);
/**
* Release a preparser request handle.
*
* @param req the preparser request handle
*
* @note
* - The request handle is retained when returned by a submit function.
*
* - Mandatory to call to avoid memory leaks.
*
* - It is safe to call this API from within the on_ended callback.
*
* - The request handle should not be used after calling this function.
*
* - If called on an active request, it doesn't cancel the preparsing request,
* use vlc_preparser_Cancel() for that.
*/
VLC_API void vlc_preparser_req_Release( vlc_preparser_req *req );
/** /**
* This function destroys the preparser object and thread. * This function destroys the preparser object and thread.
* *

5
lib/media.c

@ -307,7 +307,6 @@ static void send_parsed_changed( libvlc_media_t *p_md,
static void input_item_preparse_ended(vlc_preparser_req *req, static void input_item_preparse_ended(vlc_preparser_req *req,
int status, void *user_data) int status, void *user_data)
{ {
VLC_UNUSED(req);
libvlc_media_t * p_md = user_data; libvlc_media_t * p_md = user_data;
libvlc_media_parsed_status_t new_status; libvlc_media_parsed_status_t new_status;
@ -329,6 +328,7 @@ static void input_item_preparse_ended(vlc_preparser_req *req,
vlc_assert_unreachable(); vlc_assert_unreachable();
} }
send_parsed_changed( p_md, new_status ); send_parsed_changed( p_md, new_status );
vlc_preparser_req_Release( req );
p_md->req = NULL; p_md->req = NULL;
if (atomic_fetch_sub_explicit(&p_md->worker_count, 1, if (atomic_fetch_sub_explicit(&p_md->worker_count, 1,
@ -934,7 +934,6 @@ struct libvlc_media_thumbnail_request_t
static void media_on_thumbnail_ready( vlc_preparser_req *request, int status, static void media_on_thumbnail_ready( vlc_preparser_req *request, int status,
picture_t* thumbnail, void* data ) picture_t* thumbnail, void* data )
{ {
(void) request;
(void) status; (void) status;
libvlc_media_thumbnail_request_t *req = data; libvlc_media_thumbnail_request_t *req = data;
@ -950,6 +949,8 @@ static void media_on_thumbnail_ready( vlc_preparser_req *request, int status,
libvlc_event_send( &p_media->event_manager, &event ); libvlc_event_send( &p_media->event_manager, &event );
if ( pic != NULL ) if ( pic != NULL )
libvlc_picture_release( pic ); libvlc_picture_release( pic );
vlc_preparser_req_Release( request );
} }
// Start an asynchronous thumbnail generation // Start an asynchronous thumbnail generation

1
modules/gui/qt/player/player_controller.cpp

@ -1026,6 +1026,7 @@ static void on_preparse_ended_callback(vlc_preparser_req *req,
input_item_t *p_item = vlc_preparser_req_GetItem(req); input_item_t *p_item = vlc_preparser_req_GetItem(req);
PlayerControllerPrivate *me = reinterpret_cast<PlayerControllerPrivate *>(userdata); PlayerControllerPrivate *me = reinterpret_cast<PlayerControllerPrivate *>(userdata);
me->onArtFetchEnded(p_item, input_item_IsArtFetched(p_item)); me->onArtFetchEnded(p_item, input_item_IsArtFetched(p_item));
vlc_preparser_req_Release(req);
} }

3
modules/misc/medialibrary/Thumbnailer.cpp

@ -49,7 +49,7 @@ Thumbnailer::Thumbnailer( vlc_medialibrary_module_t* ml )
throw std::runtime_error( "Failed to instantiate a vlc_preparser_t" ); throw std::runtime_error( "Failed to instantiate a vlc_preparser_t" );
} }
void Thumbnailer::onThumbnailToFilesComplete(vlc_preparser_req *, int , void Thumbnailer::onThumbnailToFilesComplete(vlc_preparser_req *req, int ,
const bool *result_array, const bool *result_array,
size_t result_count, void *data) size_t result_count, void *data)
{ {
@ -64,6 +64,7 @@ void Thumbnailer::onThumbnailToFilesComplete(vlc_preparser_req *, int ,
} }
ctx->thumbnailer->m_currentContext = nullptr; ctx->thumbnailer->m_currentContext = nullptr;
ctx->thumbnailer->m_cond.broadcast(); ctx->thumbnailer->m_cond.broadcast();
vlc_preparser_req_Release( req );
} }
bool Thumbnailer::generate( const medialibrary::IMedia&, const std::string& mrl, bool Thumbnailer::generate( const medialibrary::IMedia&, const std::string& mrl,

1
src/libvlccore.sym

@ -1055,5 +1055,6 @@ vlc_preparser_GenerateThumbnail
vlc_preparser_GenerateThumbnailToFiles vlc_preparser_GenerateThumbnailToFiles
vlc_preparser_Cancel vlc_preparser_Cancel
vlc_preparser_req_GetItem vlc_preparser_req_GetItem
vlc_preparser_req_Release
vlc_preparser_Delete vlc_preparser_Delete
vlc_preparser_SetTimeout vlc_preparser_SetTimeout

1
src/media_source/media_tree.c

@ -177,6 +177,7 @@ media_subtree_preparse_ended(vlc_preparser_req *req, int status, void *user_data
} }
vlc_media_tree_Notify(tree, on_preparse_end, subtree_root, status); vlc_media_tree_Notify(tree, on_preparse_end, subtree_root, status);
vlc_media_tree_Unlock(tree); vlc_media_tree_Unlock(tree);
vlc_preparser_req_Release(req);
} }
static inline void static inline void

1
src/playlist/preparse.c

@ -103,6 +103,7 @@ on_preparse_ended(vlc_preparser_req *req, int status, void *userdata)
vlc_playlist_Notify(playlist, on_items_updated, index, vlc_playlist_Notify(playlist, on_items_updated, index,
&playlist->items.data[index], 1); &playlist->items.data[index], 1);
vlc_playlist_Unlock(playlist); vlc_playlist_Unlock(playlist);
vlc_preparser_req_Release(req);
} }
static const struct vlc_preparser_cbs preparser_callbacks = { static const struct vlc_preparser_cbs preparser_callbacks = {

37
src/preparser/preparser.c

@ -87,6 +87,8 @@ struct vlc_preparser_req
struct vlc_runnable runnable; /**< to be passed to the executor */ struct vlc_runnable runnable; /**< to be passed to the executor */
struct vlc_list node; /**< node of vlc_preparser_t.submitted_tasks */ struct vlc_list node; /**< node of vlc_preparser_t.submitted_tasks */
vlc_atomic_rc_t rc;
}; };
static struct vlc_preparser_req * static struct vlc_preparser_req *
@ -106,6 +108,7 @@ PreparserRequestNew(vlc_preparser_t *preparser, void (*run)(void *), input_item_
req->pic = NULL; req->pic = NULL;
req->outputs = NULL; req->outputs = NULL;
req->output_count = 0; req->output_count = 0;
vlc_atomic_rc_init(&req->rc);
if (thumb_arg == NULL) if (thumb_arg == NULL)
req->thumb_arg = (struct vlc_thumbnailer_arg) { req->thumb_arg = (struct vlc_thumbnailer_arg) {
@ -220,7 +223,7 @@ OnArtFetchEnded(input_item_t *item, bool fetched, void *userdata)
struct vlc_preparser_req *req = userdata; struct vlc_preparser_req *req = userdata;
NotifyPreparseEnded(req); NotifyPreparseEnded(req);
PreparserRequestDelete(req); vlc_preparser_req_Release(req);
} }
static const input_fetcher_callbacks_t input_fetcher_callbacks = { static const input_fetcher_callbacks_t input_fetcher_callbacks = {
@ -312,7 +315,7 @@ ParserRun(void *userdata)
end: end:
NotifyPreparseEnded(req); NotifyPreparseEnded(req);
PreparserRequestDelete(req); vlc_preparser_req_Release(req);
} }
static bool static bool
@ -429,7 +432,7 @@ error:
req->cbs.thumbnailer_to_files->on_ended(req, req->preparse_status, req->cbs.thumbnailer_to_files->on_ended(req, req->preparse_status,
NULL, 0, req->userdata); NULL, 0, req->userdata);
picture_Release(pic); picture_Release(pic);
PreparserRequestDelete(req); vlc_preparser_req_Release(req);
free(result_array); free(result_array);
} }
@ -542,7 +545,7 @@ ThumbnailerRun(void *userdata)
error: error:
if (req != NULL) if (req != NULL)
PreparserRequestDelete(req); vlc_preparser_req_Release(req);
} }
static void static void
@ -555,6 +558,13 @@ Interrupt(struct vlc_preparser_req *req)
vlc_sem_post(&req->preparse_ended); vlc_sem_post(&req->preparse_ended);
} }
static struct vlc_preparser_req *
PreparserRequestRetain(struct vlc_preparser_req *req)
{
vlc_atomic_rc_inc(&req->rc);
return req;
}
vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent, vlc_preparser_t* vlc_preparser_New( vlc_object_t *parent,
const struct vlc_preparser_cfg *cfg ) const struct vlc_preparser_cfg *cfg )
{ {
@ -670,11 +680,11 @@ vlc_preparser_Push( vlc_preparser_t *preparser, input_item_t *item,
vlc_executor_Submit(preparser->parser, &req->runnable); vlc_executor_Submit(preparser->parser, &req->runnable);
return req; return PreparserRequestRetain(req);
} }
int ret = Fetch(req); int ret = Fetch(req);
return ret == VLC_SUCCESS ? req : NULL; return ret == VLC_SUCCESS ? PreparserRequestRetain(req) : NULL;
} }
vlc_preparser_req * vlc_preparser_req *
@ -700,7 +710,7 @@ vlc_preparser_GenerateThumbnail( vlc_preparser_t *preparser, input_item_t *item,
vlc_executor_Submit(preparser->thumbnailer, &req->runnable); vlc_executor_Submit(preparser->thumbnailer, &req->runnable);
return req; return PreparserRequestRetain(req);
} }
static int static int
@ -834,7 +844,7 @@ vlc_preparser_GenerateThumbnailToFiles( vlc_preparser_t *preparser, input_item_t
vlc_executor_Submit(preparser->thumbnailer, &req->runnable); vlc_executor_Submit(preparser->thumbnailer, &req->runnable);
return req; return PreparserRequestRetain(req);
} }
size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req *req ) size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req *req )
@ -900,7 +910,7 @@ size_t vlc_preparser_Cancel( vlc_preparser_t *preparser, vlc_preparser_req *req
NULL, 0, NULL, 0,
req_itr->userdata); req_itr->userdata);
} }
PreparserRequestDelete(req_itr); vlc_preparser_req_Release(req_itr);
/* Small optimisation in the likely case where the user cancel /* Small optimisation in the likely case where the user cancel
* only one task */ * only one task */
@ -931,6 +941,15 @@ void vlc_preparser_SetTimeout( vlc_preparser_t *preparser,
preparser->timeout = timeout; preparser->timeout = timeout;
} }
void vlc_preparser_req_Release( vlc_preparser_req *req )
{
assert(req != NULL);
if (!vlc_atomic_rc_dec(&req->rc))
return;
PreparserRequestDelete(req);
}
void vlc_preparser_Delete( vlc_preparser_t *preparser ) void vlc_preparser_Delete( vlc_preparser_t *preparser )
{ {
/* In case vlc_preparser_Deactivate() has not been called */ /* In case vlc_preparser_Deactivate() has not been called */

4
test/libvlc/media.c

@ -211,21 +211,21 @@ static void test_media_tracks(libvlc_instance_t *vlc)
static void input_item_preparse_timeout( vlc_preparser_req *req, static void input_item_preparse_timeout( vlc_preparser_req *req,
int status, void *user_data ) int status, void *user_data )
{ {
VLC_UNUSED(req);
vlc_sem_t *p_sem = user_data; vlc_sem_t *p_sem = user_data;
assert( status == VLC_ETIMEOUT ); assert( status == VLC_ETIMEOUT );
vlc_sem_post(p_sem); vlc_sem_post(p_sem);
vlc_preparser_req_Release(req);
} }
static void input_item_preparse_cancel( vlc_preparser_req *req, static void input_item_preparse_cancel( vlc_preparser_req *req,
int status, void *user_data ) int status, void *user_data )
{ {
VLC_UNUSED(req);
vlc_sem_t *p_sem = user_data; vlc_sem_t *p_sem = user_data;
assert( status == -EINTR ); assert( status == -EINTR );
vlc_sem_post(p_sem); vlc_sem_post(p_sem);
vlc_preparser_req_Release(req);
} }
static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout, static void test_input_metadata_timeout(libvlc_instance_t *vlc, int timeout,

4
test/src/preparser/thumbnail.c

@ -71,7 +71,6 @@ struct test_ctx
static void thumbnailer_callback( vlc_preparser_req *req, int status, static void thumbnailer_callback( vlc_preparser_req *req, int status,
picture_t* thumbnail, void *data ) picture_t* thumbnail, void *data )
{ {
(void) req;
struct test_ctx* p_ctx = data; struct test_ctx* p_ctx = data;
vlc_mutex_lock( &p_ctx->lock ); vlc_mutex_lock( &p_ctx->lock );
@ -113,6 +112,7 @@ static void thumbnailer_callback( vlc_preparser_req *req, int status,
p_ctx->b_done = true; p_ctx->b_done = true;
vlc_cond_signal( &p_ctx->cond ); vlc_cond_signal( &p_ctx->cond );
vlc_mutex_unlock( &p_ctx->lock ); vlc_mutex_unlock( &p_ctx->lock );
vlc_preparser_req_Release( req );
} }
static void test_thumbnails( libvlc_instance_t* p_vlc ) static void test_thumbnails( libvlc_instance_t* p_vlc )
@ -189,12 +189,12 @@ static void test_thumbnails( libvlc_instance_t* p_vlc )
static void thumbnailer_callback_cancel( vlc_preparser_req *req, int status, static void thumbnailer_callback_cancel( vlc_preparser_req *req, int status,
picture_t* p_thumbnail, void *data ) picture_t* p_thumbnail, void *data )
{ {
(void) req;
assert( p_thumbnail == NULL ); assert( p_thumbnail == NULL );
assert( status == -EINTR ); assert( status == -EINTR );
vlc_sem_t *sem = data; vlc_sem_t *sem = data;
vlc_sem_post(sem); vlc_sem_post(sem);
vlc_preparser_req_Release(req);
} }
static void test_cancel_thumbnail( libvlc_instance_t* p_vlc ) static void test_cancel_thumbnail( libvlc_instance_t* p_vlc )

3
test/src/preparser/thumbnail_to_files.c

@ -112,13 +112,13 @@ static void parser_on_ended(vlc_preparser_req *req, int status, void *userdata)
assert(es_fmt->video.i_height == test_entry->out_height); assert(es_fmt->video.i_height == test_entry->out_height);
vlc_sem_post(&context->sem); vlc_sem_post(&context->sem);
vlc_preparser_req_Release(req);
} }
static void on_ended(vlc_preparser_req *req, int status, static void on_ended(vlc_preparser_req *req, int status,
const bool *result_array, size_t result_count, void *data) const bool *result_array, size_t result_count, void *data)
{ {
struct context *context = data; struct context *context = data;
(void) req;
assert(status == VLC_SUCCESS); assert(status == VLC_SUCCESS);
assert(context->test_count == result_count); assert(context->test_count == result_count);
@ -163,6 +163,7 @@ static void on_ended(vlc_preparser_req *req, int status,
input_item_Release(thumb); input_item_Release(thumb);
} }
} }
vlc_preparser_req_Release(req);
} }
static int get_formats(enum vlc_thumbnailer_format *out_format, static int get_formats(enum vlc_thumbnailer_format *out_format,

Loading…
Cancel
Save