[vlc-devel] [PATCH] Enable JPEG RTP packetization
Andrey Utkin
andrey.krieger.utkin at gmail.com
Sun Dec 15 20:04:11 CET 2013
Oops, previous version had compilation problem.
---8<---
---
modules/stream_out/rtpfmt.c | 196 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 196 insertions(+)
diff --git a/modules/stream_out/rtpfmt.c b/modules/stream_out/rtpfmt.c
index f351832..7e53a67 100644
--- a/modules/stream_out/rtpfmt.c
+++ b/modules/stream_out/rtpfmt.c
@@ -54,6 +54,7 @@ static int rtp_packetize_g726_32 (sout_stream_id_t *, block_t *);
static int rtp_packetize_g726_40 (sout_stream_id_t *, block_t *);
static int rtp_packetize_xiph (sout_stream_id_t *, block_t *);
static int rtp_packetize_vp8 (sout_stream_id_t *, block_t *);
+static int rtp_packetize_jpeg (sout_stream_id_t *, block_t *);
#define XIPH_IDENT (0)
@@ -521,6 +522,12 @@ 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_MJPG:
+ case VLC_CODEC_JPEG:
+ rtp_fmt->ptname = "JPEG";
+ rtp_fmt->payload_type = 26;
+ rtp_fmt->pf_packetize = rtp_packetize_jpeg;
+ break;
default:
msg_Err( obj, "cannot add this stream (unsupported "
@@ -1426,3 +1433,192 @@ static int rtp_packetize_vp8( sout_stream_id_t *id, block_t *in )
return VLC_SUCCESS;
}
+
+static int rtp_packetize_jpeg( sout_stream_id_t *id, block_t *in )
+{
+ uint8_t *p_data = in->p_buffer;
+ int i_data = in->i_buffer;
+ uint8_t *bufend = p_data + i_data;
+
+ const uint8_t *qtables = NULL;
+ int nb_qtables = 0;
+ int off = 0; // fragment offset in frame
+ int y_sampling_factor;
+ // type is set by pixel format (determined by y_sampling_factor):
+ // 0 for yuvj422p
+ // 1 for yuvj420p
+ // += 64 if DRI present
+ int type;
+ int w = 0; // Width in multiples of 8
+ int h = 0; // Height in multiples of 8
+ int restart_interval;
+ int dri_found = 0;
+
+ // Skip SOI
+ if (GetWBE(p_data) != 0xffd8)
+ return VLC_EGENERIC;
+ p_data += 2;
+ i_data -= 2;
+
+ /* parse the header to get necessary info */
+ int header_finished = 0;
+ while (!header_finished && p_data + 4 <= bufend) {
+ uint16_t marker = GetWBE(p_data);
+ uint8_t *section = p_data + 2;
+ int section_size = GetWBE(section);
+ uint8_t *section_body = p_data + 4;
+ if (section + section_size > bufend)
+ return VLC_EGENERIC;
+
+ assert((marker & 0xff00) == 0xff00);
+ switch (marker)
+ {
+ case 0xffdb /*DQT*/:
+ if (section_body[0])
+ {
+ // Only 8-bit precision is supported
+ return VLC_EGENERIC;
+ }
+
+ /* a quantization table is 64 bytes long */
+ nb_qtables = section_size / 65;
+ qtables = section_body;
+ break;
+ case 0xffc0 /*SOF0*/:
+ {
+ int height = GetWBE(§ion_body[1]);
+ int width = GetWBE(§ion_body[3]);
+ if (width > 2040 || height > 2040)
+ {
+ // larger than limit supported by RFC 2435
+ return VLC_EGENERIC;
+ }
+ // Round up by 8, divide by 8
+ w = ((width+7)&~7) >> 3;
+ h = ((height+7)&~7) >> 3;
+
+ // Get components sampling to determine type
+ // Y has component ID 1
+ // Possible configurations of sampling factors:
+ // Y - 0x22, Cb - 0x11, Cr - 0x11 => yuvj420p
+ // Y - 0x21, Cb - 0x11, Cr - 0x11 => yuvj422p
+
+ // Only 3 components are supported by RFC 2435
+ if (section_body[5] != 3) // Number of components
+ return VLC_EGENERIC;
+ for (int j = 0; j < 3; j++)
+ {
+ if (section_body[6 + j * 3] == 1 /* Y */)
+ {
+ y_sampling_factor = section_body[6 + j * 3 + 1];
+ }
+ else if (section_body[6 + j * 3 + 1] != 0x11)
+ {
+ // Sampling factor is unsupported by RFC 2435
+ return VLC_EGENERIC;
+ }
+ }
+ break;
+ }
+ case 0xffdd /*DRI*/:
+ restart_interval = GetWBE(section_body);
+ dri_found = 1;
+ break;
+ case 0xffda /*SOS*/:
+ /* SOS is last marker in the header */
+ header_finished = 1;
+ break;
+ default:
+ break;
+ }
+ // Step over marker, 16bit length and section body
+ p_data += 2 + section_size;
+ i_data -= 2 + section_size;
+ }
+ if (!header_finished)
+ return VLC_EGENERIC;
+ if (!w || !h)
+ return VLC_EGENERIC;
+
+ switch (y_sampling_factor)
+ {
+ case 0x22: // yuvj420p
+ type = 1;
+ break;
+ case 0x21: // yuvj422p
+ type = 0;
+ break;
+ default:
+ // Sampling format unsupported by RFC 2435
+ return VLC_EGENERIC;
+ }
+
+ if (dri_found)
+ type += 64;
+
+ while ( i_data )
+ {
+ int hdr_size = 8 + dri_found * 4;
+ if (off == 0 && nb_qtables)
+ hdr_size += 4 + 64 * nb_qtables;
+
+ int i_payload = __MIN( i_data, (int)(rtp_mtu (id) - hdr_size) );
+ if ( i_payload <= 0 )
+ return VLC_EGENERIC;
+
+ block_t *out = block_Alloc( 12 + hdr_size + i_payload );
+ if( out == NULL )
+ return VLC_ENOMEM;
+
+ uint8_t *p = out->p_buffer + 12;
+ /* set main header */
+ /* set type-specific=0, set offset in following 24 bits: */
+ SetDWBE(p, off & 0x00ffffff);
+ p += 4;
+ *p++ = type;
+ *p++ = 255; // Quant value
+ *p++ = w;
+ *p++ = h;
+
+ // Write restart_marker_hdr if needed
+ if (dri_found)
+ {
+ SetWBE(p, restart_interval);
+ p += 2;
+ // restart_count. Hardcoded same value as in gstreamer implementation
+ SetWBE(p, 0xffff);
+ p += 2;
+ }
+
+ if (off == 0 && nb_qtables)
+ {
+ /* set quantization tables header */
+ *p++ = 0;
+ *p++ = 0;
+ SetWBE (p, 64 * nb_qtables);
+ p += 2;
+ for (int i = 0; i < nb_qtables; i++)
+ {
+ memcpy (p, &qtables[65 * i + 1], 64);
+ p += 64;
+ }
+ }
+
+ /* rtp common header */
+ rtp_packetize_common( id, out, (i_payload == i_data),
+ (in->i_pts > VLC_TS_INVALID ? in->i_pts : in->i_dts) );
+ memcpy( p, p_data, i_payload );
+
+ out->i_buffer = 12 + hdr_size + i_payload;
+ out->i_dts = in->i_dts;
+ out->i_length = in->i_length;
+
+ rtp_packetize_send( id, out );
+
+ p_data += i_payload;
+ i_data -= i_payload;
+ off += i_payload;
+ }
+
+ return VLC_SUCCESS;
+}
--
1.8.1.5
More information about the vlc-devel
mailing list