gint ms_fifo_get_read_ptr(MSFifo *fifo, gint bsize, void **ret_ptr) { gchar *rnext; *ret_ptr=NULL; /* //ms_trace("ms_fifo_get_read_ptr: entering.");*/ g_return_val_if_fail(bsize<=fifo->r_gran,-EINVAL); if (bsize>fifo->readsize) { ms_trace("Not enough data: bsize=%i, readsize=%i",bsize,fifo->readsize); return (-ENODATA); } rnext=fifo->rd_ptr+bsize; if (rnext<=fifo->r_end){ *ret_ptr=fifo->rd_ptr; fifo->rd_ptr=rnext; }else{ int unread=fifo->r_end-fifo->rd_ptr; *ret_ptr=fifo->begin-unread; memcpy(fifo->buffer->buffer,fifo->r_end-fifo->saved_offset,fifo->saved_offset); fifo->rd_ptr=(char*)(*ret_ptr) + bsize; fifo->r_end=fifo->w_end; /* this is important ! */ ms_trace("moving read ptr to %x",fifo->rd_ptr); } /* update write size*/ fifo->writesize+=bsize; fifo->readsize-=bsize; return bsize; }
gint ms_fifo_get_write_ptr(MSFifo *fifo, gint bsize, void **ret_ptr) { gchar *wnext; *ret_ptr=NULL; /* //ms_trace("ms_fifo_get_write_ptr: Entering.");*/ g_return_val_if_fail(bsize<=fifo->w_gran,-EINVAL); if (bsize>fifo->writesize) { ms_trace("Not enough space: bsize=%i, writesize=%i",bsize,fifo->writesize); *ret_ptr=NULL; return(-ENODATA); } wnext=fifo->wr_ptr+bsize; if (wnext<=fifo->w_end){ *ret_ptr=fifo->wr_ptr; fifo->wr_ptr=wnext; }else{ *ret_ptr=fifo->begin; fifo->r_end=fifo->wr_ptr; fifo->wr_ptr=fifo->begin+bsize; ms_trace("moving write ptr to %x",fifo->wr_ptr); } fifo->prev_wr_ptr=*ret_ptr; /* update readsize*/ fifo->readsize+=bsize; fifo->writesize-=bsize; /* //ms_trace("ms_fifo_get_write_ptr: readsize=%i, writesize=%i",fifo->readsize,fifo->writesize);*/ return bsize; }
void ms_read_process(MSRead *r) { MSFifo *f; MSQueue *q; MSMessage *msg=NULL; int err; gint gran=r->gran; void *p; f=r->foutputs[0]; if ((f!=NULL) && (r->state==MS_READ_STATE_STARTED)) { ms_fifo_get_write_ptr(f,gran,&p); if (p!=NULL) { err=read(r->fd,p,gran); if (err<0) { /* temp: */ g_warning("ms_read_process: failed to read: %s.\n",strerror(errno)); } else if (err<gran){ ms_trace("ms_read_process: end of file."); ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL); r->state=MS_READ_STATE_STOPPED; close(r->fd); r->fd=-1; } if (r->need_swap) swap_buffer(p,gran); } } /* process output queues*/ q=r->qoutputs[0]; if ((q!=NULL) && (r->fd>0)) { msg=ms_message_new(r->gran); err=read(r->fd,msg->data,r->gran); if (err>0){ msg->size=err; ms_queue_put(q,msg); if (r->need_swap) swap_buffer(msg->data,r->gran); }else{ ms_filter_notify_event(MS_FILTER(r),MS_READ_EVENT_EOF,NULL); ms_trace("End of file reached."); r->state=MS_READ_STATE_STOPPED; } } }
/*execute the processing chain attached to a sync source. It is called as a thread by ms_main()*/ void *ms_thread_run(void *sync_ptr) { MSSync *sync=(MSSync*) sync_ptr; GList *filter; MSFilter *f; ms_sync_lock(sync); while(sync->run) { //g_message("sync->run=%i",sync->run); if (sync->samples_per_tick==0) ms_sync_suspend(sync); if (sync->flags & MS_SYNC_NEED_UPDATE){ ms_compile(sync); ms_sync_setup(sync); } filter=sync->execution_list; ms_sync_unlock(sync); //ms_trace("Calling synchronisation"); ms_sync_synchronize(sync); while(filter!=NULL) { f=(MSFilter*)filter->data; if (MS_FILTER_GET_CLASS(f)->attributes & FILTER_IS_SOURCE) { /* execute it once */ ms_trace("Running source filter %s.",f->klass->name); ms_filter_process(f); } else { /* make the filter process its input data until it has no more */ while ( ms_filter_fifos_have_data(f) || ms_filter_queues_have_data(f) ) { ms_trace("Running filter %s.",f->klass->name); ms_filter_process(f); } } filter=g_list_next(filter); } ms_sync_lock(sync); } g_cond_signal(sync->stop_cond); /* signal that the sync thread has finished */ ms_sync_unlock(sync); g_message("Mediastreamer processing thread is exiting."); return NULL; }
MSBuffer * ms_buffer_new(guint32 size) { MSBuffer *buf; buf=(MSBuffer*)g_malloc(sizeof(MSBuffer)+size); buf->ref_count=0; buf->size=size; ms_trace("ms_buffer_new: Allocating buffer of %i bytes.",size); /* allocate the data buffer: there is a lot of optmisation that can be done by using a pool of cached buffers*/ buf->buffer=((char*)(buf))+sizeof(MSBuffer); /* to avoid to do two allocations, buffer info and buffer are contigous.*/ buf->flags=MS_BUFFER_CONTIGUOUS; return(buf); }
/** * ms_start: * @sync: A synchronisation source to be started. * * Starts a thread that will shedule all processing chains attached to the synchronisation source @sync. * * */ void ms_start(MSSync *sync) { if (sync->run==1) return; /*already running*/ ms_compile(sync); ms_sync_setup(sync); /* this is to avoid race conditions, for example: ms_start(sync); ms_oss_write_start(ossw); here tge ossw filter need to be compiled to run ms_oss_write_start() */ ms_trace("ms_start: creating new thread."); sync->run=1; sync->thread=g_thread_create((GThreadFunc)ms_thread_run,(gpointer)sync,TRUE,NULL); if (sync->thread==NULL){ g_warning("Could not create thread !"); } }
void ms_rtp_send_process(MSRtpSend *r) { MSFifo *fi; MSQueue *qi; MSSync *sync= r->sync; int gran=ms_sync_get_samples_per_tick(sync); guint32 ts; void *s; guint skip; guint32 synctime=sync->time; g_return_if_fail(gran>0); if (r->rtpsession==NULL) return; ms_filter_lock(MS_FILTER(r)); skip=r->delay!=0; if (skip) r->delay--; /* process output fifo and output queue*/ fi=r->f_inputs[0]; if (fi!=NULL) { ts=get_new_timestamp(r,synctime); /* try to read r->packet_size bytes and send them in a rtp packet*/ ms_fifo_get_read_ptr(fi,r->packet_size,&s); if (!skip){ rtp_session_send_with_ts(r->rtpsession,s,r->packet_size,ts); ms_trace("len=%i, ts=%i ",r->packet_size,ts); } } qi=r->q_inputs[0]; if (qi!=NULL) { MSMessage *msg; /* read a MSMessage and send it through the network*/ while ( (msg=ms_queue_get(qi))!=NULL){ ts=get_new_timestamp(r,synctime); if (!skip) { /*g_message("Sending packet with ts=%u",ts);*/ rtp_session_send_with_ts(r->rtpsession,msg->data,msg->size,ts); } ms_message_destroy(msg); } } ms_filter_unlock(MS_FILTER(r)); }
guint32 get_new_timestamp(MSRtpSend *r,guint32 synctime) { guint32 clockts; /* use the sync system time to compute a timestamp */ PayloadType *pt=rtp_profile_get_payload(r->rtpsession->profile,r->rtpsession->payload_type); g_return_val_if_fail(pt!=NULL,0); clockts=(guint32)(((double)synctime * (double)pt->clock_rate)/1000.0); ms_trace("ms_rtp_send_process: sync->time=%i clock=%i",synctime,clockts); if (r->flags & RTPSEND_CONFIGURED){ if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(clockts,r->ts+(2*r->ts_inc) )){ r->ts=clockts; } else r->ts+=r->ts_inc; }else{ r->ts=clockts; } return r->ts; }
/* compile graphs attached to a sync source*/ int ms_compile(MSSync *sync) { int i; GList *list1=NULL,*list2=NULL,*elem; GList *proc_chain=NULL; MSFilter *f; /* first free the old list if we are just updating*/ if (sync->execution_list!=NULL) g_list_free(sync->execution_list); /* get the list of filters attached to this sync*/ for (i=0;i<sync->filters;i++) { //printf("found filter !\n"); list1=g_list_append(list1,sync->attached_filters[i]); } /* find the processing chain */ while (list1!=NULL) { list2=NULL; /* sort the list by types of filter*/ list1=g_list_sort(list1,compare); /* save into the processing chain list*/ //printf("list1 :%i elements\n",g_list_length(list1)); proc_chain=g_list_concat(proc_chain,list1); /* get all following filters. They are appended to list2*/ elem=list1; while (elem!=NULL) { f=(MSFilter*)(elem->data); /* check if filter 's status */ if (f->klass->attributes & FILTER_CAN_SYNC) { sync->samples_per_tick=0; } list2=get_nexts(f,list2); elem=g_list_next(elem); } list1=list2; } sync->execution_list=proc_chain; sync->flags&=~MS_SYNC_NEED_UPDATE; ms_trace("%i filters successfully compiled in a processing chain.",g_list_length(sync->execution_list)); return 0; }
void ms_speex_dec_class_init(MSSpeexDecClass *klass) { gint frame_size=0; ms_filter_class_init(MS_FILTER_CLASS(klass)); /* use the largest frame size to configure fifos */ speex_mode_query(&speex_wb_mode, SPEEX_MODE_FRAME_SIZE, &frame_size); MS_FILTER_CLASS(klass)->process=(MSFilterProcessFunc)ms_speex_dec_process; MS_FILTER_CLASS(klass)->setup=(MSFilterSetupFunc)ms_speex_dec_setup; MS_FILTER_CLASS(klass)->unsetup=(MSFilterSetupFunc)ms_speex_dec_unsetup; MS_FILTER_CLASS(klass)->destroy=(MSFilterDestroyFunc)ms_speex_dec_destroy; MS_FILTER_CLASS(klass)->set_property=(MSFilterPropertyFunc)ms_speex_dec_set_property; ms_filter_class_set_name(MS_FILTER_CLASS(klass),"SpeexDecoder"); MS_FILTER_CLASS(klass)->info=(MSFilterInfo*)&speex_info; MS_FILTER_CLASS(klass)->max_foutputs=1; MS_FILTER_CLASS(klass)->max_qinputs=1; MS_FILTER_CLASS(klass)->w_maxgran=frame_size*2; ms_trace("ms_speex_dec_class_init: w_maxgran is %i.",MS_FILTER_CLASS(klass)->w_maxgran); }
MSFifo * ms_fifo_new_with_buffer(gint r_gran, gint w_gran, gint r_offset, gint w_offset, gint min_fifo_size) { MSFifo *fifo; MSBuffer *buf; gint saved_offset=MAX(r_gran+r_offset,w_offset); gint fifo_size; gint tmp; if (min_fifo_size==0) min_fifo_size=w_gran; /* we must allocate a fifo with a size multiple of min_fifo_size, with a saved_offset */ if (min_fifo_size>MS_BUFFER_LARGE) fifo_size=(min_fifo_size) + saved_offset; else fifo_size=(6*min_fifo_size) + saved_offset; buf=ms_buffer_new(fifo_size); fifo=ms_fifo_new(buf,r_gran,w_gran,r_offset,w_offset); ms_trace("fifo_size=%i",fifo_size); return(fifo); }
MSFifo * ms_fifo_new(MSBuffer *buf, gint r_gran, gint w_gran, gint r_offset, gint w_offset) { MSFifo *fifo; gint saved_offset=MAX(r_gran+r_offset,w_offset); g_return_val_if_fail(saved_offset<=(buf->size),NULL); fifo=g_malloc(sizeof(MSFifo)); fifo->buffer=buf; fifo->r_gran=r_gran; fifo->w_gran=w_gran; fifo->begin=fifo->wr_ptr=fifo->rd_ptr=buf->buffer+saved_offset; fifo->readsize=0; fifo->size=fifo->writesize=buf->size-saved_offset; fifo->saved_offset= saved_offset; fifo->r_end=fifo->w_end=buf->buffer+buf->size; fifo->pre_end=fifo->w_end-saved_offset; buf->ref_count++; fifo->prev_data=NULL; fifo->next_data=NULL; ms_trace("fifo base=%x, begin=%x, end=%x, saved_offset=%i, size=%i" ,fifo->buffer->buffer,fifo->begin,fifo->w_end,fifo->saved_offset,fifo->size); return(fifo); }