bugfixes and ID3 support

This commit is contained in:
Mathias Panzenböck 2012-12-27 20:09:06 +01:00
parent 8debf03fb9
commit 82890cf759
5 changed files with 122 additions and 5 deletions

View File

@ -1,5 +1,5 @@
BUILDDIR=build
OBJ=$(BUILDDIR)/audioextract.o $(BUILDDIR)/wave.o $(BUILDDIR)/ogg.o $(BUILDDIR)/mpeg.o
OBJ=$(BUILDDIR)/audioextract.o $(BUILDDIR)/wave.o $(BUILDDIR)/ogg.o $(BUILDDIR)/mpeg.o $(BUILDDIR)/id3.o
CC=gcc
CFLAGS=-Wall -std=c99 -O2 -fmessage-length=0 -g
BIN=$(BUILDDIR)/audioextract
@ -11,7 +11,7 @@ all: $(BIN)
$(BIN): $(OBJ)
$(CC) $(CFLAGS) $(OBJ) -o $@
$(BUILDDIR)/audioextract.o: audioextract.c audioextract.h ogg.h wave.h mpeg.h
$(BUILDDIR)/audioextract.o: audioextract.c audioextract.h ogg.h wave.h mpeg.h id3.h
$(CC) $(CFLAGS) $< -o $@ -c
$(BUILDDIR)/wave.o: wave.c audioextract.h wave.h
@ -23,5 +23,8 @@ $(BUILDDIR)/ogg.o: ogg.c audioextract.h ogg.h
$(BUILDDIR)/mpeg.o: mpeg.c audioextract.h mpeg.h
$(CC) $(CFLAGS) $< -o $@ -c
$(BUILDDIR)/id3.o: id3.c audioextract.h id3.h
$(CC) $(CFLAGS) $< -o $@ -c
clean:
rm $(BIN) $(OBJ)

View File

@ -12,13 +12,15 @@
#include "wave.h"
#include "ogg.h"
#include "mpeg.h"
#include "id3.h"
enum fileformat {
NONE,
OGG,
RIFF,
AIFF,
MPEG
MPEG,
ID3v2
/* TODO: AAC and MKV/WebM? */
};
@ -53,7 +55,12 @@ const unsigned char *findmagic(const unsigned char *start, const unsigned char *
return start;
default:
if (IS_MPEG_MAGIC(start))
if (IS_ID3v2_MAGIC(start))
{
*format = ID3v2;
return start;
}
else if (IS_MPEG_MAGIC(start))
{
*format = MPEG;
return start;
@ -185,8 +192,17 @@ int extract(const char *filepath, size_t *numfilesptr)
}
break;
case ID3v2:
case MPEG:
if (mpeg_isframe(ptr, end, &mpeg))
if (format == ID3v2)
{
if (!id3v2_istag(ptr, end, &length))
break;
}
else
length = 0;
if (mpeg_isframe(ptr + length, end, &mpeg))
{
uint8_t version = mpeg.version;
uint8_t layer = mpeg.layer;
@ -197,6 +213,9 @@ int extract(const char *filepath, size_t *numfilesptr)
layer == 3 ? "mp3" :
"mpeg");
write(outfd, ptr, length);
ptr += length;
do {
write(outfd, ptr, mpeg.frame_size);
ptr += mpeg.frame_size;
@ -204,6 +223,19 @@ int extract(const char *filepath, size_t *numfilesptr)
&& mpeg_isframe(ptr, end, &mpeg)
&& mpeg.version == version
&& mpeg.layer == layer);
if (id3v1_istag(ptr, end, &length))
{
write(outfd, ptr, length);
ptr += length;
}
if (id3v2_istag(ptr, end, &length))
{
write(outfd, ptr, length);
ptr += length;
}
close(outfd);
continue;
}

46
id3.c Normal file
View File

@ -0,0 +1,46 @@
#include "id3.h"
int id3v1_istag(const unsigned char *start, const unsigned char *end, size_t *lengthptr)
{
if ((intptr_t)end <= ID3v1_TAG_SIZE || end - ID3v1_TAG_SIZE < start)
return 0;
if (!IS_ID3v1_MAGIC(start))
return 0;
if (lengthptr) *lengthptr = ID3v1_TAG_SIZE;
return 1;
}
int id3v2_istag(const unsigned char *start, const unsigned char *end, size_t *lengthptr)
{
if ((intptr_t)end <= ID3v2_HEADER_SIZE || end - ID3v2_HEADER_SIZE < start)
return 0;
if (!IS_ID3v2_MAGIC(start))
return 0;
uint8_t major = start[3];
uint8_t minor = start[4];
uint8_t flags = start[5];
uint32_t size = ((start[6] & 0x7f) << 21)
| ((start[7] & 0x7f) << 14)
| ((start[8] & 0x7f) << 7)
| (start[9] & 0x7f);
if (major == 0xff || major < 2 || minor == 0xff || *(uint32_t *)(start + 6) & 0x80808080)
return 0;
size_t length = size + ID3v2_HEADER_SIZE;
/* has footer? */
if (flags & 0x10)
length += ID3v2_FOOTER_SIZE;
if ((intptr_t)end <= length || end - length < start)
return 0;
if (lengthptr) *lengthptr = length;
return 1;
}

33
id3.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef AUDIOEXTRACT_ID3_H__
#define AUDIOEXTRACT_ID3_H__
#include "audioextract.h"
#if __BYTE_ORDER == __LITTLE_ENDIAN
# define ID3_MASK (uint32_t)0x00FFFFFF
# define ID3v1_MAGIC (uint32_t)0x00474154 /* "TAG\0" (reversed) */
# define ID3v2_MAGIC (uint32_t)0x00334449 /* "ID3\0" (reversed) */
#elif __BYTE_ORDER == __BIG_ENDIAN
# define ID3_MASK (uint32_t)0xFFFFFF00
# define ID3v1_MAGIC (uint32_t)0x54414700 /* "TAG\0" */
# define ID3v2_MAGIC (uint32_t)0x49443300 /* "ID3\0" */
#else
# error unsupported endian
#endif
#define IS_ID3v1_MAGIC(hdr) ((*(uint32_t *)(hdr) & ID3_MASK) == ID3v1_MAGIC)
#define IS_ID3v2_MAGIC(hdr) ((*(uint32_t *)(hdr) & ID3_MASK) == ID3v2_MAGIC)
#define ID3v1_TAG_SIZE 128
#define ID3v2_HEADER_SIZE 10
#define ID3v2_FOOTER_SIZE 10
int id3v1_istag(const unsigned char *start, const unsigned char *end, size_t *lengthptr);
int id3v2_istag(const unsigned char *start, const unsigned char *end, size_t *lengthptr);
#endif /* AUDIOEXTRACT_ID3_H__ */

3
mpeg.c
View File

@ -79,6 +79,9 @@ int mpeg_isframe(const unsigned char *start, const unsigned char *end, struct mp
uint32_t samprate = mpeg_srates[ver][srx];
uint16_t samples = mpeg_frame_samples[ver][lyr];
uint8_t slot_size = mpeg_slot_size[lyr];
if (bitrate == 0 || samprate == 0 || samples == 0)
return 0;
// In-between calculations
// Frame sizes are truncated integers