0

In my project I need receive a video through UDP. Source have a IP 224.0.0.21, Sink have a IP 169.254.170.141. I receive video through a port 3956 (This is a valid information from Wireshark). I use SharpPcap for receive UDP traffic, but it have not methods for join to multicast. I try this code from MSDN, but it dont work.

        IPAddress multicastaddress = IPAddress.Parse("224.0.0.21");
        IPEndPoint remoteep = new IPEndPoint(IPAddress.Any, 3956);
        m_ClientTarget.JoinMulticastGroup(multicastaddress, localAddr);

In my PC I have some network adapters, but I use the IP address from device, that connected to source video. Source and sink connected directly. When I start monitor traffic in the wireshark my programm also receive packet, but without the wireshack it cant do it. My code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SharpPcap;
using SharpPcap.LibPcap;
using SharpPcap.AirPcap;
using SharpPcap.WinPcap;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Threading;

namespace GVSPCapture
{
    public partial class Form1 : Form
    {

        static int frameCounter = 0;
        static byte[] pixels = new byte[1920 * 1080 * 3];
        static IPAddress fpgaAddr = IPAddress.Parse("224.0.0.21");
        static IPAddress localAddr = IPAddress.Parse("169.254.170.141");
        static MulticastOption mcastOption = new MulticastOption(fpgaAddr, localAddr);
        private static UdpClient m_ClientTarget = new UdpClient(3956);
        private static IPAddress m_GrpAddr;
        const int GroupPort = 3956;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            findDevices();
        }

        public void findDevices()
        {
            string ver = SharpPcap.Version.VersionString;

            var devices = CaptureDeviceList.Instance;

            foreach (var dev in devices)
            {
                lbxDevices.Items.Add(dev.Name + dev.Description);
            }

        }

        private void JoinVideoMulticast()
        {

            IPAddress multicastaddress = IPAddress.Parse("224.0.0.21");
            IPEndPoint remoteep = new IPEndPoint(IPAddress.Any, 3956);
            m_ClientTarget.JoinMulticastGroup(multicastaddress, IPAddress.Parse("169.254.170.141"));

            while (true)
            { }

        }

        private void startCapture(ICaptureDevice dev)
        {
            if (!dev.Started)
            {
                dev.OnPacketArrival += new PacketArrivalEventHandler(device_OnPacketArrival);
                int readTimeoutMilliseconds = 1000;
                if (dev is AirPcapDevice)
                {
                    // NOTE: AirPcap devices cannot disable local capture
                    var airPcap = dev as AirPcapDevice;
                    airPcap.Open(SharpPcap.WinPcap.OpenFlags.DataTransferUdp, readTimeoutMilliseconds);
                }
                else if (dev is WinPcapDevice)
                {
                    var winPcap = dev as WinPcapDevice;

                    winPcap.Open(SharpPcap.WinPcap.OpenFlags.DataTransferUdp | SharpPcap.WinPcap.OpenFlags.NoCaptureLocal, readTimeoutMilliseconds);
                }
                else if (dev is LibPcapLiveDevice)
                {
                    var livePcapDevice = dev as LibPcapLiveDevice;
                    livePcapDevice.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
                }
                else
                {
                    throw new System.InvalidOperationException("unknown device type of " + dev.GetType().ToString());
                }

                dev.StartCapture();

                Thread recvThread = new Thread(JoinVideoMulticast);
                recvThread.Start();

            }
        }

        delegate void SetTextCallback(string text);

        private void SetText(string text)
        {
            // InvokeRequired required compares the thread ID of the
            // calling thread to the thread ID of the creating thread.
            // If these threads are different, it returns true.
            if (this.tbxCnt.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.tbxCnt.Text = text;
            }
        }

        private void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            var time = e.Packet.Timeval.Date;
            var len = e.Packet.Data.Length;
            if (len == 572)
            {
                var tmp = e.Packet.Data;
                int packet_id = tmp[47] << 16 | tmp[48] << 8 | tmp[49];
                int startPos = (packet_id - 1) * 522;
                for (int i = 50; i < tmp.Length; i+=3)
                {
                    pixels[startPos + i + 0 - 50] = tmp[i];
                    pixels[startPos + i + 1 - 50] = tmp[i];
                    pixels[startPos + i + 2 - 50] = tmp[i];
                }
            }
            if (len == 60)
            {
                var im = CopyDataToBitmap(pixels);
                pictbFrame.Image = im;
                frameCounter += 1;
                SetText(frameCounter.ToString());
            }
        }

        public Bitmap CopyDataToBitmap(byte[] data)
        {
            GCHandle pinned = GCHandle.Alloc(data, GCHandleType.Pinned);
            IntPtr ptr = pinned.AddrOfPinnedObject();
            BitmapData dt = new BitmapData();
            dt.Scan0 = ptr;
            dt.Stride = 5760;
            dt.Width = 1920;
            dt.Height = 1080;
            dt.PixelFormat = PixelFormat.Format24bppRgb;
            Bitmap btm = new Bitmap(1920, 1080, 5760, PixelFormat.Format24bppRgb, dt.Scan0);
            return btm;
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            int devNum = lbxDevices.SelectedIndex;
            if (devNum > 0)
            {
                var device = CaptureDeviceList.Instance[devNum];
                startCapture(device);
            }
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            int devNum = lbxDevices.SelectedIndex;
            if (devNum > 0)
            {
                var device = CaptureDeviceList.Instance[devNum];
                if (device.Started)
                {
                    device.StopCapture();
                    device.Close();
                }
            }
            m_ClientTarget.DropMulticastGroup(fpgaAddr);
        }
    }
}
  • One problem is that is a multicast address that is reserved for router functions, and you should not be trying to join it on a PC in the first place. – Ron Maupin Aug 24 '17 at 18:12
  • @RonMaupin What is bad in joining a multicast address? – L.B Aug 24 '17 at 19:17
  • It is bad when the multicast group is reserved for a different purpose. That multicast group should never be used for video. There is a block of multicast addresses (`239.0.0.0-239.255.255.255` Organization-Local Scope) reserved for this type of thing. It is like trying to use IP addresses that belong to Google for your own purposes. IANA maintains the _[IPv4 Multicast Address Space Registry](https://www.iana.org/assignments/multicast-addresses/multicast-addresses.xhtml)_ in the same way that they maintain assignments of unicast addresses. – Ron Maupin Aug 24 '17 at 19:21
  • By the way, multicast addresses are destination addresses, not source addresses. – Ron Maupin Aug 24 '17 at 19:24
  • @RonMaupin **What is bad in joining a multicast address?** OP doesn't say he/she sends data to that address. Video source can be anything user has no control over it. – L.B Aug 24 '17 at 19:33
  • But, that multicast group is reserved for routers. PCs that are not routers have no business joining the multicast group. It sounds like the project is seriously flawed in that the multicast group address is being used as a source, not a destination. – Ron Maupin Aug 24 '17 at 19:37
  • `PCs that are not routers have no business joining the multicast group` Maybe this is exactly what I want to do. So I don't see any harm in joining any multicast group. The only problem is sending data to this group if it a reserved for another use (BTW: just for your info, I use multicasts for SSDP and SAP. So I am not new in this topic) – L.B Aug 24 '17 at 19:42
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/152803/discussion-between-ron-maupin-and-l-b). – Ron Maupin Aug 25 '17 at 00:33
  • Maybe its a bad adress, but I can receive video though this if I start monitor traffic with a Wireshark – Андрей Кущенко Aug 25 '17 at 19:52

2 Answers2

0

I tested the code with ffmpeg

ffmpeg.exe -i aa.mp4 -f mpeg udp://224.0.0.21:3956

int PORT = 3956;
string MULTICAST_IP = "224.0.0.21";


UdpClient udpClient = new UdpClient(PORT);
udpClient.JoinMulticastGroup(IPAddress.Parse(MULTICAST_IP));

var from = new IPEndPoint(0, 0);
var recvBuffer = udpClient.Receive(ref from);
L.B
  • 114,136
  • 19
  • 178
  • 224
0

Without seeing your code (I´m assuming that there´s more than the snippet you show) it´s difficult to help you. A basic setup for a client receiving multicast datagrams would be something like this untested snippet:

UdpClient mClient = new UdpClient(3956, AddressFamily.InterNetwork);
IPAdress groupAddress = IPAddress.Parse("224.0.0.21);
mClient.JoinMulticastGroup(groupAddress);

After that you the receiving using mClient.Receive()...

Maybe this helps? Or the documentation on MSDN (https://msdn.microsoft.com/en-us/library/ekd1t784(v=vs.110).aspx).

C.

C. Gonzalez
  • 689
  • 7
  • 8