/* * GPAC - Multimedia Framework C SDK * * Authors: Arash Shafiei * Copyright (c) Telecom ParisTech 2000-2013 * All rights reserved * * This file is part of GPAC / dashcast * * GPAC 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, or (at your option) * any later version. * * GPAC 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; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * */ #ifndef CIRCULAR_BUFFER_H_ #define CIRCULAR_BUFFER_H_ #include <stdlib.h> #include <stdio.h> #include <gpac/thread.h> /* * The method (mode) of multithread management. * It can be LIVE or OFFLINE. * LIVE means that the system is real time. The producer does not wait * for anyone and it always produces and finds a place on the circular buffer. * OFFLINE means that the system is working offline, so the producer can * wait for the consumers to finish their job. */ typedef enum { LIVE_CAMERA, LIVE_MEDIA, ON_DEMAND } LockMode; /* * Every node of the circular buffer has a data, plus * all the variables needed for multithread management. */ typedef struct { /* Pointer to the data on the node */ void *data; /* The number of the producer currently using this node */ int num_producers; /* The number of consumer currently using this node */ int num_consumers; /* The number of consumer currently waiting for this node */ int num_consumers_waiting; /* Mutex used for synchronizing the users of this node. */ GF_Mutex *mutex; /* Semaphore for producer */ GF_Semaphore *producers_semaphore; /* Semaphore for consumers */ GF_Semaphore *consumers_semaphore; /* If marked is 0 it means the data on this node is not valid. * If marked is 1 it means that the data on this node is valid. * If marked is 2 it means this node is the last node. */ int marked; /* Indicates the number of consumers which already accessed this node. * It is used for the case where the last consumer has to do something. */ int num_consumers_accessed; } Node; /* * The circular buffer has a size, a list of nodes and it * has the number of consumers using it. Also it needs to know which * locking mechanism it needs to use. (LIVE or OFFLINE) */ typedef struct { /* The size of circular buffer */ u32 size; /* A list of all the nodes */ Node *list; /* The mode for multithread management. */ LockMode mode; /* The maximum number of the consumers using the circular buffer */ u32 max_num_consumers; } CircularBuffer; /* * Producer has an index to the circular buffer. */ typedef struct { /* The index where the producer is using */ int idx; /* The maximum of the index. (Which means the size of circular buffer) */ int max_idx; char name[GF_MAX_PATH]; } Producer; /* * Consumer has an index to the circular buffer. */ typedef struct { /* The index where the consumer is using */ int idx; /* The maximum of the index. (Which means the size of circular buffer) */ int max_idx; char name[GF_MAX_PATH]; } Consumer; /* * Create a circular buffer * * @param circular_buf [out] circular buffer to be created * @param size [in] size of circular buffer * @param mode [in] mode of multithread management (LIVE or OFFLINE) * @param num_consumers [in] maximum number of the consumers of the circular buffer */ void dc_circular_buffer_create(CircularBuffer *circular_buf, u32 size, LockMode mode, int num_consumers); /* * Destroy the circular buffer * * @param circular_buf [in] circular buffer to be destroyed */ void dc_circular_buffer_destroy(CircularBuffer *circular_buf); /* * Initialize a consumer * * @param consumer [out] the consumer to be initialize * @param num_consumers [in] maximum number of the consumers */ void dc_consumer_init(Consumer *consumer, int num_consumers, char *name); /* * Return the data in the node in question. (circular_buf[consumer index]) * * @param consumer [in] consumer * @param circular_buf [in] circular buffer */ void * dc_consumer_consume(Consumer *consumer, CircularBuffer *circular_buf); /* * Consumer lock on circular buffer * * @param consumer [in] consumer * @param circular_buf [in] circular buffer * * @return 0 on success, -1 if the node in question is the last node and not usable. */ int dc_consumer_lock(Consumer *consumer, CircularBuffer *circular_buf); /* * Consumer unlock on circular buffer * * @param consumer [in] consumer * @param circular_buf [in] circular buffer * * @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer. */ int dc_consumer_unlock(Consumer *consumer, CircularBuffer *circular_buf); /* * Consumer unlock on previous node of the circular buffer * * @param consumer [in] consumer * @param circular_buf [in] circular buffer * * @return 0 on normal exit, 1 if the consumer unlocking this node is the last consumer. */ int dc_consumer_unlock_previous(Consumer *consumer, CircularBuffer *circular_buf); /* * Consumer leads its index * * @param consumer [in] consumer */ void dc_consumer_advance(Consumer *consumer); /* * Initialize a producer * * @param producer [out] the producer to be initialize * @param maxpro [in] maximum number of the producers */ void dc_producer_init(Producer *producer, int maxpro, char *name); /* * Return the data in the node in question. (circular_buf[consumer index]) * * @param producer [in] producer * @param circular_buf [in] circular buffer */ void * dc_producer_produce(Producer *producer, CircularBuffer *circular_buf); /* * Producer lock on circular buffer * * @param producer [in] producer * @param circular_buf [in] circular buffer * * @return 0 on success, -1 if the mode is live and cannot wait. */ int dc_producer_lock(Producer *producer, CircularBuffer *circular_buf); /* * Producer unlock on circular buffer * * @param producer [in] producer * @param circular_buf [in] circular buffer */ void dc_producer_unlock(Producer *producer, CircularBuffer *circular_buf); /* * Producer unlock on the previous node of the circular buffer * * @param producer [in] producer * @param circular_buf [in] circular buffer */ void dc_producer_unlock_previous(Producer *, CircularBuffer *); /* * Producer leads its index * * @param producer [in] producer * @param circular_buf [in] circular buffer */ void dc_producer_advance(Producer *producer, CircularBuffer *); /* * Producer signal that the current node is the last node * * @param producer [in] producer * @param circular_buf [in] circular buffer */ void dc_producer_end_signal(Producer *producer, CircularBuffer *circular_buf); void dc_producer_end_signal_previous(Producer *producer, CircularBuffer *circular_buf); #endif /* CIRCULAR_BUFFER_H_ */