LadioCast 0.11.4 Released – LadioCast Development Notes No.87

in LadioCast

LadioCast Version 0.11.4 has been released.

Changes from version 0.11.3 to 0.11.4 are as follows:

  • Added Ogg PCM (32-bit Float) encoding format to the Icecast 2 streamer.

  • Updated libopus library to the latest version 1.1.1.

Specification of the Ogg PCM encoding format in LadioCast follows https://wiki.xiph.org/OggPCM with the exception that numerical values are expressed in little-endian (according to other specifications of Ogg [1]).

So, for example, such a parser extension as James Almer doing on ffmpeg FFmpeg-devel PATCH lavf/ogg: OggPCM demuxing should be rewritten like the following.

ffmpeg/libavformat/oggparsepcm.c
/*
 * PCM parser for Ogg
 * Copyright (c) 2013 James Almer
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg 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.
 *
 * FFmpeg 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 FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

#include "libavutil/intreadwrite.h"
#include "avformat.h"
#include "internal.h"
#include "oggdec.h"

struct oggpcm_private {
    int vorbis_comment;
    uint32_t extra_headers;
};

static const struct ogg_pcm_codec {
    uint32_t codec_id;
    uint32_t format_id;
} ogg_pcm_codecs[] = {
    { AV_CODEC_ID_PCM_S8,    0x00 },
    { AV_CODEC_ID_PCM_U8,    0x01 },
    { AV_CODEC_ID_PCM_S16LE, 0x02 },
    { AV_CODEC_ID_PCM_S16BE, 0x03 },
    { AV_CODEC_ID_PCM_S24LE, 0x04 },
    { AV_CODEC_ID_PCM_S24BE, 0x05 },
    { AV_CODEC_ID_PCM_S32LE, 0x06 },
    { AV_CODEC_ID_PCM_S32BE, 0x07 },
    { AV_CODEC_ID_PCM_F32LE, 0x20 },
    { AV_CODEC_ID_PCM_F32BE, 0x21 },
    { AV_CODEC_ID_PCM_F64LE, 0x22 },
    { AV_CODEC_ID_PCM_F64BE, 0x23 },
};

static const struct ogg_pcm_codec *ogg_get_pcm_codec_id(uint32_t format_id)
{
    int i;

    for (i = 0; i < FF_ARRAY_ELEMS(ogg_pcm_codecs); i++)
        if (ogg_pcm_codecs[i].format_id == format_id)
            return &ogg_pcm_codecs[i];

    return NULL;
}

static int pcm_header(AVFormatContext * s, int idx)
{
    struct ogg *ogg = s->priv_data;
    struct ogg_stream *os = ogg->streams + idx;
    struct oggpcm_private *priv = os->private;
    const struct ogg_pcm_codec *pcm;
    AVStream *st = s->streams[idx];
    uint8_t *p = os->buf + os->pstart;
    uint16_t major, minor;
    uint32_t format_id;

    if (os->flags & OGG_FLAG_BOS) {
        if (os->psize < 28) {
            av_log(s, AV_LOG_ERROR, "Invalid OggPCM header packet");
            return -1;
        }

        major = AV_RL16(p + 8);
        minor = AV_RL16(p + 10);

        if (major < 1 || major > 255) {
            av_log(s, AV_LOG_ERROR, "Unsupported OggPCM version %u.%u\n", major, minor);
            return -1;
        }

        format_id = AV_RL32(p + 12);
        pcm = ogg_get_pcm_codec_id(format_id);
        if (!pcm) {
            av_log(s, AV_LOG_ERROR, "Unsupported PCM format ID 0x%X\n", format_id);
            return -1;
        }

        priv = os->private = av_mallocz(sizeof(*priv));
        if (!priv)
            return AVERROR(ENOMEM);
        st->codec->codec_type  = AVMEDIA_TYPE_AUDIO;
        st->codec->codec_id    = pcm->codec_id;
        st->codec->sample_rate = AV_RL32(p + 16);
        st->codec->channels    = AV_RL8 (p + 21);
        priv->extra_headers    = AV_RL32(p + 24);
        priv->vorbis_comment   = 1;
        avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate);
    } else if (priv && priv->vorbis_comment) {
        ff_vorbis_comment(s, &st->metadata, p, os->psize, 0);
        priv->vorbis_comment   = 0;
    } else if (priv && priv->extra_headers) {
        // TODO: Support for channel mapping and conversion headers.
        priv->extra_headers--;
    } else
        return 0;

    return 1;
}

const struct ogg_codec ff_pcm_codec = {
    .magic     = "PCM     ",
    .magicsize = 8,
    .header    = pcm_header,
    .nb_header = 2,
};

Besides that, not mentioned in the change log, the maximum system sample rate of LadioCast has been raised up from 96kHz to 192kHz.

Any comment and suggestion will be appreciated.

Thanks.

Leave a Reply

*