// This will reenable routing if previous cleared. // Should not be needed otherwise since FromSource changes will automatically update. public void UpdateRouting() { // never started before? if (_routingInstancePtr == IntPtr.Zero) { CreateRouting(); return; } // Sanity if (_selectedSource == null || String.IsNullOrEmpty(_selectedSource.Name)) { Clear(); return; } // a source_t to describe the source to connect to. NDIlib.source_t source_t = new NDIlib.source_t() { p_ndi_name = UTF.StringToUtf8(_selectedSource.Name) }; if (!NDIlib.routing_change(_routingInstancePtr, ref source_t)) { // free the memory we allocated with StringToUtf8 Marshal.FreeHGlobal(source_t.p_ndi_name); throw new InvalidOperationException("Failed to change routing."); } // free the memory we allocated with StringToUtf8 Marshal.FreeHGlobal(source_t.p_ndi_name); }
private void CreateRouting() { if (_routingInstancePtr != IntPtr.Zero) { NDIlib.routing_destroy(_routingInstancePtr); _routingInstancePtr = IntPtr.Zero; } // Sanity check if (_selectedSource == null || String.IsNullOrEmpty(_selectedSource.Name)) { return; } // .Net interop doesn't handle UTF-8 strings, so do it manually // These must be freed later IntPtr sourceNamePtr = UTF.StringToUtf8(_routingName); IntPtr groupsNamePtr = IntPtr.Zero; // make a flat list of groups if needed if (_groups != null) { StringBuilder flatGroups = new StringBuilder(); foreach (String group in _groups) { flatGroups.Append(group); if (group != _groups.Last()) { flatGroups.Append(','); } } groupsNamePtr = UTF.StringToUtf8(flatGroups.ToString()); } // Create an NDI routing description NDIlib.routing_create_t createDesc = new NDIlib.routing_create_t() { p_ndi_name = sourceNamePtr, p_groups = groupsNamePtr }; // create the NDI routing instance _routingInstancePtr = NDIlib.routing_create(ref createDesc); // free the strings we allocated Marshal.FreeHGlobal(sourceNamePtr); Marshal.FreeHGlobal(groupsNamePtr); // did it succeed? if (_routingInstancePtr == IntPtr.Zero) { throw new InvalidOperationException("Failed to create routing instance."); } // update in case we have enough info to start routing UpdateRouting(); }
// connect to an NDI source in our Dictionary by name public void Connect(NDIlib.recv_color_format_e colorFormat) { // just in case we're already connected Disconnect(); // a source_t to describe the source to connect to. NDIlib.source_t source_t = new NDIlib.source_t() { p_ndi_name = UTF.StringToUtf8(_sourceName) }; // make a description of the receiver we want NDIlib.recv_create_v3_t recvDescription = new NDIlib.recv_create_v3_t() { // the source we selected source_to_connect_to = source_t, // we want BGRA frames for this example color_format = colorFormat, // we want full quality - for small previews or limited bandwidth, choose lowest bandwidth = _videoEnabled ? NDIlib.recv_bandwidth_e.recv_bandwidth_highest : NDIlib.recv_bandwidth_e.recv_bandwidth_audio_only, // let NDIlib deinterlace for us if needed allow_video_fields = false, // The name of the NDI receiver to create. This is a NULL terminated UTF8 string and should be // the name of receive channel that you have. This is in many ways symettric with the name of // senders, so this might be "Channel 1" on your system. p_ndi_recv_name = UTF.StringToUtf8(_receiverName) }; // create a new instance connected to this source _recvInstancePtr = NDIlib.recv_create_v3(ref recvDescription); // free the memory we allocated with StringToUtf8 Marshal.FreeHGlobal(source_t.p_ndi_name); Marshal.FreeHGlobal(recvDescription.p_ndi_recv_name); // did it work? System.Diagnostics.Debug.Assert(_recvInstancePtr != IntPtr.Zero, "Failed to create NDI receive instance."); if (_recvInstancePtr != IntPtr.Zero) { // We are now going to mark this source as being on program output for tally purposes (but not on preview) SetTallyIndicators(true, false); // start up a thread to receive on _receiveThread = new Thread(ReceiveThreadProc) { IsBackground = true, Name = "NdiExampleReceiveThread" }; _receiveThread.Start(); } }
private void FindThreadProc() { // the size of an NDIlib.source_t, for pointer offsets int SourceSizeInBytes = Marshal.SizeOf(typeof(NDIlib.source_t)); while (!_exitThread) { // Wait up to 500ms sources to change if (NDIlib.find_wait_for_sources(_findInstancePtr, 500)) { uint NumSources = 0; IntPtr SourcesPtr = NDIlib.find_get_current_sources(_findInstancePtr, ref NumSources); // convert each unmanaged ptr into a managed NDIlib.source_t for (int i = 0; i < NumSources; i++) { // source ptr + (index * size of a source) IntPtr p = IntPtr.Add(SourcesPtr, (i * SourceSizeInBytes)); // marshal it to a managed source and assign to our list NDIlib.source_t src = (NDIlib.source_t)Marshal.PtrToStructure(p, typeof(NDIlib.source_t)); // .Net doesn't handle marshaling UTF-8 strings properly String name = UTF.Utf8ToString(src.p_ndi_name); // Add it to the list if not already in the list. // We don't have to remove because NDI applications remember any sources seen during each run. // They might be selected and come back when the connection is restored. if (!_sourceList.Any(item => item.Name == name)) { _sourceList.Add(new Source(src)); } } } } }
// Construct from NDIlib.source_t public Source(NDIlib.source_t source_t) { Name = UTF.Utf8ToString(source_t.p_ndi_name); }
public Finder(bool showLocalSources = false, String[] groups = null, String[] extraIps = null) { if (!NDIlib.initialize()) { if (!NDIlib.is_supported_CPU()) { throw new InvalidOperationException("CPU incompatible with NDI."); } else { throw new InvalidOperationException("Unable to initialize NDI."); } } BindingOperations.EnableCollectionSynchronization(_sourceList, _sourceLock); IntPtr groupsNamePtr = IntPtr.Zero; // make a flat list of groups if needed if (groups != null) { StringBuilder flatGroups = new StringBuilder(); foreach (String group in groups) { flatGroups.Append(group); if (group != groups.Last()) { flatGroups.Append(','); } } groupsNamePtr = UTF.StringToUtf8(flatGroups.ToString()); } // This is also optional. // The list of additional IP addresses that exist that we should query for // sources on. For instance, if you want to find the sources on a remote machine // that is not on your local sub-net then you can put a comma seperated list of // those IP addresses here and those sources will be available locally even though // they are not mDNS discoverable. An example might be "12.0.0.8,13.0.12.8". // When none is specified (IntPtr.Zero) the registry is used. // Create a UTF-8 buffer from our string // Must use Marshal.FreeHGlobal() after use! // IntPtr extraIpsPtr = NDI.Common.StringToUtf8("12.0.0.8,13.0.12.8") IntPtr extraIpsPtr = IntPtr.Zero; // make a flat list of ip addresses as comma separated strings if (extraIps != null) { StringBuilder flatIps = new StringBuilder(); foreach (String ipStr in extraIps) { flatIps.Append(ipStr); if (ipStr != groups.Last()) { flatIps.Append(','); } } extraIpsPtr = UTF.StringToUtf8(flatIps.ToString()); } // how we want our find to operate NDIlib.find_create_t findDesc = new NDIlib.find_create_t() { p_groups = groupsNamePtr, show_local_sources = showLocalSources, p_extra_ips = extraIpsPtr }; // create our find instance _findInstancePtr = NDIlib.find_create_v2(ref findDesc); // free our UTF-8 buffer if we created one if (groupsNamePtr != IntPtr.Zero) { Marshal.FreeHGlobal(groupsNamePtr); } if (extraIpsPtr != IntPtr.Zero) { Marshal.FreeHGlobal(extraIpsPtr); } // start up a thread to update on _findThread = new Thread(FindThreadProc) { IsBackground = true, Name = "NdiFindThread" }; _findThread.Start(); }
public Sender(String sourceName, bool clockVideo = true, bool clockAudio = false, String[] groups = null, String failoverName = null) { if (String.IsNullOrEmpty(sourceName)) { throw new ArgumentException("sourceName can not be null or empty.", sourceName); } if (!NDIlib.initialize()) { if (!NDIlib.is_supported_CPU()) { throw new InvalidOperationException("CPU incompatible with NDI."); } else { throw new InvalidOperationException("Unable to initialize NDI."); } } // .Net interop doesn't handle UTF-8 strings, so do it manually // These must be freed later IntPtr sourceNamePtr = UTF.StringToUtf8(sourceName); IntPtr groupsNamePtr = IntPtr.Zero; // make a flat list of groups if needed if (groups != null) { StringBuilder flatGroups = new StringBuilder(); foreach (String group in groups) { flatGroups.Append(group); if (group != groups.Last()) { flatGroups.Append(','); } } groupsNamePtr = UTF.StringToUtf8(flatGroups.ToString()); } // Create an NDI source description NDIlib.send_create_t createDesc = new NDIlib.send_create_t() { p_ndi_name = sourceNamePtr, p_groups = groupsNamePtr, clock_video = clockVideo, clock_audio = clockAudio }; // create the NDI send instance _sendInstancePtr = NDIlib.send_create(ref createDesc); // free the strings we allocated Marshal.FreeHGlobal(sourceNamePtr); Marshal.FreeHGlobal(groupsNamePtr); // did it succeed? if (_sendInstancePtr == IntPtr.Zero) { throw new InvalidOperationException("Failed to create send instance."); } if (!String.IsNullOrEmpty(failoverName)) { // .Net interop doesn't handle UTF-8 strings, so do it manually // These must be freed later IntPtr failoverNamePtr = UTF.StringToUtf8(failoverName); NDIlib.source_t failoverDesc = new NDIlib.source_t() { p_ndi_name = failoverNamePtr, p_url_address = IntPtr.Zero }; NDIlib.send_set_failover(_sendInstancePtr, ref failoverDesc); // free the strings we allocated Marshal.FreeHGlobal(failoverNamePtr); } }
// Construct from NDIlib.source_t public Source(NDIlib.source_t source_t) { Name = UTF.Utf8ToString(source_t.p_ndi_name); _ipAddress = UTF.Utf8ToString(source_t.p_ip_address); }
private void FindThreadProc() { // the size of an NDIlib.source_t, for pointer offsets int SourceSizeInBytes = Marshal.SizeOf(typeof(NDIlib.source_t)); while (!_exitThread) { // Wait up to 500ms sources to change if (NDIlib.find_wait_for_sources(_findInstancePtr, 500)) { uint NumSources = 0; IntPtr SourcesPtr = NDIlib.find_get_current_sources(_findInstancePtr, ref NumSources); // ここでソースリストを初期化しておく //_sourceList.Clear(); // convert each unmanaged ptr into a managed NDIlib.source_t for (int i = 0; i < NumSources; i++) { // source ptr + (index * size of a source) IntPtr p = IntPtr.Add(SourcesPtr, (i * SourceSizeInBytes)); // marshal it to a managed source and assign to our list NDIlib.source_t src = (NDIlib.source_t)Marshal.PtrToStructure(p, typeof(NDIlib.source_t)); // .Net doesn't handle marshaling UTF-8 strings properly String name = UTF.Utf8ToString(src.p_ndi_name); // Add it to the list if not already in the list. // We don't have to remove because NDI applications remember any sources seen during each run. // They might be selected and come back when the connection is restored. if (!_sourceList.Any(item => item.Name == name)) { // VLCが入っていなければ追加しない if (name.Contains("VLC") == true) { _sourceList.Add(new Source(src)); } } } // ソースリストから要らないソースを除いておく //foreach (var item in _sourceList) //{ // bool exclusion_flag = true; // for (int i = 0; i < NumSources; i++) // { // IntPtr p = IntPtr.Add(SourcesPtr, (i * SourceSizeInBytes)); // NDIlib.source_t src = (NDIlib.source_t)Marshal.PtrToStructure(p, typeof(NDIlib.source_t)); // String name = UTF.Utf8ToString(src.p_ndi_name); // if (item.Name == name) // { // exclusion_flag = false; // break; // } // } // if (exclusion_flag == true) // { // _sourceList.Remove(item); // break; // } //} } } }