You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
389 lines
11 KiB
389 lines
11 KiB
commit 4d0682030e20a8ed218f4ff924554f93d276d9ee
|
|
Author: Anthony Garcia <lagg@lavabit.com>
|
|
Date: Thu Apr 22 16:59:37 2010 -0700
|
|
|
|
OTHER: Cleanup
|
|
|
|
Re-enabled nellymoser (ffmpeg appears to be okay with it now)
|
|
|
|
Fixed possible infinite loop in the code that handles the data (if any)
|
|
between the header and tag data.
|
|
|
|
diff --git a/src/plugins/avcodec/avcodec.c b/src/plugins/avcodec/avcodec.c
|
|
index 6c9fea8..5554056 100644
|
|
--- a/src/plugins/avcodec/avcodec.c
|
|
+++ b/src/plugins/avcodec/avcodec.c
|
|
@@ -90,7 +90,7 @@ xmms_avcodec_plugin_setup (xmms_xform_plugin_t *xform_plugin)
|
|
xmms_magic_add ("A/52 (AC-3) header", "audio/x-ffmpeg-ac3",
|
|
"0 beshort 0x0b77", NULL);
|
|
xmms_magic_add ("DTS header", "audio/x-ffmpeg-dca",
|
|
- "0 belong 0x7ffe8001", NULL);
|
|
+ "0 belong 0x7ffe8001", NULL);
|
|
|
|
xmms_xform_plugin_indata_add (xform_plugin,
|
|
XMMS_STREAM_TYPE_MIMETYPE,
|
|
@@ -197,7 +197,8 @@ xmms_avcodec_init (xmms_xform_t *xform)
|
|
!strcmp (data->codec_id, "adpcm_swf") ||
|
|
!strcmp (data->codec_id, "pcm_s16le") ||
|
|
!strcmp (data->codec_id, "ac3") ||
|
|
- !strcmp (data->codec_id, "dca")) {
|
|
+ !strcmp (data->codec_id, "dca") ||
|
|
+ !strcmp (data->codec_id, "nellymoser")) {
|
|
/* number 1024 taken from libavformat raw.c RAW_PACKET_SIZE */
|
|
data->extradata = g_malloc0 (1024);
|
|
data->extradata_size = 1024;
|
|
diff --git a/src/plugins/flv/flv.c b/src/plugins/flv/flv.c
|
|
index 440010c..266fea6 100644
|
|
--- a/src/plugins/flv/flv.c
|
|
+++ b/src/plugins/flv/flv.c
|
|
@@ -25,29 +25,41 @@
|
|
* and other info, then data
|
|
*/
|
|
#define FLV_TAG_SIZE 11
|
|
-/* random constant */
|
|
#define FLV_CHUNK_SIZE 4096
|
|
|
|
-/* let libavcodec take care of swapping sample bytes */
|
|
-static const gchar *mime_pcm_s16le = "audio/x-ffmpeg-pcm_s16le";
|
|
-static const gchar *fmt_mime[11] = {
|
|
- /* Supported when samples are 8 bit
|
|
- * (otherwise there's no way of knowing endianness)
|
|
- */
|
|
- "audio/pcm",
|
|
- "audio/x-ffmpeg-adpcm_swf",
|
|
- "audio/mpeg",
|
|
- /* if bps is 8 bit u8
|
|
- * if bps is 16 bit sle16
|
|
- */
|
|
- "audio/pcm",
|
|
- /* libavcodec can't handle nelly without dying yet */
|
|
- /*"audio/x-ffmpeg-nellymoser",
|
|
- "audio/x-ffmpeg-nellymoser",
|
|
- "audio/x-ffmpeg-nellymoser",*/
|
|
- "", "", "",
|
|
- "", "", "",
|
|
- "audio/aac"
|
|
+typedef enum {
|
|
+ /* Only u8 bit samples since
|
|
+ there's no way to determine endianness
|
|
+ */
|
|
+ CODEC_PCM_HOST,
|
|
+ CODEC_ADPCM,
|
|
+ CODEC_MP3,
|
|
+ /* 8 bps: unsigned
|
|
+ 16 bps: signed
|
|
+ */
|
|
+ CODEC_PCM_LE,
|
|
+ CODEC_NELLYMOSER_16K,
|
|
+ CODEC_NELLYMOSER_8K,
|
|
+ /* Uses the sample rate in
|
|
+ the tag as normal
|
|
+ */
|
|
+ CODEC_NELLYMOSER,
|
|
+ CODEC_AAC = 10
|
|
+} xmms_flv_codec_id;
|
|
+
|
|
+struct xmms_flv_codec_table {
|
|
+ xmms_flv_codec_id id;
|
|
+ const gchar *mime;
|
|
+} static flv_codecs[] = {
|
|
+ {CODEC_PCM_HOST, "audio/pcm"},
|
|
+ {CODEC_ADPCM, "audio/x-ffmpeg-adpcm_swf"},
|
|
+ {CODEC_MP3, "audio/mpeg"},
|
|
+ /* Will be audio/x-ffmpeg-pcm_s16le if bps is 16 */
|
|
+ {CODEC_PCM_LE, "audio/pcm"},
|
|
+ {CODEC_NELLYMOSER_16K, "audio/x-ffmpeg-nellymoser"},
|
|
+ {CODEC_NELLYMOSER_8K, "audio/x-ffmpeg-nellymoser"},
|
|
+ {CODEC_NELLYMOSER, "audio/x-ffmpeg-nellymoser"},
|
|
+ {CODEC_AAC, "audio/aac"}
|
|
};
|
|
|
|
typedef struct {
|
|
@@ -111,23 +123,26 @@ static gboolean
|
|
xmms_flv_init (xmms_xform_t *xform)
|
|
{
|
|
xmms_sample_format_t bps;
|
|
- gint readret;
|
|
+ gint readret, i;
|
|
guint8 channels, flags, format;
|
|
- guint8 header[FLV_TAG_SIZE + 5];
|
|
- const gchar *mime;
|
|
+ guint8 header[FLV_TAG_SIZE + 1];
|
|
guint32 dataoffset, samplerate;
|
|
xmms_error_t err;
|
|
xmms_flv_data_t *flvdata;
|
|
+ struct xmms_flv_codec_table *codec = NULL;
|
|
+
|
|
+ flvdata = g_new0 (xmms_flv_data_t, 1);
|
|
+ xmms_xform_private_data_set (xform, flvdata);
|
|
|
|
readret = xmms_xform_read (xform, header, FLV_HDR_SIZE, &err);
|
|
if (readret != FLV_HDR_SIZE) {
|
|
xmms_log_error ("Header read error");
|
|
- return FALSE;
|
|
+ goto init_err;
|
|
}
|
|
|
|
if ((header[4] & HAS_AUDIO) != HAS_AUDIO) {
|
|
xmms_log_error ("FLV has no audio stream");
|
|
- return FALSE;
|
|
+ goto init_err;
|
|
}
|
|
|
|
dataoffset = get_be32 (&header[5]) - FLV_HDR_SIZE;
|
|
@@ -140,7 +155,7 @@ xmms_flv_init (xmms_xform_t *xform)
|
|
dataoffset : FLV_HDR_SIZE, &err);
|
|
if (readret <= 0) {
|
|
xmms_log_error ("Error reading header:tag body gap");
|
|
- return FALSE;
|
|
+ goto init_err;
|
|
}
|
|
|
|
dataoffset -= readret;
|
|
@@ -148,86 +163,99 @@ xmms_flv_init (xmms_xform_t *xform)
|
|
|
|
if (next_audio_tag (xform) <= 0) {
|
|
xmms_log_error ("Can't find first audio tag");
|
|
- return FALSE;
|
|
+ goto init_err;
|
|
}
|
|
|
|
- if (xmms_xform_peek (xform, header, FLV_TAG_SIZE + 5, &err) < FLV_TAG_SIZE + 5) {
|
|
+ if (xmms_xform_read (xform, header, FLV_TAG_SIZE + 1, &err) < FLV_TAG_SIZE + 1) {
|
|
xmms_log_error ("Can't read first audio tag");
|
|
- return FALSE;
|
|
+ goto init_err;
|
|
}
|
|
|
|
- flags = header[FLV_TAG_SIZE + 4];
|
|
+ flags = header[11];
|
|
XMMS_DBG ("Audio flags: %X", flags);
|
|
|
|
- switch (flags&12) {
|
|
- case 0: samplerate = 5512; break;
|
|
- case 4: samplerate = 11025; break;
|
|
- case 8: samplerate = 22050; break;
|
|
- case 12: samplerate = 44100; break;
|
|
- default: samplerate = 8000; break;
|
|
+ format = flags >> 4;
|
|
+ for (i = 0; i < G_N_ELEMENTS (flv_codecs); i++) {
|
|
+ if (flv_codecs[i].id == format) {
|
|
+ codec = &flv_codecs[i];
|
|
+ break;
|
|
+ }
|
|
}
|
|
|
|
- if (flags&2) {
|
|
- bps = XMMS_SAMPLE_FORMAT_S16;
|
|
+ if (flags & 1) {
|
|
+ channels = 2;
|
|
} else {
|
|
- bps = XMMS_SAMPLE_FORMAT_U8;
|
|
+ channels = 1;
|
|
}
|
|
|
|
- if (flags&1) {
|
|
- channels = 2;
|
|
+ if (flags & 2) {
|
|
+ bps = XMMS_SAMPLE_FORMAT_S16;
|
|
} else {
|
|
- channels = 1;
|
|
+ bps = XMMS_SAMPLE_FORMAT_U8;
|
|
}
|
|
|
|
- format = flags >> 4;
|
|
- mime = (format <= 10)? fmt_mime[format] : NULL;
|
|
- switch (format) {
|
|
- case 0:
|
|
- /* If the flv has an HE PCM audio stream, the
|
|
- * samples must be unsigned and 8 bits long
|
|
- */
|
|
- if (bps != XMMS_SAMPLE_FORMAT_U8) {
|
|
- xmms_log_error ("Only u8 HE PCM is supported");
|
|
- return FALSE;
|
|
- }
|
|
- break;
|
|
- case 3:
|
|
- if (bps == XMMS_SAMPLE_FORMAT_S16) {
|
|
- mime = mime_pcm_s16le;
|
|
- }
|
|
- break;
|
|
+ switch ((flags & 12) >> 2) {
|
|
+ case 0: samplerate = 5512; break;
|
|
+ case 1: samplerate = 11025; break;
|
|
+ case 2: samplerate = 22050; break;
|
|
+ case 3: samplerate = 44100; break;
|
|
+ default: samplerate = 8000; break;
|
|
}
|
|
|
|
- if (mime && *mime) {
|
|
- flvdata = g_new0 (xmms_flv_data_t, 1);
|
|
+ if (codec) {
|
|
+ switch (codec->id) {
|
|
+ case CODEC_PCM_HOST:
|
|
+ if (bps != XMMS_SAMPLE_FORMAT_U8) {
|
|
+ xmms_log_error ("Only u8 HE PCM is supported");
|
|
+ goto init_err;
|
|
+ }
|
|
+ break;
|
|
+ case CODEC_PCM_LE:
|
|
+ if (bps == XMMS_SAMPLE_FORMAT_S16) {
|
|
+ codec->mime = "audio/x-ffmpeg-pcm_s16le";
|
|
+ }
|
|
+ break;
|
|
+ case CODEC_NELLYMOSER_16K:
|
|
+ samplerate = 16000;
|
|
+ break;
|
|
+ case CODEC_NELLYMOSER_8K:
|
|
+ samplerate = 8000;
|
|
+ break;
|
|
+ default:
|
|
+ break;
|
|
+ }
|
|
+
|
|
flvdata->format = format;
|
|
+ flvdata->last_datasize = get_be24 (&header[1]) - 1;
|
|
|
|
XMMS_DBG ("Rate: %d, bps: %d, channels: %d", samplerate,
|
|
bps, channels);
|
|
|
|
- xmms_xform_private_data_set (xform, flvdata);
|
|
xmms_xform_outdata_type_add (xform,
|
|
XMMS_STREAM_TYPE_MIMETYPE,
|
|
- mime,
|
|
- XMMS_STREAM_TYPE_FMT_SAMPLERATE,
|
|
- samplerate,
|
|
- XMMS_STREAM_TYPE_FMT_FORMAT,
|
|
- bps,
|
|
- XMMS_STREAM_TYPE_FMT_CHANNELS,
|
|
- channels,
|
|
- XMMS_STREAM_TYPE_END);
|
|
+ codec->mime,
|
|
+ XMMS_STREAM_TYPE_FMT_SAMPLERATE,
|
|
+ samplerate,
|
|
+ XMMS_STREAM_TYPE_FMT_FORMAT,
|
|
+ bps,
|
|
+ XMMS_STREAM_TYPE_FMT_CHANNELS,
|
|
+ channels,
|
|
+ XMMS_STREAM_TYPE_END);
|
|
return TRUE;
|
|
} else {
|
|
xmms_log_error ("Unsupported audio format");
|
|
- return FALSE;
|
|
}
|
|
+
|
|
+init_err:
|
|
+ g_free (flvdata);
|
|
+ return FALSE;
|
|
}
|
|
|
|
static gint
|
|
xmms_flv_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *err)
|
|
{
|
|
- gint ret = 0, thismuch = FLV_TAG_SIZE + 5;
|
|
- guint8 header[FLV_TAG_SIZE + 6], gap = 1;
|
|
+ gint ret = 0, thismuch = FLV_TAG_SIZE + 1;
|
|
+ guint8 header[FLV_TAG_SIZE + 1];
|
|
xmms_flv_data_t *data = NULL;
|
|
|
|
data = xmms_xform_private_data_get (xform);
|
|
@@ -236,12 +264,8 @@ xmms_flv_read (xmms_xform_t *xform, xmms_sample_t *buf, gint len, xmms_error_t *
|
|
xmms_xform_auxdata_barrier (xform);
|
|
ret = next_audio_tag (xform);
|
|
if (ret > 0) {
|
|
- if (data->format == 10) {
|
|
- thismuch++;
|
|
- gap++;
|
|
- }
|
|
if (xmms_xform_read (xform, header, thismuch, err) == thismuch) {
|
|
- data->last_datasize = get_be24 (&header[5]) - gap;
|
|
+ data->last_datasize = get_be24 (&header[1]) - 1;
|
|
} else {
|
|
xmms_log_error ("Need %d bytes", thismuch);
|
|
return -1;
|
|
@@ -280,40 +304,51 @@ xmms_flv_destroy (xmms_xform_t *xform)
|
|
static gint
|
|
next_audio_tag (xmms_xform_t *xform)
|
|
{
|
|
- guint8 header[FLV_TAG_SIZE + 4];
|
|
+ guint8 header[FLV_TAG_SIZE];
|
|
guint8 dumb[FLV_CHUNK_SIZE];
|
|
gint ret = 0;
|
|
xmms_error_t err;
|
|
- guint32 datasize = 0;
|
|
+ xmms_flv_data_t *data;
|
|
+
|
|
+ data = xmms_xform_private_data_get (xform);
|
|
|
|
do {
|
|
- /* there's a last 4 bytes at the end of an FLV giving the final
|
|
- * tag's size, this isn't an error
|
|
- */
|
|
- ret = xmms_xform_peek (xform, header, FLV_TAG_SIZE + 4, &err);
|
|
- if ((ret < FLV_TAG_SIZE) && (ret > -1)) {
|
|
- ret = 0;
|
|
- break;
|
|
- } else if (ret == -1) {
|
|
- xmms_log_error ("%s", xmms_error_message_get (&err));
|
|
- break;
|
|
- }
|
|
+ /* If > 0 assume we're in the middle of a tag's data */
|
|
+ if (!data->last_datasize) {
|
|
+ /* There are 4 bytes before an actual tag giving
|
|
+ the previous tag's size. The first size in an
|
|
+ flv is always 0.
|
|
+ */
|
|
+ if (xmms_xform_read (xform, header, 4, &err) != 4) {
|
|
+ xmms_log_error ("Couldn't read last tag size");
|
|
+ return -1;
|
|
+ }
|
|
|
|
- if (header[4] == 8) {
|
|
- /* woo audio tag! */
|
|
- break;
|
|
- }
|
|
+ ret = xmms_xform_peek (xform, header, FLV_TAG_SIZE, &err);
|
|
+ if ((ret < FLV_TAG_SIZE) && (ret > -1)) {
|
|
+ return 0;
|
|
+ } else if (ret == -1) {
|
|
+ xmms_log_error ("%s", xmms_error_message_get (&err));
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ if (header[0] == 8) {
|
|
+ /* woo audio tag! */
|
|
+ break;
|
|
+ }
|
|
|
|
- ret = xmms_xform_read (xform, header, FLV_TAG_SIZE + 4, &err);
|
|
- if (ret <= 0) { return ret; }
|
|
+ if ((ret = xmms_xform_read (xform, header, FLV_TAG_SIZE, &err)) <= 0) {
|
|
+ return ret;
|
|
+ }
|
|
|
|
- datasize = get_be24 (&header[5]);
|
|
+ data->last_datasize = get_be24 (&header[1]);
|
|
+ }
|
|
|
|
- while (datasize) {
|
|
+ while (data->last_datasize) {
|
|
ret = xmms_xform_read (xform, dumb,
|
|
- (datasize < FLV_CHUNK_SIZE) ?
|
|
- datasize : FLV_CHUNK_SIZE,
|
|
- &err);
|
|
+ (data->last_datasize < FLV_CHUNK_SIZE) ?
|
|
+ data->last_datasize : FLV_CHUNK_SIZE,
|
|
+ &err);
|
|
if (ret == 0) {
|
|
xmms_log_error ("Data field short!");
|
|
break;
|
|
@@ -323,7 +358,7 @@ next_audio_tag (xmms_xform_t *xform)
|
|
break;
|
|
}
|
|
|
|
- datasize -= ret;
|
|
+ data->last_datasize -= ret;
|
|
}
|
|
|
|
} while (ret);
|