/* Gveejay Reloaded - graphical interface for VeeJay * (C) 2002-2006 Niels Elburg * * * This program 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 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include typedef struct { char *hostname; int port_num; vj_client *fd; uint8_t *data_buffer; uint8_t *tmp_buffer; uint8_t *status_buffer; int track_list[16]; int track_items; //shared int status_tokens[32]; //shared int active; int have_frame; int grey_scale; int preview; int width; int height; int need_track_list; unsigned char *queue[16]; int n_queued; int bw; } veejay_track_t; typedef struct { void *lzo; veejay_track_t **tracks; int n_tracks; GMutex *mutex; GThread *thread; int state; } veejay_preview_t; static void *gvr_preview_thread(gpointer data); static int sendvims( veejay_track_t *v, int vims_id, const char format[], ... ); static int recvvims( veejay_track_t *v, gint header_len, gint *payload, guchar *buffer ); static int veejay_get_image_data(veejay_preview_t *vp, veejay_track_t *v ); static int track_find( veejay_preview_t *vp ); static int veejay_process_status( veejay_preview_t *vp, veejay_track_t *v ); static int gvr_preview_process_image( veejay_preview_t *vp, veejay_track_t *v ); static int track_exists( veejay_preview_t *vp, const char *hostname, int port_num, int *at ); static int gvr_preview_process_status( veejay_preview_t *vp, veejay_track_t *v ); void *gvr_preview_init(int max_tracks) { veejay_preview_t *vp = (veejay_preview_t*) vj_calloc(sizeof( veejay_preview_t )); GError *err = NULL; vp->lzo = lzo_new(); vp->mutex = g_mutex_new(); vp->tracks = (veejay_track_t**) vj_calloc(sizeof( veejay_track_t*) * max_tracks ); vp->n_tracks = max_tracks; vp->state = 1; vp->thread = g_thread_create( (GThreadFunc) gvr_preview_thread, (gpointer*) vp, TRUE, &err ); if(!vp->thread ) { lzo_free(vp->lzo); g_mutex_free( vp->mutex ); free(vp); return NULL; } return (void*) vp; } static void gvr_close_connection( veejay_track_t *v ) { if(v) { veejay_msg(2, "Disconnectin VeejayGrabber %s:%d", v->hostname,v->port_num ); vj_client_close(v->fd); if(v->hostname) free(v->hostname); if(v->status_buffer) free(v->status_buffer); if(v->data_buffer) free(v->data_buffer); if(v->tmp_buffer) free(v->tmp_buffer); free(v); v= NULL; } } static int sendvims( veejay_track_t *v, int vims_id, const char format[], ... ) { gchar block[255]; gchar tmp[255]; va_list args; if( format == NULL ) { g_snprintf( block, sizeof(block)-1, "%03d:;", vims_id ); gint n = vj_client_send( v->fd, V_CMD, block ); if( n <= 0 ) { gvr_close_connection( v ); return 0; } return n; } va_start( args, format ); vsnprintf( tmp, sizeof(tmp)-1, format, args ); g_snprintf( block,sizeof(block)-1, "%03d:%s;", vims_id, tmp ); va_end( args ); gint n = vj_client_send( v->fd, V_CMD, block ); if( n <= 0 ) { gvr_close_connection( v); return 0; } return n; } static int recvvims( veejay_track_t *v, gint header_len, gint *payload, guchar *buffer ) { gint tmp_len = header_len + 1; unsigned char *tmp = vj_calloc( tmp_len ); gint len = 0; gint n = vj_client_read( v->fd, V_CMD, tmp, header_len ); if( n<= 0 ) { veejay_msg(0,"Error reading header of %d bytes: %d", header_len,n ); free(tmp); return 0; } if( sscanf( (char*)tmp, "%6d%1d", &len,&(v->grey_scale) )<=0) { veejay_msg(0, "Error reading header contents '%s'", tmp); //@ If this happens, there is still data in the socket and it is unwanted //@ to fallback, reduce image resolution by a half and try again when reconnecting. free(tmp); return 0; } if( len <= 0 ) { free(tmp); veejay_msg(0, "Frame is empty"); return 0; } gint bw = 0; gint bytes_read = len; unsigned char *buf_ptr = buffer; *payload = 0; while( bw < len ) { n = vj_client_read( v->fd, V_CMD, buf_ptr, bytes_read ); if ( n <= 0 ) { veejay_msg(0, "Recv %d out of %d bytes", bw,len); free(tmp); return 0; } bw += n; bytes_read -= n; buf_ptr += bw; } *payload = bw; free(tmp); return 1; } static unsigned char *vims_track_list( veejay_track_t *v, int slen, int *bytes_written ) { unsigned char message[10]; int tmp_len = slen + 1; unsigned char *tmp = vj_calloc( tmp_len ); sprintf(message, "%03d:;", VIMS_TRACK_LIST ); int ret = vj_client_send( v->fd, V_CMD, message ); if( ret <= 0) { free(tmp); return NULL; } ret = vj_client_read( v->fd, V_CMD, tmp, slen ); if( ret <= 0 ) { free(tmp); return NULL; } int len = 0; sscanf( (char*) tmp, "%d", &len ); unsigned char *result = NULL; if( len <= 0 || slen <= 0) { free(tmp); return result; } result = (unsigned char*) vj_calloc(sizeof( unsigned char) * (len + 1) ); int bytes_left = len; *bytes_written = 0; while( bytes_left > 0) { int n = vj_client_read( v->fd, V_CMD, result + (*bytes_written), bytes_left ); if( n <= 0 ) { bytes_left = 0; } if( n > 0 ) { *bytes_written +=n; bytes_left -= n; } } free(tmp); return result; } static int veejay_process_status( veejay_preview_t *vp, veejay_track_t *v ) { unsigned char status_len[6]; veejay_memset( status_len, 0, sizeof(status_len) ); gint nb = vj_client_read( v->fd, V_STATUS, status_len, 5 ); if( status_len[0] == 'V' ) { gint bytes = 0; sscanf( status_len + 1, "%03d", &bytes ); if( bytes > 0 ) { veejay_memset( v->status_buffer,0, sizeof(v->status_buffer)); gint n = vj_client_read( v->fd, V_STATUS, v->status_buffer, bytes ); if( n <= 0 ) { veejay_msg(0, "Error reading statusline"); return 0; } while( vj_client_poll( v->fd, V_STATUS ) ) // is there a more recent message? { veejay_memset( status_len, 0, sizeof( status_len ) ); n = vj_client_read(v->fd, V_STATUS, status_len, 5 ); sscanf( status_len+1, "%03d", &bytes ); if(bytes > 0 ) vj_client_read( v->fd, V_STATUS, v->status_buffer, bytes ); } g_mutex_lock( vp->mutex ); veejay_memset( v->status_tokens,0, sizeof(sizeof(int) * 32)); status_to_arr( v->status_buffer, v->status_tokens ); g_mutex_unlock( vp->mutex ); return 1; } } else { g_mutex_lock(vp->mutex); gvr_close_connection( v ); g_mutex_unlock(vp->mutex); } return 0; } static int veejay_get_image_data(veejay_preview_t *vp, veejay_track_t *v ) { if(v->have_frame ) { return 1; } if(!v->have_frame && v->width <= 0 || v->height <= 0 ) return 1; gint res = sendvims( v, VIMS_RGB24_IMAGE, "%d %d", v->width,v->height ); if( res <= 0 ) { veejay_msg(0, "Error sending VIMS_RGB24_IMAGE"); return 0; } gint bw = 0; res = recvvims( v, 7, &bw, v->data_buffer ); if( res <= 0 ) { veejay_msg(0, "Error receiving compressed RGB image"); return 0; } if( bw != (3 * v->width * v->height) && bw != (v->width * v->height)) { veejay_msg(0, "Corrupted image. Drop it"); v->have_frame = 0; return bw; } // v->bw = 0; if( bw == (v->width * v->height )) { uint8_t *in = v->data_buffer; uint8_t *out = v->tmp_buffer; unsigned int i,j; unsigned int len = v->width * v->height; unsigned int stride = v->width * 3; unsigned int width = v->width; unsigned int height = v->height; for( j = 0; j < height ; j ++ ) { for( i = 0; i < width; i ++ ) { uint8_t *dst = out + j * stride + (i*3); dst[0] = in[ j * width + i ]; dst[1] = in[ j * width + i ]; dst[2] = in[ j * width + i ]; } } v->bw = 1; } v->have_frame = 1; return bw; } static int gvr_preview_process_status( veejay_preview_t *vp, veejay_track_t *v ) { if(!v) return 0; int tmp1 = 0; tmp1 = vj_client_poll( v->fd , V_STATUS ); if(tmp1) return veejay_process_status( vp, v ); else if( tmp1 == -1 ) gvr_close_connection(v); return 0; } static int gvr_preview_process_image( veejay_preview_t *vp, veejay_track_t *v ) { if( v->preview ) { if( veejay_get_image_data( vp, v ) == 0 ) { return 0; } } return 1; } static int track_exists( veejay_preview_t *vp, const char *hostname, int port_num, int *at_track ) { int i; for( i = 0; i < vp->n_tracks ; i++ ) { if( vp->tracks[i] ) { veejay_track_t *v = vp->tracks[i]; if( strcasecmp( hostname, v->hostname ) == 0 && v->port_num == port_num ) { if( at_track ) *at_track = i; return 1; } } } return 0; } static int track_find( veejay_preview_t *vp ) { int i; int res = -1; for( i = 0;i < vp->n_tracks ;i ++ ) { if( !vp->tracks[i] ) { res = i; break; } } return res; } void gvr_ext_lock(void *preview) { veejay_preview_t *vp = (veejay_preview_t*) preview; g_mutex_lock(vp->mutex); } void gvr_ext_unlock(void *preview) { veejay_preview_t *vp = (veejay_preview_t*) preview; g_mutex_unlock(vp->mutex); } char* gvr_track_get_hostname( void *preview , int num ) { veejay_preview_t *vp = (veejay_preview_t*) preview; if( vp->tracks[num] ) return vp->tracks[num]->hostname; return NULL; } int gvr_track_get_portnum( void *preview, int num) { veejay_preview_t *vp = (veejay_preview_t*) preview; if( vp->tracks[num] ) return vp->tracks[num]->port_num; return 0; } int gvr_track_already_open( void *preview, const char *hostname, int port ) { veejay_preview_t *vp = (veejay_preview_t*) preview; if(track_exists( vp, hostname, port, NULL ) ) return 1; return 0; } int gvr_track_connect( void *preview, const char *hostname, int port_num, int *new_track ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int track_num = track_find( vp ); if(track_num == -1) return 0; if(track_exists( vp, hostname, port_num, new_track ) ) return 0; vj_client *fd = vj_client_alloc(0,0,0); if(!vj_client_connect( fd, hostname, NULL, port_num ) ) { vj_client_free( fd ); return 0; } veejay_track_t *vt = (veejay_track_t*) vj_calloc( sizeof(veejay_track_t)); vt->hostname = strdup(hostname); vt->port_num = port_num; vt->active = 1; vt->fd = fd; vt->status_buffer = (uint8_t*) vj_calloc(sizeof(uint8_t) * 256); vt->data_buffer = (uint8_t*) vj_calloc(sizeof(uint8_t) * 512 * 512 * 3 ); vt->tmp_buffer = (uint8_t*) vj_calloc(sizeof(uint8_t) * 512 * 512 * 3 ); veejay_msg(2, "Track %d connected to Veejay %s : %d", track_num,hostname,port_num); g_mutex_lock( vp->mutex ); vp->tracks[ track_num ] = vt; g_mutex_unlock( vp->mutex ); return 1; } static void gvr_single_queue_vims( veejay_track_t *v, int vims_id ) { char message[10]; sprintf(message, "%03d:;", vims_id ); if( v->n_queued < 16 ) { v->queue[ v->n_queued ] = strdup( message ); v->n_queued ++; } } static void gvr_multi_queue_vims( veejay_track_t *v, int vims_id, int val ) { char message[10]; sprintf(message, "%03d:%d;", vims_id,val ); if( v->n_queued < 16 ) { v->queue[ v->n_queued ] = strdup( message ); v->n_queued ++; } } static void gvr_multivx_queue_vims( veejay_track_t *v, int vims_id, int val1,unsigned char *val2 ) { char message[300]; sprintf(message, "%03d:%d %s;", vims_id,val1,val2 ); if( v->n_queued < 16 ) { v->queue[ v->n_queued ] = strdup( message ); v->n_queued ++; } } static void gvr_multiv_queue_vims( veejay_track_t *v, int vims_id, int val1,int val2 ) { char message[10]; sprintf(message, "%03d:%d %d;", vims_id,val1,val2 ); if( v->n_queued < 16 ) { v->queue[ v->n_queued ] = strdup( message ); v->n_queued ++; } } void gvr_queue_cxvims( void *preview, int track_id, int vims_id, int val1,unsigned char *val2 ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int i; g_mutex_lock( vp->mutex ); if( track_id == -1 ) { for( i = 0; i < vp->n_tracks; i ++ ) if( vp->tracks[i]->active ) gvr_multivx_queue_vims( vp->tracks[i], vims_id,val1,val2 ); } else { gvr_multivx_queue_vims( vp->tracks[track_id], vims_id,val1,val2 ); } g_mutex_unlock( vp->mutex ); } void gvr_queue_vims( void *preview, int track_id, int vims_id ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int i; g_mutex_lock( vp->mutex ); if( track_id == -1 ) { for( i = 0; i < vp->n_tracks; i ++ ) if( vp->tracks[i]->active ) gvr_single_queue_vims( vp->tracks[i], vims_id ); } else { gvr_single_queue_vims( vp->tracks[track_id], vims_id ); } g_mutex_unlock( vp->mutex ); } void gvr_queue_mvims( void *preview, int track_id, int vims_id, int val ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int i; g_mutex_lock( vp->mutex ); if( track_id == -1 ) { for( i = 0; i < vp->n_tracks ; i ++ ) if( vp->tracks[i]->active ) gvr_multi_queue_vims( vp->tracks[i], vims_id,val ); } else { gvr_multi_queue_vims( vp->tracks[track_id], vims_id,val ); } g_mutex_unlock( vp->mutex ); } void gvr_need_track_list( void *preview, int track_id ) { veejay_preview_t *vp = (veejay_preview_t*) preview; g_mutex_lock( vp->mutex ); veejay_track_t *v = vp->tracks[track_id]; if(v) v->need_track_list = 1; g_mutex_unlock( vp->mutex ); } void gvr_queue_mmvims( void *preview, int track_id, int vims_id, int val1,int val2 ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int i; g_mutex_lock( vp->mutex ); if( track_id == -1 ) { for( i = 0; i < vp->n_tracks; i ++ ) if( vp->tracks[i]->active ) gvr_multiv_queue_vims( vp->tracks[i], vims_id,val1,val2 ); } else { gvr_multiv_queue_vims( vp->tracks[track_id], vims_id,val1,val2 ); } g_mutex_unlock( vp->mutex ); } void gvr_track_disconnect( void *preview, int track_num ) { veejay_preview_t *vp = (veejay_preview_t*) preview; g_mutex_lock( vp->mutex ); veejay_track_t *v = vp->tracks[ track_num ]; gvr_close_connection( v ); vp->tracks[ track_num ] = NULL; g_mutex_unlock( vp->mutex ); } int gvr_track_configure( void *preview, int track_num, int w, int h ) { veejay_preview_t *vp = (veejay_preview_t*) preview; g_mutex_lock( vp->mutex ); vp->tracks[ track_num ]->width = w; vp->tracks[ track_num ]->height = h; g_mutex_unlock( vp->mutex ); veejay_msg(2, "Track %d VeejayGrabber %s:%d %dx%d image", track_num, vp->tracks[ track_num ]->hostname, vp->tracks[ track_num ]->port_num, w,h); return 1; } int gvr_get_preview_status( void *preview, int track_num ) { veejay_preview_t *vp = (veejay_preview_t*) preview; return vp->tracks[track_num]->preview; } int gvr_track_toggle_preview( void *preview, int track_num, int status ) { veejay_preview_t *vp = (veejay_preview_t*) preview; g_mutex_lock( vp->mutex ); vp->tracks[ track_num ]->preview = status; vp->tracks[ track_num ]->have_frame = 0; g_mutex_unlock( vp->mutex ); veejay_msg(2, "Track %d VeejayGrabber %s:%d %s", track_num, vp->tracks[ track_num ]->hostname, vp->tracks[ track_num ]->port_num, (status ? "Active" : "Disabled") ); return status; } static GdkPixbuf **gvr_grab_images(void *preview) { veejay_preview_t *vp = (veejay_preview_t*) preview; GdkPixbuf **list = (GdkPixbuf**) vj_calloc( sizeof(GdkPixbuf*) * vp->n_tracks ); if(!list) return NULL; int i; for( i = 0; i < vp->n_tracks; i ++ ) { if( vp->tracks[i] && vp->tracks[i]->have_frame ) { veejay_track_t *v = vp->tracks[i]; if( v->bw ) list[i] =gdk_pixbuf_new_from_data(v->tmp_buffer,GDK_COLORSPACE_RGB,FALSE, 8,v->width,v->height,v->width*3,NULL,NULL ); else list[i] = gdk_pixbuf_new_from_data( v->data_buffer, GDK_COLORSPACE_RGB, FALSE, 8, v->width, v->height, v->width * 3, NULL,NULL ); /* if(v->grey_scale) { uint8_t *rgb = v->tmp_buffer; uint8_t *plane = v->data_buffer; unsigned int j,k = 0; unsigned int stride = v->width * 3; for( j = 0; j < (v->width*v->height); j+=3 ) { rgb[j+0] = v->data_buffer[j]; rgb[j+1] = v->data_buffer[j]; rgb[j+2] = v->data_buffer[j]; } for( j = 0; j < v->height; j ++ ) { for( k = 0; k < v->width ; k ++ ) { uint8_t *p = rgb + j * stride + (k*3); p[0] = plane[j * v->width + k]; p[1] = plane[j * v->width + k]; p[2] = plane[j * v->width + k]; } } list[i] = gdk_pixbuf_new_from_data(v->data_buffer, GDK_COLORSPACE_RGB, FALSE, 8, v->width,v->height,v->width * 3, NULL,NULL ); } else { list[i] = gdk_pixbuf_new_from_data( v->data_buffer, GDK_COLORSPACE_RGB, FALSE, 8, v->width,v->height,v->width * 3,NULL,NULL ); }*/ vp->tracks[i]->have_frame = 0; } } return list; } static int *int_dup( int *status ) { int *res = (int*) vj_calloc( sizeof(int) * 32 ); int i; for(i =0; i < 32 ; i ++ ) res[i] = status[i]; return res; } static int **gvr_grab_stati( void *preview ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int **list = (GdkPixbuf**) vj_calloc( sizeof(int*) * vp->n_tracks ); if(!list) return NULL; int i; for( i = 0; i < vp->n_tracks; i ++ ) { veejay_track_t *v = vp->tracks[i]; if(v) list[i] = int_dup( vp->tracks[i]->status_tokens ); } return list; } static int *gvr_grab_widths( void *preview ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int *list = (GdkPixbuf**) vj_calloc( sizeof(int) * vp->n_tracks ); if(!list) return NULL; int i; for( i = 0; i < vp->n_tracks; i ++ ) { veejay_track_t *v = vp->tracks[i]; if(v) list[i] = vp->tracks[i]->width; } return list; } static int *gvr_grab_heights( void *preview ) { veejay_preview_t *vp = (veejay_preview_t*) preview; int *list = (GdkPixbuf**) vj_calloc( sizeof(int) * vp->n_tracks ); if(!list) return NULL; int i; for( i = 0; i < vp->n_tracks; i ++ ) { veejay_track_t *v = vp->tracks[i]; if(v) list[i] = vp->tracks[i]->height; } return list; } sync_info *gvr_sync( void *preview ) { veejay_preview_t *vp = (veejay_preview_t*) preview; sync_info *s = (sync_info*) vj_calloc(sizeof(sync_info)); g_mutex_lock( vp->mutex ); s->status_list = gvr_grab_stati( preview ); s->img_list = gvr_grab_images( preview ); s->tracks = vp->n_tracks; s->widths = gvr_grab_widths( preview ); s->heights = gvr_grab_heights( preview); g_mutex_unlock( vp->mutex ); return s; } static void gvr_parse_track_list( veejay_preview_t *vp, veejay_track_t *v, unsigned char *tmp, int len ) { int i = 0; int items = 0; unsigned char *ptr = tmp; unsigned char **z = vj_calloc( sizeof( unsigned char * ) * vp->n_tracks ); while( i < len ) { int k = 0; unsigned char k_str[4]; strncpy( (char*) k_str,(char*) ptr, 3 ); if( k > 0 ) { ptr += 3; z[items] = strndup( (char*) ptr, k ); items ++; ptr += k; } i += ( 3 + k ); } if( items > 0 ) { for( i = 0; i < items ; i ++ ) { int k; int in_track = -1; for( k = 0; k < vp->n_tracks ; k ++ ) { veejay_track_t *t = vp->tracks[k]; if(t) { char hostname[255]; int port = 0; int stream_id = 0; veejay_memset(hostname,0,255 ); if( sscanf( (char*) z[i], "%s %d %d", hostname, port, &stream_id )) { if( strcasecmp( hostname, t->hostname ) == 0 && port == t->port_num ) in_track = k; } } } v->track_list[i] = in_track; free( z[i] ); } v->track_items = items; } free( z ); } int gvr_get_stream_id( void *data, int id ) { veejay_preview_t *vp = (veejay_preview_t*) data; veejay_track_t *v = vp->tracks[id]; if(v) return v->track_list[id]; return 0; } static void gvr_parse_queue( veejay_track_t *v ) { int i; for( i = 0; i < v->n_queued ; i ++ ) { vj_client_send( v->fd, V_CMD, v->queue[i] ); free( v->queue[i] ); } v->n_queued = 0; } static int gvr_veejay( veejay_preview_t *vp , veejay_track_t *v, int track_num ) { int score = 0; g_mutex_lock( vp->mutex ); if( v->need_track_list || v->n_queued > 0 ) { if( v->need_track_list ) { int bw = 0; unsigned char *tmp = vims_track_list( v, 5, &bw ); gvr_parse_track_list( vp, v, tmp, bw ); v->need_track_list = 0; } if( v->n_queued > 0 ) { gvr_parse_queue( v ); } score ++; } if( v->preview ) { if( gvr_preview_process_image( vp,v )) score++; else { v->preview = 0; v->have_frame = 0; veejay_msg(2, "Track %d VeejayGrabber %s:%d disabled", track_num, vp->tracks[ track_num ]->hostname, vp->tracks[ track_num ]->port_num); vj_client_close(v->fd); if(!vj_client_connect( v->fd, v->hostname, NULL, v->port_num ) ) { veejay_msg(0, "Unable to reconnect to Veejay. Closing track %d", track_num ); if(v->hostname) free(v->hostname); if(v->status_buffer) free(v->status_buffer); if(v->data_buffer) free(v->data_buffer); if(v->tmp_buffer) free(v->tmp_buffer); free(v); vp->tracks[track_num] = NULL; } else { v->preview = 1; v->have_frame = 0; v->active = 1; v->width = v->width >> 1; v->height = v->height >> 1; veejay_msg(2, "Restablished connection with veejay, changed preview size to %d x %d", v->width,v->height); } } } g_mutex_unlock( vp->mutex ); return score; } static void *gvr_preview_thread(gpointer data) { veejay_preview_t *vp = (veejay_preview_t*) data; int i; for( ;; ) { int score = 0; for( i = 0; i < vp->n_tracks ; i ++ ) { if( vp->tracks[i] && vp->tracks[i]->active) if(gvr_preview_process_status( vp, vp->tracks[i] )) { //after lock in status, assert if( vp->tracks[i] ) score += gvr_veejay( vp, vp->tracks[i],i ); } if( vp->state == 0 ) break; } /* for( i = 0; i < vp->n_tracks ; i ++ ) { if( vp->tracks[i] && vp->tracks[i]->active && ( vp->tracks[i]->need_track_list || vp->tracks[i]->n_queued > 0 )) { g_mutex_lock( vp->mutex ); if( vp->tracks[i]->need_track_list ) { int bw = 0; unsigned char *tmp = vims_track_list( vp->tracks[i], 5, &bw ); gvr_parse_track_list( vp, vp->tracks[i], tmp, bw ); vp->tracks[i]->need_track_list = 0; } if( vp->tracks[i]->n_queued > 0 ) gvr_parse_queue( vp->tracks[i] ); g_mutex_unlock( vp->mutex ); } } for( i = 0; i < vp->n_tracks ;i ++ ) { if( vp->tracks[i] && vp->tracks[i]->active ) { if( vp->tracks[i]->preview ) gvr_preview_process_image( vp,vp->tracks[i] ); } }*/ if( vp->state == 0 ) break; if( score == 0 ) g_usleep( 2000 ); } return NULL; }