|
Packit Service |
102f81 |
/* -*- c-basic-offset: 8; -*- */
|
|
Packit Service |
102f81 |
/* mp3.c: libshout MP3 format handler
|
|
Packit Service |
102f81 |
* $Id: mp3.c 7259 2004-07-22 18:49:41Z brendan $
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* Copyright (C) 2002-2003 the Icecast team <team@icecast.org>
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* This library is free software; you can redistribute it and/or
|
|
Packit Service |
102f81 |
* modify it under the terms of the GNU Library General Public
|
|
Packit Service |
102f81 |
* License as published by the Free Software Foundation; either
|
|
Packit Service |
102f81 |
* version 2 of the License, or (at your option) any later version.
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* This library is distributed in the hope that it will be useful,
|
|
Packit Service |
102f81 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
102f81 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit Service |
102f81 |
* Library General Public License for more details.
|
|
Packit Service |
102f81 |
*
|
|
Packit Service |
102f81 |
* You should have received a copy of the GNU Library General Public
|
|
Packit Service |
102f81 |
* License along with this library; if not, write to the Free
|
|
Packit Service |
102f81 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
Packit Service |
102f81 |
*/
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#include <stdio.h>
|
|
Packit Service |
102f81 |
#include <stdlib.h>
|
|
Packit Service |
102f81 |
#include <string.h>
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#include <shout/shout.h>
|
|
Packit Service |
102f81 |
#include "shout_private.h"
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/*
|
|
Packit Service |
102f81 |
* MP3 frame handling courtesy of Scott Manley - may he always be Manley.
|
|
Packit Service |
102f81 |
*/
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
#define MPEG_MODE_MONO 3
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* -- local datatypes -- */
|
|
Packit Service |
102f81 |
typedef struct {
|
|
Packit Service |
102f81 |
unsigned int frames;
|
|
Packit Service |
102f81 |
/* the number of samples for the current frame */
|
|
Packit Service |
102f81 |
int frame_samples;
|
|
Packit Service |
102f81 |
/* the samplerate of the current frame */
|
|
Packit Service |
102f81 |
int frame_samplerate;
|
|
Packit Service |
102f81 |
/* how many bytes for the rest of this frame */
|
|
Packit Service |
102f81 |
unsigned int frame_left;
|
|
Packit Service |
102f81 |
/* is the header bridged?? */
|
|
Packit Service |
102f81 |
int header_bridges;
|
|
Packit Service |
102f81 |
/* put part of header here if it spans a boundary */
|
|
Packit Service |
102f81 |
unsigned char header_bridge[3];
|
|
Packit Service |
102f81 |
} mp3_data_t;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
typedef struct {
|
|
Packit Service |
102f81 |
int syncword;
|
|
Packit Service |
102f81 |
int layer;
|
|
Packit Service |
102f81 |
int version;
|
|
Packit Service |
102f81 |
int error_protection;
|
|
Packit Service |
102f81 |
int bitrate_index;
|
|
Packit Service |
102f81 |
int samplerate_index;
|
|
Packit Service |
102f81 |
int padding;
|
|
Packit Service |
102f81 |
int extension;
|
|
Packit Service |
102f81 |
int mode;
|
|
Packit Service |
102f81 |
int mode_ext;
|
|
Packit Service |
102f81 |
int copyright;
|
|
Packit Service |
102f81 |
int original;
|
|
Packit Service |
102f81 |
int emphasis;
|
|
Packit Service |
102f81 |
int stereo;
|
|
Packit Service |
102f81 |
int bitrate;
|
|
Packit Service |
102f81 |
unsigned int samplerate;
|
|
Packit Service |
102f81 |
unsigned int samples;
|
|
Packit Service |
102f81 |
unsigned int framesize;
|
|
Packit Service |
102f81 |
} mp3_header_t;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* -- const data -- */
|
|
Packit Service |
102f81 |
static const unsigned int bitrate[3][3][16] =
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
{ 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 0 },
|
|
Packit Service |
102f81 |
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 0 },
|
|
Packit Service |
102f81 |
{ 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0 }
|
|
Packit Service |
102f81 |
}, {
|
|
Packit Service |
102f81 |
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 },
|
|
Packit Service |
102f81 |
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
|
|
Packit Service |
102f81 |
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }
|
|
Packit Service |
102f81 |
}, {
|
|
Packit Service |
102f81 |
{ 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 0 },
|
|
Packit Service |
102f81 |
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 },
|
|
Packit Service |
102f81 |
{ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0 }
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
};
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static const unsigned int samplerate[3][4] =
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
{ 44100, 48000, 32000, 0 },
|
|
Packit Service |
102f81 |
{ 22050, 24000, 16000, 0 },
|
|
Packit Service |
102f81 |
{ 11025, 8000, 8000, 0 }
|
|
Packit Service |
102f81 |
};
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* -- static prototypes -- */
|
|
Packit Service |
102f81 |
static int send_mp3(shout_t *self, const unsigned char *data, size_t len);
|
|
Packit Service |
102f81 |
static void close_mp3(shout_t *self);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static void parse_header(mp3_header_t *mh, uint32_t header);
|
|
Packit Service |
102f81 |
static int mp3_header(uint32_t head, mp3_header_t *mh);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
int shout_open_mp3(shout_t *self)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
mp3_data_t *mp3_data;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (!(mp3_data = (mp3_data_t *)calloc(1, sizeof(mp3_data_t))))
|
|
Packit Service |
102f81 |
return SHOUTERR_MALLOC;
|
|
Packit Service |
102f81 |
self->format_data = mp3_data;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
self->send = send_mp3;
|
|
Packit Service |
102f81 |
self->close = close_mp3;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return SHOUTERR_SUCCESS;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static int send_mp3(shout_t* self, const unsigned char* buff, size_t len)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
mp3_data_t* mp3_data = (mp3_data_t*) self->format_data;
|
|
Packit Service |
102f81 |
unsigned long pos;
|
|
Packit Service |
102f81 |
uint32_t head;
|
|
Packit Service |
102f81 |
int ret, count;
|
|
Packit Service |
102f81 |
int start, end, error, i;
|
|
Packit Service |
102f81 |
unsigned char *bridge_buff;
|
|
Packit Service |
102f81 |
mp3_header_t mh;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
bridge_buff = NULL;
|
|
Packit Service |
102f81 |
pos = 0;
|
|
Packit Service |
102f81 |
start = 0;
|
|
Packit Service |
102f81 |
error = 0;
|
|
Packit Service |
102f81 |
end = len - 1;
|
|
Packit Service |
102f81 |
memset(&mh, 0, sizeof(mh));
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* finish the previous frame */
|
|
Packit Service |
102f81 |
if (mp3_data->frame_left > 0) {
|
|
Packit Service |
102f81 |
/* is the rest of the frame here? */
|
|
Packit Service |
102f81 |
if (mp3_data->frame_left <= len) {
|
|
Packit Service |
102f81 |
self->senttime += (int64_t)((double)mp3_data->frame_samples / (double)mp3_data->frame_samplerate * 1000000);
|
|
Packit Service |
102f81 |
mp3_data->frames++;
|
|
Packit Service |
102f81 |
pos += mp3_data->frame_left;
|
|
Packit Service |
102f81 |
mp3_data->frame_left = 0;
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
mp3_data->frame_left -= len;
|
|
Packit Service |
102f81 |
pos = len;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* header was over the boundary, so build a new build a new buffer */
|
|
Packit Service |
102f81 |
if (mp3_data->header_bridges) {
|
|
Packit Service |
102f81 |
bridge_buff = (unsigned char *)malloc(len + mp3_data->header_bridges);
|
|
Packit Service |
102f81 |
if (bridge_buff == NULL) {
|
|
Packit Service |
102f81 |
return self->error = SHOUTERR_MALLOC;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
bridge_buff[0] = mp3_data->header_bridge[0];
|
|
Packit Service |
102f81 |
bridge_buff[1] = mp3_data->header_bridge[1];
|
|
Packit Service |
102f81 |
bridge_buff[2] = mp3_data->header_bridge[2];
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
memcpy(&bridge_buff[mp3_data->header_bridges], buff, len);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
buff = bridge_buff;
|
|
Packit Service |
102f81 |
len += mp3_data->header_bridges;
|
|
Packit Service |
102f81 |
end = len - 1;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
mp3_data->header_bridges = 0;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/** this is the main loop
|
|
Packit Service |
102f81 |
*** we handle everything but the last 4 bytes...
|
|
Packit Service |
102f81 |
**/
|
|
Packit Service |
102f81 |
while ((pos + 4) <= len) {
|
|
Packit Service |
102f81 |
/* find mp3 header */
|
|
Packit Service |
102f81 |
head = (buff[pos] << 24) |
|
|
Packit Service |
102f81 |
(buff[pos + 1] << 16) |
|
|
Packit Service |
102f81 |
(buff[pos + 2] << 8) |
|
|
Packit Service |
102f81 |
(buff[pos + 3]);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* is this a valid header? */
|
|
Packit Service |
102f81 |
if (mp3_header(head, &mh)) {
|
|
Packit Service |
102f81 |
if (error) {
|
|
Packit Service |
102f81 |
start = pos;
|
|
Packit Service |
102f81 |
end = len - 1;
|
|
Packit Service |
102f81 |
error = 0;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
mp3_data->frame_samples = mh.samples;
|
|
Packit Service |
102f81 |
mp3_data->frame_samplerate = mh.samplerate;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* do we have a complete frame in this buffer? */
|
|
Packit Service |
102f81 |
if (len - pos >= mh.framesize) {
|
|
Packit Service |
102f81 |
self->senttime += (int64_t)((double)mp3_data->frame_samples / (double)mp3_data->frame_samplerate * 1000000);
|
|
Packit Service |
102f81 |
mp3_data->frames++;
|
|
Packit Service |
102f81 |
pos += mh.framesize;
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
mp3_data->frame_left = mh.framesize - (len - pos);
|
|
Packit Service |
102f81 |
pos = len;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
/* there was an error
|
|
Packit Service |
102f81 |
** so we send all the valid data up to this point
|
|
Packit Service |
102f81 |
*/
|
|
Packit Service |
102f81 |
if (!error) {
|
|
Packit Service |
102f81 |
error = 1;
|
|
Packit Service |
102f81 |
end = pos - 1;
|
|
Packit Service |
102f81 |
count = end - start + 1;
|
|
Packit Service |
102f81 |
if (count > 0)
|
|
Packit Service |
102f81 |
ret = shout_send_raw(self, (char *)&buff[start], count);
|
|
Packit Service |
102f81 |
else
|
|
Packit Service |
102f81 |
ret = 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (ret != count) {
|
|
Packit Service |
102f81 |
if (bridge_buff != NULL)
|
|
Packit Service |
102f81 |
free(bridge_buff);
|
|
Packit Service |
102f81 |
return self->error = SHOUTERR_SOCKET;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
pos++;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* catch the tail if there is one */
|
|
Packit Service |
102f81 |
if ((pos > (len - 4)) && (pos < len)) {
|
|
Packit Service |
102f81 |
end = pos - 1;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
i = 0;
|
|
Packit Service |
102f81 |
while (pos < len) {
|
|
Packit Service |
102f81 |
mp3_data->header_bridge[i] = buff[pos];
|
|
Packit Service |
102f81 |
pos++;
|
|
Packit Service |
102f81 |
i++;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
mp3_data->header_bridges = i;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (!error) {
|
|
Packit Service |
102f81 |
/* if there's no errors, lets send the frames */
|
|
Packit Service |
102f81 |
count = end - start + 1;
|
|
Packit Service |
102f81 |
if (count > 0)
|
|
Packit Service |
102f81 |
ret = shout_send_raw(self, (char *)&buff[start], count);
|
|
Packit Service |
102f81 |
else
|
|
Packit Service |
102f81 |
ret = 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (bridge_buff != NULL)
|
|
Packit Service |
102f81 |
free(bridge_buff);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (ret == count) {
|
|
Packit Service |
102f81 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit Service |
102f81 |
} else {
|
|
Packit Service |
102f81 |
return self->error = SHOUTERR_SOCKET;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (bridge_buff != NULL)
|
|
Packit Service |
102f81 |
free(bridge_buff);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return self->error = SHOUTERR_SUCCESS;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static void parse_header(mp3_header_t *mh, uint32_t header)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
mh->syncword = (header >> 20) & 0x0fff;
|
|
Packit Service |
102f81 |
mh->version = ((header >> 19) & 0x01) ? 0 : 1;
|
|
Packit Service |
102f81 |
if ((mh->syncword & 0x01) == 0)
|
|
Packit Service |
102f81 |
mh->version = 2;
|
|
Packit Service |
102f81 |
mh->layer = 3 - ((header >> 17) & 0x03);
|
|
Packit Service |
102f81 |
mh->error_protection = ((header >> 16) & 0x01) ? 0 : 1;
|
|
Packit Service |
102f81 |
mh->bitrate_index = (header >> 12) & 0x0F;
|
|
Packit Service |
102f81 |
mh->samplerate_index = (header >> 10) & 0x03;
|
|
Packit Service |
102f81 |
mh->padding = (header >> 9) & 0x01;
|
|
Packit Service |
102f81 |
mh->extension = (header >> 8) & 0x01;
|
|
Packit Service |
102f81 |
mh->mode = (header >> 6) & 0x03;
|
|
Packit Service |
102f81 |
mh->mode_ext = (header >> 4) & 0x03;
|
|
Packit Service |
102f81 |
mh->copyright = (header >> 3) & 0x01;
|
|
Packit Service |
102f81 |
mh->original = (header >> 2) & 0x01;
|
|
Packit Service |
102f81 |
mh->emphasis = header & 0x03;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
mh->stereo = (mh->mode == MPEG_MODE_MONO) ? 1 : 2;
|
|
Packit Service |
102f81 |
mh->bitrate = bitrate[mh->version][mh->layer][mh->bitrate_index];
|
|
Packit Service |
102f81 |
mh->samplerate = samplerate[mh->version][mh->samplerate_index];
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if (mh->version == 0)
|
|
Packit Service |
102f81 |
mh->samples = 1152;
|
|
Packit Service |
102f81 |
else
|
|
Packit Service |
102f81 |
mh->samples = 576;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
if(mh->samplerate)
|
|
Packit Service |
102f81 |
mh->framesize = (mh->samples * mh->bitrate * 1000 / mh->samplerate) / 8 + mh->padding;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* mp3 frame parsing stuff */
|
|
Packit Service |
102f81 |
static int mp3_header(uint32_t head, mp3_header_t *mh)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
/* fill out the header struct */
|
|
Packit Service |
102f81 |
parse_header(mh, head);
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* check for syncword */
|
|
Packit Service |
102f81 |
if ((mh->syncword & 0x0ffe) != 0x0ffe)
|
|
Packit Service |
102f81 |
return 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* check for the right layer */
|
|
Packit Service |
102f81 |
if (mh->layer != 2)
|
|
Packit Service |
102f81 |
return 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* make sure bitrate is sane */
|
|
Packit Service |
102f81 |
if (mh->bitrate == 0)
|
|
Packit Service |
102f81 |
return 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
/* make sure samplerate is sane */
|
|
Packit Service |
102f81 |
if (mh->samplerate == 0)
|
|
Packit Service |
102f81 |
return 0;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
return 1;
|
|
Packit Service |
102f81 |
}
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
static void close_mp3(shout_t *self)
|
|
Packit Service |
102f81 |
{
|
|
Packit Service |
102f81 |
mp3_data_t *mp3_data = (mp3_data_t *)self->format_data;
|
|
Packit Service |
102f81 |
|
|
Packit Service |
102f81 |
free(mp3_data);
|
|
Packit Service |
102f81 |
}
|