505 lines
9.8 KiB
C
505 lines
9.8 KiB
C
/*
|
|
* Copyright (c) XMEDIA. All rights reserved.
|
|
*/
|
|
/*
|
|
* The main logic about frame cache module
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <malloc.h>
|
|
|
|
#include "log_base.h"
|
|
#include "events.h"
|
|
#include "config_svc.h"
|
|
#include "frame_cache.h"
|
|
|
|
static void cache_init(frame_cache_t *cache)
|
|
{
|
|
cache->tail = NULL;
|
|
cache->head = NULL;
|
|
cache->count = 0;
|
|
}
|
|
|
|
static void cache_destroy(frame_cache_t *cache)
|
|
{
|
|
frame_node_t *tmp = NULL;
|
|
|
|
while (cache->tail != NULL) {
|
|
tmp = cache->tail;
|
|
cache->tail = tmp->next;
|
|
free(tmp->mem);
|
|
free(tmp);
|
|
}
|
|
|
|
cache->tail = NULL;
|
|
cache->head = NULL;
|
|
cache->count = 0;
|
|
}
|
|
|
|
static int put_frame_into_cache(frame_cache_t *cache, frame_node_t *node)
|
|
{
|
|
node->next = NULL;
|
|
cache->count++;
|
|
|
|
// first time
|
|
if (cache->head == NULL && cache->tail == NULL) {
|
|
cache->head = node;
|
|
cache->tail = node;
|
|
} else {
|
|
cache->head->next = node;
|
|
cache->head = node;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int get_frame_from_cache(frame_cache_t *cache, frame_node_t **node)
|
|
{
|
|
*node = cache->tail;
|
|
|
|
if ((cache->tail != NULL) && (cache->tail->next != NULL)) {
|
|
cache->tail = cache->tail->next;
|
|
cache->count--;
|
|
} else if (cache->tail == cache->head) {
|
|
cache->tail = NULL;
|
|
cache->head = NULL;
|
|
cache->count = 0;
|
|
}
|
|
|
|
return (*node != NULL) ? 0 : -1;
|
|
}
|
|
|
|
static int free_queue(frame_queue_t *queue)
|
|
{
|
|
frame_cache_t *cache = queue->cache;
|
|
|
|
if (cache != NULL) {
|
|
cache_destroy(cache);
|
|
free(cache);
|
|
queue->cache = NULL;
|
|
}
|
|
|
|
pthread_mutex_destroy(&(queue->locker));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int free_uvc_cache(uvc_cache_t *uvc_cache)
|
|
{
|
|
/* free queue*/
|
|
free_queue(uvc_cache->ok_queue);
|
|
free_queue(uvc_cache->free_queue);
|
|
|
|
free(uvc_cache->ok_queue);
|
|
free(uvc_cache->free_queue);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int free_uac_cache(uac_cache_t *uac_cache)
|
|
{
|
|
/* free queue*/
|
|
free_queue(uac_cache->ok_queue);
|
|
free_queue(uac_cache->free_queue);
|
|
|
|
free(uac_cache->ok_queue);
|
|
free(uac_cache->free_queue);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int init_queue(frame_queue_t **queue)
|
|
{
|
|
frame_queue_t *q = *queue;
|
|
|
|
if (q == NULL) {
|
|
goto ERR;
|
|
}
|
|
|
|
q->cache = (frame_cache_t *)malloc(sizeof(frame_cache_t));
|
|
if (q->cache == NULL) {
|
|
LOGE("malloc frame cache failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
cache_init(q->cache);
|
|
|
|
/*FIXME: recursive locker....*/
|
|
pthread_mutex_init(&(q->locker), NULL);
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
return -1;
|
|
}
|
|
|
|
static int init_uvc_frame_cache(uvc_cache_t **cache)
|
|
{
|
|
uvc_cache_t *uvc_cache = *cache;
|
|
|
|
if (uvc_cache == NULL) {
|
|
LOGE("the uvc cache is null\n");
|
|
goto ERR;
|
|
}
|
|
|
|
uvc_cache->ok_queue = NULL;
|
|
uvc_cache->free_queue = NULL;
|
|
|
|
uvc_cache->ok_queue = (frame_queue_t *)malloc(sizeof(frame_queue_t));
|
|
if (uvc_cache->ok_queue == NULL) {
|
|
LOGE("malloc ok_queue failure \n");
|
|
goto ERR;
|
|
}
|
|
|
|
uvc_cache->free_queue = (frame_queue_t *)malloc(sizeof(frame_queue_t));
|
|
if (uvc_cache->free_queue == NULL) {
|
|
LOGE("malloc free_queue failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (init_queue(&(uvc_cache->ok_queue)) < 0) {
|
|
goto ERR;
|
|
}
|
|
|
|
if (init_queue(&(uvc_cache->free_queue)) < 0) {
|
|
goto ERR;
|
|
}
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
if (uvc_cache->ok_queue != NULL) {
|
|
free(uvc_cache->ok_queue);
|
|
uvc_cache->ok_queue = NULL;
|
|
}
|
|
|
|
if (uvc_cache->free_queue != NULL) {
|
|
free(uvc_cache->free_queue);
|
|
uvc_cache->free_queue = NULL;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int init_uac_frame_cache(uac_cache_t **cache)
|
|
{
|
|
uac_cache_t *uac_cache = *cache;
|
|
|
|
if (uac_cache == NULL) {
|
|
LOGE("the uac cache is null\n");
|
|
goto ERR;
|
|
}
|
|
|
|
uac_cache->ok_queue = NULL;
|
|
uac_cache->free_queue = NULL;
|
|
|
|
uac_cache->ok_queue = (frame_queue_t *)malloc(sizeof(frame_queue_t));
|
|
if (uac_cache->ok_queue == NULL) {
|
|
LOGE("malloc ok_queue failure \n");
|
|
goto ERR;
|
|
}
|
|
|
|
uac_cache->free_queue = (frame_queue_t *)malloc(sizeof(frame_queue_t));
|
|
if (uac_cache->free_queue == NULL) {
|
|
LOGE("malloc free_queue failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (init_queue(&(uac_cache->ok_queue)) < 0) {
|
|
goto ERR;
|
|
}
|
|
|
|
if (init_queue(&(uac_cache->free_queue)) < 0) {
|
|
goto ERR;
|
|
}
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
if (uac_cache->ok_queue != NULL) {
|
|
free(uac_cache->ok_queue);
|
|
uac_cache->ok_queue = NULL;
|
|
}
|
|
|
|
if (uac_cache->free_queue != NULL) {
|
|
free(uac_cache->free_queue);
|
|
uac_cache->free_queue = NULL;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static void clear_frame_cache(frame_cache_t *c)
|
|
{
|
|
cache_destroy(c);
|
|
}
|
|
|
|
static void clear_queue(frame_queue_t *q)
|
|
{
|
|
if (0 != pthread_mutex_lock(&(q->locker))) {
|
|
LOGE("failed to lock frame cache\n");
|
|
goto ERR;
|
|
}
|
|
|
|
clear_frame_cache(q->cache);
|
|
|
|
pthread_mutex_unlock(&(q->locker));
|
|
|
|
ERR:
|
|
return;
|
|
}
|
|
|
|
static int create_cache_node_list(frame_queue_t *q, unsigned int buffer_size, int cache_count)
|
|
{
|
|
int i = 0;
|
|
unsigned int page_size;
|
|
frame_node_t *n = NULL;
|
|
|
|
page_size = getpagesize();
|
|
|
|
buffer_size = (buffer_size + page_size - 1) & ~(page_size - 1);
|
|
|
|
for (; i < cache_count; ++i) {
|
|
n = (frame_node_t *)malloc(sizeof(frame_node_t));
|
|
if (!n) {
|
|
LOGE("failed to malloc frame_node_t\n");
|
|
goto ERR;
|
|
}
|
|
|
|
n->mem = (unsigned char *)memalign(page_size, buffer_size);
|
|
if (!n->mem) {
|
|
LOGE("failed to malloc frame_node_t->mem field\n");
|
|
goto ERR;
|
|
}
|
|
|
|
n->length = buffer_size;
|
|
n->used = 0;
|
|
n->next = NULL;
|
|
n->index = i;
|
|
|
|
put_node_to_queue(q, n);
|
|
}
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
|
|
if (n) {
|
|
free(n);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//only one instance for each process.
|
|
static uvc_cache_t *g_uvc_cache = NULL;
|
|
static uac_cache_t *g_uac_cache = NULL;
|
|
|
|
uvc_cache_t *uvc_cache_get(void)
|
|
{
|
|
return g_uvc_cache;
|
|
}
|
|
|
|
int create_uvc_cache(void)
|
|
{
|
|
unsigned int buffer_size;
|
|
int cache_count;
|
|
|
|
g_uvc_cache = (uvc_cache_t *)malloc(sizeof(uvc_cache_t));
|
|
if (g_uvc_cache == NULL) {
|
|
LOGE("malloc uvc_cache failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (init_uvc_frame_cache(&g_uvc_cache) < 0) {
|
|
LOGE("init uvc cache failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
buffer_size = get_config_value("uvc:imagesize", 1843200);
|
|
cache_count = get_config_value("uvc:cache_count", 6);
|
|
|
|
create_cache_node_list(g_uvc_cache->free_queue, buffer_size, cache_count);
|
|
|
|
events_init();
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
if (g_uvc_cache != NULL) {
|
|
free(g_uvc_cache);
|
|
g_uvc_cache = NULL;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void destroy_uvc_cache(void)
|
|
{
|
|
if (uvc_cache_get() != NULL) {
|
|
free_uvc_cache(uvc_cache_get());
|
|
free(uvc_cache_get());
|
|
events_deinit();
|
|
|
|
g_uvc_cache = NULL;
|
|
}
|
|
}
|
|
|
|
void clear_uvc_cache(void)
|
|
{
|
|
if (uvc_cache_get() != NULL) {
|
|
uvc_cache_t* uvc_cache = uvc_cache_get();
|
|
|
|
clear_queue(uvc_cache->free_queue);
|
|
clear_queue(uvc_cache->ok_queue);
|
|
}
|
|
}
|
|
|
|
uac_cache_t* uac_cache_get(void)
|
|
{
|
|
return g_uac_cache;
|
|
}
|
|
|
|
int create_uac_cache(void)
|
|
{
|
|
int cache_count;
|
|
unsigned int buffer_size;
|
|
|
|
g_uac_cache = (uac_cache_t *)malloc(sizeof(uac_cache_t));
|
|
|
|
if (g_uac_cache == NULL) {
|
|
LOGE("malloc uac_cache failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (init_uac_frame_cache(&g_uac_cache) < 0) {
|
|
LOGE("init uac cache failure\n");
|
|
goto ERR;
|
|
}
|
|
|
|
buffer_size = get_config_value("uac:imagesize", 1024);
|
|
cache_count = get_config_value("uac:cache_count", 6);
|
|
|
|
create_cache_node_list(g_uac_cache->free_queue, buffer_size, cache_count);
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
if (g_uac_cache != NULL) {
|
|
free(g_uac_cache);
|
|
}
|
|
|
|
g_uac_cache = NULL;
|
|
|
|
return -1;
|
|
}
|
|
|
|
void destroy_uac_cache(void)
|
|
{
|
|
if (uac_cache_get() != NULL) {
|
|
free_uac_cache(uac_cache_get());
|
|
free(uac_cache_get());
|
|
|
|
g_uac_cache = NULL;
|
|
}
|
|
}
|
|
|
|
void clear_uac_cache(void)
|
|
{
|
|
if (uac_cache_get() != NULL) {
|
|
uac_cache_t * uac_cache = uac_cache_get();
|
|
|
|
clear_queue(uac_cache->free_queue);
|
|
clear_queue(uac_cache->ok_queue);
|
|
}
|
|
}
|
|
|
|
int put_node_to_queue(frame_queue_t *q, frame_node_t* node)
|
|
{
|
|
if ((q == NULL) || (node == NULL)) {
|
|
goto ERR;
|
|
}
|
|
|
|
if (0 != pthread_mutex_lock(&(q->locker))) {
|
|
LOGE("failed to lock frame cache\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (0 != put_frame_into_cache(q->cache, node)) {
|
|
pthread_mutex_unlock(&(q->locker));
|
|
|
|
goto ERR;
|
|
}
|
|
|
|
pthread_mutex_unlock(&(q->locker));
|
|
|
|
if (g_uvc_cache && g_uvc_cache->ok_queue == q) {
|
|
node_notity_one();
|
|
}
|
|
|
|
return 0;
|
|
|
|
ERR:
|
|
return -1;
|
|
}
|
|
|
|
int get_node_from_queue(frame_queue_t *q, frame_node_t** node)
|
|
{
|
|
if ((q == NULL) || (node == NULL)) {
|
|
goto ERR;
|
|
}
|
|
|
|
if (0 != pthread_mutex_lock(&(q->locker))) {
|
|
LOGE("failed to lock frame cache\n");
|
|
goto ERR;
|
|
}
|
|
|
|
if (0 != get_frame_from_cache(q->cache, node)) {
|
|
pthread_mutex_unlock(&(q->locker));
|
|
|
|
goto ERR;
|
|
}
|
|
|
|
pthread_mutex_unlock(&(q->locker));
|
|
|
|
return 0;
|
|
ERR:
|
|
return -1;
|
|
}
|
|
|
|
int wait_queue(frame_queue_t *q)
|
|
{
|
|
if (q == NULL) {
|
|
goto ERR;
|
|
}
|
|
|
|
ERR:
|
|
return -1;
|
|
}
|
|
|
|
void debug_dump_node(frame_node_t *node)
|
|
{
|
|
printf("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
|
|
node->mem[0],
|
|
node->mem[1],
|
|
node->mem[2],
|
|
node->mem[3],
|
|
node->mem[4],
|
|
node->mem[5]);
|
|
}
|
|
|
|
void clear_ok_queue(void)
|
|
{
|
|
frame_node_t* node = NULL;
|
|
uvc_cache_t* uvc_cache = uvc_cache_get();
|
|
|
|
events_init();
|
|
while (0 == get_node_from_queue(uvc_cache->ok_queue, &node)) {
|
|
node->used = 0;
|
|
put_node_to_queue(uvc_cache->free_queue, node);
|
|
}
|
|
}
|