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

Tristan Matthews tmatth at videolan.org
Sat Jan 31 18:46:34 CET 2015


Supports RGB24 and YCbCr 4:2:0, should be trivial to add other formats.
---
 modules/stream_out/rtp.c    |  14 +++-
 modules/stream_out/rtp.h    |   4 +
 modules/stream_out/rtpfmt.c | 178 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 195 insertions(+), 1 deletion(-)

diff --git a/modules/stream_out/rtp.c b/modules/stream_out/rtp.c
index 98c5fb4..24839a9 100644
--- a/modules/stream_out/rtp.c
+++ b/modules/stream_out/rtp.c
@@ -355,7 +355,8 @@ struct sout_stream_id_sys_t
 {
     sout_stream_t *p_stream;
     /* rtp field */
-    uint16_t    i_sequence;
+    /* For RFC 4175, seqnum is extended to 32-bits */
+    uint32_t    i_sequence;
     bool        b_first_packet;
     bool        b_ts_init;
     uint32_t    i_ts_offset;
@@ -1652,6 +1653,11 @@ void rtp_packetize_common( sout_stream_id_sys_t *id, block_t *out,
     id->i_sequence++;
 }
 
+uint16_t rtp_get_extended_sequence( sout_stream_id_sys_t *id )
+{
+    return id->i_sequence >> 16;
+}
+
 void rtp_packetize_send( sout_stream_id_sys_t *id, block_t *out )
 {
     block_FifoPut( id->p_fifo, out );
@@ -1797,3 +1803,9 @@ 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 )
+{
+    int ret = sscanf( id->rtp_fmt.fmtp, "%*s width=%d; height=%d; ", width, height );
+    assert( ret == 2 );
+}
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..1ac9e8d 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_r420 (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,32 @@ 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_R420:
+            rtp_fmt->ptname = "RAW";
+            rtp_fmt->pf_packetize = rtp_packetize_r420;
+            if( asprintf( &rtp_fmt->fmtp,
+                    "sampling=YCbCr-4:2:0; width=%d; height=%d; "
+                    "depth=8; colorimetry=BT%s",
+                    p_fmt->video.i_visible_width, p_fmt->video.i_visible_height,
+                    p_fmt->video.i_visible_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_visible_width,
+                    p_fmt->video.i_visible_height ) == -1 )
+            {
+                rtp_fmt->fmtp = NULL;
+                return VLC_ENOMEM;
+            }
+            break;
         case VLC_CODEC_MJPG:
         case VLC_CODEC_JPEG:
             rtp_fmt->ptname = "JPEG";
@@ -1502,6 +1532,154 @@ 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_R420:
+            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_R420 )
+            {
+                memcpy( p_outdata, p_data, i_length );
+                p_outdata += i_length;
+                p_data += i_length;
+            }
+            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_r420( sout_stream_id_sys_t *id, block_t *in )
+{
+    return rtp_packetize_rawvideo( id, in, VLC_CODEC_R420 );
+}
+
+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;
-- 
2.1.0




More information about the vlc-devel mailing list