[vlc-commits] [Git][videolan/vlc][master] 2 commits: rtp/pcm: add parser for PCM, G.711 and DAT12

Rémi Denis-Courmont (@Courmisch) gitlab at videolan.org
Tue Nov 23 19:41:13 UTC 2021



Rémi Denis-Courmont pushed to branch master at VideoLAN / VLC


Commits:
66023648 by Rémi Denis-Courmont at 2021-11-23T18:40:13+00:00
rtp/pcm: add parser for PCM, G.711 and DAT12

Refs #26296.

- - - - -
2edb2785 by Rémi Denis-Courmont at 2021-11-23T18:40:13+00:00
rtp: remove static PCMA, PCMU and L16 parsers

- - - - -


3 changed files:

- modules/access/rtp/Makefile.am
- + modules/access/rtp/pcm.c
- modules/access/rtp/rtpfmt.c


Changes:

=====================================
modules/access/rtp/Makefile.am
=====================================
@@ -27,3 +27,11 @@ librtp_plugin_la_CFLAGS += $(GCRYPT_CFLAGS)
 librtp_plugin_la_LIBADD += libvlc_srtp.la $(GCRYPT_LIBS)
 librtp_plugin_la_DEPENDENCIES += libvlc_srtp.la
 endif
+
+# RTP payload parser plugins
+rtpparsedir = $(accessdir)/rtp
+rtpparse_LTLIBRARIES = \
+	librtp_pcm_plugin.la
+
+librtp_pcm_plugin_la_SOURCES = access/rtp/pcm.c
+librtp_pcm_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/access/rtp


=====================================
modules/access/rtp/pcm.c
=====================================
@@ -0,0 +1,242 @@
+/**
+ * @file pcm.c
+ * @brief Real-Time Protocol (RTP) linear and logarithmic audio
+ */
+/*****************************************************************************
+ * Copyright © 2021 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_aout.h>
+#include <vlc_block.h>
+#include <vlc_es.h>
+#include <vlc_plugin.h>
+#include <vlc_strings.h>
+
+#include "rtp.h"
+#define RTP_MAX_CHANS 6
+
+struct rtp_pcm {
+    vlc_fourcc_t fourcc;
+    uint16_t channel_mask;
+    uint8_t sample_bits;
+    uint8_t channel_count;
+    bool channel_reorder;
+    uint8_t channel_map[RTP_MAX_CHANS];
+};
+
+static void *rtp_pcm_init(struct vlc_rtp_pt *pt)
+{
+    struct rtp_pcm *sys = pt->opaque;
+    es_format_t fmt;
+
+    es_format_Init(&fmt, AUDIO_ES, sys->fourcc);
+    fmt.audio.i_rate = pt->frequency;
+    fmt.audio.i_physical_channels = sys->channel_mask;
+    fmt.audio.i_channels = sys->channel_count;
+    aout_FormatPrepare(&fmt.audio);
+    return vlc_rtp_pt_request_es(pt, &fmt);
+}
+
+static void rtp_pcm_destroy(struct vlc_rtp_pt *pt, void *data)
+{
+    struct vlc_rtp_es *es = data;
+
+    vlc_rtp_es_destroy(es);
+    (void) pt;
+}
+
+static void rtp_pcm_reorder(void *restrict out, const void *restrict in,
+                            size_t frames, size_t sample_size,
+                            size_t channels, const uint8_t *restrict map)
+{
+    unsigned char *outp = out;
+    const unsigned char *inp = in;
+    const size_t frame_size = sample_size * channels;
+
+    if (sample_size == 0 || sample_size > 3)
+        vlc_assert_unreachable(); /* Let compiler optimise the memcpy(). */
+
+    for (size_t i = 0; i < frames; i++) {
+        for (size_t j = 0; j < channels; j++) {
+             memcpy(outp + (sample_size * map[j]), inp, sample_size);
+             inp += sample_size;
+        }
+
+        outp += frame_size;
+    }
+}
+
+static void rtp_pcm_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
+{
+    struct rtp_pcm *sys = pt->opaque;
+    struct vlc_rtp_es *es = data;
+    const size_t frame_bits = sys->channel_count * sys->sample_bits;
+    size_t frames = (8 * block->i_buffer) / frame_bits;
+
+    block->i_buffer = ((frames * frame_bits) + 7) / 8;
+    block->i_dts = VLC_TICK_INVALID;
+
+    if (sys->channel_reorder) {
+        block_t *reordered = block_Alloc(block->i_buffer);
+
+        assert((sys->sample_bits % 8) == 0);
+
+        if (likely(reordered != NULL)) {
+            block_CopyProperties(reordered, block);
+            rtp_pcm_reorder(reordered->p_buffer, block->p_buffer, frames,
+                            sys->sample_bits / 8, sys->channel_count,
+                            sys->channel_map);
+
+        }
+
+        block_Release(block);
+        block = reordered;
+
+        if (unlikely(block == NULL))
+            return;
+    }
+
+    vlc_rtp_es_send(es, block);
+}
+
+static void rtp_pcm_release(struct vlc_rtp_pt *pt)
+{
+    struct rtp_pcm *sys = pt->opaque;
+
+    free(sys);
+}
+
+static const struct vlc_rtp_pt_operations rtp_pcm_ops = {
+    rtp_pcm_release, rtp_pcm_init, rtp_pcm_destroy, rtp_pcm_decode,
+};
+
+static const uint32_t channel_masks[] = {
+    /* By default, there is only one channel. */
+    AOUT_CHAN_CENTER,
+    /*
+     * RTP/AVP recommends AIFF-C channel order by default (RFC3551 §4.1).
+     * For 1-4 channel(s), this works well.
+     */
+    AOUT_CHAN_CENTER, AOUT_CHANS_2_0, AOUT_CHANS_3_0, AOUT_CHANS_3_1,
+    /* AIFF-C says for 5 channels, and RFC says 3.2. We assume normal 5.0. */
+    AOUT_CHANS_5_0,
+    /* Accordingly for 6 channels, we assume normal 5.1 instead of AIFF-C's. */
+    AOUT_CHANS_5_1,
+};
+
+static const uint32_t channel_order[] = {
+    AOUT_CHAN_LEFT, AOUT_CHAN_REARLEFT, AOUT_CHAN_CENTER,
+    AOUT_CHAN_RIGHT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0,
+};
+
+/* RTP puts right before center for 3.0, but center before right for 3.1! */
+static const uint32_t channel_order_3[RTP_MAX_CHANS] = {
+    AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,
+};
+
+static_assert (ARRAY_SIZE(channel_masks) == RTP_MAX_CHANS + 1, "Bad masks");
+static_assert (ARRAY_SIZE(channel_order) == RTP_MAX_CHANS + 1, "Bad order");
+
+static int rtp_pcm_open(vlc_object_t *obj, struct vlc_rtp_pt *pt,
+                        const struct vlc_sdp_pt *desc)
+{
+    vlc_fourcc_t fourcc;
+    unsigned bits;
+
+    if (vlc_ascii_strcasecmp(desc->name, "L8") == 0) {
+        fourcc = VLC_CODEC_U8; /* RFC3551 §4.5.10 */
+        bits = 8;
+
+    } else if (vlc_ascii_strcasecmp(desc->name, "L16") == 0) {
+        fourcc = VLC_CODEC_S16B; /* RFC3551 §4.5.11 */
+        bits = 16;
+
+    } else if (vlc_ascii_strcasecmp(desc->name, "L20") == 0) {
+        fourcc = VLC_CODEC_S20B; /* RFC3190 §4 */
+        bits = 20;
+
+    } else if (vlc_ascii_strcasecmp(desc->name, "L24") == 0) {
+        fourcc = VLC_CODEC_S24B; /* RFC3190 §4 */
+        bits = 24;
+
+    } else if (vlc_ascii_strcasecmp(desc->name, "PCMA") == 0) {
+        fourcc = VLC_CODEC_ALAW; /* RFC3551 §4.5.14 */
+        bits = 8;
+
+    } else if (vlc_ascii_strcasecmp(desc->name, "PCMU") == 0) {
+        fourcc = VLC_CODEC_MULAW; /* RFC3551 §4.5.14 */
+        bits = 8;
+
+    } else if (vlc_ascii_strcasecmp(desc->name, "DAT12") == 0) {
+        fourcc = VLC_CODEC_DAT12; /* RFC3190 §3 */
+        bits = 12;
+
+    } else
+        return VLC_ENOTSUP;
+
+    struct rtp_pcm *sys = malloc(sizeof (*sys));
+    if (unlikely(sys == NULL))
+        return VLC_ENOMEM;
+
+    sys->fourcc = fourcc;
+    sys->channel_count = desc->channel_count ? desc->channel_count : 1;
+    sys->channel_reorder = false;
+    sys->sample_bits = bits;
+
+    if (desc->channel_count < ARRAY_SIZE(channel_masks)) {
+        sys->channel_mask = channel_masks[desc->channel_count];
+        assert(vlc_popcount(sys->channel_mask) == sys->channel_count);
+
+        /* Octet-unaligned formats cannot readily be reordered, especially in
+         * foreign endianness. The decoder will take care of that. */
+        if ((bits % 8) == 0) {
+            const uint32_t *order = channel_order;
+
+            if (desc->channel_count == 3)
+                order = channel_order_3;
+
+            if (aout_CheckChannelReorder(order, NULL, sys->channel_mask,
+                                         sys->channel_map))
+                sys->channel_reorder = true;
+        }
+    } else {
+        msg_Warn(obj, "unknown %hhu-channels layout", desc->channel_count);
+        sys->channel_mask = 0;
+    }
+
+    pt->opaque = sys;
+    pt->ops = &rtp_pcm_ops;
+    return VLC_SUCCESS;
+}
+
+vlc_module_begin()
+    set_shortname(N_("RTP PCM"))
+    set_description(N_("RTP PCM payload parser"))
+    set_category(CAT_INPUT)
+    set_subcategory(SUBCAT_INPUT_DEMUX)
+    set_rtp_parser_callback(rtp_pcm_open)
+    add_shortcut("audio/L8", "audio/L16", "audio/L20", "audio/L24",
+                 "audio/DAT12", "audio/PCMA", "audio/PCMU")
+vlc_module_end()


=====================================
modules/access/rtp/rtpfmt.c
=====================================
@@ -55,23 +55,6 @@ static void codec_decode(struct vlc_rtp_pt *pt, void *data, block_t *block)
  * Static payload types handler
  */
 
-/* PT=0
- * PCMU: G.711 µ-law (RFC3551)
- */
-static void *pcmu_init(struct vlc_rtp_pt *pt)
-{
-    es_format_t fmt;
-
-    es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_MULAW);
-    fmt.audio.i_rate = pt->frequency;
-    fmt.audio.i_channels = pt->channel_count ? pt->channel_count : 1;
-    return vlc_rtp_pt_request_es(pt, &fmt);
-}
-
-static const struct vlc_rtp_pt_operations rtp_audio_pcmu = {
-    NULL, pcmu_init, codec_destroy, codec_decode,
-};
-
 /* PT=3
  * GSM
  */
@@ -89,40 +72,6 @@ static const struct vlc_rtp_pt_operations rtp_audio_gsm = {
     NULL, gsm_init, codec_destroy, codec_decode,
 };
 
-/* PT=8
- * PCMA: G.711 A-law (RFC3551)
- */
-static void *pcma_init(struct vlc_rtp_pt *pt)
-{
-    es_format_t fmt;
-
-    es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_ALAW);
-    fmt.audio.i_rate = pt->frequency;
-    fmt.audio.i_channels = pt->channel_count ? pt->channel_count : 1;
-    return vlc_rtp_pt_request_es(pt, &fmt);
-}
-
-static const struct vlc_rtp_pt_operations rtp_audio_pcma = {
-    NULL, pcma_init, codec_destroy, codec_decode,
-};
-
-/* PT=10,11
- * L16: 16-bits (network byte order) PCM
- */
-static void *l16_init(struct vlc_rtp_pt *pt)
-{
-    es_format_t fmt;
-
-    es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_S16B);
-    fmt.audio.i_rate = pt->frequency;
-    fmt.audio.i_channels = pt->channel_count ? pt->channel_count : 1;
-    return vlc_rtp_pt_request_es(pt, &fmt);
-}
-
-static const struct vlc_rtp_pt_operations rtp_audio_l16 = {
-    NULL, l16_init, codec_destroy, codec_decode,
-};
-
 /* PT=12
  * QCELP
  */
@@ -265,14 +214,8 @@ static struct vlc_rtp_pt *vlc_rtp_pt_create(vlc_object_t *obj,
     pt->ops = NULL;
 
     if (strcmp(desc->media->type, "audio") == 0) {
-        if (strcmp(desc->name, "PCMU") == 0)
-            pt->ops = &rtp_audio_pcmu;
-        else if (strcmp(desc->name, "GSM") == 0)
+        if (strcmp(desc->name, "GSM") == 0)
             pt->ops = &rtp_audio_gsm;
-        else if (strcmp(desc->name, "PCMA") == 0)
-            pt->ops = &rtp_audio_pcma;
-        else if (strcmp(desc->name, "L16") == 0)
-            pt->ops = &rtp_audio_l16;
         else if (strcmp(desc->name, "QCELP") == 0)
             pt->ops = &rtp_audio_qcelp;
         else if (strcmp(desc->name, "MPA") == 0)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/a18356f3f364b8d673b267bddab5dd64f1c12b72...2edb2785d42dcdd761ffcb531d80b2242c7915ec

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/a18356f3f364b8d673b267bddab5dd64f1c12b72...2edb2785d42dcdd761ffcb531d80b2242c7915ec
You're receiving this email because of your account on code.videolan.org.




More information about the vlc-commits mailing list