Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC
Commits:
77eab7cd by Rémi Denis-Courmont at 2022-03-16T07:46:28+00:00
fourcc: define code point for RTP video/raw
- - - - -
2ba4b4e5 by Rémi Denis-Courmont at 2022-03-16T07:46:28+00:00
rtp: helpers to parse a=fmtp lines
- - - - -
ba8e70e2 by Rémi Denis-Courmont at 2022-03-16T07:46:28+00:00
rtp: raw video payload format parser
- - - - -
75c7e781 by Rémi Denis-Courmont at 2022-03-16T07:46:28+00:00
rtp: decoder for RTP video/raw (RFC4175)
This implements progressive content for most formats defined in
IETF RFC4175. This only takes care of converting the RTP payloads into
VLC picture buffers; parsing the RTP headers remains the job of the RTP
access module.
For consistency, this uses exclusively planar formats.
Later optimisations could substitute packed formats selectively.
- - - - -
7 changed files:
- include/vlc_fourcc.h
- modules/access/rtp/Makefile.am
- + modules/access/rtp/fmtp.h
- + modules/access/rtp/raw.c
- modules/codec/Makefile.am
- + modules/codec/rtp-rawvid.c
- src/misc/fourcc_list.h
Changes:
=====================================
include/vlc_fourcc.h
=====================================
@@ -193,6 +193,7 @@
#define VLC_CODEC_IMM5 VLC_FOURCC('I','M','M','5')
#define VLC_CODEC_AGM VLC_FOURCC('A','G','M','0')
#define VLC_CODEC_NOTCHLC VLC_FOURCC('n','c','l','c')
+#define VLC_CODEC_RTP_VIDEO_RAW VLC_FOURCC('R','T','P','V')
/***********
* Chromas
=====================================
modules/access/rtp/Makefile.am
=====================================
@@ -28,12 +28,15 @@ librtp_plugin_la_LIBADD += libvlc_srtp.la $(GCRYPT_LIBS)
librtp_plugin_la_DEPENDENCIES += libvlc_srtp.la
endif
+noinst_HEADERS += access/rtp/fmtp.h
+
# RTP payload parser plugins
rtpparsedir = $(accessdir)/rtp
rtpparse_LTLIBRARIES = \
librtp_ac3_plugin.la \
librtp_mpeg12_plugin.la \
librtp_pcm_plugin.la \
+ librtp_raw_plugin.la \
librtp_h264_plugin.la \
librtp_xiph_plugin.la
@@ -43,6 +46,8 @@ librtp_mpeg12_plugin_la_SOURCES = access/rtp/mpeg12.c
librtp_pcm_plugin_la_SOURCES = access/rtp/pcm.c
librtp_pcm_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/access/rtp
+librtp_raw_plugin_la_SOURCES = access/rtp/raw.c
+
librtp_h264_plugin_la_SOURCES = access/rtp/h264.c
librtp_xiph_plugin_la_SOURCES = access/rtp/xiph.c
=====================================
modules/access/rtp/fmtp.h
=====================================
@@ -0,0 +1,106 @@
+/**
+ * @file fmtp.h
+ * @brief SDP format parameters (fmtp) helpers
+ */
+/*****************************************************************************
+ * Copyright © 2022 Rémi Denis-Courmont
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+static inline
+const char *vlc_sdp_fmtp_get_str(const struct vlc_sdp_pt *desc,
+ const char *name, size_t *restrict lenp)
+{
+ const char *p = desc->parameters;
+ size_t namelen = strlen(name);
+
+ while (p != NULL) {
+ p += strspn(p, " ");
+
+ if (strncmp(p, name, namelen) == 0 && p[namelen] == '=') {
+ p += namelen + 1;
+ *lenp = strcspn(p, ";");
+ return p;
+ }
+
+ p = strchr(p, ';');
+ if (p != NULL)
+ p++;
+ }
+
+ return NULL;
+}
+
+static
+int vlc_sdp_fmtp_get_ull(const struct vlc_sdp_pt *desc, const char *name,
+ unsigned long long *restrict res)
+{
+ size_t len;
+ const char *n = vlc_sdp_fmtp_get_str(desc, name, &len);
+ if (n == NULL)
+ return -ENOENT;
+ if (len == 0)
+ return -EINVAL;
+
+ char *end;
+ unsigned long long ull = strtoull(n, &end, 10);
+ if (end != n + len)
+ return -EINVAL;
+
+ *res = ull;
+ return 0;
+}
+
+static inline
+int vlc_sdp_fmtp_get_u16(const struct vlc_sdp_pt *desc, const char *name,
+ uint16_t *restrict res)
+{
+ unsigned long long ull;
+ int err = vlc_sdp_fmtp_get_ull(desc, name, &ull);
+ if (err == 0) {
+ if (ull >> 16)
+ return -ERANGE;
+
+ *res = ull;
+ }
+ return err;
+}
+
+static inline
+int vlc_sdp_fmtp_get_u8(const struct vlc_sdp_pt *desc, const char *name,
+ uint8_t *restrict res)
+{
+ unsigned long long ull;
+ int err = vlc_sdp_fmtp_get_ull(desc, name, &ull);
+ if (err == 0) {
+ if (ull >> 8)
+ return -ERANGE;
+
+ *res = ull;
+ }
+ return err;
+}
+
+#define vlc_sdp_fmtp_get(desc, name, vp) \
+ _Generic (*(vp), \
+ uint16_t: vlc_sdp_fmtp_get_u16(desc, name, (uint16_t *)(vp)), \
+ uint8_t: vlc_sdp_fmtp_get_u8(desc, name, (uint8_t *)(vp)))
+
=====================================
modules/access/rtp/raw.c
=====================================
@@ -0,0 +1,191 @@
+/**
+ * @file raw.c
+ * @brief Real-Time Protocol raw video payload format parser
+ */
+/*****************************************************************************
+ * Copyright © 2022 Rémi Denis-Courmont
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ ****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <assert.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <vlc_common.h>
+#include <vlc_block.h>
+#include <vlc_es.h>
+#include <vlc_plugin.h>
+#include <vlc_strings.h>
+
+#include "rtp.h"
+#include "fmtp.h"
+
+enum vlc_rtp_colorimetry {
+ VLC_RTP_COLOR_UNKNOWN,
+ VLC_RTP_COLOR_BT601_5,
+ VLC_RTP_COLOR_BT709_2,
+ VLC_RTP_COLOR_SMPTE240M,
+};
+
+/* video/raw: raw video ES */
+struct rtp_raw {
+ struct vlc_logger *log;
+ char *sampling;
+ uint16_t width;
+ uint16_t height;
+ uint8_t depth;
+ enum vlc_rtp_colorimetry colorimetry;
+};
+
+static void *rtp_raw_begin(struct vlc_rtp_pt *pt)
+{
+ struct rtp_raw *sys = pt->opaque;
+ es_format_t fmt;
+
+ es_format_Init(&fmt, VIDEO_ES, VLC_CODEC_RTP_VIDEO_RAW);
+ fmt.video.i_width = sys->width;
+ fmt.video.i_height = sys->height;
+
+ switch (sys->colorimetry) {
+ case VLC_RTP_COLOR_UNKNOWN:
+ fmt.video.primaries = COLOR_PRIMARIES_UNDEF;
+ fmt.video.transfer = TRANSFER_FUNC_UNDEF;
+ fmt.video.space = COLOR_SPACE_UNDEF;
+ break;
+ case VLC_RTP_COLOR_BT601_5:
+ fmt.video.primaries = COLOR_PRIMARIES_BT601_525;
+ fmt.video.transfer = TRANSFER_FUNC_BT709;
+ fmt.video.space = COLOR_SPACE_BT601;
+ break;
+ case VLC_RTP_COLOR_BT709_2:
+ fmt.video.primaries = COLOR_PRIMARIES_BT709;
+ fmt.video.transfer = TRANSFER_FUNC_BT709;
+ fmt.video.space = COLOR_SPACE_BT709;
+ break;
+ case VLC_RTP_COLOR_SMPTE240M:
+ fmt.video.primaries = COLOR_PRIMARIES_SMTPE_240;
+ fmt.video.transfer = TRANSFER_FUNC_SMPTE_240;
+ fmt.video.space = COLOR_SPACE_SMPTE_240;
+ break;
+ }
+
+ fmt.i_level = sys->depth;
+ /* Do not allocate anything and do not free anything there: */
+ fmt.p_extra = sys->sampling;
+ fmt.i_extra = strlen(sys->sampling) + 1;
+
+ return vlc_rtp_pt_request_es(pt, &fmt);
+}
+
+static void rtp_raw_end(struct vlc_rtp_pt *pt, void *data)
+{
+ struct vlc_rtp_es *es = data;
+
+ vlc_rtp_es_destroy(es);
+ (void) pt;
+}
+
+static void rtp_raw_unwrap(struct vlc_rtp_pt *pt, void *data, block_t *block,
+ const struct vlc_rtp_pktinfo *restrict info)
+{
+ struct rtp_raw *sys = pt->opaque;
+ struct vlc_rtp_es *es = data;
+
+ if (block->i_buffer < 8) {
+ vlc_warning(sys->log, "malformatted packet (%zu bytes)",
+ block->i_buffer);
+ block_Release(block);
+ return;
+ }
+
+ /* NOTE: The M bit flags the last packet of a frame or field.
+ * It is not currently needed for anything. */
+ (void) info;
+
+ /* NOTE: The extended sequence header is ignored here. This would need to
+ * be processed in the generic RTP code along the baseline sequence header.
+ * We assume that reordering will not too severe to need that. */
+ block->p_buffer += 2;
+ block->i_buffer -= 2;
+ vlc_rtp_es_send(es, block);
+ return;
+}
+
+static void rtp_raw_close(struct vlc_rtp_pt *pt)
+{
+ struct rtp_raw *sys = pt->opaque;
+
+ free(sys->sampling);
+ free(sys);
+}
+
+static const struct vlc_rtp_pt_operations rtp_raw_ops = {
+ rtp_raw_close, rtp_raw_begin, rtp_raw_end, rtp_raw_unwrap,
+};
+
+static int rtp_raw_open(vlc_object_t *obj, struct vlc_rtp_pt *pt,
+ const struct vlc_sdp_pt *desc)
+{
+ if (vlc_ascii_strcasecmp(desc->name, "raw") != 0 /* RFC4175 */)
+ return VLC_ENOTSUP;
+
+ struct rtp_raw *sys = malloc(sizeof (*sys));
+ if (unlikely(sys == NULL))
+ return VLC_ENOMEM;
+
+ sys->log = obj->logger;
+
+ size_t slen, clen;
+ const char *s = vlc_sdp_fmtp_get_str(desc, "sampling", &slen);
+ const char *c = vlc_sdp_fmtp_get_str(desc, "colorimetry", &clen);
+ if (s == NULL || c == NULL
+ || vlc_sdp_fmtp_get(desc, "width", &sys->width)
+ || vlc_sdp_fmtp_get(desc, "height", &sys->height)
+ || vlc_sdp_fmtp_get(desc, "depth", &sys->depth)) {
+ free(sys);
+ vlc_error(sys->log, "missing parameters for raw video");
+ return VLC_EINVAL;
+ }
+
+ sys->sampling = strndup(s, slen);
+
+ if (clen == 7 && strncmp(c, "BT601-5", 7) == 0)
+ sys->colorimetry = VLC_RTP_COLOR_BT601_5;
+ else if (clen == 7 && strncmp(c, "BT709-2", 7) == 0)
+ sys->colorimetry = VLC_RTP_COLOR_BT709_2;
+ else if (clen == 9 && strncmp(c, "SMPTE240M", 9) == 0)
+ sys->colorimetry = VLC_RTP_COLOR_SMPTE240M;
+ else {
+ vlc_warning(sys->log, "unknown colorimetry %.*s", (int)clen, c);
+ sys->colorimetry = VLC_RTP_COLOR_UNKNOWN;
+ }
+ /* TODO: interlacing, chroma location (optional parameters) */
+
+ pt->opaque = sys;
+ pt->ops = &rtp_raw_ops;
+ return VLC_SUCCESS;
+}
+
+vlc_module_begin()
+ set_shortname(N_("RTP raw"))
+ set_description(N_("RTP raw video payload parser"))
+ set_subcategory(SUBCAT_INPUT_DEMUX)
+ set_rtp_parser_callback(rtp_raw_open)
+ add_shortcut("video/raw")
+vlc_module_end()
=====================================
modules/codec/Makefile.am
=====================================
@@ -122,6 +122,9 @@ libschroedinger_plugin_la_LIBADD = $(LIBS_schroedinger)
EXTRA_LTLIBRARIES += libschroedinger_plugin.la
codec_LTLIBRARIES += $(LTLIBschroedinger)
+librtp_rawvid_plugin_la_SOURCES = codec/rtp-rawvid.c
+codec_LTLIBRARIES += librtp_rawvid_plugin.la
+
### Image codecs ###
=====================================
modules/codec/rtp-rawvid.c
=====================================
@@ -0,0 +1,864 @@
+/*****************************************************************************
+ * rtp-rawvid.c: RTP raw video decoder
+ *****************************************************************************
+ * Copyright (C) 2022 Rémi Denis-Courmont
+ *
+ * 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
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_codec.h>
+
+#define PLANES_3(bits) \
+ uint##bits##_t *restrict p0 = planes[0]; \
+ uint##bits##_t *restrict p1 = planes[1]; \
+ uint##bits##_t *restrict p2 = planes[2]; \
+ (void)0
+
+#define PLANES_4(bits) \
+ uint##bits##_t *restrict p0 = planes[0]; \
+ uint##bits##_t *restrict p1 = planes[1]; \
+ uint##bits##_t *restrict p2 = planes[2]; \
+ uint##bits##_t *restrict p3 = planes[3]; \
+ (void)0
+
+/* Read one 8-bit sample from one octet */
+#define READ_8(a) \
+ uint_fast8_t a; \
+\
+ do { \
+ a = *(in++); \
+ len--; \
+ } while (0)
+
+/* Read four 10-bit samples from five octets. */
+#define READ_10(a, b, c, d) \
+ uint_fast16_t a, b, c, d; \
+\
+ do { \
+ uint_fast8_t b0_ = in[0]; \
+ uint_fast8_t b1_ = in[1]; \
+ uint_fast8_t b2_ = in[2]; \
+ uint_fast8_t b3_ = in[3]; \
+ uint_fast8_t b4_ = in[4]; \
+\
+ a = (b0_ << 2) | (b1_ >> 6); \
+ b = ((b1_ << 4) | (b2_ >> 4)) & 0x3ff; \
+ c = ((b2_ << 6) | (b3_ >> 2)) & 0x3ff; \
+ d = ((b3_ << 8) | (b4_ >> 0)) & 0x3ff; \
+ in += 5; \
+ len -= 5; \
+ } while (0)
+
+/* Read two 12-bit samples from three octets. */
+#define READ_12(a, b) \
+ uint_fast16_t a, b; \
+\
+ do { \
+ uint_fast8_t b0_ = in[0]; \
+ uint_fast8_t b1_ = in[1]; \
+ uint_fast8_t b2_ = in[2]; \
+\
+ a = (b0_ << 4) | (b1_ >> 4); \
+ b = ((b1_ << 4) | (b2_ >> 0)) & 0xfff; \
+ in += 3; \
+ len -= 3; \
+ } while (0)
+
+
+/* Read one 16-bit sample from two octets */
+#define READ_16(a) \
+ uint_fast16_t a; \
+\
+ do { \
+ a = GetWBE(in); \
+ in += 2; \
+ len -= 2; \
+ } while (0)
+
+#define WRITE_RGB(n) \
+ do { \
+ *(p0++) = g##n; \
+ *(p1++) = b##n; \
+ *(p2++) = r##n; \
+ } while (0)
+
+#define WRITE_RGBA(n) \
+ do { \
+ *(p0++) = g##n; \
+ *(p1++) = b##n; \
+ *(p2++) = r##n; \
+ *(p3++) = a##n; \
+ } while (0)
+
+#define WRITE_YUV444(n) \
+ do { \
+ *(p0++) = y##n; \
+ *(p1++) = u##n; \
+ *(p2++) = v##n; \
+ } while (0)
+
+#define WRITE_YUV422(n) \
+ do { \
+ *(p0++) = y0##n; \
+ *(p0++) = y1##n; \
+ *(p1++) = u##n; \
+ *(p2++) = v##n; \
+ } while (0)
+
+#define WRITE_YUV420(n) \
+ do { \
+ *(p0++) = y00##n; \
+ *(p0++) = y01##n; \
+ *(p3++) = y10##n; \
+ *(p3++) = y11##n; \
+ *(p1++) = u##n; \
+ *(p2++) = v##n; \
+ } while (0)
+
+#define WRITE_YUV411(n) \
+ do { \
+ *(p0++) = y0##n; \
+ *(p0++) = y1##n; \
+ *(p0++) = y2##n; \
+ *(p0++) = y3##n; \
+ *(p1++) = u##n; \
+ *(p2++) = v##n; \
+ } while (0)
+
+static void decode_rgb_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(8);
+
+ while (len > 0) {
+ READ_8(r0);
+ READ_8(g0);
+ READ_8(b0);
+ WRITE_RGB(0);
+ }
+}
+
+static void decode_rgb_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_10(r0, g0, b0, r1);
+ READ_10(g1, b1, r2, g2);
+ READ_10(b2, r3, b3, g3);
+ WRITE_RGB(0);
+ WRITE_RGB(1);
+ WRITE_RGB(2);
+ WRITE_RGB(3);
+ }
+}
+
+static void decode_rgb_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_12(r0, g0);
+ READ_12(b0, r1);
+ READ_12(g1, b1);
+ WRITE_RGB(0);
+ WRITE_RGB(1);
+ }
+}
+
+static void decode_rgb_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_16(r0);
+ READ_16(g0);
+ READ_16(b0);
+ WRITE_RGB(0);
+ }
+}
+
+static void decode_rgba_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(8);
+
+ while (len > 0) {
+ READ_8(r0);
+ READ_8(g0);
+ READ_8(b0);
+ READ_8(a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_rgba_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_10(r0, g0, b0, a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_rgba_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_12(r0, g0);
+ READ_12(b0, a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_rgba_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_16(r0);
+ READ_16(g0);
+ READ_16(b0);
+ READ_16(a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_bgr_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(8);
+
+ while (len > 0) {
+ READ_8(b0);
+ READ_8(g0);
+ READ_8(r0);
+ WRITE_RGB(0);
+ }
+}
+
+static void decode_bgr_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_10(b0, g0, r0, b1);
+ READ_10(g1, r1, b2, g2);
+ READ_10(r2, b3, g3, r3);
+ WRITE_RGB(0);
+ WRITE_RGB(1);
+ WRITE_RGB(2);
+ WRITE_RGB(3);
+ }
+}
+
+static void decode_bgr_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_12(b0, g0);
+ READ_12(r0, b1);
+ READ_12(g1, r1);
+ WRITE_RGB(0);
+ WRITE_RGB(1);
+ }
+}
+
+static void decode_bgr_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_16(b0);
+ READ_16(g0);
+ READ_16(r0);
+ WRITE_RGB(0);
+ }
+}
+
+static void decode_bgra_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(8);
+
+ while (len > 0) {
+ READ_8(b0);
+ READ_8(g0);
+ READ_8(r0);
+ READ_8(a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_bgra_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_10(b0, g0, r0, a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_bgra_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_12(b0, g0);
+ READ_12(r0, a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_bgra_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_16(b0);
+ READ_16(g0);
+ READ_16(r0);
+ READ_16(a0);
+ WRITE_RGBA(0);
+ }
+}
+
+static void decode_yuv444_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(8);
+
+ while (len > 0) {
+ READ_8(u0);
+ READ_8(y0);
+ READ_8(v0);
+ WRITE_YUV444(0);
+ }
+}
+
+static void decode_yuv444_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_10(u0, y0, v0, u1);
+ READ_10(y1, v1, u2, y2);
+ READ_10(v2, u3, y3, v3);
+ WRITE_YUV444(0);
+ WRITE_YUV444(1);
+ WRITE_YUV444(2);
+ WRITE_YUV444(3);
+ }
+}
+
+static void decode_yuv444_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_12(u0, y0);
+ READ_12(v0, u1);
+ READ_12(y1, v1);
+ WRITE_YUV444(0);
+ WRITE_YUV444(1);
+ }
+}
+
+static void decode_yuv444_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_16(u0);
+ READ_16(y0);
+ READ_16(v0);
+ WRITE_YUV444(0);
+ }
+}
+
+static void decode_yuv422_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(8);
+
+ while (len > 0) {
+ READ_8(u0);
+ READ_8(y00);
+ READ_8(v0);
+ READ_8(y10);
+ WRITE_YUV422(0);
+ }
+}
+
+static void decode_yuv422_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_10(u0, y00, v0, y10);
+ WRITE_YUV422(0);
+ }
+}
+
+static void decode_yuv422_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_12(u0, y00);
+ READ_12(v0, y10);
+ WRITE_YUV422(0);
+ }
+}
+
+static void decode_yuv422_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(16);
+
+ while (len > 0) {
+ READ_16(u0);
+ READ_16(y00);
+ READ_16(v0);
+ READ_16(y10);
+ WRITE_YUV422(0);
+ }
+}
+
+static void decode_yuv420_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(8);
+
+ while (len > 0) {
+ READ_8(y000);
+ READ_8(y010);
+ READ_8(y100);
+ READ_8(y110);
+ READ_8(u0);
+ READ_8(v0);
+ WRITE_YUV420(0);
+ }
+}
+
+static void decode_yuv420_10(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_10(y000, y010, y100, y110);
+ READ_10(u0, v0, y001, y011);
+ READ_10(y101, y111, u1, v1);
+ WRITE_YUV420(0);
+ WRITE_YUV420(1);
+ }
+}
+
+static void decode_yuv420_12(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_12(y000, y010);
+ READ_12(y100, y110);
+ READ_12(u0, v0);
+ WRITE_YUV420(0);
+ }
+}
+
+static void decode_yuv420_16(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_4(16);
+
+ while (len > 0) {
+ READ_16(y000);
+ READ_16(y010);
+ READ_16(y100);
+ READ_16(y110);
+ READ_16(u0);
+ READ_16(v0);
+ WRITE_YUV420(0);
+ }
+}
+
+static void decode_yuv411_8(void *restrict *restrict planes,
+ const unsigned char *restrict in, size_t len)
+{
+ PLANES_3(8);
+
+ while (len > 0) {
+ READ_8(u0);
+ READ_8(y00);
+ READ_8(y10);
+ READ_8(v0);
+ READ_8(y20);
+ READ_8(y30);
+ WRITE_YUV411(0);
+ }
+}
+
+typedef void (*vlc_rtp_video_raw_cb)(void *restrict *,
+ const unsigned char *, size_t);
+
+struct vlc_rtp_video_raw_dec {
+ unsigned int pgroup;
+ bool half_height_uv;
+ vlc_rtp_video_raw_cb decode_line;
+ picture_t *pic;
+};
+
+static int Decode(decoder_t *dec, vlc_frame_t *block)
+{
+ struct vlc_rtp_video_raw_dec *sys = dec->p_sys;
+ picture_t *pic = sys->pic;
+ bool continuation;
+
+ if (block == NULL) {
+ /* Draining */
+ if (pic != NULL) /* Send incomplete picture */
+ decoder_QueueVideo(dec, pic);
+ sys->pic = NULL;
+ return VLCDEC_SUCCESS;
+ }
+
+ if ((block->i_flags & VLC_FRAME_FLAG_DISCONTINUITY)
+ && pic != NULL && pic->date != block->i_pts) {
+ /* Ideally, the EOS is set on the last block for a picture.
+ * This manual check is necessary to deal with packet loss. */
+ decoder_QueueVideo(dec, pic);
+ pic = sys->pic = NULL;
+ }
+
+ if (pic == NULL) {
+ pic = decoder_NewPicture(dec);
+
+ if (pic == NULL) {
+ block_Release(block);
+ return VLCDEC_SUCCESS;
+ }
+
+ pic->date = block->i_pts;
+ pic->b_progressive = true; /* TODO: interlacing */
+ sys->pic = pic;
+ }
+
+ const unsigned char *in = block->p_buffer;
+ size_t inlen = block->i_buffer;
+ const unsigned int width = dec->fmt_out.video.i_width;
+ const unsigned int height = dec->fmt_out.video.i_height;
+
+ do {
+ if (unlikely(inlen < 6)) {
+corrupt: msg_Err(dec, "corrupt packet, %zu bytes remaining", inlen);
+ break;
+ }
+
+ uint_fast16_t length = GetWBE(in);
+ uint_fast16_t lineno = GetWBE(in + 2);
+ uint_fast16_t offset = GetWBE(in + 4);
+
+ lineno &= 0x7fff; /* TODO: interlacing */
+ continuation = (offset & 0x8000) != 0;
+ offset &= 0x7fff;
+
+ in += 6;
+ inlen -= 6;
+
+ div_t d = div(length, sys->pgroup);
+
+ if (inlen < length /* input buffer underflow */
+ || d.rem != 0 /* length must be a multiple of pgroup size */
+ || offset + d.quot >= width /* output scanline overflow */
+ || lineno >= height /* output picture overflow */)
+ goto corrupt;
+
+ void *restrict planes[4];
+
+ if (sys->half_height_uv) {
+ /* For I420, treat the odd Y lines as the 4th plane */
+ if (unlikely(lineno & 1))
+ goto corrupt; /* line number must always be even */
+
+ assert(pic->i_planes <= 3);
+ planes[0] = pic->p[0].p_pixels + lineno * pic->p[0].i_pitch
+ + offset * pic->p[0].i_pixel_pitch;
+ planes[3] = ((unsigned char *)planes[0]) + pic->p[0].i_pitch;
+ lineno /= 2;
+
+ for (int i = 1; i < pic->i_planes; i++) {
+ plane_t *p = &pic->p[i];
+
+ planes[i] = p->p_pixels + lineno * p->i_pitch
+ + offset * p->i_pixel_pitch;
+ }
+ } else {
+ for (int i = 0; i < pic->i_planes; i++) {
+ plane_t *p = &pic->p[i];
+
+ planes[i] = p->p_pixels + lineno * p->i_pitch
+ + offset * p->i_pixel_pitch;
+ }
+ }
+
+ sys->decode_line(planes, in, length);
+ } while (continuation);
+
+ if (block->i_flags & VLC_FRAME_FLAG_END_OF_SEQUENCE) {
+ decoder_QueueVideo(dec, pic);
+ sys->pic = NULL;
+ }
+
+ block_Release(block);
+ return VLCDEC_SUCCESS;
+}
+
+static void Close(vlc_object_t *obj)
+{
+ decoder_t *dec = (decoder_t *)obj;
+ struct vlc_rtp_video_raw_dec *sys = dec->p_sys;
+
+ if (sys->pic != NULL)
+ picture_Release(sys->pic);
+}
+
+struct vlc_rtp_video_raw_format {
+ vlc_fourcc_t fourcc;
+ vlc_rtp_video_raw_cb line_cb;
+};
+
+/**
+ * RTP video/raw sampling
+ *
+ * This defines the list of all supported (per component) bit depths.
+ */
+struct vlc_rtp_video_raw_sampling {
+ struct vlc_rtp_video_raw_format depth8;
+ struct vlc_rtp_video_raw_format depth10;
+ struct vlc_rtp_video_raw_format depth12;
+ struct vlc_rtp_video_raw_format depth16;
+};
+
+/**
+ * RTP video/raw samplings
+ *
+ * This type defines the list of all support RTP video/raw samplings.
+ * \note This is purposedly a structure rather than an array so that CPU
+ * optimisations can readily cherry-pick which samplings to optimise.
+ */
+struct vlc_rtp_video_raw_samplings {
+ struct vlc_rtp_video_raw_sampling rgb;
+ struct vlc_rtp_video_raw_sampling rgba;
+ struct vlc_rtp_video_raw_sampling bgr;
+ struct vlc_rtp_video_raw_sampling bgra;
+ struct vlc_rtp_video_raw_sampling yuv444;
+ struct vlc_rtp_video_raw_sampling yuv422;
+ struct vlc_rtp_video_raw_sampling yuv420;
+ struct vlc_rtp_video_raw_sampling yuv411;
+};
+
+#ifdef WORDS_BIGENDIAN
+#define NE(x) x##B
+#else
+#define NE(x) x##L
+#endif
+
+static const struct vlc_rtp_video_raw_samplings samplings = {
+ .rgb = {
+ { VLC_CODEC_GBR_PLANAR, decode_rgb_8, },
+ { NE(VLC_CODEC_GBR_PLANAR_10), decode_rgb_10, },
+ { NE(VLC_CODEC_GBR_PLANAR_12), decode_rgb_12, },
+ { NE(VLC_CODEC_GBR_PLANAR_16), decode_rgb_16, },
+ },
+ .rgba = {
+ { VLC_CODEC_GBR_PLANAR, decode_rgba_8, },
+ { NE(VLC_CODEC_GBR_PLANAR_10), decode_rgba_10, },
+ { NE(VLC_CODEC_GBR_PLANAR_12), decode_rgba_12, },
+ { NE(VLC_CODEC_GBR_PLANAR_16), decode_rgba_16, },
+ },
+ .bgr = {
+ { VLC_CODEC_GBR_PLANAR, decode_bgr_8, },
+ { NE(VLC_CODEC_GBR_PLANAR_10), decode_bgr_10, },
+ { NE(VLC_CODEC_GBR_PLANAR_12), decode_bgr_12, },
+ { NE(VLC_CODEC_GBR_PLANAR_16), decode_bgr_16, },
+ },
+ .bgra = {
+ { VLC_CODEC_GBR_PLANAR, decode_bgra_8, },
+ { NE(VLC_CODEC_GBR_PLANAR_10), decode_bgra_10, },
+ { NE(VLC_CODEC_GBR_PLANAR_12), decode_bgra_12, },
+ { NE(VLC_CODEC_GBR_PLANAR_16), decode_bgra_16, },
+ },
+ .yuv444 = {
+ { VLC_CODEC_I444, decode_yuv444_8, },
+ { NE(VLC_CODEC_I444_10), decode_yuv444_10, },
+ { NE(VLC_CODEC_I444_12), decode_yuv444_12, },
+ { NE(VLC_CODEC_I444_16), decode_yuv444_16, },
+ },
+ .yuv422 = {
+ { VLC_CODEC_I422, decode_yuv422_8, },
+ { NE(VLC_CODEC_I422_10), decode_yuv422_10, },
+ { NE(VLC_CODEC_I422_12), decode_yuv422_12, },
+ { NE(VLC_CODEC_I422_16), decode_yuv422_16, },
+ },
+ .yuv420 = {
+ { VLC_CODEC_I420, decode_yuv420_8, },
+ { NE(VLC_CODEC_I420_10), decode_yuv420_10, },
+ { NE(VLC_CODEC_I420_12), decode_yuv420_12, },
+ { NE(VLC_CODEC_I420_16), decode_yuv420_16, },
+ },
+ .yuv411 = {
+ { VLC_CODEC_I411, decode_yuv411_8, },
+ /* High-definition 4:1:1 not supported */
+ { 0, NULL }, { 0, NULL }, { 0, NULL }
+ },
+};
+
+static int Open(vlc_object_t *obj)
+{
+ decoder_t *dec = (decoder_t *)obj;
+ const char *sname = dec->fmt_in.p_extra;
+
+ if (dec->fmt_in.i_codec != VLC_CODEC_RTP_VIDEO_RAW)
+ return VLC_ENOTSUP;
+ if (dec->fmt_in.i_extra <= 0 || sname[dec->fmt_in.i_extra - 1] != '\0')
+ return VLC_EINVAL;
+
+ /* Sampling is supplied as extra data, bit depth as level */
+ unsigned int depth = dec->fmt_in.i_level;
+ const struct vlc_rtp_video_raw_sampling *sampling;
+ unsigned int spmp; /* samples per macropixel */
+ bool half_height_uv = false;
+
+ if (strcmp(sname, "RGB") == 0) {
+ sampling = &samplings.rgb;
+ spmp = 3;
+ } else if (strcmp(sname, "RGBA") == 0) {
+ sampling = &samplings.rgba;
+ spmp = 4;
+ } else if (strcmp(sname, "BGR") == 0) {
+ sampling = &samplings.bgr;
+ spmp = 3;
+ } else if (strcmp(sname, "BGRA") == 0) {
+ sampling = &samplings.bgra;
+ spmp = 4;
+ } else if (strcmp(sname, "YCbCr-4:4:4") == 0) {
+ sampling = &samplings.yuv444;
+ spmp = 3;
+ } else if (strcmp(sname, "YCbCr-4:2:2") == 0) {
+ sampling = &samplings.yuv422;
+ spmp = 4;
+ } else if (strcmp(sname, "YCbCr-4:2:0") == 0) {
+ sampling = &samplings.yuv420;
+ spmp = 6;
+ half_height_uv = true;
+ } else if (strcmp(sname, "YCbCr-4:1:1") == 0) {
+ sampling = &samplings.yuv411;
+ spmp = 6;
+ } else {
+ msg_Err(obj, "unknown RTP video sampling %s", sname);
+ return VLC_ENOTSUP;
+ }
+
+ const struct vlc_rtp_video_raw_format *format;
+
+ switch (depth) {
+ case 8:
+ format = &sampling->depth8;
+ break;
+ case 10:
+ format = &sampling->depth10;
+ break;
+ case 12:
+ format = &sampling->depth12;
+ break;
+ case 16:
+ format = &sampling->depth16;
+ break;
+ default:
+ msg_Err(obj, "unsupported RTP video bit depth %u", depth);
+ return VLC_ENOTSUP;
+ }
+
+ if (format->fourcc == 0) {
+ msg_Err(obj, "unimplemented RTP video format %u-bit %s",
+ depth, sname);
+ return VLC_ENOTSUP;
+ }
+
+ struct vlc_rtp_video_raw_dec *sys = vlc_obj_malloc(obj, sizeof (*sys));
+ if (unlikely(sys == NULL))
+ return VLC_ENOMEM;
+
+ es_format_Copy(&dec->fmt_out, &dec->fmt_in);
+ dec->fmt_out.i_codec = format->fourcc;
+ dec->fmt_out.video.i_chroma = format->fourcc;
+
+ int ret = decoder_UpdateVideoFormat(dec);
+ if (ret != VLC_SUCCESS)
+ return ret;
+
+ unsigned int bpmp = depth * spmp;
+
+ /* pixel group size equals LCM(depth * spmp, 8) bits */
+ sys->pgroup = bpmp >> ((bpmp % 8) ? vlc_ctz(bpmp) : 3);
+ sys->half_height_uv = half_height_uv;
+ sys->decode_line = format->line_cb;
+ sys->pic = NULL;
+ dec->p_sys = sys;
+ dec->pf_decode = Decode;
+ return VLC_SUCCESS;
+}
+
+vlc_module_begin()
+ set_description(N_("RTP raw video decoder"))
+ set_capability("video decoder", 50)
+ set_subcategory(SUBCAT_INPUT_VCODEC)
+ set_callbacks(Open, Close)
+vlc_module_end()
=====================================
src/misc/fourcc_list.h
=====================================
@@ -1271,6 +1271,8 @@ static const staticentry_t p_list_video[] = {
A("AGM7"),
B(VLC_CODEC_NOTCHLC, "NotchLC"),
+
+ B(VLC_CODEC_RTP_VIDEO_RAW, "RTP raw video"),
};
static const staticentry_t p_list_audio[] = {
View it on GitLab:
https://code.videolan.org/videolan/vlc/-/compare/aed74edea926e985c42257475a757169a58ea7f6...75c7e781ae85ad9f6091f84856fb0467ef6b8779
--
View it on GitLab:
https://code.videolan.org/videolan/vlc/-/compare/aed74edea926e985c42257475a757169a58ea7f6...75c7e781ae85ad9f6091f84856fb0467ef6b8779
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
_______________________________________________
vlc-commits mailing list
vlc-commits@videolan.org
https://mailman.videolan.org/listinfo/vlc-commits