From 109adf8368c4fca7af4e1bfc1ff9e8648ed1c73f Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 22:12:18 +0000 Subject: [PATCH 01/13] Cleanup: Codestyle --- src/format_flac.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/format_flac.c b/src/format_flac.c index d804463d..a4401dd3 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -34,9 +34,9 @@ static void flac_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ICECAST_LOG_DEBUG("freeing FLAC codec"); - stats_event (ogg_info->mount, "FLAC_version", NULL); - ogg_stream_clear (&codec->os); - free (codec); + stats_event(ogg_info->mount, "FLAC_version", NULL); + ogg_stream_clear(&codec->os); + free(codec); } @@ -45,36 +45,40 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o { refbuf_t * refbuf; - if (codec->headers) - { + if (codec->headers) { ogg_packet packet; - if (ogg_stream_pagein (&codec->os, page) < 0) - { + + if (ogg_stream_pagein(&codec->os, page) < 0) { ogg_info->error = 1; return NULL; } - while (ogg_stream_packetout (&codec->os, &packet)) - { + + while (ogg_stream_packetout(&codec->os, &packet)) { int type = packet.packet[0]; - if (type == 0xFF) - { + + if (type == 0xFF) { codec->headers = 0; break; } + if (type >= 1 && type <= 0x7E) continue; if (type >= 0x81 && type <= 0xFE) continue; + ogg_info->error = 1; + return NULL; } - if (codec->headers) - { - format_ogg_attach_header (ogg_info, page); + + if (codec->headers) { + format_ogg_attach_header(ogg_info, page); return NULL; } } - refbuf = make_refbuf_with_page (page); + + refbuf = make_refbuf_with_page(page); + return refbuf; } @@ -84,13 +88,13 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page) { ogg_state_t *ogg_info = plugin->_state; - ogg_codec_t *codec = calloc (1, sizeof (ogg_codec_t)); + ogg_codec_t *codec = calloc(1, sizeof(ogg_codec_t)); ogg_packet packet; - ogg_stream_init (&codec->os, ogg_page_serialno (page)); - ogg_stream_pagein (&codec->os, page); + ogg_stream_init(&codec->os, ogg_page_serialno(page)); + ogg_stream_pagein(&codec->os, page); - ogg_stream_packetout (&codec->os, &packet); + ogg_stream_packetout(&codec->os, &packet); ICECAST_LOG_DEBUG("checking for FLAC codec"); do @@ -108,7 +112,7 @@ ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page) ICECAST_LOG_INFO("seen initial FLAC header"); parse += 4; - stats_event_args (ogg_info->mount, "FLAC_version", "%d.%d", parse[0], parse[1]); + stats_event_args(ogg_info->mount, "FLAC_version", "%d.%d", parse[0], parse[1]); codec->process_page = process_flac_page; codec->codec_free = flac_codec_free; codec->headers = 1; From 65f7f559e4d102fc718c832062849378890ce4b7 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 22:14:12 +0000 Subject: [PATCH 02/13] Fix: Check for packet.bytes >= 1 --- src/format_flac.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/format_flac.c b/src/format_flac.c index a4401dd3..c09a5c10 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -54,18 +54,20 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o } while (ogg_stream_packetout(&codec->os, &packet)) { - int type = packet.packet[0]; + if (packet.bytes >= 1) { + int type = packet.packet[0]; - if (type == 0xFF) { - codec->headers = 0; - break; + if (type == 0xFF) { + codec->headers = 0; + break; + } + + if (type >= 1 && type <= 0x7E) + continue; + if (type >= 0x81 && type <= 0xFE) + continue; } - if (type >= 1 && type <= 0x7E) - continue; - if (type >= 0x81 && type <= 0xFE) - continue; - ogg_info->error = 1; return NULL; From 756e3b7d22fb6819d79b06b5b3cf72924dd82799 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 22:33:28 +0000 Subject: [PATCH 03/13] Update: Parse FLAC block types and report via ICECAST_LOG_DEBUG() --- src/format_flac.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/src/format_flac.c b/src/format_flac.c index c09a5c10..8b058d6f 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -19,6 +19,7 @@ #endif #include +#include #include #include @@ -30,6 +31,64 @@ #define CATMODULE "format-flac" #include "logging.h" +typedef enum { + FLAC_BLOCK_TYPE__ERROR = -1, + FLAC_BLOCK_TYPE_STREAMINFO = 0, + FLAC_BLOCK_TYPE_PADDING = 1, + FLAC_BLOCK_TYPE_APPLICATION = 2, + FLAC_BLOCK_TYPE_SEEKTABLE = 3, + FLAC_BLOCK_TYPE_VORBIS_COMMENT = 4, + FLAC_BLOCK_TYPE_CUESHEET = 5, + FLAC_BLOCK_TYPE_PICTURE = 6 +} flac_block_type_t; + +static flac_block_type_t flac_blocktype(const ogg_packet * packet) +{ + uint8_t type; + + if (packet->bytes <= 4) + return FLAC_BLOCK_TYPE__ERROR; + + type = packet->packet[0] & 0x7F; + + if (type <= FLAC_BLOCK_TYPE_PICTURE) { + return type; + } else { + return FLAC_BLOCK_TYPE__ERROR; + } +} + +static const char * flac_block_type_to_name(flac_block_type_t type) +{ + switch (type) { + case FLAC_BLOCK_TYPE__ERROR: + return ""; + break; + case FLAC_BLOCK_TYPE_STREAMINFO: + return "STREAMINFO"; + break; + case FLAC_BLOCK_TYPE_PADDING: + return "PADDING"; + break; + case FLAC_BLOCK_TYPE_APPLICATION: + return "APPLICATION"; + break; + case FLAC_BLOCK_TYPE_SEEKTABLE: + return "SEEKTABLE"; + break; + case FLAC_BLOCK_TYPE_VORBIS_COMMENT: + return "VORBIS_COMMENT"; + break; + case FLAC_BLOCK_TYPE_CUESHEET: + return "CUESHEET"; + break; + case FLAC_BLOCK_TYPE_PICTURE: + return "PICTURE"; + break; + } + + return ""; +} static void flac_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { @@ -55,13 +114,18 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o while (ogg_stream_packetout(&codec->os, &packet)) { if (packet.bytes >= 1) { - int type = packet.packet[0]; + uint8_t type = packet.packet[0]; + flac_block_type_t blocktype; if (type == 0xFF) { codec->headers = 0; break; } + blocktype = flac_blocktype(&packet); + + ICECAST_LOG_DEBUG("Found header of type %s%s", flac_block_type_to_name(blocktype), (type & 0x80) ? "|0x80" : ""); + if (type >= 1 && type <= 0x7E) continue; if (type >= 0x81 && type <= 0xFE) From c80fd692b2e300f1b2642efaffe52794fb8300b8 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 22:53:49 +0000 Subject: [PATCH 04/13] Feature: Added basic FLAC METADATA_BLOCK_HEADER parser --- src/format_flac.c | 68 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/src/format_flac.c b/src/format_flac.c index 8b058d6f..18b9569b 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -42,20 +43,55 @@ typedef enum { FLAC_BLOCK_TYPE_PICTURE = 6 } flac_block_type_t; -static flac_block_type_t flac_blocktype(const ogg_packet * packet) +typedef struct { + flac_block_type_t type; + bool last; + size_t len; + const void *data; +} flac_block_t; + +/* returns true if parse was ok, false on error */ +static bool flac_parse_block(flac_block_t *block, const ogg_packet * packet) { uint8_t type; + uint32_t len; + /* check header length */ if (packet->bytes <= 4) - return FLAC_BLOCK_TYPE__ERROR; + return false; - type = packet->packet[0] & 0x7F; + type = packet->packet[0]; - if (type <= FLAC_BLOCK_TYPE_PICTURE) { - return type; - } else { - return FLAC_BLOCK_TYPE__ERROR; + /* 0xFF is the sync code for a FRAME not a block */ + if (type == 0xFF) + return false; + + memset(block, 0, sizeof(*block)); + + if (type & 0x80) { + block->last = true; + type &= 0x7F; } + + if (type > FLAC_BLOCK_TYPE_PICTURE) + return false; + + block->type = type; + + len = (unsigned char)packet->packet[1]; + len <<= 8; + len |= (unsigned char)packet->packet[2]; + len <<= 8; + len |= (unsigned char)packet->packet[3]; + + /* check Ogg packet size vs. self-sync size */ + if (packet->bytes != (len + 4)) + return false; + + block->len = len; + block->data = packet->packet + 4; + + return true; } static const char * flac_block_type_to_name(flac_block_type_t type) @@ -113,23 +149,17 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o } while (ogg_stream_packetout(&codec->os, &packet)) { - if (packet.bytes >= 1) { - uint8_t type = packet.packet[0]; - flac_block_type_t blocktype; + flac_block_t block; - if (type == 0xFF) { + if (flac_parse_block(&block, &packet)) { + ICECAST_LOG_DEBUG("Found header of type %s%s with %zu bytes of data", flac_block_type_to_name(block.type), block.last ? "(last)" : "", block.len); + + if (block.last) { codec->headers = 0; break; } - blocktype = flac_blocktype(&packet); - - ICECAST_LOG_DEBUG("Found header of type %s%s", flac_block_type_to_name(blocktype), (type & 0x80) ? "|0x80" : ""); - - if (type >= 1 && type <= 0x7E) - continue; - if (type >= 0x81 && type <= 0xFE) - continue; + continue; } ogg_info->error = 1; From e0ed27bc4f798be4bd37600a83b5db92f4636259 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 23:50:28 +0000 Subject: [PATCH 05/13] Update: Created a stub function to handle all FLAC BLOCKs --- src/format_flac.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/src/format_flac.c b/src/format_flac.c index 18b9569b..e8fd8988 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -51,16 +51,16 @@ typedef struct { } flac_block_t; /* returns true if parse was ok, false on error */ -static bool flac_parse_block(flac_block_t *block, const ogg_packet * packet) +static bool flac_parse_block(flac_block_t *block, const ogg_packet * packet, size_t offset) { uint8_t type; uint32_t len; /* check header length */ - if (packet->bytes <= 4) + if ((size_t)packet->bytes <= (4 + offset)) return false; - type = packet->packet[0]; + type = packet->packet[offset]; /* 0xFF is the sync code for a FRAME not a block */ if (type == 0xFF) @@ -78,18 +78,18 @@ static bool flac_parse_block(flac_block_t *block, const ogg_packet * packet) block->type = type; - len = (unsigned char)packet->packet[1]; + len = (unsigned char)packet->packet[1 + offset]; len <<= 8; - len |= (unsigned char)packet->packet[2]; + len |= (unsigned char)packet->packet[2 + offset]; len <<= 8; - len |= (unsigned char)packet->packet[3]; + len |= (unsigned char)packet->packet[3 + offset]; /* check Ogg packet size vs. self-sync size */ - if (packet->bytes != (len + 4)) + if ((size_t)packet->bytes != (len + 4 + offset)) return false; block->len = len; - block->data = packet->packet + 4; + block->data = packet->packet + 4 + offset; return true; } @@ -126,6 +126,11 @@ static const char * flac_block_type_to_name(flac_block_type_t type) return ""; } +static void flac_handle_block(ogg_state_t *ogg_info, ogg_codec_t *codec, const flac_block_t *block) +{ + ICECAST_LOG_DEBUG("Found header of type %s%s with %zu bytes of data", flac_block_type_to_name(block->type), block->last ? "(last)" : "", block->len); +} + static void flac_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) { ICECAST_LOG_DEBUG("freeing FLAC codec"); @@ -134,7 +139,6 @@ static void flac_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) free(codec); } - /* Here, we just verify the page is ok and then add it to the queue */ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, ogg_page *page, format_plugin_t *plugin) { @@ -151,8 +155,8 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o while (ogg_stream_packetout(&codec->os, &packet)) { flac_block_t block; - if (flac_parse_block(&block, &packet)) { - ICECAST_LOG_DEBUG("Found header of type %s%s with %zu bytes of data", flac_block_type_to_name(block.type), block.last ? "(last)" : "", block.len); + if (flac_parse_block(&block, &packet, 0)) { + flac_handle_block(ogg_info, codec, &block); if (block.last) { codec->headers = 0; @@ -196,6 +200,7 @@ ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page) do { unsigned char *parse = packet.packet; + flac_block_t block; if (page->header_len + page->body_len != 79) break; @@ -214,6 +219,9 @@ ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page) codec->headers = 1; codec->name = "FLAC"; + if (flac_parse_block(&block, &packet, 13)) + flac_handle_block(ogg_info, codec, &block); + format_ogg_attach_header(ogg_info, page); return codec; } while (0); From 488f767b9eef0960642b604b5af65ea953187d7a Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 23:52:27 +0000 Subject: [PATCH 06/13] Update: Updated copyright --- src/format_flac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/format_flac.c b/src/format_flac.c index e8fd8988..04bd0a7d 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -8,7 +8,7 @@ * oddsock , * Karl Heyes * and others (see AUTHORS for details). - * Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft , + * Copyright 2014-2022, Philipp "ph3-der-loewe" Schafft , */ From b23ef22eaf783360ec70b98f6e3c5dbfc89a0a90 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Tue, 15 Mar 2022 23:55:45 +0000 Subject: [PATCH 07/13] Update: Added stub for Xiph metadata (vorbis comments, ...) --- src/Makefile.am | 2 ++ src/metadata_xiph.c | 17 +++++++++++++++++ src/metadata_xiph.h | 12 ++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 src/metadata_xiph.c create mode 100644 src/metadata_xiph.h diff --git a/src/Makefile.am b/src/Makefile.am index 5796bcc0..e58b7016 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -47,6 +47,7 @@ noinst_HEADERS = \ event_exec.h \ event_url.h \ acl.h auth.h \ + metadata_xiph.h \ format.h \ format_ogg.h \ format_mp3.h \ @@ -95,6 +96,7 @@ icecast_SOURCES = \ listensocket.c \ fastevent.c \ navigation.c \ + metadata_xiph.c \ format.c \ format_ogg.c \ format_mp3.c \ diff --git a/src/metadata_xiph.c b/src/metadata_xiph.c new file mode 100644 index 00000000..40ef6ece --- /dev/null +++ b/src/metadata_xiph.c @@ -0,0 +1,17 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2022, Philipp "ph3-der-loewe" Schafft + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "metadata_xiph.h" + +#include "logging.h" +#define CATMODULE "metadata-xiph" + diff --git a/src/metadata_xiph.h b/src/metadata_xiph.h new file mode 100644 index 00000000..5386c1fc --- /dev/null +++ b/src/metadata_xiph.h @@ -0,0 +1,12 @@ +/* Icecast + * + * This program is distributed under the GNU General Public License, version 2. + * A copy of this license is included with this source. + * + * Copyright 2022, Philipp "ph3-der-loewe" Schafft + */ + +#ifndef __METADATA_XIPH_H__ +#define __METADATA_XIPH_H__ + +#endif From e169a7d020487bd94219ef5eac2341821d993d5a Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 16 Mar 2022 00:43:40 +0000 Subject: [PATCH 08/13] Feature: Added functions to parse vorbis comments --- src/metadata_xiph.c | 85 +++++++++++++++++++++++++++++++++++++++++++++ src/metadata_xiph.h | 11 ++++++ 2 files changed, 96 insertions(+) diff --git a/src/metadata_xiph.c b/src/metadata_xiph.c index 40ef6ece..608177c0 100644 --- a/src/metadata_xiph.c +++ b/src/metadata_xiph.c @@ -10,8 +10,93 @@ #include #endif +#include +#include + #include "metadata_xiph.h" #include "logging.h" #define CATMODULE "metadata-xiph" +uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in) +{ + uint32_t ret = 0; + ret += in[3]; + ret <<= 8; + ret += in[2]; + ret <<= 8; + ret += in[1]; + ret <<= 8; + ret += in[0]; + return ret; +} + +bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buffer, size_t len) +{ + bool ret = true; + size_t expected_len = 8; + uint32_t vendor_len; + uint32_t count; + uint32_t i; + char *out_buffer = NULL; + size_t out_buffer_len = 0; + + if (!vc || !buffer || len < expected_len) + return false; + + /* reading vendor tag and discarding it */ + vendor_len = metadata_xiph_read_u32be_unaligned(buffer); + expected_len += vendor_len; + + if (len < expected_len) + return false; + + buffer += 4 + vendor_len; + + count = metadata_xiph_read_u32be_unaligned(buffer); + + expected_len += count * 4; + + if (len < expected_len) + return false; + + buffer += 4; + + for (i = 0; i < count; i++) { + uint32_t comment_len = metadata_xiph_read_u32be_unaligned(buffer); + + buffer += 4; + + expected_len += comment_len; + + if (len < expected_len) { + ret = false; + break; + } + + if (out_buffer_len < comment_len || !out_buffer) { + char *n_out_buffer = realloc(out_buffer, comment_len + 1); + if (!n_out_buffer) { + ret = false; + break; + } + + out_buffer = n_out_buffer; + out_buffer_len = comment_len; + } + + memcpy(out_buffer, buffer, comment_len); + out_buffer[comment_len] = 0; + buffer += comment_len; + + vorbis_comment_add(vc, out_buffer); + } + + if (!ret) { + free(out_buffer); + vorbis_comment_clear(vc); + vorbis_comment_init(vc); + } + + return ret; +} diff --git a/src/metadata_xiph.h b/src/metadata_xiph.h index 5386c1fc..a9c60806 100644 --- a/src/metadata_xiph.h +++ b/src/metadata_xiph.h @@ -9,4 +9,15 @@ #ifndef __METADATA_XIPH_H__ #define __METADATA_XIPH_H__ +#include +#include +#include /* for size_t */ + +#include + +uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in); + +/* returns true if parsing was successful, *vc must be in inited state before and will be in inited state after (even when false is returned) */ +bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buffer, size_t len); + #endif From 873e462035d4708ca7f023ac877af379a307faaa Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 16 Mar 2022 01:00:39 +0000 Subject: [PATCH 09/13] Cleanup: Migrated Opus support to new metadata_xiph --- src/format_opus.c | 93 +++-------------------------------------------- 1 file changed, 5 insertions(+), 88 deletions(-) diff --git a/src/format_opus.c b/src/format_opus.c index a1d3d27a..9d12b677 100644 --- a/src/format_opus.c +++ b/src/format_opus.c @@ -7,7 +7,7 @@ * * Copyright 2012, David Richards, Mozilla Foundation, * and others (see AUTHORS for details). - * Copyright 2014-2018, Philipp "ph3-der-loewe" Schafft , + * Copyright 2014-2022, Philipp "ph3-der-loewe" Schafft , */ @@ -21,6 +21,7 @@ #include #include +#include "metadata_xiph.h" #include "format_opus.h" #include "stats.h" #include "refbuf.h" @@ -37,19 +38,6 @@ static void opus_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) free(codec); } -static uint32_t __read_header_u32be_unaligned(const unsigned char *in) -{ - uint32_t ret = 0; - ret += in[3]; - ret <<= 8; - ret += in[2]; - ret <<= 8; - ret += in[1]; - ret <<= 8; - ret += in[0]; - return ret; -} - static void __handle_header_opushead(ogg_state_t *ogg_info, ogg_packet *packet) { if (packet->bytes < 19) { @@ -63,17 +51,12 @@ static void __handle_header_opushead(ogg_state_t *ogg_info, ogg_packet *packet) } stats_event_args(ogg_info->mount, "audio_channels", "%ld", (long int)packet->packet[9]); - stats_event_args(ogg_info->mount, "audio_samplerate", "%ld", (long int)__read_header_u32be_unaligned(packet->packet+12)); + stats_event_args(ogg_info->mount, "audio_samplerate", "%ld", (long int)metadata_xiph_read_u32be_unaligned(packet->packet+12)); } static void __handle_header_opustags(ogg_state_t *ogg_info, ogg_packet *packet, format_plugin_t *plugin) { - size_t comments; - size_t next; size_t left = packet->bytes; - size_t buflen = 0; - char *buf = NULL; - char *buf_new; const void *p = packet->packet; if (packet->bytes < 16) { @@ -85,77 +68,11 @@ static void __handle_header_opustags(ogg_state_t *ogg_info, ogg_packet *packet, p += 8; left -= 8; - /* Now the vendor string follows. We just skip it. */ - next = __read_header_u32be_unaligned(p); - p += 4; - left -= 4; - - if (left < (next + 4)) { - ICECAST_LOG_WARN("Bad Opus header: corrupted OpusTags header."); - return; - } - p += next; - left -= next; - - /* Next is the comment counter. */ - comments = __read_header_u32be_unaligned(p); - p += 4; - left -= 4; - - /* Ok, next (comments) blocks follows, each composed of 4 byte length followed by the data */ - if (left < (comments * 4)) { - ICECAST_LOG_WARN("Bad Opus header: corrupted OpusTags header."); - return; - } - vorbis_comment_clear(&plugin->vc); vorbis_comment_init(&plugin->vc); - - while (comments) { - next = __read_header_u32be_unaligned(p); - p += 4; - left -= 4; - - if (left < next) { - if (buf) - free(buf); - vorbis_comment_clear(&plugin->vc); - vorbis_comment_init(&plugin->vc); - ICECAST_LOG_WARN("Bad Opus header: corrupted OpusTags header."); - return; - } - - if ((next + 1) > buflen) { - buf_new = realloc(buf, next + 1); - if (buf_new) { - buf = buf_new; - buflen = next + 1; - } - } - - if (buflen >= (next + 1)) { - memcpy(buf, p, next); - buf[next] = 0; - vorbis_comment_add(&plugin->vc, buf); - } - - p += next; - left -= next; - - comments--; - if (comments && left < 4) { - if (buf) - free(buf); - vorbis_comment_clear(&plugin->vc); - vorbis_comment_init(&plugin->vc); - ICECAST_LOG_WARN("Bad Opus header: corrupted OpusTags header."); - return; - } + if (!metadata_xiph_read_vorbis_comments(&plugin->vc, p, left)) { + ICECAST_LOG_WARN("Bad Opus header: corrupted OpusTags header."); } - - if (buf) - free(buf); - ogg_info->log_metadata = 1; } From 595179a248b032ffc4f33b8f98afb88a472093dc Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 16 Mar 2022 01:01:03 +0000 Subject: [PATCH 10/13] Feature: Added support for FLAC VORBIS_COMMENT --- src/format_flac.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/format_flac.c b/src/format_flac.c index 04bd0a7d..436c28cf 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -25,6 +25,7 @@ #include #include "refbuf.h" +#include "metadata_xiph.h" #include "format_ogg.h" #include "client.h" #include "stats.h" @@ -126,9 +127,20 @@ static const char * flac_block_type_to_name(flac_block_type_t type) return ""; } -static void flac_handle_block(ogg_state_t *ogg_info, ogg_codec_t *codec, const flac_block_t *block) +static void flac_handle_block(format_plugin_t *plugin, ogg_state_t *ogg_info, ogg_codec_t *codec, const flac_block_t *block) { ICECAST_LOG_DEBUG("Found header of type %s%s with %zu bytes of data", flac_block_type_to_name(block->type), block->last ? "(last)" : "", block->len); + + switch (block->type) { + case FLAC_BLOCK_TYPE_VORBIS_COMMENT: + vorbis_comment_clear(&plugin->vc); + vorbis_comment_init(&plugin->vc); + if (!metadata_xiph_read_vorbis_comments(&plugin->vc, block->data, block->len)) { + ICECAST_LOG_ERROR("Can not parse FLAC header block VORBIS_COMMENT"); + } + ogg_info->log_metadata = 1; + break; + } } static void flac_codec_free (ogg_state_t *ogg_info, ogg_codec_t *codec) @@ -156,7 +168,7 @@ static refbuf_t *process_flac_page (ogg_state_t *ogg_info, ogg_codec_t *codec, o flac_block_t block; if (flac_parse_block(&block, &packet, 0)) { - flac_handle_block(ogg_info, codec, &block); + flac_handle_block(plugin, ogg_info, codec, &block); if (block.last) { codec->headers = 0; @@ -220,7 +232,7 @@ ogg_codec_t *initial_flac_page (format_plugin_t *plugin, ogg_page *page) codec->name = "FLAC"; if (flac_parse_block(&block, &packet, 13)) - flac_handle_block(ogg_info, codec, &block); + flac_handle_block(plugin, ogg_info, codec, &block); format_ogg_attach_header(ogg_info, page); return codec; From 7108aab18bd4a0db0e642e8adc1b7fc7339938e8 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 16 Mar 2022 01:26:38 +0000 Subject: [PATCH 11/13] Fix: Actually use the correct name for the function --- src/format_opus.c | 2 +- src/metadata_xiph.c | 8 ++++---- src/metadata_xiph.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/format_opus.c b/src/format_opus.c index 9d12b677..94c7e0a6 100644 --- a/src/format_opus.c +++ b/src/format_opus.c @@ -51,7 +51,7 @@ static void __handle_header_opushead(ogg_state_t *ogg_info, ogg_packet *packet) } stats_event_args(ogg_info->mount, "audio_channels", "%ld", (long int)packet->packet[9]); - stats_event_args(ogg_info->mount, "audio_samplerate", "%ld", (long int)metadata_xiph_read_u32be_unaligned(packet->packet+12)); + stats_event_args(ogg_info->mount, "audio_samplerate", "%ld", (long int)metadata_xiph_read_u32le_unaligned(packet->packet+12)); } static void __handle_header_opustags(ogg_state_t *ogg_info, ogg_packet *packet, format_plugin_t *plugin) diff --git a/src/metadata_xiph.c b/src/metadata_xiph.c index 608177c0..beeec5b0 100644 --- a/src/metadata_xiph.c +++ b/src/metadata_xiph.c @@ -18,7 +18,7 @@ #include "logging.h" #define CATMODULE "metadata-xiph" -uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in) +uint32_t metadata_xiph_read_u32le_unaligned(const unsigned char *in) { uint32_t ret = 0; ret += in[3]; @@ -45,7 +45,7 @@ bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buff return false; /* reading vendor tag and discarding it */ - vendor_len = metadata_xiph_read_u32be_unaligned(buffer); + vendor_len = metadata_xiph_read_u32le_unaligned(buffer); expected_len += vendor_len; if (len < expected_len) @@ -53,7 +53,7 @@ bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buff buffer += 4 + vendor_len; - count = metadata_xiph_read_u32be_unaligned(buffer); + count = metadata_xiph_read_u32le_unaligned(buffer); expected_len += count * 4; @@ -63,7 +63,7 @@ bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buff buffer += 4; for (i = 0; i < count; i++) { - uint32_t comment_len = metadata_xiph_read_u32be_unaligned(buffer); + uint32_t comment_len = metadata_xiph_read_u32le_unaligned(buffer); buffer += 4; diff --git a/src/metadata_xiph.h b/src/metadata_xiph.h index a9c60806..3c1056b4 100644 --- a/src/metadata_xiph.h +++ b/src/metadata_xiph.h @@ -15,7 +15,7 @@ #include -uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in); +uint32_t metadata_xiph_read_u32le_unaligned(const unsigned char *in); /* returns true if parsing was successful, *vc must be in inited state before and will be in inited state after (even when false is returned) */ bool metadata_xiph_read_vorbis_comments(vorbis_comment *vc, const void *buffer, size_t len); From 5d93c6b97f4fc933c020fa3b2d441ba0881b4599 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 16 Mar 2022 01:28:27 +0000 Subject: [PATCH 12/13] Update: Do not warn about blocks we do not handle --- src/format_flac.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/format_flac.c b/src/format_flac.c index 436c28cf..c88344bd 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -140,6 +140,9 @@ static void flac_handle_block(format_plugin_t *plugin, ogg_state_t *ogg_info, og } ogg_info->log_metadata = 1; break; + default: + /* no-op */ + break; } } From 04f16811e1de827a0c90fabc0cae366ab9810035 Mon Sep 17 00:00:00 2001 From: Philipp Schafft Date: Wed, 16 Mar 2022 01:29:02 +0000 Subject: [PATCH 13/13] Feature: Report data from FLAC block STREAMINFO --- src/format_flac.c | 25 +++++++++++++++++++++++++ src/metadata_xiph.c | 13 +++++++++++++ src/metadata_xiph.h | 1 + 3 files changed, 39 insertions(+) diff --git a/src/format_flac.c b/src/format_flac.c index c88344bd..e8205420 100644 --- a/src/format_flac.c +++ b/src/format_flac.c @@ -127,11 +127,36 @@ static const char * flac_block_type_to_name(flac_block_type_t type) return ""; } +static void flac_handle_block_streaminfo(format_plugin_t *plugin, ogg_state_t *ogg_info, ogg_codec_t *codec, const flac_block_t *block) +{ + uint32_t raw; + uint32_t sample_rate; + uint32_t channels; + uint32_t bits; + + if (block->len != 34) { + ICECAST_LOG_ERROR("Can not parse FLAC header block STREAMINFO"); + return; + } + + raw = metadata_xiph_read_u32be_unaligned(block->data + 10); + sample_rate = ((raw >> 12) & 0xfffff) + 0; + channels = ((raw >> 9) & 0x7 ) + 1; + bits = ((raw >> 4) & 0x1F ) + 1; + + stats_event_args(ogg_info->mount, "audio_samplerate", "%ld", (long int)sample_rate); + stats_event_args(ogg_info->mount, "audio_channels", "%ld", (long int)channels); + stats_event_args(ogg_info->mount, "audio_bits", "%ld", (long int)bits); +} + static void flac_handle_block(format_plugin_t *plugin, ogg_state_t *ogg_info, ogg_codec_t *codec, const flac_block_t *block) { ICECAST_LOG_DEBUG("Found header of type %s%s with %zu bytes of data", flac_block_type_to_name(block->type), block->last ? "(last)" : "", block->len); switch (block->type) { + case FLAC_BLOCK_TYPE_STREAMINFO: + flac_handle_block_streaminfo(plugin, ogg_info, codec, block); + break; case FLAC_BLOCK_TYPE_VORBIS_COMMENT: vorbis_comment_clear(&plugin->vc); vorbis_comment_init(&plugin->vc); diff --git a/src/metadata_xiph.c b/src/metadata_xiph.c index beeec5b0..395f6542 100644 --- a/src/metadata_xiph.c +++ b/src/metadata_xiph.c @@ -18,6 +18,19 @@ #include "logging.h" #define CATMODULE "metadata-xiph" +uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in) +{ + uint32_t ret = 0; + ret += in[0]; + ret <<= 8; + ret += in[1]; + ret <<= 8; + ret += in[2]; + ret <<= 8; + ret += in[3]; + return ret; +} + uint32_t metadata_xiph_read_u32le_unaligned(const unsigned char *in) { uint32_t ret = 0; diff --git a/src/metadata_xiph.h b/src/metadata_xiph.h index 3c1056b4..7127fdca 100644 --- a/src/metadata_xiph.h +++ b/src/metadata_xiph.h @@ -15,6 +15,7 @@ #include +uint32_t metadata_xiph_read_u32be_unaligned(const unsigned char *in); uint32_t metadata_xiph_read_u32le_unaligned(const unsigned char *in); /* returns true if parsing was successful, *vc must be in inited state before and will be in inited state after (even when false is returned) */