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

Rémi Denis-Courmont remi at remlab.net
Wed Jan 28 16:50:37 CET 2015


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.

> +                }
> +            }
> +            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/




More information about the vlc-devel mailing list