[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