[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