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

Reply via email to