/** * Add a SAP announce */ int SAP_Add (sap_handler_t *p_sap, session_descriptor_t *p_session) { int i; char psz_addr[NI_MAXNUMERICHOST]; sap_session_t *p_sap_session; mtime_t i_hash; union { struct sockaddr a; struct sockaddr_in in; struct sockaddr_in6 in6; } addr; socklen_t addrlen; addrlen = p_session->addrlen; if ((addrlen == 0) || (addrlen > sizeof (addr))) { msg_Err( p_sap, "No/invalid address specified for SAP announce" ); return VLC_EGENERIC; } /* Determine SAP multicast address automatically */ memcpy (&addr, &p_session->addr, addrlen); switch (addr.a.sa_family) { #if defined (HAVE_INET_PTON) || defined (WIN32) case AF_INET6: { /* See RFC3513 for list of valid IPv6 scopes */ struct in6_addr *a6 = &addr.in6.sin6_addr; memcpy( a6->s6_addr + 2, "\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x02\x7f\xfe", 14 ); if( IN6_IS_ADDR_MULTICAST( a6 ) ) /* force flags to zero, preserve scope */ a6->s6_addr[1] &= 0xf; else /* Unicast IPv6 - assume global scope */ memcpy( a6->s6_addr, "\xff\x0e", 2 ); break; } #endif case AF_INET: { /* See RFC2365 for IPv4 scopes */ uint32_t ipv4 = addr.in.sin_addr.s_addr; /* 224.0.0.0/24 => 224.0.0.255 */ if ((ipv4 & htonl (0xffffff00)) == htonl (0xe0000000)) ipv4 = htonl (0xe00000ff); else /* 239.255.0.0/16 => 239.255.255.255 */ if ((ipv4 & htonl (0xffff0000)) == htonl (0xefff0000)) ipv4 = htonl (0xefffffff); else /* 239.192.0.0/14 => 239.195.255.255 */ if ((ipv4 & htonl (0xfffc0000)) == htonl (0xefc00000)) ipv4 = htonl (0xefc3ffff); else if ((ipv4 & htonl (0xff000000)) == htonl (0xef000000)) ipv4 = 0; else /* other addresses => 224.2.127.254 */ ipv4 = htonl (0xe0027ffe); if( ipv4 == 0 ) { msg_Err( p_sap, "Out-of-scope multicast address " "not supported by SAP" ); return VLC_EGENERIC; } addr.in.sin_addr.s_addr = ipv4; break; } default: msg_Err( p_sap, "Address family %d not supported by SAP", addr.a.sa_family ); return VLC_EGENERIC; } i = vlc_getnameinfo( &addr.a, addrlen, psz_addr, sizeof( psz_addr ), NULL, NI_NUMERICHOST ); if( i ) { msg_Err( p_sap, "%s", gai_strerror( i ) ); return VLC_EGENERIC; } /* Find/create SAP address thread */ msg_Dbg( p_sap, "using SAP address: %s", psz_addr); vlc_mutex_lock (&p_sap->lock); sap_address_t *sap_addr; for (sap_addr = p_sap->first; sap_addr; sap_addr = sap_addr->next) if (!strcmp (psz_addr, sap_addr->group)) break; if (sap_addr == NULL) { sap_addr = AddressCreate (VLC_OBJECT(p_sap), psz_addr); if (sap_addr == NULL) { vlc_mutex_unlock (&p_sap->lock); return VLC_EGENERIC; } sap_addr->next = p_sap->first; p_sap->first = sap_addr; } /* Switch locks. * NEVER take the global SAP lock when holding a SAP thread lock! */ vlc_mutex_lock (&sap_addr->lock); vlc_mutex_unlock (&p_sap->lock); memcpy (&p_session->orig, &sap_addr->orig, sap_addr->origlen); p_session->origlen = sap_addr->origlen; size_t headsize = 20, length; switch (p_session->orig.ss_family) { #ifdef AF_INET6 case AF_INET6: headsize += 16; break; #endif case AF_INET: headsize += 4; break; default: assert (0); } /* XXX: Check for dupes */ length = headsize + strlen (p_session->psz_sdp); p_sap_session = malloc (sizeof (*p_sap_session) + length + 1); if (p_sap_session == NULL) { vlc_mutex_unlock (&sap_addr->lock); return VLC_EGENERIC; /* NOTE: we should destroy the thread if left unused */ } p_sap_session->next = sap_addr->first; sap_addr->first = p_sap_session; p_sap_session->p_sd = p_session; p_sap_session->length = length; /* Build the SAP Headers */ uint8_t *psz_head = p_sap_session->data; /* SAPv1, not encrypted, not compressed */ psz_head[0] = 0x20; psz_head[1] = 0x00; /* No authentication length */ i_hash = mdate(); psz_head[2] = i_hash >> 8; /* Msg id hash */ psz_head[3] = i_hash; /* Msg id hash 2 */ headsize = 4; switch (p_session->orig.ss_family) { #ifdef AF_INET6 case AF_INET6: { struct in6_addr *a6 = &((struct sockaddr_in6 *)&p_session->orig)->sin6_addr; memcpy (psz_head + headsize, a6, 16); psz_head[0] |= 0x10; /* IPv6 flag */ headsize += 16; break; } #endif case AF_INET: { uint32_t ipv4 = (((struct sockaddr_in *)&p_session->orig)->sin_addr.s_addr); memcpy (psz_head + headsize, &ipv4, 4); headsize += 4; break; } } memcpy (psz_head + headsize, "application/sdp", 16); headsize += 16; /* Build the final message */ strcpy( (char *)psz_head + headsize, p_session->psz_sdp); sap_addr->session_count++; vlc_cond_signal (&sap_addr->wait); vlc_mutex_unlock (&sap_addr->lock); return VLC_SUCCESS; }
static void DecSysHold( decoder_sys_t *p_sys ) { vlc_mutex_lock( &p_sys->lock ); p_sys->i_refcount++; vlc_mutex_unlock( &p_sys->lock ); }
void CommonManage( vout_thread_t *p_vout ) { /* If we do not control our window, we check for geometry changes * ourselves because the parent might not send us its events. */ vlc_mutex_lock( &p_vout->p_sys->lock ); if( p_vout->p_sys->hparent && !p_vout->b_fullscreen ) { RECT rect_parent; POINT point; vlc_mutex_unlock( &p_vout->p_sys->lock ); GetClientRect( p_vout->p_sys->hparent, &rect_parent ); point.x = point.y = 0; ClientToScreen( p_vout->p_sys->hparent, &point ); OffsetRect( &rect_parent, point.x, point.y ); if( !EqualRect( &rect_parent, &p_vout->p_sys->rect_parent ) ) { p_vout->p_sys->rect_parent = rect_parent; /* FIXME I find such #ifdef quite weirds. Are they really needed ? */ #if defined(MODULE_NAME_IS_direct3d) SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, SWP_NOZORDER ); UpdateRects( p_vout, true ); #else /* This one is to force the update even if only * the position has changed */ SetWindowPos( p_vout->p_sys->hwnd, 0, 1, 1, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, 0 ); SetWindowPos( p_vout->p_sys->hwnd, 0, 0, 0, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, 0 ); #if defined(MODULE_NAME_IS_wingdi) || defined(MODULE_NAME_IS_wingapi) unsigned int i_x, i_y, i_width, i_height; vout_PlacePicture( p_vout, rect_parent.right - rect_parent.left, rect_parent.bottom - rect_parent.top, &i_x, &i_y, &i_width, &i_height ); SetWindowPos( p_vout->p_sys->hvideownd, HWND_TOP, i_x, i_y, i_width, i_height, 0 ); #endif #endif } } else { vlc_mutex_unlock( &p_vout->p_sys->lock ); } /* autoscale toggle */ if( p_vout->i_changes & VOUT_SCALE_CHANGE ) { p_vout->i_changes &= ~VOUT_SCALE_CHANGE; p_vout->b_autoscale = var_GetBool( p_vout, "autoscale" ); p_vout->i_zoom = (int) ZOOM_FP_FACTOR; UpdateRects( p_vout, true ); } /* scaling factor */ if( p_vout->i_changes & VOUT_ZOOM_CHANGE ) { p_vout->i_changes &= ~VOUT_ZOOM_CHANGE; p_vout->b_autoscale = false; p_vout->i_zoom = (int)( ZOOM_FP_FACTOR * var_GetFloat( p_vout, "scale" ) ); UpdateRects( p_vout, true ); } /* Check for cropping / aspect changes */ if( p_vout->i_changes & VOUT_CROP_CHANGE || p_vout->i_changes & VOUT_ASPECT_CHANGE ) { p_vout->i_changes &= ~VOUT_CROP_CHANGE; p_vout->i_changes &= ~VOUT_ASPECT_CHANGE; p_vout->fmt_out.i_x_offset = p_vout->fmt_in.i_x_offset; p_vout->fmt_out.i_y_offset = p_vout->fmt_in.i_y_offset; p_vout->fmt_out.i_visible_width = p_vout->fmt_in.i_visible_width; p_vout->fmt_out.i_visible_height = p_vout->fmt_in.i_visible_height; p_vout->fmt_out.i_aspect = p_vout->fmt_in.i_aspect; p_vout->fmt_out.i_sar_num = p_vout->fmt_in.i_sar_num; p_vout->fmt_out.i_sar_den = p_vout->fmt_in.i_sar_den; p_vout->output.i_aspect = p_vout->fmt_in.i_aspect; UpdateRects( p_vout, true ); } /* We used to call the Win32 PeekMessage function here to read the window * messages. But since window can stay blocked into this function for a * long time (for example when you move your window on the screen), I * decided to isolate PeekMessage in another thread. */ /* * Fullscreen change */ if( p_vout->i_changes & VOUT_FULLSCREEN_CHANGE || p_vout->p_sys->i_changes & VOUT_FULLSCREEN_CHANGE ) { Win32ToggleFullscreen( p_vout ); p_vout->i_changes &= ~VOUT_FULLSCREEN_CHANGE; p_vout->p_sys->i_changes &= ~VOUT_FULLSCREEN_CHANGE; } /* * Pointer change */ EventThreadMouseAutoHide( p_vout->p_sys->p_event ); /* * "Always on top" status change */ if( p_vout->p_sys->b_on_top_change ) { HMENU hMenu = GetSystemMenu( p_vout->p_sys->hwnd, FALSE ); bool b = var_GetBool( p_vout, "video-on-top" ); /* Set the window on top if necessary */ if( b && !( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) ) { CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_CHECKED ); SetWindowPos( p_vout->p_sys->hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); } else /* The window shouldn't be on top */ if( !b && ( GetWindowLong( p_vout->p_sys->hwnd, GWL_EXSTYLE ) & WS_EX_TOPMOST ) ) { CheckMenuItem( hMenu, IDM_TOGGLE_ON_TOP, MF_BYCOMMAND | MFS_UNCHECKED ); SetWindowPos( p_vout->p_sys->hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE ); } p_vout->p_sys->b_on_top_change = false; } }
static picture_t *decode(decoder_t *dec, block_t **pblock) { decoder_sys_t *sys = dec->p_sys; block_t *block; MMAL_BUFFER_HEADER_T *buffer; bool need_flush = false; uint32_t len; uint32_t flags = 0; MMAL_STATUS_T status; picture_t *ret = NULL; /* * Configure output port if necessary */ if (sys->output_format) { if (change_output_format(dec) < 0) msg_Err(dec, "Failed to change output port format"); } if (!pblock) goto out; block = *pblock; /* * Check whether full flush is required */ if (block && block->i_flags & BLOCK_FLAG_DISCONTINUITY) { flush_decoder(dec); block_Release(*pblock); return NULL; } /* * Send output buffers */ if (atomic_load(&sys->started)) { buffer = mmal_queue_get(sys->decoded_pictures); if (buffer) { ret = (picture_t *)buffer->user_data; ret->date = buffer->pts; ret->b_progressive = sys->b_progressive; ret->b_top_field_first = sys->b_top_field_first; if (sys->output_pool) { buffer->data = NULL; mmal_buffer_header_reset(buffer); mmal_buffer_header_release(buffer); } } fill_output_port(dec); } if (ret) goto out; /* * Process input */ if (!block) goto out; *pblock = NULL; if (block->i_flags & BLOCK_FLAG_CORRUPTED) flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED; vlc_mutex_lock(&sys->mutex); while (block->i_buffer > 0) { buffer = mmal_queue_timedwait(sys->input_pool->queue, 2); if (!buffer) { msg_Err(dec, "Failed to retrieve buffer header for input data"); need_flush = true; break; } mmal_buffer_header_reset(buffer); buffer->cmd = 0; buffer->pts = block->i_pts != 0 ? block->i_pts : block->i_dts; buffer->dts = block->i_dts; buffer->alloc_size = sys->input->buffer_size; len = block->i_buffer; if (len > buffer->alloc_size) len = buffer->alloc_size; buffer->data = block->p_buffer; block->p_buffer += len; block->i_buffer -= len; buffer->length = len; if (block->i_buffer == 0) buffer->user_data = block; buffer->flags = flags; status = mmal_port_send_buffer(sys->input, buffer); if (status != MMAL_SUCCESS) { msg_Err(dec, "Failed to send buffer to input port (status=%"PRIx32" %s)", status, mmal_status_to_string(status)); break; } atomic_fetch_add(&sys->input_in_transit, 1); } vlc_mutex_unlock(&sys->mutex); out: if (need_flush) flush_decoder(dec); return ret; }
/************************************************************************** * libvlc_media_list_retain (Public) * * Increase an object refcount. **************************************************************************/ void libvlc_media_list_retain( libvlc_media_list_t * p_mlist ) { vlc_mutex_lock( &p_mlist->refcount_lock ); p_mlist->i_refcount++; vlc_mutex_unlock( &p_mlist->refcount_lock ); }
/***************************************************************************** * Run: xosd thread ***************************************************************************** * This part of the interface runs in a separate thread *****************************************************************************/ static void Run( intf_thread_t *p_intf ) { playlist_t *p_playlist; playlist_item_t *p_item = NULL; char *psz_display = NULL; int cancel = vlc_savecancel(); while( true ) { // Wait for a signal vlc_restorecancel( cancel ); vlc_mutex_lock( &p_intf->p_sys->lock ); mutex_cleanup_push( &p_intf->p_sys->lock ); while( !p_intf->p_sys->b_need_update ) vlc_cond_wait( &p_intf->p_sys->cond, &p_intf->p_sys->lock ); p_intf->p_sys->b_need_update = false; vlc_cleanup_run(); // Compute the signal cancel = vlc_savecancel(); p_playlist = pl_Get( p_intf ); PL_LOCK; // If the playlist is empty don't do anything if( playlist_IsEmpty( p_playlist ) ) { PL_UNLOCK; continue; } free( psz_display ); int i_status = playlist_Status( p_playlist ); if( i_status == PLAYLIST_STOPPED ) { psz_display = strdup(_("Stop")); } else if( i_status == PLAYLIST_PAUSED ) { psz_display = strdup(_("Pause")); } else { p_item = playlist_CurrentPlayingItem( p_playlist ); if( !p_item ) { psz_display = NULL; PL_UNLOCK; continue; } input_item_t *p_input = p_item->p_input; mtime_t i_duration = input_item_GetDuration( p_input ); if( i_duration != -1 ) { char psz_durationstr[MSTRTIME_MAX_SIZE]; secstotimestr( psz_durationstr, i_duration / 1000000 ); if( asprintf( &psz_display, "%s (%s)", p_input->psz_name, psz_durationstr ) == -1 ) psz_display = NULL; } else psz_display = strdup( p_input->psz_name ); } PL_UNLOCK; /* Display */ xosd_display( p_intf->p_sys->p_osd, 0, /* first line */ XOSD_string, psz_display ); } }
/** * Video filter */ static picture_t *FilterVideo( filter_t *p_filter, picture_t *p_src ) { filter_sys_t *p_sys = p_filter->p_sys; logo_list_t *p_list = &p_sys->list; picture_t *p_dst = filter_NewPicture( p_filter ); if( !p_dst ) goto exit; picture_Copy( p_dst, p_src ); /* */ vlc_mutex_lock( &p_sys->lock ); logo_t *p_logo; if( p_list->i_next_pic < p_src->date ) p_logo = LogoListNext( p_list, p_src->date ); else p_logo = LogoListCurrent( p_list ); /* */ const picture_t *p_pic = p_logo->p_pic; if( p_pic ) { const video_format_t *p_fmt = &p_pic->format; const int i_dst_w = p_filter->fmt_out.video.i_visible_width; const int i_dst_h = p_filter->fmt_out.video.i_visible_height; if( p_sys->i_pos ) { if( p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM ) { p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height; } else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_TOP) ) { p_sys->i_pos_y = ( i_dst_h - p_fmt->i_visible_height ) / 2; } else { p_sys->i_pos_y = 0; } if( p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT ) { p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width; } else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT) ) { p_sys->i_pos_x = ( i_dst_w - p_fmt->i_visible_width ) / 2; } else { p_sys->i_pos_x = 0; } } /* */ const int i_alpha = p_logo->i_alpha != -1 ? p_logo->i_alpha : p_list->i_alpha; if( filter_ConfigureBlend( p_sys->p_blend, i_dst_w, i_dst_h, p_fmt ) || filter_Blend( p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y, p_pic, i_alpha ) ) { msg_Err( p_filter, "failed to blend a picture" ); } } vlc_mutex_unlock( &p_sys->lock ); exit: picture_Release( p_src ); return p_dst; }
/***************************************************************************** * Manage: manage main thread messages ***************************************************************************** * In this function, called approx. 10 times a second, we check what the * main program wanted to tell us. *****************************************************************************/ static int Manage( intf_thread_t *p_intf ) { GtkListStore *p_liststore; vlc_mutex_lock( &p_intf->change_lock ); /* Update the input */ if( p_intf->p_sys->p_input == NULL ) { p_intf->p_sys->p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE ); } else if( p_intf->p_sys->p_input->b_dead ) { vlc_object_release( p_intf->p_sys->p_input ); p_intf->p_sys->p_input = NULL; } if( p_intf->p_sys->p_input ) { input_thread_t *p_input = p_intf->p_sys->p_input; int64_t i_time = 0, i_length = 0; vlc_mutex_lock( &p_input->object_lock ); if( !p_input->b_die ) { playlist_t *p_playlist; E_(GtkModeManage)( p_intf ); p_intf->p_sys->b_playing = 1; /* update playlist interface */ p_playlist = (playlist_t *) vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if (p_playlist != NULL) { p_liststore = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT); /* Hidden index */ PlaylistRebuildListStore(p_liststore, p_playlist); gtk_tree_view_set_model(p_intf->p_sys->p_tvplaylist, (GtkTreeModel*) p_liststore); g_object_unref(p_liststore); vlc_object_release( p_playlist ); } /* Manage the slider */ i_time = var_GetTime( p_intf->p_sys->p_input, "time" ); i_length = var_GetTime( p_intf->p_sys->p_input, "length" ); if (p_intf->p_libvlc->i_cpu & CPU_CAPABILITY_FPU) { /* Manage the slider for CPU_CAPABILITY_FPU hardware */ if( p_intf->p_sys->b_playing ) { float newvalue = p_intf->p_sys->p_adj->value; /* If the user hasn't touched the slider since the last time, * then the input can safely change it */ if( newvalue == p_intf->p_sys->f_adj_oldvalue ) { /* Update the value */ p_intf->p_sys->p_adj->value = p_intf->p_sys->f_adj_oldvalue = ( 100 * i_time ) / i_length; g_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed" ); } /* Otherwise, send message to the input if the user has * finished dragging the slider */ else if( p_intf->p_sys->b_slider_free ) { double f_pos = (double)newvalue / 100.0; /* release the lock to be able to seek */ vlc_mutex_unlock( &p_input->object_lock ); var_SetFloat( p_input, "position", f_pos ); vlc_mutex_lock( &p_input->object_lock ); /* Update the old value */ p_intf->p_sys->f_adj_oldvalue = newvalue; } } } else { /* Manage the slider without CPU_CAPABILITY_FPU hardware */ if( p_intf->p_sys->b_playing ) { off_t newvalue = p_intf->p_sys->p_adj->value; /* If the user hasn't touched the slider since the last time, * then the input can safely change it */ if( newvalue == p_intf->p_sys->i_adj_oldvalue ) { /* Update the value */ p_intf->p_sys->p_adj->value = p_intf->p_sys->i_adj_oldvalue = ( 100 * i_time ) / i_length; g_signal_emit_by_name( GTK_OBJECT( p_intf->p_sys->p_adj ), "value_changed" ); } /* Otherwise, send message to the input if the user has * finished dragging the slider */ else if( p_intf->p_sys->b_slider_free ) { double f_pos = (double)newvalue / 100.0; /* release the lock to be able to seek */ vlc_mutex_unlock( &p_input->object_lock ); var_SetFloat( p_input, "position", f_pos ); vlc_mutex_lock( &p_input->object_lock ); /* Update the old value */ p_intf->p_sys->i_adj_oldvalue = newvalue; } } } } vlc_mutex_unlock( &p_input->object_lock ); } else if( p_intf->p_sys->b_playing && !p_intf->b_die ) { E_(GtkModeManage)( p_intf ); p_intf->p_sys->b_playing = 0; } #ifndef NEED_GTK2_MAIN if( p_intf->b_die ) { vlc_mutex_unlock( &p_intf->change_lock ); /* Prepare to die, young Skywalker */ gtk_main_quit(); return FALSE; } #endif vlc_mutex_unlock( &p_intf->change_lock ); return TRUE; }
/***************************************************************************** * CreateFiler: allocate mosaic video filter *****************************************************************************/ static int CreateFilter( vlc_object_t *p_this ) { filter_t *p_filter = (filter_t *)p_this; filter_sys_t *p_sys; vlc_object_t *p_libvlc = VLC_OBJECT( p_filter->p_libvlc ); char *psz_order, *_psz_order; char *psz_offsets; int i_index; vlc_value_t val; int i_command; /* The mosaic thread is more important than the decoder threads */ vlc_thread_set_priority( p_this, VLC_THREAD_PRIORITY_OUTPUT ); /* Allocate structure */ p_sys = p_filter->p_sys = malloc( sizeof( filter_sys_t ) ); if( p_sys == NULL ) return VLC_ENOMEM; p_filter->pf_sub_filter = Filter; vlc_mutex_init( &p_sys->lock ); vlc_mutex_lock( &p_sys->lock ); var_Create( p_libvlc, "mosaic-lock", VLC_VAR_MUTEX ); var_Get( p_libvlc, "mosaic-lock", &val ); p_sys->p_lock = val.p_address; config_ChainParse( p_filter, CFG_PREFIX, ppsz_filter_options, p_filter->p_cfg ); #define GET_VAR( name, min, max ) \ i_command = var_CreateGetIntegerCommand( p_filter, CFG_PREFIX #name ); \ p_sys->i_##name = __MIN( max, __MAX( min, i_command ) ); \ var_AddCallback( p_filter, CFG_PREFIX #name, MosaicCallback, p_sys ); GET_VAR( width, 0, INT_MAX ); GET_VAR( height, 0, INT_MAX ); GET_VAR( xoffset, 0, INT_MAX ); GET_VAR( yoffset, 0, INT_MAX ); GET_VAR( align, 0, 10 ); if( p_sys->i_align == 3 || p_sys->i_align == 7 ) p_sys->i_align = 5; /* FIXME: NOT THREAD SAFE w.r.t. callback */ GET_VAR( borderw, 0, INT_MAX ); GET_VAR( borderh, 0, INT_MAX ); GET_VAR( rows, 1, INT_MAX ); GET_VAR( cols, 1, INT_MAX ); GET_VAR( alpha, 0, 255 ); GET_VAR( position, 0, 2 ); GET_VAR( delay, 100, INT_MAX ); #undef GET_VAR p_sys->i_delay *= 1000; /* FIXME: NOT THREAD SAFE w.r.t. callback */ p_sys->b_ar = var_CreateGetBoolCommand( p_filter, CFG_PREFIX "keep-aspect-ratio" ); var_AddCallback( p_filter, CFG_PREFIX "keep-aspect-ratio", MosaicCallback, p_sys ); p_sys->b_keep = var_CreateGetBoolCommand( p_filter, CFG_PREFIX "keep-picture" ); if ( !p_sys->b_keep ) { p_sys->p_image = image_HandlerCreate( p_filter ); } p_sys->i_order_length = 0; p_sys->ppsz_order = NULL; psz_order = var_CreateGetStringCommand( p_filter, CFG_PREFIX "order" ); _psz_order = psz_order; var_AddCallback( p_filter, CFG_PREFIX "order", MosaicCallback, p_sys ); if( *psz_order ) { char *psz_end = NULL; i_index = 0; do { psz_end = strchr( psz_order, ',' ); i_index++; p_sys->ppsz_order = realloc( p_sys->ppsz_order, i_index * sizeof(char *) ); p_sys->ppsz_order[i_index - 1] = strndup( psz_order, psz_end - psz_order ); psz_order = psz_end+1; } while( psz_end ); p_sys->i_order_length = i_index; } free( _psz_order ); /* Manage specific offsets for substreams */ psz_offsets = var_CreateGetStringCommand( p_filter, CFG_PREFIX "offsets" ); p_sys->i_offsets_length = 0; p_sys->pi_x_offsets = NULL; p_sys->pi_y_offsets = NULL; mosaic_ParseSetOffsets( p_filter, p_sys, psz_offsets ); free( psz_offsets ); var_AddCallback( p_filter, CFG_PREFIX "offsets", MosaicCallback, p_sys ); vlc_mutex_unlock( &p_sys->lock ); return VLC_SUCCESS; }
void input_item_SetURI( input_item_t *p_i, const char *psz_uri ) { assert( psz_uri ); #ifndef NDEBUG if( !strstr( psz_uri, "://" ) || strchr( psz_uri, ' ' ) || strchr( psz_uri, '"' ) ) fprintf( stderr, "Warning: %s(\"%s\"): file path instead of URL.\n", __func__, psz_uri ); #endif vlc_mutex_lock( &p_i->lock ); free( p_i->psz_uri ); p_i->psz_uri = strdup( psz_uri ); p_i->i_type = GuessType( p_i ); if( p_i->psz_name ) ; else if( p_i->i_type == ITEM_TYPE_FILE || p_i->i_type == ITEM_TYPE_DIRECTORY ) { const char *psz_filename = strrchr( p_i->psz_uri, '/' ); if( psz_filename && *psz_filename == '/' ) psz_filename++; if( psz_filename && *psz_filename ) p_i->psz_name = strdup( psz_filename ); /* Make the name more readable */ if( p_i->psz_name ) { decode_URI( p_i->psz_name ); EnsureUTF8( p_i->psz_name ); } } else { /* Strip login and password from title */ int r; vlc_url_t url; vlc_UrlParse( &url, psz_uri, 0 ); if( url.psz_protocol ) { if( url.i_port > 0 ) r=asprintf( &p_i->psz_name, "%s://%s:%d%s", url.psz_protocol, url.psz_host, url.i_port, url.psz_path ? url.psz_path : "" ); else r=asprintf( &p_i->psz_name, "%s://%s%s", url.psz_protocol, url.psz_host ? url.psz_host : "", url.psz_path ? url.psz_path : "" ); } else { if( url.i_port > 0 ) r=asprintf( &p_i->psz_name, "%s:%d%s", url.psz_host, url.i_port, url.psz_path ? url.psz_path : "" ); else r=asprintf( &p_i->psz_name, "%s%s", url.psz_host, url.psz_path ? url.psz_path : "" ); } vlc_UrlClean( &url ); if( -1==r ) p_i->psz_name=NULL; /* recover from undefined value */ } vlc_mutex_unlock( &p_i->lock ); }
void input_item_SetEpg( input_item_t *p_item, const vlc_epg_t *p_update ) { vlc_mutex_lock( &p_item->lock ); /* */ vlc_epg_t *p_epg = NULL; for( int i = 0; i < p_item->i_epg; i++ ) { vlc_epg_t *p_tmp = p_item->pp_epg[i]; if( (p_tmp->psz_name == NULL) != (p_update->psz_name == NULL) ) continue; if( p_tmp->psz_name && p_update->psz_name && strcmp(p_tmp->psz_name, p_update->psz_name) ) continue; p_epg = p_tmp; break; } /* */ if( !p_epg ) { p_epg = vlc_epg_New( p_update->psz_name ); if( p_epg ) TAB_APPEND( p_item->i_epg, p_item->pp_epg, p_epg ); } if( p_epg ) vlc_epg_Merge( p_epg, p_update ); vlc_mutex_unlock( &p_item->lock ); if( !p_epg ) return; #ifdef EPG_DEBUG char *psz_epg; if( asprintf( &psz_epg, "EPG %s", p_epg->psz_name ? p_epg->psz_name : "unknown" ) < 0 ) goto signal; input_item_DelInfo( p_item, psz_epg, NULL ); vlc_mutex_lock( &p_item->lock ); for( int i = 0; i < p_epg->i_event; i++ ) { const vlc_epg_event_t *p_evt = p_epg->pp_event[i]; time_t t_start = (time_t)p_evt->i_start; struct tm tm_start; char psz_start[128]; localtime_r( &t_start, &tm_start ); snprintf( psz_start, sizeof(psz_start), "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d", 1900 + tm_start.tm_year, 1 + tm_start.tm_mon, tm_start.tm_mday, tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec ); if( p_evt->psz_short_description || p_evt->psz_description ) InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s %s", p_evt->psz_name, p_evt->i_duration/60/60, (p_evt->i_duration/60)%60, p_evt->psz_short_description ? p_evt->psz_short_description : "" , p_evt->psz_description ? p_evt->psz_description : "" ); else InputItemAddInfo( p_item, psz_epg, psz_start, "%s (%2.2d:%2.2d)", p_evt->psz_name, p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 ); } vlc_mutex_unlock( &p_item->lock ); free( psz_epg ); signal: #endif if( p_epg->i_event > 0 ) { vlc_event_t event = { .type = vlc_InputItemInfoChanged, }; vlc_event_send( &p_item->event_manager, &event ); }
/***************************************************************************** * PORTAUDIOThread: all interactions with libportaudio.a are handled * in this single thread. Otherwise libportaudio.a is _not_ happy :-( *****************************************************************************/ static void* PORTAUDIOThread( vlc_object_t *p_this ) { pa_thread_t *pa_thread = (pa_thread_t*)p_this; aout_instance_t *p_aout; aout_sys_t *p_sys; int i_err; int canc = vlc_savecancel (); while( vlc_object_alive (pa_thread) ) { /* Wait for start of stream */ vlc_mutex_lock( &pa_thread->lock_signal ); if( !pa_thread->b_signal ) vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal ); vlc_mutex_unlock( &pa_thread->lock_signal ); pa_thread->b_signal = false; p_aout = pa_thread->p_aout; p_sys = p_aout->output.p_sys; if( PAOpenDevice( p_aout ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open portaudio device" ); pa_thread->b_error = true; } if( !pa_thread->b_error && PAOpenStream( p_aout ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open portaudio device" ); pa_thread->b_error = true; i_err = Pa_Terminate(); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } } /* Tell the main thread that we are ready */ vlc_mutex_lock( &pa_thread->lock_wait ); pa_thread->b_wait = true; vlc_cond_signal( &pa_thread->wait ); vlc_mutex_unlock( &pa_thread->lock_wait ); /* Wait for end of stream */ vlc_mutex_lock( &pa_thread->lock_signal ); if( !pa_thread->b_signal ) vlc_cond_wait( &pa_thread->signal, &pa_thread->lock_signal ); vlc_mutex_unlock( &pa_thread->lock_signal ); pa_thread->b_signal = false; if( pa_thread->b_error ) continue; i_err = Pa_StopStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_StopStream: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } i_err = Pa_CloseStream( p_sys->p_stream ); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_CloseStream: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } i_err = Pa_Terminate(); if( i_err != paNoError ) { msg_Err( p_aout, "Pa_Terminate: %d (%s)", i_err, Pa_GetErrorText( i_err ) ); } /* Tell the main thread that we are ready */ vlc_mutex_lock( &pa_thread->lock_wait ); pa_thread->b_wait = true; vlc_cond_signal( &pa_thread->wait ); vlc_mutex_unlock( &pa_thread->lock_wait ); } vlc_restorecancel (canc); return NULL; }
/***************************************************************************** * Open: open the audio device *****************************************************************************/ static int Open( vlc_object_t * p_this ) { aout_instance_t *p_aout = (aout_instance_t *)p_this; struct aout_sys_t * p_sys; int i_err; msg_Dbg( p_aout, "entering Open()"); /* Allocate p_sys structure */ p_sys = malloc( sizeof(aout_sys_t) ); if( p_sys == NULL ) return VLC_ENOMEM; p_sys->p_aout = p_aout; p_sys->p_stream = 0; p_aout->output.p_sys = p_sys; p_aout->output.pf_play = Play; /* Retrieve output device id from config */ p_sys->i_device_id = var_CreateGetInteger( p_aout, "portaudio-audio-device" ); #ifdef PORTAUDIO_IS_SERIOUSLY_BROKEN if( !b_init ) { /* Test device */ if( PAOpenDevice( p_aout ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open portaudio device" ); free( p_sys ); return VLC_EGENERIC; } /* Close device for now. We'll re-open it later on */ if( ( i_err = Pa_Terminate() ) != paNoError ) { msg_Err( p_aout, "closing the device returned %d", i_err ); } b_init = true; /* Now we need to setup our DirectSound play notification structure */ pa_thread = vlc_object_create( p_aout, sizeof(pa_thread_t) ); pa_thread->p_aout = p_aout; pa_thread->b_error = false; vlc_mutex_init( &pa_thread->lock_wait ); vlc_cond_init( &pa_thread->wait ); pa_thread->b_wait = false; vlc_mutex_init( &pa_thread->lock_signal ); vlc_cond_init( &pa_thread->signal ); pa_thread->b_signal = false; /* Create PORTAUDIOThread */ if( vlc_thread_create( pa_thread, "aout", PORTAUDIOThread, VLC_THREAD_PRIORITY_OUTPUT ) ) { msg_Err( p_aout, "cannot create PORTAUDIO thread" ); return VLC_EGENERIC; } } else { pa_thread->p_aout = p_aout; pa_thread->b_wait = false; pa_thread->b_signal = false; pa_thread->b_error = false; } /* Signal start of stream */ vlc_mutex_lock( &pa_thread->lock_signal ); pa_thread->b_signal = true; vlc_cond_signal( &pa_thread->signal ); vlc_mutex_unlock( &pa_thread->lock_signal ); /* Wait until thread is ready */ vlc_mutex_lock( &pa_thread->lock_wait ); if( !pa_thread->b_wait ) vlc_cond_wait( &pa_thread->wait, &pa_thread->lock_wait ); vlc_mutex_unlock( &pa_thread->lock_wait ); pa_thread->b_wait = false; if( pa_thread->b_error ) { msg_Err( p_aout, "PORTAUDIO thread failed" ); Close( p_this ); return VLC_EGENERIC; } return VLC_SUCCESS; #else if( PAOpenDevice( p_aout ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open portaudio device" ); free( p_sys ); return VLC_EGENERIC; } if( PAOpenStream( p_aout ) != VLC_SUCCESS ) { msg_Err( p_aout, "cannot open portaudio device" ); } return VLC_SUCCESS; #endif }
static void DoFingerprint( vlc_object_t *p_this, fingerprinter_sys_t *p_sys, acoustid_fingerprint_t *fp ) { p_sys->p_input = NULL; p_sys->p_item = NULL; p_sys->chroma_fingerprint.psz_fingerprint = NULL; vlc_cleanup_push( cancelDoFingerprint, p_sys ); p_sys->p_item = input_item_New( NULL, NULL ); if ( ! p_sys->p_item ) goto end; char *psz_sout_option; /* Note: need at -max- 2 channels, but we can't guess it before playing */ /* the stereo upmix could make the mono tracks fingerprint to differ :/ */ if ( asprintf( &psz_sout_option, "sout=#transcode{acodec=%s,channels=2}:chromaprint", ( VLC_CODEC_S16L == VLC_CODEC_S16N ) ? "s16l" : "s16b" ) == -1 ) goto end; input_item_AddOption( p_sys->p_item, psz_sout_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_sout_option ); input_item_AddOption( p_sys->p_item, "vout=dummy", VLC_INPUT_OPTION_TRUSTED ); input_item_AddOption( p_sys->p_item, "aout=dummy", VLC_INPUT_OPTION_TRUSTED ); if ( fp->i_duration ) { if ( asprintf( &psz_sout_option, "stop-time=%u", fp->i_duration ) == -1 ) goto end; input_item_AddOption( p_sys->p_item, psz_sout_option, VLC_INPUT_OPTION_TRUSTED ); free( psz_sout_option ); } input_item_SetURI( p_sys->p_item, p_sys->psz_uri ) ; p_sys->p_input = input_Create( p_this, p_sys->p_item, "fingerprinter", NULL ); if ( p_sys->p_input ) { p_sys->chroma_fingerprint.i_duration = fp->i_duration; var_Create( p_sys->p_input, "fingerprint-data", VLC_VAR_ADDRESS ); var_SetAddress( p_sys->p_input, "fingerprint-data", & p_sys->chroma_fingerprint ); input_Start( p_sys->p_input ); /* Wait for input to start && end */ p_sys->condwait.i_input_state = var_GetInteger( p_sys->p_input, "state" ); if ( likely( var_AddCallback( p_sys->p_input, "intf-event", inputStateCallback, p_sys ) == VLC_SUCCESS ) ) { while( p_sys->condwait.i_input_state <= PAUSE_S ) { vlc_mutex_lock( &p_sys->condwait.lock ); mutex_cleanup_push( &p_sys->condwait.lock ); vlc_cond_wait( &p_sys->condwait.wait, &p_sys->condwait.lock ); vlc_cleanup_run(); } var_DelCallback( p_sys->p_input, "intf-event", inputStateCallback, p_sys ); } input_Stop( p_sys->p_input, true ); input_Close( p_sys->p_input ); p_sys->p_input = NULL; if ( p_sys->chroma_fingerprint.psz_fingerprint ) { fp->psz_fingerprint = strdup( p_sys->chroma_fingerprint.psz_fingerprint ); if ( ! fp->i_duration ) /* had not given hint */ fp->i_duration = p_sys->chroma_fingerprint.i_duration; } } end: vlc_cleanup_run( ); }
/* Flls a callback_info_t data structure in response * to an "intf-event" input event. * * @warning This function executes in the input thread. * * @return VLC_SUCCESS on success, VLC_E* on error. */ static int InputCallback( vlc_object_t *p_this, const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *data ) { input_thread_t *p_input = (input_thread_t *)p_this; intf_thread_t *p_intf = data; intf_sys_t *p_sys = p_intf->p_sys; dbus_int32_t i_state = PLAYBACK_STATE_INVALID; callback_info_t *p_info = calloc( 1, sizeof( callback_info_t ) ); if( unlikely(p_info == NULL) ) return VLC_ENOMEM; switch( newval.i_int ) { case INPUT_EVENT_DEAD: i_state = PLAYBACK_STATE_STOPPED; break; case INPUT_EVENT_STATE: switch( var_GetInteger( p_input, "state" ) ) { case OPENING_S: case PLAYING_S: i_state = PLAYBACK_STATE_PLAYING; break; case PAUSE_S: i_state = PLAYBACK_STATE_PAUSED; break; default: i_state = PLAYBACK_STATE_STOPPED; } break; case INPUT_EVENT_ITEM_META: p_info->signal = SIGNAL_INPUT_METADATA; break; case INPUT_EVENT_RATE: p_info->signal = SIGNAL_RATE; break; case INPUT_EVENT_POSITION: { mtime_t i_now = mdate(), i_pos, i_projected_pos, i_interval; float f_current_rate; /* Detect seeks * XXX: This is way more convoluted than it should be... */ i_pos = var_GetInteger( p_input, "time" ); if( !p_intf->p_sys->i_last_input_pos_event || !( var_GetInteger( p_input, "state" ) == PLAYING_S ) ) { p_intf->p_sys->i_last_input_pos_event = i_now; p_intf->p_sys->i_last_input_pos = i_pos; break; } f_current_rate = var_GetFloat( p_input, "rate" ); i_interval = ( i_now - p_intf->p_sys->i_last_input_pos_event ); i_projected_pos = p_intf->p_sys->i_last_input_pos + ( i_interval * f_current_rate ); p_intf->p_sys->i_last_input_pos_event = i_now; p_intf->p_sys->i_last_input_pos = i_pos; if( llabs( i_pos - i_projected_pos ) < SEEK_THRESHOLD ) break; p_info->signal = SIGNAL_SEEK; break; } default: free( p_info ); return VLC_SUCCESS; /* don't care */ } vlc_mutex_lock( &p_sys->lock ); if( i_state != PLAYBACK_STATE_INVALID && i_state != p_sys->i_playing_state ) { p_sys->i_playing_state = i_state; p_info->signal = SIGNAL_STATE; } if( p_info->signal ) vlc_array_append( p_intf->p_sys->p_events, p_info ); else free( p_info ); vlc_mutex_unlock( &p_intf->p_sys->lock ); wakeup_main_loop( p_intf ); (void)psz_var; (void)oldval; return VLC_SUCCESS; }
/***************************************************************************** * Filter *****************************************************************************/ static subpicture_t *Filter( filter_t *p_filter, mtime_t date ) { filter_sys_t *p_sys = p_filter->p_sys; bridge_t *p_bridge; subpicture_t *p_spu; int i_index, i_real_index, i_row, i_col; int i_greatest_real_index_used = p_sys->i_order_length - 1; unsigned int col_inner_width, row_inner_height; subpicture_region_t *p_region; subpicture_region_t *p_region_prev = NULL; /* Allocate the subpicture internal data. */ p_spu = filter_NewSubpicture( p_filter ); if( !p_spu ) return NULL; /* Initialize subpicture */ p_spu->i_channel = 0; p_spu->i_start = date; p_spu->i_stop = 0; p_spu->b_ephemer = true; p_spu->i_alpha = p_sys->i_alpha; p_spu->b_absolute = false; vlc_mutex_lock( &p_sys->lock ); vlc_mutex_lock( p_sys->p_lock ); p_bridge = GetBridge( p_filter ); if ( p_bridge == NULL ) { vlc_mutex_unlock( p_sys->p_lock ); vlc_mutex_unlock( &p_sys->lock ); return p_spu; } if ( p_sys->i_position == position_offsets ) { /* If we have either too much or not enough offsets, fall-back * to automatic positioning. */ if ( p_sys->i_offsets_length != p_sys->i_order_length ) { msg_Err( p_filter, "Number of specified offsets (%d) does not match number " "of input substreams in mosaic-order (%d), falling back " "to mosaic-position=0", p_sys->i_offsets_length, p_sys->i_order_length ); p_sys->i_position = position_auto; } } if ( p_sys->i_position == position_auto ) { int i_numpics = p_sys->i_order_length; /* keep slots and all */ for ( i_index = 0; i_index < p_bridge->i_es_num; i_index++ ) { bridged_es_t *p_es = p_bridge->pp_es[i_index]; if ( !p_es->b_empty ) { i_numpics ++; if( p_sys->i_order_length && p_es->psz_id != NULL ) { /* We also want to leave slots for images given in * mosaic-order that are not available in p_vout_picture */ int i; for( i = 0; i < p_sys->i_order_length ; i++ ) { if( !strcmp( p_sys->ppsz_order[i], p_es->psz_id ) ) { i_numpics--; break; } } } } } p_sys->i_rows = ceil(sqrt( (double)i_numpics )); p_sys->i_cols = ( i_numpics % p_sys->i_rows == 0 ? i_numpics / p_sys->i_rows : i_numpics / p_sys->i_rows + 1 ); } col_inner_width = ( ( p_sys->i_width - ( p_sys->i_cols - 1 ) * p_sys->i_borderw ) / p_sys->i_cols ); row_inner_height = ( ( p_sys->i_height - ( p_sys->i_rows - 1 ) * p_sys->i_borderh ) / p_sys->i_rows ); i_real_index = 0; for ( i_index = 0; i_index < p_bridge->i_es_num; i_index++ ) { bridged_es_t *p_es = p_bridge->pp_es[i_index]; video_format_t fmt_in, fmt_out; picture_t *p_converted; memset( &fmt_in, 0, sizeof( video_format_t ) ); memset( &fmt_out, 0, sizeof( video_format_t ) ); if ( p_es->b_empty ) continue; while ( p_es->p_picture != NULL && p_es->p_picture->date + p_sys->i_delay < date ) { if ( p_es->p_picture->p_next != NULL ) { picture_t *p_next = p_es->p_picture->p_next; picture_Release( p_es->p_picture ); p_es->p_picture = p_next; } else if ( p_es->p_picture->date + p_sys->i_delay + BLANK_DELAY < date ) { /* Display blank */ picture_Release( p_es->p_picture ); p_es->p_picture = NULL; p_es->pp_last = &p_es->p_picture; break; } else { msg_Dbg( p_filter, "too late picture for %s (%"PRId64 ")", p_es->psz_id, date - p_es->p_picture->date - p_sys->i_delay ); break; } } if ( p_es->p_picture == NULL ) continue; if ( p_sys->i_order_length == 0 ) { i_real_index++; } else { int i; for ( i = 0; i <= p_sys->i_order_length; i++ ) { if ( i == p_sys->i_order_length ) break; if ( strcmp( p_es->psz_id, p_sys->ppsz_order[i] ) == 0 ) { i_real_index = i; break; } } if ( i == p_sys->i_order_length ) i_real_index = ++i_greatest_real_index_used; } i_row = ( i_real_index / p_sys->i_cols ) % p_sys->i_rows; i_col = i_real_index % p_sys->i_cols ; if ( !p_sys->b_keep ) { /* Convert the images */ fmt_in.i_chroma = p_es->p_picture->format.i_chroma; fmt_in.i_height = p_es->p_picture->format.i_height; fmt_in.i_width = p_es->p_picture->format.i_width; if( fmt_in.i_chroma == VLC_CODEC_YUVA || fmt_in.i_chroma == VLC_CODEC_RGBA ) fmt_out.i_chroma = VLC_CODEC_YUVA; else fmt_out.i_chroma = VLC_CODEC_I420; fmt_out.i_width = col_inner_width; fmt_out.i_height = row_inner_height; if( p_sys->b_ar ) /* keep aspect ratio */ { if( (float)fmt_out.i_width / (float)fmt_out.i_height > (float)fmt_in.i_width / (float)fmt_in.i_height ) { fmt_out.i_width = ( fmt_out.i_height * fmt_in.i_width ) / fmt_in.i_height; } else { fmt_out.i_height = ( fmt_out.i_width * fmt_in.i_height ) / fmt_in.i_width; } } fmt_out.i_visible_width = fmt_out.i_width; fmt_out.i_visible_height = fmt_out.i_height; p_converted = image_Convert( p_sys->p_image, p_es->p_picture, &fmt_in, &fmt_out ); if( !p_converted ) { msg_Warn( p_filter, "image resizing and chroma conversion failed" ); continue; } } else { p_converted = p_es->p_picture; fmt_in.i_width = fmt_out.i_width = p_converted->format.i_width; fmt_in.i_height = fmt_out.i_height = p_converted->format.i_height; fmt_in.i_chroma = fmt_out.i_chroma = p_converted->format.i_chroma; fmt_out.i_visible_width = fmt_out.i_width; fmt_out.i_visible_height = fmt_out.i_height; } p_region = subpicture_region_New( &fmt_out ); /* FIXME the copy is probably not needed anymore */ if( p_region ) picture_Copy( p_region->p_picture, p_converted ); if( !p_sys->b_keep ) picture_Release( p_converted ); if( !p_region ) { msg_Err( p_filter, "cannot allocate SPU region" ); p_filter->pf_sub_buffer_del( p_filter, p_spu ); vlc_mutex_unlock( &p_sys->lock ); vlc_mutex_unlock( p_sys->p_lock ); return p_spu; } if( p_es->i_x >= 0 && p_es->i_y >= 0 ) { p_region->i_x = p_es->i_x; p_region->i_y = p_es->i_y; } else if( p_sys->i_position == position_offsets ) { p_region->i_x = p_sys->pi_x_offsets[i_real_index]; p_region->i_y = p_sys->pi_y_offsets[i_real_index]; } else { if( fmt_out.i_width > col_inner_width || p_sys->b_ar || p_sys->b_keep ) { /* we don't have to center the video since it takes the whole rectangle area or it's larger than the rectangle */ p_region->i_x = p_sys->i_xoffset + i_col * ( p_sys->i_width / p_sys->i_cols ) + ( i_col * p_sys->i_borderw ) / p_sys->i_cols; } else { /* center the video in the dedicated rectangle */ p_region->i_x = p_sys->i_xoffset + i_col * ( p_sys->i_width / p_sys->i_cols ) + ( i_col * p_sys->i_borderw ) / p_sys->i_cols + ( col_inner_width - fmt_out.i_width ) / 2; } if( fmt_out.i_height > row_inner_height || p_sys->b_ar || p_sys->b_keep ) { /* we don't have to center the video since it takes the whole rectangle area or it's taller than the rectangle */ p_region->i_y = p_sys->i_yoffset + i_row * ( p_sys->i_height / p_sys->i_rows ) + ( i_row * p_sys->i_borderh ) / p_sys->i_rows; } else { /* center the video in the dedicated rectangle */ p_region->i_y = p_sys->i_yoffset + i_row * ( p_sys->i_height / p_sys->i_rows ) + ( i_row * p_sys->i_borderh ) / p_sys->i_rows + ( row_inner_height - fmt_out.i_height ) / 2; } } p_region->i_align = p_sys->i_align; p_region->i_alpha = p_es->i_alpha; if( p_region_prev == NULL ) { p_spu->p_region = p_region; } else { p_region_prev->p_next = p_region; } p_region_prev = p_region; } vlc_mutex_unlock( p_sys->p_lock ); vlc_mutex_unlock( &p_sys->lock ); return p_spu; }
/***************************************************************************** * config_SaveConfigFile: Save a module's config options. ***************************************************************************** * It's no use to save the config options that kept their default values, so * we'll try to be a bit clever here. * * When we save we mustn't delete the config options of the modules that * haven't been loaded. So we cannot just create a new config file with the * config structures we've got in memory. * I don't really know how to deal with this nicely, so I will use a completly * dumb method ;-) * I will load the config file in memory, but skipping all the sections of the * modules we want to save. Then I will create a brand new file, dump the file * loaded in memory and then append the sections of the modules we want to * save. * Really stupid no ? *****************************************************************************/ static int SaveConfigFile (vlc_object_t *p_this) { module_t *p_parser; char *permanent = NULL, *temporary = NULL; if( config_PrepareDir( p_this ) ) { msg_Err( p_this, "no configuration directory" ); return -1; } /* List all available modules */ module_t **list = module_list_get (NULL); char *bigbuf = NULL; size_t bigsize = 0; FILE *file = config_OpenConfigFile (p_this); if (file != NULL) { struct stat st; /* Some users make vlcrc read-only to prevent changes. * The atomic replacement scheme breaks this "feature", * so we check for read-only by hand. */ if (fstat (fileno (file), &st) || !(st.st_mode & S_IWUSR)) { msg_Err (p_this, "configuration file is read-only"); goto error; } bigsize = (st.st_size < LONG_MAX) ? st.st_size : 0; bigbuf = malloc (bigsize + 1); if (bigbuf == NULL) goto error; /* backup file into memory, we only need to backup the sections we * won't save later on */ char *p_index = bigbuf; char *line = NULL; size_t bufsize; ssize_t linelen; bool backup = false; while ((linelen = getline (&line, &bufsize, file)) != -1) { char *p_index2; if ((line[0] == '[') && (p_index2 = strchr(line,']'))) { /* we found a new section, check if we need to do a backup */ backup = true; for (int i = 0; (p_parser = list[i]) != NULL; i++) { if (!strncmp (line + 1, p_parser->psz_object_name, strlen (p_parser->psz_object_name))) { backup = false; /* no, we will rewrite it! */ break; } } } /* save line if requested and line is valid (doesn't begin with a * space, tab, or eol) */ if (backup && !memchr ("\n\t ", line[0], 3)) { memcpy (p_index, line, linelen); p_index += linelen; } } fclose (file); file = NULL; free (line); *p_index = '\0'; bigsize = p_index - bigbuf; } /* * Save module config in file */ permanent = config_GetConfigFile (p_this); if (!permanent) { module_list_free (list); goto error; } if (asprintf (&temporary, "%s.%u", permanent, getpid ()) == -1) { temporary = NULL; module_list_free (list); goto error; } /* Configuration lock must be taken before vlcrc serializer below. */ vlc_rwlock_rdlock (&config_lock); /* The temporary configuration file is per-PID. Therefore SaveConfigFile() * should be serialized against itself within a given process. */ static vlc_mutex_t lock = VLC_STATIC_MUTEX; vlc_mutex_lock (&lock); int fd = vlc_open (temporary, O_CREAT|O_WRONLY|O_TRUNC, S_IRUSR|S_IWUSR); if (fd == -1) { vlc_rwlock_unlock (&config_lock); vlc_mutex_unlock (&lock); module_list_free (list); goto error; } file = fdopen (fd, "wt"); if (file == NULL) { msg_Err (p_this, "cannot create configuration file: %m"); vlc_rwlock_unlock (&config_lock); close (fd); vlc_mutex_unlock (&lock); module_list_free (list); goto error; } fprintf( file, "\xEF\xBB\xBF###\n" "### "PACKAGE_NAME" "PACKAGE_VERSION"\n" "###\n" "\n" "###\n" "### lines beginning with a '#' character are comments\n" "###\n" "\n" ); /* Ensure consistent number formatting... */ locale_t loc = newlocale (LC_NUMERIC_MASK, "C", NULL); locale_t baseloc = uselocale (loc); /* We would take the config lock here. But this would cause a lock * inversion with the serializer above and config_AutoSaveConfigFile(). vlc_rwlock_rdlock (&config_lock);*/ /* Look for the selected module, if NULL then save everything */ for (int i = 0; (p_parser = list[i]) != NULL; i++) { module_config_t *p_item, *p_end; if( !p_parser->i_config_items ) continue; fprintf( file, "[%s]", p_parser->psz_object_name ); if( p_parser->psz_longname ) fprintf( file, " # %s\n\n", p_parser->psz_longname ); else fprintf( file, "\n\n" ); for( p_item = p_parser->p_config, p_end = p_item + p_parser->confsize; p_item < p_end; p_item++ ) { if ((p_item->i_type & CONFIG_HINT) /* ignore hint */ || p_item->b_removed /* ignore deprecated option */ || p_item->b_unsaveable) /* ignore volatile option */ continue; if (IsConfigIntegerType (p_item->i_type)) { int64_t val = p_item->value.i; config_Write (file, p_item->psz_text, (p_item->i_type == CONFIG_ITEM_BOOL) ? N_("boolean") : N_("integer"), val == p_item->orig.i, p_item->psz_name, "%"PRId64, val); } else if (IsConfigFloatType (p_item->i_type)) { float val = p_item->value.f; config_Write (file, p_item->psz_text, N_("float"), val == p_item->orig.f, p_item->psz_name, "%f", val); } else { const char *psz_value = p_item->value.psz; bool modified; assert (IsConfigStringType (p_item->i_type)); modified = !!strcmp (psz_value ? psz_value : "", p_item->orig.psz ? p_item->orig.psz : ""); config_Write (file, p_item->psz_text, N_("string"), !modified, p_item->psz_name, "%s", psz_value ? psz_value : ""); } p_item->b_dirty = false; } } vlc_rwlock_unlock (&config_lock); module_list_free (list); if (loc != (locale_t)0) { uselocale (baseloc); freelocale (loc); } /* * Restore old settings from the config in file */ if (bigsize) fwrite (bigbuf, 1, bigsize, file); /* * Flush to disk and replace atomically */ fflush (file); /* Flush from run-time */ if (ferror (file)) { vlc_unlink (temporary); vlc_mutex_unlock (&lock); msg_Err (p_this, "cannot write configuration file"); clearerr (file); goto error; } #if defined(__APPLE__) || defined(__ANDROID__) fsync (fd); /* Flush from OS */ #else fdatasync (fd); /* Flush from OS */ #endif #if defined (WIN32) || defined (__OS2__) /* Windows cannot (re)move open files nor overwrite existing ones */ fclose (file); vlc_unlink (permanent); #endif /* Atomically replace the file... */ if (vlc_rename (temporary, permanent)) vlc_unlink (temporary); /* (...then synchronize the directory, err, TODO...) */ /* ...and finally close the file */ vlc_mutex_unlock (&lock); #if !defined (WIN32) && !defined (__OS2__) fclose (file); #endif free (temporary); free (permanent); free (bigbuf); return 0; error: if( file ) fclose( file ); free (temporary); free (permanent); free (bigbuf); return -1; }
/***************************************************************************** * Callback to update params on the fly *****************************************************************************/ static int MosaicCallback( vlc_object_t *p_this, char const *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data ) { VLC_UNUSED(oldval); filter_sys_t *p_sys = (filter_sys_t *) p_data; #define VAR_IS( a ) !strcmp( psz_var, CFG_PREFIX a ) if( VAR_IS( "alpha" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing alpha from %d/255 to %d/255", p_sys->i_alpha, newval.i_int); p_sys->i_alpha = __MIN( __MAX( newval.i_int, 0 ), 255 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "height" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing height from %dpx to %dpx", p_sys->i_height, newval.i_int ); p_sys->i_height = __MAX( newval.i_int, 0 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "width" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing width from %dpx to %dpx", p_sys->i_width, newval.i_int ); p_sys->i_width = __MAX( newval.i_int, 0 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "xoffset" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing x offset from %dpx to %dpx", p_sys->i_xoffset, newval.i_int ); p_sys->i_xoffset = __MAX( newval.i_int, 0 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "yoffset" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing y offset from %dpx to %dpx", p_sys->i_yoffset, newval.i_int ); p_sys->i_yoffset = __MAX( newval.i_int, 0 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "align" ) ) { int i_old = 0, i_new = 0; vlc_mutex_lock( &p_sys->lock ); newval.i_int = __MIN( __MAX( newval.i_int, 0 ), 10 ); if( newval.i_int == 3 || newval.i_int == 7 ) newval.i_int = 5; while( pi_align_values[i_old] != p_sys->i_align ) i_old++; while( pi_align_values[i_new] != newval.i_int ) i_new++; msg_Dbg( p_this, "changing alignment from %d (%s) to %d (%s)", p_sys->i_align, ppsz_align_descriptions[i_old], newval.i_int, ppsz_align_descriptions[i_new] ); p_sys->i_align = newval.i_int; vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "borderw" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing border width from %dpx to %dpx", p_sys->i_borderw, newval.i_int ); p_sys->i_borderw = __MAX( newval.i_int, 0 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "borderh" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing border height from %dpx to %dpx", p_sys->i_borderh, newval.i_int ); p_sys->i_borderh = __MAX( newval.i_int, 0 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "position" ) ) { if( newval.i_int > 2 || newval.i_int < 0 ) { msg_Err( p_this, "Position is either 0 (%s), 1 (%s) or 2 (%s)", ppsz_pos_descriptions[0], ppsz_pos_descriptions[1], ppsz_pos_descriptions[2] ); } else { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing position method from %d (%s) to %d (%s)", p_sys->i_position, ppsz_pos_descriptions[p_sys->i_position], newval.i_int, ppsz_pos_descriptions[newval.i_int]); p_sys->i_position = newval.i_int; vlc_mutex_unlock( &p_sys->lock ); } } else if( VAR_IS( "rows" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing number of rows from %d to %d", p_sys->i_rows, newval.i_int ); p_sys->i_rows = __MAX( newval.i_int, 1 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "cols" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "changing number of columns from %d to %d", p_sys->i_cols, newval.i_int ); p_sys->i_cols = __MAX( newval.i_int, 1 ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "order" ) ) { char *psz_order; int i_index; vlc_mutex_lock( &p_sys->lock ); msg_Dbg( p_this, "Changing mosaic order to %s", newval.psz_string ); psz_order = newval.psz_string; while( p_sys->i_order_length-- ) { free( p_sys->ppsz_order[p_sys->i_order_length] ); } free( p_sys->ppsz_order ); p_sys->ppsz_order = NULL; if( *psz_order ) { char *psz_end = NULL; i_index = 0; do { psz_end = strchr( psz_order, ',' ); i_index++; p_sys->ppsz_order = realloc( p_sys->ppsz_order, i_index * sizeof(char *) ); p_sys->ppsz_order[i_index - 1] = strndup( psz_order, psz_end - psz_order ); psz_order = psz_end+1; } while( psz_end ); p_sys->i_order_length = i_index; } vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "offsets" ) ) { vlc_mutex_lock( &p_sys->lock ); msg_Info( p_this, "Changing mosaic-offsets to %s", newval.psz_string ); if( p_sys->i_offsets_length != 0 ) { p_sys->i_offsets_length = 0; free( p_sys->pi_x_offsets ); free( p_sys->pi_y_offsets ); p_sys->pi_x_offsets = NULL; p_sys->pi_y_offsets = NULL; } mosaic_ParseSetOffsets( p_this, p_sys, newval.psz_string ); vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "keep-aspect-ratio" ) ) { vlc_mutex_lock( &p_sys->lock ); if( newval.i_int ) { msg_Dbg( p_this, "keeping aspect ratio" ); p_sys->b_ar = 1; } else { msg_Dbg( p_this, "won't keep aspect ratio" ); p_sys->b_ar = 0; } vlc_mutex_unlock( &p_sys->lock ); } else if( VAR_IS( "keep-picture" ) ) { vlc_mutex_lock( &p_sys->lock ); p_sys->b_keep = newval.b_bool; if ( !p_sys->b_keep && !p_sys->p_image ) { p_sys->p_image = image_HandlerCreate( p_this ); } vlc_mutex_unlock( &p_sys->lock ); } return VLC_SUCCESS; }
/** * Sub source */ static subpicture_t *FilterSub( filter_t *p_filter, mtime_t date ) { filter_sys_t *p_sys = p_filter->p_sys; logo_list_t *p_list = &p_sys->list; subpicture_t *p_spu; subpicture_region_t *p_region; video_format_t fmt; picture_t *p_pic; logo_t *p_logo; vlc_mutex_lock( &p_sys->lock ); /* Basic test: b_spu_update occurs on a dynamic change, & i_next_pic is the general timer, when to look at updating the logo image */ if( ( !p_sys->b_spu_update && p_list->i_next_pic > date ) || !p_list->i_repeat ) { vlc_mutex_unlock( &p_sys->lock ); return NULL; } /* adjust index to the next logo */ p_logo = LogoListNext( p_list, date ); p_sys->b_spu_update = false; p_pic = p_logo->p_pic; /* Allocate the subpicture internal data. */ p_spu = filter_NewSubpicture( p_filter ); if( !p_spu ) goto exit; p_spu->b_absolute = p_sys->b_absolute; p_spu->i_start = date; p_spu->i_stop = 0; p_spu->b_ephemer = true; /* Send an empty subpicture to clear the display when needed */ if( p_list->i_repeat != -1 && p_list->i_counter == 0 ) { p_list->i_repeat--; if( p_list->i_repeat < 0 ) goto exit; } if( !p_pic || !p_logo->i_alpha || ( p_logo->i_alpha == -1 && !p_list->i_alpha ) ) goto exit; /* Create new SPU region */ memset( &fmt, 0, sizeof(video_format_t) ); fmt.i_chroma = VLC_CODEC_YUVA; fmt.i_sar_num = fmt.i_sar_den = 1; fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch; fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines; fmt.i_x_offset = fmt.i_y_offset = 0; p_region = subpicture_region_New( &fmt ); if( !p_region ) { msg_Err( p_filter, "cannot allocate SPU region" ); p_filter->pf_sub_buffer_del( p_filter, p_spu ); p_spu = NULL; goto exit; } /* */ picture_Copy( p_region->p_picture, p_pic ); /* where to locate the logo: */ if( p_sys->i_pos < 0 ) { /* set to an absolute xy */ p_region->i_align = SUBPICTURE_ALIGN_RIGHT | SUBPICTURE_ALIGN_TOP; p_spu->b_absolute = true; } else { /* set to one of the 9 relative locations */ p_region->i_align = p_sys->i_pos; p_spu->b_absolute = false; } p_region->i_x = p_sys->i_pos_x; p_region->i_y = p_sys->i_pos_y; p_spu->p_region = p_region; p_spu->i_alpha = ( p_logo->i_alpha != -1 ? p_logo->i_alpha : p_list->i_alpha ); exit: vlc_mutex_unlock( &p_sys->lock ); return p_spu; }
/***************************************************************************** * RunIntf: main loop *****************************************************************************/ static void RunIntf( intf_thread_t *p_intf ) { p_intf->p_sys->p_vout = NULL; if( InitThread( p_intf ) < 0 ) { msg_Err( p_intf, "cannot initialize intf" ); return; } /* Main loop */ while( !p_intf->b_die ) { vlc_mutex_lock( &p_intf->change_lock ); /* Notify the interfaces */ if( p_intf->p_sys->b_triggered ) { playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE ); if( p_playlist != NULL ) { vlc_value_t val; val.b_bool = VLC_TRUE; var_Set( p_playlist, "intf-show", val ); vlc_object_release( p_playlist ); } p_intf->p_sys->b_triggered = VLC_FALSE; } vlc_mutex_unlock( &p_intf->change_lock ); /* Take care of the video output */ if( p_intf->p_sys->p_vout && p_intf->p_sys->p_vout->b_die ) { var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved", MouseEvent, p_intf ); var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down", MouseEvent, p_intf ); vlc_object_release( p_intf->p_sys->p_vout ); p_intf->p_sys->p_vout = NULL; } if( p_intf->p_sys->p_vout == NULL ) { p_intf->p_sys->p_vout = vlc_object_find( p_intf, VLC_OBJECT_VOUT, FIND_ANYWHERE ); if( p_intf->p_sys->p_vout ) { var_AddCallback( p_intf->p_sys->p_vout, "mouse-moved", MouseEvent, p_intf ); var_AddCallback( p_intf->p_sys->p_vout, "mouse-button-down", MouseEvent, p_intf ); } } /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); } if( p_intf->p_sys->p_vout ) { var_DelCallback( p_intf->p_sys->p_vout, "mouse-moved", MouseEvent, p_intf ); var_DelCallback( p_intf->p_sys->p_vout, "mouse-button-down", MouseEvent, p_intf ); vlc_object_release( p_intf->p_sys->p_vout ); } }
/** * Sub source */ static subpicture_t *FilterSub(filter_t *p_filter, mtime_t date) { filter_sys_t *p_sys = p_filter->p_sys; BarGraph_t *p_BarGraph = &(p_sys->p_BarGraph); subpicture_t *p_spu; subpicture_region_t *p_region; video_format_t fmt; picture_t *p_pic; vlc_mutex_lock(&p_sys->lock); /* Basic test: b_spu_update occurs on a dynamic change */ if (!p_sys->b_spu_update) { vlc_mutex_unlock(&p_sys->lock); return NULL; } p_pic = p_BarGraph->p_pic; /* Allocate the subpicture internal data. */ p_spu = filter_NewSubpicture(p_filter); if (!p_spu) goto exit; p_spu->b_absolute = p_sys->b_absolute; p_spu->i_start = date; p_spu->i_stop = 0; p_spu->b_ephemer = true; /* Send an empty subpicture to clear the display when needed */ if (!p_pic || !p_BarGraph->i_alpha) goto exit; /* Create new SPU region */ memset(&fmt, 0, sizeof(video_format_t)); fmt.i_chroma = VLC_CODEC_YUVA; fmt.i_sar_num = fmt.i_sar_den = 1; fmt.i_width = fmt.i_visible_width = p_pic->p[Y_PLANE].i_visible_pitch; fmt.i_height = fmt.i_visible_height = p_pic->p[Y_PLANE].i_visible_lines; fmt.i_x_offset = fmt.i_y_offset = 0; p_region = subpicture_region_New(&fmt); if (!p_region) { msg_Err(p_filter, "cannot allocate SPU region"); subpicture_Delete(p_spu); p_spu = NULL; goto exit; } /* */ picture_Copy(p_region->p_picture, p_pic); /* where to locate the bar graph: */ if (p_sys->i_pos < 0) { /* set to an absolute xy */ p_region->i_align = SUBPICTURE_ALIGN_RIGHT | SUBPICTURE_ALIGN_TOP; p_spu->b_absolute = true; } else { /* set to one of the 9 relative locations */ p_region->i_align = p_sys->i_pos; p_spu->b_absolute = false; } p_region->i_x = p_sys->i_pos_x; p_region->i_y = p_sys->i_pos_y; p_spu->p_region = p_region; p_spu->i_alpha = p_BarGraph->i_alpha ; exit: vlc_mutex_unlock(&p_sys->lock); return p_spu; }
/** * Filter a picture */ picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) { if( !p_pic_in || !p_filter) return NULL; const video_format_t *p_fmt_in = &p_filter->fmt_in.video; filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_pic_out = filter_NewPicture( p_filter ); if( !p_pic_out ) { picture_Release( p_pic_in ); return NULL; } int i_ret = 0; p_sys->b_bake_request = false; if ((p_sys->pi_order == NULL) || (p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL) || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)) p_sys->b_init = false; if ((p_sys->ps_pieces_shapes == NULL) && p_sys->s_current_param.b_advanced && (p_sys->s_current_param.i_shape_size != 0)) p_sys->b_init = false; /* assert initialized & allocated data match with current frame characteristics */ if ( p_sys->s_allocated.i_planes != p_pic_out->i_planes) p_sys->b_init = false; p_sys->s_current_param.i_planes = p_pic_out->i_planes; if (p_sys->ps_pict_planes != NULL) { for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) { if ( (p_sys->ps_pict_planes[i_plane].i_lines != p_pic_in->p[i_plane].i_visible_lines) || (p_sys->ps_pict_planes[i_plane].i_width != p_pic_in->p[i_plane].i_visible_pitch / p_pic_in->p[i_plane].i_pixel_pitch) || (p_sys->ps_desk_planes[i_plane].i_lines != p_pic_out->p[i_plane].i_visible_lines) || (p_sys->ps_desk_planes[i_plane].i_width != p_pic_out->p[i_plane].i_visible_pitch / p_pic_out->p[i_plane].i_pixel_pitch) ) p_sys->b_init = false; } } p_sys->s_current_param.i_pict_width = (int) p_pic_in->p[0].i_visible_pitch / p_pic_in->p[0].i_pixel_pitch; p_sys->s_current_param.i_pict_height = (int) p_pic_in->p[0].i_visible_lines; p_sys->s_current_param.i_desk_width = (int) p_pic_out->p[0].i_visible_pitch / p_pic_out->p[0].i_pixel_pitch; p_sys->s_current_param.i_desk_height = (int) p_pic_out->p[0].i_visible_lines; /* assert no mismatch between sizes */ if ( p_sys->s_current_param.i_pict_width != p_sys->s_current_param.i_desk_width || p_sys->s_current_param.i_pict_height != p_sys->s_current_param.i_desk_height || p_sys->s_current_param.i_pict_width != (int) p_fmt_in->i_visible_width || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_visible_height ) { picture_Release(p_pic_in); picture_Release(p_pic_out); return NULL; } vlc_mutex_lock( &p_sys->lock ); /* check if we have to compute initial data */ if ( p_sys->b_change_param || p_sys->b_bake_request || !p_sys->b_init ) { if ( p_sys->s_allocated.i_rows != p_sys->s_new_param.i_rows || p_sys->s_allocated.i_cols != p_sys->s_new_param.i_cols || p_sys->s_allocated.i_rotate != p_sys->s_new_param.i_rotate || p_sys->s_allocated.i_mode != p_sys->s_new_param.i_mode || p_sys->b_bake_request || !p_sys->b_init ) { p_sys->b_bake_request = true; p_sys->b_init = false; p_sys->b_shuffle_rqst = true; p_sys->b_shape_init = false; } if ( p_sys->s_current_param.i_border != p_sys->s_new_param.i_border || p_sys->s_current_param.i_shape_size != p_sys->s_new_param.i_shape_size ) { p_sys->b_bake_request = true; p_sys->b_shape_init = false; } /* depending on the game selected, set associated internal flags */ switch ( p_sys->s_new_param.i_mode ) { case 0: /* jigsaw puzzle */ p_sys->s_new_param.b_advanced = true; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = false; break; case 1: /* sliding puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = true; p_sys->s_new_param.b_near = true; break; case 2: /* swap puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = true; break; case 3: /* exchange puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = false; break; } p_sys->s_current_param.i_mode = p_sys->s_new_param.i_mode; if ( p_sys->s_current_param.b_blackslot != p_sys->s_new_param.b_blackslot && p_sys->i_selected == NO_PCE && p_sys->s_current_param.b_blackslot ) p_sys->i_selected = 0; if ( p_sys->s_current_param.i_auto_shuffle_speed != p_sys->s_new_param.i_auto_shuffle_speed ) p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_new_param.i_auto_shuffle_speed); if ( p_sys->s_current_param.i_auto_solve_speed != p_sys->s_new_param.i_auto_solve_speed ) p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed); p_sys->s_current_param.i_rows = p_sys->s_new_param.i_rows; p_sys->s_current_param.i_cols = p_sys->s_new_param.i_cols; p_sys->s_current_param.i_pieces_nbr = p_sys->s_current_param.i_rows * p_sys->s_current_param.i_cols; p_sys->s_current_param.b_advanced = p_sys->s_new_param.b_advanced; if (!p_sys->s_new_param.b_advanced) { p_sys->s_current_param.b_blackslot = p_sys->s_new_param.b_blackslot; p_sys->s_current_param.b_near = p_sys->s_new_param.b_near || p_sys->s_new_param.b_blackslot; p_sys->s_current_param.i_border = 0; p_sys->s_current_param.b_preview = false; p_sys->s_current_param.i_preview_size= 0; p_sys->s_current_param.i_shape_size = 0; p_sys->s_current_param.i_auto_shuffle_speed = 0; p_sys->s_current_param.i_auto_solve_speed = 0; p_sys->s_current_param.i_rotate = 0; } else { p_sys->s_current_param.b_blackslot = false; p_sys->s_current_param.b_near = false; p_sys->s_current_param.i_border = p_sys->s_new_param.i_border; p_sys->s_current_param.b_preview = p_sys->s_new_param.b_preview; p_sys->s_current_param.i_preview_size = p_sys->s_new_param.i_preview_size; p_sys->s_current_param.i_shape_size = p_sys->s_new_param.i_shape_size; p_sys->s_current_param.i_auto_shuffle_speed = p_sys->s_new_param.i_auto_shuffle_speed; p_sys->s_current_param.i_auto_solve_speed = p_sys->s_new_param.i_auto_solve_speed; p_sys->s_current_param.i_rotate = p_sys->s_new_param.i_rotate; } p_sys->b_change_param = false; } vlc_mutex_unlock( &p_sys->lock ); /* generate initial puzzle data when needed */ if ( p_sys->b_bake_request ) { if (!p_sys->b_shuffle_rqst) { /* here we have to keep the same position * we have to save locations before generating new data */ save_game_t *ps_save_game = puzzle_save(p_filter); if (!ps_save_game) return CopyInfoAndRelease( p_pic_out, p_pic_in ); i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in ); if ( i_ret != VLC_SUCCESS ) { free(ps_save_game->ps_pieces); free(ps_save_game); return CopyInfoAndRelease( p_pic_out, p_pic_in ); } puzzle_load( p_filter, ps_save_game); free(ps_save_game->ps_pieces); free(ps_save_game); } else { i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in ); if ( i_ret != VLC_SUCCESS ) return CopyInfoAndRelease( p_pic_out, p_pic_in ); } } /* shuffle the desk and generate pieces data */ if ( p_sys->b_shuffle_rqst && p_sys->b_init ) { i_ret = puzzle_bake_piece ( p_filter ); if (i_ret != VLC_SUCCESS) return CopyInfoAndRelease( p_pic_out, p_pic_in ); } /* preset output pic */ if ( !p_sys->b_bake_request && !p_sys->b_shuffle_rqst && p_sys->b_init && !p_sys->b_finished ) puzzle_preset_desk_background(p_pic_out, 0, 127, 127); else { /* copy src to dst during init & bake process */ for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ ) memcpy( p_pic_out->p[i_plane].p_pixels, p_pic_in->p[i_plane].p_pixels, p_pic_in->p[i_plane].i_pitch * (int32_t) p_pic_in->p[i_plane].i_visible_lines ); } vlc_mutex_lock( &p_sys->pce_lock ); /* manage the game, adjust locations, groups and regenerate some corrupted data if any */ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { puzzle_solve_pces_accuracy( p_filter ); } for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { puzzle_solve_pces_group( p_filter ); } if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ) puzzle_count_pce_group( p_filter); if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ) { i_ret = puzzle_sort_layers( p_filter); if (i_ret != VLC_SUCCESS) { vlc_mutex_unlock( &p_sys->pce_lock ); return CopyInfoAndRelease( p_pic_out, p_pic_in ); } } for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 24 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { p_sys->i_calc_corn_loop++; p_sys->i_calc_corn_loop %= p_sys->s_allocated.i_pieces_nbr; puzzle_calculate_corners( p_filter, p_sys->i_calc_corn_loop ); } /* computer moves some piece depending on auto_solve and auto_shuffle param */ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->ps_puzzle_array != NULL && p_sys->s_current_param.b_advanced ) { puzzle_auto_shuffle( p_filter ); puzzle_auto_solve( p_filter ); } vlc_mutex_unlock( &p_sys->pce_lock ); /* draw output pic */ if ( !p_sys->b_bake_request && p_sys->b_init && p_sys->ps_puzzle_array != NULL ) { puzzle_draw_borders(p_filter, p_pic_in, p_pic_out); p_sys->i_pointed_pce = NO_PCE; puzzle_draw_pieces(p_filter, p_pic_in, p_pic_out); /* when puzzle_draw_pieces() has not updated p_sys->i_pointed_pce, * use puzzle_find_piece to define the piece pointed by the mouse */ if (p_sys->i_pointed_pce == NO_PCE) p_sys->i_mouse_drag_pce = puzzle_find_piece( p_filter, p_sys->i_mouse_x, p_sys->i_mouse_y, -1); else p_sys->i_mouse_drag_pce = p_sys->i_pointed_pce; if (p_sys->s_current_param.b_preview ) puzzle_draw_preview(p_filter, p_pic_in, p_pic_out); /* highlight the selected piece when not playing jigsaw mode */ if ( p_sys->i_selected != NO_PCE && !p_sys->s_current_param.b_blackslot && !p_sys->s_current_param.b_advanced ) { int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols); int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols); puzzle_draw_rectangle(p_pic_out, p_sys->ps_puzzle_array[r][c][0].i_x, p_sys->ps_puzzle_array[r][c][0].i_y, p_sys->ps_puzzle_array[r][c][0].i_width, p_sys->ps_puzzle_array[r][c][0].i_lines, 255, 127, 127); } /* draw the blackslot when playing sliding puzzle mode */ if ( p_sys->i_selected != NO_PCE && p_sys->s_current_param.b_blackslot && !p_sys->s_current_param.b_advanced ) { int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols); int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols); puzzle_fill_rectangle(p_pic_out, p_sys->ps_puzzle_array[r][c][0].i_x, p_sys->ps_puzzle_array[r][c][0].i_y, p_sys->ps_puzzle_array[r][c][0].i_width, p_sys->ps_puzzle_array[r][c][0].i_lines, 0, 127, 127); } /* Draw the 'puzzle_shuffle' button if the puzzle is finished */ if ( p_sys->b_finished ) puzzle_draw_sign(p_pic_out, 0, 0, SHUFFLE_WIDTH, SHUFFLE_LINES, ppsz_shuffle_button, false); /* draw an arrow at mouse pointer to indicate current action (rotation...) */ if ((p_sys->i_mouse_drag_pce != NO_PCE) && !p_sys->b_mouse_drag && !p_sys->b_finished && p_sys->s_current_param.b_advanced ) { vlc_mutex_lock( &p_sys->pce_lock ); int32_t i_delta_x; if (p_sys->s_current_param.i_rotate != 3) i_delta_x = 0; else if ( (p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_actual_angle & 1) == 0) i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_width / 6; else i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_lines / 6; if (p_sys->s_current_param.i_rotate == 0) p_sys->i_mouse_action = 0; else if (p_sys->s_current_param.i_rotate == 1) p_sys->i_mouse_action = 2; else if ( p_sys->i_mouse_x >= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x + i_delta_x) ) p_sys->i_mouse_action = -1; /* rotate counterclockwise */ else if ( p_sys->i_mouse_x <= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x - i_delta_x) ) p_sys->i_mouse_action = +1; else p_sys->i_mouse_action = 4; /* center click: only mirror */ if ( p_sys->i_mouse_action == +1 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, false); else if ( p_sys->i_mouse_action == -1 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, true); else if ( p_sys->i_mouse_action == 4 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_mir_arrow_sign, false); vlc_mutex_unlock( &p_sys->pce_lock ); } } return CopyInfoAndRelease( p_pic_out, p_pic_in ); }
/***************************************************************************** * RunIntf: main loop *****************************************************************************/ static void RunIntf( intf_thread_t *p_intf ) { vlc_object_t * p_vout = NULL; mtime_t mtime = 0; mtime_t mlast = 0; vcdplayer_t * p_vcdplayer; input_thread_t * p_input; access_t * p_access; /* What you add to the last input number entry. It accumulates all of the 10_ADD keypresses */ int number_addend = 0; if( InitThread( p_intf ) < 0 ) { msg_Err( p_intf, "can't initialize intf" ); return; } p_input = p_intf->p_sys->p_input; while ( !p_intf->p_sys->p_vcdplayer ) { msleep( INTF_IDLE_SLEEP ); } p_vcdplayer = p_intf->p_sys->p_vcdplayer; p_access = p_vcdplayer->p_access; dbg_print( INPUT_DBG_CALL, "intf initialized" ); /* Main loop */ while( !p_intf->b_die ) { vlc_mutex_lock( &p_intf->change_lock ); /* * Have we timed-out in showing a still frame? */ if( p_intf->p_sys->b_still && !p_intf->p_sys->b_infinite_still ) { if( p_intf->p_sys->m_still_time > 0 ) { /* Update remaining still time */ dbg_print(INPUT_DBG_STILL, "updating still time"); mtime = mdate(); if( mlast ) { p_intf->p_sys->m_still_time -= mtime - mlast; } mlast = mtime; } else { /* Still time has elapsed; set to continue playing. */ dbg_print(INPUT_DBG_STILL, "wait time done - setting play"); var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S ); p_intf->p_sys->m_still_time = 0; p_intf->p_sys->b_still = 0; mlast = 0; } } /* * Do we have a keyboard event? */ if( p_vout && p_intf->p_sys->b_key_pressed ) { vlc_value_t val; int i, i_action = -1; struct hotkey *p_hotkeys = p_intf->p_vlc->p_hotkeys; p_intf->p_sys->b_key_pressed = VLC_FALSE; /* Find action triggered by hotkey (if any) */ var_Get( p_intf->p_vlc, "key-pressed", &val ); dbg_print( INPUT_DBG_EVENT, "Key pressed %d", val.i_int ); for( i = 0; p_hotkeys[i].psz_action != NULL; i++ ) { if( p_hotkeys[i].i_key == val.i_int ) { i_action = p_hotkeys[i].i_action; } } if( i_action != -1) { switch (i_action) { case ACTIONID_NAV_LEFT: dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_LEFT - prev (%d)", number_addend ); do { vcdplayer_play_prev( p_access ); } while (number_addend-- > 0); break; case ACTIONID_NAV_RIGHT: dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_RIGHT - next (%d)", number_addend ); do { vcdplayer_play_next( p_access ); } while (number_addend-- > 0); break; case ACTIONID_NAV_UP: dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_UP - return" ); do { vcdplayer_play_return( p_access ); } while (number_addend-- > 0); break; case ACTIONID_NAV_DOWN: dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_DOWN - default" ); vcdplayer_play_default( p_access ); break; case ACTIONID_NAV_ACTIVATE: { vcdinfo_itemid_t itemid; itemid.type=p_vcdplayer->play_item.type; dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_ACTIVATE" ); if ( vcdplayer_pbc_is_on( p_vcdplayer ) && number_addend != 0 ) { lid_t next_num=vcdinfo_selection_get_lid(p_vcdplayer->vcd, p_vcdplayer->i_lid, number_addend); if (VCDINFO_INVALID_LID != next_num) { itemid.num = next_num; itemid.type = VCDINFO_ITEM_TYPE_LID; vcdplayer_play( p_access, itemid ); } } else { itemid.num = number_addend; vcdplayer_play( p_access, itemid ); } break; } } number_addend = 0; /* Any keypress gets rid of still frame waiting. FIXME - should handle just the ones that cause an action. */ if( p_intf->p_sys->b_still ) { dbg_print(INPUT_DBG_STILL, "Playing still after activate"); var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S ); p_intf->p_sys->b_still = 0; p_intf->p_sys->b_infinite_still = 0; p_intf->p_sys->m_still_time = 0; } } else { unsigned int digit_entered=0; switch (val.i_int) { case '9': digit_entered++; case '8': digit_entered++; case '7': digit_entered++; case '6': digit_entered++; case '5': digit_entered++; case '4': digit_entered++; case '3': digit_entered++; case '2': digit_entered++; case '1': digit_entered++; case '0': { number_addend *= 10; number_addend += digit_entered; dbg_print( INPUT_DBG_EVENT, "Added %d. Number is now: %d\n", digit_entered, number_addend); break; } } } } vlc_mutex_unlock( &p_intf->change_lock ); if( p_vout == NULL ) { p_vout = vlc_object_find( p_intf->p_sys->p_input, VLC_OBJECT_VOUT, FIND_CHILD ); if( p_vout ) { var_AddCallback( p_vout, "key-pressed", KeyEvent, p_intf ); } } /* Wait a bit */ msleep( INTF_IDLE_SLEEP ); } if( p_vout ) { var_DelCallback( p_vout, "key-pressed", KeyEvent, p_intf ); vlc_object_release( p_vout ); } vlc_object_release( p_intf->p_sys->p_input ); }
/* mouse callback */ int puzzle_mouse( filter_t *p_filter, vlc_mouse_t *p_mouse, const vlc_mouse_t *p_old, const vlc_mouse_t *p_new ) { filter_sys_t *p_sys = p_filter->p_sys; const video_format_t *p_fmt_in = &p_filter->fmt_in.video; /* Only take events inside the puzzle area */ if( p_new->i_x < 0 || p_new->i_x >= (int)p_fmt_in->i_width || p_new->i_y < 0 || p_new->i_y >= (int)p_fmt_in->i_height ) return VLC_EGENERIC; if (! p_sys->b_init || p_sys->b_change_param) { *p_mouse = *p_new; return VLC_SUCCESS; } p_sys->i_mouse_x = p_new->i_x; p_sys->i_mouse_y = p_new->i_y; /* If the puzzle is finished, shuffle it if needed */ if( p_sys->b_finished ) { p_sys->b_mouse_drag = false; p_sys->b_mouse_mvt = false; if( vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ) && p_new->i_x < SHUFFLE_WIDTH && p_new->i_y < SHUFFLE_LINES ) { p_sys->b_shuffle_rqst = true; return VLC_EGENERIC; } else { /* otherwise we can forward the mouse */ *p_mouse = *p_new; return VLC_SUCCESS; } } if ( !p_sys->s_current_param.b_advanced ) { /* "square" game mode (sliding puzzle, swap...) */ const bool b_clicked = vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ); if( b_clicked ) { /* */ const int32_t i_border_width = p_fmt_in->i_width * p_sys->s_current_param.i_border / 100 / 2; const int32_t i_border_height = p_fmt_in->i_height * p_sys->s_current_param.i_border / 100 / 2; const int32_t i_pos_x = (p_new->i_x - i_border_width) * p_sys->s_allocated.i_cols / (p_fmt_in->i_width - 2*i_border_width); const int32_t i_pos_y = (p_new->i_y - i_border_height) * p_sys->s_allocated.i_rows / (p_fmt_in->i_height - 2*i_border_height); const int32_t i_pos = i_pos_y * p_sys->s_allocated.i_cols + i_pos_x; p_sys->i_mouse_drag_pce = i_pos; /* do not take into account if border clicked */ if ((p_new->i_x <= i_border_width) || (p_new->i_y <= i_border_height) || (p_new->i_x >= (int) p_fmt_in->i_width - i_border_width) || (p_new->i_y >= (int) p_fmt_in->i_height - i_border_height ) ) { *p_mouse = *p_new; return VLC_SUCCESS; } else if( p_sys->i_selected == NO_PCE ) p_sys->i_selected = i_pos; else if( p_sys->i_selected == i_pos && !p_sys->s_current_param.b_blackslot ) p_sys->i_selected = -1; else if( ( p_sys->i_selected == i_pos + 1 && p_sys->i_selected%p_sys->s_allocated.i_cols != 0 ) || ( p_sys->i_selected == i_pos - 1 && i_pos % p_sys->s_allocated.i_cols != 0 ) || p_sys->i_selected == i_pos + p_sys->s_allocated.i_cols || p_sys->i_selected == i_pos - p_sys->s_allocated.i_cols || !p_sys->s_current_param.b_near ) { /* Swap two pieces */ int32_t a = p_sys->pi_order[ p_sys->i_selected ]; p_sys->pi_order[ p_sys->i_selected ] = p_sys->pi_order[ i_pos ]; p_sys->pi_order[ i_pos ] = a; /* regen piece location from updated pi_order */ if ( p_sys->ps_pieces != NULL && p_sys->pi_order != NULL ) { int32_t i = 0; for (int32_t row = 0; row < p_sys->s_allocated.i_rows; row++) { for (int32_t col = 0; col < p_sys->s_allocated.i_cols; col++) { int32_t orow = p_sys->pi_order[i] / (p_sys->s_allocated.i_cols); int32_t ocol = p_sys->pi_order[i] % (p_sys->s_allocated.i_cols); p_sys->ps_pieces[i].i_original_row = orow; p_sys->ps_pieces[i].i_original_col = ocol; p_sys->ps_pieces[i].i_top_shape = 0; p_sys->ps_pieces[i].i_btm_shape = 0; p_sys->ps_pieces[i].i_right_shape = 0; p_sys->ps_pieces[i].i_left_shape = 0; p_sys->ps_pieces[i].i_actual_angle = 0; p_sys->ps_pieces[i].i_actual_mirror = +1; p_sys->ps_pieces[i].b_overlap = false; p_sys->ps_pieces[i].b_finished = false; p_sys->ps_pieces[i].i_group_ID = i; for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) { p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_width = p_sys->ps_puzzle_array[row][col][i_plane].i_width; p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_lines = p_sys->ps_puzzle_array[row][col][i_plane].i_lines; p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_original_x = p_sys->ps_puzzle_array[orow][ocol][i_plane].i_x; p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_original_y = p_sys->ps_puzzle_array[orow][ocol][i_plane].i_y; p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_actual_x = p_sys->ps_puzzle_array[row][col][i_plane].i_x; p_sys->ps_pieces[i].ps_piece_in_plane[i_plane].i_actual_y = p_sys->ps_puzzle_array[row][col][i_plane].i_y; } i++; } } } p_sys->i_selected = p_sys->s_current_param.b_blackslot ? i_pos : NO_PCE; p_sys->b_finished = puzzle_is_finished( p_sys, p_sys->pi_order ); } } } else /* jigsaw puzzle mode */ { if ((p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL) || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)) { *p_mouse = *p_new; return VLC_SUCCESS; } if( vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT ) ) { vlc_mutex_lock( &p_sys->pce_lock ); if (p_sys->i_mouse_drag_pce != NO_PCE) { int i_ret = puzzle_piece_foreground( p_filter, p_sys->i_mouse_drag_pce); if (i_ret != VLC_SUCCESS) { vlc_mutex_unlock( &p_sys->pce_lock ); return i_ret; } p_sys->i_mouse_drag_pce = 0; uint32_t i_group_ID = p_sys->ps_pieces[0].i_group_ID; for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) { if ( i_group_ID == p_sys->ps_pieces[i].i_group_ID ) { p_sys->ps_pieces[i].b_finished = false; } else { break; } } p_sys->b_mouse_drag = true; p_sys->b_mouse_mvt = false; } else { /* player click an empty area then search a piece which is overlapping another one and place it here */ p_sys->b_mouse_drag = false; for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) if ( p_sys->ps_pieces[i].b_overlap ) { puzzle_move_group( p_filter, i, p_new->i_x - p_sys->ps_pieces[i].i_center_x, p_new->i_y - p_sys->ps_pieces[i].i_center_y ); p_sys->ps_pieces[i].b_overlap = false; break; } p_sys->b_mouse_drag = false; } vlc_mutex_unlock( &p_sys->pce_lock ); } else if( vlc_mouse_HasReleased( p_old, p_new, MOUSE_BUTTON_LEFT ) ) { if ( !p_sys->b_mouse_mvt && p_sys->b_mouse_drag ) { /* piece clicked without any mouse mvt => rotate it or mirror */ if ( p_sys->s_current_param.i_rotate != 0) { vlc_mutex_lock( &p_sys->pce_lock ); uint32_t i_group_ID = p_sys->ps_pieces[0].i_group_ID; for (uint32_t i = 0; i < p_sys->s_allocated.i_pieces_nbr; i++) if ( i_group_ID == p_sys->ps_pieces[i].i_group_ID ) puzzle_rotate_pce( p_filter, i, p_sys->i_mouse_action, p_sys->ps_pieces[0].i_center_x, p_sys->ps_pieces[0].i_center_y, p_sys->i_mouse_action != 4 ? true : false ); vlc_mutex_unlock( &p_sys->pce_lock ); } } p_sys->b_mouse_drag = false; p_sys->b_mouse_mvt = false; } else /* no action on left button */ { /* check if the mouse is in the preview area */ switch ( p_sys->i_preview_pos ) { case 0: if ( p_new->i_x < (int)p_fmt_in->i_width / 2 && p_new->i_y < (int)p_fmt_in->i_height / 2 ) p_sys->i_preview_pos++; break; case 1: if ( p_new->i_x > (int)p_fmt_in->i_width / 2 && p_new->i_y < (int)p_fmt_in->i_height / 2 ) p_sys->i_preview_pos++; break; case 2: if ( p_new->i_x > (int)p_fmt_in->i_width / 2 && p_new->i_y > (int)p_fmt_in->i_height / 2 ) p_sys->i_preview_pos++; break; case 3: if ( p_new->i_x < (int)p_fmt_in->i_width / 2 && p_new->i_y > (int)p_fmt_in->i_height / 2 ) p_sys->i_preview_pos++; break; } p_sys->i_preview_pos %= 4; if ( !vlc_mouse_IsLeftPressed( p_new ) ) p_sys->b_mouse_drag = false; int i_dx, i_dy; vlc_mouse_GetMotion( &i_dx, &i_dy, p_old, p_new ); if ( i_dx != 0 || i_dy != 0 ) p_sys->b_mouse_mvt = true; if (p_sys->b_mouse_drag) { if ( ( p_new->i_x <= 0 ) || ( p_new->i_y <= 0 ) || ( p_new->i_x >= (int) p_fmt_in->i_width ) || ( p_new->i_y >= (int) p_fmt_in->i_height ) ) { /* if the mouse is outside the window, stop moving the piece/group */ p_sys->b_mouse_drag = false; p_sys->b_mouse_mvt = true; } else if ( i_dx != 0 || i_dy != 0 ) { vlc_mutex_lock( &p_sys->pce_lock ); puzzle_move_group( p_filter, p_sys->i_mouse_drag_pce, i_dx, i_dy); vlc_mutex_unlock( &p_sys->pce_lock ); } } } } return VLC_EGENERIC; }
/************************************************************************** * libvlc_media_list_lock (Public) * * The lock must be held in access operations. It is never used in the * Public method. **************************************************************************/ void libvlc_media_list_lock( libvlc_media_list_t * p_mlist ) { vlc_mutex_lock( &p_mlist->object_lock ); }
int GetInputMeta( playlist_item_t *item, DBusMessageIter *args ) { input_item_t *p_input = item->p_input; DBusMessageIter dict, dict_entry, variant, list; /** The duration of the track can be expressed in second, milli-seconds and µ-seconds */ dbus_int64_t i_mtime = input_item_GetDuration( p_input ); dbus_uint32_t i_time = i_mtime / 1000000; dbus_int64_t i_length = i_mtime / 1000; char *psz_trackid; if( -1 == asprintf( &psz_trackid, MPRIS_TRACKID_FORMAT, item->i_id ) ) return VLC_ENOMEM; const char* ppsz_meta_items[] = { "mpris:trackid", "xesam:url", "xesam:title", "xesam:artist", "xesam:album", "xesam:tracknumber", "vlc:time", "mpris:length", "xesam:genre", "xesam:userRating", "xesam:contentCreated", "mpris:artUrl", "mb:trackId", "vlc:audio-bitrate", "vlc:audio-samplerate", "vlc:video-bitrate", "vlc:audio-codec", "vlc:copyright", "xesam:comment", "vlc:encodedby", "language", "vlc:length", "vlc:nowplaying", "vlc:publisher", "vlc:setting", "status", "vlc:url", "vlc:video-codec" }; dbus_message_iter_open_container( args, DBUS_TYPE_ARRAY, "{sv}", &dict ); ADD_META( 0, DBUS_TYPE_OBJECT_PATH, psz_trackid ); ADD_VLC_META_STRING( 1, URI ); ADD_VLC_META_STRING( 2, Title ); ADD_META_SINGLETON_STRING_LIST( 3, Artist ); ADD_VLC_META_STRING( 4, Album ); ADD_VLC_META_STRING( 5, TrackNum ); ADD_META( 6, DBUS_TYPE_UINT32, i_time ); ADD_META( 7, DBUS_TYPE_INT64, i_mtime ); ADD_META_SINGLETON_STRING_LIST( 8, Genre ); //ADD_META( 9, DBUS_TYPE_DOUBLE, rating ); ADD_VLC_META_STRING( 10, Date ); // this is supposed to be in ISO 8601 extended format ADD_VLC_META_STRING( 11, ArtURL ); ADD_VLC_META_STRING( 12, TrackID ); ADD_VLC_META_STRING( 17, Copyright ); ADD_META_SINGLETON_STRING_LIST( 18, Description ); ADD_VLC_META_STRING( 19, EncodedBy ); ADD_VLC_META_STRING( 20, Language ); ADD_META( 21, DBUS_TYPE_INT64, i_length ); ADD_VLC_META_STRING( 22, NowPlaying ); ADD_VLC_META_STRING( 23, Publisher ); ADD_VLC_META_STRING( 24, Setting ); ADD_VLC_META_STRING( 25, URL ); free( psz_trackid ); vlc_mutex_lock( &p_input->lock ); if( p_input->p_meta ) { int i_status = vlc_meta_GetStatus( p_input->p_meta ); ADD_META( 23, DBUS_TYPE_INT32, i_status ); } vlc_mutex_unlock( &p_input->lock ); dbus_message_iter_close_container( args, &dict ); return VLC_SUCCESS; }
/**************************************************************************** * DecodeBlock: ****************************************************************************/ static subpicture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; subpicture_t *p_spu = NULL; block_t *p_block; if( !pp_block || *pp_block == NULL ) return NULL; p_block = *pp_block; if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { p_sys->i_max_stop = VLC_TS_INVALID; block_Release( p_block ); return NULL; } *pp_block = NULL; if( p_block->i_buffer == 0 || p_block->p_buffer[0] == '\0' ) { block_Release( p_block ); return NULL; } subpicture_updater_sys_t *p_spu_sys = malloc( sizeof(*p_spu_sys) ); if( !p_spu_sys ) { block_Release( p_block ); return NULL; } subpicture_updater_t updater = { .pf_validate = SubpictureValidate, .pf_update = SubpictureUpdate, .pf_destroy = SubpictureDestroy, .p_sys = p_spu_sys, }; p_spu = decoder_NewSubpicture( p_dec, &updater ); if( !p_spu ) { msg_Warn( p_dec, "can't get spu buffer" ); free( p_spu_sys ); block_Release( p_block ); return NULL; } p_spu_sys->p_img = NULL; p_spu_sys->p_dec_sys = p_sys; p_spu_sys->i_subs_len = p_block->i_buffer; p_spu_sys->p_subs_data = malloc( p_block->i_buffer ); p_spu_sys->i_pts = p_block->i_pts; if( !p_spu_sys->p_subs_data ) { decoder_DeleteSubpicture( p_dec, p_spu ); block_Release( p_block ); return NULL; } memcpy( p_spu_sys->p_subs_data, p_block->p_buffer, p_block->i_buffer ); p_spu->i_start = p_block->i_pts; p_spu->i_stop = __MAX( p_sys->i_max_stop, p_block->i_pts + p_block->i_length ); p_spu->b_ephemer = true; p_spu->b_absolute = true; p_sys->i_max_stop = p_spu->i_stop; vlc_mutex_lock( &p_sys->lock ); if( p_sys->p_track ) { ass_process_chunk( p_sys->p_track, p_spu_sys->p_subs_data, p_spu_sys->i_subs_len, p_block->i_pts / 1000, p_block->i_length / 1000 ); } vlc_mutex_unlock( &p_sys->lock ); DecSysHold( p_sys ); /* Keep a reference for the returned subpicture */ block_Release( p_block ); return p_spu; }
static void *Run( void *data ) { intf_thread_t *p_intf = data; intf_sys_t *p_sys = p_intf->p_sys; int canc = vlc_savecancel(); for( ;; ) { vlc_mutex_lock( &p_sys->lock ); int i_watches = vlc_array_count( p_sys->p_watches ); struct pollfd fds[i_watches]; memset(fds, 0, sizeof fds); int i_fds = GetPollFds( p_intf, fds ); int timeout = next_timeout(p_intf); vlc_mutex_unlock( &p_sys->lock ); /* thread cancellation is allowed while the main loop sleeps */ vlc_restorecancel( canc ); while (poll(fds, i_fds, timeout) == -1) { if (errno != EINTR) goto error; } canc = vlc_savecancel(); /* Was the main loop woken up manually ? */ if (fds[0].revents & POLLIN) { char buf; (void)read( fds[0].fd, &buf, 1 ); } /* We need to lock the mutex while building lists of events, * timeouts and watches to process but we can't keep the lock while * processing them, or else we risk a deadlock: * * The signal functions could lock mutex X while p_events is locked; * While some other function in vlc (playlist) might lock mutex X * and then set a variable which would call AllCallback(), which itself * needs to lock p_events to add a new event. */ vlc_mutex_lock( &p_intf->p_sys->lock ); process_timeouts(p_intf); /* Get the list of watches to process */ i_watches = vlc_array_count( p_sys->p_watches ); DBusWatch *p_watches[i_watches ? i_watches : 1]; for( int i = 0; i < i_watches; i++ ) { p_watches[i] = vlc_array_item_at_index( p_sys->p_watches, i ); } /* Get the list of events to process */ int i_events = vlc_array_count( p_intf->p_sys->p_events ); callback_info_t* p_info[i_events ? i_events : 1]; for( int i = i_events - 1; i >= 0; i-- ) { p_info[i] = vlc_array_item_at_index( p_intf->p_sys->p_events, i ); vlc_array_remove( p_intf->p_sys->p_events, i ); } /* now we can release the lock and process what's pending */ vlc_mutex_unlock( &p_intf->p_sys->lock ); ProcessEvents( p_intf, p_info, i_events ); ProcessWatches( p_intf, p_watches, i_watches, fds, i_fds ); DispatchDBusMessages( p_intf ); } error: vlc_restorecancel(canc); return NULL; }
static void EqzFilter( filter_t *p_filter, float *out, float *in, int i_samples, int i_channels ) { filter_sys_t *p_sys = p_filter->p_sys; int i, ch, j; vlc_mutex_lock( &p_sys->lock ); for( i = 0; i < i_samples; i++ ) { for( ch = 0; ch < i_channels; ch++ ) { const float x = in[ch]; float o = 0.0; for( j = 0; j < p_sys->i_band; j++ ) { float y = p_sys->f_alpha[j] * ( x - p_sys->x[ch][1] ) + p_sys->f_gamma[j] * p_sys->y[ch][j][0] - p_sys->f_beta[j] * p_sys->y[ch][j][1]; p_sys->y[ch][j][1] = p_sys->y[ch][j][0]; p_sys->y[ch][j][0] = y; o += y * p_sys->f_amp[j]; } p_sys->x[ch][1] = p_sys->x[ch][0]; p_sys->x[ch][0] = x; /* Second filter */ if( p_sys->b_2eqz ) { const float x2 = EQZ_IN_FACTOR * x + o; o = 0.0; for( j = 0; j < p_sys->i_band; j++ ) { float y = p_sys->f_alpha[j] * ( x2 - p_sys->x2[ch][1] ) + p_sys->f_gamma[j] * p_sys->y2[ch][j][0] - p_sys->f_beta[j] * p_sys->y2[ch][j][1]; p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0]; p_sys->y2[ch][j][0] = y; o += y * p_sys->f_amp[j]; } p_sys->x2[ch][1] = p_sys->x2[ch][0]; p_sys->x2[ch][0] = x2; /* We add source PCM + filtered PCM */ out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o ); } else { /* We add source PCM + filtered PCM */ out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o ); } } in += i_channels; out += i_channels; } vlc_mutex_unlock( &p_sys->lock ); }
static int SendIn( sout_stream_t *p_stream, sout_stream_id_t *id, block_t *p_buffer ) { in_sout_stream_sys_t *p_sys = (in_sout_stream_sys_t *)p_stream->p_sys; bridge_t *p_bridge; bool b_no_es = true; int i; int i_date = mdate(); /* First forward the packet for our own ES */ if( !p_sys->b_placeholder ) p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); /* Then check all bridged streams */ vlc_mutex_lock( &lock ); p_bridge = var_GetAddress( p_stream->p_libvlc, p_sys->psz_name ); if( p_bridge ) { for ( i = 0; i < p_bridge->i_es_num; i++ ) { if ( !p_bridge->pp_es[i]->b_empty ) b_no_es = false; while ( p_bridge->pp_es[i]->p_block != NULL && (p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay < i_date || p_bridge->pp_es[i]->p_block->i_dts + p_sys->i_delay < p_bridge->pp_es[i]->i_last) ) { block_t *p_block = p_bridge->pp_es[i]->p_block; msg_Dbg( p_stream, "dropping a packet (%"PRId64 ")", i_date - p_block->i_dts - p_sys->i_delay ); p_bridge->pp_es[i]->p_block = p_bridge->pp_es[i]->p_block->p_next; block_Release( p_block ); } if ( p_bridge->pp_es[i]->p_block == NULL ) { p_bridge->pp_es[i]->pp_last = &p_bridge->pp_es[i]->p_block; } if ( p_bridge->pp_es[i]->b_changed ) { if ( p_bridge->pp_es[i]->b_empty && p_bridge->pp_es[i]->id != NULL ) { p_stream->p_next->pf_del( p_stream->p_next, p_bridge->pp_es[i]->id ); } else { /* We need at least two packets to enter the mux. */ if ( p_bridge->pp_es[i]->p_block == NULL || p_bridge->pp_es[i]->p_block->p_next == NULL ) { continue; } p_bridge->pp_es[i]->fmt.i_id += p_sys->i_id_offset; if( !p_sys->b_placeholder ) { p_bridge->pp_es[i]->id = p_stream->p_next->pf_add( p_stream->p_next, &p_bridge->pp_es[i]->fmt ); if ( p_bridge->pp_es[i]->id == NULL ) { msg_Warn( p_stream, "couldn't create chain for id %d", p_bridge->pp_es[i]->fmt.i_id ); } } msg_Dbg( p_stream, "bridging in input codec=%4.4s id=%d pos=%d", (char*)&p_bridge->pp_es[i]->fmt.i_codec, p_bridge->pp_es[i]->fmt.i_id, i ); } } p_bridge->pp_es[i]->b_changed = false; if ( p_bridge->pp_es[i]->b_empty ) continue; if ( p_bridge->pp_es[i]->p_block == NULL ) { if ( p_bridge->pp_es[i]->id != NULL && p_bridge->pp_es[i]->i_last < i_date ) { if( !p_sys->b_placeholder ) p_stream->p_next->pf_del( p_stream->p_next, p_bridge->pp_es[i]->id ); p_bridge->pp_es[i]->fmt.i_id -= p_sys->i_id_offset; p_bridge->pp_es[i]->b_changed = true; p_bridge->pp_es[i]->id = NULL; } continue; } if ( p_bridge->pp_es[i]->id != NULL || p_sys->b_placeholder) { block_t *p_block = p_bridge->pp_es[i]->p_block; while ( p_block != NULL ) { p_bridge->pp_es[i]->i_last = p_block->i_dts; p_block->i_pts += p_sys->i_delay; p_block->i_dts += p_sys->i_delay; p_block = p_block->p_next; } sout_stream_id_t *newid = NULL; if( p_sys->b_placeholder ) { switch( p_bridge->pp_es[i]->fmt.i_cat ) { case VIDEO_ES: p_sys->i_last_video = i_date; newid = p_sys->id_video; if( !newid ) break; if( !p_sys->b_switch_on_iframe || p_sys->i_state == placeholder_off || ( p_bridge->pp_es[i]->fmt.i_cat == VIDEO_ES && p_bridge->pp_es[i]->p_block->i_flags & BLOCK_FLAG_TYPE_I ) ) { p_stream->p_next->pf_send( p_stream->p_next, newid, p_bridge->pp_es[i]->p_block ); p_sys->i_state = placeholder_off; } break; case AUDIO_ES: newid = p_sys->id_audio; if( !newid ) break; p_sys->i_last_audio = i_date; default: p_stream->p_next->pf_send( p_stream->p_next, newid?newid:p_bridge->pp_es[i]->id, p_bridge->pp_es[i]->p_block ); break; } } else /* !b_placeholder */ p_stream->p_next->pf_send( p_stream->p_next, p_bridge->pp_es[i]->id, p_bridge->pp_es[i]->p_block ); } else { block_ChainRelease( p_bridge->pp_es[i]->p_block ); } p_bridge->pp_es[i]->p_block = NULL; p_bridge->pp_es[i]->pp_last = &p_bridge->pp_es[i]->p_block; } if( b_no_es ) { for ( i = 0; i < p_bridge->i_es_num; i++ ) free( p_bridge->pp_es[i] ); free( p_bridge->pp_es ); free( p_bridge ); var_Destroy( p_stream->p_libvlc, p_sys->psz_name ); } } if( p_sys->b_placeholder ) { switch( id->i_cat ) { case VIDEO_ES: if( ( p_sys->i_last_video + p_sys->i_placeholder_delay < i_date && ( !p_sys->b_switch_on_iframe || p_buffer->i_flags & BLOCK_FLAG_TYPE_I ) ) || p_sys->i_state == placeholder_on ) { p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); p_sys->i_state = placeholder_on; } else block_Release( p_buffer ); break; case AUDIO_ES: if( p_sys->i_last_audio + p_sys->i_placeholder_delay < i_date ) p_stream->p_next->pf_send( p_stream->p_next, id->id, p_buffer ); else block_Release( p_buffer ); break; default: block_Release( p_buffer ); /* FIXME: placeholder subs anyone? */ break; } } vlc_mutex_unlock( &lock ); return VLC_SUCCESS; }