diff options
Diffstat (limited to 'debian/transcode/transcode-1.1.7/import/packets.c')
| -rw-r--r-- | debian/transcode/transcode-1.1.7/import/packets.c | 529 |
1 files changed, 529 insertions, 0 deletions
diff --git a/debian/transcode/transcode-1.1.7/import/packets.c b/debian/transcode/transcode-1.1.7/import/packets.c new file mode 100644 index 00000000..b9123355 --- /dev/null +++ b/debian/transcode/transcode-1.1.7/import/packets.c @@ -0,0 +1,529 @@ +/* + * packets.c + * + * Copyright (C) Thomas Oestreich - June 2001 + * + * This file is part of transcode, a video stream processing tool + * + * transcode 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, or (at your option) + * any later version. + * + * transcode 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 GNU Make; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "transcode.h" +#include "libtc/libtc.h" + +#include "packets.h" + +#define FLUSH_BUFFER_MAX (1024<<4) + + +pthread_mutex_t packet_list_lock=PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t pack_ctr_lock=PTHREAD_MUTEX_INITIALIZER; + +packet_list_t *packet_list_head; +packet_list_t *packet_list_tail; + +static int sbuf_max = 0; +static int sbuf_next= 0; + +static packet_list_t **sbuf_ptr; char *sbuf_mem; + +//important internal parameter and counter +static int verbose_flag=TC_QUIET; +static int pack_ctr, pack_fill_ctr=0; +static int ifd=0; + +pthread_cond_t packet_pop_cv=PTHREAD_COND_INITIALIZER; +pthread_cond_t packet_push_cv=PTHREAD_COND_INITIALIZER; +static pthread_t packet_thread; + +extern int seq_info_delay(void); + +packet_list_t *packet_register(int id) + +{ + + /* objectives: + =========== + + register new packet + + allocate space for packet buffer and establish backward reference + + requirements: + ============= + + thread-safe + + global mutex: packet_list_lock + + */ + + packet_list_t *ptr; + + pthread_mutex_lock(&packet_list_lock); + + // retrieve a valid pointer from the pool + +#ifdef STATBUFFER + if(verbose_flag & TC_FLIST) + tc_log_msg(__FILE__, "packet id=%d", id); + if((ptr = sbuf_retrieve()) == NULL) { + pthread_mutex_unlock(&packet_list_lock); + return(NULL); + } +#else + + if((ptr = tc_malloc(sizeof(packet_list_t))) == NULL) { + pthread_mutex_unlock(&packet_list_lock); + return(NULL); + } +#endif + + ptr->status = PACKET_EMPTY; + + ptr->next = NULL; + ptr->prev = NULL; + + ptr->id = id; + + if(packet_list_tail != NULL) + { + packet_list_tail->next = ptr; + ptr->prev = packet_list_tail; + } + + packet_list_tail = ptr; + + /* first packet registered must set packet_list_head */ + + if(packet_list_head == NULL) packet_list_head = ptr; + + pthread_mutex_unlock(&packet_list_lock); + + return(ptr); + +} + + +/* ------------------------------------------------------------------ */ + + +void packet_remove(packet_list_t *ptr) + +{ + + /* objectives: + =========== + + remove packet from chained list + + requirements: + ============= + + thread-safe + + */ + + + if(ptr == NULL) return; // do nothing if null pointer + + pthread_mutex_lock(&packet_list_lock); + + if(ptr->prev != NULL) (ptr->prev)->next = ptr->next; + if(ptr->next != NULL) (ptr->next)->prev = ptr->prev; + + if(ptr == packet_list_tail) packet_list_tail = ptr->prev; + if(ptr == packet_list_head) packet_list_head = ptr->next; + + // release valid pointer to pool + ptr->status = PACKET_EMPTY; + +#ifdef STATBUFFER + sbuf_release(ptr); +#else + free(ptr); +#endif + + pthread_mutex_unlock(&packet_list_lock); + +} + + +/* ------------------------------------------------------------------ */ + + +packet_list_t *packet_retrieve() + +{ + + /* objectives: + =========== + + get pointer to next packet for rendering + + requirements: + ============= + + thread-safe + + */ + + packet_list_t *ptr; + + pthread_mutex_lock(&packet_list_lock); + + ptr = packet_list_head; + + /* move along the chain and check for status */ + + while(ptr != NULL) + { + if(ptr->status == PACKET_READY) + { + pthread_mutex_unlock(&packet_list_lock); + return(ptr); + } + ptr = ptr->next; + } + + pthread_mutex_unlock(&packet_list_lock); + + return(NULL); +} + +/* ------------------------------------------------------------------ */ + +int sbuf_alloc(int ex_num) +{ + + /* objectives: + =========== + + allocate memory for ringbuffer structure + return -1 on failure, 0 on success + + */ + + int n, num; + + if(ex_num < 0) return(-1); + + num = ex_num + 2; //alloc some more because + + if((sbuf_ptr = tc_zalloc(num * sizeof(packet_list_t *)))==NULL) { + tc_log_perror(__FILE__, "out of memory"); + return(-1); + } + + if((sbuf_mem = tc_zalloc(num * sizeof(packet_list_t)))==NULL) { + tc_log_perror(__FILE__, "out of memory"); + return(-1); + } + + // init ringbuffer + for (n=0; n<num; ++n) { + sbuf_ptr[n] = (packet_list_t *) (sbuf_mem + n * sizeof(packet_list_t)); + + sbuf_ptr[n]->status = PACKET_NULL; + sbuf_ptr[n]->bufid = n; + } + + // assign to static + sbuf_max = num; + + return(0); +} + +/* ------------------------------------------------------------------ */ + +void sbuf_free() +{ + + /* objectives: + =========== + + free memory for ringbuffer structure + + */ + + if(sbuf_max > 0) { + free(sbuf_ptr); + free(sbuf_mem); + } +} + + + +/* ------------------------------------------------------------------ */ + +packet_list_t *sbuf_retrieve() +{ + + /* objectives: + =========== + + retrieve a valid pointer to a packet_list_t structure + return NULL on failure, valid pointer on success + + thread safe + + */ + + packet_list_t *ptr; + + ptr = sbuf_ptr[sbuf_next]; + + // check, if this structure is really free to reuse + + if(ptr->status != PACKET_NULL) return(NULL); + + // ok + + if(verbose_flag & TC_FLIST) + tc_log_msg(__FILE__, "alloc =%d [%d]", sbuf_next, ptr->bufid); + ++sbuf_next; + sbuf_next %= sbuf_max; + + return(ptr); +} + + + +/* ------------------------------------------------------------------ */ + +int sbuf_release(packet_list_t *ptr) +{ + + /* objectives: + =========== + + release a valid pointer to a packet_list_t structure + return -1 on failure, 0 on success + + thread safe + + */ + + // instead of freeing the memory and setting the pointer + // to NULL we only change a flag + + if(ptr == NULL) return(-1); + + if(ptr->status != PACKET_EMPTY) { + return(-1); + } else { + + if(verbose_flag & TC_FLIST) + tc_log_msg(__FILE__, "release=%d [%d]", sbuf_next, ptr->bufid); + ptr->status = PACKET_NULL; + + } + + return(0); +} + +/* ------------------------------------------------------------------ + * + * packet buffer management + * + * API: flush_buffer_init + * flush_buffer_write + * flush_buffer_close + * + *-------------------------------------------------------------------*/ + +int packet_buffer_flush() + +{ + + /* objectives: + =========== + + flush a packet and release memory + + requirements: + ============= + + thread-safe + + */ + + packet_list_t *ptr; + + size_t n = 0; + + ptr = packet_retrieve(); + + pthread_mutex_lock(&pack_ctr_lock); + + //info: + if(verbose_flag & TC_SYNC) + tc_log_msg(__FILE__, "packet buffer status (%03d/%03d) [%.1f%%]", pack_ctr, pack_fill_ctr, (double) 100*pack_fill_ctr/FLUSH_BUFFER_MAX); + pthread_mutex_unlock(&pack_ctr_lock); + + if(ptr==NULL) { + //Ooops, shouldn't happen + return(-1); + } + + n = tc_pwrite(ifd, ptr->buffer, ptr->size); + + if(verbose_flag & TC_SYNC) + tc_log_msg(__FILE__, "done writing packet (%d/%03d)", ptr->id, pack_ctr); + + // no release, if not set! + ptr->status = PACKET_EMPTY; + + packet_remove(ptr); + + return(0); +} + +/* ------------------------------------------------------------------ */ + +static void flush_buffer_thread(void) +{ + + int tt; + + for (;;) { + + pthread_mutex_lock(&pack_ctr_lock); + + while(pack_fill_ctr==0) { + pthread_cond_wait(&packet_pop_cv, &pack_ctr_lock); +#ifdef BROKEN_PTHREADS // Used to be MacOSX specific; kernel 2.6 as well? + pthread_testcancel(); +#endif + } + + pthread_mutex_unlock(&pack_ctr_lock); + + if(packet_buffer_flush()==0) { + + pthread_mutex_lock(&pack_ctr_lock); + tt=pack_fill_ctr; + --pack_fill_ctr; + pthread_mutex_unlock(&pack_ctr_lock); + + //notify submissions + if(tt==FLUSH_BUFFER_MAX) pthread_cond_signal(&packet_push_cv); + } + } + + return; +} + +/* ------------------------------------------------------------------ */ + +int flush_buffer_init(int _ifd, int _verbose) +{ + + ifd=_ifd; + verbose_flag = _verbose; + + pack_fill_ctr=0; + +#ifdef STATBUFFER + // allocate buffer + if(verbose_flag & TC_DEBUG) + tc_log_msg(__FILE__, "allocating %d framebuffer (static)", FLUSH_BUFFER_MAX); + if(sbuf_alloc(FLUSH_BUFFER_MAX)<0) { + tc_log_error(__FILE__, "static framebuffer allocation failed"); + exit(1); + } +#else + if(verbose_flag & TC_DEBUG) + tc_log_msg(__FILE__, "%d framebuffer (dynamic) requested", FLUSH_BUFFER_MAX); +#endif + + + // start the flush thread + if(pthread_create(&packet_thread, NULL, (void *) flush_buffer_thread, NULL)!=0) { + tc_log_error(__FILE__, "failed to start packet flush thread"); + return(-1); + } else { + if(verbose_flag & TC_SYNC) + tc_log_msg(__FILE__, "flush buffer thread started"); + } + + return(0); +} + +/* ------------------------------------------------------------------ */ + +int flush_buffer_write(int fd_out, char*buffer, int packet_size) +{ + + packet_list_t *pack_ptr=NULL; + + + pthread_mutex_lock(&pack_ctr_lock); + + while(pack_fill_ctr == FLUSH_BUFFER_MAX) { + pthread_cond_wait(&packet_push_cv, &pack_ctr_lock); +#ifdef BROKEN_PTHREADS // Used to be MacOSX specific; kernel 2.6 as well? + pthread_testcancel(); +#endif + } + + pthread_mutex_unlock(&pack_ctr_lock); + + pack_ptr = packet_register(pack_ctr); + + ac_memcpy(pack_ptr->buffer, buffer, packet_size); + + pack_ptr->size = packet_size; + pack_ptr->status = PACKET_READY; //packet ready to go + + + //total processed packets + ++pack_ctr; + + pthread_mutex_lock(&pack_ctr_lock); + + ++pack_fill_ctr; + + //info: buffer status + if(verbose_flag & TC_SYNC) + tc_log_msg(__FILE__, "packet submitted to flush buffer (%03d/%03d) [%.1f%%]", pack_ctr, pack_fill_ctr, (double) 100*pack_fill_ctr/FLUSH_BUFFER_MAX); + + pthread_mutex_unlock(&pack_ctr_lock); + + //notify write thread + pthread_cond_signal(&packet_pop_cv); + + return(packet_size); +} + +/* ------------------------------------------------------------------ */ + +int flush_buffer_close() +{ + + pthread_mutex_lock(&pack_ctr_lock); + + while(pack_fill_ctr>0) { + pthread_mutex_unlock(&pack_ctr_lock); + usleep(TC_DELAY_MAX); + pthread_mutex_lock(&pack_ctr_lock); + } + + pthread_mutex_unlock(&pack_ctr_lock); + + return(0); +} + |
