Commit 49fd520a authored by Srikanth Raju's avatar Srikanth Raju

ML: Include Media Library header

parent 9f1f778c
/*****************************************************************************
* vlc_media_library.h: SQL-based media library
*****************************************************************************
* Copyright (C) 2008-2010 the VideoLAN Team and AUTHORS
* $Id$
*
* Authors: Antoine Lejeune <phytos@videolan.org>
* Jean-Philippe André <jpeg@videolan.org>
* Rémi Duraffort <ivoire@videolan.org>
* Adrien Maglo <magsoft@videolan.org>
* Srikanth Raju <srikiraju at gmail dot com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 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 General Public License for more details.
*
* You should have received a copy of the GNU 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_MEDIA_LIBRARY_H
# define VLC_MEDIA_LIBRARY_H
# ifdef __cplusplus
extern "C" {
# endif
#include <vlc_common.h>
#include <assert.h>
#include <vlc_playlist.h>
/*****************************************************************************
* ML Enums
*****************************************************************************/
#define ML_PERSON_ARTIST "Artist"
#define ML_PERSON_ALBUM_ARTIST "Album Artist"
#define ML_PERSON_ENCODER "Encoder"
#define ML_PERSON_PUBLISHER "Publisher"
#define ml_priv( gc, t ) ((t *)(((char *)(gc)) - offsetof(t, ml_gc_data)))
/** List of Query select types.
* In a query array or variable argument list, each select type is followed
* by an argument (X) of variable type (char* or int, @see ml_element_t).
* These types can be used either in the query list or in the result array.
* Some types are reserved for the result array:
*/
typedef enum
{
ML_ALBUM = 1, /**< Album Title */
ML_ALBUM_ID, /**< Album ID */
ML_ALBUM_COVER, /**< Album Cover art url */
/* FIXME: Remove ML_ARTIST */
ML_ARTIST, /**< Artist, interpreted as ML_PEOPLE
&& ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
ML_ARTIST_ID, /**< Artist ID, interpreted as ML_PEOPLE_ID
&& ML_PEOPLE_ROLE = ML_PERSON_ARTIST */
ML_COMMENT, /**< Comment about media */
ML_COUNT_MEDIA, /**< Number of medias */
ML_COUNT_ALBUM, /**< Number of albums */
ML_COUNT_PEOPLE, /**< Number of people */
ML_COVER, /**< Cover art url */
ML_DURATION, /**< Duration in ms */
ML_DISC_NUMBER, /**< Disc number of the track */
ML_EXTRA, /**< Extra/comment (string) on the media */
ML_FIRST_PLAYED, /**< First time media was played */
ML_FILESIZE, /**< Size of the media file */
ML_GENRE, /**< Genre of the media (if any) */
ML_ID, /**< Media ID */
ML_IMPORT_TIME, /**< Date when media was imported */
ML_LANGUAGE, /**< Language */
ML_LAST_PLAYED, /**< Last play UNIX timestamp */
ML_LAST_SKIPPED, /**< Time when media was last skipped */
ML_ORIGINAL_TITLE, /**< Media original title (if any) */
ML_PEOPLE, /**< Any People associated with this media */
ML_PEOPLE_ID, /**< Id of a person */
ML_PEOPLE_ROLE, /**< Person role */
ML_PLAYED_COUNT, /**< Media play count */
ML_PREVIEW, /**< Url of the video preview */
ML_SKIPPED_COUNT, /**< Number of times skipped */
ML_SCORE, /**< Computed media score */
ML_TITLE, /**< Media title */
ML_TRACK_NUMBER, /**< Media track number (if any) */
ML_TYPE, /**< Media type. @see ml_type_e */
ML_URI, /**< Media full URI. */
ML_VOTE, /**< Media user vote value */
ML_YEAR, /**< Media publishing year */
ML_DIRECTORY, /**< Monitored directory */
ML_MEDIA, /**< Full media descriptor. @see ml_media_t */
ML_MEDIA_SPARSE, /**< Sparse media. @see ml_media_t */
ML_MEDIA_EXTRA, /**< Sparse + Extra = Full media */
/* Some special elements */
ML_LIMIT = -1, /**< Limit a query to X results */
ML_SORT_DESC = -2, /**< Sort a query descending on argument X */
ML_SORT_ASC = -3, /**< Sort a query ascending on argument X */
ML_DISTINCT = -4, /**< Add DISTINCT to SELECT statements. */
ML_END = -42 /**< End of argument list */
} ml_select_e;
/** Media types (audio, video, etc...) */
typedef enum
{
ML_UNKNOWN = 0, /**< Unknown media type */
ML_AUDIO = 1 << 0, /**< Audio only media */
ML_VIDEO = 1 << 1, /**< Video media. May contain audio channels */
ML_STREAM = 1 << 2, /**< Streamed media = not a local file */
ML_NODE = 1 << 3, /**< Nodes like simple nodes, directories, playlists, etc */
ML_REMOVABLE = 1 << 4, /**< Removable media: CD/DVD/Card/... */
} ml_type_e;
/** Query result item/list type: integers, strings, medias, timestamps */
typedef enum {
ML_TYPE_INT, /**< Object is an int */
ML_TYPE_PSZ, /**< A string char* */
ML_TYPE_TIME, /**< A timestamp mtime_t */
ML_TYPE_MEDIA, /**< A pointer to a media ml_media_t* */
} ml_result_type_e;
/** Arguments for VLC Control for the media library */
typedef enum
{
ML_SET_DATABASE, /**< arg1 = char *psz_host
arg2 = int i_port
arg3 = char *psz_user
arg4 = char *psz_pass */
ML_INIT_DATABASE, /**< No arg */
ML_ADD_INPUT_ITEM, /**< arg1 = input_item_t* */
ML_ADD_PLAYLIST_ITEM, /**< arg1 = playlist_item_t * */
ML_ADD_MONITORED, /**< arg1 = char* */
ML_DEL_MONITORED, /**< arg1 = char* */
ML_GET_MONITORED, /**< arg1 = vlc_array_t* */
} ml_control_e;
/* Operations that can be specified between find conditions */
typedef enum
{
ML_OP_NONE = 0, /**< This is to specify an actual condition */
ML_OP_AND, /**< AND condition */
ML_OP_OR, /**< OR condition */
ML_OP_NOT, /**< NOT condition */
ML_OP_SPECIAL /**< This is for inclusion of
* special stuffs like LIMIT */
} ml_op_e;
/* Comparison operators used in a single find condition */
typedef enum
{
ML_COMP_NONE = 0,
ML_COMP_LESSER, ///< <
ML_COMP_LESSER_OR_EQUAL, ///< <=
ML_COMP_EQUAL, ///< ==
ML_COMP_GREATER_OR_EQUAL, ///< >=
ML_COMP_GREATER, ///< >
ML_COMP_HAS, ///< "Contains", equivalent to SQL "LIKE %x%"
ML_COMP_STARTS_WITH, ///< Equivalent to SQL "LIKE %x"
ML_COMP_ENDS_WITH, ///< Equivalent to SQL "LIKE x%"
} ml_comp_e;
/*****************************************************************************
* ML Structures and types
*****************************************************************************/
typedef struct media_library_t media_library_t;
typedef struct media_library_sys_t media_library_sys_t;
typedef struct ml_media_t ml_media_t;
typedef struct ml_result_t ml_result_t;
typedef struct ml_element_t ml_element_t;
typedef struct ml_person_t ml_person_t;
typedef struct ml_ftree_t ml_ftree_t;
typedef struct ml_gc_object_t
{
vlc_spinlock_t spin;
bool pool;
uintptr_t refs;
void (*pf_destructor) (struct ml_gc_object_t *);
} ml_gc_object_t;
#define ML_GC_MEMBERS ml_gc_object_t ml_gc_data;
/** Main structure of the media library. VLC object. */
struct media_library_t
{
VLC_COMMON_MEMBERS
module_t *p_module; /**< the media library module */
media_library_sys_t *p_sys; /**< internal struture */
/** Member functions */
struct
{
/**< Search in the database */
int ( * pf_Find ) ( media_library_t *p_media_library,
vlc_array_t *p_result_array,
va_list args );
/**< Search in the database using an array of arguments */
int ( * pf_FindAdv ) ( media_library_t *p_media_library,
vlc_array_t *p_result_array,
ml_select_e selected_type,
const char *psz_lvalue,
ml_ftree_t *tree );
/**< Update the database using an array of arguments */
int ( * pf_Update ) ( media_library_t *p_media_library,
ml_select_e selected_type,
const char *psz_lvalue,
ml_ftree_t *where,
vlc_array_t *changes );
/**< Delete many medias in the database */
int ( * pf_Delete ) ( media_library_t *p_media_library,
vlc_array_t *p_array );
/**< Control the media library */
int ( * pf_Control ) ( media_library_t *p_media_library,
int i_query, va_list args );
/**< Create associated input item */
input_item_t* ( * pf_InputItemFromMedia ) (
media_library_t *p_media_library, int i_media );
/**< Get a media */
ml_media_t* ( * pf_GetMedia ) (
media_library_t *p_media_library, int i_media,
ml_select_e select, bool reload );
} functions;
};
/**
* @brief Structure to describe a media
*
* This is the main structure holding the meta data in ML.
* @see b_sparse indicates whether the media struct has valid values
* in its Extra fields. Otherwise, it must be loaded with the API
* function.
* @see i_id indicates whether this struct is saved in the ML if i_id > 0
* Otherwise, it can be added to the database
*/
struct ml_media_t
{
ML_GC_MEMBERS
vlc_mutex_t lock; /**< Mutex for multithreaded access */
bool b_sparse; /**< Specifies if media is loaded fully */
ml_type_e i_type; /**< Type of the media (ml_type_e) */
int8_t i_vote; /**< User vote */
int16_t i_disc_number; /**< Disc number of media */
int16_t i_track_number; /**< Track number */
int16_t i_year; /**< Year of release */
int32_t i_id; /**< Media ID in the database */
int32_t i_score; /**< Score computed about the media */
int32_t i_album_id; /**< Album id */
int32_t i_played_count; /**< How many time the media was played */
int32_t i_skipped_count; /**< No. of times file was skipped */
int32_t i_bitrate; /**< Extra: Bitrate of the media */
int32_t i_samplerate; /**< Extra: Samplerate of the media */
int32_t i_bpm; /**< Extra: Beats per minute */
char *psz_uri; /**< URI to find the media */
char *psz_title; /**< Title of the media */
char *psz_orig_title; /**< Original title (mainly for movies) */
char *psz_album; /**< Name of the album */
char *psz_cover; /**< URI of the cover */
char *psz_genre; /**< Genre of the media */
char *psz_preview; /**< Preview thumbnail for video, if any */
char *psz_comment; /**< Comment or description about media */
char *psz_language; /**< Extra: Language */
char *psz_extra; /**< Extra: Some extra datas like lyrics */
ml_person_t *p_people; /**< Extra: People associated with this
media This meta holds only one
artist if b_sparse = true */
int64_t i_filesize; /**< Size of the file */
mtime_t i_duration; /**< Duration in microseconds */
mtime_t i_last_played; /**< Time when the media was last played */
mtime_t i_last_skipped; /**< Time when the media was last skipped */
mtime_t i_first_played; /**< First played */
mtime_t i_import_time; /**< Time when media was added */
};
/**
* @brief Main communication struct between GUI and sql_media_library.
* Generic representation of an ML/SQL query result.
*/
struct ml_result_t
{
int32_t id; /**< Media/Album/Artist... ID (if any) */
ml_result_type_e type; /**< Type of value */
union
{
/* Classical results */
int i;
char *psz;
mtime_t time;
/* Complex result: media descriptor */
ml_media_t *p_media;
} value; /**< Value of the result obtained */
};
/**
* @brief Element of a query: criteria type/value pair
* Used for update and delete queries
*/
struct ml_element_t
{
ml_select_e criteria; /**< SELECT criteria type. @see ml_select_e */
union
{
int i;
char* str;
} value; /**< SELECT criteria value (string or int) */
union
{
int i;
char* str;
} lvalue; /**< Refer to @see ml_ftree_t lvalue docs */
};
/**
* Binary tree used to parse the WHERE condition for a search
*
* Let [expr] indicate a valid expression
* [expr] = [expr] AND [expr], where the left and right are respective
* [expr] = [expr] OR [expr]
* [expr] = [expr] NOT [NULL]
* [expr] = [expr] SPEC [spec_expr]
* [expr] = [criteria=val]
* [spec_expr] = [DISTINCT/LIMIT/ASC/DESC = val ]
*/
struct ml_ftree_t
{
ml_op_e op; /**< Operator. ML_OP_NONE means this is a leaf
* node. Criteria and value gives its data.
* ML_OP_SPECIAL specifies a special node
* that does not form a part of the WHERE.
* The right node consists of the data
* with its criteria set to the special val
* and the left node is the corresponding
* subtree of the parent node.
* ML_OP_NOT only left sub tree is considered
* ML_OP_AND and ML_OP_OR consider both
* left and right subtrees */
ml_ftree_t *left; /**< Left child of Bin tree */
ml_ftree_t *right; /**< Right child of Bin tree */
ml_select_e criteria; /**< SELECT criteria type @see ml_select_e
* The criteria value is considered only when
* op = ML_OP_NONE i.e. in leaf nodes */
ml_comp_e comp; /**< Condition between type and value */
union
{
int i;
char *str;
} value; /**< SELECT criteria value ( string or int ) */
union
{
int i;
char *str;
} lvalue; /**< Used as key value for people types/roles.
An empty string "" denotes ANY person role.
NULL is used for all other criterias */
};
/**
* Person class. Implemented as a linked list
*/
struct ml_person_t
{
char *psz_role; /**< Type of person */
char *psz_name; /**< Name of the person */
int i_id; /**< ID in the database */
ml_person_t *p_next; /**< Next person in list */
};
/*****************************************************************************
* ML Function headers
*****************************************************************************/
/**
* @brief Acquire a reference to the media library singleton
* @param p_this The object holding the media library
* @return The media library object. NULL if the media library
* object could not be loaded
*/
VLC_EXPORT( media_library_t*, __ml_Hold, ( vlc_object_t* p_this ) );
#define ml_Hold( a ) __ml_Hold( VLC_OBJECT(a) )
/**
* @brief Discard your ref to media library
* @param p_this The object holding the media library
*/
VLC_EXPORT( void, __ml_Release, ( vlc_object_t* p_this ) );
#define ml_Release(a) __ml_Release( VLC_OBJECT(a))
/**
* @brief Create a Media Library VLC object.
* @param p_this Parent to attach the ML object to.
* @param psz_name Name for the module
* @return The ML object.
*/
VLC_EXPORT( media_library_t*, __ml_Create, ( vlc_object_t *p_this, char* psz_name ) );
/**
* @brief Destructor for the Media library singleton
* @param p_this Parent the ML object is attached to
*/
VLC_EXPORT( void, __ml_Destroy, ( vlc_object_t* p_this ) );
/**
* @brief Control the Media Library
* @param p_media_library the media library object
* @param i_type one of ml_control_e values @see ml_control_e.
* @param ... optional arguments.
* @return VLC_SUCCESS or an error
*/
static inline int ml_ControlVa( media_library_t *p_media_library,
ml_control_e i_type, va_list args )
{
return p_media_library->functions.pf_Control( p_media_library,
i_type,
args );
}
/**
* @brief Control the Media Library
* @param i_type one of ml_control_e values @see ml_control_e.
* Variable arguments list equivalent
*/
#define ml_Control( a, b, args... ) __ml_Control( a, b, ## args )
static inline int __ml_Control( media_library_t *p_media_library,
ml_control_e i_type, ... )
{
va_list args;
int returned;
va_start( args, i_type );
returned = ml_ControlVa( p_media_library, i_type, args );
va_end( args );
return returned;
}
/**
* @brief Determine an attribute's type (int or string)
* @param meta Attribute to test @see ml_select_e
* @return -1 if invalid, 0 if this is an integer, 1 if this is a string
*/
static inline int ml_AttributeIsString( ml_select_e meta )
{
switch( meta )
{
/* Strings */
case ML_ALBUM:
case ML_ARTIST:
case ML_COMMENT:
case ML_COVER:
case ML_EXTRA:
case ML_GENRE:
case ML_LANGUAGE:
case ML_PREVIEW:
case ML_PEOPLE:
case ML_PEOPLE_ROLE:
case ML_ORIGINAL_TITLE:
case ML_TITLE:
case ML_URI:
return 1;
/* Integers */
case ML_ALBUM_ID:
case ML_ARTIST_ID:
case ML_DURATION:
case ML_DISC_NUMBER:
case ML_COUNT_MEDIA:
case ML_COUNT_ALBUM:
case ML_COUNT_PEOPLE:
case ML_FILESIZE:
case ML_FIRST_PLAYED:
case ML_ID:
case ML_IMPORT_TIME:
case ML_LAST_PLAYED:
case ML_LIMIT:
case ML_PLAYED_COUNT:
case ML_PEOPLE_ID:
case ML_SCORE:
case ML_SKIPPED_COUNT:
case ML_TRACK_NUMBER:
case ML_TYPE:
case ML_VOTE:
case ML_YEAR:
return 0;
/* Invalid or no following value (in a SELECT statement) */
default:
return -1;
}
}
/* Reference Counting Functions */
/**
* @brief Increment reference count of media
* @param p_media The media object
*/
static inline void ml_gc_incref( ml_media_t* p_media )
{
unsigned refs;
ml_gc_object_t* p_gc = &p_media->ml_gc_data;
assert( p_gc );
vlc_spin_lock (&p_gc->spin);
refs = ++p_gc->refs;
vlc_spin_unlock (&p_gc->spin);
assert (refs != 1); /* there had to be a reference already */
}
/**
* @brief Decrease reference count of media
* @param p_media The media object
*/
static inline void ml_gc_decref( ml_media_t* p_media )
{
/* The below code is from vlc_release(). */
unsigned refs;
bool pool;
ml_gc_object_t* p_gc = &p_media->ml_gc_data;
assert( p_gc );
vlc_spin_lock (&p_gc->spin);
assert( p_gc->refs != 0 );
refs = --p_gc->refs;
pool = p_gc->pool;
assert( ( refs != 0 && p_gc->pool == true ) || ( refs == 0 && p_gc->pool == false ) );
vlc_spin_unlock (&p_gc->spin);
if( refs == 0 && pool == false )
{
vlc_spin_destroy (&p_gc->spin);
p_gc->pf_destructor (p_gc);
}
}
/*****************************************************************************
* ML Free Functions
*****************************************************************************/
/**
* @brief Free a person object
* @param p_media Person object to free
* @note This function is NOT threadsafe
*/
static inline void ml_FreePeople( ml_person_t *p_person )
{
if( p_person == NULL )
return;
ml_FreePeople( p_person->p_next );
free( p_person->psz_name );
free( p_person->psz_role );
free( p_person );
}
/**
* @brief Free only the content of a media. @see ml_media_t
* @param p_media Media object
* @note This function is NOT threadsafe.
*/
static inline void ml_FreeMediaContent( ml_media_t *p_media )
{
free( p_media->psz_uri );
free( p_media->psz_title );
free( p_media->psz_orig_title );
free( p_media->psz_cover );
free( p_media->psz_comment );
free( p_media->psz_extra );
free( p_media->psz_genre );
free( p_media->psz_album );
free( p_media->psz_preview );
free( p_media->psz_language );
ml_FreePeople( p_media->p_people );
p_media->b_sparse = true;
p_media->i_id = 0;
p_media->i_type = ML_UNKNOWN;
p_media->i_album_id = 0;
p_media->i_disc_number = 0;
p_media->i_track_number = 0;
p_media->i_year = 0;
p_media->i_vote = 0;
p_media->i_score = 0;
p_media->i_filesize = 0;
p_media->i_duration = 0;
p_media->i_played_count = 0;
p_media->i_last_played = 0;
p_media->i_skipped_count = 0;
p_media->i_last_skipped = 0;
p_media->i_first_played = 0;
p_media->i_import_time = 0;
p_media->i_bitrate = 0;
p_media->i_samplerate = 0;
p_media->i_bpm = 0;
}
/**
* @brief Free a result item. @see ml_result_t
* @param p_result Result item to free
* @note This will free any strings and decref medias.
*/
static inline void ml_FreeResult( ml_result_t *p_result )
{
if( p_result )
{
switch( p_result->type )
{
case ML_TYPE_PSZ:
free( p_result->value.psz );
break;
case ML_TYPE_MEDIA:
ml_gc_decref( p_result->value.p_media );
break;
default:
break;
}
free( p_result );
}
}
/**
* @brief Free a ml_element_t item.
* @param p_find Find object to free
* @see ml_element_t */
static inline void ml_FreeElement( ml_element_t *p_elt )
{
if( p_elt )
{
if( ml_AttributeIsString( p_elt->criteria ) )
{
free( p_elt->value.str );
}
if( p_elt->criteria == ML_PEOPLE )
{
free( p_elt->lvalue.str );
}
free( p_elt );
}
}
/**
* @brief Destroy a vlc_array_t of ml_result_t
* @param ml_result_array The result array to free
* @note Frees all results and contents of the results
*/
static inline void ml_DestroyResultArray( vlc_array_t *p_result_array )
{
for( int i = 0; i < vlc_array_count( p_result_array ); i++ )
{
ml_FreeResult( ( ml_result_t* ) vlc_array_item_at_index(
p_result_array, i ) );
}
}
/*****************************************************************************
* ML Object Management Functions
*****************************************************************************/
/** Helpers for locking and unlocking */
#define ml_LockMedia( a ) vlc_mutex_lock( &a->lock )
#define ml_UnlockMedia( a ) vlc_mutex_unlock( &a->lock )
/**
* @brief Object constructor for ml_media_t
* @param p_ml The media library object
* @param id If 0, this item isn't in database. If non zero, it is and
* it will be a singleton
* @param select Type of object
* @param reload Whether to reload from database
*/
VLC_EXPORT( ml_media_t*, media_New, ( media_library_t* p_ml, int id,
ml_select_e select, bool reload ) );
/* Forward declaration */
static inline int ml_CopyPersons( ml_person_t** a, ml_person_t* b );
/**
* @brief Copy all members of a ml_media_t to another.
* @param b Destination media, already allocated
* @param a Source media, cannot be NULL, const
* @note This does not check memory allocation (for strdup). It is threadsafe
* @todo Free b content, before inserting a?
*/
static inline int ml_CopyMedia( ml_media_t *b, ml_media_t *a )
{
if( !a || !b ) return VLC_EGENERIC;
assert( a != b );
ml_LockMedia( a );
ml_LockMedia( b );
b->b_sparse = a->b_sparse;
b->i_id = a->i_id;
b->i_type = a->i_type;
b->i_album_id = a->i_album_id;
b->i_disc_number = a->i_disc_number;
b->i_track_number = a->i_track_number;
b->i_year = a->i_year;
b->i_vote = a->i_vote;
b->i_score = a->i_score;
b->i_filesize = a->i_filesize;
b->i_duration = a->i_duration;
b->i_played_count = a->i_played_count;
b->i_last_played = a->i_last_played;
b->i_skipped_count = a->i_skipped_count;
b->i_last_skipped = a->i_last_skipped;
b->i_first_played = a->i_first_played;
b->i_import_time = a->i_import_time;
b->i_bitrate = a->i_bitrate;
b->i_samplerate = a->i_samplerate;
b->i_bpm = a->i_bpm;
free( b->psz_uri );
if( a->psz_uri )
b->psz_uri = strdup( a->psz_uri );
free( b->psz_title );
if( a->psz_title )
b->psz_title = strdup( a->psz_title );
free( b->psz_orig_title );
if( a->psz_orig_title )
b->psz_orig_title = strdup( a->psz_orig_title );
free( b->psz_album );
if( a->psz_album )
b->psz_album = strdup( a->psz_album );
free( b->psz_cover );
if( a->psz_cover )
b->psz_cover = strdup( a->psz_cover );