Hello community,

here is the log from the commit of package icecast for openSUSE:Factory checked 
in at 2014-11-24 11:09:28
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/icecast (Old)
 and      /work/SRC/openSUSE:Factory/.icecast.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "icecast"

Changes:
--------
--- /work/SRC/openSUSE:Factory/icecast/icecast.changes  2014-11-18 
22:46:01.000000000 +0100
+++ /work/SRC/openSUSE:Factory/.icecast.new/icecast.changes     2014-11-24 
11:10:11.000000000 +0100
@@ -1,0 +2,5 @@
+Sat Nov 22 12:44:18 UTC 2014 - fi...@opensuse.org
+
+- Add icecast-mp3-frame-validation.patch: validate mp3 frame.
+
+-------------------------------------------------------------------

New:
----
  icecast-mp3-frame-validation.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ icecast.spec ++++++
--- /var/tmp/diff_new_pack.o5gyAf/_old  2014-11-24 11:10:12.000000000 +0100
+++ /var/tmp/diff_new_pack.o5gyAf/_new  2014-11-24 11:10:12.000000000 +0100
@@ -35,6 +35,8 @@
 Patch3:         icecast-add_pidfile_directive.patch
 # PATCH-FIX-UPSTREAM -- Produce valid json status, already in upstream trunk 
svn. boo#905468.
 Patch4:         icecast-2.4.0-produce-valid-json.patch
+# PATCH-FEATURE-OPENSUSE -- mp3 frame validation
+Patch100:       icecast-mp3-frame-validation.patch
 BuildRequires:  curl-devel
 BuildRequires:  libtheora-devel
 BuildRequires:  libtool
@@ -79,6 +81,7 @@
 %patch1
 %patch3
 %patch4
+%patch100
 
 %build
 autoreconf -fiv

++++++ icecast-mp3-frame-validation.patch ++++++
Description: MP3 Frame validation
Author: Paul Kelly <p...@stjohnspoint.co.uk>

Icecast does not make any attempt to demarcate the boundaries between MP3 
frames, and when a listening client connects to the server it generally is 
sent an initial partial frame that can't be decoded. This is not a problem 
for almost all client players.

It becomes a problem however when a "pre-roll" intro clip is used. When 
Icecast connects the listener to the main stream after playing the intro 
clip, it will very likely cut in in the middle of a frame, which causes a 
problem for some players. Flash player in particular exhibits strange 
behaviour with the audio cutting in and out every few seconds. Pausing the 
player and resuming cures the problem.

http://lists.xiph.org/pipermail//icecast-dev/2011-October/001998.html

Index: src/format_mp3.c
===================================================================
--- src/format_mp3.c.orig
+++ src/format_mp3.c
@@ -509,6 +509,161 @@ static int complete_read (source_t *sour
     return 1;
 }
 
+static int bitrate_table[2][3][14] =
+{
+    {
+        /* MPEG-2 Layer III */
+        { 8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160},
+        /* MPEG-2 Layer II */
+        { 8, 16, 24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160},
+        /* MPEG-2 Layer I */
+        {32, 48, 56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256}
+    },
+    {
+        /* MPEG-1 Layer III */
+        {32, 40, 48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320},
+        /* MPEG-1 Layer II */
+        {32, 48, 56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384},
+        /* MPEG-1 Layer I */
+        {32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}
+    }
+};
+
+static int samplerate_table[4][3] =
+{
+    {11025, 12000,  8000}, /* MPEG-2 LSF */
+    {    0,     0,     0}, /* Reserved */
+    {22050, 24000, 16000}, /* MPEG-2 */
+    {44100, 48000, 32000}  /* MPEG-1 */
+};
+
+static int framesize_table[2][3] =
+{
+    /* L.III  L.II   L.I */
+    {  576, 1152,  384}, /* MPEG-2 */
+    { 1152, 1152,  384}  /* MPEG-1 */
+};
+
+static int slotsize_table[3] =
+{
+    1, /* L. III */
+    1, /* L. II  */
+    4  /* L. I   */
+};
+
+static int validate_header(mpeg_frame_t *fr)
+{
+    unsigned char version_code, layer_code, bitrate_code,
+                  samplerate_code, padding;
+    char message[200];
+
+#define MAX_FRAME_LEN 2880  /* 160kbps Layer II @ 8kHz */
+
+    /* Check sync word is present */
+    if (fr->data[0] != 0xff || (fr->data[1] & 0xe0) != 0xe0)
+        goto invalid_frame;
+
+    /* Validate header by checking no reserved values are present */
+    if ( (version_code    = (fr->data[1] & 0x18) >> 3) ==  1
+      || (layer_code      = (fr->data[1] & 0x06) >> 1) ==  0
+      || (bitrate_code    = (fr->data[2] & 0xf0) >> 4) == 15
+      || (samplerate_code = (fr->data[2] & 0x0c) >> 2) ==  3)
+        goto invalid_frame;
+
+    if (bitrate_code == 0) /* Free-format bitrate */
+        /* We can't calculate the frame length anyway from this so can go no
+         * further with validation, so return the header as invalid. This is
+         * arguably a bug. */
+        goto invalid_frame;
+
+    /* Calculate data length of frame */
+    fr->kbps = bitrate_table[version_code & 1][layer_code - 1][bitrate_code - 
1];
+    fr->sample_rate_Hz = samplerate_table[version_code][samplerate_code];
+    padding = (fr->data[2] & 0x02) >> 1;
+    fr->bytes = (framesize_table[version_code & 1][layer_code - 1] / 8
+            / slotsize_table[layer_code - 1] * fr->kbps * 1000
+            / fr->sample_rate_Hz + padding) * slotsize_table[layer_code - 1];
+
+    if (fr->bytes <= 0 || fr->bytes > MAX_FRAME_LEN)
+        goto invalid_frame;
+
+    if ((fr->data[3] & 0xc0) >> 6 == 3) /* mono */
+        fr->channels = 1;
+    else
+        fr->channels = 2;
+
+    return fr->bytes;
+
+invalid_frame:
+    fr->bytes = -1;
+    return -1;
+}
+
+/* Parse the MP3 data (also handles MPEG audio layers I/II) to check if there
+ * is a partial frame at the end of the data. If so the partial data is stored
+ * in the MP3 state (where it will be appended to the next time complete_read()
+ * is called) and the modified refbuf containing only complete frames is
+ * returned.
+ * Note that incomplete frames occuring at the *start* of the data buffer are
+ * ignored. This is so that huge frames (greater than the REFBUF size) can 
still
+ * be handled correctly.
+ */
+static void remove_partial_frames(refbuf_t *refbuf, mp3_state *source_mp3)
+{
+    int frame_offset = 0, valid_frames = 0;
+
+    /* while there are enough bytes remaining for a valid header */
+    while (refbuf->len - frame_offset >= 4)
+    {
+        mpeg_frame_t fr;
+
+        /* check the header is valid and determine the total frame length */
+        fr.data = (unsigned char *)refbuf->data+frame_offset;
+        validate_header(&fr);
+
+        /* If any frames are bigger than the refbuf size, then we need to leave
+         * them intact and just put up with the fact they will be split up. 
Such
+         * huge frames should be very rare in practice. */
+        if (fr.bytes > REFBUF_SIZE)
+            return;
+
+        if (fr.bytes > 0) /* if header is valid */
+        {
+            if(frame_offset + fr.bytes > refbuf->len)
+                /* this frame extends beyond the buffer */
+                break;
+
+            valid_frames++;
+            /* Skip to start of next frame */
+            frame_offset += fr.bytes;
+            continue;
+        }
+
+        /* Validation failed: shift forward by one byte and keep searching for 
header */
+        frame_offset++;
+    }
+
+    if (frame_offset == refbuf->len || valid_frames == 0)
+        /* buffer contained only either wholly complete or wholly partial 
frames */
+        return;
+
+    /* Allocate a new refbuf to hold the partial last frame. When 
complete_read()
+     * is called again it will append to this. */
+    source_mp3->read_data = refbuf_new (REFBUF_SIZE);
+    source_mp3->read_count = refbuf->len - frame_offset;
+
+    /* Copy the partial frame into the new refbuf and reduce the byte count for
+     * the existing refbuf accordingly. */
+    memcpy (source_mp3->read_data->data, refbuf->data+frame_offset,
+            source_mp3->read_count);
+    refbuf->len = frame_offset;
+
+    /* Finally adjust the metadata interval offset to avoid "double-counting" 
of
+     * the bytes in the partial frame. */
+    source_mp3->offset -= source_mp3->read_count;
+
+    return;
+}
 
 /* read an mp3 stream which does not have shoutcast style metadata */
 static refbuf_t *mp3_get_no_meta (source_t *source)
@@ -529,7 +684,10 @@ static refbuf_t *mp3_get_no_meta (source
     }
     refbuf->associated = source_mp3->metadata;
     refbuf_addref (source_mp3->metadata);
+
+    remove_partial_frames(refbuf, source_mp3);
     refbuf->sync_point = 1;
+
     return refbuf;
 }
 
@@ -650,6 +808,8 @@ static refbuf_t *mp3_get_filter_meta (so
     }
     refbuf->associated = source_mp3->metadata;
     refbuf_addref (source_mp3->metadata);
+
+    remove_partial_frames(refbuf, source_mp3);
     refbuf->sync_point = 1;
 
     return refbuf;
Index: src/format_mp3.h
===================================================================
--- src/format_mp3.h.orig
+++ src/format_mp3.h
@@ -39,6 +39,16 @@ typedef struct {
     char build_metadata[4081];
 } mp3_state;
 
+typedef struct
+{
+    unsigned char *data; /* Pointer to complete MPEG audio frame (including
+                          * sync word and header */
+    int bytes;           /* Length of MPEG frame in bytes */
+    int kbps;            /* Bitrate in kilobits per second */
+    int sample_rate_Hz;  /* Sample rate in hertz */
+    int channels;        /* Number of channels (mono/stereo) */
+} mpeg_frame_t;
+
 int format_mp3_get_plugin(struct source_tag *src);
 
 #endif  /* __FORMAT_MP3_H__ */
-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to