From 8f07db5c10ea415904ec62aef92633600d3ed693 Mon Sep 17 00:00:00 2001 From: Julien BLACHE Date: Wed, 18 Nov 2009 20:14:03 +0100 Subject: [PATCH] Add support for FLAC files with ID3v2 tags. Patch from Wolfgang Holler . --- src/transcode.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/transcode.c b/src/transcode.c index 05dd3d59..9cba60ee 100644 --- a/src/transcode.c +++ b/src/transcode.c @@ -48,6 +48,9 @@ #define XCODE_BUFFER_SIZE ((AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2) #define RAW_BUFFER_SIZE 256 +#define ID3V2_MIN_HEADER_SIZE 10 + + struct transcode_ctx { AVFormatContext *fmtctx; /* Audio stream */ @@ -78,6 +81,38 @@ static char *roku_codecs = "mpeg,mp4a,wma,wav"; static char *itunes_codecs = "mpeg,mp4a,mp4v,alac,wav"; +static int +id3v2_tag_len(const uint8_t *buf) +{ + int len; + + len = ID3V2_MIN_HEADER_SIZE + + ((buf[6] & 0x7f) << 21) + + ((buf[7] & 0x7f) << 14) + + ((buf[8] & 0x7f) << 7) + + (buf[9] & 0x7f); + + if (buf[5] & 0x10) + len += ID3V2_MIN_HEADER_SIZE; + + return len; +} + +static int +has_id3v2_tag(const uint8_t *buf) +{ + return ((buf[0] == 'I') + && (buf[1] == 'D') + && (buf[2] == '3') + && (buf[3] != 0xff) + && (buf[4] != 0xff) + && ((buf[6] & 0x80) == 0) + && ((buf[7] & 0x80) == 0) + && ((buf[8] & 0x80) == 0) + && ((buf[9] & 0x80) == 0)); +} + + static inline void add_le16(uint8_t *dst, uint16_t val) { @@ -273,6 +308,7 @@ struct transcode_ctx * transcode_setup(struct media_file_info *mfi, size_t *est_size) { struct transcode_ctx *ctx; + int hdr_len; int i; int ret; @@ -359,6 +395,39 @@ transcode_setup(struct media_file_info *mfi, size_t *est_size) { DPRINTF(E_WARN, L_XCODE, "Could not open %s: %s\n", mfi->fname, strerror(errno)); + free(ctx->rawbuffer); + avcodec_close(ctx->acodec); + goto setup_fail; + } + + /* Check for ID3v2 header */ + ret = read(ctx->fd, ctx->rawbuffer, ID3V2_MIN_HEADER_SIZE); + if ((ret < 0) || (ret != ID3V2_MIN_HEADER_SIZE)) + { + if (ret < 0) + DPRINTF(E_WARN, L_XCODE, "Could not read raw data: %s\n", strerror(errno)); + else + DPRINTF(E_WARN, L_XCODE, "Could not read enough raw data\n"); + + free(ctx->rawbuffer); + avcodec_close(ctx->acodec); + goto setup_fail; + } + + ret = has_id3v2_tag(ctx->rawbuffer); + if (ret) + { + hdr_len = id3v2_tag_len(ctx->rawbuffer); + DPRINTF(E_DBG, L_XCODE, "Skipping ID3V2 header of %d bytes\n", hdr_len); + } + else + hdr_len = 0; + + ret = lseek(ctx->fd, hdr_len, SEEK_SET); + if (ret < 0) + { + DPRINTF(E_WARN, L_XCODE, "Could not seek: %s\n", strerror(errno)); + free(ctx->rawbuffer); avcodec_close(ctx->acodec); goto setup_fail;