0

Hi I wanted to proxy multicast video to unicast like udpxy does: http://www.udpxy.com, but in C# since I could not find any suitable RTP library that I could use (they were eather too complex or I could't understand how to use them), I decided to port over one that udpxy uses rtp.c: https://github.com/pcherenkov/udpxy/blob/master/chipmunk/rtp.c

everything went fine (almost, as I didn't want to use pointers), until I wanted to translate RTP_Process to C#

RTP_Process in C

RTP_process( void** pbuf, size_t* len, int verify, FILE* log )
{
    int rtp_padding = -1;
    size_t front_skip = 0, back_skip = 0, pad_len = 0;

    char* buf = NULL;
    size_t pkt_len = 0;

    assert( pbuf && len && log );
    buf = *pbuf;
    pkt_len = *len;

    if( verify && !RTP_verify( buf, pkt_len, log ) )
        return -1;

    if( 0 != RTP_hdrlen( buf, pkt_len, &front_skip, log ) )
        return -1;

    rtp_padding = buf[0] & 0x20;
    if( rtp_padding ) {
        pad_len = buf[ pkt_len - 1 ];
    }

    back_skip += pad_len;

    if( verify && (pkt_len < (front_skip + back_skip)) ) {
        (void) tmfprintf( log, "RTP_process: invalid header "
                "(skip [%lu] exceeds packet length [%lu])\n",
                (u_long)(front_skip + back_skip), (u_long)pkt_len );
        return -1;
    }

    /* adjust buffer/length to skip heading and padding */
    /*
    TRACE( (void)tmfprintf( log, "In: RTP buf=[%p] of [%lu] bytes, "
                "fskip=[%ld], bskip=[%lu]\n",
                (void*)buf, (u_long)pkt_len,
                (u_long)front_skip, (u_long)back_skip ) );
    */

    buf += front_skip;
    pkt_len -= (front_skip + back_skip);

    /*
    TRACE( (void)tmfprintf( log, "Out RTP buf=[%p] of [%lu] bytes\n",
                (void*)buf, (u_long)pkt_len ) );
    */
    *pbuf = buf;
    *len  = pkt_len;

    return 0;
}

RTP_Process in C#

public byte[] RTP_process(int verify)
{
    /* process RTP package to retrieve the payload: set
    * pbuf to the start of the payload area; set len to
    * be equal payload's length
    *
    * @param pbuf      address of pointer to beginning of RTP packet
    * @param len       pointer to RTP packet's length
    * @param verify    verify that it is an RTP packet if != 0
    * @param log       log file
    *
    * @return 0 if there was no error, -1 otherwise;
    *         set pbuf to point to beginning of payload and len
    *         be payload size in bytes
    */
    int rtp_padding = -1;
    int front_skip = 0, back_skip = 0, pad_len = 0;

    int pkt_len = 0;

    //assert(pbuf && len && log);
    //buf = *pbuf;
    pbuf = buf;
    //pkt_len = *len;
    len = pkt_len;

    /*
    if (verify != 1 && RTP_verify() != 1)
        RTPOK = - 1;

    if (0 != RTP_hdrlen(buf, pkt_len, front_skip)) //?????
        RTPOK = - 1;

    */

    rtp_padding = buf[0] & 0x20;
    if (rtp_padding != -1) //???????
    {
        pad_len = buf[pkt_len - 1];
    }

    back_skip += pad_len;

    if ((verify != -1) && (pkt_len < (front_skip + back_skip))) //???????
    {
        Console.WriteLine("RTP_process: invalid header (skip {0} exceeds packet length {1})\n", (long)(front_skip + back_skip), (long)pkt_len);
        RTPOK = - 1;
    }

    /* adjust buffer/length to skip heading and padding */
    /*
    TRACE( (void)tmfprintf( log, "In: RTP buf=[%p] of [%lu] bytes, "
                "fskip=[%ld], bskip=[%lu]\n",
                (void*)buf, (u_long)pkt_len,
                (u_long)front_skip, (u_long)back_skip ) );
    */

    //buf += front_skip;
    //pkt_len -= (front_skip + back_skip);

    /*
    TRACE( (void)tmfprintf( log, "Out RTP buf=[%p] of [%lu] bytes\n",
                (void*)buf, (u_long)pkt_len ) );
    */
    pbuf = buf;
    len = pkt_len;

    RTPOK = 0;
    return pbuf;
}

here the problems started 1. buf += front_skip; complained that operator += cannot be applied to operands of type byte[] and int then why did it work in RTP_Process in C and what is a C# equivalent of that 2. in

if (rtp_padding != -1) //???????
{
    pad_len = buf[pkt_len - 1]; //There is an exeption trown: System.IndexOutOfRangeException: Index was outside the bounds of the array.

its clear that I interpreted and translated something the wrong way, but the onlything I would like to do is to get MPEG-TS frame out of RTP stream to then forward it to a TCP socket, so if anyone can suggest a better way of doing that I would love to hear it

Thanks for Anwsering and Best Regards }

1 Answers1

0

First, I suggest to read carefully RFC-3550, it has all information about RTP-packet structure (mostly you need Section #5: RTP Fixed Header and extensions).

  1. Then you have to implement RTP_hdrlen to calculate RTP header size, it must return front_skip value as RTP header size including extensions. So, you don't have to use buf += front_skip;, RTP payload starts from byte buf[front_skip].

  2. You have wrong packet length parameter here: int pkt_len = 0;, that's why the exception is thrown here pad_len = buf[pkt_len - 1];.

Community
  • 1
  • 1
Kozyr
  • 201
  • 1
  • 7
  • well I have rewritten RTP_Process and RTP_hrdlen: https://github.com/veso266/multicast2unicast/blob/master/multicast2unicast/RTP/rtp2time.cs but it still doesn't work, using this to test: https://github.com/Cinegy/TsDecoder is there a way to identify MPEG-TS frame by hand? – PersonaNonGrata Oct 20 '18 at 17:56
  • here is some sample data I am trying this with: https://github.com/veso266/multicast2unicast/blob/master/multicast2unicast/SLO%201%20(RTP2).cs – PersonaNonGrata Oct 20 '18 at 18:11
  • Despite RTP header extension length isn't always 4 bytes per extension (but it is true for the sample data), the code looks good: front_skip = 36, payload len = 1128, first payload byte is 0x47 (this is MPEG-TS sync character). I didn't work with mpeg-ts, some info about it here: https://en.wikipedia.org/wiki/MPEG_transport_stream#Packet – Kozyr Oct 20 '18 at 21:27
  • well it looks like I have a MPEG-TS frame in my ByteArray now as it starts with 0x47 or 71 in dec I just don't know why this: https://github.com/Cinegy/TsDecoder does not want to read it – PersonaNonGrata Oct 21 '18 at 09:43
  • no just a blank console :) I also tried to create TCP Server and just writing this array out to VLC CLient and it could not play the stream – PersonaNonGrata Oct 21 '18 at 15:16
  • I tried ts-packet-anlayser (https://github.com/daniep01/ts-packet-anlayser) and it doesn't parse the sample either. Perhaps, it is not the first packet of a stream or need more packets for decoding – Kozyr Oct 21 '18 at 16:53
  • I don't know I tried the same with live data, but its only blank console, not sure how can I save more data in a file from Multicast Group? – PersonaNonGrata Oct 21 '18 at 18:22
  • Check your stream with Wireshark. I set up MPEG-TS streaming using VLC player, captured it with Wireshark and able to see RTP structure, MPEG-TS blocks – Kozyr Oct 22 '18 at 05:45
  • well the onlything I can figure out is that maybe my data does not change here: https://github.com/veso266/multicast2unicast/blob/master/multicast2unicast/Program.cs is my function that captures it and feeds it into RTP_Process() – PersonaNonGrata Oct 22 '18 at 19:48