[vlc-devel] [PATCH] rtp: implement raw video packetization (RFC 4175)
Rémi Denis-Courmont
remi at remlab.net
Tue Jan 27 23:32:45 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;
> +
This is needlessly complicated. Just make the seq 32-bits.
> /* 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
> )
This won't work where visible dimensions are smaller.
> + {
> + 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++;
> + }
> + }
> + 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