1002 lines
29 KiB
Diff
Executable File
1002 lines
29 KiB
Diff
Executable File
From 16f6b7a5baec41f18fde75fd311fb988e3c31810 Mon Sep 17 00:00:00 2001
|
|
From: Shengjiu Wang <shengjiu.wang@nxp.com>
|
|
Date: Fri, 13 Jul 2018 18:13:24 +0800
|
|
Subject: [PATCH] tinycompress: Add id3 decoding
|
|
|
|
Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
|
|
---
|
|
include/tinycompress/id3_tag_decode.h | 198 +++++++++++
|
|
src/utils/Makefile.am | 2 +-
|
|
src/utils/cplay.c | 88 +++++
|
|
src/utils/id3_tag_decode.c | 642 ++++++++++++++++++++++++++++++++++
|
|
4 files changed, 929 insertions(+), 1 deletion(-)
|
|
create mode 100644 include/tinycompress/id3_tag_decode.h
|
|
create mode 100644 src/utils/id3_tag_decode.c
|
|
|
|
diff --git a/include/tinycompress/id3_tag_decode.h b/include/tinycompress/id3_tag_decode.h
|
|
new file mode 100644
|
|
index 0000000..1a911d7
|
|
--- /dev/null
|
|
+++ b/include/tinycompress/id3_tag_decode.h
|
|
@@ -0,0 +1,198 @@
|
|
+/*
|
|
+ * Copyright (c) 2006-2017 Cadence Design Systems, Inc.
|
|
+ * Copyright 2018 NXP
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be included
|
|
+ * in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+
|
|
+/******************************************************************
|
|
+ * file name : id3_tag_decode.h
|
|
+ *
|
|
+ * description : stores typedefs of structures specific to MP3 tag
|
|
+ *
|
|
+ * revision history:
|
|
+ * 29 04 2004 DK creation
|
|
+ *****************************************************************/
|
|
+
|
|
+#ifndef ID3_TAG_DECODE_H
|
|
+#define ID3_TAG_DECODE_H
|
|
+
|
|
+typedef signed char WORD8;
|
|
+typedef signed char * pWORD8;
|
|
+typedef unsigned char UWORD8;
|
|
+typedef unsigned char * pUWORD8;
|
|
+
|
|
+typedef signed short WORD16;
|
|
+typedef signed short * pWORD16;
|
|
+typedef unsigned short UWORD16;
|
|
+typedef unsigned short * pUWORD16;
|
|
+
|
|
+typedef signed int WORD24;
|
|
+typedef signed int * pWORD24;
|
|
+typedef unsigned int UWORD24;
|
|
+typedef unsigned int * pUWORD24;
|
|
+
|
|
+typedef signed int WORD32;
|
|
+typedef signed int * pWORD32;
|
|
+typedef unsigned int UWORD32;
|
|
+typedef unsigned int * pUWORD32;
|
|
+
|
|
+typedef void VOID;
|
|
+typedef void * pVOID;
|
|
+
|
|
+typedef signed int BOOL;
|
|
+typedef unsigned int UBOOL;
|
|
+typedef signed int FLAG;
|
|
+typedef unsigned int UFLAG;
|
|
+typedef signed int LOOPIDX;
|
|
+typedef unsigned int ULOOPIDX;
|
|
+typedef signed int WORD;
|
|
+typedef unsigned int UWORD;
|
|
+
|
|
+#define MAX_TAG_FRAME_SIZE 100
|
|
+
|
|
+#define ID3V1 (0x544147) /* 0x544147 is TAG in WORD8 */
|
|
+
|
|
+#define ID3V2 (0x494433) /* 0x494433 is ID3 in WORD8 */
|
|
+
|
|
+/*
|
|
+ * structure corresponding to ID3 tag v1 header.
|
|
+ * this structure has all the field corresponding to ID3 tag v1 header.
|
|
+ */
|
|
+
|
|
+typedef struct {
|
|
+ WORD32 tag; // 3 bytes
|
|
+
|
|
+ WORD16 version; // 2 bytes
|
|
+
|
|
+ WORD8 flag; //1 byte
|
|
+
|
|
+ WORD32 size; //4 bytes
|
|
+
|
|
+} id3_v2_header_struct;
|
|
+
|
|
+/* structure which will store the frame data and
|
|
+ * also put a limit max data to be stored
|
|
+ */
|
|
+typedef struct {
|
|
+ WORD8 frame_data[MAX_TAG_FRAME_SIZE];
|
|
+
|
|
+ WORD32 max_size; //4 bytes
|
|
+
|
|
+ WORD16 tag_present;
|
|
+
|
|
+ WORD16 exceeds_buffer_size;
|
|
+
|
|
+} id3_v2_frame_struct;
|
|
+
|
|
+/*
|
|
+ * structure corresponding to ID3 tag v2.
|
|
+ * this structure has some of the field corresponding to ID3 tag v2.
|
|
+ * if user wants to read some more tag information from
|
|
+ * the MP3 file, he can add that field in this structure and pass address
|
|
+ * of that element to get_inf function in id3_tag_decode.c under the
|
|
+ * corresponding field frame header. few fields which are needed are already
|
|
+ * populated by reading from the TAG header.
|
|
+ */
|
|
+typedef struct {
|
|
+ id3_v2_frame_struct album_movie_show_title;
|
|
+
|
|
+ id3_v2_frame_struct composer_name;
|
|
+
|
|
+ id3_v2_frame_struct content_type;
|
|
+
|
|
+ id3_v2_frame_struct encoded_by;
|
|
+
|
|
+ id3_v2_frame_struct lyricist_text_writer;
|
|
+
|
|
+ id3_v2_frame_struct content_group_description;
|
|
+
|
|
+ id3_v2_frame_struct title_songname_content_description;
|
|
+
|
|
+ id3_v2_frame_struct medxa_type;
|
|
+
|
|
+ id3_v2_frame_struct original_album_movie_show_title;
|
|
+
|
|
+ id3_v2_frame_struct original_filename;
|
|
+
|
|
+ id3_v2_frame_struct original_lyricist_text_writer;
|
|
+
|
|
+ id3_v2_frame_struct original_artist_performer;
|
|
+
|
|
+ id3_v2_frame_struct file_owner_licensee;
|
|
+
|
|
+ id3_v2_frame_struct lead_performer_soloist;
|
|
+
|
|
+ id3_v2_frame_struct publisher;
|
|
+
|
|
+ id3_v2_frame_struct private_frame;
|
|
+
|
|
+ id3_v2_frame_struct other_info;
|
|
+
|
|
+ id3_v2_header_struct id3_v2_header;
|
|
+
|
|
+ WORD32 header_end;
|
|
+
|
|
+ WORD32 bytes_consumed;
|
|
+
|
|
+} id3v2_struct;
|
|
+
|
|
+/*
|
|
+ * structure corresponding to ID3 tag v1.
|
|
+ * this structure has all the field corresponding to ID3 tag v1.
|
|
+ */
|
|
+typedef struct {
|
|
+ WORD8 song_title[30]; //30 word8acters
|
|
+
|
|
+ WORD8 artist[30]; //30 word8acters
|
|
+
|
|
+ WORD8 album[30]; //30 word8acters
|
|
+
|
|
+ WORD8 year[4]; //4 word8acters
|
|
+
|
|
+ WORD8 comment[30]; //30 word8acters
|
|
+
|
|
+ WORD8 genre[1]; //1 byte
|
|
+
|
|
+} id3v1_struct;
|
|
+
|
|
+WORD32 get_info(const char *inp_buffer,
|
|
+ unsigned int avail_inp,
|
|
+ WORD32 tag_size,
|
|
+ id3_v2_frame_struct *dest);
|
|
+
|
|
+WORD32 search_id3_v2(UWORD8 *buffer);
|
|
+
|
|
+WORD32 decode_id3_v2(const char *const buffer,
|
|
+ id3v2_struct *id3v2,
|
|
+ WORD32 continue_flag,
|
|
+ WORD32 insize);
|
|
+
|
|
+WORD32 get_id3_v2_bytes(UWORD8 *buffer);
|
|
+
|
|
+WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1);
|
|
+
|
|
+WORD32 search_id3_v1(UWORD8 *buffer);
|
|
+
|
|
+WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1);
|
|
+
|
|
+void init_id3v2_field(id3v2_struct *id3v2);
|
|
+
|
|
+#endif
|
|
diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am
|
|
index 1b996d4..e813689 100644
|
|
--- a/src/utils/Makefile.am
|
|
+++ b/src/utils/Makefile.am
|
|
@@ -1,6 +1,6 @@
|
|
bin_PROGRAMS = cplay crecord
|
|
|
|
-cplay_SOURCES = cplay.c
|
|
+cplay_SOURCES = cplay.c id3_tag_decode.c
|
|
crecord_SOURCES = crecord.c
|
|
|
|
cplay_CFLAGS = -I$(top_srcdir)/include
|
|
diff --git a/src/utils/cplay.c b/src/utils/cplay.c
|
|
index 87863a3..2a52b52 100644
|
|
--- a/src/utils/cplay.c
|
|
+++ b/src/utils/cplay.c
|
|
@@ -72,6 +72,7 @@
|
|
#include "sound/compress_params.h"
|
|
#include "tinycompress/tinycompress.h"
|
|
#include "tinycompress/tinymp3.h"
|
|
+#include "tinycompress/id3_tag_decode.h"
|
|
|
|
static int verbose;
|
|
static const unsigned int DEFAULT_CODEC_ID = SND_AUDIOCODEC_PCM;
|
|
@@ -245,12 +246,97 @@ int main(int argc, char **argv)
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
+void shift_buffer(char *buf, int buf_size, int bytes_consumed)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ if (bytes_consumed <= 0)
|
|
+ return;
|
|
+
|
|
+ for (i = 0; i < buf_size - bytes_consumed; i++)
|
|
+ buf[i] = buf[i + bytes_consumed];
|
|
+}
|
|
+
|
|
+void parse_id3(FILE *file, int *offset) {
|
|
+ /* ID3 tag specific declarations */
|
|
+ unsigned char id3_buf[128];
|
|
+ unsigned char id3v2_buf[4096];
|
|
+ signed int id3_v1_found = 0, id3_v1_decoded = 0;
|
|
+ signed int id3_v2_found = 0, id3_v2_complete = 0;
|
|
+ signed int i_bytes_consumed = 0;
|
|
+ signed int i_fread_bytes;
|
|
+ id3v1_struct id3v1;
|
|
+ id3v2_struct id3v2;
|
|
+
|
|
+ {
|
|
+ fseek(file, -128, SEEK_END);
|
|
+ fread(id3_buf, 1, 128, file);
|
|
+
|
|
+ /* search for ID3V1 */
|
|
+ id3_v1_found = search_id3_v1(id3_buf + 0);
|
|
+ if (id3_v1_found) {
|
|
+ /* if ID3V1 is found, decode ID3V1 */
|
|
+ decode_id3_v1(id3_buf + 3, &id3v1);
|
|
+ id3_v1_decoded = 1;
|
|
+ }
|
|
+ fseek(file, 0, SEEK_SET);
|
|
+ }
|
|
+
|
|
+ {
|
|
+ signed int flag = 0;
|
|
+ signed int continue_flag = 0;
|
|
+
|
|
+ i_fread_bytes = fread(id3v2_buf,
|
|
+ sizeof(char), 0x1000, file);
|
|
+
|
|
+ /* search for ID3V2 */
|
|
+ id3_v2_found =
|
|
+ search_id3_v2(id3v2_buf);
|
|
+
|
|
+ if (id3_v2_found) {
|
|
+ /* initialise the max fields */
|
|
+ init_id3v2_field(&id3v2);
|
|
+
|
|
+ while (!id3_v2_complete && id3_v2_found) {
|
|
+ /* if ID3V2 is found, decode ID3V2 */
|
|
+ id3_v2_complete = decode_id3_v2((const char *const)id3v2_buf,
|
|
+ &id3v2, continue_flag, i_fread_bytes);
|
|
+
|
|
+ if (!id3_v2_complete) {
|
|
+ continue_flag = 1;
|
|
+ i_bytes_consumed = id3v2.bytes_consumed;
|
|
+
|
|
+ fseek(file, i_bytes_consumed, SEEK_SET);
|
|
+
|
|
+ i_fread_bytes = fread(id3v2_buf,
|
|
+ sizeof(unsigned char), 0x1000, file);
|
|
+ if (i_fread_bytes <= 0) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (id3_v2_complete) {
|
|
+ i_bytes_consumed = id3v2.bytes_consumed;
|
|
+ fseek(file, i_bytes_consumed, SEEK_SET);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ *offset = i_bytes_consumed;
|
|
+}
|
|
+
|
|
void get_codec_mp3(FILE *file, struct compr_config *config,
|
|
struct snd_codec *codec)
|
|
{
|
|
size_t read;
|
|
struct mp3_header header;
|
|
unsigned int channels, rate, bits;
|
|
+ int offset = 0;
|
|
+
|
|
+ parse_id3(file, &offset);
|
|
+
|
|
+ fseek(file, offset, SEEK_SET);
|
|
|
|
read = fread(&header, 1, sizeof(header), file);
|
|
if (read != sizeof(header)) {
|
|
@@ -279,6 +365,8 @@ void get_codec_mp3(FILE *file, struct compr_config *config,
|
|
codec->level = 0;
|
|
codec->ch_mode = 0;
|
|
codec->format = 0;
|
|
+
|
|
+ fseek(file, offset, SEEK_SET);
|
|
}
|
|
|
|
void get_codec_iec(FILE *file, struct compr_config *config,
|
|
diff --git a/src/utils/id3_tag_decode.c b/src/utils/id3_tag_decode.c
|
|
new file mode 100644
|
|
index 0000000..393967a
|
|
--- /dev/null
|
|
+++ b/src/utils/id3_tag_decode.c
|
|
@@ -0,0 +1,642 @@
|
|
+/*
|
|
+ * Copyright (c) 2006-2017 Cadence Design Systems, Inc.
|
|
+ * Copyright 2018 NXP
|
|
+ *
|
|
+ * Permission is hereby granted, free of charge, to any person obtaining
|
|
+ * a copy of this software and associated documentation files (the
|
|
+ * "Software"), to deal in the Software without restriction, including
|
|
+ * without limitation the rights to use, copy, modify, merge, publish,
|
|
+ * distribute, sublicense, and/or sell copies of the Software, and to
|
|
+ * permit persons to whom the Software is furnished to do so, subject to
|
|
+ * the following conditions:
|
|
+ *
|
|
+ * The above copyright notice and this permission notice shall be included
|
|
+ * in all copies or substantial portions of the Software.
|
|
+ *
|
|
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
|
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
|
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
|
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
+ */
|
|
+#include <ctype.h>
|
|
+#include "tinycompress/id3_tag_decode.h"
|
|
+
|
|
+#define CHAR4(c1, c2, c3, c4) \
|
|
+ (int)(((unsigned char)(c1) << 24) | \
|
|
+ ((unsigned char)(c2) << 16) | \
|
|
+ ((unsigned char)(c3) << 8) | \
|
|
+ ((unsigned char)c4))
|
|
+
|
|
+#ifndef MSVC_BUILD
|
|
+unsigned int umin(unsigned int a, unsigned int b)
|
|
+{
|
|
+ return (a < b ? a : b);
|
|
+}
|
|
+
|
|
+#else
|
|
+unsigned int umin(unsigned int a, unsigned int b)
|
|
+{
|
|
+ return (a < b ? a : b);
|
|
+}
|
|
+#endif
|
|
+
|
|
+/***********************************************************
|
|
+ * function name : display
|
|
+ *
|
|
+ * description : display ID3 tag contents.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ *
|
|
+ * values returned : 0
|
|
+ ***********************************************************/
|
|
+
|
|
+static void display2(const id3_v2_frame_struct * const src,
|
|
+ int size,
|
|
+ const char * const disp)
|
|
+{
|
|
+ int j;
|
|
+
|
|
+
|
|
+ for (j = 0; j < size; j++) {
|
|
+ int c = src->frame_data[j];
|
|
+
|
|
+ if (c) {
|
|
+ if (!isprint(c))
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static VOID display1(WORD8 src[], WORD32 size, WORD8 disp[])
|
|
+{
|
|
+ WORD32 j;
|
|
+
|
|
+ for (j = 0; j < size ; j++) {
|
|
+ int c = src[j];
|
|
+
|
|
+ if (c) {
|
|
+ if (!isprint(c))
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+/*****************************************************************
|
|
+ * function name : init_id3_header
|
|
+ *
|
|
+ * description : initialise the max filed size of teh farem.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ *
|
|
+ * values returned : 0
|
|
+ ****************************************************************/
|
|
+
|
|
+VOID init_id3v2_field(id3v2_struct *id3v2)
|
|
+{
|
|
+ id3v2->album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->composer_name.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->content_type.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->encoded_by.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->content_group_description.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->title_songname_content_description.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->medxa_type.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->original_album_movie_show_title.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->original_filename.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->original_lyricist_text_writer.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->original_artist_performer.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->file_owner_licensee.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->lead_performer_soloist.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->publisher.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->private_frame.max_size = MAX_TAG_FRAME_SIZE;
|
|
+ id3v2->other_info.max_size = MAX_TAG_FRAME_SIZE;
|
|
+
|
|
+ /* resetting the flag to indicate presese of frame */
|
|
+ id3v2->album_movie_show_title.tag_present = 0;
|
|
+ id3v2->composer_name.tag_present = 0;
|
|
+ id3v2->content_type.tag_present = 0;
|
|
+ id3v2->encoded_by.tag_present = 0;
|
|
+ id3v2->lyricist_text_writer.tag_present = 0;
|
|
+ id3v2->content_group_description.tag_present = 0;
|
|
+ id3v2->title_songname_content_description.tag_present = 0;
|
|
+ id3v2->medxa_type.tag_present = 0;
|
|
+ id3v2->original_album_movie_show_title.tag_present = 0;
|
|
+ id3v2->original_filename.tag_present = 0;
|
|
+ id3v2->original_lyricist_text_writer.tag_present = 0;
|
|
+ id3v2->original_artist_performer.tag_present = 0;
|
|
+ id3v2->file_owner_licensee.tag_present = 0;
|
|
+ id3v2->lead_performer_soloist.tag_present = 0;
|
|
+ id3v2->publisher.tag_present = 0;
|
|
+ id3v2->private_frame.tag_present = 0;
|
|
+ id3v2->other_info.tag_present = 0;
|
|
+
|
|
+ /* resetting the flag which indicates that size of the frame has
|
|
+ * exceeded the max buffer size
|
|
+ */
|
|
+ id3v2->album_movie_show_title.exceeds_buffer_size = 0;
|
|
+ id3v2->composer_name.exceeds_buffer_size = 0;
|
|
+ id3v2->content_type.exceeds_buffer_size = 0;
|
|
+ id3v2->encoded_by.exceeds_buffer_size = 0;
|
|
+ id3v2->lyricist_text_writer.exceeds_buffer_size = 0;
|
|
+ id3v2->content_group_description.exceeds_buffer_size = 0;
|
|
+ id3v2->title_songname_content_description.exceeds_buffer_size = 0;
|
|
+ id3v2->medxa_type.exceeds_buffer_size = 0;
|
|
+ id3v2->original_album_movie_show_title.exceeds_buffer_size = 0;
|
|
+ id3v2->original_filename.exceeds_buffer_size = 0;
|
|
+ id3v2->original_lyricist_text_writer.exceeds_buffer_size = 0;
|
|
+ id3v2->original_artist_performer.exceeds_buffer_size = 0;
|
|
+ id3v2->file_owner_licensee.exceeds_buffer_size = 0;
|
|
+ id3v2->lead_performer_soloist.exceeds_buffer_size = 0;
|
|
+ id3v2->publisher.exceeds_buffer_size = 0;
|
|
+ id3v2->private_frame.exceeds_buffer_size = 0;
|
|
+ id3v2->other_info.exceeds_buffer_size = 0;
|
|
+
|
|
+ id3v2->bytes_consumed = 0;
|
|
+ id3v2->header_end = 0;
|
|
+}
|
|
+
|
|
+/***************************************************************
|
|
+ * function name : search_id3_v2
|
|
+ *
|
|
+ * description : finds if ID3V2 starts at the start of given buffer.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ * buffer input buffer
|
|
+ *
|
|
+ * values returned : FLAG 1: ID3 found 0: ID3 not found
|
|
+ ***************************************************************/
|
|
+WORD32 search_id3_v2(UWORD8 *buffer)
|
|
+{
|
|
+ UWORD32 temp;
|
|
+
|
|
+ temp = buffer[0] << 16;
|
|
+ temp |= buffer[1] << 8;
|
|
+ temp |= buffer[2];
|
|
+
|
|
+ if (temp == ID3V2)
|
|
+ return 1; /* ID3 found */
|
|
+
|
|
+ return 0; /* ID3 not found */
|
|
+}
|
|
+
|
|
+/**************************************************************
|
|
+ * function name : search_id3_v1
|
|
+ *
|
|
+ * description : finds if ID3V1 starts at the start of given buffer.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ * buffer input buffer
|
|
+ *
|
|
+ * values returned : FLAG 1: ID3 found 0: ID3 not found
|
|
+ **************************************************************/
|
|
+WORD32 search_id3_v1(UWORD8 *buffer)
|
|
+{
|
|
+ UWORD32 temp;
|
|
+
|
|
+ temp = buffer[0] << 16;
|
|
+ temp |= buffer[1] << 8;
|
|
+ temp |= buffer[2];
|
|
+
|
|
+ if (temp == ID3V1)
|
|
+ return 1; /* ID3 found */
|
|
+
|
|
+ return 0; /* ID3 not found */
|
|
+}
|
|
+
|
|
+/***************************************************************
|
|
+ * function name : decode_id3_v1
|
|
+ *
|
|
+ * description : decodes ID3V1 tag.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ * buffer input buffer
|
|
+ * id3v1 structure
|
|
+ *
|
|
+ * values returned : bytes consumed
|
|
+ **************************************************************/
|
|
+WORD32 decode_id3_v1(UWORD8 *buffer, id3v1_struct *id3v1)
|
|
+{
|
|
+ WORD32 bytes_consumed = 0;
|
|
+ short tag_type;
|
|
+
|
|
+ /* setting the tag type */
|
|
+ tag_type = 1;
|
|
+
|
|
+ bytes_consumed = get_v1_info(buffer, id3v1);
|
|
+
|
|
+ return bytes_consumed;
|
|
+}
|
|
+
|
|
+/***********************************************************
|
|
+ * function name : get_v1_info
|
|
+ *
|
|
+ * description : gets ID3V1 information fields.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ * buffer input buffer
|
|
+ * id3v1 structure
|
|
+ *
|
|
+ * values returned : bytes consumed
|
|
+ ***********************************************************/
|
|
+WORD32 get_v1_info(UWORD8 *buffer, id3v1_struct *id3v1)
|
|
+{
|
|
+ WORD32 i;
|
|
+ WORD32 bytes_consumed = 0;
|
|
+
|
|
+ /* get song_title */
|
|
+ for (i = 0; i < 30; i++)
|
|
+ id3v1->song_title[i] = buffer[i];
|
|
+
|
|
+ buffer += 30;
|
|
+ bytes_consumed += 30;
|
|
+ display1(id3v1->song_title, 30, (WORD8 *)"song_title : ");
|
|
+
|
|
+ /* get artist */
|
|
+ for (i = 0; i < 30; i++)
|
|
+ id3v1->artist[i] = buffer[i];
|
|
+
|
|
+ buffer += 30;
|
|
+ bytes_consumed += 30;
|
|
+ display1(id3v1->artist, 30, (WORD8 *)"artist : ");
|
|
+
|
|
+ /* get album */
|
|
+ for (i = 0; i < 30; i++)
|
|
+ id3v1->album[i] = buffer[i];
|
|
+
|
|
+ buffer += 30;
|
|
+ bytes_consumed += 30;
|
|
+ display1(id3v1->album, 30, (WORD8 *)"album : ");
|
|
+
|
|
+ /* get year */
|
|
+ for (i = 0; i < 4; i++)
|
|
+ id3v1->year[i] = buffer[i];
|
|
+
|
|
+ buffer += 4;
|
|
+ bytes_consumed += 4;
|
|
+ display1(id3v1->year, 4, (WORD8 *)"year : ");
|
|
+
|
|
+ /* get comment */
|
|
+ for (i = 0; i < 30; i++)
|
|
+ id3v1->comment[i] = buffer[i];
|
|
+
|
|
+ buffer += 30;
|
|
+ bytes_consumed += 30;
|
|
+ display1(id3v1->comment, 30, (WORD8 *)"comment : ");
|
|
+
|
|
+ /* get genre */
|
|
+ for (i = 0; i < 1; i++)
|
|
+ id3v1->genre[i] = buffer[i];
|
|
+
|
|
+ buffer += 1;
|
|
+ bytes_consumed += 1;
|
|
+
|
|
+ return bytes_consumed;
|
|
+}
|
|
+
|
|
+/*****************************************************
|
|
+ * function name : decode_id3_v2
|
|
+ *
|
|
+ * description : decodes ID3V2 tag.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ * buffer input buffer
|
|
+ * id3v2 structure
|
|
+ * continue_flag FLAG to indicate whether
|
|
+ * it is first call or not
|
|
+ * insize input buffer size
|
|
+ *
|
|
+ * values returned : bytes consumed
|
|
+ ******************************************************/
|
|
+WORD32 decode_id3_v2(const char *const buffer,
|
|
+ id3v2_struct *const id3v2,
|
|
+ WORD32 continue_flag,
|
|
+ WORD32 insize)
|
|
+{
|
|
+ UWORD32 size = 0, flag;
|
|
+ WORD32 i, buf_update_val;
|
|
+ UWORD8 buf[4], frame_header[10], id3_buffer[10];
|
|
+ WORD8 *bitstream_ptr;
|
|
+ short tag_type;
|
|
+
|
|
+ WORD32 bytes_consumed = 0;
|
|
+
|
|
+ if (id3v2->header_end == 1) {
|
|
+ id3v2->bytes_consumed += insize;
|
|
+ if (id3v2->bytes_consumed < id3v2->id3_v2_header.size)
|
|
+ return 0;
|
|
+
|
|
+ id3v2->bytes_consumed = (id3v2->id3_v2_header.size + 10);
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ bitstream_ptr = (WORD8 *)id3_buffer;
|
|
+
|
|
+ if (!continue_flag) {
|
|
+ bytes_consumed += 3;
|
|
+ /* setting the tag type */
|
|
+ tag_type = 2;
|
|
+ id3v2->id3_v2_header.version = buffer[bytes_consumed + 0] << 8;
|
|
+ id3v2->id3_v2_header.version |= buffer[bytes_consumed + 1];
|
|
+ id3v2->id3_v2_header.flag = buffer[bytes_consumed + 2];
|
|
+
|
|
+ /* making the msb of each byte zero */
|
|
+ buf[0] = buffer[bytes_consumed + 6] & 0x7f;
|
|
+ buf[1] = buffer[bytes_consumed + 5] & 0x7f;
|
|
+ buf[2] = buffer[bytes_consumed + 4] & 0x7f;
|
|
+ buf[3] = buffer[bytes_consumed + 3] & 0x7f;
|
|
+
|
|
+ bytes_consumed += 7;
|
|
+
|
|
+ /* concatenation the bytes after making
|
|
+ * 7th bit zero to get 28 bits size
|
|
+ */
|
|
+ size = buf[0];
|
|
+ size |= (buf[1] << 7);
|
|
+ size |= (buf[2] << 14);
|
|
+ size |= (buf[3] << 21);
|
|
+ /* storing the size */
|
|
+ id3v2->id3_v2_header.size = size;
|
|
+
|
|
+ /* check for extended header */
|
|
+ if (id3v2->id3_v2_header.flag & 0x20) {
|
|
+ for (i = 0; i < 10; i++)
|
|
+ bitstream_ptr[i] = buffer[bytes_consumed + i];
|
|
+
|
|
+ i = 0;
|
|
+ bytes_consumed += 10;
|
|
+
|
|
+ size = bitstream_ptr[i++] << 24;
|
|
+ size |= bitstream_ptr[i++] << 16;
|
|
+ size |= bitstream_ptr[i++] << 8;
|
|
+ size |= bitstream_ptr[i++];
|
|
+
|
|
+ /* two bytes for flag */
|
|
+ i += 2;
|
|
+ {
|
|
+ UWORD32 padding_size;
|
|
+
|
|
+ padding_size = bitstream_ptr[i++] << 24;
|
|
+ padding_size |= bitstream_ptr[i++] << 16;
|
|
+ padding_size |= bitstream_ptr[i++] << 8;
|
|
+ padding_size |= bitstream_ptr[i++];
|
|
+
|
|
+ /* skipping the padding and frame size
|
|
+ * number of bytes
|
|
+ */
|
|
+ bytes_consumed += (padding_size + size);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ while (id3v2->header_end != 1) {
|
|
+ char *key;
|
|
+ id3_v2_frame_struct *value;
|
|
+ unsigned int avail_inp;
|
|
+
|
|
+ /* reading the 10 bytes to get the frame header */
|
|
+
|
|
+ for (i = 0; i < 10; i++)
|
|
+ frame_header[i] = buffer[bytes_consumed + i];
|
|
+ bytes_consumed += 10;
|
|
+
|
|
+ /* getting the size from the header */
|
|
+ size = frame_header[4] << 24;
|
|
+ size |= frame_header[5] << 16;
|
|
+ size |= frame_header[6] << 8;
|
|
+ size |= frame_header[7];
|
|
+
|
|
+ /* decoding the flag, currently not used */
|
|
+ flag = frame_header[8] << 8;
|
|
+ flag |= frame_header[9];
|
|
+
|
|
+ avail_inp = insize - bytes_consumed;
|
|
+
|
|
+ /* switching to the frame type */
|
|
+ switch (CHAR4(frame_header[0],
|
|
+ frame_header[1],
|
|
+ frame_header[2],
|
|
+ frame_header[3])) {
|
|
+ case CHAR4('A', 'E', 'N', 'C'):
|
|
+ case CHAR4('A', 'P', 'I', 'C'):
|
|
+ case CHAR4('C', 'O', 'M', 'M'):
|
|
+ case CHAR4('C', 'O', 'M', 'R'):
|
|
+ case CHAR4('E', 'N', 'C', 'R'):
|
|
+ case CHAR4('E', 'Q', 'U', 'A'):
|
|
+ case CHAR4('E', 'T', 'C', 'O'):
|
|
+ case CHAR4('G', 'E', 'O', 'B'):
|
|
+ case CHAR4('G', 'R', 'I', 'D'):
|
|
+ case CHAR4('I', 'P', 'L', 'S'):
|
|
+ case CHAR4('L', 'I', 'N', 'K'):
|
|
+ case CHAR4('M', 'C', 'D', 'I'):
|
|
+ case CHAR4('M', 'L', 'L', 'T'):
|
|
+ case CHAR4('O', 'W', 'N', 'E'):
|
|
+ case CHAR4('P', 'C', 'N', 'T'):
|
|
+ case CHAR4('P', 'O', 'P', 'M'):
|
|
+ case CHAR4('P', 'O', 'S', 'S'):
|
|
+ case CHAR4('R', 'B', 'U', 'F'):
|
|
+ case CHAR4('R', 'V', 'A', 'D'):
|
|
+ case CHAR4('R', 'V', 'R', 'B'):
|
|
+ case CHAR4('S', 'Y', 'L', 'T'):
|
|
+ case CHAR4('S', 'Y', 'T', 'C'):
|
|
+ case CHAR4('T', 'B', 'P', 'M'):
|
|
+ case CHAR4('T', 'C', 'O', 'P'):
|
|
+ case CHAR4('T', 'D', 'A', 'T'):
|
|
+ case CHAR4('T', 'D', 'L', 'Y'):
|
|
+ case CHAR4('T', 'F', 'L', 'T'):
|
|
+ case CHAR4('T', 'I', 'M', 'E'):
|
|
+ case CHAR4('T', 'K', 'E', 'Y'):
|
|
+ case CHAR4('T', 'L', 'A', 'N'):
|
|
+ case CHAR4('T', 'L', 'E', 'N'):
|
|
+ case CHAR4('T', 'M', 'E', 'D'):
|
|
+ case CHAR4('T', 'O', 'F', 'N'):
|
|
+ case CHAR4('T', 'O', 'L', 'Y'):
|
|
+ case CHAR4('T', 'O', 'R', 'Y'):
|
|
+ case CHAR4('T', 'P', 'E', '2'):
|
|
+ case CHAR4('T', 'P', 'E', '3'):
|
|
+ case CHAR4('T', 'P', 'E', '4'):
|
|
+ case CHAR4('T', 'P', 'O', 'S'):
|
|
+ case CHAR4('T', 'R', 'C', 'K'):
|
|
+ case CHAR4('T', 'R', 'D', 'A'):
|
|
+ case CHAR4('T', 'R', 'S', 'N'):
|
|
+ case CHAR4('T', 'R', 'S', 'O'):
|
|
+ case CHAR4('T', 'S', 'I', 'Z'):
|
|
+ case CHAR4('T', 'S', 'R', 'C'):
|
|
+ case CHAR4('T', 'S', 'S', 'E'):
|
|
+ case CHAR4('T', 'Y', 'E', 'R'):
|
|
+ case CHAR4('T', 'X', 'X', 'X'):
|
|
+ case CHAR4('U', 'F', 'I', 'D'):
|
|
+ case CHAR4('U', 'S', 'E', 'R'):
|
|
+ case CHAR4('U', 'S', 'L', 'T'):
|
|
+ case CHAR4('W', 'C', 'O', 'M'):
|
|
+ case CHAR4('W', 'C', 'O', 'P'):
|
|
+ case CHAR4('W', 'O', 'A', 'F'):
|
|
+ case CHAR4('W', 'O', 'A', 'R'):
|
|
+ case CHAR4('W', 'O', 'A', 'S'):
|
|
+ case CHAR4('W', 'O', 'R', 'S'):
|
|
+ case CHAR4('W', 'P', 'A', 'Y'):
|
|
+ case CHAR4('W', 'P', 'U', 'B'):
|
|
+ case CHAR4('W', 'X', 'X', 'X'):
|
|
+ case CHAR4('T', 'I', 'T', '3'):
|
|
+ key = "other_info : ";
|
|
+ value = &id3v2->other_info;
|
|
+ break;
|
|
+ case CHAR4('P', 'R', 'I', 'V'):
|
|
+ key = "private_frame : ";
|
|
+ value = &id3v2->private_frame;
|
|
+ break;
|
|
+ case CHAR4('T', 'A', 'L', 'B'):
|
|
+ key = "album_movie_show_title : ";
|
|
+ value = &id3v2->album_movie_show_title;
|
|
+ break;
|
|
+ case CHAR4('T', 'C', 'O', 'M'):
|
|
+ key = "composer_name : ";
|
|
+ value = &id3v2->composer_name;
|
|
+ break;
|
|
+ case CHAR4('T', 'C', 'O', 'N'):
|
|
+ key = "content_type : ";
|
|
+ value = &id3v2->content_type;
|
|
+ break;
|
|
+ case CHAR4('T', 'E', 'N', 'C'):
|
|
+ key = "encoded_by : ";
|
|
+ value = &id3v2->encoded_by;
|
|
+ break;
|
|
+ case CHAR4('T', 'E', 'X', 'T'):
|
|
+ key = "lyricist_text_writer : ";
|
|
+ value = &id3v2->lyricist_text_writer;
|
|
+ break;
|
|
+ case CHAR4('T', 'I', 'T', '1'):
|
|
+ key = "content_group_description : ";
|
|
+ value = &id3v2->content_group_description;
|
|
+ break;
|
|
+ case CHAR4('T', 'I', 'T', '2'):
|
|
+ key = "title_songname_content_description : ";
|
|
+ value = &id3v2->title_songname_content_description;
|
|
+ break;
|
|
+ case CHAR4('T', 'O', 'A', 'L'):
|
|
+ key = "original_album_movie_show_title : ";
|
|
+ value = &id3v2->original_album_movie_show_title;
|
|
+ break;
|
|
+ case CHAR4('T', 'O', 'P', 'E'):
|
|
+ key = "original_artist_performer : ";
|
|
+ value = &id3v2->original_artist_performer;
|
|
+ break;
|
|
+ case CHAR4('T', 'O', 'W', 'N'):
|
|
+ key = "file_owner_licensee : ";
|
|
+ value = &id3v2->file_owner_licensee;
|
|
+ break;
|
|
+ case CHAR4('T', 'P', 'E', '1'):
|
|
+ key = "lead_performer_soloist : ";
|
|
+ value = &id3v2->lead_performer_soloist;
|
|
+ break;
|
|
+ case CHAR4('T', 'P', 'U', 'B'):
|
|
+ key = "publisher : ";
|
|
+ value = &id3v2->publisher;
|
|
+ break;
|
|
+ default:
|
|
+ /* skipping the read 10 bytes */
|
|
+ buf_update_val = -10;
|
|
+ id3v2->header_end = 1;
|
|
+ value = 0;
|
|
+ key = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (value != 0)
|
|
+ buf_update_val = get_info(&buffer[bytes_consumed],
|
|
+ avail_inp, size, value);
|
|
+
|
|
+ /* Negative value for buf_update_val means one of two things:
|
|
+ * 1. The default case happened and we're done with ID3V2 tag
|
|
+ * frames, or
|
|
+ * 2. get_info() returned -1 to indicate that more input is
|
|
+ * required to decode this frame of the tag.
|
|
+ */
|
|
+ if (buf_update_val >= 0)
|
|
+ display2(value,
|
|
+ umin(value->max_size, buf_update_val), key);
|
|
+
|
|
+ if (buf_update_val == -1) {
|
|
+ id3v2->bytes_consumed += bytes_consumed;
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+ bytes_consumed += buf_update_val;
|
|
+
|
|
+ /* Is there enough input left (10 bytes) to begin
|
|
+ * decoding another frame? If not, bag out temporarily
|
|
+ * now. The caller will refill our input buffer and
|
|
+ * call us again with continue_flag == 1.
|
|
+ */
|
|
+ if (insize - bytes_consumed < 10) {
|
|
+ id3v2->bytes_consumed += bytes_consumed;
|
|
+ return 0; /* not completely decoded */
|
|
+ }
|
|
+ }
|
|
+
|
|
+ id3v2->bytes_consumed += bytes_consumed;
|
|
+ if ((id3v2->bytes_consumed + 10) < id3v2->id3_v2_header.size)
|
|
+ return 0; /* not completely decoded */
|
|
+
|
|
+ return 1; /* completely decoded */
|
|
+}
|
|
+
|
|
+/*******************************************************
|
|
+ * function name : get_id3_v2_bytes
|
|
+ *
|
|
+ * description : tells the size of ID3V2 tag.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ * buffer input buffer
|
|
+ *
|
|
+ * values returned : bytes consumed
|
|
+ ********************************************************/
|
|
+WORD32 get_id3_v2_bytes(UWORD8 *buffer)
|
|
+{
|
|
+ WORD32 size;
|
|
+
|
|
+ /* making the msb of each byte zero */
|
|
+ size = (buffer[9] & 0x7f);
|
|
+ size |= ((buffer[8] & 0x7f) << 7);
|
|
+ size |= ((buffer[7] & 0x7f) << 14);
|
|
+ size |= ((buffer[6] & 0x7f) << 21);
|
|
+
|
|
+ return (size + 10);
|
|
+}
|
|
+
|
|
+/****************************************************
|
|
+ * function name : get_info
|
|
+ *
|
|
+ * description : read the frame information from the input buffer.
|
|
+ *
|
|
+ * arguments : input parameters
|
|
+ *
|
|
+ * values returned : update value for buffer
|
|
+ ****************************************************/
|
|
+WORD32 get_info(const char *inp_buffer,
|
|
+ unsigned int avail_inp,
|
|
+ WORD32 tag_size,
|
|
+ id3_v2_frame_struct *dest)
|
|
+{
|
|
+ WORD32 j;
|
|
+
|
|
+ /* setting the tag to indicate the presence of frame */
|
|
+ dest->tag_present = 1;
|
|
+ /* If there isn't enough input available, we punt back to the top
|
|
+ * level and ask for more.
|
|
+ */
|
|
+ if (avail_inp < umin(tag_size, dest->max_size))
|
|
+ return -1;
|
|
+
|
|
+ if (dest->max_size >= tag_size) {
|
|
+ for (j = 0; j < tag_size ; j++)
|
|
+ dest->frame_data[j] = inp_buffer[j];
|
|
+ } else {
|
|
+ dest->exceeds_buffer_size = 1;
|
|
+ for (j = 0; j < dest->max_size ; j++)
|
|
+ dest->frame_data[j] = inp_buffer[j];
|
|
+ }
|
|
+ return tag_size;
|
|
+}
|
|
--
|
|
2.7.4
|
|
|