parsing mp3 id3v2 tags on the fly for streams
git-svn-id: https://svn.musicpd.org/mpd/trunk@1281 09075e82-0dd4-0310-85a5-a0d7c8717e4f
This commit is contained in:
5
TODO
5
TODO
@@ -1,9 +1,6 @@
|
|||||||
1) play streams
|
1) play streams
|
||||||
a) put some sort of error reporting for streaming/inputStream!
|
a) put some sort of error reporting for streaming/inputStream!
|
||||||
b) parse metadata on the fly in decoders
|
b) in songinfo add a metadata tag item for indicating stream
|
||||||
c) command for dealing with the changing metadata, currentsonginfo
|
|
||||||
or something
|
|
||||||
d) in songinfo add a metadata tag item for indicating stream
|
|
||||||
|
|
||||||
2) http stuff
|
2) http stuff
|
||||||
a) allow http proxy
|
a) allow http proxy
|
||||||
|
@@ -608,7 +608,7 @@ void decode() {
|
|||||||
strncpy(dc->metadata+pos, string, \
|
strncpy(dc->metadata+pos, string, \
|
||||||
DECODE_METADATA_LENGTH-1-pos); \
|
DECODE_METADATA_LENGTH-1-pos); \
|
||||||
element = pos; \
|
element = pos; \
|
||||||
pos += slen; \
|
pos += slen+1; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -196,7 +196,56 @@ int fillMp3InputBuffer(mp3DecodeData * data) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decodeNextFrameHeader(mp3DecodeData * data) {
|
#ifdef HAVE_ID3TAG
|
||||||
|
static MpdTag * mp3_parseId3Tag(mp3DecodeData * data, signed long tagsize) {
|
||||||
|
MpdTag * ret = NULL;
|
||||||
|
struct id3_tag * id3Tag = NULL;
|
||||||
|
id3_length_t count;
|
||||||
|
id3_byte_t const *id3_data;
|
||||||
|
id3_byte_t * allocated = NULL;
|
||||||
|
|
||||||
|
count = data->stream.bufend - data->stream.this_frame;
|
||||||
|
|
||||||
|
if(tagsize <= count) {
|
||||||
|
id3_data = data->stream.this_frame;
|
||||||
|
mad_stream_skip(&(data->stream), tagsize);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
allocated = malloc(tagsize);
|
||||||
|
if(!allocated) goto fail;
|
||||||
|
|
||||||
|
memcpy(allocated, data->stream.this_frame, count);
|
||||||
|
mad_stream_skip(&(data->stream), count);
|
||||||
|
|
||||||
|
while(count < tagsize) {
|
||||||
|
int len;
|
||||||
|
|
||||||
|
len = readFromInputStream(data->inStream,
|
||||||
|
allocated+count, (size_t)1,
|
||||||
|
tagsize-count);
|
||||||
|
if(len <= 0 && inputStreamAtEOF(data->inStream)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(len <= 0) my_usleep(10000);
|
||||||
|
else count += len;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count != tagsize) goto fail;
|
||||||
|
|
||||||
|
id3_data = allocated;
|
||||||
|
}
|
||||||
|
|
||||||
|
id3Tag = id3_tag_parse(id3_data, tagsize);
|
||||||
|
|
||||||
|
ret = parseId3Tag(id3Tag);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if(allocated) free(allocated);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int decodeNextFrameHeader(mp3DecodeData * data, MpdTag ** tag) {
|
||||||
if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
|
if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
|
||||||
if(fillMp3InputBuffer(data) < 0) {
|
if(fillMp3InputBuffer(data) < 0) {
|
||||||
return DECODE_BREAK;
|
return DECODE_BREAK;
|
||||||
@@ -211,13 +260,23 @@ int decodeNextFrameHeader(mp3DecodeData * data) {
|
|||||||
(data->stream).this_frame,
|
(data->stream).this_frame,
|
||||||
(data->stream).bufend-
|
(data->stream).bufend-
|
||||||
(data->stream).this_frame);
|
(data->stream).this_frame);
|
||||||
|
|
||||||
|
printf("HERE 1\n");
|
||||||
if(tagsize>0) {
|
if(tagsize>0) {
|
||||||
mad_stream_skip(&(data->stream),tagsize);
|
printf("HERE 1-1\n");
|
||||||
|
if(tag) *tag =mp3_parseId3Tag(data, tagsize);
|
||||||
|
else {
|
||||||
|
mad_stream_skip(&(data->stream),
|
||||||
|
tagsize);
|
||||||
|
}
|
||||||
|
printf("HERE 1-2\n");
|
||||||
return DECODE_CONT;
|
return DECODE_CONT;
|
||||||
}
|
}
|
||||||
|
printf("HERE 2\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if(MAD_RECOVERABLE((data->stream).error)) {
|
if(MAD_RECOVERABLE((data->stream).error)) {
|
||||||
|
if(tag) printf("AHHH\n");
|
||||||
return DECODE_SKIP;
|
return DECODE_SKIP;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -331,7 +390,9 @@ fail:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc) {
|
int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
|
||||||
|
MpdTag ** tag)
|
||||||
|
{
|
||||||
struct xing xing;
|
struct xing xing;
|
||||||
int ret;
|
int ret;
|
||||||
int skip;
|
int skip;
|
||||||
@@ -341,7 +402,7 @@ int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc) {
|
|||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
skip = 0;
|
skip = 0;
|
||||||
while((ret = decodeNextFrameHeader(data))==DECODE_CONT &&
|
while((ret = decodeNextFrameHeader(data, tag))==DECODE_CONT &&
|
||||||
(!dc || !dc->stop));
|
(!dc || !dc->stop));
|
||||||
if(ret==DECODE_SKIP) skip = 1;
|
if(ret==DECODE_SKIP) skip = 1;
|
||||||
else if(ret==DECODE_BREAK || (dc && dc->stop)) return -1;
|
else if(ret==DECODE_BREAK || (dc && dc->stop)) return -1;
|
||||||
@@ -409,7 +470,7 @@ int getMp3TotalTime(char * file) {
|
|||||||
if(openInputStream(&inStream, file) < 0) return -1;
|
if(openInputStream(&inStream, file) < 0) return -1;
|
||||||
initMp3DecodeData(&data,&inStream);
|
initMp3DecodeData(&data,&inStream);
|
||||||
data.stream.options |= MAD_OPTION_IGNORECRC;
|
data.stream.options |= MAD_OPTION_IGNORECRC;
|
||||||
if(decodeFirstFrame(&data, NULL)<0) ret = -1;
|
if(decodeFirstFrame(&data, NULL, NULL)<0) ret = -1;
|
||||||
else ret = data.totalTime+0.5;
|
else ret = data.totalTime+0.5;
|
||||||
mp3DecodeDataFinalize(&data);
|
mp3DecodeDataFinalize(&data);
|
||||||
|
|
||||||
@@ -417,12 +478,14 @@ int getMp3TotalTime(char * file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
|
int openMp3FromInputStream(InputStream * inStream, mp3DecodeData * data,
|
||||||
DecoderControl * dc)
|
DecoderControl * dc, MpdTag ** tag)
|
||||||
{
|
{
|
||||||
initMp3DecodeData(data, inStream);
|
initMp3DecodeData(data, inStream);
|
||||||
data->stream.options |= MAD_OPTION_IGNORECRC;
|
data->stream.options |= MAD_OPTION_IGNORECRC;
|
||||||
if(decodeFirstFrame(data, dc)<0) {
|
*tag = NULL;
|
||||||
|
if(decodeFirstFrame(data, dc, tag)<0) {
|
||||||
mp3DecodeDataFinalize(data);
|
mp3DecodeDataFinalize(data);
|
||||||
|
if(tag && *tag) freeMpdTag(*tag);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +603,7 @@ int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc) {
|
|||||||
|
|
||||||
while(1) {
|
while(1) {
|
||||||
skip = 0;
|
skip = 0;
|
||||||
while((ret = decodeNextFrameHeader(data))==DECODE_CONT &&
|
while((ret = decodeNextFrameHeader(data, NULL))==DECODE_CONT &&
|
||||||
!dc->stop && !dc->seek);
|
!dc->stop && !dc->seek);
|
||||||
if(ret==DECODE_BREAK || dc->stop || dc->seek) break;
|
if(ret==DECODE_BREAK || dc->stop || dc->seek) break;
|
||||||
else if(ret==DECODE_SKIP) skip = 1;
|
else if(ret==DECODE_SKIP) skip = 1;
|
||||||
@@ -565,8 +628,9 @@ void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, AudioFormat * af) {
|
|||||||
|
|
||||||
int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
|
int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
|
||||||
mp3DecodeData data;
|
mp3DecodeData data;
|
||||||
|
MpdTag * tag;
|
||||||
|
|
||||||
if(openMp3FromInputStream(inStream, &data, dc) < 0) {
|
if(openMp3FromInputStream(inStream, &data, dc, &tag) < 0) {
|
||||||
closeInputStream(inStream);
|
closeInputStream(inStream);
|
||||||
if(!dc->stop) {
|
if(!dc->stop) {
|
||||||
ERROR("Input does not appear to be a mp3 bit stream.\n");
|
ERROR("Input does not appear to be a mp3 bit stream.\n");
|
||||||
@@ -583,6 +647,12 @@ int mp3_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream) {
|
|||||||
getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
|
getOutputAudioFormat(&(dc->audioFormat), &(cb->audioFormat));
|
||||||
|
|
||||||
dc->totalTime = data.totalTime;
|
dc->totalTime = data.totalTime;
|
||||||
|
|
||||||
|
if(tag) {
|
||||||
|
copyMpdTagToDecoderControlMetadata(dc, tag);
|
||||||
|
freeMpdTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
dc->state = DECODE_STATE_DECODE;
|
dc->state = DECODE_STATE_DECODE;
|
||||||
|
|
||||||
while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
|
while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
|
||||||
|
49
src/tag.c
49
src/tag.c
@@ -37,13 +37,6 @@
|
|||||||
#include <FLAC/file_decoder.h>
|
#include <FLAC/file_decoder.h>
|
||||||
#include <FLAC/metadata.h>
|
#include <FLAC/metadata.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ID3TAG
|
|
||||||
#ifdef USE_MPD_ID3TAG
|
|
||||||
#include "libid3tag/id3tag.h"
|
|
||||||
#else
|
|
||||||
#include <id3tag.h>
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void printMpdTag(FILE * fp, MpdTag * tag) {
|
void printMpdTag(FILE * fp, MpdTag * tag) {
|
||||||
if(tag->artist) myfprintf(fp,"Artist: %s\n",tag->artist);
|
if(tag->artist) myfprintf(fp,"Artist: %s\n",tag->artist);
|
||||||
@@ -95,25 +88,11 @@ char * getID3Info(struct id3_tag * tag, char * id) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MpdTag * id3Dup(char * file) {
|
|
||||||
MpdTag * ret = NULL;
|
|
||||||
#ifdef HAVE_ID3TAG
|
#ifdef HAVE_ID3TAG
|
||||||
struct id3_file * id3_file;
|
MpdTag * parseId3Tag(struct id3_tag * tag) {
|
||||||
struct id3_tag * tag;
|
MpdTag * ret = NULL;
|
||||||
char * str;
|
char * str;
|
||||||
|
|
||||||
id3_file = id3_file_open(file, ID3_FILE_MODE_READONLY);
|
|
||||||
|
|
||||||
if(!id3_file) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
tag = id3_file_tag(id3_file);
|
|
||||||
if(!tag) {
|
|
||||||
id3_file_close(id3_file);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
str = getID3Info(tag,ID3_FRAME_ARTIST);
|
str = getID3Info(tag,ID3_FRAME_ARTIST);
|
||||||
if(str) {
|
if(str) {
|
||||||
if(!ret) ret = newMpdTag();
|
if(!ret) ret = newMpdTag();
|
||||||
@@ -142,6 +121,30 @@ MpdTag * id3Dup(char * file) {
|
|||||||
ret->track = str;
|
ret->track = str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
MpdTag * id3Dup(char * file) {
|
||||||
|
MpdTag * ret = NULL;
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
struct id3_file * id3_file;
|
||||||
|
struct id3_tag * tag;
|
||||||
|
|
||||||
|
id3_file = id3_file_open(file, ID3_FILE_MODE_READONLY);
|
||||||
|
|
||||||
|
if(!id3_file) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = id3_file_tag(id3_file);
|
||||||
|
if(!tag) {
|
||||||
|
id3_file_close(id3_file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = parseId3Tag(tag);
|
||||||
|
|
||||||
id3_file_close(id3_file);
|
id3_file_close(id3_file);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
11
src/tag.h
11
src/tag.h
@@ -22,6 +22,13 @@
|
|||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
#ifdef USE_MPD_ID3TAG
|
||||||
|
#include "libid3tag/id3tag.h"
|
||||||
|
#else
|
||||||
|
#include <id3tag.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct _MpdTag {
|
typedef struct _MpdTag {
|
||||||
char * artist;
|
char * artist;
|
||||||
@@ -31,6 +38,10 @@ typedef struct _MpdTag {
|
|||||||
int time;
|
int time;
|
||||||
} MpdTag;
|
} MpdTag;
|
||||||
|
|
||||||
|
#ifdef HAVE_ID3TAG
|
||||||
|
MpdTag * parseId3Tag(struct id3_tag *);
|
||||||
|
#endif
|
||||||
|
|
||||||
MpdTag * id3Dup(char * file);
|
MpdTag * id3Dup(char * file);
|
||||||
|
|
||||||
MpdTag * newMpdTag();
|
MpdTag * newMpdTag();
|
||||||
|
Reference in New Issue
Block a user