[vlc-devel] [PATCH] rtp: implement raw video packetization (RFC 4175)

Tristan Matthews le.businessman at gmail.com
Wed Jan 28 18:47:20 CET 2015


On Wed, Jan 28, 2015 at 10:50 AM, Rémi Denis-Courmont <remi at remlab.net>
wrote:

> Le mardi 27 janvier 2015, 16:49:31 Tristan Matthews a écrit :
> > Supports RGB24 and I420, should be trivial to add other formats.
> > ---
> >  modules/stream_out/rtp.c    |  19 +++++
> >  modules/stream_out/rtp.h    |   4 +
> >  modules/stream_out/rtpfmt.c | 196
> > ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 219
> > insertions(+)
> >
> > diff --git a/modules/stream_out/rtp.c b/modules/stream_out/rtp.c
> > index 98c5fb4..4762d47 100644
> > --- a/modules/stream_out/rtp.c
> > +++ b/modules/stream_out/rtp.c
> > @@ -361,6 +361,9 @@ struct sout_stream_id_sys_t
> >      uint32_t    i_ts_offset;
> >      uint8_t     ssrc[4];
> >
> > +    /* For RFC 4175, seqnum is extended to 32-bits */
> > +    uint16_t    i_extended_sequence;
> > +
> >      /* for rtsp */
> >      uint16_t    i_seq_sent_next;
> >
> > @@ -984,6 +987,7 @@ static sout_stream_id_sys_t *Add( sout_stream_t
> > *p_stream, es_format_t *p_fmt ) (int64_t)1000 * var_GetInteger( p_stream,
> > SOUT_CFG_PREFIX "caching");
> >
> >      vlc_rand_bytes (&id->i_sequence, sizeof (id->i_sequence));
> > +    vlc_rand_bytes (&id->i_extended_sequence, sizeof
> > (id->i_extended_sequence)); vlc_rand_bytes (id->ssrc, sizeof (id->ssrc));
> >
> >      bool format = false;
> > @@ -1002,6 +1006,7 @@ static sout_stream_id_sys_t *Add( sout_stream_t
> > *p_stream, es_format_t *p_fmt ) * initialized inside vod_init_id() to
> avoid
> > race
> >               * conditions. */
> >              id->i_sequence = id->i_seq_sent_next;
> > +            id->i_extended_sequence = 0;
> >          }
> >          /* vod_init_id() may fail either because the ES wasn't found in
> >           * the VoD media, or because the RTSP session is gone. In the
> > @@ -1045,6 +1050,7 @@ static sout_stream_id_sys_t *Add( sout_stream_t
> > *p_stream, es_format_t *p_fmt ) goto error;
> >          }
> >          id->i_sequence = 0; /* FIXME: awful hack for libvlc_srtp */
> > +        id->i_extended_sequence = 0;
> >      }
> >  #endif
> >
> > @@ -1650,6 +1656,14 @@ void rtp_packetize_common( sout_stream_id_sys_t
> *id,
> > block_t *out, memcpy( out->p_buffer + 8, id->ssrc, 4 );
> >
> >      id->i_sequence++;
> > +    /* Wrap-around to 0 just occured */
> > +    if (!id->i_sequence)
> > +        id->i_extended_sequence++;
> > +}
> > +
> > +uint16_t rtp_get_extended_sequence( sout_stream_id_sys_t *id )
> > +{
> > +    return id->i_extended_sequence;
> >  }
> >
> >  void rtp_packetize_send( sout_stream_id_sys_t *id, block_t *out )
> > @@ -1797,3 +1811,8 @@ static sout_access_out_t *GrabberCreate(
> sout_stream_t
> > *p_stream ) p_grab->pf_write    = AccessOutGrabberWrite;
> >      return p_grab;
> >  }
> > +
> > +void rtp_get_video_geometry( sout_stream_id_sys_t *id, int *width, int
> > *height ) +{
> > +    sscanf( id->rtp_fmt.fmtp, "%*s width=%d; height=%d; ", width,
> height );
> > +}
> > diff --git a/modules/stream_out/rtp.h b/modules/stream_out/rtp.h
> > index ff26c69..01d6b61 100644
> > --- a/modules/stream_out/rtp.h
> > +++ b/modules/stream_out/rtp.h
> > @@ -89,6 +89,10 @@ typedef struct rtp_format_t
> >  int rtp_get_fmt( vlc_object_t *obj, es_format_t *p_fmt, const char *mux,
> >                   rtp_format_t *p_rtp_fmt );
> >
> > +/* Only used by rtp_packetize_rawvideo */
> > +void rtp_get_video_geometry( sout_stream_id_sys_t *id, int *width, int
> > *height ); +uint16_t rtp_get_extended_sequence( sout_stream_id_sys_t *id
> );
> > +
> >  /* VoD */
> >  int  OpenVoD ( vlc_object_t * );
> >  void CloseVoD( vlc_object_t * );
> > diff --git a/modules/stream_out/rtpfmt.c b/modules/stream_out/rtpfmt.c
> > index d8c8621..1759c6a 100644
> > --- a/modules/stream_out/rtpfmt.c
> > +++ b/modules/stream_out/rtpfmt.c
> > @@ -6,6 +6,8 @@
> >   * $Id$
> >   *
> >   * Authors: Laurent Aimar <fenrir at via.ecp.fr>
> > + * RFC 4175 support based on gstrtpvrawpay.c (LGPL 2) by:
> > + * Wim Taymans <wim.taymans at gmail.com>
> >   *
> >   * This program is free software; you can redistribute it and/or modify
> it
> >   * under the terms of the GNU Lesser General Public License as
> published by
> > @@ -57,6 +59,8 @@ static int rtp_packetize_g726_40 (sout_stream_id_sys_t
> *,
> > block_t *); static int rtp_packetize_xiph (sout_stream_id_sys_t *,
> block_t
> > *); static int rtp_packetize_vp8 (sout_stream_id_sys_t *, block_t *);
> > static int rtp_packetize_jpeg (sout_stream_id_sys_t *, block_t *);
> +static
> > int rtp_packetize_i420 (sout_stream_id_sys_t *, block_t *); +static int
> > rtp_packetize_rgb24 (sout_stream_id_sys_t *, block_t *);
> >
> >  #define XIPH_IDENT (0)
> >
> > @@ -524,6 +528,31 @@ int rtp_get_fmt( vlc_object_t *obj, es_format_t
> *p_fmt,
> > const char *mux, rtp_fmt->ptname = "VP8";
> >              rtp_fmt->pf_packetize = rtp_packetize_vp8;
> >              break;
> > +        case VLC_CODEC_I420:
> > +            rtp_fmt->ptname = "RAW";
> > +            rtp_fmt->pf_packetize = rtp_packetize_i420;
> > +            if( asprintf( &rtp_fmt->fmtp,
> > +                    "sampling=YCbCr-4:2:0; width=%d; height=%d; "
> > +                    "depth=8; colorimetry=BT%s",
> > +                    p_fmt->video.i_width, p_fmt->video.i_height,
> > +                    p_fmt->video.i_height > 576 ? "709-2" : "601-5") ==
> -1
> > ) +            {
> > +                rtp_fmt->fmtp = NULL;
> > +                return VLC_ENOMEM;
> > +            }
> > +            break;
> > +        case VLC_CODEC_RGB24:
> > +            rtp_fmt->ptname = "RAW";
> > +            rtp_fmt->pf_packetize = rtp_packetize_rgb24;
> > +            if( asprintf( &rtp_fmt->fmtp,
> > +                    "sampling=RGB; width=%d; height=%d; "
> > +                    "depth=8; colorimetry=SMPTE240M",
> > +                    p_fmt->video.i_width, p_fmt->video.i_height) == -1 )
> > +            {
> > +                rtp_fmt->fmtp = NULL;
> > +                return VLC_ENOMEM;
> > +            }
> > +            break;
> >          case VLC_CODEC_MJPG:
> >          case VLC_CODEC_JPEG:
> >              rtp_fmt->ptname = "JPEG";
> > @@ -1502,6 +1531,173 @@ static int rtp_packetize_vp8(
> sout_stream_id_sys_t
> > *id, block_t *in ) return VLC_SUCCESS;
> >  }
> >
> > +
> > +/* See RFC 4175 */
> > +static int rtp_packetize_rawvideo( sout_stream_id_sys_t *id, block_t
> *in,
> > vlc_fourcc_t i_format  ) +{
> > +    int i_width, i_height;
> > +    rtp_get_video_geometry( id, &i_width, &i_height );
> > +    int i_pgroup; /* Size of a group of pixels */
> > +    int i_xdec, i_ydec; /* sub-sampling factor in x and y */
> > +    switch( i_format )
> > +    {
> > +        case VLC_CODEC_RGB24:
> > +            i_pgroup = 3;
> > +            i_xdec = i_ydec = 1;
> > +            break;
> > +        case VLC_CODEC_I420:
> > +            i_pgroup = 6;
> > +            i_xdec = i_ydec = 2;
> > +            break;
> > +        default:
> > +            assert(0);
> > +    }
> > +
> > +    static const int RTP_HEADER_LEN = 12;
> > +    /* each partial or complete line needs a 6 byte header */
> > +    const int i_line_header_size = 6;
> > +    const int i_min_line_size = i_line_header_size + i_pgroup;
> > +    uint8_t *p_data = in->p_buffer;
> > +
> > +    for( uint16_t i_line_number = 0, i_column = 0; i_line_number <
> > i_height; ) +    {
> > +        /* Allocate a packet */
> > +        int i_payload = (int)(rtp_mtu (id) - RTP_HEADER_LEN);
> > +        if( i_payload <= 0 )
> > +        {
> > +            block_Release( in );
> > +            return VLC_EGENERIC;
> > +        }
> > +
> > +        block_t *out = block_Alloc( RTP_HEADER_LEN + i_payload );
> > +        if( unlikely( out == NULL ) )
> > +        {
> > +            block_Release( in );
> > +            return VLC_ENOMEM;
> > +        }
> > +
> > +        /* Do headers first... */
> > +
> > +        /* Write extended seqnum */
> > +        uint8_t *p_outdata = out->p_buffer + RTP_HEADER_LEN;
> > +        SetWBE( p_outdata, rtp_get_extended_sequence( id ) );
> > +        p_outdata += 2;
> > +        i_payload -= 2;
> > +
> > +        uint8_t *p_headers = p_outdata;
> > +
> > +        for( uint8_t i_cont = 0x80; i_cont && i_payload >
> i_min_line_size;
> > ) +        {
> > +            i_payload -= i_line_header_size;
> > +
> > +            int i_pixels = i_width - i_column;
> > +            int i_length = (i_pixels * i_pgroup) / i_xdec;
> > +
> > +            const bool b_next_line = i_payload >= i_length;
> > +            if( !b_next_line )
> > +            {
> > +                i_pixels = (i_payload / i_pgroup) * i_xdec;
> > +                i_length = (i_pixels * i_pgroup) / i_xdec;
> > +            }
> > +
> > +            i_payload -= i_length;
> > +
> > +            /* write length */
> > +            SetWBE( p_outdata, i_length );
> > +            p_outdata += 2;
> > +
> > +            /* write line number */
> > +            /* TODO: support interlaced */
> > +            const uint8_t i_field = 0;
> > +            SetWBE( p_outdata, i_line_number );
> > +            *p_outdata |= i_field << 7;
> > +            p_outdata += 2;
> > +
> > +            /* continue if there's still room in the packet and we have
> > more lines */ +            i_cont = (i_payload > i_min_line_size &&
> > i_line_number < (i_height - i_ydec)) ? 0x80 : 0x00; +
> > +            /* write offset and continuation marker */
> > +            SetWBE( p_outdata, i_column );
> > +            *p_outdata |= i_cont;
> > +            p_outdata += 2;
> > +
> > +            if( b_next_line )
> > +            {
> > +                i_column = 0;
> > +                i_line_number += i_ydec;
> > +            }
> > +            else
> > +            {
> > +                i_column += i_pixels;
> > +            }
> > +        }
> > +
> > +        /* write the actual video data here */
> > +        for( uint8_t i_cont = 0x80; i_cont; p_headers +=
> i_line_header_size
> > ) +        {
> > +            const uint16_t i_length = GetWBE( p_headers );
> > +            const uint16_t i_lin = GetWBE( p_headers + 2 ) & 0x7fff;
> > +            uint16_t i_offs = GetWBE( p_headers + 4 ) & 0x7fff;
> > +            i_cont = p_headers[4] & 0x80;
> > +
> > +            if( i_format == VLC_CODEC_RGB24 )
> > +            {
> > +                const int i_ystride = i_width * i_pgroup;
> > +                i_offs /= i_xdec;
> > +                memcpy( p_outdata, p_data + (i_lin * i_ystride) +
> (i_offs *
> > i_pgroup), i_length ); +                p_outdata += i_length;
> > +            }
> > +            else if( i_format == VLC_CODEC_I420 )
> > +            {
> > +                const int i_ystride = i_width;
> > +                const uint8_t *p_u = p_data + i_width * i_height;
> > +                const uint8_t *p_v = p_u + (i_width * i_height) /
> (i_xdec *
> > i_ydec); +                const int i_uvstride = i_width / i_xdec;
> > +
> > +                const uint8_t *p_yd1 = p_data + (i_lin * i_ystride) +
> > i_offs; +                const uint8_t *p_yd2 = p_yd1 + i_ystride;
> > +                const unsigned i_uvoff = (i_lin / i_ydec * i_uvstride) +
> > (i_offs / i_xdec); +                const uint8_t *p_ud = p_u + i_uvoff;
> > +                const uint8_t *p_vd = p_v + i_uvoff;
> > +
> > +                unsigned i_pixels = i_length / i_pgroup;
> > +                while( i_pixels-- )
> > +                {
> > +                    *p_outdata++ = *p_yd1++;
> > +                    *p_outdata++ = *p_yd1++;
> > +                    *p_outdata++ = *p_yd2++;
> > +                    *p_outdata++ = *p_yd2++;
> > +                    *p_outdata++ = *p_ud++;
> > +                    *p_outdata++ = *p_vd++;
>
> This weird packing really is not I420... IMHO, there should be a separate
> FOURCC and an encoder to convert to it.
>

Hmm, I was planning to later add 4:4:4, 4:2:2 and 4:1:1 that according the
RFC, must also be packed in this "interleaved" manner. This would mean
adding a new fourcc+encoder for each of these as well?


>
> > +                }
> > +            }
> > +            else assert(0);
> > +        }
> > +
> > +        /* rtp common header */
> > +        rtp_packetize_common( id, out, i_line_number >= i_height,
> > +                (in->i_pts > VLC_TS_INVALID ? in->i_pts : in->i_dts) );
> > +
> > +        out->i_dts    = in->i_dts;
> > +        out->i_length = in->i_length;
> > +
> > +        rtp_packetize_send( id, out );
> > +    }
> > +
> > +    block_Release( in );
> > +    return VLC_SUCCESS;
> > +}
> > +
> > +static int rtp_packetize_i420( sout_stream_id_sys_t *id, block_t *in )
> > +{
> > +    return rtp_packetize_rawvideo( id, in, VLC_CODEC_I420 );
> > +}
> > +
> > +static int rtp_packetize_rgb24( sout_stream_id_sys_t *id, block_t *in )
> > +{
> > +    return rtp_packetize_rawvideo( id, in, VLC_CODEC_RGB24 );
> > +}
> > +
> >  static int rtp_packetize_jpeg( sout_stream_id_sys_t *id, block_t *in )
> >  {
> >      uint8_t *p_data = in->p_buffer;
>
> --
> Rémi Denis-Courmont
> http://www.remlab.net/
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20150128/4c5b0163/attachment.html>


More information about the vlc-devel mailing list