vlc | branch: master | Tristan Matthews <[email protected]> | Sat Jan 31 16:46:34 2015 +0000| [42dcbd6a9bba300bfc8fb6ed353ad68c4678dec4] | committer: Tristan Matthews
rtp: implement raw video packetization (RFC 4175) Supports RGB24 and YCbCr 4:2:0, should be trivial to add other formats. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=42dcbd6a9bba300bfc8fb6ed353ad68c4678dec4 --- 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 <[email protected]> + * RFC 4175 support based on gstrtpvrawpay.c (LGPL 2) by: + * Wim Taymans <[email protected]> * * 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; _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
