gstreamer/gst-libs/gst/vaapi/gstvaapidisplaycache.c

392 lines
9.8 KiB
C

/*
* gstvaapidisplaycache.c - VA display cache
*
* Copyright (C) 2012-2013 Intel Corporation
* Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
*
* This library 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 library 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 library; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA
*/
#include "sysdeps.h"
#include <glib.h>
#include <string.h>
#include "gstvaapidisplaycache.h"
#define DEBUG 1
#include "gstvaapidebug.h"
typedef struct _CacheEntry CacheEntry;
struct _CacheEntry
{
GstVaapiDisplayInfo info;
};
struct _GstVaapiDisplayCache
{
GMutex mutex;
GList *list;
};
static void
cache_entry_free (CacheEntry * entry)
{
GstVaapiDisplayInfo *info;
if (!entry)
return;
info = &entry->info;
if (info->display_name) {
g_free (info->display_name);
info->display_name = NULL;
}
g_slice_free (CacheEntry, entry);
}
static CacheEntry *
cache_entry_new (const GstVaapiDisplayInfo * di)
{
GstVaapiDisplayInfo *info;
CacheEntry *entry;
entry = g_slice_new (CacheEntry);
if (!entry)
return NULL;
info = &entry->info;
info->display = di->display;
info->va_display = di->va_display;
info->native_display = di->native_display;
info->display_type = di->display_type;
info->display_name = NULL;
if (di->display_name) {
info->display_name = g_strdup (di->display_name);
if (!info->display_name)
goto error;
}
return entry;
error:
cache_entry_free (entry);
return NULL;
}
static inline gboolean
is_compatible_display_type (const GstVaapiDisplayType display_type,
guint display_types)
{
if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY)
return TRUE;
if (display_types == GST_VAAPI_DISPLAY_TYPE_ANY)
return TRUE;
return ((1U << display_type) & display_types) != 0;
}
static GList *
cache_lookup_1 (GstVaapiDisplayCache * cache, GCompareFunc func,
gconstpointer data, guint display_types)
{
GList *l;
g_mutex_lock (&cache->mutex);
for (l = cache->list; l != NULL; l = l->next) {
GstVaapiDisplayInfo *const info = &((CacheEntry *) l->data)->info;
if (!is_compatible_display_type (info->display_type, display_types))
continue;
if (func (info, data))
break;
}
g_mutex_unlock (&cache->mutex);
return l;
}
static inline const GstVaapiDisplayInfo *
cache_lookup (GstVaapiDisplayCache * cache, GCompareFunc func,
gconstpointer data, guint display_types)
{
GList *const m = cache_lookup_1 (cache, func, data, display_types);
return m ? &((CacheEntry *) m->data)->info : NULL;
}
static gint
compare_display (gconstpointer a, gconstpointer display)
{
const GstVaapiDisplayInfo *const info = a;
return info->display == display;
}
static gint
compare_va_display (gconstpointer a, gconstpointer va_display)
{
const GstVaapiDisplayInfo *const info = a;
return info->va_display == va_display;
}
static gint
compare_native_display (gconstpointer a, gconstpointer native_display)
{
const GstVaapiDisplayInfo *const info = a;
return info->native_display == native_display;
}
static gint
compare_display_name (gconstpointer a, gconstpointer b)
{
const GstVaapiDisplayInfo *const info = a;
const gchar *const display_name = b;
if (info->display_name == NULL && display_name == NULL)
return TRUE;
if (!info->display_name || !display_name)
return FALSE;
return strcmp (info->display_name, display_name) == 0;
}
/**
* gst_vaapi_display_cache_new:
*
* Creates a new VA display cache.
*
* Return value: the newly created #GstVaapiDisplayCache object
*/
GstVaapiDisplayCache *
gst_vaapi_display_cache_new (void)
{
GstVaapiDisplayCache *cache;
cache = g_slice_new0 (GstVaapiDisplayCache);
if (!cache)
return NULL;
g_mutex_init (&cache->mutex);
return cache;
}
/**
* gst_vaapi_display_cache_new:
* @cache: the #GstVaapiDisplayCache to destroy
*
* Destroys a VA display cache.
*/
void
gst_vaapi_display_cache_free (GstVaapiDisplayCache * cache)
{
GList *l;
if (!cache)
return;
if (cache->list) {
for (l = cache->list; l != NULL; l = l->next)
cache_entry_free (l->data);
g_list_free (cache->list);
cache->list = NULL;
}
g_mutex_clear (&cache->mutex);
g_slice_free (GstVaapiDisplayCache, cache);
}
/**
* gst_vaapi_display_cache_get_size:
* @cache: the #GstVaapiDisplayCache
*
* Gets the size of the display cache @cache.
*
* Return value: the size of the display cache
*/
guint
gst_vaapi_display_cache_get_size (GstVaapiDisplayCache * cache)
{
guint size;
g_return_val_if_fail (cache != NULL, 0);
g_mutex_lock (&cache->mutex);
size = g_list_length (cache->list);
g_mutex_unlock (&cache->mutex);
return size;
}
/**
* gst_vaapi_display_cache_add:
* @cache: the #GstVaapiDisplayCache
* @info: the display cache info to add
*
* Adds a new entry with data from @info. The display @info data is
* copied into the newly created cache entry.
*
* Return value: %TRUE on success
*/
gboolean
gst_vaapi_display_cache_add (GstVaapiDisplayCache * cache,
GstVaapiDisplayInfo * info)
{
CacheEntry *entry;
g_return_val_if_fail (cache != NULL, FALSE);
g_return_val_if_fail (info != NULL, FALSE);
entry = cache_entry_new (info);
if (!entry)
return FALSE;
g_mutex_lock (&cache->mutex);
cache->list = g_list_prepend (cache->list, entry);
g_mutex_unlock (&cache->mutex);
return TRUE;
}
/**
* gst_vaapi_display_cache_remove:
* @cache: the #GstVaapiDisplayCache
* @display: the display to remove from cache
*
* Removes any cache entry that matches the specified #GstVaapiDisplay.
*/
void
gst_vaapi_display_cache_remove (GstVaapiDisplayCache * cache,
GstVaapiDisplay * display)
{
GList *m;
m = cache_lookup_1 (cache, compare_display, display,
GST_VAAPI_DISPLAY_TYPE_ANY);
if (!m)
return;
cache_entry_free (m->data);
g_mutex_lock (&cache->mutex);
cache->list = g_list_delete_link (cache->list, m);
g_mutex_unlock (&cache->mutex);
}
/**
* gst_vaapi_display_cache_lookup:
* @cache: the #GstVaapiDisplayCache
* @display: the display to find
*
* Looks up the display cache for the specified #GstVaapiDisplay.
*
* Return value: a #GstVaapiDisplayInfo matching @display, or %NULL if
* none was found
*/
const GstVaapiDisplayInfo *
gst_vaapi_display_cache_lookup (GstVaapiDisplayCache * cache,
GstVaapiDisplay * display)
{
g_return_val_if_fail (cache != NULL, NULL);
g_return_val_if_fail (display != NULL, NULL);
return cache_lookup (cache, compare_display, display,
GST_VAAPI_DISPLAY_TYPE_ANY);
}
/**
* gst_vaapi_display_cache_lookup_custom:
* @cache: the #GstVaapiDisplayCache
* @func: an comparison function
* @data: user data passed to the function
*
* Looks up an element in the display @cache using the supplied
* function @func to find the desired element. It iterates over all
* elements in cache, calling the given function which should return
* %TRUE when the desired element is found.
*
* The comparison function takes two gconstpointer arguments, a
* #GstVaapiDisplayInfo as the first argument, and that is used to
* compare against the given user @data argument as the second
* argument.
*
* Return value: a #GstVaapiDisplayInfo causing @func to succeed
* (i.e. returning %TRUE), or %NULL if none was found
*/
const GstVaapiDisplayInfo *
gst_vaapi_display_cache_lookup_custom (GstVaapiDisplayCache * cache,
GCompareFunc func, gconstpointer data, guint display_types)
{
g_return_val_if_fail (cache != NULL, NULL);
g_return_val_if_fail (func != NULL, NULL);
return cache_lookup (cache, func, data, display_types);
}
/**
* gst_vaapi_display_cache_lookup_by_va_display:
* @cache: the #GstVaapiDisplayCache
* @va_display: the VA display to find
*
* Looks up the display cache for the specified VA display.
*
* Return value: a #GstVaapiDisplayInfo matching @va_display, or %NULL
* if none was found
*/
const GstVaapiDisplayInfo *
gst_vaapi_display_cache_lookup_by_va_display (GstVaapiDisplayCache * cache,
VADisplay va_display)
{
g_return_val_if_fail (cache != NULL, NULL);
g_return_val_if_fail (va_display != NULL, NULL);
return cache_lookup (cache, compare_va_display, va_display,
GST_VAAPI_DISPLAY_TYPE_ANY);
}
/**
* gst_vaapi_display_cache_lookup_by_native_display:
* @cache: the #GstVaapiDisplayCache
* @native_display: the native display to find
*
* Looks up the display cache for the specified native display.
*
* Return value: a #GstVaapiDisplayInfo matching @native_display, or
* %NULL if none was found
*/
const GstVaapiDisplayInfo *
gst_vaapi_display_cache_lookup_by_native_display (GstVaapiDisplayCache * cache,
gpointer native_display, guint display_types)
{
g_return_val_if_fail (cache != NULL, NULL);
g_return_val_if_fail (native_display != NULL, NULL);
return cache_lookup (cache, compare_native_display, native_display,
display_types);
}
/**
* gst_vaapi_display_cache_lookup_by_name:
* @cache: the #GstVaapiDisplayCache
* @display_name: the display name to match
*
* Looks up the display cache for the specified display name.
*
* Return value: a #GstVaapiDisplayInfo matching @display_name, or
* %NULL if none was found
*/
const GstVaapiDisplayInfo *
gst_vaapi_display_cache_lookup_by_name (GstVaapiDisplayCache * cache,
const gchar * display_name, guint display_types)
{
g_return_val_if_fail (cache != NULL, NULL);
return cache_lookup (cache, compare_display_name, display_name,
display_types);
}