On Tue, 11 Oct 2005, Joel Yliluoma wrote:
So in an hour's work, I wrote MP3 support to swftools.
By MP3 support I mean that it's now possible to say this:
.sound sound1 "mp3file.mp3"
Attached is the patch to swftools-2005-09-25-1334 source code.
Attached is a patch with some bugs fixed,
when comparing to the previous version.
Most importantly, the first patch failed to
recognize mpeg-1 different from mpeg-2.
--
Joel Yliluoma
http://iki.fi/bisqwit/
diff -NaHudr swftools-2005-09-25-1334/lib/modules/swfsound.c
swftools-updated/lib/modules/swfsound.c
--- swftools-2005-09-25-1334/lib/modules/swfsound.c 2005-08-16
17:43:14.000000000 +0300
+++ swftools-updated/lib/modules/swfsound.c 2005-10-11 23:50:49.643820000
+0300
@@ -312,3 +312,25 @@
}
+void swf_SetSoundDefineMP3(TAG*tag, U8* data, unsigned length,
+ unsigned SampRate,
+ unsigned Channels,
+ unsigned NumFrames)
+{
+ U8 compression = 2; // 0 = raw, 1 = ADPCM, 2 = mp3, 3 = raw le, 6 =
nellymoser
+ U8 rate; // 0 = 5.5 Khz, 1 = 11 Khz, 2 = 22 Khz, 3 = 44 Khz
+ U8 size = 1; // 0 = 8 bit, 1 = 16 bit
+ U8 type = Channels==2; // 0=mono, 1=stereo
+
+ rate = (SampRate >= 40000) ? 3
+ : (SampRate >= 19000) ? 2
+ : (SampRate >= 8000) ? 1
+ : 0;
+
+ swf_SetU8(tag,(compression<<4)|(rate<<2)|(size<<1)|type);
+
+ swf_SetU32(tag, NumFrames * 576);
+
+ swf_SetU16(tag, 0); //delayseek
+ swf_SetBlock(tag, data, length);
+}
diff -NaHudr swftools-2005-09-25-1334/lib/rfxswf.h swftools-updated/lib/rfxswf.h
--- swftools-2005-09-25-1334/lib/rfxswf.h 2005-09-18 16:26:03.000000000
+0300
+++ swftools-updated/lib/rfxswf.h 2005-10-11 23:40:06.175642032 +0300
@@ -746,6 +746,10 @@
void swf_SetSoundStreamHead(TAG*tag, int avgnumsamples);
void swf_SetSoundStreamBlock(TAG*tag, S16*samples, int seek, char first); /*
expects 2304 samples */
void swf_SetSoundDefine(TAG*tag, S16*samples, int num);
+void swf_SetSoundDefineMP3(TAG*tag, U8* data, unsigned length,
+ unsigned SampRate,
+ unsigned Channels,
+ unsigned NumFrames);
void swf_SetSoundInfo(TAG*tag, SOUNDINFO*info);
// swftools.c
diff -NaHudr swftools-2005-09-25-1334/mp3.c swftools-updated/mp3.c
--- swftools-2005-09-25-1334/mp3.c 1970-01-01 02:00:00.000000000 +0200
+++ swftools-updated/mp3.c 2005-10-12 01:52:35.393177280 +0300
@@ -0,0 +1,197 @@
+/* mp3.c
+ Routines for handling .mp3 files
+
+ Part of the swftools package.
+
+ Copyright (c) 2005 Joel Yliluoma <[EMAIL PROTECTED]>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mp3.h"
+
+struct MP3Frame
+{
+ unsigned bitrate;
+ unsigned samprate;
+ unsigned chanmode;
+ unsigned framesize;
+ unsigned char* data;
+ struct MP3Frame* next;
+};
+
+// 0 4 8 C
+static const unsigned BR_mpeg1[16] =
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0};
+static const unsigned BR_mpeg2[16] = {0,8, 16,24,32,40,48,56, 64, 80,
96,112,128,144,160,0};
+static const unsigned BR_reserved[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+static const unsigned*const BR[4] = {BR_mpeg2, BR_reserved, BR_mpeg2,
BR_mpeg1};
+
+static const unsigned SR_mpeg1[4] = {44100,48000,32000,0};
+static const unsigned SR_mpeg2[4] = {22050,24000,16000,0};
+static const unsigned SR_mpeg25[4] = {11025,12000,8000,0};
+static const unsigned SR_reserved[4] = {0,0,0,0};
+static const unsigned*const SR[4] = {SR_mpeg25, SR_reserved, SR_mpeg2,
SR_mpeg1};
+
+int readMP3(char* filename, struct MP3*mp3)
+{
+ struct MP3Frame* root = 0;
+ struct MP3Frame** cur = &root;
+
+ unsigned totalsize = 0;
+ unsigned first_samprate = 0;
+ unsigned nframes = 0;
+ int first_chanmode = -1;
+
+ FILE*fi = fopen(filename, "rb");
+ if(!fi) return 0;
+
+ for(;;)
+ {
+ unsigned char FrameBuf[2048];
+ unsigned char* hdr = FrameBuf;
+ unsigned char* data = FrameBuf+4;
+ unsigned char* frdata;
+
+ unsigned char mpegver;
+ unsigned padding;
+ unsigned bitrate;
+ unsigned samprate;
+ unsigned framesize;
+ int chanmode;
+
+ if(fread(hdr,1,4,fi) < 4) break;
+ if(hdr[0] != 0xFF
+ || (hdr[1] & 0xE0) != 0xE0)
+ {
+ fprintf(stderr, "readMP3: invalid header %02X %02X %02X %02X\n",
+ hdr[0],hdr[1],hdr[2],hdr[3]);
+ break;
+ }
+
+ mpegver = (hdr[1] >> 3) & 0x03;
+
+ bitrate = BR[mpegver][ (hdr[2] >> 4) & 0x0F ] * 1000;
+ samprate = SR[mpegver][ (hdr[2] >> 2) & 0x03 ];
+ chanmode = (hdr[3] >> 6) & 0x03;
+
+ padding = (hdr[2] & 2) ? 1 : 0;
+
+ if(!bitrate || !samprate)
+ {
+ /* Invalid frame */
+ /*break;*/
+ }
+ if(!first_samprate) first_samprate = samprate;
+ else if(first_samprate != samprate)
+ {
+ /* Sampling rate changed?!? */
+ fprintf(stderr, "readMP3: sampling rate changed?\n");
+ /*break;*/
+ }
+ if(first_chanmode<0) first_chanmode = chanmode;
+ else if(first_chanmode != chanmode)
+ {
+ /* Channel mode changed?!? */
+ fprintf(stderr, "readMP3: chanmode changed?\n");
+ /*break;*/
+ }
+
+ framesize = ((mpegver == 3 ? 144 : 72) * bitrate) / samprate + padding;
+
+/*
+ fprintf(stderr, "%02X %02X %02X %02X -
bitrate=%u,samprate=%u,chanmode=%u,padding=%u,framesize=%u\n",
+
hdr[0],hdr[1],hdr[2],hdr[3],bitrate,samprate,chanmode,padding,framesize);
+*/
+ if(framesize > sizeof(FrameBuf)) break;
+ if(fread(data, 1, framesize - 4, fi) < framesize-4)
+ {
+ fprintf(stderr, "readMP3: short read at frame %u\n", nframes);
+ break;
+ }
+
+ if(!bitrate || !samprate) continue;
+
+ frdata = (unsigned char*)malloc(framesize);
+ if(!frdata)
+ {
+ fprintf(stderr, "readMP3: malloc failed\n");
+ break;
+ }
+
+ *cur = (struct MP3Frame*)malloc(sizeof(*root));
+ if(!*cur)
+ {
+ fprintf(stderr, "readMP3: malloc failed\n");
+ free(frdata);
+ break;
+ }
+
+ (*cur)->next = 0;
+ (*cur)->bitrate = bitrate;
+ (*cur)->samprate = samprate;
+ (*cur)->chanmode = chanmode;
+ (*cur)->framesize = framesize;
+ (*cur)->data = frdata;
+
+ memcpy(frdata, FrameBuf, framesize);
+ cur = &(*cur)->next;
+
+ totalsize += framesize;
+ ++nframes;
+ }
+ if(!root)
+ {
+ fprintf(stderr, "readMP3: not a MP3 file\n");
+ return 0;
+ }
+
+ /*
+ fprintf(stderr, "readMP3: read %u frames (%u bytes)\n", nframes,
totalsize);
+ */
+
+ mp3->SampRate = first_samprate;
+ mp3->Channels = first_chanmode == 3 ? 1 : 2;
+ mp3->NumFrames = nframes;
+ mp3->size = totalsize;
+ mp3->data = (unsigned char*)malloc(mp3->size);
+ if(mp3->data)
+ {
+ unsigned pos=0;
+ struct MP3Frame* it;
+ for(it=root; it; it=it->next)
+ {
+ memcpy(mp3->data + pos, it->data, it->framesize);
+ pos += it->framesize;
+ }
+ }
+ else
+ {
+ fprintf(stderr, "readMP3: malloc failed\n");
+ }
+
+ while(root)
+ {
+ struct MP3Frame* next = root->next;
+ free(root->data);
+ free(root);
+ root = next;
+ }
+
+ return mp3->data != NULL;
+}
+
diff -NaHudr swftools-2005-09-25-1334/mp3.h swftools-updated/mp3.h
--- swftools-2005-09-25-1334/mp3.h 1970-01-01 02:00:00.000000000 +0200
+++ swftools-updated/mp3.h 2005-10-12 01:52:35.393177280 +0300
@@ -0,0 +1,18 @@
+/* mp3.h
+ Header file for mp3.c
+
+ Part of the swftools package.
+
+ Copyright (c) 2005 Joel Yliluoma <[EMAIL PROTECTED]>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+struct MP3 {
+ unsigned short SampRate;
+ unsigned char Channels;
+ unsigned int NumFrames;
+ unsigned char* data;
+ unsigned long size;
+};
+
+int readMP3(char* filename, struct MP3*mp3);
diff -NaHudr swftools-2005-09-25-1334/src/Makefile.in
swftools-updated/src/Makefile.in
--- swftools-2005-09-25-1334/src/Makefile.in 2005-07-23 11:11:16.000000000
+0300
+++ swftools-updated/src/Makefile.in 2005-10-11 23:23:28.582299272 +0300
@@ -11,6 +11,8 @@
$(C) wav2swf.c -o $@
wav.$(O): wav.c wav.h
$(C) wav.c -o $@
+mp3.$(O): mp3.c mp3.h
+ $(C) mp3.c -o $@
png2swf.$(O): png2swf.c
$(C) png2swf.c -o $@
gif2swf.$(O): gif2swf.c
@@ -81,8 +83,8 @@
jpeg2swf$(E): jpeg2swf.$(O) ../lib/librfxswf$(A)
$(L) jpeg2swf.$(O) -o $@ ../lib/librfxswf$(A) $(LIBS)
$(STRIP) $@
-swfc$(E): parser.$(O) swfc.$(O) ../lib/q.$(O) wav.$(O) ../lib/png.$(O)
../lib/librfxswf$(A)
- $(L) parser.$(O) swfc.$(O) ../lib/q.$(O) wav.$(O) ../lib/png.$(O) -o $@
../lib/librfxswf$(A) $(LIBS)
+swfc$(E): parser.$(O) swfc.$(O) ../lib/q.$(O) wav.$(O) mp3.$(O)
../lib/png.$(O) ../lib/librfxswf$(A)
+ $(L) parser.$(O) swfc.$(O) ../lib/q.$(O) wav.$(O) mp3.$(O)
../lib/png.$(O) -o $@ ../lib/librfxswf$(A) $(LIBS)
$(STRIP) $@
install:
diff -NaHudr swftools-2005-09-25-1334/src/mp3.c swftools-updated/src/mp3.c
--- swftools-2005-09-25-1334/src/mp3.c 1970-01-01 02:00:00.000000000 +0200
+++ swftools-updated/src/mp3.c 2005-10-11 23:51:35.882790608 +0300
@@ -0,0 +1,167 @@
+/* mp3.c
+ Routines for handling .mp3 files
+
+ Part of the swftools package.
+
+ Copyright (c) 2005 Joel Yliluoma <[EMAIL PROTECTED]>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "mp3.h"
+
+struct MP3Frame
+{
+ unsigned bitrate;
+ unsigned samprate;
+ unsigned chanmode;
+ unsigned framesize;
+ unsigned char* data;
+ struct MP3Frame* next;
+};
+
+static const unsigned BR_mpeg1[16] =
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0};
+static const unsigned BR_mpeg2[16] =
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0};
+static const unsigned BR_reserved[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0};
+static const unsigned*const BR[4] = {BR_mpeg2, BR_reserved, BR_mpeg2,
BR_mpeg1};
+
+static const unsigned SR_mpeg1[4] = {44100,48000,32000,0};
+static const unsigned SR_mpeg2[4] = {22050,24000,16000,0};
+static const unsigned SR_mpeg25[4] = {11025,12000,8000,0};
+static const unsigned SR_reserved[4] = {0,0,0,0};
+static const unsigned*const SR[4] = {SR_mpeg25, SR_reserved, SR_mpeg2,
SR_mpeg1};
+
+int readMP3(char* filename, struct MP3*mp3)
+{
+ struct MP3Frame* root = 0;
+ struct MP3Frame** cur = &root;
+
+ unsigned totalsize = 0;
+ unsigned first_samprate = 0;
+ unsigned nframes = 0;
+ int first_chanmode = -1;
+
+ FILE*fi = fopen(filename, "rb");
+ if(!fi) return 0;
+
+ for(;;)
+ {
+ unsigned char FrameBuf[2048];
+ unsigned char* hdr = FrameBuf;
+ unsigned char* data = FrameBuf+4;
+ unsigned char* frdata;
+
+ unsigned char mpegver;
+ unsigned padding;
+ unsigned bitrate;
+ unsigned samprate;
+ unsigned framesize;
+ int chanmode;
+
+ if(fread(hdr,1,4,fi) < 4) break;
+
+ if(hdr[0] != 0xFF) break;
+
+ if((hdr[1] & 0xE0) != 0xE0) break;
+
+ mpegver = (hdr[1] >> 3) & 2;
+
+ bitrate = BR[mpegver][ (hdr[2] >> 4) & 0x0F ] * 1000;
+ samprate = SR[mpegver][ (hdr[2] >> 2) & 0x03 ];
+ chanmode = (hdr[3] >> 6) & 0x03;
+
+ padding = (hdr[2] & 2) ? 1 : 0;
+
+ if(!bitrate || !samprate)
+ {
+ /* Invalid frame */
+ break;
+ }
+ if(!first_samprate) first_samprate = samprate;
+ else if(first_samprate != samprate)
+ {
+ /* Sampling rate changed?!? */
+ break;
+ }
+ if(first_chanmode<0) first_chanmode = chanmode;
+ else if(first_chanmode != chanmode)
+ {
+ /* Channel mode changed?!? */
+ break;
+ }
+
+ framesize = ((mpegver == 3 ? 144 : 72) * bitrate) / samprate + padding;
+
+ if(framesize > sizeof(FrameBuf)) break;
+ if(fread(data, 1, framesize - 4, fi) < framesize-4) break;
+
+ frdata = (unsigned char*)malloc(framesize);
+ if(!frdata) break;
+
+ *cur = (struct MP3Frame*)malloc(sizeof(*root));
+ if(!*cur)
+ {
+ free(frdata);
+ break;
+ }
+
+ (*cur)->next = 0;
+ (*cur)->bitrate = bitrate;
+ (*cur)->samprate = samprate;
+ (*cur)->chanmode = chanmode;
+ (*cur)->framesize = framesize;
+ (*cur)->data = frdata;
+
+ memcpy(frdata, FrameBuf, framesize);
+ cur = &(*cur)->next;
+
+ totalsize += framesize;
+ ++nframes;
+ }
+ if(!root)
+ {
+ fprintf(stderr, "readMP3: not a MP3 file\n");
+ return 0;
+ }
+
+ mp3->SampRate = first_samprate;
+ mp3->Channels = first_chanmode == 3 ? 1 : 2;
+ mp3->NumFrames = nframes;
+ mp3->size = totalsize;
+ mp3->data = (unsigned char*)malloc(mp3->size);
+ if(mp3->data)
+ {
+ unsigned pos=0;
+ struct MP3Frame* it;
+ for(it=root; it; it=it->next)
+ {
+ memcpy(mp3->data + pos, it->data, it->framesize);
+ pos += it->framesize;
+ }
+ }
+ while(root)
+ {
+ struct MP3Frame* next = root->next;
+ free(root->data);
+ free(root);
+ root = next;
+ }
+
+ return mp3->data != NULL;
+}
+
diff -NaHudr swftools-2005-09-25-1334/src/mp3.h swftools-updated/src/mp3.h
--- swftools-2005-09-25-1334/src/mp3.h 1970-01-01 02:00:00.000000000 +0200
+++ swftools-updated/src/mp3.h 2005-10-11 23:24:14.225360472 +0300
@@ -0,0 +1,18 @@
+/* mp3.h
+ Header file for mp3.c
+
+ Part of the swftools package.
+
+ Copyright (c) 2005 Joel Yliluoma <[EMAIL PROTECTED]>
+
+ This file is distributed under the GPL, see file COPYING for details */
+
+struct MP3 {
+ unsigned short SampRate;
+ unsigned char Channels;
+ unsigned int NumFrames;
+ unsigned char* data;
+ unsigned long size;
+};
+
+int readMP3(char* filename, struct MP3*mp3);
diff -NaHudr swftools-2005-09-25-1334/src/swfc.c swftools-updated/src/swfc.c
--- swftools-2005-09-25-1334/src/swfc.c 2005-05-16 15:23:01.000000000 +0300
+++ swftools-updated/src/swfc.c 2005-10-11 23:51:20.282162264 +0300
@@ -34,6 +34,7 @@
#include "../lib/q.h"
#include "parser.h"
#include "wav.h"
+#include "mp3.h"
#include "../lib/png.h"
//#define DEBUG
@@ -1201,17 +1202,15 @@
void s_sound(char*name, char*filename)
{
struct WAV wav, wav2;
+ struct MP3 mp3;
sound_t* sound;
- U16*samples;
- int numsamples;
- int t;
- int blocksize = 1152;
+ U16*samples = NULL;
+ unsigned numsamples;
+ unsigned blocksize = 1152;
+ int is_mp3 = 0;
- if(!readWAV(filename, &wav)) {
- warning("Couldn't read wav file \"%s\"", filename);
- samples = 0;
- numsamples = 0;
- } else {
+ if(readWAV(filename, &wav)) {
+ int t;
convertWAV2mono(&wav, &wav2, 44100);
samples = (U16*)wav2.data;
numsamples = wav2.size/2;
@@ -1222,6 +1221,16 @@
samples[t] = (samples[t]>>8)&0xff | (samples[t]<<8)&0xff00;
}
#endif
+ } else if(readMP3(filename, &mp3)) {
+ fprintf(stderr, "\"%s\" seems to work as a MP3 file...\n", filename);
+ blocksize = 1;
+ is_mp3 = 1;
+ }
+ else
+ {
+ warning("Couldn't read WAV/MP3 file \"%s\"", filename);
+ samples = 0;
+ numsamples = 0;
}
if(numsamples%blocksize != 0)
@@ -1240,7 +1249,18 @@
tag = swf_InsertTag(tag, ST_DEFINESOUND);
swf_SetU16(tag, id); //id
- swf_SetSoundDefine(tag, samples, numsamples);
+ if(is_mp3)
+ {
+ swf_SetSoundDefineMP3(
+ tag, mp3.data, mp3.size,
+ mp3.SampRate,
+ mp3.Channels,
+ mp3.NumFrames);
+ }
+ else
+ {
+ swf_SetSoundDefine(tag, samples, numsamples);
+ }
sound = (sound_t*)malloc(sizeof(sound_t)); /* mem leak */
sound->tag = tag;
diff -NaHudr swftools-2005-09-25-1334/src/wav.c swftools-updated/src/wav.c
--- swftools-2005-09-25-1334/src/wav.c 2004-05-09 12:25:40.000000000 +0300
+++ swftools-updated/src/wav.c 2005-10-11 23:46:38.705968352 +0300
@@ -63,7 +63,7 @@
if(!getWAVBlock (fi, &block))
return 0;
if(strncmp(block.id,"RIFF",4)) {
- fprintf(stderr, "readWAV: not a wav file\n");
+ fprintf(stderr, "readWAV: not a WAV file\n");
return 0;
}
if(block.size + 8 < filesize)
_______________________________________________
Swftools-common mailing list
[email protected]
http://lists.nongnu.org/mailman/listinfo/swftools-common