/** Remove this drawable from the list of busy ones */ static void ReleaseDrawable (vlc_object_t *obj, xcb_window_t window) { xcb_window_t *used; size_t n = 0; vlc_mutex_lock (&serializer); used = var_GetAddress (obj->p_libvlc, "xid-in-use"); assert (used); while (used[n] != window) { assert (used[n]); n++; } do used[n] = used[n + 1]; while (used[++n]); if (n == 0) var_SetAddress (obj->p_libvlc, "xid-in-use", NULL); vlc_mutex_unlock (&serializer); if (n == 0) free (used); /* Variables are reference-counted... */ var_Destroy (obj->p_libvlc, "xid-in-use"); }
static struct decklink_sys_t *GetDLSys(vlc_object_t *obj) { vlc_object_t *libvlc = VLC_OBJECT(obj->p_libvlc); struct decklink_sys_t *sys; vlc_mutex_lock(&sys_lock); if (var_Type(libvlc, "decklink-sys") == VLC_VAR_ADDRESS) sys = (struct decklink_sys_t*)var_GetAddress(libvlc, "decklink-sys"); else { sys = (struct decklink_sys_t*)malloc(sizeof(*sys)); if (sys) { sys->p_output = NULL; sys->offset = 0; sys->users = 0; sys->i_rate = -1; vlc_mutex_init(&sys->lock); vlc_cond_init(&sys->cond); var_Create(libvlc, "decklink-sys", VLC_VAR_ADDRESS); var_SetAddress(libvlc, "decklink-sys", (void*)sys); } } vlc_mutex_unlock(&sys_lock); return sys; }
static void ReleaseDLSys(vlc_object_t *obj) { vlc_object_t *libvlc = VLC_OBJECT(obj->p_libvlc); vlc_mutex_lock(&sys_lock); struct decklink_sys_t *sys = (struct decklink_sys_t*)var_GetAddress(libvlc, "decklink-sys"); if (--sys->users == 0) { msg_Dbg(obj, "Destroying decklink data"); vlc_mutex_destroy(&sys->lock); vlc_cond_destroy(&sys->cond); if (sys->p_output) { sys->p_output->StopScheduledPlayback(0, NULL, 0); sys->p_output->DisableVideoOutput(); sys->p_output->DisableAudioOutput(); sys->p_output->Release(); } free(sys); var_Destroy(libvlc, "decklink-sys"); } vlc_mutex_unlock(&sys_lock); }
/** * Release the drawable. */ static void Close (vlc_object_t *obj) { vout_window_t *wnd = (vout_window_t *)obj; void **used, *val = wnd->p_sys; size_t n = 0; /* Remove this drawable from the list of busy ones */ vlc_mutex_lock (&serializer); used = var_GetAddress (VLC_OBJECT (obj->p_libvlc), "drawables-in-use"); assert (used); while (used[n] != val) { assert (used[n]); n++; } do used[n] = used[n + 1]; while (used[++n] != NULL); if (n == 0) /* should not be needed (var_Destroy...) but better safe than sorry: */ var_SetAddress (obj->p_libvlc, "drawables-in-use", NULL); vlc_mutex_unlock (&serializer); if (n == 0) free (used); /* Variables are reference-counted... */ var_Destroy (obj->p_libvlc, "drawables-in-use"); }
/************************************************************************** * get_nsobject **************************************************************************/ void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi ) { assert (p_mi != NULL); #ifdef __APPLE__ return var_GetAddress (p_mi, "drawable-nsobject"); #else return NULL; #endif }
/************************************************************************** * get_hwnd **************************************************************************/ void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi ) { assert (p_mi != NULL); #ifdef WIN32 return var_GetAddress (p_mi, "drawable-hwnd"); #else return NULL; #endif }
/** * This function will free the snapshot addr */ static void VoutSnapshotAddrFree( vout_thread_t *p_vout ) { block_t *p_image = NULL; p_image = (block_t *) var_GetAddress( p_vout, "snapshot-addr" ); if( p_image != NULL ) block_Release( p_image ); }
/** * Destroy playlist. * This is not thread-safe. Any reference to the playlist is assumed gone. * (In particular, all interface and services threads must have been joined). * * \param p_playlist the playlist object */ void playlist_Destroy( playlist_t *p_playlist ) { playlist_private_t *p_sys = pl_priv(p_playlist); /* Remove all services discovery */ playlist_ServicesDiscoveryKillAll( p_playlist ); msg_Dbg( p_playlist, "destroying" ); playlist_Deactivate( p_playlist ); if( p_sys->p_preparser ) playlist_preparser_Delete( p_sys->p_preparser ); /* Release input resources */ assert( p_sys->p_input == NULL ); input_resource_Release( p_sys->p_input_resource ); if( p_playlist->p_media_library != NULL ) playlist_MLDump( p_playlist ); PL_LOCK; /* Release the current node */ set_current_status_node( p_playlist, NULL ); /* Release the current item */ set_current_status_item( p_playlist, NULL ); PL_UNLOCK; vlc_cond_destroy( &p_sys->signal ); vlc_mutex_destroy( &p_sys->lock ); /* Remove all remaining items */ FOREACH_ARRAY( playlist_item_t *p_del, p_playlist->all_items ) free( p_del->pp_children ); vlc_gc_decref( p_del->p_input ); free( p_del ); FOREACH_END(); ARRAY_RESET( p_playlist->all_items ); FOREACH_ARRAY( playlist_item_t *p_del, p_sys->items_to_delete ) free( p_del->pp_children ); vlc_gc_decref( p_del->p_input ); free( p_del ); FOREACH_END(); ARRAY_RESET( p_sys->items_to_delete ); ARRAY_RESET( p_playlist->items ); ARRAY_RESET( p_playlist->current ); vlc_http_cookie_jar_t *cookies = var_GetAddress( p_playlist, "http-cookies" ); if ( cookies ) { var_Destroy( p_playlist, "http-cookies" ); vlc_http_cookies_destroy( cookies ); } vlc_object_release( p_playlist ); }
static osd_menu_t *osd_Find( vlc_object_t *p_this, bool visible, const char *func ) { osd_menu_t *menu; vlc_mutex_lock( &osd_mutex ); menu = var_GetAddress( p_this->p_libvlc, "osd-object" ); if( menu == NULL || ( visible && !osd_isVisible(menu) ) ) { vlc_mutex_unlock( &osd_mutex ); msg_Err( p_this, "%s failed", func ); } return menu; }
static aout_instance_t *findAout (vlc_object_t *obj) { input_thread_t *(*pf_find_input) (vlc_object_t *); pf_find_input = var_GetAddress (obj, "find-input-callback"); if (unlikely(pf_find_input == NULL)) return NULL; input_thread_t *p_input = pf_find_input (obj); if (p_input == NULL) return NULL; aout_instance_t *p_aout = input_GetAout (p_input); vlc_object_release (p_input); return p_aout; }
/** Acquire a drawable */ static int AcquireDrawable (vlc_object_t *obj, xcb_window_t window) { xcb_window_t *used; size_t n = 0; if (var_Create (obj->p_libvlc, "xid-in-use", VLC_VAR_ADDRESS)) return VLC_ENOMEM; /* Keep a list of busy drawables, so we don't overlap videos if there are * more than one video track in the stream. */ vlc_mutex_lock (&serializer); used = var_GetAddress (obj->p_libvlc, "xid-in-use"); if (used != NULL) { while (used[n]) { if (used[n] == window) goto skip; n++; } } used = realloc (used, sizeof (*used) * (n + 2)); if (used != NULL) { used[n] = window; used[n + 1] = 0; var_SetAddress (obj->p_libvlc, "xid-in-use", used); } else { skip: msg_Warn (obj, "X11 drawable 0x%08"PRIx8" is busy", window); window = 0; } vlc_mutex_unlock (&serializer); return (window == 0) ? VLC_EGENERIC : VLC_SUCCESS; }
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( p_sys->p_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( p_sys->p_lock ); return VLC_SUCCESS; }
static sout_stream_id_t * AddOut( sout_stream_t *p_stream, es_format_t *p_fmt ) { out_sout_stream_sys_t *p_sys = (out_sout_stream_sys_t *)p_stream->p_sys; bridge_t *p_bridge; bridged_es_t *p_es; int i; if ( p_sys->b_inited ) { msg_Err( p_stream, "bridge-out can only handle 1 es at a time." ); return NULL; } p_sys->b_inited = true; vlc_mutex_lock( p_sys->p_lock ); p_bridge = var_GetAddress( p_stream->p_libvlc, p_sys->psz_name ); if ( p_bridge == NULL ) { p_bridge = xmalloc( sizeof( bridge_t ) ); var_Create( p_stream->p_libvlc, p_sys->psz_name, VLC_VAR_ADDRESS ); var_SetAddress( p_stream->p_libvlc, p_sys->psz_name, p_bridge ); p_bridge->i_es_num = 0; p_bridge->pp_es = NULL; } for ( i = 0; i < p_bridge->i_es_num; i++ ) { if ( p_bridge->pp_es[i]->b_empty && !p_bridge->pp_es[i]->b_changed ) break; } if ( i == p_bridge->i_es_num ) { p_bridge->pp_es = xrealloc( p_bridge->pp_es, (p_bridge->i_es_num + 1) * sizeof(bridged_es_t *) ); p_bridge->i_es_num++; p_bridge->pp_es[i] = xmalloc( sizeof(bridged_es_t) ); } p_sys->p_es = p_es = p_bridge->pp_es[i]; p_es->fmt = *p_fmt; p_es->fmt.i_id = p_sys->i_id; p_es->p_block = NULL; p_es->pp_last = &p_es->p_block; p_es->b_empty = false; p_es->id = NULL; p_es->i_last = VLC_TS_INVALID; p_es->b_changed = true; msg_Dbg( p_stream, "bridging out input codec=%4.4s id=%d pos=%d", (char*)&p_es->fmt.i_codec, p_es->fmt.i_id, i ); vlc_mutex_unlock( p_sys->p_lock ); return (sout_stream_id_t *)p_sys; }
/** * Find the drawable set by libvlc application. */ static int Open (vlc_object_t *obj, const char *varname, bool ptr) { vout_window_t *wnd = (vout_window_t *)obj; void **used, *val; size_t n = 0; if (var_Create (obj->p_libvlc, "drawables-in-use", VLC_VAR_ADDRESS) || var_Create (obj, varname, VLC_VAR_DOINHERIT | (ptr ? VLC_VAR_ADDRESS : VLC_VAR_INTEGER))) return VLC_ENOMEM; if (ptr) val = var_GetAddress (obj, varname); else val = (void *)(uintptr_t)var_GetInteger (obj, varname); var_Destroy (obj, varname); /* Keep a list of busy drawables, so we don't overlap videos if there are * more than one video track in the stream. */ vlc_mutex_lock (&serializer); /* TODO: per-type list of busy drawables */ used = var_GetAddress (VLC_OBJECT (obj->p_libvlc), "drawables-in-use"); if (used != NULL) { while (used[n] != NULL) { if (used[n] == val) goto skip; n++; } } used = realloc (used, sizeof (*used) * (n + 2)); if (used != NULL) { used[n] = val; used[n + 1] = NULL; var_SetAddress (obj->p_libvlc, "drawables-in-use", used); } else { skip: msg_Warn (wnd, "drawable %p is busy", val); val = NULL; } vlc_mutex_unlock (&serializer); if (val == NULL) return VLC_EGENERIC; if (ptr) wnd->handle.hwnd = val; else wnd->handle.xid = (uintptr_t)val; /* FIXME: check that X server matches --x11-display (if specified) */ /* FIXME: get window size (in platform-dependent ways) */ wnd->control = Control; wnd->p_sys = val; return VLC_SUCCESS; }