summaryrefslogtreecommitdiff
path: root/formats
diff options
context:
space:
mode:
Diffstat (limited to 'formats')
-rwxr-xr-xformats/Makefile.am2
-rwxr-xr-xformats/ffmpeg/Makefile.am74
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_aac.h90
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_amr.h56
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_audio.h215
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_dummy.h37
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_ffmpeg.h36
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_ffmpeg_drm.h37
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_ffmpeg_mem.h37
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_id3tag.h282
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_imelody.h44
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_midi.h49
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_mmf.h36
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_mp3.h34
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_private.h52
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_tag_id3.h56
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_tags.h65
-rwxr-xr-xformats/ffmpeg/include/mm_file_format_wav.h37
-rwxr-xr-xformats/ffmpeg/mm_file_format_aac.c965
-rwxr-xr-xformats/ffmpeg/mm_file_format_amr.c501
-rwxr-xr-xformats/ffmpeg/mm_file_format_dummy.c91
-rwxr-xr-xformats/ffmpeg/mm_file_format_ffmpeg.c1296
-rwxr-xr-xformats/ffmpeg/mm_file_format_ffmpeg_mem.c248
-rwxr-xr-xformats/ffmpeg/mm_file_format_frame.c357
-rwxr-xr-xformats/ffmpeg/mm_file_format_imelody.c1699
-rwxr-xr-xformats/ffmpeg/mm_file_format_midi.c1518
-rwxr-xr-xformats/ffmpeg/mm_file_format_mmf.c2934
-rwxr-xr-xformats/ffmpeg/mm_file_format_mp3.c1459
-rwxr-xr-xformats/ffmpeg/mm_file_format_tag_id3.c198
-rwxr-xr-xformats/ffmpeg/mm_file_format_tags.c250
-rwxr-xr-xformats/ffmpeg/mm_file_format_wav.c505
-rwxr-xr-xformats/ffmpeg/mm_file_formats.c1049
32 files changed, 14309 insertions, 0 deletions
diff --git a/formats/Makefile.am b/formats/Makefile.am
new file mode 100755
index 0000000..2962060
--- /dev/null
+++ b/formats/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS=ffmpeg
+
diff --git a/formats/ffmpeg/Makefile.am b/formats/ffmpeg/Makefile.am
new file mode 100755
index 0000000..8457f15
--- /dev/null
+++ b/formats/ffmpeg/Makefile.am
@@ -0,0 +1,74 @@
+lib_LTLIBRARIES = libmmfile_formats.la
+
+
+libmmfile_formats_la_DEPENDENCIES = $(top_builddir)/utils/libmmfile_utils.la
+
+noinst_HEADERS = include/mm_file_format_dummy.h \
+ include/mm_file_format_aac.h \
+ include/mm_file_format_amr.h \
+ include/mm_file_format_imelody.h \
+ include/mm_file_format_midi.h \
+ include/mm_file_format_ffmpeg_mem.h \
+ include/mm_file_format_ffmpeg.h \
+ include/mm_file_format_mmf.h \
+ include/mm_file_format_mp3.h \
+ include/mm_file_format_wav.h \
+ include/mm_file_format_private.h
+
+libmmfile_formats_la_SOURCES = mm_file_formats.c \
+ mm_file_format_dummy.c \
+ mm_file_format_ffmpeg.c \
+ mm_file_format_ffmpeg_mem.c \
+ mm_file_format_mp3.c \
+ mm_file_format_aac.c \
+ mm_file_format_mmf.c \
+ mm_file_format_amr.c \
+ mm_file_format_midi.c \
+ mm_file_format_imelody.c \
+ mm_file_format_wav.c \
+ mm_file_format_frame.c
+
+libmmfile_formats_la_CFLAGS = -I$(srcdir)/include \
+ $(MMCOMMON_CFLAGS) \
+ -I$(srcdir)/../../include \
+ -I$(srcdir)/../../utils/include \
+ -D_LARGEFILE64_SOURCE \
+ -D_FILE_OFFSET_BITS=64 \
+ $(AVUTIL_CFLAGS) \
+ $(AVCODEC_CFLAGS) \
+ $(SWSCALE_CFLAGS) \
+ $(AVFORMAT_CFLAGS)
+
+if USE_TESTMODE
+libmmfile_formats_la_CFLAGS += -D__MMFILE_TEST_MODE__
+endif
+
+if USE_DUMP
+libmmfile_formats_la_CFLAGS += -DMMFILE_FORMAT_DEBUG_DUMP
+endif
+
+if USE_DRM
+libmmfile_formats_la_CFLAGS += $(DRMCLIENT_CFLAGS) -DDRM_SUPPORT
+endif
+
+if USE_IOMMAP
+libmmfile_formats_la_CFLAGS += -D__MMFILE_MMAP_MODE__
+endif
+
+
+libmmfile_formats_la_LIBADD = $(MMCOMMON_LIBS) \
+ $(AVUTIL_LIBS) \
+ $(AVCODEC_LIBS) \
+ $(AVFORMAT_LIBS) \
+ $(SWSCALE_LIBS) \
+ $(top_builddir)/utils/libmmfile_utils.la
+
+if USE_DRM
+libmmfile_formats_la_LIBADD += $(DRMCLIENT_LIBS)
+endif
+
+libmmfile_formats_la_CFLAGS += $(MMLOG_CFLAGS) -DMMF_LOG_OWNER=0x040 -DMMF_DEBUG_PREFIX=\"MMF-FILE-FORMAT-FFMPEG\"
+libmmfile_formats_la_LIBADD += $(MMLOG_LIBS)
+
+libmmfile_formats_la_CFLAGS += -D__MMFILE_FFMPEG_V100__
+libmmfile_formats_la_CFLAGS += -D__MMFILE_FFMPEG_V085__
diff --git a/formats/ffmpeg/include/mm_file_format_aac.h b/formats/ffmpeg/include/mm_file_format_aac.h
new file mode 100755
index 0000000..25f3328
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_aac.h
@@ -0,0 +1,90 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_AAC_H__
+#define __MM_FILE_FORMAT_AAC_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mm_file_formats.h"
+
+#define MMFILE_AAC_PARSER_SUCCESS 1
+#define MMFILE_AAC_PARSER_FAIL 0
+
+typedef enum _mmfile_aac_profile_type {
+ AAC_PROFILE_MAIN,
+ AAC_PROFILE_LC,
+ AAC_PROFILE_SSR,
+ AAC_PROFILE_LTP,
+ AAC_PROFILE_UNKNOWN
+}TAacProfileType;
+
+typedef void* MMFileAACHandle;
+
+typedef struct _mmfileaacstreaminfo {
+ unsigned int iseekable;
+ long long duration;
+ long long fileSize;
+ unsigned int bitRate;
+ unsigned int samplingRate;
+ unsigned int frameRate;
+ unsigned int numAudioChannels;
+ unsigned int numTracks;
+ TAacProfileType profileType;
+} tMMFILE_AAC_STREAM_INFO;
+
+
+typedef struct _mmfileaactaginfo {
+ char *title;
+ char *author;
+ char *artist;
+ char *album;
+ char *year;
+ char *copyright;
+ char *comment;
+ char *genre;
+ char *tracknum;
+ char *composer;
+ char *classification;
+ char *rating;
+ char *recordDate;
+ char *conductor;
+ char *artworkMime;
+ char *artwork;
+ unsigned int artworkSize;
+} tMMFILE_AAC_TAG_INFO;
+
+
+int mmfile_aacparser_open (MMFileAACHandle *handle, const char *src);
+int mmfile_aacparser_get_stream_info (MMFileAACHandle handle, tMMFILE_AAC_STREAM_INFO *aacinfo);
+int mmfile_aacparser_get_tag_info (MMFileAACHandle handle, tMMFILE_AAC_TAG_INFO *info);
+int mmfile_aacparser_get_next_frame (MMFileAACHandle handle, tMMFILE_AAC_STREAM_INFO *aacinfo);
+int mmfile_aacparser_close (MMFileAACHandle handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_AAC_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_amr.h b/formats/ffmpeg/include/mm_file_format_amr.h
new file mode 100755
index 0000000..4df6dcd
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_amr.h
@@ -0,0 +1,56 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_AMR_H__
+#define __MM_FILE_FORMAT_AMR_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mm_file_formats.h"
+
+#define MMFILE_AMR_PARSER_SUCCESS 1
+#define MMFILE_AMR_PARSER_FAIL 0
+
+typedef void* MMFileAMRHandle;
+
+typedef struct _mmfileamrstreaminfo {
+ long long duration;
+ long long fileSize;
+ unsigned int bitRate;
+ unsigned int samplingRate;
+ unsigned int frameRate;
+ unsigned int numAudioChannels;
+ unsigned int numTracks;
+} tMMFILE_AMR_STREAM_INFO;
+
+
+int mmfile_amrparser_open (MMFileAMRHandle *handle, const char *src);
+int mmfile_amrparser_get_stream_info (MMFileAMRHandle handle, tMMFILE_AMR_STREAM_INFO *amrinfo);
+int mmfile_amrparser_close (MMFileAMRHandle handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_AMR_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_audio.h b/formats/ffmpeg/include/mm_file_format_audio.h
new file mode 100755
index 0000000..0711395
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_audio.h
@@ -0,0 +1,215 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _MM_FILE_FORMAT_AUDIO_H_
+#define _MM_FILE_FORMAT_AUDIO_H_
+
+#define MPEG_1_SIZE_LAYER_1 384
+#define MPEG_1_SIZE_LAYER_2_3 1152
+
+#define MPEG_2_SIZE_LAYER_1 (MPEG_1_SIZE_LAYER_1 / 2)
+#define MPEG_2_SIZE_LAYER_2_3 (MPEG_1_SIZE_LAYER_2_3 / 2)
+
+/* MP3 */
+#define MP3TAGINFO_SIZE 128 // file end 128 byte
+#define FRAMES_FLAG 0x0001
+#define BYTES_FLAG 0x0002
+#define TOC_FLAG 0x0004
+#define VBR_SCALE_FLAG 0x0008
+
+#define FRAMES_AND_BYTES (FRAMES_FLAG | BYTES_FLAG)
+#define VALID_SYNC(x) (((unsigned char *)(x))[0] == 0xFF && (((unsigned char *)(x))[1] & 0xE0) == 0xE0)
+
+#define AV_MP3HDR_VERSION_OFS 1
+#define AV_MP3HDR_VERSION_M 0x18
+#define AV_MP3HDR_VERSION_SHIFT 3
+
+#define AV_MP3HDR_LAYER_OFS 1
+#define AV_MP3HDR_LAYER_M 0x06
+#define AV_MP3HDR_LAYER_SHIFT 1
+
+#define AV_MP3HDR_CRC_OFS 1
+#define AV_MP3HDR_CRC_M 0x01
+#define AV_MP3HDR_CRC_SHIFT 0
+
+#define AV_MP3HDR_BITRATE_OFS 2
+#define AV_MP3HDR_BITRATE_M 0xF0
+#define AV_MP3HDR_BITRATE_SHIFT 4
+
+#define AV_MP3HDR_SAMPLERATE_OFS 2
+#define AV_MP3HDR_SAMPLERATE_M 0x0C
+#define AV_MP3HDR_SAMPLERATE_SHIFT 2
+
+#define AV_MP3HDR_PADDING_OFS 2
+#define AV_MP3HDR_PADDING_M 0x02
+#define AV_MP3HDR_PADDING_SHIFT 1
+
+#define AV_MP3HDR_PRIVATE_OFS 2
+#define AV_MP3HDR_PRIVATE_M 0x01
+#define AV_MP3HDR_PRIVATE_SHIFT 0
+
+#define AV_MP3HDR_CHANNEL_OFS 3
+#define AV_MP3HDR_CHANNEL_M 0xC0
+#define AV_MP3HDR_CHANNEL_SHIFT 6
+
+#define AV_MP3HDR_CHANNEL_EXT_OFS 3
+#define AV_MP3HDR_CHANNEL_EXT_M 0x30
+#define AV_MP3HDR_CHANNEL_EXT_SHIFT 4
+
+#define AV_MP3HDR_COPYRIGHT_OFS 3
+#define AV_MP3HDR_COPYRIGHT_M 0x08
+#define AV_MP3HDR_COPYRIGHT_SHIFT 3
+
+#define AV_MP3HDR_ORIGINAL_OFS 3
+#define AV_MP3HDR_ORIGINAL_M 0x06
+#define AV_MP3HDR_ORIGINAL_SHIFT 2
+
+#define AV_MP3HDR_EMPHASIS_OFS 3
+#define AV_MP3HDR_EMPHASIS_M 0x03
+#define AV_MP3HDR_EMPHASIS_SHIFT 0
+
+#define MASK_MPEG 0x18 // 00011000
+#define MASK_MPEG_25 0x00 // 00000000
+#define MASK_MPEG_2 0x10 // 00010000
+#define MASK_MPEG_1 0x18 // 00011000
+
+#define MASK_LAYER 0x06 // 00000110
+#define MASK_LAYER_3 0x02 // 00000010
+#define MASK_LAYER_2 0x04 // 00000100
+#define MASK_LAYER_1 0x06 // 00000110
+
+#define MASK_CHANNEL 0xC0 // 11000000
+#define MASK_CHANNEL_ST 0x00 // 00000000
+#define MASK_CHANNEL_JS 0x40 // 01000000
+#define MASK_CHANNEL_DC 0x80 // 10000000
+#define MASK_CHANNEL_MN 0xC0 // 11000000
+
+#define MASK_SAMPLERATE 0x0C // 00001100
+
+#define MASK_PADDING 0x02 // 00000010
+
+#define _AV_MP3_HEADER_POSITION_MAX (50*1024) // mp3 header should be exist inside this size
+#define AV_MP3_HEADER_READ_MAX 200000 // mp3 header should be exist inside this size
+#define AV_WM_LOCALCODE_SIZE_MAX 2
+
+/*
+ * Xing Header Information
+ */
+typedef struct{
+ int hId; // from MPEG header, 0=MPEG2, 1=MPEG1
+ int sampRate; // determined from MPEG header
+ int flags; // from Xing header data
+ int frames; // total bit stream frames from Xing header data
+ int bytes; // total bit stream bytes from Xing header data
+ int vbrScale; // encoded vbr scale from Xing header data
+ unsigned char *toc; // pointer to unsigned char toc_buffer[100]
+ // may be NULL if toc not desired
+} AvXHeadData;
+
+typedef struct{
+ int hId; // from MPEG header, 0=MPEG2, 1=MPEG1
+ int vID; // ver. ID
+ int sampRate; // determined from MPEG header
+ float delay; // delay
+ int qualityIndicator; // qualityIndicator
+ int bytes; // total bit stream bytes from Xing header data
+ int frames; // total bit stream frames from Xing header data
+ int numOfTOC; // numOfTOC
+ int vbriScale; // encoded vbri scale from VBRI header data
+ int sizePerTable; // encoded sizePerTable from VBRI header data
+ int framesPerTable; //encoded framesPerTable from VBRI header data
+ unsigned char *toc; // pointer to unsigned char toc_buffer[100]
+ // may be NULL if toc not desired
+} AvVBRIHeadData;
+
+typedef enum {
+
+ AV_MPEG_VER_RESERVED, /* Reserved */
+ AV_MPEG_VER_1, /* MPEG Version 1.0 */
+ AV_MPEG_VER_2, /* MPEG Version 2.0 */
+ AV_MPEG_VER_25, /* MPEG Version 2.5 */
+ AV_MPEG_VER_4, /* MPEG Version 4 */
+ AV_MPEG_VER_UNKNOWN /* Unable to determine version information */
+} AvMp3VerEnumType;
+
+typedef enum {
+ AV_MP3_LAYER_RESERVED = 0, /* Reserved */
+ AV_MPEG2_LAYER_AAC = AV_MP3_LAYER_RESERVED, /* MPEG2 AAC compression */
+ AV_MP3_LAYER_1, /* MPEG Layer 1 compression */
+ AV_MP3_LAYER_2, /* MPEG Layer 2 compression */
+ AV_MP3_LAYER_3, /* MPEG Layer 3 compression */
+ AV_MP3_LAYER_UNKNOWN /* Unable to determine layer information */
+}AvMpegLayerEnumType;
+
+typedef enum {
+ AV_MP3_BITRATE_FREE = 0, /* Free bitrate (determined by software) */
+ AV_MP3_BITRATE_8K = 8, /* Fixed bitrates */
+ AV_MP3_BITRATE_16K = 16, /* */
+ AV_MP3_BITRATE_24K = 24, /* */
+ AV_MP3_BITRATE_32K = 32, /* */
+ AV_MP3_BITRATE_40K = 40, /* */
+ AV_MP3_BITRATE_48K = 48, /* */
+ AV_MP3_BITRATE_56K = 56, /* */
+ AV_MP3_BITRATE_64K = 64, /* */
+ AV_MP3_BITRATE_80K = 80, /* */
+ AV_MP3_BITRATE_96K = 96, /* */
+ AV_MP3_BITRATE_112K = 112, /* */
+ AV_MP3_BITRATE_128K = 128, /* */
+ AV_MP3_BITRATE_144K = 144, /* */
+ AV_MP3_BITRATE_160K = 160, /* */
+ AV_MP3_BITRATE_176K = 176, /* */
+ AV__MP3_BITRATE_192K = 192, /* */
+ AV_MP3_BITRATE_224K = 224, /* */
+ AV_MP3_BITRATE_256K = 256, /* */
+ AV_MP3_BITRATE_288K = 288, /* */
+ AV_MP3_BITRATE_320K = 320, /* */
+ AV_MP3_BITRATE_352K = 352, /* */
+ AV_MP3_BITRATE_384K = 384, /* */
+ AV_MP3_BITRATE_416K = 416, /* */
+ AV_MP3_BITRATE_448K = 448, /* */
+ AV_MP3_BITRATE_VAR = 500, /* Variable bitrate (Changes each frame) */
+ AV_MP3_BITRATE_UNK = 501 /* Unable to determine bitrate information */
+} AvMp3BitRateEnumType;
+
+typedef enum {
+ AV_SAMPLE_RATE_NONE, /* Zero sampling rate, turn clocks off */
+
+ AV_SAMPLE_RATE_8000 = 8000, /* 8k */
+ AV_SAMPLE_RATE_11025 = 11025, /* 11.025k */
+ AV_SAMPLE_RATE_12000 = 12000, /* 12k */
+
+ AV_SAMPLE_RATE_16000 = 16000, /* 16k */
+ AV_SAMPLE_RATE_22050 = 22050, /* 22.050k */
+ AV_SAMPLE_RATE_24000 = 24000, /* 24k */
+
+ AV_SAMPLE_RATE_32000 = 32000, /* 32k */
+ AV_SAMPLE_RATE_44100 = 44100, /* 44.1k */
+ AV_SAMPLE_RATE_48000 = 48000, /* 48k */
+
+ AV_SAMPLE_RATE_64000 = 64000, /* 64k */
+ AV_SAMPLE_RATE_88200 = 88200, /* 88.2k */
+ AV_SAMPLE_RATE_96000 = 96000, /* 96k */
+
+ AV_SAMPLE_RATE_MAX = 96001, /* MAX */
+ AV_SAMPLE_RATE_UNKNOWN = AV_SAMPLE_RATE_MAX /* Unknown rate */
+} AvSampleRateType;
+
+#endif /* _MM_FILE_FORMAT_AUDIO_H_ */
diff --git a/formats/ffmpeg/include/mm_file_format_dummy.h b/formats/ffmpeg/include/mm_file_format_dummy.h
new file mode 100755
index 0000000..43a5ad0
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_dummy.h
@@ -0,0 +1,37 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_DUMMY_H__
+#define __MM_FILE_FORMAT_DUMMY_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_DUMMY_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_ffmpeg.h b/formats/ffmpeg/include/mm_file_format_ffmpeg.h
new file mode 100755
index 0000000..1820ca5
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_ffmpeg.h
@@ -0,0 +1,36 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_FFMPEG_H__
+#define __MM_FILE_FORMAT_FFMPEG_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_FFMPEG_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_ffmpeg_drm.h b/formats/ffmpeg/include/mm_file_format_ffmpeg_drm.h
new file mode 100755
index 0000000..092fd8c
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_ffmpeg_drm.h
@@ -0,0 +1,37 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _MM_FILE_PLUGIN_FFMPEG_H_
+#define _MM_FILE_PLUGIN_FFMPEG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libavformat/avformat.h>
+
+extern URLProtocol MMFileDRMProtocol;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MM_FILE_PLUGIN_FFMPEG_H_ */
diff --git a/formats/ffmpeg/include/mm_file_format_ffmpeg_mem.h b/formats/ffmpeg/include/mm_file_format_ffmpeg_mem.h
new file mode 100755
index 0000000..2cf62e2
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_ffmpeg_mem.h
@@ -0,0 +1,37 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _MM_FILE_PLUGIN_FFMPEG_MEM_H_
+#define _MM_FILE_PLUGIN_FFMPEG_MEM_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libavformat/avformat.h>
+
+extern URLProtocol MMFileMEMProtocol;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MM_FILE_PLUGIN_FFMPEG_H_ */
diff --git a/formats/ffmpeg/include/mm_file_format_id3tag.h b/formats/ffmpeg/include/mm_file_format_id3tag.h
new file mode 100755
index 0000000..8af7ee1
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_id3tag.h
@@ -0,0 +1,282 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_PLUGIN_ID3TAG_H__
+#define __MM_FILE_PLUGIN_ID3TAG_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include "mm_file_utils.h"
+
+#define IS_ID3V2_TAG(x) (((x))[0] == 0x49 && ((x))[1] == 0x44 && ((x))[2] == 0x33)
+#define IS_INCLUDE_URL(x) (((x))[0] == 0x2D && ((x))[1] == 0x2D && ((x))[2] == 0x3E)
+#define IS_INCLUDE_URL_UTF16(x) (((x))[0] == 0x2D && ((x))[1] == NULL && ((x))[2] == 0x2D && ((x))[3] == NULL && ((x))[4] == 0x3E && ((x))[5] == NULL)
+#define IS_ENCODEDBY_UTF16(x) (((x))[0] == 0xFF && ((x))[1] == 0xFE)
+#define IS_ENCODEDBY_UTF16_R(x) (((x))[0] == 0xFE && ((x))[1] == 0xFF)
+
+#define NEWLINE_OF_UTF16(x) (((x))[0] == 0xFF && ((x))[1] == 0xFE && ((x))[2] == 0x00 && ((x))[3] == 0x00)
+#define NEWLINE_OF_UTF16_R(x) (((x))[0] == 0xFE && ((x))[1] == 0xFF && ((x))[2] == 0x00 && ((x))[3] == 0x00)
+
+
+#define AV_WM_LOCALCODE_SIZE_MAX 2
+#define MP3_TAGv2_HEADER_LEN 10
+#define MP3_TAGv2_23_TXT_HEADER_LEN 10
+#define MP3_TAGv2_22_TXT_HEADER_LEN 6
+#define TAGV1_SEEK_GAP 10
+
+
+typedef enum {
+ AV_ID3V2_PICTURE_TYPE_MIN,
+ AV_ID3V2_PICTURE_TYPE_OTHER = AV_ID3V2_PICTURE_TYPE_MIN,
+ AV_ID3V2_PICTURE_TYPE_PNG_ONLY_FILEICON,
+ AV_ID3V2_PICTURE_TYPE_OTHER_FILEICON,
+ AV_ID3V2_PICTURE_TYPE_FRONT_COVER,
+ AV_ID3V2_PICTURE_TYPE_BACK_COVER,
+ AV_ID3V2_PICTURE_TYPE_LEAFLET_PAGE,
+ AV_ID3V2_PICTURE_TYPE_MEDIA_SIDEOFCD,
+ AV_ID3V2_PICTURE_TYPE_LEAD_ARTIST,
+ AV_ID3V2_PICTURE_TYPE_ARTIST_PERFORMER,
+ AV_ID3V2_PICTURE_TYPE_CONDUCTOR,
+ AV_ID3V2_PICTURE_TYPE_BAND_ORCHESTRA,
+ AV_ID3V2_PICTURE_TYPE_COMPOSER,
+ AV_ID3V2_PICTURE_TYPE_LYRICIST_TEXTWRITER,
+ AV_ID3V2_PICTURE_TYPE_RECORDING_LOCATION,
+ AV_ID3V2_PICTURE_TYPE_DURING_RECORDING,
+ AV_ID3V2_PICTURE_TYPE_DURING_PERFORMANCE,
+ AV_ID3V2_PICTURE_TYPE_MOVIE_VIDEO_SCREEN_CAPTURE,
+ AV_ID3V2_PICTURE_TYPE_BRIGHT_COLOURED_FISH,
+ AV_ID3V2_PICTURE_TYPE_ILLUSTRATION,
+ AV_ID3V2_PICTURE_TYPE_BAND_ARTIST_LOGOTYPE,
+ AV_ID3V2_PICTURE_TYPE_PUBLISHER_STUDIO_LOGOTYPE,
+
+ AV_ID3V2_PICTURE_TYPE_MAX,
+ AV_ID3V2_PICTURE_TYPE_UNKNOWN = AV_ID3V2_PICTURE_TYPE_MAX /* Unknown picture type */
+
+} AvID3v2PictureType;
+
+
+#define MP3TAGINFO_SIZE 128 // file end 128 byte
+#define MP3_ID3_TITLE_LENGTH 30
+#define MP3_ID3_ARTIST_LENGTH 30
+#define MP3_ID3_ALBUM_LENGTH 30
+#define MP3_ID3_YEAR_LENGTH 4
+#define MP3_ID3_DESCRIPTION_LENGTH 30
+#define MP3_ID3_GENRE_LENGTH 30
+
+#define MP3_ID3_TRACKNUM_LENGTH 30
+#define MP3_ID3_ENCBY_LENGTH 30
+#define MP3_ID3_URL_LENGTH 100
+#define MP3_ID3_FRAMEID_LENGTH 30
+#define MP3_ID3_ORIGINARTIST_LENGTH 30
+#define MP3_ID3_COMPOSER_LENGTH 100
+#define MP3_ID3_IMAGE_DESCRIPTION_MAX_LENGTH 65
+#define MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH 31
+#define MP3_ID3_IMAGE_EXT_MAX_LENGTH 4
+#define TCC_FM_PATH_MOUNT_MMC "/Mount/Mmc"
+
+
+
+typedef enum {
+ AV_ID3V2_ISO_8859,
+ AV_ID3V2_UTF16,
+ AV_ID3V2_UTF16_BE,
+ AV_ID3V2_UTF8
+
+} AvID3v2EncodingType;
+
+
+typedef struct{
+ char *pImageBuf;
+ char imageDescription[MP3_ID3_IMAGE_DESCRIPTION_MAX_LENGTH];
+ char imageMIMEType[MP3_ID3_IMAGE_MIME_TYPE_MAX_LENGTH];
+ char imageExt[MP3_ID3_IMAGE_EXT_MAX_LENGTH];
+ int pictureType;
+ int imageLen;
+ int imgDesLen;
+ int imgMimetypeLen;
+ bool bURLInfo;
+
+} AvTagVer2ImageInfo;
+
+ typedef struct{
+ int tagLen;
+ char tagVersion;
+
+ bool bTagVer2Found;
+
+ bool bTitleMarked;
+ bool bArtistMarked;
+ bool bAlbumMarked;
+ bool bYearMarked;
+ bool bDescriptionMarked;
+ bool bGenreMarked;
+
+ bool bTrackNumMarked;
+ bool bEncByMarked;
+ bool bURLMarked;
+ bool bCopyRightMarked;
+ bool bOriginArtistMarked;
+ bool bComposerMarked;
+ bool bImageMarked;
+ bool bRecDateMarked;
+ bool bContentGroupMarked;
+
+ bool bGenreUTF16;
+
+} AvTagVer2AdditionalData;
+
+
+typedef struct
+{
+ int titleLen;
+ int artistLen;
+ int authorLen;
+ int copyrightLen;
+ int descriptionLen;
+ int commentLen;
+ int ratingLen;
+ int albumLen;
+ int yearLen;
+ int genreLen;
+ int tracknumLen;
+ int recdateLen;
+
+// for PC Studio Podcast
+ int contentGroupLen;
+
+// for ID3V2 Tag
+ int encbyLen;
+ int urlLen;
+ int originartistLen;
+ int composerLen;
+
+// To send resolution info to appl from OEM
+ int width;
+ int height;
+
+ unsigned int bitRate;
+ unsigned int sampleRate;
+ unsigned int channels;
+// unsigned long creationTime;
+ unsigned long duration;
+
+// for mp3 Info
+ char *pToc; // VBR�϶� SeekPosition�� ���ϱ� ���� TOC ���̺��� ������ ��� �ִ� char �迭 , 100 ����Ʈ ����
+ unsigned int mpegVersion; // 1 : mpeg 1, 2 : mpeg 2, 3 : mpeg2.5
+ unsigned int layer; // 1 : layer1, 2 : layer2, 3 : layer3
+ unsigned int channelIndex; // 0 : stereo, 1 : joint_stereo, 2 : dual_channel, 3 : mono
+ unsigned int objectType;
+ unsigned int headerType;
+ long fileLen; // mp3 ������ ��ü ����
+ long headerPos; // mp3 ����� ó������ ��Ÿ���� ��ġ
+ long datafileLen; // ID3Tag���� �����ϰ� ���� mp3 frame���� ���� , VBR�϶� XHEADDATA �� bytes �� �ش��Ѵ�
+ int frameSize; // mp3 frame �� ���� ũ��
+ int frameNum; // mp3 ���Ͽ� �������� � ����ִ°�?
+ bool bVbr; // VBR mp3?
+ bool bPadding; // Padding?
+ bool bV1tagFound;
+
+ char *pTitle; //Title/songname/
+ char *pArtist; //Lead performer(s)/Soloist(s),
+ char *pAuthor; //Author
+ char *pCopyright;
+ char *pDescription;
+ char *pComment; //Same to Description. Apps use Description. So replace this to Description for ID3V2 Tag
+ char *pRating;
+ char *pAlbum; //Album/Movie/
+ char *pYear;
+ char *pGenre;
+ char *pTrackNum; //Track number/Position in set
+ char *pRecDate; //Recording dates
+
+// for PC Studio Podcast
+ char *pContentGroup;
+
+// for ID3V2 Tag
+ char *pEncBy; //Encoded by
+ char *pURL; //User defined URL link frame for ID3V2 Tag
+ char *pOriginArtist; //Original artist(s)/performer(s)
+ char *pComposer; //Composer
+ AvTagVer2ImageInfo imageInfo; //Album art attached feature
+ AvTagVer2AdditionalData tagV2Info; //Needed data for ID3 tag parsing
+
+// for DRM 2.0
+ char *pTransactionID;
+
+//for ID3V1 Tag
+ unsigned char genre;
+
+} AvFileContentInfo;
+
+typedef struct {
+ int videocodec;
+ int audiocodec;
+ int width;
+ int height;
+} AvExtraInfo;
+
+inline static void mm_file_free_AvFileContentInfo (AvFileContentInfo *pInfo)
+{
+ if (pInfo) {
+ if (pInfo->pToc) mmfile_free (pInfo->pToc);
+ if (pInfo->pTitle) mmfile_free (pInfo->pTitle);
+ if (pInfo->pArtist) mmfile_free (pInfo->pArtist);
+ if (pInfo->pAuthor) mmfile_free (pInfo->pAuthor);
+ if (pInfo->pCopyright) mmfile_free (pInfo->pCopyright);
+ if (pInfo->pDescription) mmfile_free (pInfo->pDescription);
+ if (pInfo->pComment) mmfile_free (pInfo->pComment);
+ if (pInfo->pRating) mmfile_free (pInfo->pRating);
+ if (pInfo->pAlbum) mmfile_free (pInfo->pAlbum);
+ if (pInfo->pYear) mmfile_free (pInfo->pYear);
+ if (pInfo->pGenre) mmfile_free (pInfo->pGenre);
+ if (pInfo->pTrackNum) mmfile_free (pInfo->pTrackNum);
+ if (pInfo->pRecDate) mmfile_free (pInfo->pRecDate);
+
+ if (pInfo->pContentGroup) mmfile_free (pInfo->pContentGroup);
+
+ if (pInfo->pEncBy) mmfile_free (pInfo->pEncBy);
+ if (pInfo->pURL) mmfile_free (pInfo->pURL);
+ if (pInfo->pOriginArtist) mmfile_free (pInfo->pOriginArtist);
+ if (pInfo->pComposer) mmfile_free (pInfo->pComposer);
+
+ if (pInfo->imageInfo.pImageBuf) mmfile_free (pInfo->imageInfo.pImageBuf);
+
+ if (pInfo->pTransactionID) mmfile_free (pInfo->pTransactionID);
+ }
+}
+
+
+bool mm_file_id3tag_parse_v110 (AvFileContentInfo* pInfo, unsigned char *buffer); //20050401 Condol : for MP3 content Info.
+bool mm_file_id3tag_parse_v222 (AvFileContentInfo* pInfo, unsigned char *buffer);
+bool mm_file_id3tag_parse_v223 (AvFileContentInfo* pInfo, unsigned char *buffer);
+bool mm_file_id3tag_parse_v224 (AvFileContentInfo* pInfo, unsigned char *buffer);
+void mm_file_id3tag_restore_content_info (AvFileContentInfo* pInfo);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_PLUGIN_ID3TAG_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_imelody.h b/formats/ffmpeg/include/mm_file_format_imelody.h
new file mode 100755
index 0000000..41cee55
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_imelody.h
@@ -0,0 +1,44 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_IMELODY_H__
+#define __MM_FILE_FORMAT_IMELODY_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mmfileimelodytags
+{
+ char *title;
+ char *composer;
+ int beat;
+ char *copyright;
+ char *comment;
+} tMMFileImelodyTagInfo;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_IMELODY_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_midi.h b/formats/ffmpeg/include/mm_file_format_midi.h
new file mode 100755
index 0000000..87a3b99
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_midi.h
@@ -0,0 +1,49 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_MIDI_H__
+#define __MM_FILE_FORMAT_MIDI_H__
+
+#include "mm_file_formats.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ int duration;
+ int track_num;
+ int is_xmf;
+
+ char *title;
+ char *copyright;
+ char *comment;
+} MIDI_INFO_SIMPLE;
+
+MIDI_INFO_SIMPLE* mmfile_format_get_midi_infomation (char* uri);
+void mmfile_format_free_midi_infomation (MIDI_INFO_SIMPLE *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_MIDI_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_mmf.h b/formats/ffmpeg/include/mm_file_format_mmf.h
new file mode 100755
index 0000000..ffd7eae
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_mmf.h
@@ -0,0 +1,36 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_MMF_H__
+#define __MM_FILE_FORMAT_MMF_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_MMF_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_mp3.h b/formats/ffmpeg/include/mm_file_format_mp3.h
new file mode 100755
index 0000000..320b9a4
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_mp3.h
@@ -0,0 +1,34 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_MP3_H__
+#define __MM_FILE_FORMAT_MP3_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_MP3_H__*/
+
diff --git a/formats/ffmpeg/include/mm_file_format_private.h b/formats/ffmpeg/include/mm_file_format_private.h
new file mode 100755
index 0000000..366d5db
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_private.h
@@ -0,0 +1,52 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _MMFILE_FORMAT_PRIVATE_H_
+#define _MMFILE_FORMAT_PRIVATE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <mm_types.h>
+#include "mm_file_formats.h"
+
+/* open functions list: the order of list depends on mm-types.h */
+int mmfile_format_open_dummy (MMFileFormatContext *fileContext);
+int mmfile_format_open_ffmpg (MMFileFormatContext *fileContext);
+int mmfile_format_open_mp3 (MMFileFormatContext *fileContext);
+//int mmfile_format_open_3gp (MMFileFormatContext *fileContext);
+//int mmfile_format_open_avi (MMFileFormatContext *fileContext);
+//int mmfile_format_open_asf (MMFileFormatContext *fileContext);
+int mmfile_format_open_mmf (MMFileFormatContext *fileContext);
+int mmfile_format_open_amr (MMFileFormatContext *fileContext);
+int mmfile_format_open_aac (MMFileFormatContext *fileContext);
+int mmfile_format_open_wav (MMFileFormatContext *fileContext);
+int mmfile_format_open_mid (MMFileFormatContext *fileContext);
+int mmfile_format_open_imy (MMFileFormatContext *fileContext);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MMFILE_FORMAT_PRIVATE_H_ */
+
diff --git a/formats/ffmpeg/include/mm_file_format_tag_id3.h b/formats/ffmpeg/include/mm_file_format_tag_id3.h
new file mode 100755
index 0000000..e3b4d81
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_tag_id3.h
@@ -0,0 +1,56 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _MMFILE_ID3_TAG_H_
+#define _MMFILE_ID3_TAG_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mm_file_utils.h"
+#include "mm_file_format_tags.h"
+
+#define MMFILE_ID3TAG_FAIL 0
+#define MMFILE_ID3TAG_SUCCESS 1
+
+typedef void* MMFileID3TagHandle;
+
+typedef enum mmfileId3TagInfoVersion
+{
+ MMFILE_ID3TAG_V1_0 = 0,
+ MMFILE_ID3TAG_V1_1,
+ MMFILE_ID3TAG_V2_0,
+ MMFILE_ID3TAG_V2_2,
+ MMFILE_ID3TAG_V2_3,
+ MMFILE_ID3TAG_V2_4,
+ MMFILE_ID3TAG_VMAX,
+} eMMFileID3TagVersion;
+
+int MMFileID3V1TagFind (MMFileIOHandle *fp, unsigned char bAppended, unsigned int startOffset, unsigned int endOffset, tMMFileTags *out);
+int MMFileID3V2TagFind (MMFileIOHandle *fp, unsigned char bAppended, unsigned int startOffset, unsigned int endOffset, tMMFileTags *out);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*_MMFILE_ID3_TAG_H_ */
+
diff --git a/formats/ffmpeg/include/mm_file_format_tags.h b/formats/ffmpeg/include/mm_file_format_tags.h
new file mode 100755
index 0000000..eb5100d
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_tags.h
@@ -0,0 +1,65 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef _MMFILE_TAGS_H_
+#define _MMFILE_TAGS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void* MMFileTagsHandle;
+
+#define MMFILE_TAGS_SUCCESS 1
+#define MMFILE_TAGS_FAIL 0
+
+typedef enum mmfiletagstype
+{
+ MMFILE_TAG_ID3V1 = 0,
+ MMFILE_TAG_ID3V2,
+ MMFILE_TAG_MUSICAL_MATCH,
+ MMFILE_TAG_LYRICS3,
+ MMFILE_TAG_APE,
+ MMFILE_TAG_MAX,
+} eMMFileTagsType;
+
+typedef struct mmfileTags
+{
+ eMMFileTagsType typeOfTag;
+ unsigned char bAppendedTag;
+ unsigned int version;
+ unsigned int startOffset;
+ unsigned int tagSize;
+ unsigned int endOffset;
+} tMMFileTags;
+
+int MMFileOpenTags (MMFileTagsHandle *tagsHandle, const char *uriName);
+int MMFileGetFirstTag (MMFileTagsHandle tagsHandle, tMMFileTags *out);
+int MMFileGetNextTag (MMFileTagsHandle tagsHandle, tMMFileTags *out);
+int MMFileTagsClose (MMFileTagsHandle tagsHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* _MMFILE_TAGS_H_ */
+
diff --git a/formats/ffmpeg/include/mm_file_format_wav.h b/formats/ffmpeg/include/mm_file_format_wav.h
new file mode 100755
index 0000000..f7bd25c
--- /dev/null
+++ b/formats/ffmpeg/include/mm_file_format_wav.h
@@ -0,0 +1,37 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#ifndef __MM_FILE_FORMAT_WAV_H__
+#define __MM_FILE_FORMAT_WAV_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*__MM_FILE_FORMAT_WAV_H__*/
+
diff --git a/formats/ffmpeg/mm_file_format_aac.c b/formats/ffmpeg/mm_file_format_aac.c
new file mode 100755
index 0000000..762440f
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_aac.c
@@ -0,0 +1,965 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h> /*memcmp*/
+#include <stdlib.h> /*malloc*/
+
+#include <mm_error.h>
+
+#include "mm_debug.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_private.h"
+#include "mm_file_format_aac.h"
+
+
+// Internal Error Type
+#define MMFILE_AAC_PARSER_FILE_END 2
+
+// Media specific definations
+#define MMFILE_AAC_ADIF_HEADER_MAX_SIZE 30
+#define MMFILE_AAC_ADTS_HEADER_MAX_SIZE 7
+#define AAC_ADTS_FRAME_LEN_OFFSET 30
+#define AAC_ADTS_SAMPLES_PER_FRAME 1024
+
+#define IS_AAC_ADIF_HEADER(buff) (!(memcmp((buff), "ADIF", 4)))
+#define IS_AAC_ADTS_HEADER(buff) (((buff)[0] == 0xff) && (((buff)[1] & 0xf0) == 0xf0))
+
+
+// Array to Number conversions
+#define GET_INT_NUMBER(buff) (int)( (((int)(buff)[0]) << 24) | \
+ (((int)(buff)[1]) << 16) | \
+ (((int)(buff)[2]) << 8) | \
+ (((int)(buff)[3])))
+
+#define GET_SHORT_NUMBER(buff) (short)( ((short)(buff)[0] << 8) | \
+ ((short)(buff)[1]) )
+
+
+
+typedef enum _mmfile_aac_format_type {
+ AAC_FORMAT_ADIF,
+ AAC_FORMAT_ADTS,
+ AAC_FORMAT_UNKNOWN
+}TAacFormatType;
+
+typedef enum _mmfile_aac_bitstream_type {
+ AAC_STREAM_CONSTANT,
+ AAC_STREAM_VARIABLE
+}TAacStreamType;
+
+typedef enum _mmfile_aac_mpeg_type {
+ AAC_MPEG_4,
+ AAC_MPEG_2
+}TAacMpegType;
+
+typedef struct _mmfile_aac_handle {
+ MMFileIOHandle* hFile;
+ AvFileContentInfo id3Handle;
+ unsigned int streamOffset;
+ unsigned int tagOffset;
+ char isTagPresent;
+ unsigned int tagInfoSize;
+ unsigned char tagVersion;
+ TAacFormatType formatType;
+ TAacStreamType streamType;
+ TAacMpegType mpegType;
+ tMMFILE_AAC_STREAM_INFO streamInfo;
+ tMMFILE_AAC_TAG_INFO tagInfo;
+}tMMFILE_AAC_HANDLE;
+
+
+/*Index table for Sampling frequency */
+const int Sampling_freq_table[16] = { 96000, 88200, 64000, 48000,
+ 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000,
+ 0, 0, 0, 0 };
+
+/* internal APIs */
+void _aac_init_handle(tMMFILE_AAC_HANDLE* privateData);
+int _search_id3tag(tMMFILE_AAC_HANDLE* pData);
+int _parse_id3_tag(tMMFILE_AAC_HANDLE* pData);
+int _get_range_bits_value (unsigned char* buff, int fieldOffset, int fieldSize);
+int _parse_aac_adif_header (tMMFILE_AAC_HANDLE* pData);
+int _get_next_adts_frame_length(tMMFILE_AAC_HANDLE* pData, int* frameLen);
+int _parse_aac_adts_header(tMMFILE_AAC_HANDLE* pData);
+
+
+void _aac_init_handle(tMMFILE_AAC_HANDLE* privateData)
+{
+ /* Default Initializations */
+ privateData->streamOffset = 0;
+ privateData->isTagPresent = FALSE;
+ privateData->streamOffset = 0;
+ privateData->tagOffset = 0;
+
+ privateData->streamInfo.fileSize = 0;
+ privateData->streamInfo.duration = 0;
+ privateData->streamInfo.bitRate = 0;
+ privateData->streamInfo.samplingRate = 0;
+ privateData->streamInfo.frameRate = 0;
+ privateData->streamInfo.numAudioChannels = 0;
+ privateData->streamInfo.numTracks = 1;
+ privateData->streamInfo.profileType = 0;
+
+ privateData->tagInfo.title = NULL;
+ privateData->tagInfo.author = NULL;
+ privateData->tagInfo.artist = NULL;
+ privateData->tagInfo.album = NULL;
+ privateData->tagInfo.year = NULL;
+ privateData->tagInfo.copyright = NULL;
+ privateData->tagInfo.comment = NULL;
+ privateData->tagInfo.genre = NULL;
+ privateData->tagInfo.composer = NULL;
+ privateData->tagInfo.classification = NULL;
+ privateData->tagInfo.rating = NULL;
+ privateData->tagInfo.recordDate = NULL;
+ privateData->tagInfo.conductor = NULL;
+ privateData->tagInfo.artwork = NULL;
+ privateData->tagInfo.artworkSize = 0;
+ privateData->tagInfo.artworkMime = NULL;
+}
+
+
+int _search_id3tag(tMMFILE_AAC_HANDLE* pData)
+{
+ unsigned char tagHeader[MP3_TAGv2_HEADER_LEN] = {0,};
+ int encSize = 0;
+ int readed = 0;
+
+ mmfile_seek(pData->hFile, 0, MMFILE_SEEK_SET);
+ readed = mmfile_read (pData->hFile, tagHeader, MP3_TAGv2_HEADER_LEN);
+ if (MP3_TAGv2_HEADER_LEN != readed) {
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("Read Fail");
+#endif
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ if (!IS_ID3V2_TAG(tagHeader)) {
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("No ID3 Tag");
+#endif
+ goto search_end;
+ }
+
+ if (tagHeader[3] == 0xFF || tagHeader[4] == 0xFF ||
+ tagHeader[6] >= 0x80 || tagHeader[7] >= 0x80 ||
+ tagHeader[8] >= 0x80 || tagHeader[9] >= 0x80) {
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("Read Fail");
+#endif
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ pData->tagVersion = tagHeader[3];
+
+ if(pData->tagVersion > 4) {
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("\nTag version not supported");
+#endif
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ encSize = GET_INT_NUMBER(&tagHeader[6]);
+ pData->tagInfoSize = MP3_TAGv2_HEADER_LEN;
+
+ pData->tagInfoSize += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | \
+ ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
+
+ if(pData->tagInfoSize > pData->streamInfo.fileSize) {
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("Invalid size");
+#endif
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ pData->isTagPresent = TRUE;
+ pData->tagOffset = 0;
+ pData->streamOffset = pData->tagInfoSize;
+
+ /* Filling the information in id3Handle for tag parsing */
+ pData->id3Handle.fileLen = pData->streamInfo.fileSize;
+ pData->id3Handle.tagV2Info.tagLen = pData->tagInfoSize;
+ pData->id3Handle.tagV2Info.tagVersion = pData->tagVersion;
+ pData->id3Handle.tagV2Info.tagLen = pData->tagInfoSize;
+
+search_end:
+ return MMFILE_AAC_PARSER_SUCCESS;
+}
+
+
+int _parse_id3_tag(tMMFILE_AAC_HANDLE* pData)
+{
+ unsigned char* tagBuff = NULL;
+ AvFileContentInfo* hTag = &pData->id3Handle;
+ int ret = FALSE;
+ int readed = 0;
+
+ mmfile_seek(pData->hFile, pData->tagOffset, MMFILE_SEEK_SET);
+ tagBuff = (unsigned char*) mmfile_malloc(hTag->fileLen);
+ if(tagBuff == NULL) {
+ ret = MMFILE_AAC_PARSER_FAIL;
+ debug_error ("failed to memory allocation. %d\n", hTag->fileLen);
+ goto failure;
+ }
+
+ readed = mmfile_read(pData->hFile, tagBuff, hTag->fileLen);
+ if (readed != hTag->fileLen) {
+ debug_error ("failed to read. %d, %lld\n", readed, hTag->fileLen);
+ goto failure;
+ }
+
+ switch(hTag->tagV2Info.tagVersion) {
+ case 1:
+ ret = mm_file_id3tag_parse_v110(hTag, tagBuff);
+ break;
+ case 2:
+ ret = mm_file_id3tag_parse_v222(hTag, tagBuff);
+ break;
+ case 3:
+ ret = mm_file_id3tag_parse_v223(hTag, tagBuff);
+ break;
+ case 4:
+ ret = mm_file_id3tag_parse_v224(hTag, tagBuff);
+ break;
+ default:
+ debug_error ("Invalid Tag version [%d]\n", hTag->tagV2Info.tagVersion);
+ break;
+ }
+
+ if(ret == FALSE) {
+ ret = MMFILE_AAC_PARSER_FAIL;
+ debug_warning ("failed to parse\n");
+ goto failure;
+ }
+
+ mm_file_id3tag_restore_content_info(hTag);
+
+ pData->tagInfo.title = hTag->pTitle;
+ pData->tagInfo.author = hTag->pAuthor;
+ pData->tagInfo.artist = hTag->pArtist;
+ pData->tagInfo.album = hTag->pAlbum;
+ pData->tagInfo.year = hTag->pYear;
+ pData->tagInfo.copyright = hTag->pCopyright;
+ pData->tagInfo.comment = hTag->pDescription;
+ pData->tagInfo.genre = hTag->pGenre;
+ pData->tagInfo.tracknum = hTag->pTrackNum;
+ pData->tagInfo.composer = hTag->pComposer;
+ pData->tagInfo.classification = hTag->pContentGroup;
+ pData->tagInfo.rating = hTag->pRating;
+ pData->tagInfo.recordDate = hTag->pRecDate;
+ pData->tagInfo.conductor = hTag->pConductor;
+ pData->tagInfo.artworkMime = hTag->imageInfo.imageMIMEType;
+ pData->tagInfo.artworkSize = hTag->imageInfo.imageLen;
+ pData->tagInfo.artwork = hTag->imageInfo.pImageBuf;
+
+ ret = MMFILE_AAC_PARSER_SUCCESS;
+
+
+failure:
+ if(tagBuff) {
+ mmfile_free(tagBuff);
+ tagBuff = NULL;
+ }
+
+ return ret;
+
+}
+
+
+int _get_range_bits_value (unsigned char* buff, int fieldOffset, int fieldSize)
+{
+ int pos = 0;
+ unsigned int srcByteStartOff = 0;
+ unsigned int srcByteEndOff = 0;
+ unsigned int srcBitStartOff = 0;
+ unsigned int srcBitEndOff = 0;
+ unsigned char dest[4] = {0,};
+ unsigned int res = 0;
+ unsigned int i,j, temp;
+ unsigned char extraByteFlag = 0;
+ unsigned int occupiedBytes = 0;
+ unsigned char mask = 0, maskBit = 0x01;
+
+
+ srcByteStartOff = (fieldOffset / 8);
+ srcBitStartOff = (fieldOffset % 8);
+
+ srcByteEndOff = ((fieldOffset + fieldSize - 1) / 8);
+ srcBitEndOff = ((fieldOffset + fieldSize - 1) % 8);
+
+ occupiedBytes = srcByteEndOff - srcByteStartOff + 1;
+
+ for(i = srcByteStartOff, j = 0; i <= srcByteEndOff && j <= 3; i++,j++) {
+ dest[j] = buff[i];
+ }
+
+ for(pos = 7; pos>= (char)srcBitStartOff; pos--) {
+ mask = mask | maskBit;
+ maskBit <<= 1;
+ }
+
+ dest[0] = dest[0] & mask;
+
+ if(i <= srcByteEndOff) {
+ extraByteFlag = 1;
+ }
+
+ res = GET_INT_NUMBER(dest);
+
+ if(!extraByteFlag) {
+ temp = (4 - occupiedBytes) * 8 + (7 - srcBitEndOff);
+ res >>= temp;
+ }
+
+ if(extraByteFlag) {
+ res <<= srcBitStartOff;
+ temp = buff[srcByteEndOff] >> (7 - srcBitEndOff);
+ res = res | (unsigned int)temp;
+ }
+
+ return res;
+}
+
+
+int _parse_aac_adif_header (tMMFILE_AAC_HANDLE* pData)
+{
+ unsigned char adifHeader[MMFILE_AAC_ADIF_HEADER_MAX_SIZE] = {0,};
+ int currentBitOffset = 0;
+ unsigned int fieldValue = 0;
+ int copyRightStatus = 0;
+ int readed = 0;
+
+ mmfile_seek(pData->hFile, pData->streamOffset, MMFILE_SEEK_SET);
+ readed = mmfile_read(pData->hFile, adifHeader, MMFILE_AAC_ADIF_HEADER_MAX_SIZE);
+ if (readed < 0) {
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ if(memcmp(adifHeader, "ADIF", 4) != 0) {
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+ currentBitOffset += 32;
+
+ copyRightStatus = _get_range_bits_value(adifHeader, currentBitOffset, 1);
+ currentBitOffset += 1;
+
+ if(copyRightStatus) {
+ //skipping Copyright info
+ currentBitOffset += 72;
+ }
+
+ //Original/copy
+ fieldValue = _get_range_bits_value(adifHeader, currentBitOffset, 1);
+ currentBitOffset += 1;
+
+ //skipping Home status
+ currentBitOffset += 1;
+
+ //Bit stream type
+ fieldValue = _get_range_bits_value(adifHeader, currentBitOffset, 1);
+ currentBitOffset += 1;
+ if(!fieldValue) {
+ pData->streamType = AAC_STREAM_CONSTANT;
+ }
+ else {
+ pData->streamType = AAC_STREAM_VARIABLE;
+ }
+
+ //Bit-rate
+ pData->streamInfo.bitRate = _get_range_bits_value(adifHeader, currentBitOffset, 23);
+ currentBitOffset += 23;
+
+ //Num of program config elements
+ fieldValue = _get_range_bits_value(adifHeader, currentBitOffset, 4);
+ currentBitOffset += 4;
+
+ //skipping adif buffer fullness
+ currentBitOffset += 20;
+
+ //skipping element instance tag
+ currentBitOffset += 4;
+
+ //Profile
+ pData->streamInfo.profileType = _get_range_bits_value(adifHeader, currentBitOffset, 2);
+ currentBitOffset += 2;
+
+ //sampling freq index
+ fieldValue = _get_range_bits_value(adifHeader, currentBitOffset, 4);
+ currentBitOffset += 4;
+ pData->streamInfo.samplingRate = Sampling_freq_table[fieldValue];
+
+ //num_front_channel_elements
+ pData->streamInfo.numAudioChannels = _get_range_bits_value(adifHeader, currentBitOffset, 4);
+ currentBitOffset += 4;
+
+ //num_side_channel_elements
+ pData->streamInfo.numAudioChannels += _get_range_bits_value(adifHeader, currentBitOffset, 4);
+ currentBitOffset += 4;
+
+ //num_back_channel_elements
+ pData->streamInfo.numAudioChannels += _get_range_bits_value(adifHeader, currentBitOffset, 4);
+ currentBitOffset += 4;
+
+ //num_lfe_channel_elements
+ pData->streamInfo.numAudioChannels += _get_range_bits_value(adifHeader, currentBitOffset, 2);
+ currentBitOffset += 2;
+
+ return MMFILE_AAC_PARSER_SUCCESS;
+
+}
+
+
+int _parse_aac_adts_header(tMMFILE_AAC_HANDLE* pData)
+{
+ unsigned char adtsHeader[MMFILE_AAC_ADTS_HEADER_MAX_SIZE] = {0,};
+ int currentBitOffset = 0;
+ unsigned int fieldValue = 0;
+ int readed = 0;
+
+ mmfile_seek(pData->hFile, pData->streamOffset, MMFILE_SEEK_SET);
+ readed = mmfile_read(pData->hFile, adtsHeader, MMFILE_AAC_ADTS_HEADER_MAX_SIZE);
+ if (readed < 0) {
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ if(!IS_AAC_ADTS_HEADER(adtsHeader)) {
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+ currentBitOffset += 12;
+
+ //adtsId
+ fieldValue = _get_range_bits_value(adtsHeader, currentBitOffset, 1);
+ currentBitOffset += 1;
+ pData->mpegType = (fieldValue != 0);
+
+ //LayerType
+ fieldValue = _get_range_bits_value(adtsHeader, currentBitOffset, 2);
+ currentBitOffset += 2;
+
+ //skipping Protection Absent
+ currentBitOffset += 1;
+
+ //ProfileType
+ fieldValue = _get_range_bits_value(adtsHeader, currentBitOffset, 2);
+ currentBitOffset += 2;
+ pData->streamInfo.profileType = fieldValue;
+
+ //SamplingrateIndex
+ fieldValue = _get_range_bits_value(adtsHeader, currentBitOffset, 4);
+ currentBitOffset += 4;
+ pData->streamInfo.samplingRate = Sampling_freq_table[fieldValue];
+
+ //skipping PrivateBit
+ currentBitOffset += 1;
+
+ //ChannelConfig
+ pData->streamInfo.numAudioChannels = _get_range_bits_value(adtsHeader, currentBitOffset, 3);
+ currentBitOffset += 3;
+
+ //Original/copy status
+ fieldValue = _get_range_bits_value(adtsHeader, currentBitOffset, 1);
+ currentBitOffset += 1;
+
+ //skipping Home status
+ fieldValue = _get_range_bits_value(adtsHeader, currentBitOffset, 1);
+ currentBitOffset += 1;
+
+ //copy right Id status bit
+ currentBitOffset += 1;
+
+ return MMFILE_AAC_PARSER_SUCCESS;
+}
+
+
+int _get_next_adts_frame_length(tMMFILE_AAC_HANDLE* pData, int* frameLen)
+{
+ unsigned char adtsHeader[MMFILE_AAC_ADTS_HEADER_MAX_SIZE] = {0,};
+ int ret = MMFILE_AAC_PARSER_SUCCESS;
+ long long filePosBefore = mmfile_tell(pData->hFile);
+ int readed = 0;
+
+ readed = mmfile_read(pData->hFile, adtsHeader, MMFILE_AAC_ADTS_HEADER_MAX_SIZE);
+ if (readed < 0)
+ return MMFILE_AAC_PARSER_FAIL;
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("\nFILE POS: %lld\n", filePosBefore);
+ debug_msg("\nADTS HEADER: [%2x] [%2x] [%2x] [%2x] [%2x] [%2x]\n",
+ adtsHeader[0], adtsHeader[1], adtsHeader[2], adtsHeader[3], adtsHeader[4], adtsHeader[5]);
+#endif
+
+ if(mmfile_tell(pData->hFile) >= pData->streamInfo.fileSize) {
+ *frameLen = 0;
+ ret = MMFILE_AAC_PARSER_FILE_END;
+ goto function_end;
+ }
+
+ if(!IS_AAC_ADTS_HEADER(adtsHeader)) {
+ *frameLen = 0;
+ ret = MMFILE_AAC_PARSER_FAIL;
+ goto function_end;
+ }
+
+ *frameLen = _get_range_bits_value(adtsHeader, AAC_ADTS_FRAME_LEN_OFFSET, 13);
+
+ if(*frameLen == 0 || *frameLen > (pData->streamInfo.fileSize - filePosBefore)) {
+ *frameLen = 0;
+ ret = MMFILE_AAC_PARSER_FAIL;
+ goto function_end;
+ }
+
+function_end:
+
+ mmfile_seek(pData->hFile, filePosBefore + *frameLen, MMFILE_SEEK_SET);
+
+ return ret;
+}
+
+
+int mmfile_aacparser_open (MMFileAACHandle *handle, const char *filenamec)
+{
+ tMMFILE_AAC_HANDLE *privateData = NULL;
+ int ret = 0;
+ unsigned char header[4] = {0,};
+ int firstFrameLen = 0;
+ int readed = 0;
+
+ if (NULL == filenamec) {
+ debug_error ("file source is NULL\n");
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ privateData = mmfile_malloc (sizeof(tMMFILE_AAC_HANDLE));
+ if (NULL == privateData) {
+ debug_error ("file source is NULL\n");
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ ret = mmfile_open (&privateData->hFile, filenamec, MMFILE_RDONLY);
+ if(ret == MMFILE_UTIL_FAIL) {
+ debug_error ("error: mmfile_open\n");
+ goto exception;
+ }
+
+ /* Initialize the members of handle */
+ _aac_init_handle(privateData);
+
+ mmfile_seek (privateData->hFile, 0, MMFILE_SEEK_END);
+ privateData->streamInfo.fileSize= mmfile_tell(privateData->hFile);
+
+ mmfile_seek (privateData->hFile, 0, MMFILE_SEEK_SET);
+
+ /* Search the existance of ID3 tag */
+ ret = _search_id3tag(privateData);
+ if(ret == MMFILE_AAC_PARSER_FAIL) {
+ debug_error("Error in searching the ID3 tag\n");
+ goto exception;
+ }
+
+ mmfile_seek (privateData->hFile, privateData->streamOffset, MMFILE_SEEK_SET);
+ readed = mmfile_read (privateData->hFile, header, 4);
+ if (readed != 4)
+ goto exception;
+
+ if(IS_AAC_ADIF_HEADER(header)) {
+ privateData->formatType = AAC_FORMAT_ADIF;
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("AAC Format: ADIF\n");
+#endif
+
+ }
+ else if(IS_AAC_ADTS_HEADER(header)) {
+ privateData->formatType = AAC_FORMAT_ADTS;
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("AAC Format: ADTS\n");
+#endif
+
+ /* Verify whether the first frame size is proper */
+ mmfile_seek (privateData->hFile, privateData->streamOffset, MMFILE_SEEK_SET);
+ ret = _get_next_adts_frame_length(privateData, &firstFrameLen);
+ if(ret == MMFILE_AAC_PARSER_FAIL) {
+ debug_error("Invalid Frame length in ADTS header\n");
+ goto exception;
+ }
+ }
+ else {
+ privateData->formatType = AAC_FORMAT_UNKNOWN;
+ debug_error("AAC Format: UNKNOWN\n");
+ goto exception;
+ }
+
+ *handle = privateData;
+
+ return MMFILE_AAC_PARSER_SUCCESS;
+
+exception:
+ if (privateData) {
+ mmfile_close (privateData->hFile);
+ mmfile_free (privateData);
+ *handle = NULL;
+ }
+ return MMFILE_AAC_PARSER_FAIL;
+
+}
+
+
+int mmfile_aacparser_get_stream_info (MMFileAACHandle handle, tMMFILE_AAC_STREAM_INFO *aacinfo)
+{
+ tMMFILE_AAC_HANDLE *privateData = NULL;
+ int frameLen = 0;
+ long long totalFrames = 0, totalFrameLength = 0;
+ unsigned long long streamDataSize = 0;
+ int ret = MMFILE_AAC_PARSER_SUCCESS;
+
+ if (NULL == handle || NULL == aacinfo) {
+ debug_error ("handle is NULL\n");
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ privateData = (tMMFILE_AAC_HANDLE *) handle;
+
+ if(privateData->formatType == AAC_FORMAT_ADIF) {
+ ret = _parse_aac_adif_header(privateData);
+ aacinfo->iseekable = 0;
+ }
+ else {
+ ret = _parse_aac_adts_header(privateData);
+ aacinfo->iseekable = 1;
+ }
+
+ if(ret == MMFILE_AAC_PARSER_FAIL) {
+ debug_error("Error in parsing the stream header\n");
+ return ret;
+ }
+
+ mmfile_seek(privateData->hFile, privateData->streamOffset, MMFILE_SEEK_SET);
+
+ if(privateData->formatType == AAC_FORMAT_ADTS) {
+
+ while(TRUE) {
+ ret = _get_next_adts_frame_length(privateData, &frameLen);
+ if(ret != MMFILE_AAC_PARSER_SUCCESS) {
+ break;
+ }
+ totalFrameLength += frameLen - MMFILE_AAC_ADTS_HEADER_MAX_SIZE;
+ totalFrames++;
+ }
+
+ if(ret == MMFILE_AAC_PARSER_FAIL) {
+ debug_error("Found corrupted frames!!! Ignoring\n");
+ }
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("No of ADTS frames: %d\n", totalFrames);
+#endif
+ privateData->streamInfo.frameRate = privateData->streamInfo.samplingRate / AAC_ADTS_SAMPLES_PER_FRAME;
+
+ if(privateData->streamInfo.frameRate)
+ privateData->streamInfo.duration = (totalFrames * 1000) / privateData->streamInfo.frameRate;
+ else privateData->streamInfo.duration = 0;
+
+ if(privateData->streamInfo.duration)
+ privateData->streamInfo.bitRate = (totalFrameLength * 8 * 1000) / (privateData->streamInfo.duration);
+ else privateData->streamInfo.bitRate = 0;
+
+ }
+ else {
+ streamDataSize = (unsigned long long)privateData->streamInfo.fileSize - privateData->tagInfoSize;
+ privateData->streamInfo.duration = streamDataSize * 8 * 1000 / privateData->streamInfo.bitRate;
+ }
+
+ // Return the stream info structure
+ memcpy(aacinfo, &(privateData->streamInfo), sizeof(tMMFILE_AAC_STREAM_INFO));
+
+ return MMFILE_AAC_PARSER_SUCCESS;
+}
+
+
+int mmfile_aacparser_get_tag_info (MMFileAACHandle handle, tMMFILE_AAC_TAG_INFO *tagInfo)
+{
+ tMMFILE_AAC_HANDLE *privateData = NULL;
+ int ret = 0;
+
+ if (NULL == handle || NULL == tagInfo) {
+ debug_error ("handle is NULL\n");
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ privateData = (tMMFILE_AAC_HANDLE *) handle;
+ if(privateData->id3Handle.tagV2Info.tagVersion == 0)
+ {
+ debug_warning ("There is no Tag info\n");
+ return MMFILE_AAC_PARSER_SUCCESS;
+ }
+
+ ret = _parse_id3_tag(privateData);
+ if(ret == MMFILE_AAC_PARSER_FAIL) {
+ debug_warning ("Error in parsing the Tag info\n");
+ return ret;
+ }
+
+ // Return the tag info structure
+ memcpy(tagInfo, &(privateData->tagInfo), sizeof(tMMFILE_AAC_TAG_INFO));
+
+ return MMFILE_AAC_PARSER_SUCCESS;
+}
+
+
+int mmfile_aacparser_close (MMFileAACHandle handle)
+{
+ tMMFILE_AAC_HANDLE *privateData = NULL;
+
+ if (NULL == handle) {
+ debug_error ("handle is NULL\n");
+ return MMFILE_AAC_PARSER_FAIL;
+ }
+
+ privateData = (tMMFILE_AAC_HANDLE *) handle;
+ mm_file_free_AvFileContentInfo(&privateData->id3Handle);
+
+ mmfile_close(privateData->hFile);
+
+ return MMFILE_AAC_PARSER_SUCCESS;
+}
+
+
+/* mm plugin interface */
+int mmfile_format_read_stream_aac (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_aac (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_aac (MMFileFormatContext *formatContext);
+int mmfile_format_close_aac (MMFileFormatContext *formatContext);
+
+
+EXPORT_API
+int mmfile_format_open_aac (MMFileFormatContext *formatContext)
+{
+ MMFileAACHandle handle = NULL;
+ int res = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext || NULL == formatContext->uriFileName) {
+ debug_error ("error: mmfile_format_open_aac\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->pre_checked == 0) {
+ res = MMFileFormatIsValidAAC (formatContext->uriFileName);
+ if (res == 0) {
+ debug_error("It is not AAC file\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+ }
+
+ formatContext->ReadStream = mmfile_format_read_stream_aac;
+ formatContext->ReadFrame = mmfile_format_read_frame_aac;
+ formatContext->ReadTag = mmfile_format_read_tag_aac;
+ formatContext->Close = mmfile_format_close_aac;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ res = mmfile_aacparser_open (&handle, formatContext->uriFileName);
+ if (MMFILE_AAC_PARSER_FAIL == res) {
+ debug_error ("mmfile_aacparser_open\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->privateFormatData = handle;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_stream_aac (MMFileFormatContext *formatContext)
+{
+ MMFileAACHandle handle = NULL;
+ tMMFILE_AAC_STREAM_INFO aacinfo = {0,};
+ MMFileFormatStream *audioStream = NULL;
+
+ int ret = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext ) {
+ debug_error ("error: invalid params\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ handle = formatContext->privateFormatData;
+
+ ret = mmfile_aacparser_get_stream_info (handle, &aacinfo);
+ if (MMFILE_FORMAT_SUCCESS != ret) {
+ debug_error ("error: mmfile_aacparser_get_stream_info\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ formatContext->isseekable = aacinfo.iseekable;
+ formatContext->duration = aacinfo.duration;
+ formatContext->videoStreamId = -1;
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = aacinfo.numTracks;
+ formatContext->nbStreams = 1;
+
+ audioStream = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == audioStream) {
+ debug_error ("error: calloc_audiostream\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ audioStream->streamType = MMFILE_AUDIO_STREAM;
+ audioStream->codecId = MM_AUDIO_CODEC_AAC;
+ audioStream->bitRate = aacinfo.bitRate;
+ audioStream->framePerSec = aacinfo.frameRate;
+ audioStream->width = 0;
+ audioStream->height = 0;
+ audioStream->nbChannel = aacinfo.numAudioChannels;
+ audioStream->samplePerSec = aacinfo.samplingRate;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
+
+#ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+#endif
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ return ret;
+}
+
+EXPORT_API
+int mmfile_format_read_tag_aac (MMFileFormatContext *formatContext)
+{
+ MMFileAACHandle handle = NULL;
+ tMMFILE_AAC_TAG_INFO aacinfo = {0,};
+ int ret= MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext) {
+ debug_error ("error: invalid params\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ handle = formatContext->privateFormatData;
+
+ ret = mmfile_aacparser_get_tag_info (handle, &aacinfo);
+ if (MMFILE_FORMAT_SUCCESS != ret) {
+ debug_warning ("error: mmfile_aacparser_get_tag_info\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ if(aacinfo.title)
+ formatContext->title = mmfile_strdup(aacinfo.title);
+ if(aacinfo.author)
+ formatContext->author = mmfile_strdup(aacinfo.author);
+ if(aacinfo.artist)
+ formatContext->artist = mmfile_strdup(aacinfo.artist);
+ if(aacinfo.album)
+ formatContext->album = mmfile_strdup(aacinfo.album);
+ if(aacinfo.year)
+ formatContext->year = mmfile_strdup(aacinfo.year);
+ if(aacinfo.copyright)
+ formatContext->copyright = mmfile_strdup(aacinfo.copyright);
+ if(aacinfo.comment)
+ formatContext->comment = mmfile_strdup(aacinfo.comment);
+ if(aacinfo.genre)
+ formatContext->genre = mmfile_strdup(aacinfo.genre);
+ if(aacinfo.tracknum)
+ formatContext->tagTrackNum= mmfile_strdup(aacinfo.tracknum);
+ if(aacinfo.composer)
+ formatContext->composer = mmfile_strdup(aacinfo.composer);
+ if(aacinfo.classification)
+ formatContext->classification = mmfile_strdup(aacinfo.classification);
+ if(aacinfo.rating)
+ formatContext->rating = mmfile_strdup(aacinfo.rating); /*not exist rating tag in id3*/
+ if(aacinfo.conductor)
+ formatContext->conductor = mmfile_strdup(aacinfo.conductor);
+ if(aacinfo.artworkMime)
+ formatContext->artworkMime = mmfile_strdup(aacinfo.artworkMime);
+ if(aacinfo.artwork) {
+ formatContext->artworkSize = aacinfo.artworkSize;
+ formatContext->artwork = mmfile_malloc(aacinfo.artworkSize);
+ if(formatContext->artwork == NULL) {
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+ memcpy(formatContext->artwork, aacinfo.artwork, aacinfo.artworkSize);
+ }
+
+#ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+#endif
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ return ret;
+}
+
+
+EXPORT_API
+int mmfile_format_read_frame_aac (MMFileFormatContext *formatContext,
+ unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ debug_error ("error: mmfile_format_read_frame_aac, no handling\n");
+
+ return MMFILE_FORMAT_FAIL;
+}
+
+
+EXPORT_API
+int mmfile_format_close_aac (MMFileFormatContext *formatContext)
+{
+ MMFileAACHandle handle = NULL;
+ int ret = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext ) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ handle = formatContext->privateFormatData;
+
+ if(NULL != handle) {
+ ret = mmfile_aacparser_close(handle);
+ if(ret == MMFILE_AAC_PARSER_FAIL) {
+ debug_error("error: mmfile_format_close_aac\n");
+ }
+ }
+
+ if(formatContext->streams[MMFILE_AUDIO_STREAM]) {
+ mmfile_free(formatContext->streams[MMFILE_AUDIO_STREAM]);
+ formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
+ }
+
+ formatContext->ReadStream = NULL;
+ formatContext->ReadFrame = NULL;
+ formatContext->ReadTag = NULL;
+ formatContext->Close = NULL;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
diff --git a/formats/ffmpeg/mm_file_format_amr.c b/formats/ffmpeg/mm_file_format_amr.c
new file mode 100755
index 0000000..d15cf62
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_amr.c
@@ -0,0 +1,501 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h> /*memcmp*/
+#include <stdlib.h> /*malloc*/
+
+
+#include <mm_error.h>
+#include "mm_debug.h"
+
+#include "mm_file_utils.h"
+#include "mm_file_format_private.h"
+#include "mm_file_format_amr.h"
+
+
+// Media specific definations
+#define NUM_AMR_NB_MODES 8
+#define NUM_AMR_WB_MODES 9
+
+#define MMFILE_AMR_SINGLE_CH_HEADER_SIZE 6
+#define MMFILE_AMR_SINGLE_CH_HEADER "#!AMR\n"
+#define MMFILE_AMR_WB_SINGLE_CH_HEADER_SIZE 9
+#define MMFILE_AMR_WB_SINGLE_CH_HEADER "#!AMR-WB\n"
+#define MMFILE_AMR_MULTI_CH_HEADER_SIZE 12
+#define MMFILE_AMR_MULTI_CH_HEADER "#!AMR_MC1.0\n"
+#define MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE 15
+#define MMFILE_AMR_WB_MULTI_CH_HEADER "#!AMR-WB_MC1.0\n"
+
+#define MMFILE_AMR_MAX_HEADER_SIZE MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE
+#define MMFILE_AMR_MIN_HEADER_SIZE MMFILE_AMR_SINGLE_CH_HEADER_SIZE
+
+#define MMFILE_AMR_FRAME_DUR 20
+#define AMR_NB_SAMPLES_PER_SEC 8000
+#define AMR_WB_SAMPLES_PER_SEC 16000
+
+#define AMR_MAX_READ_BUF_SZ 4096
+
+#define AMR_GET_MODE(firstByte) (((firstByte) >> 3) & 0x0F)
+
+
+typedef enum _mmfile_amr_format_types {
+ AMR_FORMAT_NB,
+ AMR_FORMAT_WB,
+ AMR_FORMAT_UNKNOWN
+}eAmrFormatType;
+
+typedef enum _mmfile_amr_channel_type {
+ AMR_CHANNEL_TYPE_SINGLE,
+ AMR_CHANNEL_TYPE_MULTIPLE,
+ AMR_CHANNEL_TYPE_UNKNOWN
+}eAmrChannelType;
+
+typedef struct _mmfile_amr_handle {
+ MMFileIOHandle* hFile;
+ long long duration;
+ long long fileSize;
+ unsigned int streamOffset;
+ unsigned int bitRate;
+ unsigned int samplingRate;
+ unsigned int frameRate;
+ unsigned int numAudioChannels;
+ long long numFrames;
+ unsigned int numTracks;
+ int amrMode;
+ eAmrFormatType amrFormat;
+ eAmrChannelType amrChannelType;
+}tMMFILE_AMR_HANDLE;
+
+
+typedef struct _mmfile_amr_mode_config {
+ unsigned int bitRate;
+ unsigned int frameSize;
+}tAmrModeConfig;
+
+/*RTP format only supported*/
+/*mode vs bitRate-frameSize lookup table; [0]->AMR-NB [1]->AMR-WB */
+const tAmrModeConfig AmrModeConfigTable[2][16] =
+{
+ {
+ {4750, 13}, {5150, 14}, {5900, 16}, {6700, 18},
+ {7400, 20}, {7950, 21}, {10200,27}, {12200,32},
+ {0, 6}, {0, 1}, {0, 1}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+ },
+ {
+ {6600, 18}, {8850, 24}, {12650,33}, {14250,37},
+ {15850,41}, {18250,47}, {19850,51}, {23050,59},
+ {23850,61}, {0, 6}, {0, 6}, {0, 1},
+ {0, 1}, {0, 1}, {0, 1}, {0, 1},
+ }
+};
+
+/* internal APIs */
+
+void _amr_init_handle(tMMFILE_AMR_HANDLE* pData)
+{
+ pData->hFile = NULL;
+ pData->duration = 0;
+ pData->fileSize = 0L;
+ pData->streamOffset = 0;
+ pData->bitRate = 0;
+ pData->samplingRate = 0;
+ pData->frameRate = 0;
+ pData->numAudioChannels = 1;
+ pData->numTracks = 1;
+ pData->numFrames = 0;
+ pData->amrChannelType = AMR_CHANNEL_TYPE_SINGLE;
+}
+
+int _parse_amr_header(tMMFILE_AMR_HANDLE* pData)
+{
+
+ unsigned char header[MMFILE_AMR_MAX_HEADER_SIZE];
+ int ret = MMFILE_AMR_PARSER_SUCCESS;
+
+ ret = mmfile_read(pData->hFile, header, MMFILE_AMR_MAX_HEADER_SIZE);
+ if(ret != MMFILE_AMR_MAX_HEADER_SIZE) {
+ return MMFILE_AMR_PARSER_FAIL;
+ }
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("\nAMR HEADER: [%2x] [%2x] [%2x] [%2x] [%2x]\n \
+ [%2x] [%2x] [%2x] [%2x] [%2x]\n \
+ [%2x] [%2x] [%2x] [%2x] [%2x]\n",
+ header[0], header[1], header[2], header[3],header[4],
+ header[5], header[6], header[7], header[8],header[9],
+ header[10],header[11],header[12],header[13],header[14]);
+#endif
+
+ if(!(memcmp(header, MMFILE_AMR_SINGLE_CH_HEADER, MMFILE_AMR_SINGLE_CH_HEADER_SIZE))) {
+ pData->amrFormat = AMR_FORMAT_NB;
+ pData->amrChannelType = AMR_CHANNEL_TYPE_SINGLE;
+ pData->streamOffset = MMFILE_AMR_SINGLE_CH_HEADER_SIZE;
+ }
+
+ else if(!(memcmp(header, MMFILE_AMR_WB_SINGLE_CH_HEADER, MMFILE_AMR_WB_SINGLE_CH_HEADER_SIZE))) {
+ pData->amrFormat = AMR_FORMAT_WB;
+ pData->amrChannelType = AMR_CHANNEL_TYPE_SINGLE;
+ pData->streamOffset = MMFILE_AMR_WB_SINGLE_CH_HEADER_SIZE;
+ }
+
+ else if(!(memcmp(header, MMFILE_AMR_MULTI_CH_HEADER, MMFILE_AMR_MULTI_CH_HEADER_SIZE))){
+ pData->amrFormat = AMR_FORMAT_NB;
+ pData->amrChannelType = AMR_CHANNEL_TYPE_MULTIPLE;
+ pData->streamOffset = MMFILE_AMR_MULTI_CH_HEADER_SIZE;
+ }
+
+ else if(!(memcmp(header, MMFILE_AMR_WB_MULTI_CH_HEADER, MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE))) {
+ pData->amrFormat = AMR_FORMAT_WB;
+ pData->amrChannelType = AMR_CHANNEL_TYPE_MULTIPLE;
+ pData->streamOffset = MMFILE_AMR_WB_MULTI_CH_HEADER_SIZE;
+ }
+
+ else {
+ pData->amrFormat = AMR_FORMAT_UNKNOWN;
+ pData->amrChannelType = AMR_CHANNEL_TYPE_UNKNOWN;
+ ret = MMFILE_AMR_PARSER_FAIL;
+ }
+
+ return ret;
+}
+
+
+int _parse_amr_stream(tMMFILE_AMR_HANDLE* pData)
+{
+ int frameLen = 0;
+ unsigned char amrMode = 0;
+ int ret = MMFILE_AMR_PARSER_SUCCESS;
+ unsigned char *p;
+ unsigned char *buf;
+ int readed;
+ int pos;
+ long long sum_bitrate = 0;
+ long long frames_bitrate = 0;
+
+ buf = mmfile_malloc (AMR_MAX_READ_BUF_SZ);
+ if (!buf) {
+ debug_error ("failed to memory allocaion.\n");
+ return MMFILE_AMR_PARSER_FAIL;
+ }
+
+ for (readed = 0;;) {
+ readed = mmfile_read (pData->hFile, buf, AMR_MAX_READ_BUF_SZ);
+ if (readed <= 0) break;
+
+ for (p = buf, pos = 0;;) {
+ amrMode = AMR_GET_MODE ((*(char *)p));
+ frameLen = AmrModeConfigTable[pData->amrFormat][amrMode].frameSize;
+ sum_bitrate += AmrModeConfigTable[pData->amrFormat][amrMode].bitRate;
+ pData->numFrames++;
+ frames_bitrate += (AmrModeConfigTable[pData->amrFormat][amrMode].bitRate == 0 ? 0 : 1);
+
+ p += frameLen;
+ pos += frameLen;
+ if (pos == readed) {
+ break;
+ } else if (pos > readed) {
+ mmfile_seek (pData->hFile, (pos - readed), MMFILE_SEEK_CUR);
+ break;
+ }
+ }
+ }
+
+ mmfile_free (buf);
+
+ pData->duration = pData->numFrames * MMFILE_AMR_FRAME_DUR;
+ pData->frameRate = 1000 / MMFILE_AMR_FRAME_DUR;
+
+ if(frames_bitrate) {
+ pData->bitRate = sum_bitrate / frames_bitrate;
+ }
+
+ return ret;
+}
+
+
+int mmfile_amrparser_open (MMFileAMRHandle *handle, const char *filenamec)
+{
+ tMMFILE_AMR_HANDLE *privateData = NULL;
+ int ret = 0;
+
+ if (NULL == filenamec || NULL == handle) {
+ debug_error ("file source is NULL\n");
+ return MMFILE_AMR_PARSER_FAIL;
+ }
+
+ privateData = mmfile_malloc (sizeof(tMMFILE_AMR_HANDLE));
+ if (NULL == privateData) {
+ debug_error ("file source is NULL\n");
+ return MMFILE_AMR_PARSER_FAIL;
+ }
+
+ /* Initialize the members of handle */
+ _amr_init_handle(privateData);
+
+ ret = mmfile_open (&privateData->hFile, filenamec, MMFILE_RDONLY);
+ if(ret == MMFILE_UTIL_FAIL) {
+ debug_error ("error: mmfile_open\n");
+ goto exception;
+ }
+
+ mmfile_seek (privateData->hFile, 0, MMFILE_SEEK_END);
+ privateData->fileSize= mmfile_tell(privateData->hFile);
+ mmfile_seek (privateData->hFile, 0, MMFILE_SEEK_SET);
+
+ if(privateData->fileSize < MMFILE_AMR_MIN_HEADER_SIZE) {
+ debug_error("Too small file to parse!!\n");
+ goto exception;
+ }
+
+ ret = _parse_amr_header(privateData);
+ if(ret == MMFILE_AMR_PARSER_FAIL) {
+ debug_error("Invalid AMR header\n");
+ goto exception;
+ }
+
+ if(privateData->amrChannelType != AMR_CHANNEL_TYPE_SINGLE) {
+ debug_error("Unsupported channel mode\n"); /*Need to study AMR_Format.txt, Pg:36*/
+ goto exception;
+ }
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("AMR Format Type: %s\n", \
+ privateData->amrFormat == AMR_FORMAT_NB? "AMR-NB":"AMR-WB");
+#endif
+
+ *handle = privateData;
+
+ return MMFILE_AMR_PARSER_SUCCESS;
+
+exception:
+ if (privateData) {
+ mmfile_close (privateData->hFile);
+ mmfile_free (privateData);
+ *handle = NULL;
+ }
+ return MMFILE_AMR_PARSER_FAIL;
+
+}
+
+
+int mmfile_amrparser_get_stream_info (MMFileAMRHandle handle, tMMFILE_AMR_STREAM_INFO *amrinfo)
+{
+ tMMFILE_AMR_HANDLE *privateData = NULL;
+ int ret;
+
+ if (NULL == handle || NULL == amrinfo) {
+ debug_error ("handle is NULL\n");
+ return MMFILE_AMR_PARSER_FAIL;
+ }
+
+ privateData = (tMMFILE_AMR_HANDLE *) handle;
+
+ mmfile_seek(privateData->hFile, privateData->streamOffset, MMFILE_SEEK_SET);
+
+ ret = _parse_amr_stream(privateData);
+ if(ret == MMFILE_AMR_PARSER_FAIL) {
+ debug_error("Error in parsing the stream\n");
+ return ret;
+ }
+
+ amrinfo->duration = privateData->duration;
+ amrinfo->fileSize = privateData->fileSize;
+ amrinfo->bitRate = privateData->bitRate;
+ amrinfo->frameRate = privateData->frameRate;
+ amrinfo->numAudioChannels = 1;
+ amrinfo->numTracks = 1;
+
+ if(privateData->amrFormat == AMR_FORMAT_NB) {
+ amrinfo->samplingRate = AMR_NB_SAMPLES_PER_SEC;
+ }
+ else {
+ amrinfo->samplingRate = AMR_WB_SAMPLES_PER_SEC;
+ }
+
+ return MMFILE_AMR_PARSER_SUCCESS;
+}
+
+
+int mmfile_amrparser_close (MMFileAMRHandle handle)
+{
+ tMMFILE_AMR_HANDLE *privateData = NULL;
+
+ if (NULL == handle) {
+ debug_error ("handle is NULL\n");
+ return MMFILE_AMR_PARSER_FAIL;
+ }
+
+ privateData = (tMMFILE_AMR_HANDLE *) handle;
+
+ mmfile_close(privateData->hFile);
+
+ return MMFILE_AMR_PARSER_SUCCESS;
+}
+
+
+
+/* mm plugin interface */
+int mmfile_format_read_stream_amr (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_amr (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_amr (MMFileFormatContext *formatContext);
+int mmfile_format_close_amr (MMFileFormatContext *formatContext);
+
+
+EXPORT_API
+int mmfile_format_open_amr (MMFileFormatContext *formatContext)
+{
+ MMFileAMRHandle handle = NULL;
+ int res = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext || NULL == formatContext->uriFileName) {
+ debug_error ("error: mmfile_format_open_amr\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->ReadStream = mmfile_format_read_stream_amr;
+ formatContext->ReadFrame = mmfile_format_read_frame_amr;
+ formatContext->ReadTag = mmfile_format_read_tag_amr;
+ formatContext->Close = mmfile_format_close_amr;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ res = mmfile_amrparser_open (&handle, formatContext->uriFileName);
+ if (MMFILE_AMR_PARSER_FAIL == res) {
+ debug_error ("mmfile_amrparser_open\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->privateFormatData = handle;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_stream_amr (MMFileFormatContext *formatContext)
+{
+ MMFileAMRHandle handle = NULL;
+ tMMFILE_AMR_STREAM_INFO amrinfo = {0,};
+ MMFileFormatStream *audioStream = NULL;
+
+ int ret = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext ) {
+ debug_error ("error: invalid params\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ handle = formatContext->privateFormatData;
+
+ ret = mmfile_amrparser_get_stream_info (handle, &amrinfo);
+ if (MMFILE_FORMAT_SUCCESS != ret) {
+ debug_error ("error: mmfile_amrparser_get_stream_info\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ formatContext->duration = amrinfo.duration;
+ formatContext->videoStreamId = -1;
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = amrinfo.numTracks;
+ formatContext->nbStreams = 1;
+
+ audioStream = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == audioStream) {
+ debug_error ("error: calloc_audiostream\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ audioStream->streamType = MMFILE_AUDIO_STREAM;
+ audioStream->codecId = MM_AUDIO_CODEC_AMR;
+ audioStream->bitRate = amrinfo.bitRate;
+ audioStream->framePerSec = amrinfo.frameRate;
+ audioStream->width = 0;
+ audioStream->height = 0;
+ audioStream->nbChannel = amrinfo.numAudioChannels;
+ audioStream->samplePerSec = amrinfo.samplingRate;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
+
+#ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+#endif
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ return ret;
+}
+
+EXPORT_API
+int mmfile_format_read_tag_amr (MMFileFormatContext *formatContext)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_frame_amr (MMFileFormatContext *formatContext,
+ unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ debug_error ("error: mmfile_format_read_frame_amr, no handling\n");
+
+ return MMFILE_FORMAT_FAIL;
+}
+
+
+EXPORT_API
+int mmfile_format_close_amr (MMFileFormatContext *formatContext)
+{
+ MMFileAMRHandle handle = NULL;
+ int ret = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext ) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ handle = formatContext->privateFormatData;
+
+ if(NULL != handle) {
+ ret = mmfile_amrparser_close(handle);
+ if(ret == MMFILE_AMR_PARSER_FAIL) {
+ debug_error("error: mmfile_format_close_amr\n");
+ }
+ }
+
+ if(formatContext->streams[MMFILE_AUDIO_STREAM]) {
+ mmfile_free(formatContext->streams[MMFILE_AUDIO_STREAM]);
+ formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
+ }
+
+ formatContext->ReadStream = NULL;
+ formatContext->ReadFrame = NULL;
+ formatContext->ReadTag = NULL;
+ formatContext->Close = NULL;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
diff --git a/formats/ffmpeg/mm_file_format_dummy.c b/formats/ffmpeg/mm_file_format_dummy.c
new file mode 100755
index 0000000..b8f7a19
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_dummy.c
@@ -0,0 +1,91 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h> /*memcmp*/
+#include <stdlib.h> /*malloc*/
+
+#include <mm_error.h>
+
+#include "mm_debug.h"
+
+#include "mm_file_format_private.h"
+#include "mm_file_format_dummy.h"
+
+
+/* internal functions */
+
+
+/* plugin manadatory API */
+int mmfile_format_read_stream_dummy (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_dummy (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_dummy (MMFileFormatContext *formatContext);
+int mmfile_format_close_dummy (MMFileFormatContext *formatContext);
+
+
+EXPORT_API
+int mmfile_format_open_dummy (MMFileFormatContext *formatContext)
+{
+ debug_warning ("called mmfile_format_open_dummy\n");
+
+ formatContext->ReadStream = mmfile_format_read_stream_dummy;
+ formatContext->ReadFrame = mmfile_format_read_frame_dummy;
+ formatContext->ReadTag = mmfile_format_read_tag_dummy;
+ formatContext->Close = mmfile_format_close_dummy;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_stream_dummy (MMFileFormatContext * formatContext)
+{
+ debug_warning ("called mmfile_format_read_stream_dummy\n");
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_frame_dummy (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ debug_warning ("called mmfile_format_read_frame_dummy\n");
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_tag_dummy (MMFileFormatContext *formatContext)
+{
+ debug_warning ("called mmfile_format_read_tag_dummy\n");
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_close_dummy (MMFileFormatContext *formatContext)
+{
+ debug_warning ("called mmfile_format_close_dummy\n");
+ if (formatContext)
+ {
+ formatContext->ReadStream = NULL;
+ formatContext->ReadFrame = NULL;
+ formatContext->ReadTag = NULL;
+ formatContext->Close = NULL;
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
diff --git a/formats/ffmpeg/mm_file_format_ffmpeg.c b/formats/ffmpeg/mm_file_format_ffmpeg.c
new file mode 100755
index 0000000..7d0b12f
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_ffmpeg.c
@@ -0,0 +1,1296 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#ifdef __MMFILE_FFMPEG_V085__
+#include <libswscale/swscale.h>
+#endif
+#include <mm_error.h>
+#include <mm_types.h>
+#include "mm_debug.h"
+#include "mm_file_formats.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_ffmpeg.h"
+
+#include "mm_file_format_ffmpeg_mem.h"
+#include <sys/time.h>
+
+
+
+#define _SHORT_MEDIA_LIMIT 2000 /* under X seconds duration*/
+
+extern int img_convert (AVPicture *dst, int dst_pix_fmt, const AVPicture *src, int src_pix_fmt,int src_width, int src_height);
+
+/* internal functions */
+static int _is_good_pgm (unsigned char *buf, int wrap, int xsize, int ysize);
+#ifdef MMFILE_FORMAT_DEBUG_DUMP
+static void _save_pgm (unsigned char *buf, int wrap, int xsize, int ysize, char *filename);
+#endif
+#ifdef __MMFILE_TEST_MODE__
+static void _dump_av_packet (AVPacket *pkt);
+#endif
+
+static int _get_video_fps (int frame_cnt, int duration, AVRational r_frame_rate, int is_roundup);
+static int _get_first_good_video_frame (AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, int videoStream, AVFrame **pFrame);
+
+static int ConvertVideoCodecEnum (int AVVideoCodecID);
+static int ConvertAudioCodecEnum (int AVAudioCodecID);
+
+/* plugin manadatory API */
+int mmfile_format_read_stream_ffmpg (MMFileFormatContext * formatContext);
+int mmfile_format_read_frame_ffmpg (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_ffmpg (MMFileFormatContext *formatContext);
+int mmfile_format_close_ffmpg (MMFileFormatContext *formatContext);
+static int getMimeType(int formatId, char *mimeType);
+
+
+
+EXPORT_API
+int mmfile_format_open_ffmpg (MMFileFormatContext *formatContext)
+{
+ AVFormatContext *pFormatCtx = NULL;
+ AVInputFormat *grab_iformat = NULL;
+ int ret = 0;
+ int i;
+ char ffmpegFormatName[MMFILE_FILE_FMT_MAX_LEN] = {0,};
+ char mimeType[MMFILE_MIMETYPE_MAX_LEN] = {0,};
+
+ formatContext->ReadStream = mmfile_format_read_stream_ffmpg;
+ formatContext->ReadFrame = mmfile_format_read_frame_ffmpg;
+ formatContext->ReadTag = mmfile_format_read_tag_ffmpg;
+ formatContext->Close = mmfile_format_close_ffmpg;
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg ("ffmpeg version: %d\n", avformat_version ());
+ /**
+ * FFMPEG DEBUG LEVEL
+ * AV_LOG_QUIET -1
+ * AV_LOG_FATAL 0
+ * AV_LOG_ERROR 0
+ * AV_LOG_WARNING 1
+ * AV_LOG_INFO 1
+ * AV_LOG_VERBOSE 1
+ * AV_LOG_DEBUG 2
+ */
+ av_log_set_level (AV_LOG_DEBUG);
+#else
+ av_log_set_level (AV_LOG_QUIET);
+#endif
+
+ av_register_all();
+
+ if (formatContext->filesrc->type == MM_FILE_SRC_TYPE_MEMORY) {
+
+#ifdef __MMFILE_FFMPEG_V085__
+ ffurl_register_protocol(&MMFileMEMProtocol, sizeof (URLProtocol));
+#else
+ register_protocol (&MMFileMEMProtocol);
+#endif
+ if(getMimeType(formatContext->filesrc->memory.format,mimeType)< 0) {
+ debug_error ("error: Error in MIME Type finding\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ memset (ffmpegFormatName, 0x00, MMFILE_FILE_FMT_MAX_LEN);
+
+ ret = mmfile_util_get_ffmpeg_format (mimeType,ffmpegFormatName);
+
+ if (MMFILE_UTIL_SUCCESS != ret) {
+ debug_error ("error: mmfile_util_get_ffmpeg_format\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ grab_iformat = av_find_input_format (ffmpegFormatName);
+
+ if (NULL == grab_iformat) {
+ debug_error ("error: cannot find format\n");
+ goto exception;
+ }
+
+#ifdef __MMFILE_FFMPEG_V085__
+ ret = avformat_open_input (&pFormatCtx, formatContext->uriFileName, grab_iformat, NULL);
+#else
+ ret = av_open_input_file (&pFormatCtx, formatContext->uriFileName, grab_iformat, 0, NULL);
+#endif
+ if (ret < 0) {
+ debug_error("error: cannot open %s %d\n", formatContext->uriFileName, ret);
+ goto exception;
+ }
+ formatContext->privateFormatData = pFormatCtx;
+ }
+
+ if (formatContext->filesrc->type == MM_FILE_SRC_TYPE_FILE) {
+
+ if (formatContext->isdrm == MM_FILE_DRM_OMA) {
+ debug_error ("error: drm content\n");
+ goto exception;
+ } else {
+HANDLING_DRM_DIVX:
+#ifdef __MMFILE_FFMPEG_V085__
+ ret = avformat_open_input(&pFormatCtx, formatContext->filesrc->file.path, NULL, NULL);
+#else
+ ret = av_open_input_file(&pFormatCtx, formatContext->filesrc->file.path, NULL, 0, NULL);
+#endif
+ if (ret < 0) {
+ debug_error("error: cannot open %s %d\n", formatContext->filesrc->file.path, ret);
+ goto exception;
+ }
+ formatContext->privateFormatData = pFormatCtx;
+ }
+ }
+
+ if (!pFormatCtx || !(pFormatCtx->nb_streams > 0)) {
+ debug_warning ("failed to find av stream. maybe corrupted data.\n");
+ goto exception;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("number of stream: %d\n", pFormatCtx->nb_streams);
+ #endif
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 0;
+
+ for(i = 0; i < pFormatCtx->nb_streams; i++) {
+#ifdef __MMFILE_FFMPEG_V085__
+ if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("FFMPEG video codec id: 0x%08X\n", pFormatCtx->streams[i]->codec->codec_id);
+ #endif
+ formatContext->videoTotalTrackNum += 1;
+ }
+ if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("FFMPEG audio codec id: 0x%08X\n", pFormatCtx->streams[i]->codec->codec_id);
+ #endif
+ formatContext->audioTotalTrackNum += 1;
+ }
+#else
+ if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("FFMPEG video codec id: 0x%08X\n", pFormatCtx->streams[i]->codec->codec_id);
+ #endif
+ formatContext->videoTotalTrackNum += 1;
+ }
+ if (pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("FFMPEG audio codec id: 0x%08X\n", pFormatCtx->streams[i]->codec->codec_id);
+ #endif
+ formatContext->audioTotalTrackNum += 1;
+ }
+#endif
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("format: %s (%s)\n", pFormatCtx->iformat->name, pFormatCtx->iformat->long_name);
+ #ifdef __MMFILE_FFMPEG_V085__
+ av_dump_format (pFormatCtx, 0, formatContext->filesrc->file.path, 0);
+ #else
+ dump_format (pFormatCtx, 0, formatContext->filesrc->file.path, 0);
+ #endif
+ #endif
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception: /* fail to get content information */
+
+ mmfile_format_close_ffmpg (formatContext);
+ formatContext->privateFormatData = NULL;
+
+ return MMFILE_FORMAT_FAIL;
+}
+
+
+EXPORT_API
+int mmfile_format_read_stream_ffmpg (MMFileFormatContext * formatContext)
+{
+ AVFormatContext *pFormatCtx = NULL;
+ AVCodecContext *pAudioCodecCtx = NULL;
+ AVCodecContext *pVideoCodecCtx = NULL;
+
+ MMFileFormatStream *videoStream = NULL;
+ MMFileFormatStream *audioStream = NULL;
+ int ret = 0;
+
+ if (NULL == formatContext || NULL == formatContext->privateFormatData) {
+ debug_error ("invalid param\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ pFormatCtx = formatContext->privateFormatData;
+
+ /**
+ *@important if data is corrupted, occur segment fault by av_find_stream_info().
+ * - fixed 2009-06-25.
+ */
+#ifdef __MMFILE_FFMPEG_V100__
+ ret = avformat_find_stream_info (pFormatCtx, NULL);
+#else
+ ret = av_find_stream_info (pFormatCtx);
+#endif
+ if ( ret < 0 ) {
+ debug_warning ("failed to find stream info. errcode = %d\n", ret);
+ goto exception;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("FFMPEG: dur %lld, start %lld\n", pFormatCtx->duration, pFormatCtx->start_time);
+ #endif
+
+ /**
+ *@note asf has long duration bug. and Some content's start time is wrong(negative number).
+ */
+ if(pFormatCtx->start_time < 0) {
+ debug_warning ("Wrong Start time = %lld\n", pFormatCtx->start_time);
+ formatContext->duration = (long long)(pFormatCtx->duration) * 1000 / AV_TIME_BASE;
+ }
+ else {
+ formatContext->duration = (long long)(pFormatCtx->duration + pFormatCtx->start_time) * 1000 / AV_TIME_BASE;
+ }
+
+ formatContext->videoStreamId = -1;
+ formatContext->audioStreamId = -1;
+ formatContext->nbStreams = 0;
+
+ int i = 0;
+ for ( i = 0; i < pFormatCtx->nb_streams; i++ ) {
+#ifdef __MMFILE_FFMPEG_V085__
+ if ( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+#else
+ if ( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO) {
+#endif
+ if (formatContext->videoStreamId == -1) {
+ videoStream = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == videoStream) {
+ debug_error ("mmfile_malloc error\n");
+ goto exception;
+ }
+
+ videoStream->streamType = MMFILE_VIDEO_STREAM;
+ formatContext->streams[MMFILE_VIDEO_STREAM] = videoStream;
+ formatContext->nbStreams += 1;
+ formatContext->videoStreamId = i;
+
+ pVideoCodecCtx = pFormatCtx->streams[i]->codec;
+ if (pVideoCodecCtx) {
+ videoStream->codecId = ConvertVideoCodecEnum (pVideoCodecCtx->codec_id);
+
+ /**
+ * Get FPS
+ * 1. try to get average fps of video stream.
+ * 2. if (1) failed, try to get fps of media container.
+ */
+ videoStream->framePerSec = _get_video_fps (pFormatCtx->streams[i]->nb_frames,
+ pFormatCtx->streams[i]->duration,
+ pFormatCtx->streams[i]->time_base,
+ 1);
+
+ if (videoStream->framePerSec == 0)
+ videoStream->framePerSec = av_q2d (pFormatCtx->streams[i]->r_frame_rate);
+
+ videoStream->width = pVideoCodecCtx->width;
+ videoStream->height = pVideoCodecCtx->height;
+ videoStream->bitRate = pVideoCodecCtx->bit_rate;
+ }
+ }
+ }
+#ifdef __MMFILE_FFMPEG_V085__
+ else if ( pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) {
+#else
+ else if ( pFormatCtx->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO ) {
+#endif
+ if (formatContext->audioStreamId == -1) {
+ audioStream = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == audioStream) {
+ debug_error ("mmfile_malloc error\n");
+ goto exception;
+ }
+
+ audioStream->streamType = MMFILE_AUDIO_STREAM;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
+ formatContext->nbStreams += 1;
+ formatContext->audioStreamId = i;
+
+ pAudioCodecCtx = pFormatCtx->streams[i]->codec;
+ if (pAudioCodecCtx) {
+ audioStream->codecId = ConvertAudioCodecEnum (pAudioCodecCtx->codec_id);
+ audioStream->bitRate = pAudioCodecCtx->bit_rate;
+ audioStream->nbChannel = pAudioCodecCtx->channels;
+ audioStream->samplePerSec = pAudioCodecCtx->sample_rate;
+ }
+ }
+ }
+ }
+
+ if ( formatContext->nbStreams == 0 ) {
+ debug_error("error: there is no audio and video track\n");
+ goto exception;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+ #endif
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ if (videoStream) {
+ mmfile_free (videoStream);
+ formatContext->streams[MMFILE_VIDEO_STREAM] = NULL;
+ }
+
+ if (audioStream) {
+ mmfile_free (audioStream);
+ formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
+ }
+
+ if (pFormatCtx) {
+#ifdef __MMFILE_FFMPEG_V100__
+ avformat_close_input (&pFormatCtx);
+#else
+ av_close_input_file (pFormatCtx);
+#endif
+ formatContext->privateFormatData = NULL;
+ }
+
+ formatContext->audioTotalTrackNum = 0;
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->nbStreams = 0;
+
+ return MMFILE_FORMAT_FAIL;
+}
+
+
+EXPORT_API
+int mmfile_format_read_tag_ffmpg (MMFileFormatContext *formatContext)
+{
+ AVFormatContext *pFormatCtx = NULL;
+
+ if (NULL == formatContext || NULL == formatContext->privateFormatData) {
+ debug_error ("invalid param\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ pFormatCtx = formatContext->privateFormatData;
+
+ if (formatContext->formatType == MM_FILE_FORMAT_3GP ||formatContext->formatType == MM_FILE_FORMAT_MP4) {
+ MMFileUtilGetMetaDataFromMP4 (formatContext);
+ }
+
+#ifdef __MMFILE_FFMPEG_V085__
+/*metadata extracted by ffmpeg*/
+ int idx = 0;
+
+ if(pFormatCtx != NULL) {
+ for(idx = 0; idx < 3; idx++) {
+ AVDictionary *metainfo = NULL;
+
+ if(idx == 0) { //Check metadata of Content
+ if(pFormatCtx->metadata != NULL) {
+ metainfo = pFormatCtx->metadata;
+ } else {
+ continue;
+ }
+ } else if(idx == 1) { //Check metadata of Video stream
+ if (formatContext->videoStreamId != -1) {
+ AVStream *st = pFormatCtx->streams[formatContext->videoStreamId];
+ if(st != NULL)
+ metainfo = st->metadata;
+ } else {
+ continue;
+ }
+ } else if(idx == 2) { //Check metadata of Audio stream
+ if (formatContext->audioStreamId != -1) {
+ AVStream *st = pFormatCtx->streams[formatContext->audioStreamId];
+ if(st != NULL)
+ metainfo = st->metadata;
+ } else {
+ continue;
+ }
+ } else {
+ metainfo = NULL;
+ }
+
+ if(metainfo != NULL) {
+ AVDictionaryEntry *tag = NULL;
+ while((tag=av_dict_get(metainfo, "", tag, AV_DICT_IGNORE_SUFFIX))) {
+ if(tag->key != NULL) {
+ if(!strcasecmp(tag->key, "title")) {
+ if (formatContext->title) free (formatContext->title);
+ formatContext->title = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "artist")) {
+ if (formatContext->artist) free (formatContext->artist);
+ formatContext->artist = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "composer")) {
+ if (formatContext->composer) free (formatContext->composer);
+ formatContext->composer = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "album")) {
+ if (formatContext->album) free (formatContext->album);
+ formatContext->album = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "copyright")) {
+ if (formatContext->copyright) free (formatContext->copyright);
+ formatContext->copyright = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "comment")) {
+ if (formatContext->comment) free (formatContext->comment);
+ formatContext->comment = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "genre")) {
+ if (formatContext->genre) free (formatContext->genre);
+ formatContext->genre = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "date")) {
+ if (formatContext->year) free (formatContext->year);
+ formatContext->year = mmfile_strdup (tag->value);
+ } else if((!strcasecmp(tag->key, "track")) || (!strcasecmp(tag->key, "tracknumber"))) {
+ if (formatContext->tagTrackNum) free (formatContext->tagTrackNum);
+ formatContext->tagTrackNum = mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "lyrics")) {
+ if (formatContext->unsyncLyrics) free (formatContext->unsyncLyrics);
+ formatContext->unsyncLyrics= mmfile_strdup (tag->value);
+ } else if(!strcasecmp(tag->key, "rotate")) { //can be "90", "180", "270"
+ if (formatContext->rotate) free (formatContext->rotate);
+ formatContext->rotate= mmfile_strdup (tag->value);
+ } else {
+ debug_log("Not support metadata. [%s:%s]", tag->key, tag->value);
+ }
+ }
+ }
+ }
+ }
+ }
+#else
+ if (pFormatCtx->title[0]) {
+ if (formatContext->title)
+ free (formatContext->title);
+ formatContext->title = mmfile_strdup (pFormatCtx->title);
+ }
+ if (pFormatCtx->author[0]){
+ if (formatContext->author)
+ free (formatContext->author);
+ formatContext->author = mmfile_strdup (pFormatCtx->author);
+ }
+ if (pFormatCtx->copyright[0]) {
+ if (formatContext->copyright)
+ free (formatContext->copyright);
+ formatContext->copyright = mmfile_strdup (pFormatCtx->copyright);
+ }
+ if (pFormatCtx->comment[0]) {
+ if (formatContext->comment)
+ free (formatContext->comment);
+ formatContext->comment = mmfile_strdup (pFormatCtx->comment);
+ }
+ if (pFormatCtx->album[0]) {
+ if (formatContext->album)
+ free (formatContext->album);
+ formatContext->album = mmfile_strdup (pFormatCtx->album);
+ }
+ if (pFormatCtx->genre[0]) {
+ if (formatContext->genre)
+ free (formatContext->genre);
+ formatContext->genre = mmfile_strdup (pFormatCtx->genre);
+ }
+
+ if (pFormatCtx->year) {
+ char year[10] = {0,};
+ snprintf (year, 10, "%d", pFormatCtx->year);
+ year[9] = '\0';
+ if (formatContext->year)
+ free (formatContext->year);
+ formatContext->year = mmfile_strdup (year);
+ }
+
+ if (pFormatCtx->track) {
+ char tracknum[10] = {0,};
+ snprintf (tracknum, 10, "%d", pFormatCtx->track);
+ tracknum[9] = '\0';
+ if (formatContext->tagTrackNum)
+ free (formatContext->tagTrackNum);
+ formatContext->tagTrackNum = mmfile_strdup (tracknum);
+ }
+#endif
+ #ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_tags (formatContext);
+ #endif
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_frame_ffmpg (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ AVFormatContext *pFormatCtx = NULL;
+ AVCodecContext *pVideoCodecCtx = NULL;
+ AVCodec *pVideoCodec = NULL;
+ AVFrame *pFrame = NULL;
+ AVFrame *pFrameRGB = NULL;
+
+ int width;
+ int height;
+ int numBytes = 0;
+ int ret = 0;
+
+ if (NULL == formatContext ||
+ NULL == frame ||
+ NULL == formatContext->privateFormatData ||
+ formatContext->videoTotalTrackNum <= 0) {
+
+ debug_error ("invalid param\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ pFormatCtx = formatContext->privateFormatData;
+
+ if (formatContext->videoStreamId != -1) {
+ pVideoCodecCtx = pFormatCtx->streams[formatContext->videoStreamId]->codec;
+ if (NULL == pVideoCodecCtx) {
+ debug_error ("invalid param\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ pVideoCodec = avcodec_find_decoder (pVideoCodecCtx->codec_id);
+ if ( NULL == pVideoCodec ) {
+ debug_error ("error: avcodec_find_decoder failed\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("flag: 0x%08X\n", pVideoCodec->capabilities);
+ // debug_msg (" DRAW_HORIZ_BAND : %d\n", pVideoCodec->capabilities & CODEC_CAP_DRAW_HORIZ_BAND ? 1 : 0);
+ // debug_msg (" DR1 : %d\n", pVideoCodec->capabilities & CODEC_CAP_DR1 ? 1 : 0);
+ // debug_msg (" PARSE_ONLY : %d\n", pVideoCodec->capabilities & CODEC_CAP_PARSE_ONLY ? 1 : 0);
+ // debug_msg (" TRUNCATED : %d\n", pVideoCodec->capabilities & CODEC_CAP_TRUNCATED ? 1 : 0);
+ // debug_msg (" HWACCEL : %d\n", pVideoCodec->capabilities & CODEC_CAP_HWACCEL ? 1 : 0);
+ // debug_msg (" DELAY : %d\n", pVideoCodec->capabilities & CODEC_CAP_DELAY ? 1 : 0);
+ // debug_msg (" SMALL_LAST_FRAME: %d\n", pVideoCodec->capabilities & CODEC_CAP_SMALL_LAST_FRAME ? 1 : 0);
+ // debug_msg (" HWACCEL_VDPAU : %d\n", pVideoCodec->capabilities & CODEC_CAP_HWACCEL_VDPAU ? 1 : 0);
+ #endif
+
+ if (pVideoCodec->capabilities & CODEC_CAP_TRUNCATED) {
+ pVideoCodecCtx->flags |= CODEC_FLAG_TRUNCATED;
+ }
+
+ /*set workaround bug flag*/
+ pVideoCodecCtx->workaround_bugs = FF_BUG_AUTODETECT;
+#ifdef __MMFILE_FFMPEG_V100__
+ ret = avcodec_open2 (pVideoCodecCtx, pVideoCodec, NULL);
+#else
+ ret = avcodec_open (pVideoCodecCtx, pVideoCodec);
+#endif
+ if (ret < 0) {
+ debug_error ("error: avcodec_open fail.\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ pFrameRGB = avcodec_alloc_frame ();
+
+ if (!pFrameRGB) {
+ debug_error ("error: pFrame or pFrameRGB is NULL\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /* search & decode */
+ // seek_ts = formatContext->duration > _SHORT_MEDIA_LIMIT ? seek_ts : 0; /*if short media, seek first key frame*/
+ ret = _get_first_good_video_frame (pFormatCtx, pVideoCodecCtx, formatContext->videoStreamId, &pFrame);
+ if ( ret != MMFILE_FORMAT_SUCCESS ) {
+ debug_error ("error: get key frame\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("Video default resolution = [%dx%d]\n", pVideoCodecCtx->coded_width, pVideoCodecCtx->coded_height);
+ debug_msg ("Video coded resolution = [%dx%d]\n", pVideoCodecCtx->width, pVideoCodecCtx->height);
+ #endif
+
+ /*sometimes, ffmpeg's width/height is wrong*/
+ #if 0 /*coded_width/height sometimes wrong. so use width/height*/
+ width = pVideoCodecCtx->coded_width == 0 ? pVideoCodecCtx->width : pVideoCodecCtx->coded_width;
+ height = pVideoCodecCtx->coded_height == 0 ? pVideoCodecCtx->height : pVideoCodecCtx->coded_height;
+ #endif
+ if((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
+ width = pVideoCodecCtx->coded_width;
+ height = pVideoCodecCtx->coded_height;
+ } else {
+ width = pVideoCodecCtx->width;
+ height = pVideoCodecCtx->height;
+ }
+
+ numBytes = avpicture_get_size(PIX_FMT_RGB24, width, height);
+ if (numBytes < 0) {
+ debug_error ("error: avpicture_get_size. [%d x %d]\n", width, height);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ frame->frameData = mmfile_malloc (numBytes);
+ if (NULL == frame->frameData) {
+ debug_error ("error: avpicture_get_size. [%d]\n", numBytes);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ ret = avpicture_fill ((AVPicture *)pFrameRGB, frame->frameData, PIX_FMT_RGB24, width, height);
+ if (ret < 0) {
+ debug_error ("error: avpicture_fill fail. errcode = 0x%08X\n", ret);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+#ifdef __MMFILE_FFMPEG_V085__
+ struct SwsContext *img_convert_ctx = NULL;
+
+ img_convert_ctx = sws_getContext (width, height, pVideoCodecCtx->pix_fmt,
+ width, height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
+
+ if (NULL == img_convert_ctx) {
+ debug_error ("failed to get img convet ctx\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ ret = sws_scale (img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize,
+ 0, height, pFrameRGB->data, pFrameRGB->linesize);
+ if ( ret < 0 ) {
+ debug_error ("failed to convet image\n");
+ ret = MMFILE_FORMAT_FAIL;
+ sws_freeContext(img_convert_ctx);
+ img_convert_ctx = NULL;
+ goto exception;
+ }
+
+ sws_freeContext(img_convert_ctx);
+ img_convert_ctx = NULL;
+#else
+ ret = img_convert ((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pVideoCodecCtx->pix_fmt, width, height);
+ if ( ret < 0 ) {
+ debug_error ("failed to convet image\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+#endif
+ frame->frameSize = numBytes;
+ frame->frameWidth = width;
+ frame->frameHeight = height;
+ frame->configLenth = 0;
+ frame->bCompressed = 0; /* false */
+
+ if (pFrame) av_free (pFrame);
+ if (pFrameRGB) av_free (pFrameRGB);
+
+ avcodec_close(pVideoCodecCtx);
+
+ return MMFILE_FORMAT_SUCCESS;
+ }
+
+
+exception:
+ if (pVideoCodecCtx) avcodec_close (pVideoCodecCtx);
+ if (frame->frameData) { mmfile_free (frame->frameData); frame->frameData = NULL; }
+ if (pFrame) av_free (pFrame);
+ if (pFrameRGB) av_free (pFrameRGB);
+ return ret;
+}
+
+
+EXPORT_API
+int mmfile_format_close_ffmpg(MMFileFormatContext *formatContext)
+{
+ if (formatContext) {
+ AVFormatContext *pFormatCtx = formatContext->privateFormatData;
+
+ if (pFormatCtx) {
+#ifdef __MMFILE_FFMPEG_V100__
+ avformat_close_input(&pFormatCtx);
+#else
+ av_close_input_file (pFormatCtx);
+#endif
+ formatContext->privateFormatData = NULL;
+ }
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+/**
+ * return average of difference
+ */
+static unsigned int _diff_memory (const void *s1, const void *s2, unsigned int n)
+{
+ char *s = (char *)s1;
+ char *d = (char *)s2;
+ int i;
+ int ret;
+ int tmp;
+
+ for (i = 0, ret = 0; i < n; i++) {
+ if (*s++ != *d++) {
+ tmp = (*s - *d);
+ ret += (tmp < 0 ? -tmp : tmp);
+ }
+ }
+ ret /= n;
+ return ret;
+}
+
+int64_t gettime(void)
+{
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+
+#define IS_GOOD_OLD_METHOD
+#ifdef IS_GOOD_OLD_METHOD
+/**
+ * compare with center line.
+ */
+static int _is_good_pgm (unsigned char *buf, int wrap, int xsize, int ysize)
+{
+#define _MM_CHUNK_NUM 8 /*FIXME*/
+#define _MM_CHUNK_LIMIT (_MM_CHUNK_NUM / 2)
+#define _MM_CHUNK_DIFF_LIMIT (_MM_CHUNK_LIMIT * 2 + 1) /*FIXME*/
+
+ int i;
+ int step;
+ int point;
+ unsigned char *cnt; /*center line of image*/
+ int is_different;
+ unsigned int sum_diff;
+ int cnt_offset;
+
+ /*set center line*/
+ step = ysize / _MM_CHUNK_NUM;
+ cnt_offset = (ysize / 2);
+ cnt = buf + cnt_offset * wrap;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("checking frame. %p, %d, %d, %d\n", buf, wrap, xsize, ysize);
+ #endif
+
+ /*if too small, always ok return.*/
+ if (ysize < _MM_CHUNK_NUM)
+ return 1;
+
+ for (point = 0, sum_diff = 0, i = step; i < ysize; i += step) {
+ if (i != cnt_offset) {
+
+ /*binary compare*/
+ is_different = _diff_memory (cnt, buf + i * wrap, xsize);
+ point += (is_different == 0 ? 0 : 1);
+ sum_diff += is_different;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("check %04d line. %s [%d]\n", i, (is_different == 0 ? "same" : "different"), is_different);
+ #endif
+
+ if (point >= _MM_CHUNK_LIMIT) {
+ if (sum_diff > _MM_CHUNK_DIFF_LIMIT) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("Good :-)\n");
+ #endif
+ return 1;
+ } else {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("Bad :-(\n");
+ #endif
+ return 0;
+ }
+ }
+ }
+
+ }
+ return 0;
+}
+#else // IS_GOOD_OLD_METHOD
+/* ToDo : for enhancement */
+#endif // IS_GOOD_OLD_METHOD
+
+
+
+static int
+_get_video_fps (int frame_cnt, int duration, AVRational r_frame_rate, int is_roundup)
+{
+ double fps, round;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("frame count: %d, dur: %d, num: %d, den: %d\n", frame_cnt, duration, r_frame_rate.num, r_frame_rate.den)
+ #endif
+
+ if (duration <= 0 || r_frame_rate.num <= 0 || r_frame_rate.den <= 0)
+ return 0;
+
+ round = (is_roundup != 0 ? 0.50f : 0.00f);
+
+ fps = (double)frame_cnt / ((double)(duration * r_frame_rate.num) / r_frame_rate.den) + round;
+
+ return (int)fps;
+}
+
+#ifdef MMFILE_FORMAT_DEBUG_DUMP
+static void _save_pgm (unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
+{
+ FILE *f;
+ int i;
+
+ f = fopen(filename,"w");
+ if (f) {
+ fprintf (f,"P5\n%d %d\n%d\n",xsize,ysize,255);
+ for (i = 0; i < ysize; i++)
+ fwrite (buf + i * wrap, 1, xsize, f);
+ fclose (f);
+ }
+}
+#endif
+
+#ifdef __MMFILE_TEST_MODE__
+static void _dump_av_packet (AVPacket *pkt)
+{
+ debug_msg ("--------- AV Packet -----------\n");
+ debug_msg (" pts: %lld\n", pkt->pts);
+ debug_msg (" dts: %lld\n", pkt->dts);
+ debug_msg (" data: %p\n", pkt->data);
+ debug_msg (" size: %d\n", pkt->size);
+ debug_msg (" stream_index: %d\n", pkt->stream_index);
+#ifdef __MMFILE_FFMPEG_V085__
+ debug_msg (" flags: 0x%08X, %s\n", pkt->flags, (pkt->flags & AV_PKT_FLAG_KEY) ? "Keyframe" : "_");
+#else
+ debug_msg (" flags: 0x%08X, %s\n", pkt->flags, (pkt->flags & PKT_FLAG_KEY) ? "Keyframe" : "_");
+#endif
+ debug_msg (" duration: %d\n", pkt->duration);
+ debug_msg (" destruct: %p\n", pkt->destruct);
+ debug_msg (" priv: %p\n", pkt->priv);
+ debug_msg (" pos: %lld\n", pkt->pos);
+ debug_msg (" convergence_duration: %lld\n", pkt->convergence_duration);
+ debug_msg ("-------------------------------\n");
+}
+#endif
+
+static int _get_first_good_video_frame (AVFormatContext *pFormatCtx, AVCodecContext *pCodecCtx, int videoStream, AVFrame **pFrame)
+{
+ // AVStream *st = NULL;
+ AVPacket pkt;
+
+ AVFrame *frame = NULL;
+ AVFrame *tmp_frame = NULL;
+ AVFrame *first_frame = NULL;
+
+ // long long timestamp;
+ int stream_id = videoStream;
+ int ret;
+ int found = 0;
+ int i,v, len, got_picture;
+ int retry = 0;
+ int key_detected;
+#ifdef MMFILE_FORMAT_DEBUG_DUMP
+ char pgm_name[256] = {0,};
+#endif
+
+#define _RETRY_SEARCH_LIMIT 150
+#define _KEY_SEARCH_LIMIT (_RETRY_SEARCH_LIMIT*2) /*2 = 1 read. some frame need to read one more*/
+#define _FRAME_SEARCH_LIMIT 1000
+
+ first_frame = avcodec_alloc_frame ();
+ tmp_frame = avcodec_alloc_frame ();
+
+ if (!first_frame || !tmp_frame) {
+ debug_error ("failed to alloc frame.\n");
+ if (first_frame) av_free (first_frame);
+ if (tmp_frame) av_free (tmp_frame);
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("frame: 1. %p, 2. %p\n", first_frame, tmp_frame);
+ #endif
+
+#ifdef __MMFILE_FFMPEG_V085__
+ pCodecCtx->skip_frame = AVDISCARD_BIDIR;
+#else
+ pCodecCtx->hurry_up = 1;
+#endif
+
+ for(i = 0, v = 0, key_detected = 0, frame = first_frame; i < _KEY_SEARCH_LIMIT && v < _FRAME_SEARCH_LIMIT;) {
+ av_init_packet (&pkt);
+ got_picture = 0;
+
+ ret = av_read_frame (pFormatCtx, &pkt);
+ if (ret < 0) {
+ debug_error ("read failed. (maybe EOF or broken)\n");
+ break;
+ } else {
+ if (pkt.stream_index == stream_id) {
+ v++;
+#ifdef __MMFILE_FFMPEG_V085__
+ if ((pkt.flags & AV_PKT_FLAG_KEY ) || (key_detected == 1))
+#else
+ if ((pkt.flags & PKT_FLAG_KEY ) || (key_detected == 1))
+#endif
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("video frame: %d, %d, %d\n", retry, i, v);
+ _dump_av_packet (&pkt);
+ #endif
+
+ i++;
+ key_detected = 0;
+#ifdef __MMFILE_FFMPEG_V085__
+ len = avcodec_decode_video2 (pCodecCtx, frame, &got_picture, &pkt);
+#else
+ len = avcodec_decode_video (pCodecCtx, frame, &got_picture, pkt.data, pkt.size);
+#endif
+ if (len < 0) {
+ debug_warning ("Error while decoding frame %dth\n", i);
+ } else if (got_picture) {
+ if (frame->key_frame) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("key frame!\n");
+ #endif
+ #ifdef MMFILE_FORMAT_DEBUG_DUMP
+ sprintf (pgm_name, "./key_%d_%d_%d.pgm", retry, i, v);
+ _save_pgm (frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height, pgm_name);
+ #endif
+
+ found++;
+
+ #ifdef __MMFILE_TEST_MODE__
+ int64_t ti;
+ ti = gettime();
+ #endif
+ ret = _is_good_pgm (frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height);
+ #ifdef __MMFILE_TEST_MODE__
+ ti = gettime() - ti;
+ debug_msg ("Elapsed time = %lld\n", ti);
+ #endif
+ if (ret != 0) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("is good frame.\n");
+ #endif
+ break;
+ } else {
+ /*reset video frame count & retry searching*/
+ debug_warning ("not good fame. retry scanning.\n");
+ i = 0;
+ v = 0;
+ retry++;
+ }
+
+ /*set buffer frame*/
+ frame = tmp_frame;
+
+ /*limit of retry.*/
+ if (retry > _RETRY_SEARCH_LIMIT) break;
+
+ } else {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("skip (not key frame).\n");
+ #endif
+ #ifdef MMFILE_FORMAT_DEBUG_DUMP
+ sprintf (pgm_name, "./not_key_%d_%d_%d.pgm", retry, i, v);
+ _save_pgm (frame->data[0], frame->linesize[0], pCodecCtx->width, pCodecCtx->height, pgm_name);
+ #endif
+ }
+ } else {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("decode not completed.\n");
+ #endif
+ key_detected = 1;
+ }
+ }
+ }
+ }
+ av_free_packet (&pkt);
+ }
+
+ /*free pkt after loop breaking*/
+ if (pkt.data) av_free_packet (&pkt);
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("found: %d, retry: %d\n", found, retry);
+ #endif
+
+ /*set decode frame to output*/
+ if (found > 0) {
+ ret = MMFILE_FORMAT_SUCCESS;
+ if (retry == 0 || found == retry) {
+ *pFrame = first_frame;
+ if (tmp_frame) av_free (tmp_frame);
+ } else {
+ *pFrame = tmp_frame;
+ if (first_frame) av_free (first_frame);
+ }
+ } else {
+ ret = MMFILE_FORMAT_FAIL;
+ if (first_frame) av_free (first_frame);
+ if (tmp_frame) av_free (tmp_frame);
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("out frame: %p\n", *pFrame);
+ #endif
+
+#ifdef __MMFILE_FFMPEG_V085__
+ pCodecCtx->skip_frame = AVDISCARD_NONE;
+#else
+ pCodecCtx->hurry_up = 0;
+#endif
+
+ return ret;
+}
+
+static int ConvertVideoCodecEnum (int AVVideoCodecID)
+{
+ int ret_codecid = 0;
+
+ switch (AVVideoCodecID)
+ {
+ case AV_CODEC_ID_NONE:
+ ret_codecid = MM_VIDEO_CODEC_NONE;
+ break;
+ case AV_CODEC_ID_MPEG1VIDEO:
+ ret_codecid = MM_VIDEO_CODEC_MPEG1;
+ break;
+ case AV_CODEC_ID_MPEG2VIDEO: ///< preferred ID for MPEG-1/2 video decoding
+ ret_codecid = MM_VIDEO_CODEC_MPEG2;
+ break;
+ case AV_CODEC_ID_MPEG2VIDEO_XVMC:
+ ret_codecid = MM_VIDEO_CODEC_MPEG2;
+ break;
+ case AV_CODEC_ID_H261:
+ ret_codecid = MM_VIDEO_CODEC_H261;
+ break;
+ case AV_CODEC_ID_H263:
+ ret_codecid = MM_VIDEO_CODEC_H263;
+ break;
+ case AV_CODEC_ID_MPEG4:
+ ret_codecid = MM_VIDEO_CODEC_MPEG4;
+ break;
+ case AV_CODEC_ID_MSMPEG4V1:
+ ret_codecid = MM_VIDEO_CODEC_MPEG4;
+ break;
+ case AV_CODEC_ID_MSMPEG4V2:
+ ret_codecid = MM_VIDEO_CODEC_MPEG4;
+ break;
+ case AV_CODEC_ID_MSMPEG4V3:
+ ret_codecid = MM_VIDEO_CODEC_MPEG4;
+ break;
+ case AV_CODEC_ID_WMV1:
+ ret_codecid = MM_VIDEO_CODEC_WMV;
+ break;
+ case AV_CODEC_ID_WMV2:
+ ret_codecid = MM_VIDEO_CODEC_WMV;
+ break;
+ case AV_CODEC_ID_H263P:
+ ret_codecid = MM_VIDEO_CODEC_H263;
+ break;
+ case AV_CODEC_ID_H263I:
+ ret_codecid = MM_VIDEO_CODEC_H263;
+ break;
+ case AV_CODEC_ID_FLV1:
+ ret_codecid = MM_VIDEO_CODEC_FLV;
+ break;
+ case AV_CODEC_ID_H264:
+ ret_codecid = MM_VIDEO_CODEC_H264;
+ break;
+ case AV_CODEC_ID_INDEO2:
+ case AV_CODEC_ID_INDEO3:
+ case AV_CODEC_ID_INDEO4:
+ case AV_CODEC_ID_INDEO5:
+ ret_codecid = MM_VIDEO_CODEC_INDEO;
+ break;
+ case AV_CODEC_ID_THEORA:
+ ret_codecid = MM_VIDEO_CODEC_THEORA;
+ break;
+ case AV_CODEC_ID_CINEPAK:
+ ret_codecid = MM_VIDEO_CODEC_CINEPAK;
+ break;
+#ifndef __MMFILE_FFMPEG_V085__
+ case CODEC_ID_XVID:
+ ret_codecid = MM_VIDEO_CODEC_XVID;
+ break;
+#endif
+ case AV_CODEC_ID_VC1:
+ ret_codecid = MM_VIDEO_CODEC_VC1;
+ break;
+ case AV_CODEC_ID_WMV3:
+ ret_codecid = MM_VIDEO_CODEC_WMV;
+ break;
+ case AV_CODEC_ID_AVS:
+ ret_codecid = MM_VIDEO_CODEC_AVS;
+ break;
+ case AV_CODEC_ID_RL2:
+ ret_codecid = MM_VIDEO_CODEC_REAL;
+ break;
+ default:
+ ret_codecid = MM_VIDEO_CODEC_NONE;
+ break;
+ }
+
+ return ret_codecid;
+}
+
+
+static int ConvertAudioCodecEnum (int AVAudioCodecID)
+{
+ int ret_codecid = 0;
+
+ switch (AVAudioCodecID)
+ {
+ case AV_CODEC_ID_AMR_NB:
+ case AV_CODEC_ID_AMR_WB:
+ ret_codecid = MM_AUDIO_CODEC_AMR;
+ break;
+ /* RealAudio codecs*/
+ case AV_CODEC_ID_RA_144:
+ case AV_CODEC_ID_RA_288:
+ ret_codecid = MM_AUDIO_CODEC_REAL;
+ break;
+ case AV_CODEC_ID_MP2:
+ ret_codecid = MM_AUDIO_CODEC_MP2;
+ break;
+ case AV_CODEC_ID_MP3:
+ case AV_CODEC_ID_MP3ADU:
+ case AV_CODEC_ID_MP3ON4:
+ ret_codecid = MM_AUDIO_CODEC_MP3;
+ break;
+ case AV_CODEC_ID_AAC:
+ ret_codecid = MM_AUDIO_CODEC_AAC;
+ break;
+ case AV_CODEC_ID_AC3:
+ ret_codecid = MM_AUDIO_CODEC_AC3;
+ break;
+ case AV_CODEC_ID_VORBIS:
+ ret_codecid = MM_AUDIO_CODEC_VORBIS;
+ break;
+ case AV_CODEC_ID_WMAV1:
+ case AV_CODEC_ID_WMAV2:
+ case AV_CODEC_ID_WMAVOICE:
+ case AV_CODEC_ID_WMAPRO:
+ case AV_CODEC_ID_WMALOSSLESS:
+ ret_codecid = MM_AUDIO_CODEC_WMA;
+ break;
+ case AV_CODEC_ID_FLAC:
+ ret_codecid = MM_AUDIO_CODEC_FLAC;
+ break;
+ case AV_CODEC_ID_ALAC:
+ ret_codecid = MM_AUDIO_CODEC_ALAC;
+ break;
+ case AV_CODEC_ID_WAVPACK:
+ ret_codecid = MM_AUDIO_CODEC_WAVE;
+ break;
+ case AV_CODEC_ID_ATRAC3:
+ case AV_CODEC_ID_ATRAC3P:
+ case AV_CODEC_ID_EAC3:
+ ret_codecid = MM_AUDIO_CODEC_AC3;
+ break;
+ default:
+ ret_codecid = MM_AUDIO_CODEC_NONE;
+ break;
+ }
+
+ return ret_codecid;
+}
+
+
+
+static int getMimeType(int formatId, char *mimeType)
+{
+ int ret = 0; /*default: success*/
+
+ switch(formatId) {
+ case MM_FILE_FORMAT_3GP:
+ case MM_FILE_FORMAT_MP4:
+ sprintf(mimeType,"video/3gpp");
+ break;
+ case MM_FILE_FORMAT_ASF:
+ case MM_FILE_FORMAT_WMA:
+ case MM_FILE_FORMAT_WMV:
+ sprintf(mimeType,"video/x-ms-asf");
+ break;
+ case MM_FILE_FORMAT_AVI:
+ sprintf(mimeType,"video/avi");
+ break;
+ case MM_FILE_FORMAT_OGG:
+ sprintf(mimeType,"video/ogg");
+ break;
+ case MM_FILE_FORMAT_REAL:
+ sprintf(mimeType,"video/vnd.rn-realvideo");
+ break;
+ case MM_FILE_FORMAT_AMR:
+ sprintf(mimeType,"audio/AMR");
+ break;
+ case MM_FILE_FORMAT_AAC:
+ sprintf(mimeType,"audio/aac");
+ break;
+ case MM_FILE_FORMAT_MP3:
+ sprintf(mimeType,"audio/mp3");
+ break;
+ case MM_FILE_FORMAT_AIFF:
+ case MM_FILE_FORMAT_WAV:
+ sprintf(mimeType,"audio/wave");
+ break;
+ case MM_FILE_FORMAT_MID:
+ sprintf(mimeType,"audio/midi");
+ break;
+ case MM_FILE_FORMAT_MMF:
+ sprintf(mimeType,"audio/mmf");
+ break;
+ case MM_FILE_FORMAT_DIVX:
+ sprintf(mimeType,"video/divx");
+ break;
+ case MM_FILE_FORMAT_IMELODY:
+ sprintf(mimeType,"audio/iMelody");
+ break;
+ case MM_FILE_FORMAT_JPG:
+ sprintf(mimeType,"image/jpeg");
+ break;
+ case MM_FILE_FORMAT_AU:
+ sprintf(mimeType,"audio/basic");
+ break;
+ case MM_FILE_FORMAT_VOB:
+ sprintf(mimeType,"video/mpeg");
+ break;
+ case MM_FILE_FORMAT_FLV:
+ sprintf(mimeType,"video/x-flv");
+ break;
+ case MM_FILE_FORMAT_QT:
+ sprintf(mimeType,"video/quicktime");
+ break;
+ case MM_FILE_FORMAT_MATROSKA:
+ sprintf(mimeType,"video/x-matroska");
+ break;
+ case MM_FILE_FORMAT_FLAC:
+ sprintf(mimeType,"audio/x-flac");
+ break;
+ default:
+ ret = -1;
+ }
+
+ debug_msg ("id: %d, mimetype: %s\n", formatId, mimeType);
+
+ return ret;
+}
+
+
diff --git a/formats/ffmpeg/mm_file_format_ffmpeg_mem.c b/formats/ffmpeg/mm_file_format_ffmpeg_mem.c
new file mode 100755
index 0000000..b117132
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_ffmpeg_mem.c
@@ -0,0 +1,248 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+#include "mm_debug.h"
+#include "mm_file_utils.h"
+
+
+typedef struct {
+ unsigned char *ptr;
+ long long size;
+ long long offset;
+ int state;
+} MMFmemIOHandle;
+
+static int mmf_mem_open (URLContext *handle, const char *filename, int flags)
+{
+ MMFmemIOHandle *memHandle = NULL;
+ char **splitedString = NULL;
+
+
+ if (!handle || !filename || !handle->prot)
+ {
+ debug_error ("invalid param\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ filename += strlen(handle->prot->name) + 3; /* ://%d:%d means (memory addr:mem size)*/
+
+ splitedString = mmfile_strsplit (filename, ":");
+ if (splitedString == NULL)
+ {
+ debug_error ("invalid param\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ if (!splitedString[0] || !splitedString[1])
+
+ {
+ debug_error ("invalid param\n");
+ goto exception;
+ }
+
+ memHandle = mmfile_malloc (sizeof(MMFmemIOHandle));
+ if (!memHandle)
+ {
+ debug_error ("error: mmfile_malloc memHandle\n");
+ goto exception;
+ }
+
+ memHandle->ptr = (unsigned char *) atoll(splitedString[0]); //memory allocation address changed. memHandle->ptr = (unsigned char *) atoi(splitedString[0]);
+ memHandle->size = atoi(splitedString[1]);
+ memHandle->offset = 0;
+ memHandle->state = 0;
+
+ handle->priv_data = (void*) memHandle;
+
+ // Imp to reset them otherwise file seek will fail
+ handle->is_streamed = 0; /*FALSE*/
+ handle->max_packet_size = 0;
+
+ if (splitedString)
+ {
+ mmfile_strfreev (splitedString);
+ }
+
+ return MMFILE_UTIL_SUCCESS;
+
+exception:
+
+ if (splitedString)
+ {
+ mmfile_strfreev (splitedString);
+ }
+
+#if 0 //dead code
+ if (memHandle)
+ {
+ mmfile_free (memHandle);
+ handle->priv_data = NULL;
+ }
+#endif
+
+ return MMFILE_UTIL_FAIL;
+}
+
+static int mmf_mem_read (URLContext *h, unsigned char *buf, int size)
+{
+ MMFmemIOHandle *memHandle = NULL;
+ const unsigned char *c = NULL;
+ int len = 0;
+
+
+ if (!h || !h->priv_data || !buf)
+ {
+ debug_error ("invalid para\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ memHandle = h->priv_data;
+
+ if (!memHandle->ptr)
+ {
+ debug_error ("invalid para\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ if (memHandle->offset >= memHandle->size) {
+ // for some file formats last file read
+ debug_error ("File Read is beyond the file Size\n");
+ return MMFILE_UTIL_FAIL;
+
+ }
+
+ c = memHandle->ptr + memHandle->offset;
+
+ if (memHandle->state != EOF)
+ {
+ len = size;
+ if (len + memHandle->offset > memHandle->size)
+ {
+ len = memHandle->size - memHandle->offset;
+ }
+ }
+
+ memcpy (buf, c, len);
+
+ memHandle->offset += len;
+
+ if ( memHandle->offset == memHandle->size)
+ {
+ memHandle->state = EOF;
+ }
+
+ return len;
+}
+
+static int mmf_mem_write (URLContext *h, unsigned char *buf, int size)
+{
+ if (!h || !h->priv_data || !buf)
+ {
+ debug_error ("invalid para\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ debug_error ("NOTE PERMITTED\n");
+ return MMFILE_UTIL_FAIL;
+}
+
+
+static long long mmf_mem_seek (URLContext *h, long long pos, int whence)
+{
+ MMFmemIOHandle *memHandle = NULL;
+ long long tmp_offset = 0;
+
+
+ if (!h || !h->priv_data)
+ {
+ debug_error ("invalid para\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ memHandle = h->priv_data;
+
+ switch (whence)
+ {
+ case SEEK_SET:
+ tmp_offset = 0 + pos;
+ break;
+ case SEEK_CUR:
+ tmp_offset = memHandle->offset + pos;
+ break;
+ case SEEK_END:
+ tmp_offset = memHandle->size + pos;
+ break;
+ case AVSEEK_SIZE: /*FFMPEG specific*/
+ return memHandle->size;
+ default:
+ return MMFILE_UTIL_FAIL;
+ }
+
+ /*check validation*/
+ if (tmp_offset < 0 && tmp_offset > memHandle->size)
+ {
+ debug_error ("invalid file offset\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ /*set */
+ memHandle->state = (tmp_offset >= memHandle->size) ? EOF : !EOF;
+ memHandle->offset = (unsigned int) tmp_offset;
+
+ return tmp_offset;
+}
+
+static int mmf_mem_close (URLContext *h)
+{
+ MMFmemIOHandle *memHandle = NULL;
+
+ if (!h || !h->priv_data)
+ {
+ debug_error ("invalid para\n");
+ return MMFILE_UTIL_FAIL;
+ }
+
+ memHandle = h->priv_data;
+
+ if (memHandle)
+ {
+ mmfile_free (memHandle);
+ h->priv_data = NULL;
+ }
+
+ return MMFILE_UTIL_SUCCESS;
+}
+
+
+URLProtocol MMFileMEMProtocol = {
+ .name = "mem",
+ .url_open = mmf_mem_open,
+ .url_read = mmf_mem_read,
+ .url_write = mmf_mem_write,
+ .url_seek = mmf_mem_seek,
+ .url_close = mmf_mem_close,
+};
diff --git a/formats/ffmpeg/mm_file_format_frame.c b/formats/ffmpeg/mm_file_format_frame.c
new file mode 100755
index 0000000..7d7a8f0
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_frame.c
@@ -0,0 +1,357 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+#include <stdbool.h>
+#include <libavformat/avformat.h>
+#include <libavcodec/avcodec.h>
+#include <libswscale/swscale.h>
+
+#include "mm_debug.h"
+#include "mm_file_formats.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_frame.h"
+
+#define MILLION 1000000
+#ifdef MMFILE_FORMAT_DEBUG_DUMP
+static void _save_pgm (unsigned char *buf,int wrap, int xsize,int ysize,char *filename);
+
+static void _save_pgm (unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
+{
+ FILE *f;
+ int i;
+
+ f = fopen(filename,"w");
+ if (f) {
+ fprintf (f,"P5\n%d %d\n%d\n",xsize,ysize,255);
+ for (i = 0; i < ysize; i++)
+ fwrite (buf + i * wrap, 1, xsize, f);
+ fclose (f);
+ }
+}
+#endif
+
+int mmfile_format_get_frame(const char* path, double timestamp, bool is_accurate, unsigned char **frame, int *size, int *width, int *height)
+{
+ int i = 0;
+ int ret = MMFILE_FORMAT_SUCCESS;
+ int videoStream = -1;
+ int frameFinished = 0;
+ double pos = timestamp;
+ bool find = false ;
+ bool first_seek = true;
+ int64_t pts = 0;
+ AVFormatContext *pFormatCtx = NULL;
+ AVCodecContext *pVideoCodecCtx = NULL;
+ AVCodec *pVideoCodec = NULL;
+ AVFrame *pFrame = NULL, *pFrameRGB = NULL;
+ AVPacket packet;
+ int len = 0;
+ int key_detected = 0;
+
+ if (!size || !width || !height) {
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ av_register_all();
+
+ /* Open video file */
+ if(avformat_open_input(&pFormatCtx, path, NULL, NULL) != 0) {
+ debug_error("error : avformat_open_input failed");
+ return MMFILE_FORMAT_FAIL; /* Couldn't open file */
+ }
+
+ if (!pFormatCtx) {
+ debug_warning ("failed to find av stream. maybe corrupted data.\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /* Retrieve stream information */
+#ifdef __MMFILE_FFMPEG_V100__
+ if(avformat_find_stream_info(pFormatCtx, NULL) < 0) {
+#else
+ if(av_find_stream_info(pFormatCtx) < 0) {
+#endif
+ debug_error("error : av_find_stream_info failed");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception; /* Couldn't find stream information */
+ }
+
+ /* Find the first video stream */
+ for(i = 0; i < pFormatCtx->nb_streams; i++) {
+ if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ videoStream = i;
+ break;
+ }
+ }
+
+ if(videoStream == -1) {
+ debug_error("error : videoStream == -1");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception; /* Didn't find a video stream */
+ }
+
+ /* Get a pointer to the codec context for the video stream */
+ pVideoCodecCtx=pFormatCtx->streams[videoStream]->codec;
+ if (pVideoCodecCtx == NULL) {
+ debug_error ("invalid param\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /* Find the decoder for the video stream */
+ pVideoCodec = avcodec_find_decoder(pVideoCodecCtx->codec_id);
+ if(pVideoCodec == NULL) {
+ debug_error("error : Unsupported codec");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception; /* Codec not found */
+ }
+
+ /* Open codec */
+#ifdef __MMFILE_FFMPEG_V100__
+ if(avcodec_open2(pVideoCodecCtx, pVideoCodec, NULL) < 0) {
+#else
+ if(avcodec_open(pVideoCodecCtx, pVideoCodec) < 0) {
+#endif
+ debug_error("error : avcodec_open failed");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;; /*Could not open codec */
+ }
+
+ /* Storing Data */
+ /* Allocate video frame */
+ pFrame = avcodec_alloc_frame();
+ if(pFrame == NULL) {
+ debug_error ("error: pFrame is NULL\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /* Allocate an AVFrame structure */
+ pFrameRGB = avcodec_alloc_frame();
+ if(pFrameRGB == NULL) {
+ debug_error ("error: pFrameRGB is NULL\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /* Seeking */
+ AVStream *pStream = pFormatCtx->streams[videoStream];
+ double duration = (double) pFormatCtx->duration / AV_TIME_BASE;
+#if 0
+ if (duration <= 0) {
+ double tmpDuration = 0.0;
+
+ if (pStream->codec->bit_rate > 0 && pFormatCtx->file_size > 0) {
+ if (pStream->codec->bit_rate >= 8)
+ tmpDuration = 0.9 * pFormatCtx->file_size / (pStream->codec->bit_rate / 8);
+
+ if (tmpDuration > 0)
+ duration = tmpDuration;
+ }
+ }
+#endif
+ duration = duration * MILLION;
+ if ((duration <= 0) ||(duration <= pos)) {
+ debug_error("duration error duration[%f] pos[%f]", duration, pos);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ if (is_accurate)
+ av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_ANY);
+ else
+ av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
+
+ /* Reading Data */
+ int64_t tmpPts = 0;
+#ifdef __MMFILE_TEST_MODE__
+ int idx = 0;
+#endif
+
+ av_init_packet(&packet);
+
+ while(av_read_frame(pFormatCtx, &packet) >= 0) {
+ frameFinished = 0;
+
+ // Is this a packet from the video stream?
+ if(packet.stream_index == videoStream) {
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("find Video Stream+++++++[%2d]", idx++);
+#endif
+ /* Decode video frame*/
+ len = avcodec_decode_video2(pVideoCodecCtx, pFrame, &frameFinished, &packet);
+ if (len < 0) {
+ debug_warning ("Error while decoding frame");
+ } else if ((packet.flags & AV_PKT_FLAG_KEY) || (key_detected == 1)) {
+
+ key_detected = 0;
+
+ if (first_seek || !is_accurate) {
+ /* This is first seeking or not accurate mode.
+ Sometimes flag is AV_PKT_FLAG_KEY but frameFinished is NULL.
+ first_seek is used when accurate mode and when time stamp's frame is not key frame.
+ Go back to previousto Key frame and decode frame until time stamp's frame*/
+
+ if (frameFinished) {
+ if(pFrame->key_frame) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg("find Video Stream+++++++Find key frame");
+ #endif
+
+ find = true;
+ } else {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg("find Video Stream+++++++skip (not key frame)");
+ #endif
+ }
+ } else {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg("find Video Stream+++++++Find key but no frame");
+ #endif
+ key_detected = 1;
+ }
+ }
+ } else {
+ if (first_seek) {
+ pts = (packet.pts == AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
+ first_seek = false;
+
+ av_seek_frame(pFormatCtx, -1, pos, AVSEEK_FLAG_BACKWARD);
+ } else {
+ tmpPts = (packet.pts == AV_NOPTS_VALUE) ? (packet.dts * av_q2d(pStream->time_base)) : packet.pts;
+ if (pts == tmpPts)
+ find = true;
+ }
+ }
+
+ if(find && frameFinished) {
+ #ifdef MMFILE_FORMAT_DEBUG_DUMP
+ char pgm_name[256] = {0,};
+ sprintf (pgm_name, "./key_%d.ppm", (int)pos/1000);
+ _save_pgm (pFrame->data[0], pFrame->linesize[0], pVideoCodecCtx->width, pVideoCodecCtx->height, pgm_name);
+ #endif
+ break;
+ }
+ }
+
+ /* Free the packet that was allocated by av_read_frame*/
+ av_free_packet(&packet);
+ av_init_packet(&packet);
+ }
+
+ /*free pkt after loop breaking*/
+ av_free_packet (&packet);
+
+ /* Did we get a video frame?*/
+ if(frameFinished && find) {
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("Find Frame");
+#endif
+ /* return frame infromations*/
+ if((pVideoCodecCtx->width == 0) || (pVideoCodecCtx->height == 0)) {
+ *width = pVideoCodecCtx->coded_width;
+ *height = pVideoCodecCtx->coded_height;
+ } else {
+ *width = pVideoCodecCtx->width;
+ *height = pVideoCodecCtx->height;
+ }
+
+ *size = avpicture_get_size(PIX_FMT_RGB24, *width, *height);
+ *frame = mmfile_malloc (*size);
+ if (NULL == *frame) {
+ debug_error ("error: avpicture_get_size. [%d]\n", size);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+#ifdef __MMFILE_TEST_MODE__
+ debug_msg("size : %d", *size);
+ debug_msg("width : %d", *width);
+ debug_msg("height : %d", *height);
+ debug_msg("frame : %x", *frame);
+#endif
+ ret = avpicture_fill ((AVPicture *)pFrameRGB, *frame, PIX_FMT_RGB24, *width, *height);
+ if (ret < 0) {
+ debug_error ("error: avpicture_fill fail. errcode = 0x%08X\n", ret);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+#ifdef __MMFILE_FFMPEG_V085__
+ struct SwsContext *img_convert_ctx = NULL;
+
+ img_convert_ctx = sws_getContext (*width, *height, pVideoCodecCtx->pix_fmt,
+ *width, *height, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL);
+
+ if (NULL == img_convert_ctx) {
+ debug_error ("failed to get img convet ctx\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ ret = sws_scale (img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize,
+ 0, *height, pFrameRGB->data, pFrameRGB->linesize);
+ if ( ret < 0 ) {
+ debug_error ("failed to convet image\n");
+ sws_freeContext(img_convert_ctx);
+ img_convert_ctx = NULL;
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ sws_freeContext(img_convert_ctx);
+ img_convert_ctx = NULL;
+#else
+ ret = img_convert ((AVPicture *)pFrameRGB, PIX_FMT_RGB24, (AVPicture*)pFrame, pVideoCodecCtx->pix_fmt, *width, *height);
+ if ( ret < 0 ) {
+ debug_error ("failed to convet image\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+#endif
+
+ }
+ else
+ {
+ debug_error("Not Found Proper Frame[%d][%d]", frameFinished, find);
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ if (pFrame) av_free (pFrame);
+ if (pFrameRGB) av_free (pFrameRGB);
+ if (pVideoCodecCtx) avcodec_close(pVideoCodecCtx);
+ /* Close video file */
+ if (pFormatCtx) avformat_close_input(&pFormatCtx);
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ if (*frame) { mmfile_free (*frame); *frame = NULL; }
+ if (pFrame) av_free (pFrame);
+ if (pFrameRGB) av_free (pFrameRGB);
+ if (pVideoCodecCtx) avcodec_close (pVideoCodecCtx);
+ /* Close video file */
+ if (pFormatCtx) avformat_close_input(&pFormatCtx);
+
+ return ret;
+ }
diff --git a/formats/ffmpeg/mm_file_format_imelody.c b/formats/ffmpeg/mm_file_format_imelody.c
new file mode 100755
index 0000000..5baefbd
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_imelody.c
@@ -0,0 +1,1699 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h> /*memcmp*/
+#include <stdlib.h> /*malloc*/
+
+#include "mm_debug.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_private.h"
+#include "mm_file_format_imelody.h"
+#include "mm_file_format_midi.h"
+
+/**
+ * Define
+ */
+#define AV_MIDI_COUNT_MAX 1600
+#define AV_MIDI_NOTE_MAX 256
+#define AV_MIDI_VOL_MAX 250
+#define MIDI_LIMIT 127
+#define MIDI_MAX 255
+
+#define VOL_INTERVAL 12
+
+#define MIDI_HEADER_LENGTH 52
+
+static unsigned char midiData[AV_MIDI_COUNT_MAX] ;
+static unsigned char midiHeader[MIDI_HEADER_LENGTH]= {0x4d,0x54,0x68,0x64,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x01,0x00,0x30,0x4d,0x54,
+ 0x72,0x6b,0x00,0x00,0x00,0x00,0x00,0xff,0x58,0x04,0x04,0x02,0x18,0x08,0x00,0xff,
+ 0x59,0x02,0x00,0x00,0x00,0xff,0x51,0x03,0x00,0x00,0x00,0x00,0xc0,0x00,0x00,0xb0,
+ 0x07,0x00,0x00,0x90};
+
+
+static unsigned char noteTotal[AV_MIDI_COUNT_MAX];
+static char octave[AV_MIDI_NOTE_MAX];
+static int durationSpec[AV_MIDI_NOTE_MAX];
+static int restSpec[AV_MIDI_NOTE_MAX];
+
+static struct {
+ char flat_sharp;
+ char note;
+ char duration;
+ char duration_specifier;
+ char rest;
+ char rest_specifier;
+ char vol;
+} Melody[AV_MIDI_NOTE_MAX];
+
+static struct {
+ int note;
+ int duration_on;
+ int duration_off;
+} noteData[AV_MIDI_NOTE_MAX];
+
+/*imelody key string (to validatation check)*/
+static const char *g_imy_key_str [] = {
+ "BEGIN:IMELODY",
+ "VERSION:",
+ "FORMAT:",
+ "MELODY:",
+ "END:IMELODY",
+};
+
+
+static int __is_good_imelody (unsigned char *src, unsigned int size);
+static unsigned char* __get_load_memory (char *src, int *out_size);
+static unsigned char __AvMIDISetVolume(char* pMelodyBuf);
+static int __AvMIDISetBeat(char* pMelodyBuf);
+static char __AvMIDISetStyle(char* pMelodyBuf);
+static unsigned char* __AvConvertIMelody2MIDI(char* pMelodyBuf, unsigned int* pBufLen);
+static int __get_imelody_tag (const char *uriname, tMMFileImelodyTagInfo *tags);
+
+
+/* interface functions */
+int mmfile_format_read_stream_imy (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_imy (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_imy (MMFileFormatContext *formatContext);
+int mmfile_format_close_imy (MMFileFormatContext *formatContext);
+
+
+EXPORT_API
+int mmfile_format_open_imy (MMFileFormatContext *formatContext)
+{
+ int ret = 0;
+
+ if (!formatContext) {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->pre_checked == 0) {
+ ret = MMFileFormatIsValidIMY (formatContext->uriFileName);
+ if (ret == 0) {
+ debug_error("It is not imelody file\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+ }
+
+ formatContext->ReadStream = mmfile_format_read_stream_imy;
+ formatContext->ReadFrame = mmfile_format_read_frame_imy;
+ formatContext->ReadTag = mmfile_format_read_tag_imy;
+ formatContext->Close = mmfile_format_close_imy;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ formatContext->privateFormatData = NULL;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_stream_imy (MMFileFormatContext *formatContext)
+{
+ MIDI_INFO_SIMPLE *info = NULL;
+ MMFileFormatStream *audioStream = NULL;
+
+ unsigned char *imy = NULL;
+ int imy_size = 0;
+ unsigned char *midi = NULL;
+ unsigned int midi_size = 0;
+ char src2[MMFILE_URI_MAX_LEN];
+
+ int ret = 0;
+
+ if (!formatContext) {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ /*convert iMelody to Midi*/
+ imy = __get_load_memory (formatContext->uriFileName, &imy_size);
+ if (!imy) {
+ debug_error ("failed to load memory.\n");
+ goto exception;
+ }
+ ret = __is_good_imelody (imy, imy_size);
+ if (ret != MMFILE_FORMAT_SUCCESS) {
+ debug_error ("it's broken file.\n");
+ goto exception;
+ }
+ midi = __AvConvertIMelody2MIDI ((char *)imy, &midi_size);
+ if (!midi) {
+ debug_error ("failed to convert.");
+ goto exception;
+ }
+
+ /*make uri*/
+ memset (src2, 0x00, MMFILE_URI_MAX_LEN);
+ sprintf (src2, "%s%u:%u", MMFILE_MEM_URI, (unsigned int)midi, midi_size);
+
+ /*get infomation*/
+ info = mmfile_format_get_midi_infomation (src2);
+ if (!info) {
+ debug_error ("failed to get infomation");
+ goto exception;
+ }
+
+ formatContext->duration = info->duration;
+ formatContext->videoStreamId = -1;
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = info->track_num;
+ formatContext->nbStreams = 1;
+
+
+ audioStream = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == audioStream) {
+ debug_error ("error: mmfile_malloc audiostream\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ audioStream->streamType = MMFILE_AUDIO_STREAM;
+ audioStream->codecId = MM_AUDIO_CODEC_IMELODY;
+ audioStream->bitRate = 0;
+ audioStream->framePerSec = 0;
+ audioStream->width = 0;
+ audioStream->height = 0;
+ audioStream->nbChannel = 1;
+ audioStream->samplePerSec = 0;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
+
+ #ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+ #endif
+
+ mmfile_free (imy);
+ mmfile_free (midi);
+ mmfile_format_free_midi_infomation (info);
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ mmfile_free (imy);
+ mmfile_free (midi);
+ mmfile_format_free_midi_infomation (info);
+ mmfile_free (audioStream);
+ return MMFILE_FORMAT_FAIL;
+}
+
+EXPORT_API
+int mmfile_format_read_frame_imy (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_tag_imy (MMFileFormatContext *formatContext)
+{
+ tMMFileImelodyTagInfo taginfo = {0,};
+ unsigned int tag_len;
+ unsigned int cnv_len;
+ const char *locale = MMFileUtilGetLocale (NULL);
+
+ if (!formatContext) {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ __get_imelody_tag (formatContext->uriFileName, &taginfo);
+
+ /**
+ * UTF8 convert
+ */
+ if (taginfo.title) {
+ tag_len = strlen (taginfo.title);
+ cnv_len = 0;
+ formatContext->title = mmfile_string_convert ((const char*)taginfo.title,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+
+ if (formatContext->title == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->title = mmfile_strdup (taginfo.title);
+ }
+ mmfile_free (taginfo.title);
+ }
+
+ if (taginfo.composer) {
+ tag_len = strlen (taginfo.composer);
+ cnv_len = 0;
+ formatContext->composer = mmfile_string_convert ((const char*)taginfo.composer,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+ if (formatContext->composer == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->composer = mmfile_strdup (taginfo.composer);
+ }
+ mmfile_free (taginfo.composer);
+ }
+
+ if (taginfo.comment) {
+ tag_len = strlen (taginfo.comment);
+ cnv_len = 0;
+ formatContext->comment = mmfile_string_convert ((const char*)taginfo.comment,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+ if (formatContext->comment == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->comment = mmfile_strdup (taginfo.comment);
+ }
+ mmfile_free (taginfo.comment);
+ }
+
+ if (taginfo.copyright) {
+ tag_len = strlen (taginfo.copyright);
+ cnv_len = 0;
+ formatContext->copyright = mmfile_string_convert ((const char*)taginfo.copyright,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+ if (formatContext->copyright == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->copyright = mmfile_strdup (taginfo.copyright);
+ }
+ mmfile_free (taginfo.copyright);
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_close_imy (MMFileFormatContext *formatContext)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+static int __get_imelody_tag (const char *uriname, tMMFileImelodyTagInfo *tags)
+{
+#define _MMFILE_IMY_TAG_BUFFER_LENGTH 512
+#define _MMFILE_IMY_HEADER_LENGTH 20
+#define _MMFILE_IMY_KEY_BUFFER_LENGTH 20
+#define _MMFILE_IMY_VALUE_BUFFER_LENGTH 128
+
+ MMFileIOHandle *fp = NULL;
+ unsigned char buffer[_MMFILE_IMY_TAG_BUFFER_LENGTH] = {0,};
+ int readed = 0;
+ long long filesize = 0;
+ unsigned int startoffset = 0;
+ unsigned int endoffset = 0;
+ unsigned int i = 0, j = 0;
+ char imy_key_buffer[_MMFILE_IMY_KEY_BUFFER_LENGTH] = {0,};
+ unsigned int imy_key_buffer_index = 0;
+ char imy_value_buffer[_MMFILE_IMY_VALUE_BUFFER_LENGTH] = {0,};
+ unsigned int imy_value_buffer_index = 0;
+ int isKeyBuffer = 1;
+ int isDone = 0;
+
+ int ret = MMFILE_FORMAT_FAIL;
+
+ if (!uriname || !tags)
+ {
+ debug_error("uriname or tags is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ ret = mmfile_open (&fp, uriname, MMFILE_RDONLY);
+ if (ret == MMFILE_UTIL_FAIL)
+ {
+ debug_error ( "open failed.\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ mmfile_seek (fp, 0, MMFILE_SEEK_END);
+ filesize = mmfile_tell (fp);
+ mmfile_seek (fp, 0, MMFILE_SEEK_SET);
+
+ if (filesize < _MMFILE_IMY_HEADER_LENGTH)
+ {
+ debug_error ( "header is too small.\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exit;
+ }
+
+ /* set begin and end point at the file */
+ startoffset = 0;
+ endoffset = filesize;
+
+ i = startoffset;
+ isKeyBuffer = 1;
+ while (i < endoffset)
+ {
+ mmfile_seek (fp, i, MMFILE_SEEK_SET);
+ readed = mmfile_read (fp, buffer, _MMFILE_IMY_TAG_BUFFER_LENGTH);
+ if (readed < 0)
+ {
+ debug_error ( "read error. size = %d. Maybe end of file.\n", readed);
+ ret = 0;
+ break;
+ }
+
+ j = 0;
+ while (j < readed)
+ {
+ if ( *(buffer+j) == 0x3a )
+ {
+ isKeyBuffer = 0;
+ }
+ else if ( *(buffer+j) == 0x0d )
+ {
+ }
+ else if ( *(buffer+j) == 0x0a )
+ {
+ isKeyBuffer = 1;
+ isDone = 1;
+ }
+ else
+ {
+ if (isKeyBuffer)
+ {
+ if (imy_key_buffer_index < _MMFILE_IMY_KEY_BUFFER_LENGTH)
+ {
+ imy_key_buffer[imy_key_buffer_index++] = *(buffer+j);
+ }
+
+ }
+ else
+ {
+ if (imy_value_buffer_index < _MMFILE_IMY_VALUE_BUFFER_LENGTH)
+ {
+ imy_value_buffer[imy_value_buffer_index++] = *(buffer+j);
+ }
+ }
+ }
+
+ if (isDone)
+ {
+ if (!strncmp (imy_key_buffer, "NAME", 4))
+ {
+ tags->title = mmfile_strdup (imy_value_buffer);
+ }
+ else if (!strncmp (imy_key_buffer, "COMPOSER", 8))
+ {
+ tags->composer = mmfile_strdup (imy_value_buffer);
+ }
+ else if (!strncmp (imy_key_buffer, "COPYRIGHT", 9))
+ {
+ tags->copyright = mmfile_strdup (imy_value_buffer);
+ }
+
+ memset (imy_key_buffer, 0x00, _MMFILE_IMY_KEY_BUFFER_LENGTH);
+ memset (imy_value_buffer, 0x00, _MMFILE_IMY_VALUE_BUFFER_LENGTH);
+ imy_key_buffer_index = 0;
+ imy_value_buffer_index = 0;
+ isDone = 0;
+ }
+
+ j++;
+ }
+
+ memset (buffer, 0x00, _MMFILE_IMY_TAG_BUFFER_LENGTH);
+
+ i = i + j;
+ }
+
+exit:
+ mmfile_close (fp);
+ return ret;
+}
+
+static unsigned char *
+__get_load_memory (char *src, int *out_size)
+{
+ unsigned char *buf = NULL;
+ MMFileIOHandle *fp = NULL;
+ long long src_size = 0L;
+ int readed =0;
+ int ret = 0;
+
+ /*open*/
+ ret = mmfile_open (&fp, src, MMFILE_RDONLY);
+ if (ret == MMFILE_UTIL_FAIL) {
+ debug_error ( "open failed.\n");
+ return NULL;
+ }
+
+ /*get file size*/
+ mmfile_seek (fp, 0L, MMFILE_SEEK_END);
+ src_size = mmfile_tell (fp);
+ mmfile_seek (fp, 0L, MMFILE_SEEK_SET);
+
+ if (src_size <= 0) {
+ debug_error ("failed to get file size.\n");
+ goto failed;
+ }
+
+ /*alloc read buffer*/
+ if ((buf = mmfile_malloc (src_size)) == NULL) {
+ debug_error ( "memory allocation failed.\n");
+ goto failed;
+ }
+
+ /*read data*/
+ if ((readed = mmfile_read (fp, buf, src_size) ) != src_size) {
+ debug_error ( "read error. size = %d\n", readed);
+ goto failed;
+ }
+
+ *out_size = (int)src_size;
+ mmfile_close (fp);
+
+ return buf;
+
+failed:
+ if (buf) mmfile_free (buf);
+ if (fp) mmfile_close (fp);
+ return NULL;
+}
+
+
+static int
+__is_good_imelody (unsigned char *src, unsigned int size)
+{
+ int i, j;
+ int key_len;
+ int is_found;
+ unsigned char *p;
+ int num = sizeof (g_imy_key_str) / sizeof (g_imy_key_str[0]);
+
+ for (i = 0; i < num; i++) {
+ key_len = strlen (g_imy_key_str[i]);
+ p = src;
+ is_found = 0;
+ for (j = 0; j <= size - key_len; j++, p++) {
+ if (memcmp (g_imy_key_str[i], p, key_len) == 0) {
+ is_found = 1;
+ break;
+ }
+ }
+ if (is_found) continue; else return MMFILE_FORMAT_FAIL;
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+static unsigned char*
+__AvConvertIMelody2MIDI(char* pMelodyBuf, unsigned int* pBufLen)
+{
+ unsigned char* pConvertBuf;
+ char* pStart;
+ char* pMelodyStart;
+ char noteBase[6];
+ int octaveCount;
+ int octaveValue;
+ int count;
+ int noteCount = 0;
+ int MelodyCount;
+ int number;
+ int numberCount;
+ char style = '0';
+ int tempoData[3];
+ int tempoValue;
+ int trackSize;
+ int repeat = 0;
+ int repeatCount = 0;
+ char vol = '%';
+ int volInterval = 0;
+
+ for(count = 0;count < AV_MIDI_NOTE_MAX;count++)
+ {
+ restSpec[count] = 0;
+ durationSpec[count] = 0;
+ }
+
+ for(octaveCount = 0;octaveCount < AV_MIDI_NOTE_MAX;octaveCount++)
+ octave[octaveCount] = '%';
+
+ for(MelodyCount = 0;MelodyCount < AV_MIDI_NOTE_MAX;MelodyCount++)
+ {
+ Melody[MelodyCount].flat_sharp = '%';
+ Melody[MelodyCount].note = '%';
+ Melody[MelodyCount].duration = '%';
+ Melody[MelodyCount].duration_specifier = '%';
+ Melody[MelodyCount].rest = '%';
+ Melody[MelodyCount].rest_specifier = '%';
+ Melody[MelodyCount].vol = '%';
+ }
+
+ for(MelodyCount = 0;MelodyCount < AV_MIDI_NOTE_MAX;MelodyCount++)
+ {
+ noteData[MelodyCount].note = 0;
+ noteData[MelodyCount].duration_on = 0;
+ noteData[MelodyCount].duration_off = 0;
+ }
+
+
+ memset(midiData, 0, sizeof(midiData));
+ memcpy(midiData, midiHeader, MIDI_HEADER_LENGTH);
+
+ pStart = pMelodyBuf;
+
+ midiData[49] = __AvMIDISetVolume(pMelodyBuf);
+
+ pMelodyBuf = pStart;
+
+ tempoValue = __AvMIDISetBeat(pMelodyBuf);
+
+ for(number = 0;tempoValue != 0;number++)
+ {
+ tempoData[0] = tempoValue % 16;
+ tempoValue = tempoValue / 16;
+
+ tempoData[1] = tempoValue % 16;
+ tempoValue = tempoValue / 16;
+
+ tempoData[2] = tempoData[0] + tempoData[1] * 16;
+
+ midiData[42-number] = tempoData[2];
+ }
+
+ pMelodyBuf = pStart;
+
+ while(!(*pMelodyBuf == '@' || (*pMelodyBuf == 'E' && *(pMelodyBuf+2) == 'D')))
+ pMelodyBuf++;
+
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '1' && *pMelodyBuf <= '9')
+ {
+ repeat = *pMelodyBuf - '0';
+ pMelodyBuf++;
+
+ }
+
+ repeat = 0;
+
+ pMelodyBuf = pStart;
+
+ pMelodyBuf = pMelodyBuf + 42;
+
+ while(!(*pMelodyBuf == 'M' && *(pMelodyBuf+5) == 'Y' && *(pMelodyBuf+6) == ':')) //2007-02-28 AVMS_Sound:k2bogus - UMTS200073205;imy play, [MELODY:] extract fix
+ pMelodyBuf++;
+
+ pMelodyBuf = pMelodyBuf + 6;
+
+ pMelodyStart = pMelodyBuf;
+
+ /**@note if newline detected, stop reading
+ * why? mobileBAE player stopped at newline.
+ * 2009/08/12
+ */
+ while(!((*pMelodyBuf == 'E' && *(pMelodyBuf+2) == 'D') || (*pMelodyBuf == '\n')))
+ {
+ if(noteCount>=AV_MIDI_NOTE_MAX)
+ {
+ debug_warning ("__AvConvertIMelody2MIDI : noteCount>=AV_MIDI_NOTE_MAX\n");
+ break;
+ }
+
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '*')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '8')
+ octave[noteCount] = *pMelodyBuf;
+ }
+
+ if(*pMelodyBuf == '#' || *pMelodyBuf == '&')
+ Melody[noteCount].flat_sharp = *pMelodyBuf;
+
+ if(*pMelodyBuf == 'r')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '5')
+ {
+ Melody[noteCount].rest = *pMelodyBuf;
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '.' || *pMelodyBuf == ':' || *pMelodyBuf == ';')
+ Melody[noteCount].rest_specifier = *pMelodyBuf;
+ }
+ }
+
+ if(*pMelodyBuf == 'V')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '+' || *pMelodyBuf == '-')
+ Melody[noteCount].vol = *pMelodyBuf;
+ }
+
+ if(*pMelodyBuf >= 'a' && *pMelodyBuf <= 'g')
+ {
+ Melody[noteCount].note = *pMelodyBuf;
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '5')
+ {
+ Melody[noteCount].duration = *pMelodyBuf;
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '.' || *pMelodyBuf == ':' || *pMelodyBuf == ';')
+ Melody[noteCount].duration_specifier = *pMelodyBuf;
+
+ else
+ pMelodyBuf--;
+
+ noteCount++;
+ }
+ }
+ }
+
+ for(octaveCount = 1;octaveCount < noteCount;octaveCount++)
+ {
+ if(octave[octaveCount] == '%')
+ octave[octaveCount] = octave[octaveCount-1];
+ }
+
+ for(number = 0;number < noteCount;number++)
+ {
+ if(octave[0] == '%' && octave[number] == '%')
+ octaveValue = 4;
+
+ else
+ octaveValue = octave[number] - '0';
+
+ octaveValue = octaveValue * 12;
+
+ if(Melody[number].flat_sharp == '#')
+ {
+ switch(Melody[number].note)
+ {
+ case 'c': noteData[number].note = octaveValue + 1;
+ break;
+ case 'd': noteData[number].note = octaveValue + 3;
+ break;
+ case 'f': noteData[number].note = octaveValue + 6;
+ break;
+ case 'g': noteData[number].note = octaveValue + 8;
+ break;
+ case 'a': noteData[number].note = octaveValue + 10;
+ }
+ }
+
+ else
+ if(Melody[number].flat_sharp == '&')
+ {
+ switch(Melody[number].note)
+ {
+ case 'd': noteData[number].note = octaveValue + 1;
+ break;
+ case 'e': noteData[number].note = octaveValue + 3;
+ break;
+ case 'g': noteData[number].note = octaveValue + 6;
+ break;
+ case 'a': noteData[number].note = octaveValue + 8;
+ break;
+ case 'b': noteData[number].note = octaveValue + 10;
+ }
+ }
+
+ else
+ {
+ switch(Melody[number].note)
+ {
+ case 'c': noteData[number].note = octaveValue;
+ break;
+ case 'd': noteData[number].note = octaveValue + 2;
+ break;
+ case 'e': noteData[number].note = octaveValue + 4;
+ break;
+ case 'f': noteData[number].note = octaveValue + 5;
+ break;
+ case 'g': noteData[number].note = octaveValue + 7;
+ break;
+ case 'a': noteData[number].note = octaveValue + 9;
+ break;
+ case 'b': noteData[number].note = octaveValue + 11;
+ }
+ }
+ }
+
+ pMelodyBuf = pMelodyStart;
+
+ style = __AvMIDISetStyle(pMelodyBuf);
+
+ for(number = 0;number < noteCount;number++)
+ {
+ if(style == '0')
+ {
+ switch(Melody[number].duration)
+ {
+ case '0': noteData[number].duration_on = 183;
+ noteData[number].duration_off = 9;
+ break;
+ case '1': noteData[number].duration_on = 91;
+ noteData[number].duration_off = 5;
+ break;
+ case '2': noteData[number].duration_on = 46;
+ noteData[number].duration_off = 2;
+ break;
+ case '3': noteData[number].duration_on = 23;
+ noteData[number].duration_off = 1;
+ break;
+ case '4': noteData[number].duration_on = 11;
+ noteData[number].duration_off = 1;
+ break;
+ case '5': noteData[number].duration_on = 5;
+ noteData[number].duration_off = 1;
+ }
+ }
+
+ else
+ if(style == '1')
+ {
+ switch(Melody[number].duration)
+ {
+ case '0': noteData[number].duration_on = 192;
+ noteData[number].duration_off = 0;
+ break;
+ case '1': noteData[number].duration_on = 96;
+ noteData[number].duration_off = 0;
+ break;
+ case '2': noteData[number].duration_on = 48;
+ noteData[number].duration_off = 0;
+ break;
+ case '3': noteData[number].duration_on = 24;
+ noteData[number].duration_off = 0;
+ break;
+ case '4': noteData[number].duration_on = 12;
+ noteData[number].duration_off = 0;
+ break;
+ case '5': noteData[number].duration_on = 6;
+ noteData[number].duration_off = 0;
+ }
+ }
+
+ else
+ {
+ switch(Melody[number].duration)
+ {
+ case '0': noteData[number].duration_on = 96;
+ noteData[number].duration_off = 96;
+ break;
+ case '1': noteData[number].duration_on = 48;
+ noteData[number].duration_off = 48;
+ break;
+ case '2': noteData[number].duration_on = 24;
+ noteData[number].duration_off = 24;
+ break;
+ case '3': noteData[number].duration_on = 12;
+ noteData[number].duration_off = 12;
+ break;
+ case '4': noteData[number].duration_on = 6;
+ noteData[number].duration_off = 6;
+ break;
+ case '5': noteData[number].duration_on = 3;
+ noteData[number].duration_off = 3;
+ }
+ }
+
+ switch(Melody[number].duration)
+ {
+ case '0': durationSpec[number] = 192;
+ break;
+ case '1': durationSpec[number] = 96;
+ break;
+ case '2': durationSpec[number] = 48;
+ break;
+ case '3': durationSpec[number] = 24;
+ break;
+ case '4': durationSpec[number] = 12;
+ break;
+ case '5': durationSpec[number] = 6;
+ }
+
+ if(Melody[number].duration_specifier != '%')
+ {
+ switch(Melody[number].duration_specifier)
+ {
+ case '.': noteData[number].duration_on += (durationSpec[number] / 2);
+ break;
+ case ':': noteData[number].duration_on += durationSpec[number];
+ break;
+ case ';': noteData[number].duration_on -= (durationSpec[number] / 3);
+ }
+
+ if(noteData[number].duration_on > MIDI_MAX)
+ noteData[number].duration_on = MIDI_LIMIT;
+ }
+ }
+
+ for(number = 1;number < noteCount;number++)
+ {
+ if(Melody[number].rest >= '0' && Melody[number].rest <= '5')
+ {
+ switch(Melody[number].rest)
+ {
+ case '0': noteData[number-1].duration_off += 192;
+ restSpec[number] = 192;
+ break;
+ case '1': noteData[number-1].duration_off += 96;
+ restSpec[number] = 96;
+ break;
+ case '2': noteData[number-1].duration_off += 48;
+ restSpec[number] = 48;
+ break;
+ case '3': noteData[number-1].duration_off += 24;
+ restSpec[number] = 24;
+ break;
+ case '4': noteData[number-1].duration_off += 12;
+ restSpec[number] = 12;
+ break;
+ case '5': noteData[number-1].duration_off += 6;
+ restSpec[number] = 6;
+ }
+
+ if(noteData[number-1].duration_off > MIDI_MAX && Melody[number].rest_specifier == '%')
+ noteData[number-1].duration_off = MIDI_LIMIT;
+ }
+
+ if(Melody[number].rest_specifier != '%')
+ {
+ switch(Melody[number].rest_specifier)
+ {
+ case '.': noteData[number-1].duration_off += (restSpec[number] / 2);
+ break;
+ case ':': noteData[number-1].duration_off += restSpec[number];
+ break;
+ case ';': noteData[number-1].duration_off -= (restSpec[number] / 3);
+ }
+
+ if(noteData[number-1].duration_off > MIDI_MAX)
+ noteData[number-1].duration_off = MIDI_LIMIT;
+ }
+ }
+
+ if(Melody[0].rest >= '0' && Melody[0].rest <= '5')
+ {
+ switch(Melody[0].rest)
+ {
+ case '0': midiData[50] += 192;
+ restSpec[0] = 192;
+ break;
+ case '1': midiData[50] += 96;
+ restSpec[0] = 96;
+ break;
+ case '2': midiData[50] += 48;
+ restSpec[0] = 48;
+ break;
+ case '3': midiData[50] += 24;
+ restSpec[0] = 24;
+ break;
+ case '4': midiData[50] += 12;
+ restSpec[0] = 12;
+ break;
+ case '5': midiData[50] += 6;
+ restSpec[0] = 6;
+ }
+
+ if(Melody[0].rest_specifier != '%')
+ {
+ switch(Melody[0].rest_specifier)
+ {
+ case '.': midiData[50] += (restSpec[0] / 2);
+ break;
+ case ':': midiData[50] += restSpec[0];
+ break;
+ case ';': midiData[50] -= (restSpec[0] / 3);
+ }
+ }
+
+ if(midiData[50] > MIDI_LIMIT)
+ midiData[50] = MIDI_LIMIT;
+
+ if(Melody[0].rest == '0')
+ midiData[50] = MIDI_LIMIT;
+ }
+
+ for(number = 0;number < noteCount;number++)
+ {
+ noteBase[0] = noteData[number].note;
+ noteBase[2] = noteData[number].duration_on;
+ noteBase[3] = noteData[number].note;
+ noteBase[5] = noteData[number].duration_off;
+
+ noteTotal[6*number] = noteBase[0];
+ noteTotal[6*number+2] = noteBase[2];
+ noteTotal[6*number+3] = noteBase[3];
+ noteTotal[6*number+5] = noteBase[5];
+ noteTotal[6*number+4] = 0;
+
+ if(noteTotal[6*number+2] > MIDI_LIMIT)
+ noteTotal[6*number+2] = MIDI_LIMIT;
+
+ if(noteTotal[6*number+5] > MIDI_LIMIT)
+ noteTotal[6*number+5] = MIDI_LIMIT;
+ }
+
+ for(number = 1;number < noteCount;number++)
+ {
+ noteTotal[1] = 84;
+
+ if(Melody[0].vol == '+')
+ noteTotal[1] = 84 + VOL_INTERVAL;
+
+ if(Melody[0].vol == '-')
+ noteTotal[1] = 84 - VOL_INTERVAL;
+
+ switch(Melody[number].vol)
+ {
+ case '+': noteTotal[6*number+1] = noteTotal[6*(number-1)+1] + VOL_INTERVAL;
+ break;
+ case '-': noteTotal[6*number+1] = noteTotal[6*(number-1)+1] - VOL_INTERVAL;
+ }
+
+ if(noteTotal[6*number+1] > MIDI_LIMIT)
+ noteTotal[6*number+1] = MIDI_LIMIT;
+
+ if((noteTotal[6*(number-1)+1] == 0 || noteTotal[6*(number-1)+1] == 7) && Melody[number].vol == '-')
+ noteTotal[6*number+1] = 0;
+
+ if(Melody[number].vol == '%')
+ noteTotal[6*number+1] = noteTotal[6*(number-1)+1];
+ }
+
+ for(number = 0;number < 6 * noteCount;number++)
+ midiData[52+number] = noteTotal[number];
+
+ for(number = 6 * noteCount;number < 6 * noteCount * (repeat + 1);number++)
+ {
+ noteTotal[number] = noteTotal[repeatCount];
+ midiData[52+number] = noteTotal[number];
+ repeatCount++;
+
+ if(repeatCount == 6 * noteCount)
+ repeatCount = 0;
+ }
+
+ if(vol != '%')
+ {
+ switch(vol)
+ {
+ case '+': midiData[52+(6*noteCount+1)] = midiData[52+(6*(noteCount-1)+1)] + VOL_INTERVAL;
+ break;
+ case '-': midiData[52+(6*noteCount+1)] = midiData[52+(6*(noteCount-1)+1)] - VOL_INTERVAL;
+ }
+
+ if(Melody[0].vol != '%')
+ {
+ switch(Melody[0].vol)
+ {
+ case '+': midiData[52+(6*noteCount+1)] += VOL_INTERVAL;
+ break;
+ case '-': midiData[52+(6*noteCount+1)] -= VOL_INTERVAL;
+ }
+ }
+
+ if(midiData[52+(6*noteCount+1)] > MIDI_LIMIT)
+ midiData[52+(6*noteCount+1)] = MIDI_LIMIT;
+
+ if((midiData[52+(6*(noteCount-1)+1)] == 0 || midiData[52+(6*(noteCount-1)+1)] == 7) && vol == '-')
+ {
+ midiData[52+(6*noteCount+1)] = 0;
+
+ if(Melody[0].vol == '+')
+ midiData[52+(6*noteCount+1)] = 12;
+ }
+
+ if((midiData[52+(6*(noteCount-1)+1)] == 12 || midiData[52+(6*(noteCount-1)+1)] == 19) && vol == '-' && Melody[0].vol == '-')
+ midiData[52+(6*noteCount+1)] = 0;
+ }
+
+ else
+ if(Melody[0].vol != '%' && vol == '%' && repeat != 0)
+ {
+ switch(Melody[0].vol)
+ {
+ case '+': midiData[52+(6*noteCount+1)] = midiData[52+(6*(noteCount-1)+1)] + VOL_INTERVAL;
+ break;
+ case '-': midiData[52+(6*noteCount+1)] = midiData[52+(6*(noteCount-1)+1)] - VOL_INTERVAL;
+ }
+
+ if(midiData[52+(6*noteCount+1)] > MIDI_LIMIT)
+ midiData[52+(6*noteCount+1)] = MIDI_LIMIT;
+
+ if((midiData[52+(6*(noteCount-1)+1)] == 0 || midiData[52+(6*(noteCount-1)+1)] == 7) && Melody[0].vol == '-')
+ midiData[52+(6*noteCount+1)] = 0;
+ }
+
+ else
+ if(Melody[0].vol == '%' && vol == '%' && repeat != 0)
+ midiData[52+(6*noteCount+1)] = midiData[52+(6*(noteCount-1)+1)];
+
+ volInterval = midiData[52+(6*noteCount+1)] - midiData[53];
+
+ for(repeatCount = 0;repeatCount < repeat;repeatCount++)
+ for(number = 6 * noteCount * repeatCount + 1;number < 6 * noteCount * (repeatCount + 1);number = number + 6)
+ {
+ midiData[52+(number+6*noteCount)] = midiData[52+number] + volInterval;
+
+ if(midiData[52+number] + volInterval > MIDI_LIMIT)
+ midiData[52+(number+6*noteCount)] = MIDI_LIMIT;
+
+ if(midiData[52+number] < volInterval * (-1))
+ midiData[52+(number+6*noteCount)] = 0;
+ }
+
+ for(number = 1;number < 6 * noteCount * (repeat + 1);number = number + 6)
+ {
+ if(midiData[52+number] > MIDI_LIMIT)
+ midiData[52+number] = MIDI_LIMIT;
+ }
+
+ pMelodyBuf = pMelodyStart;
+ count = noteCount;
+
+ if(repeat != 0)
+ {
+ while(*pMelodyBuf != '@')
+ pMelodyBuf++;
+
+ pMelodyBuf++;
+
+ if(vol !='%')
+ pMelodyBuf = pMelodyBuf + 2;
+
+ while(!(*pMelodyBuf == '*' || *pMelodyBuf == '#' || *pMelodyBuf == '&' || *pMelodyBuf == 'r' || *pMelodyBuf == 'V' || *pMelodyBuf == 'E' || (*pMelodyBuf >= 'a' && *pMelodyBuf <= 'g')))
+ pMelodyBuf++;
+ }
+
+ if(*pMelodyBuf != 'E' && *pMelodyBuf != ':')
+ {
+ pMelodyBuf--;
+
+ while(*pMelodyBuf != 'E')
+ {
+ if(noteCount>=AV_MIDI_NOTE_MAX)
+ {
+ debug_warning ("__AvConvertIMelody2MIDI : noteCount>=AV_MIDI_NOTE_MAX\n");
+ break;
+ }
+
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '*')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '8')
+ octave[noteCount] = *pMelodyBuf;
+ }
+
+ if(*pMelodyBuf == '#' || *pMelodyBuf == '&')
+ Melody[noteCount].flat_sharp = *pMelodyBuf;
+
+ if(*pMelodyBuf == 'r')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '5')
+ {
+ Melody[noteCount].rest = *pMelodyBuf;
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '.' || *pMelodyBuf == ':' || *pMelodyBuf == ';')
+ Melody[noteCount].rest_specifier = *pMelodyBuf;
+ }
+ }
+
+ if(*pMelodyBuf == 'V')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '+' || *pMelodyBuf == '-')
+ Melody[noteCount].vol = *pMelodyBuf;
+ }
+
+ if(*pMelodyBuf >= 'a' && *pMelodyBuf <= 'g')
+ {
+ Melody[noteCount].note = *pMelodyBuf;
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '5')
+ {
+ Melody[noteCount].duration = *pMelodyBuf;
+ pMelodyBuf++;
+
+ if(*pMelodyBuf == '.' || *pMelodyBuf == ':' || *pMelodyBuf == ';')
+ Melody[noteCount].duration_specifier = *pMelodyBuf;
+
+ else
+ pMelodyBuf--;
+
+ noteCount++;
+ }
+ }
+ }
+
+ for(octaveCount = count;octaveCount < noteCount;octaveCount++)
+ {
+ if(octave[octaveCount] == '%')
+ octave[octaveCount] = octave[octaveCount-1];
+ }
+
+ for(number = count;number < noteCount;number++)
+ {
+ octaveValue = octave[number] - '0';
+
+ octaveValue = octaveValue * 12;
+
+ if(Melody[number].flat_sharp == '#')
+ {
+ switch(Melody[number].note)
+ {
+ case 'c': noteData[number].note = octaveValue + 1;
+ break;
+ case 'd': noteData[number].note = octaveValue + 3;
+ break;
+ case 'f': noteData[number].note = octaveValue + 6;
+ break;
+ case 'g': noteData[number].note = octaveValue + 8;
+ break;
+ case 'a': noteData[number].note = octaveValue + 10;
+ }
+ }
+
+ else
+ if(Melody[number].flat_sharp == '&')
+ {
+ switch(Melody[number].note)
+ {
+ case 'd': noteData[number].note = octaveValue + 1;
+ break;
+ case 'e': noteData[number].note = octaveValue + 3;
+ break;
+ case 'g': noteData[number].note = octaveValue + 6;
+ break;
+ case 'a': noteData[number].note = octaveValue + 8;
+ break;
+ case 'b': noteData[number].note = octaveValue + 10;
+ }
+ }
+
+ else
+ {
+ switch(Melody[number].note)
+ {
+ case 'c': noteData[number].note = octaveValue;
+ break;
+ case 'd': noteData[number].note = octaveValue + 2;
+ break;
+ case 'e': noteData[number].note = octaveValue + 4;
+ break;
+ case 'f': noteData[number].note = octaveValue + 5;
+ break;
+ case 'g': noteData[number].note = octaveValue + 7;
+ break;
+ case 'a': noteData[number].note = octaveValue + 9;
+ break;
+ case 'b': noteData[number].note = octaveValue + 11;
+ }
+ }
+
+
+ if(style == '0')
+ {
+ switch(Melody[number].duration)
+ {
+ case '0': noteData[number].duration_on = 183;
+ noteData[number].duration_off = 9;
+ break;
+ case '1': noteData[number].duration_on = 91;
+ noteData[number].duration_off = 5;
+ break;
+ case '2': noteData[number].duration_on = 46;
+ noteData[number].duration_off = 2;
+ break;
+ case '3': noteData[number].duration_on = 23;
+ noteData[number].duration_off = 1;
+ break;
+ case '4': noteData[number].duration_on = 11;
+ noteData[number].duration_off = 1;
+ break;
+ case '5': noteData[number].duration_on = 5;
+ noteData[number].duration_off = 1;
+ }
+ }
+
+ else
+ if(style == '1')
+ {
+ switch(Melody[number].duration)
+ {
+ case '0': noteData[number].duration_on = 192;
+ noteData[number].duration_off = 0;
+ break;
+ case '1': noteData[number].duration_on = 96;
+ noteData[number].duration_off = 0;
+ break;
+ case '2': noteData[number].duration_on = 48;
+ noteData[number].duration_off = 0;
+ break;
+ case '3': noteData[number].duration_on = 24;
+ noteData[number].duration_off = 0;
+ break;
+ case '4': noteData[number].duration_on = 12;
+ noteData[number].duration_off = 0;
+ break;
+ case '5': noteData[number].duration_on = 6;
+ noteData[number].duration_off = 0;
+ }
+ }
+
+ else
+ {
+ switch(Melody[number].duration)
+ {
+ case '0': noteData[number].duration_on = 96;
+ noteData[number].duration_off = 96;
+ break;
+ case '1': noteData[number].duration_on = 48;
+ noteData[number].duration_off = 48;
+ break;
+ case '2': noteData[number].duration_on = 24;
+ noteData[number].duration_off = 24;
+ break;
+ case '3': noteData[number].duration_on = 12;
+ noteData[number].duration_off = 12;
+ break;
+ case '4': noteData[number].duration_on = 6;
+ noteData[number].duration_off = 6;
+ break;
+ case '5': noteData[number].duration_on = 3;
+ noteData[number].duration_off = 3;
+ }
+ }
+
+ switch(Melody[number].duration)
+ {
+ case '0': durationSpec[number] = 192;
+ break;
+ case '1': durationSpec[number] = 96;
+ break;
+ case '2': durationSpec[number] = 48;
+ break;
+ case '3': durationSpec[number] = 24;
+ break;
+ case '4': durationSpec[number] = 12;
+ break;
+ case '5': durationSpec[number] = 6;
+ }
+
+ if(Melody[number].duration_specifier != '%')
+ {
+ switch(Melody[number].duration_specifier)
+ {
+ case '.': noteData[number].duration_on += (durationSpec[number] / 2);
+ break;
+ case ':': noteData[number].duration_on += durationSpec[number];
+ break;
+ case ';': noteData[number].duration_on -= (durationSpec[number] / 3);
+ }
+
+ if(noteData[number].duration_on > MIDI_MAX)
+ noteData[number].duration_on = MIDI_LIMIT;
+ }
+ }
+
+ for(number = count + 1;number < noteCount;number++)
+ {
+ if(Melody[number].rest >= '0' && Melody[number].rest <= '5')
+ {
+ switch(Melody[number].rest)
+ {
+ case '0': noteData[number-1].duration_off += 192;
+ restSpec[number] = 192;
+ break;
+ case '1': noteData[number-1].duration_off += 96;
+ restSpec[number] = 96;
+ break;
+ case '2': noteData[number-1].duration_off += 48;
+ restSpec[number] = 48;
+ break;
+ case '3': noteData[number-1].duration_off += 24;
+ restSpec[number] = 24;
+ break;
+ case '4': noteData[number-1].duration_off += 12;
+ restSpec[number] = 12;
+ break;
+ case '5': noteData[number-1].duration_off += 6;
+ restSpec[number] = 6;
+ }
+
+ if(noteData[number-1].duration_off > MIDI_MAX && Melody[number].rest_specifier == '%')
+ noteData[number-1].duration_off = MIDI_LIMIT;
+ }
+
+ if(Melody[number].rest_specifier != '%')
+ {
+ switch(Melody[number].rest_specifier)
+ {
+ case '.': noteData[number-1].duration_off += (restSpec[number] / 2);
+ break;
+ case ':': noteData[number-1].duration_off += restSpec[number];
+ break;
+ case ';': noteData[number-1].duration_off -= (restSpec[number] / 3);
+ }
+
+ if(noteData[number-1].duration_off > MIDI_MAX)
+ noteData[number-1].duration_off = MIDI_LIMIT;
+ }
+ }
+
+ if(Melody[count].rest >= '0' && Melody[count].rest <= '5')
+ {
+ switch(Melody[count].rest)
+ {
+ case '0': midiData[52+(6*count*(repeat+1)-1)] += 192;
+ restSpec[count] = 192;
+ break;
+ case '1': midiData[52+(6*count*(repeat+1)-1)] += 96;
+ restSpec[count] = 96;
+ break;
+ case '2': midiData[52+(6*count*(repeat+1)-1)] += 48;
+ restSpec[count] = 48;
+ break;
+ case '3': midiData[52+(6*count*(repeat+1)-1)] += 24;
+ restSpec[count] = 24;
+ break;
+ case '4': midiData[52+(6*count*(repeat+1)-1)] += 12;
+ restSpec[count] = 12;
+ break;
+ case '5': midiData[52+(6*count*(repeat+1)-1)] += 6;
+ restSpec[count] = 6;
+ }
+
+ if(Melody[count].rest_specifier != '%')
+ {
+ switch(Melody[count].rest_specifier)
+ {
+ case '.': midiData[52+(6*count*(repeat+1)-1)] += (restSpec[count] / 2);
+ break;
+ case ':': midiData[52+(6*count*(repeat+1)-1)] += restSpec[count];
+ break;
+ case ';': midiData[52+(6*count*(repeat+1)-1)] -= (restSpec[count] / 3);
+ }
+ }
+
+ if(midiData[52+(6*count*(repeat+1)-1)] > MIDI_LIMIT)
+ midiData[52+(6*count*(repeat+1)-1)] = MIDI_LIMIT;
+
+ if(Melody[count].rest == '0')
+ midiData[52+(6*count*(repeat+1)-1)] = MIDI_LIMIT;
+ }
+
+ for(number = count;number < noteCount;number++)
+ {
+ noteBase[0] = noteData[number].note;
+ noteBase[2] = noteData[number].duration_on;
+ noteBase[3] = noteData[number].note;
+ noteBase[5] = noteData[number].duration_off;
+
+ noteTotal[6*number] = noteBase[0];
+ noteTotal[6*number+2] = noteBase[2];
+ noteTotal[6*number+3] = noteBase[3];
+ noteTotal[6*number+5] = noteBase[5];
+ noteTotal[6*number+4] = 0;
+
+ if(noteTotal[6*number+2] > MIDI_LIMIT)
+ noteTotal[6*number+2] = MIDI_LIMIT;
+
+ if(noteTotal[6*number+5] > MIDI_LIMIT)
+ noteTotal[6*number+5] = MIDI_LIMIT;
+ }
+
+ for(number = count + 1;number < noteCount;number++)
+ {
+ noteTotal[6*count+1] = midiData[52+(6*count*(repeat+1)-5)];
+
+ if(Melody[count].vol == '+')
+ noteTotal[6*count+1] = noteTotal[6*count+1] + VOL_INTERVAL;
+
+ if(Melody[count].vol == '-' && (noteTotal[6*count+1] == 0 || noteTotal[6*count+1] == 7))
+ noteTotal[6*count+1] = 0;
+
+ if(Melody[count].vol == '-' && noteTotal[6*count+1] >= 12)
+ noteTotal[6*count+1] = noteTotal[6*count+1] - VOL_INTERVAL;
+
+ if(noteTotal[6*count+1] > MIDI_LIMIT)
+ noteTotal[6*count+1] = MIDI_LIMIT;
+
+ switch(Melody[number].vol)
+ {
+ case '+': noteTotal[6*number+1] = noteTotal[6*(number-1)+1] + VOL_INTERVAL;
+ break;
+ case '-': noteTotal[6*number+1] = noteTotal[6*(number-1)+1] - VOL_INTERVAL;
+ }
+
+ if(noteTotal[6*number+1] > MIDI_LIMIT)
+ noteTotal[6*number+1] = MIDI_LIMIT;
+
+ if((noteTotal[6*(number-1)+1] == 0 || noteTotal[6*(number-1)+1] == 7) && Melody[number].vol == '-')
+ noteTotal[6*number+1] = 0;
+
+ if(Melody[number].vol == '%')
+ noteTotal[6*number+1] = noteTotal[6*(number-1)+1];
+ }
+
+ numberCount = 6 * count;
+
+ for(number = 6 * count * (repeat + 1);number < 6 * (count * (repeat + 1) + (noteCount - count));number++)
+ {
+ midiData[52+number] = noteTotal[numberCount];
+ numberCount++;
+ }
+ }
+
+ noteTotal[6*(count*(repeat+1)+(noteCount-count))] = 0; //0x00
+ noteTotal[6*(count*(repeat+1)+(noteCount-count))+1] = MIDI_MAX; //0xff
+ noteTotal[6*(count*(repeat+1)+(noteCount-count))+2] = 47; //0x2f
+ noteTotal[6*(count*(repeat+1)+(noteCount-count))+3] = 0; //0x00
+
+ for(number = 6 * (count * (repeat + 1) + (noteCount - count));number <= 6 * (count * (repeat + 1) + (noteCount - count)) + 3;number++)
+ midiData[51+number] = noteTotal[number];
+
+ trackSize = (6 * (count * (repeat + 1) + (noteCount - count)) + 56) - 22 -1 ;
+
+ midiData[20] = (trackSize & 0xff00) >> 8;
+ midiData[21] = (trackSize & 0x00ff);
+
+
+ *pBufLen = 6 * (count * (repeat + 1) + (noteCount - count)) + 56 -1;
+
+ pConvertBuf = (unsigned char*) mmfile_malloc (*pBufLen);
+ if(pConvertBuf == NULL)
+ {
+ debug_error ("__AvConvertIMelody2MIDI: malloc failed!\n");
+ return NULL;
+ }
+
+ memcpy(pConvertBuf, midiData, *pBufLen);
+
+ return pConvertBuf;
+}
+
+static unsigned char
+__AvMIDISetVolume(char* pMelodyBuf)
+{
+ unsigned char midiVol;
+
+ pMelodyBuf = pMelodyBuf + 42;
+
+ while(!((*pMelodyBuf == 'V' && (*(pMelodyBuf+1) < 'a' || *(pMelodyBuf+1) > 'z')) || (*pMelodyBuf == 'M' && *(pMelodyBuf+5) == 'Y' && *(pMelodyBuf+6) == ':'))) //2007-02-28 AVMS_Sound:k2bogus - UMTS200073205;imy play, [MELODY:] extract fix
+ pMelodyBuf++;
+
+ if(*pMelodyBuf != 'V')
+ midiVol = AV_MIDI_VOL_MAX;
+
+ else
+ {
+ pMelodyBuf = pMelodyBuf + 5;
+
+ if(*pMelodyBuf == 'E')
+ pMelodyBuf = pMelodyBuf + 3;
+
+ else
+ pMelodyBuf = pMelodyBuf - 4;
+
+ if(*pMelodyBuf == '1')
+ {
+ pMelodyBuf++;
+
+ switch(*pMelodyBuf)
+ {
+ case '0': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '1': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '2': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '3': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '4': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '5': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ default : midiVol = AV_MIDI_VOL_MAX;
+ }
+ }
+
+ else
+ switch(*pMelodyBuf)
+ {
+ case '0': midiVol = 0;
+ break;
+ case '2': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '3': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '4': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '5': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '6': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '7': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '8': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ case '9': midiVol = AV_MIDI_VOL_MAX;
+ break;
+ default : midiVol = AV_MIDI_VOL_MAX;
+ }
+ }
+
+ return midiVol;
+}
+
+static int
+__AvMIDISetBeat(char* pMelodyBuf)
+{
+ int bpmValue[4] = {0};
+ int beatValue;
+
+ pMelodyBuf = pMelodyBuf + 42;
+
+ while(!((*pMelodyBuf == 'B' && (*(pMelodyBuf+1) < 'a' || *(pMelodyBuf+1) > 'z')) || (*pMelodyBuf == 'M' && *(pMelodyBuf+5) == 'Y' && *(pMelodyBuf+6) == ':'))) //2007-02-28 AVMS_Sound:k2bogus - UMTS200073205;imy play, [MELODY:] extract fix
+ pMelodyBuf++;
+
+ if(*pMelodyBuf != 'B')
+ bpmValue[3] = 120;
+
+ else
+ {
+ pMelodyBuf = pMelodyBuf + 4;
+
+ if(*pMelodyBuf == ':')
+ {
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '1' && *pMelodyBuf <= '9')
+ {
+ bpmValue[0] = *pMelodyBuf - '0';
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '9')
+ {
+ bpmValue[1] = *pMelodyBuf - '0';
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '9')
+ {
+ bpmValue[2] = *pMelodyBuf - '0';
+
+ bpmValue[0] = bpmValue[0] * 100;
+ bpmValue[1] = bpmValue[1] * 10;
+ pMelodyBuf++;
+ }
+
+ else
+ bpmValue[0] = bpmValue[0] * 10;
+ }
+ }
+
+ bpmValue[3] = bpmValue[0] + bpmValue[1] + bpmValue[2];
+ }
+ }
+
+ if(bpmValue[3] < 25 || bpmValue[3] > 900)
+ bpmValue[3] = 120;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '9')
+ bpmValue[3] = 120;
+
+ beatValue = 1000000 * 60 / bpmValue[3];
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("beat: %d = 1000000 * 60 / %d\n", beatValue, bpmValue[3]);
+ #endif
+
+ return beatValue;
+}
+
+static char
+__AvMIDISetStyle(char* pMelodyBuf)
+{
+ char styleValue = '0';
+
+ while(*pMelodyBuf != 'S')
+ pMelodyBuf--;
+
+ pMelodyBuf++;
+
+ if(*pMelodyBuf >= '0' && *pMelodyBuf <= '2')
+ pMelodyBuf++;
+
+ if(*pMelodyBuf != '.')
+ {
+ pMelodyBuf--;
+ styleValue = *pMelodyBuf;
+ }
+
+ if(styleValue < '0' || styleValue > '2') {
+ debug_warning ("unknown style. use default(S0)\n");
+ styleValue = '0';
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("style: '%c'\n", styleValue);
+ #endif
+
+ return styleValue;
+}
+
+
diff --git a/formats/ffmpeg/mm_file_format_midi.c b/formats/ffmpeg/mm_file_format_midi.c
new file mode 100755
index 0000000..c05e5b2
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_midi.c
@@ -0,0 +1,1518 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h> /*memcmp*/
+#include <stdio.h>
+#include <stdlib.h> /*malloc*/
+#include <mm_error.h>
+
+#include "mm_debug.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_private.h"
+#include "mm_file_format_midi.h"
+
+/**
+ * internal defines
+ */
+enum {
+ AV_DEC_AUDIO_MIDI,
+ AV_DEC_AUDIO_XMF,
+ AV_DEC_AUDIO_RMF,
+};
+
+#define MMFILE_XMF_100 "XMF_1.00"
+#define MMFILE_XMF_101 "XMF_1.01"
+#define MMFILE_MXMF_200 "XMF_2.00"
+#define MMFILE_RMF "IREZ"
+
+#define AvSMW_CNVID_MMF (1) /* SMAF/MA-1/MA-2/MA-3/MA-5 */
+#define AvSMW_CNVID_PHR (2) /* SMAF/Phrase L1/L2 */
+#define AvSMW_CNVID_RMD (3) /* Realtime MIDI */
+#define AvSMW_CNVID_AUD (4) /* SMAF/Audio */
+#define AvSMW_CNVID_MID (5) /* SMF */
+#define AvSMW_CNVID_HVS (9) /* HV Script */
+#define AvSMW_CNVID_WAV (11) /* WAVE */
+
+#define AvSMW_SUCCESS (0) /* success */
+#define AvSMW_ERROR (-1) /* error */
+#define AvSMW_ERROR_ARGUMENT (-2) /* error of arguments */
+#define AvSMW_ERROR_RESOURCE_OVER (-3) /* over specified resources */
+#define AvSMW_ERROR_ID (-4) /* error id number */
+#define AvSMW_ERROR_TIMEOUT (-5) /* timeout */
+#define AvSMW_ERROR_SOFTRESET (-6) /* error of soft reset for MA-5 */
+
+#define AvSMW_ERROR_FILE (-16) /* file error */
+#define AvSMW_ERROR_CONTENTS_CLASS (-17) /* SMAF Contents Class shows can't play */
+#define AvSMW_ERROR_CONTENTS_TYPE (-18) /* SMAF Contents Type shows can't play */
+#define AvSMW_ERROR_CHUNK_SIZE (-19) /* illegal SAvF Chunk Size value */
+#define AvSMW_ERROR_CHUNK (-20) /* illegal SAvF Track Chunk value */
+#define AvSMW_ERROR_UNMATCHED_TAG (-21) /* unmathced specified TAG */
+#define AvSMW_ERROR_SHORT_LENGTH (-22) /* short sequence */
+#define AvSMW_ERROR_LONG_LENGTH (-23) /* long sequence */
+#define AvSMW_ERROR_UNSUPPORTED (-24) /* unsupported format */
+#define AvSMW_ERROR_NO_INFORMATION (-25) /* no specified information */
+#define AvSMW_ERROR_HV_CONFLICT (-26) /* conflict about HV resource */
+
+#define AvSMW_ERROR_SMF_FORMAT (-50) /* invalid format type != 0/1 */
+#define AvSMW_ERROR_SMF_TRACKNUM (-51) /* invalid number of tracks */
+#define AvSMW_ERROR_SMF_TIMEUNIT (-52) /* invalid time unit */
+#define AvSMW_ERROR_SMF_CMD (-53) /* invalid command byte */
+
+
+#define SINT signed int
+#define SINT8 signed char
+#define SINT16 signed short
+#define SINT32 signed long
+#define UINT unsigned int
+#define UINT8 unsigned char
+#define UINT16 unsigned short
+#define UINT32 unsigned long
+#define ULONG unsigned long
+
+/*--------------------------------------------------------------------------*/
+/* Defines */
+/*--------------------------------------------------------------------------*/
+#define SMF_TIMEBASE_SHIFT 2 /* */
+#define SMF_TIMEBASE (1L<<SMF_TIMEBASE_SHIFT) /* [ms] */
+
+#define MAX_SMF_MESSAGES 256 /* */
+#define MAX_SMF_TRACKS 32 /* Should be <= 32 */
+#define SMF_MAX_GAIN 76 /* - 6[dB] : 90 */
+ /* -18[dB] : 45 */
+#define MINIMUM_LENGTH (20)
+
+#define MELODY_MAP (0)
+#define DRUM_MAP (1)
+#define NUM_OF_MAPS (2)
+
+
+/*--------------------------------------------------------------------------*/
+/* Types */
+/*--------------------------------------------------------------------------*/
+typedef struct _tagMidChInfo
+{
+ UINT32 dBank; /* BankH&L (0x00:00..0x7F7F) */
+ UINT32 dCurrBank; /* BankH&L (0x00:00..0x7F7F) */
+ UINT32 dProg; /* ProgramChange (0..127) */
+ UINT32 dVolume; /* ChannelVolume (0..127) */
+ UINT32 dExpression; /* Expression (0..127) */
+ UINT32 dModulation; /* Modulation (0..127) */
+ UINT32 dPitchBend; /* PitchBendH (0..127) */
+ UINT32 dBendRange; /* CurrentBendRange (0..24) */
+ UINT32 dPreBendRange; /* LatestBendRange (0..24) */
+ UINT32 dPanpot; /* Panpot (0..127) */
+ UINT32 dHold1; /* Hold1 (0..127) */
+ UINT32 dMode; /* 0:MONO, 1:POLY */
+ UINT32 dRPN; /* RPN (0x00:00..0xFF7F) */
+ UINT32 dMipMute; /* Mute switch (1:mute) */
+ UINT32 dKeyCon; /* 0:Melady, 1:OFF, 2:ON */
+ UINT32 dLedSync; /* 0:OFF, 1:ON */
+ UINT32 dVibSync; /* 0:OFF, 1:ON */
+ UINT32 dFineTune; /* 0..0x3FFF */
+ UINT32 dCoaseTune; /* 0..0x7F */
+} MIDCHINFO, *PMIDCHINFO;
+
+typedef struct _tagMIDPACKET
+{
+ SINT32 sdDeltaTime;
+ UINT32 dMsgID;
+ UINT32 dP1;
+ UINT32 dP2;
+ UINT32 dP3;
+} MIDPACKET, *PMIDPACKET;
+
+typedef struct _tagTrack
+{
+ UINT32 dSmfCmd; /* CMD @ now */
+ UINT32 dSize; /* [byte] 0 measns nothing in it. */
+ UINT8* pbBase; /* NULL measns nothing in it. */
+ UINT32 dOffset; /* offset byte */
+ SINT32 sdTicks; /* */
+} TRACKINFO, *PTRACKINFO;
+
+typedef struct _tagOrderList
+{
+ struct _tagOrderList* pPrev;
+ struct _tagOrderList* pNext;
+ UINT32 dTrack;
+ UINT32 dTicks;
+} ORDERLIST, *PORDERLIST;
+
+typedef struct _tagMidInfo
+{
+ UINT32 dTimeResolution; /* 0..0x7fff */
+ UINT8* pbText; /* */
+ UINT32 dSizeText; /* */
+ UINT8* pbTitle; /* */
+ UINT32 dSizeTitle; /* */
+ UINT8* pbCopyright; /* */
+ UINT32 dSizeCopyright; /* */
+ UINT32 dNumOfTracks; /* 1..32 */
+ UINT32 dSmfFormat; /* 0..1 */
+ UINT32 dSetupBar; /* 0:No, 1:Yes */
+ UINT32 dStart; /* Index after SetupBar */
+ UINT32 dVibNoteVoice; /* 0:No, 1:Yes */
+
+ SINT32 sdTotalTicks; /* Total ticks */
+ SINT32 sdDataEndTime; /* (22.10)[ms] */
+ SINT32 sdDelta; /* (22.10)[ms] */
+
+ UINT32 dEndFlag; /* */
+ TRACKINFO TrackInfo[MAX_SMF_TRACKS];
+
+ struct _tagOrderList* pTopOrderList;
+ struct _tagOrderList* pDoneOrderList;
+ struct _tagOrderList* pBottomOrderList;
+ ORDERLIST OrderList[MAX_SMF_TRACKS + 3];
+
+ MIDCHINFO ChInfo[16]; /* */
+ UINT32 dValid; /* 0:none, 1:Valid */
+
+ UINT8 bVoiceMap[NUM_OF_MAPS][128];/* 0:Empty, 1:Valid */
+} MIDINFO, *PMIDINFO;
+
+typedef struct _tagMidGlobals
+{
+ SINT32 sdSeqID; /* Sequence ID */
+ SINT32 sdFileID; /* File ID */
+ UINT32 dEnable; /* 0:disable */
+ UINT32 dSetup; /* 1: Just after seek */
+
+ UINT32 dRamBase; /* */
+ UINT32 dRamOffset; /* */
+ UINT32 dRamSize; /* */
+
+ MIDINFO DataInfo[2]; /* */
+
+ SINT32 sdSeekTime; /* [ms] */
+ SINT32 sdLastMsgTime; /* (22.10)[ms] */
+ SINT32 sdSmfCurrentTicks; /* Ticks @ now */
+ SINT32 sdSmfCurrentTime; /* (22.10)[ms] */
+ SINT32 sdSmfDataEndTime; /* (22.10)[ms] */
+ SINT32 sdSmfEndTime; /* (22.10)[ms] */
+ SINT32 sdSmfDelta; /* (22.10)[ms] */
+
+ UINT32 dMaxGain; /* MaxGain (0..127) */
+ UINT32 dMasterVolume; /* MsaterVolume (0..127) */
+
+ UINT32 dHoldMsgs; /* Number of messages in Q */
+ UINT32 dHoldPtrR; /* Pointer for Read */
+ MIDPACKET MsgBuffer[MAX_SMF_MESSAGES]; /* Message Q */
+
+ UINT32 dMuteFlag; /* 0:Normal, 1:MUTE */
+
+ UINT32 dSyncNoteCh; /* 0..15 */
+ UINT32 dSyncNoteKey; /* 0..127, 255:OFF */
+ UINT32 dVibNote; /* 0:No VibiNote, 1:Yes,VibNote */
+
+} MIDGLOBAL, *PMIDGLOBAL;
+
+
+/*---------------------------------------------------------------------------*/
+/* Globals */
+/*---------------------------------------------------------------------------*/
+static PMIDGLOBAL gpMidInfo;
+static PMIDINFO gPi;
+
+
+static SINT32 __AvMidFile_Initialize (void);
+static void __AvMidFile_Deinitialize (void);
+static void __AvMidInitializeOrderList (PMIDINFO pI);
+static void __AvMidSortOrderList (PMIDINFO pI);
+static void __AvMidInsertOrderList (PMIDINFO pI, UINT32 dTrack, SINT32 sdTicks);
+static void __AvMidRemoveFromOrderList (PMIDINFO pI);
+static SINT32 __AvMidGetTrackTime (PMIDINFO pI, UINT32 dTrack);
+static SINT32 __AvMidUpdateTrackTime (PMIDINFO pI, UINT32 dTrack);
+static void __AvMidResetTimeInfo (PMIDINFO pI);
+static SINT32 __AvMidGetLeastTimeTrack (PMIDINFO pI);
+static SINT32 __AvGetSizeOfFileInfo (PMIDINFO pI);
+static SINT32 __AvCheckSizeOfMidFile (UINT8* fp, UINT32 dFsize);
+static int __AvParseSkipXmf2Mid (UINT8* pbFile, UINT32 dFSize);
+static int __AvGetMidiDuration (char* szFileName, MIDI_INFO_SIMPLE *info);
+
+
+/* mm plugin interface */
+int mmfile_format_read_stream_mid (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_mid (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_mid (MMFileFormatContext *formatContext);
+int mmfile_format_close_mid (MMFileFormatContext *formatContext);
+
+EXPORT_API
+int mmfile_format_open_mid (MMFileFormatContext *formatContext)
+{
+ int res = MMFILE_FORMAT_FAIL;
+
+ if (NULL == formatContext || NULL == formatContext->uriFileName) {
+ debug_error ("error: mmfile_format_open_mid\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->pre_checked == 0) {
+ res = MMFileFormatIsValidMID (formatContext->uriFileName);
+ if ( res == 0 ) {
+ debug_error("It is not MIDI file\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+ }
+
+ formatContext->ReadStream = mmfile_format_read_stream_mid;
+ formatContext->ReadFrame = mmfile_format_read_frame_mid;
+ formatContext->ReadTag = mmfile_format_read_tag_mid;
+ formatContext->Close = mmfile_format_close_mid;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ formatContext->privateFormatData = NULL;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_stream_mid (MMFileFormatContext *formatContext)
+{
+ MMFileFormatStream *audioStream = NULL;
+ int ret = MMFILE_FORMAT_FAIL;
+ MIDI_INFO_SIMPLE *info = NULL;
+
+ if (NULL == formatContext) {
+ debug_error ("error: invalid params\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /*get infomation*/
+ info = mmfile_format_get_midi_infomation (formatContext->uriFileName);
+ if (!info) {
+ debug_error ("failed to get infomation");
+ goto exception;
+ }
+
+ formatContext->duration = info->duration;
+ formatContext->videoStreamId = -1;
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = info->track_num;
+ formatContext->nbStreams = 1;
+
+ audioStream = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == audioStream) {
+ debug_error ("error: mmfile_malloc audiostream\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ audioStream->streamType = MMFILE_AUDIO_STREAM;
+ audioStream->codecId = (info->is_xmf == 1) ? MM_AUDIO_CODEC_MXMF : MM_AUDIO_CODEC_MIDI;
+ audioStream->bitRate = 0;
+ audioStream->framePerSec = 0;
+ audioStream->width = 0;
+ audioStream->height = 0;
+ audioStream->nbChannel = 1;
+ audioStream->samplePerSec = 0;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = audioStream;
+
+ #ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+ #endif
+
+ mmfile_format_free_midi_infomation (info);
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ mmfile_format_free_midi_infomation (info);
+ mmfile_free (audioStream);
+
+ return ret;
+}
+
+EXPORT_API
+int mmfile_format_read_tag_mid (MMFileFormatContext *formatContext)
+{
+ int ret= MMFILE_FORMAT_FAIL;
+ MIDI_INFO_SIMPLE *info = NULL;
+ const char *locale = MMFileUtilGetLocale (NULL);
+ unsigned int tag_len;
+ unsigned int cnv_len;
+
+ if (NULL == formatContext) {
+ debug_error ("error: invalid params\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /*get infomation*/
+ info = mmfile_format_get_midi_infomation (formatContext->uriFileName);
+ if (!info) {
+ debug_error ("failed to get infomation");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ /**
+ * UTF8 converting.
+ */
+ if (info->title) {
+ tag_len = strlen (info->title);
+ cnv_len = 0;
+ formatContext->title = mmfile_string_convert ((const char*)info->title,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+ if (formatContext->title == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->title = mmfile_strdup (info->title);
+ }
+ }
+
+ if (info->copyright) {
+ tag_len = strlen (info->copyright);
+ cnv_len = 0;
+ formatContext->copyright = mmfile_string_convert ((const char*)info->copyright,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+ if (formatContext->copyright == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->copyright = mmfile_strdup (info->copyright);
+ }
+ }
+
+ if (info->comment) {
+ tag_len = strlen (info->comment);
+ cnv_len = 0;
+ formatContext->comment = mmfile_string_convert ((const char*)info->comment,
+ tag_len,
+ "UTF-8",
+ locale,
+ NULL,
+ (unsigned int*)&cnv_len);
+ if (formatContext->comment == NULL) {
+ debug_warning ("failed to UTF8 convert.\n");
+ formatContext->comment = mmfile_strdup (info->comment);
+ }
+ }
+
+#ifdef __MMFILE_TEST_MODE__
+ mmfile_format_print_contents (formatContext);
+#endif
+
+ mmfile_format_free_midi_infomation (info);
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ mmfile_format_free_midi_infomation (info);
+ return ret;
+}
+
+EXPORT_API
+int mmfile_format_read_frame_mid (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ debug_error ("error: mmfile_format_read_frame_midi, no handling\n");
+
+ return MMFILE_FORMAT_FAIL;
+}
+
+EXPORT_API
+int mmfile_format_close_mid (MMFileFormatContext *formatContext)
+{
+ if (NULL == formatContext ) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if(formatContext->streams[MMFILE_AUDIO_STREAM]) {
+ mmfile_free(formatContext->streams[MMFILE_AUDIO_STREAM]);
+ formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
+ }
+
+ formatContext->ReadStream = NULL;
+ formatContext->ReadFrame = NULL;
+ formatContext->ReadTag = NULL;
+ formatContext->Close = NULL;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+static char * _lc_strdup (const char *str, unsigned int size)
+{
+ char *t = NULL;
+ t = mmfile_malloc (size+1);
+ if (t) {
+ memset (t, 0x00, size+1);
+ memcpy (t, str, size);
+ }
+ return t;
+}
+
+MIDI_INFO_SIMPLE *
+mmfile_format_get_midi_infomation (char* szFileName)
+{
+ int duration = -1;
+ MIDI_INFO_SIMPLE *info = NULL;
+
+ info = mmfile_malloc (sizeof (MIDI_INFO_SIMPLE));
+ if (!info)
+ return NULL;
+
+ /*get infomation*/
+ duration = __AvGetMidiDuration (szFileName, info);
+
+ return info;
+}
+
+void
+mmfile_format_free_midi_infomation (MIDI_INFO_SIMPLE *info)
+{
+ if (info) {
+ if (info->title) mmfile_free (info->title);
+ if (info->copyright) mmfile_free (info->copyright);
+ if (info->comment) mmfile_free (info->comment);
+ mmfile_free (info);
+ }
+}
+
+
+
+/**
+ * internal midi parsing functions
+ */
+
+/****************************************************************************
+ * __AvGetMidiDuration(char* szFileName)
+ *
+ * Desc.
+ * Load SMF data
+ * Param
+ * pbFile pointer to the data
+ * dFileSize size fo the data
+ * dMode error check (0:No, 1:Yes, 2:Check, 3:OnlyInfo)
+ * pfnFunc pointer of rhe callback function
+ * pvExtArgs Reserved
+ * Return
+ * >= 0 : FileID, < 0 : Error code
+ ****************************************************************************/
+static int
+__AvGetMidiDuration(char* szFileName, MIDI_INFO_SIMPLE *info)
+{
+
+ int xmfheaderSkip=0;
+ MMFileIOHandle * hFile = NULL;
+ UINT8 * pbFile= NULL;
+ UINT8 * pIMYbuf= NULL;
+ SINT32 dFileSize;
+ int sdCurrentTime = 0;
+ // void* pvExtArgs = "mid";
+ int readed =0;
+ int ret;
+ int codecType = AV_DEC_AUDIO_MIDI;
+ int is_xmf = 0;
+
+ if ( szFileName == NULL || info == NULL)
+ return -1;
+
+ // printf ("URI: %s\n", szFileName);
+ /*open*/
+ ret = mmfile_open (&hFile, szFileName, MMFILE_RDONLY);
+ if (ret == MMFILE_UTIL_FAIL) {
+ debug_error ( "open failed.\n");
+ return -1;
+ }
+
+ /*get file size*/
+ mmfile_seek (hFile, 0L, MMFILE_SEEK_END);
+ dFileSize = mmfile_tell (hFile);
+ mmfile_seek (hFile, 0L, MMFILE_SEEK_SET);
+
+ if (dFileSize <= 0) {
+ debug_error ("failed to get file size.\n");
+ goto _RELEASE_RESOURCE;
+ }
+
+ /*alloc read buffer*/
+ pbFile = (UINT8 *) mmfile_malloc (sizeof(UINT8) * (dFileSize + 1));
+ if (!pbFile) {
+ debug_error ( "memory allocation failed.\n");
+ goto _RELEASE_RESOURCE;
+ }
+
+ /*read data*/
+ if ((readed = mmfile_read (hFile, pbFile, dFileSize) ) != dFileSize) {
+ debug_error ( "read error. size = %d\n", readed);
+ goto _RELEASE_RESOURCE;
+ }
+
+ /*init global workspace*/
+ if(__AvMidFile_Initialize())
+ goto _RELEASE_RESOURCE;
+
+ /*check format*/
+ if (!(memcmp (pbFile, MMFILE_XMF_100, 8)) ||
+ !(memcmp (pbFile, MMFILE_XMF_101, 8)) ||
+ !(memcmp (pbFile, MMFILE_MXMF_200, 8))) {
+
+ is_xmf = 1;
+ codecType = AV_DEC_AUDIO_XMF;
+ } else if (!(memcmp (pbFile, MMFILE_RMF, 4))) {
+ is_xmf = 0;
+ codecType = AV_DEC_AUDIO_RMF;
+ } else {
+ is_xmf = 0;
+ codecType = AV_DEC_AUDIO_MIDI;
+ }
+
+ /*set output param*/
+ if (codecType == AV_DEC_AUDIO_RMF) {
+
+ info->duration = sdCurrentTime = 0; /*not yet implemented.*/
+ info->track_num = 1; /*not yet implemented.*/
+ info->is_xmf = is_xmf;
+
+ } else {
+
+ /*get duration. XMF/MIDI*/
+ if(codecType == AV_DEC_AUDIO_XMF) {
+ xmfheaderSkip = __AvParseSkipXmf2Mid(pbFile, dFileSize);
+ if(xmfheaderSkip == -1)
+ goto _RELEASE_RESOURCE;
+
+ sdCurrentTime = __AvCheckSizeOfMidFile(pbFile+xmfheaderSkip, dFileSize);
+ } else {
+ sdCurrentTime = __AvCheckSizeOfMidFile(pbFile, dFileSize);
+ }
+
+ if(sdCurrentTime < 0) {
+ debug_error ("__AvGetMidiDuration: sdResult's error Code!(%d)\n", sdCurrentTime);
+ goto _RELEASE_RESOURCE;
+ }
+
+ if(sdCurrentTime > 0)
+ sdCurrentTime /= 1000;
+
+ info->duration = sdCurrentTime;
+ info->track_num = gPi->dNumOfTracks;
+ info->is_xmf = is_xmf;
+
+ info->title = _lc_strdup ((const char *)gPi->pbTitle, gPi->dSizeTitle);
+ info->copyright = _lc_strdup ((const char *)gPi->pbCopyright, gPi->dSizeCopyright);
+ info->comment = _lc_strdup ((const char *)gPi->pbText, gPi->dSizeText);
+ }
+
+_RELEASE_RESOURCE:
+
+ /*resource release*/
+ __AvMidFile_Deinitialize ();
+ mmfile_close (hFile);
+ mmfile_free (pbFile);
+ mmfile_free (pIMYbuf);
+
+ return sdCurrentTime;
+}
+
+static SINT32
+__AvMidFile_Initialize(void)
+{
+ gpMidInfo = mmfile_malloc (sizeof (MIDGLOBAL));
+
+ if (!gpMidInfo)
+ return (AvSMW_ERROR);
+
+ memset (gpMidInfo, 0x00, sizeof (MIDGLOBAL));
+
+ gpMidInfo->sdSeqID = -1; /* Sequence ID */
+ gpMidInfo->sdFileID = -1; /* File ID */
+ gpMidInfo->dEnable = 0; /* 0:disabel */
+ gpMidInfo->DataInfo[0].dValid = 0;
+ gpMidInfo->DataInfo[1].dValid = 0;
+
+ return (AvSMW_SUCCESS);
+}
+
+static void
+__AvMidFile_Deinitialize(void)
+{
+ mmfile_free (gpMidInfo);
+}
+
+
+/*---------------------------------------------------------------------------*/
+/* Functions (internal use only) */
+/*---------------------------------------------------------------------------*/
+
+/****************************************************************************
+ * __AvMidInitializeOrderList(PMIDINFO pI)
+ *
+ * Description:
+ * Initialize OrderList.
+ * Param:
+ * pI ... pointer to the data info
+ * Return:
+ * none
+ ****************************************************************************/
+static void
+__AvMidInitializeOrderList(PMIDINFO pI)
+{
+ int ix2;
+
+ for (ix2 = 1; ix2 <= MAX_SMF_TRACKS + 1; ix2++)
+ {
+ pI->OrderList[ix2].pPrev = &pI->OrderList[ix2 - 1];
+ pI->OrderList[ix2].pNext = &pI->OrderList[ix2 + 1];
+ pI->OrderList[ix2].dTrack = 0xFF;
+ pI->OrderList[ix2].dTicks = 0xFFFFFFFFL;
+ }
+ pI->OrderList[0].pPrev = NULL;
+ pI->OrderList[0].pNext = &pI->OrderList[1];
+ pI->OrderList[MAX_SMF_TRACKS + 2].pPrev = &pI->OrderList[MAX_SMF_TRACKS + 1];
+ pI->OrderList[MAX_SMF_TRACKS + 2].pNext = NULL;
+ pI->pTopOrderList = &pI->OrderList[0];
+ pI->pDoneOrderList = &pI->OrderList[1];
+ pI->pBottomOrderList = &pI->OrderList[MAX_SMF_TRACKS + 2];
+}
+
+
+/****************************************************************************
+ * __AvMidSortOrderList(PMIDINFO pI)
+ *
+ * Description:
+ * Sort OrderList. (Ascending order)
+ * Param:
+ * pI ... pointer to the data info
+ * Return:
+ * none
+ ****************************************************************************/
+static void
+__AvMidSortOrderList(PMIDINFO pI)
+{
+ PORDERLIST pSlot;
+ PORDERLIST pTerget;
+
+ pSlot = (pI->pTopOrderList)->pNext;
+ (pSlot->pPrev)->pNext = pSlot->pNext;
+ (pSlot->pNext)->pPrev = pSlot->pPrev;
+ pSlot->dTicks = ((UINT32)pI->TrackInfo[pSlot->dTrack].sdTicks << 5) + pSlot->dTrack;
+
+ pTerget = pSlot->pNext;
+ while (pTerget != pI->pDoneOrderList)
+ {
+ if (pSlot->dTicks <= pTerget->dTicks) break;
+ pTerget = pTerget->pNext;
+ }
+
+ (pTerget->pPrev)->pNext = pSlot;
+ pSlot->pPrev = pTerget->pPrev;
+ pTerget->pPrev = pSlot;
+ pSlot->pNext = pTerget;
+}
+
+
+/****************************************************************************
+ * __AvMidInsertOrderList(PMIDINFO pI, UINT32 dTrack, SINT32 sdTicks)
+ *
+ * Description:
+ * Add item to the top of the list.
+ * Param:
+ * pI ... pointer to the data info
+ * Return:
+ * none
+ ****************************************************************************/
+static void
+__AvMidInsertOrderList(PMIDINFO pI, UINT32 dTrack, SINT32 sdTicks)
+{
+ PORDERLIST pTerget;
+
+ if (pI->dNumOfTracks == 1) return;
+ if (((pI->dEndFlag >> dTrack) & 0x01) == 0) return;
+
+ pTerget = pI->pDoneOrderList->pNext;
+ if (pTerget == pI->pBottomOrderList) return;
+
+ pI->pDoneOrderList->pNext = pTerget->pNext;
+ (pTerget->pNext)->pPrev = pI->pDoneOrderList;
+
+ pTerget->dTrack = dTrack;
+ pTerget->dTicks = ((UINT32)sdTicks << 5) + dTrack;
+ pTerget->pPrev = pI->pTopOrderList;
+ pTerget->pNext = (pI->pTopOrderList)->pNext;
+ ((pI->pTopOrderList)->pNext)->pPrev = pTerget;
+ (pI->pTopOrderList)->pNext = pTerget;
+
+ __AvMidSortOrderList(pI);
+}
+
+
+/****************************************************************************
+ * __AvMidRemoveFromOrderList(PMIDINFO pI)
+ *
+ * Description:
+ * delete Item from the top of the list.
+ * Param:
+ * pI ... pointer to the data info
+ * Return:
+ * none
+ ****************************************************************************/
+static void
+__AvMidRemoveFromOrderList(PMIDINFO pI)
+{
+ PORDERLIST pSlot;
+ PORDERLIST pTerget;
+
+ pSlot = (pI->pTopOrderList)->pNext;
+ (pSlot->pPrev)->pNext = pSlot->pNext;
+ (pSlot->pNext)->pPrev = pSlot->pPrev;
+
+ pTerget = pI->pBottomOrderList;
+ (pTerget->pPrev)->pNext = pSlot;
+ pSlot->pPrev = pTerget->pPrev;
+ pTerget->pPrev = pSlot;
+ pSlot->pNext = pTerget;
+}
+
+
+/****************************************************************************
+ * __AvMidGetTrackTime(PMIDINFO pI, UINT32 dTrack)
+ *
+ * Description:
+ * Get the 1st DT from the list.
+ * Param:
+ * pI ... pointer to the data info
+ * bTrack ... #Track
+ * Return:
+ * 0 : NoError, < 0 : Error code
+ ****************************************************************************/
+static SINT32
+__AvMidGetTrackTime(PMIDINFO pI, UINT32 dTrack)
+{
+ UINT32 dTemp;
+ SINT32 dTime;
+ PTRACKINFO pMt;
+
+ if (((pI->dEndFlag >> dTrack) & 0x01) == 0) return (-1);
+
+ pMt = &(pI->TrackInfo[dTrack]);
+
+ dTime = 0;
+ do
+ {
+ if (pMt->dOffset >= pMt->dSize)
+ {
+ pI->dEndFlag &= ~(1L << dTrack);
+ return (-1);
+ }
+ dTemp = (UINT32)pMt->pbBase[pMt->dOffset++];
+ dTime = (dTime << 7) + (dTemp & 0x7f);
+ } while (dTemp >= 0x80);
+ //printf("dTime is %d\n", dTime);
+ pMt->sdTicks += dTime;
+
+ return (0);
+}
+
+
+/****************************************************************************
+ * __AvMidUpdateTrackTime(PMIDINFO pI, UINT32 dTrack)
+ *
+ * Description:
+ * Update the 1st DT on the Track and OrderList
+ * Param:
+ * pI ... pointer to the data info
+ * bTrack ... #Track
+ * Return:
+ * 0 : NoError, < 0 : Error code
+ ****************************************************************************/
+static SINT32
+__AvMidUpdateTrackTime(PMIDINFO pI, UINT32 dTrack)
+{
+ UINT32 dTemp;
+ SINT32 dTime;
+ PTRACKINFO pMt;
+
+ if (pI->dNumOfTracks == 1)
+ {
+ /* Single track */
+ if (((pI->dEndFlag >> dTrack) & 0x01) == 0)
+ {
+ return (-1);
+ }
+
+ pMt = &(pI->TrackInfo[dTrack]);
+
+ dTime = 0;
+ do
+ {
+ if (pMt->dOffset >= pMt->dSize)
+ {
+ pI->dEndFlag &= ~(1L << dTrack);
+ return (-1);
+ }
+ dTemp = (UINT32)pMt->pbBase[pMt->dOffset++];
+ dTime = (dTime << 7) + (dTemp & 0x7f);
+ } while (dTemp >= 0x80);
+
+ pMt->sdTicks += dTime;
+ }
+ else
+ {
+ /* Multi track */
+ if (((pI->dEndFlag >> dTrack) & 0x01) == 0)
+ {
+ __AvMidRemoveFromOrderList(pI);
+ return (-1);
+ }
+
+ pMt = &(pI->TrackInfo[dTrack]);
+
+ dTime = 0;
+ do
+ {
+ if (pMt->dOffset >= pMt->dSize)
+ {
+ pI->dEndFlag &= ~(1L << dTrack);
+ __AvMidRemoveFromOrderList(pI);
+ return (-1);
+ }
+ dTemp = (UINT32)pMt->pbBase[pMt->dOffset++];
+ dTime = (dTime << 7) + (dTemp & 0x7f);
+ } while (dTemp >= 0x80);
+
+ pMt->sdTicks += dTime;
+ __AvMidSortOrderList(pI);
+ }
+
+ return (0);
+}
+
+
+/****************************************************************************
+ * __AvMidResetTimeInfo(PMIDINFO pI)
+ *
+ * Description:
+ * Reset time info
+ * Param:
+ * pI ... pointer to the data info
+ * Return:
+ * none
+ ****************************************************************************/
+static void
+__AvMidResetTimeInfo(PMIDINFO pI)
+{
+ SINT32 sdTrack;
+ PTRACKINFO pMt;
+
+ pI->dEndFlag = 0;
+
+ for (sdTrack = 0; sdTrack < (UINT32)pI->dNumOfTracks; sdTrack++)
+ {
+ pMt = &(pI->TrackInfo[sdTrack]);
+
+ pMt->dSmfCmd = 0;
+ pMt->dOffset = 0;
+ pMt->sdTicks = 0;
+ if (pMt->dSize > 0) pI->dEndFlag |= (1L << sdTrack);
+ }
+
+ __AvMidInitializeOrderList(pI);
+
+ if((UINT32)pI->dNumOfTracks > MAX_SMF_TRACKS)
+ {
+ debug_error ("__AvMidResetTimeInfo: Num of tracks is over MAX track number. !!\n");
+ return;
+ }
+
+ for (sdTrack = 0; sdTrack < (UINT32)pI->dNumOfTracks; sdTrack++)
+ {
+ __AvMidGetTrackTime(pI, (UINT32)sdTrack);
+ pMt = &(pI->TrackInfo[sdTrack]);
+ __AvMidInsertOrderList(pI, (UINT32)sdTrack, pMt->sdTicks);
+ }
+}
+
+
+/****************************************************************************
+ * __AvMidGetLeastTimeTrack(PMIDINFO pI)
+ *
+ * Description:
+ * Get the track@LeasetTime
+ * Param:
+ * pI ... pointer to the setup storage
+ * Return:
+ * 0 : NoError, < 0 : Error
+ ****************************************************************************/
+static SINT32
+__AvMidGetLeastTimeTrack(PMIDINFO pI)
+{
+ PORDERLIST pTerget;
+
+ pTerget = (pI->pTopOrderList)->pNext;
+ if (pTerget == pI->pBottomOrderList) return (-1);
+
+ return ((UINT32)pTerget->dTrack);
+}
+
+
+/****************************************************************************
+ * __AvGetSizeOfFileInfo(PMIDINFO pI)
+ *
+ * Description:
+ * Get SMF info from the file
+ * Param:
+ * pI ... pointer to the setup storage
+ * Return:
+ * 0 : NoError, < 0 : Error
+ ****************************************************************************/
+static SINT32
+__AvGetSizeOfFileInfo(PMIDINFO pI)
+{
+ UINT32 dCmd;
+ UINT32 dCmd2;
+ UINT32 dSize;
+
+ UINT32 dTemp;
+ UINT32 dTime;
+ SINT32 sdTotalTicks;
+ SINT32 sdCurrentTime;
+ SINT32 sdDelta;
+ PMIDCHINFO pCh;
+ UINT32 dCh;
+
+ UINT32 dSetup; /* bit0:beat@0, bit1:tempo@0, bit2:GmOn@0, bit3:tempo@1 */
+ PTRACKINFO pMt;
+ SINT32 sdTr;
+
+ static UINT32 dBank[16];
+ static UINT32 dCurrBank[16];
+
+ SINT32 sdNonConductorTime;
+ SINT32 sdNonConductorTicks;
+ UINT32 dConductorNote;
+ dSetup = 0;
+ sdTotalTicks = 0;
+ sdCurrentTime = 0;
+ sdNonConductorTime = 0x7FFFFFFF;
+ sdNonConductorTicks = 0;
+ dConductorNote = 0;
+ sdDelta = (UINT32)(500 << 10) / pI->dTimeResolution; /* default=0.5sec */
+
+ pI->pbText = NULL;
+ pI->dSizeText = 0;
+ pI->pbTitle = NULL;
+ pI->dSizeTitle = 0;
+ pI->pbCopyright = NULL;
+ pI->dSizeCopyright = 0;
+ pI->dStart = 0;
+ pI->dSetupBar = 0;
+ pI->dVibNoteVoice = 0;
+
+ for (dCh = 0; dCh < NUM_OF_MAPS; dCh++)
+ {
+ for (dTemp = 0; dTemp < 128; dTemp++)
+ {
+ pI->bVoiceMap[dCh][dTemp] = 0;
+ }
+ }
+ pI->bVoiceMap[MELODY_MAP][0] = 1; /* GM Default Piano */
+
+ for (dCh = 0; dCh < 16; dCh++)
+ {
+ dBank[dCh] = 0;
+ dCurrBank[dCh] = 0;
+ pCh = &pI->ChInfo[dCh];
+ pCh->dKeyCon = 0;
+ pCh->dVibSync = 0;
+ pCh->dLedSync = 0;
+ }
+
+ __AvMidResetTimeInfo(pI);
+
+ if (pI->dSmfFormat != 0) dSetup |= 0x20;
+
+ while (pI->dEndFlag != 0)
+ {
+ if ((pI->dEndFlag == 1) && (sdNonConductorTime == 0x7FFFFFFF))
+ {
+ sdNonConductorTime = sdCurrentTime;
+ sdNonConductorTicks = sdTotalTicks;
+ dConductorNote |= 2;
+ }
+
+ if (pI->dNumOfTracks == 1)
+ {
+ sdTr = 0;
+ }
+ else
+ {
+ sdTr = __AvMidGetLeastTimeTrack(pI);
+ if (sdTr < 0) break;
+ }
+ pMt = &(pI->TrackInfo[sdTr]);
+
+ dTime = pMt->sdTicks - sdTotalTicks;
+ sdCurrentTime += dTime * sdDelta;
+ sdTotalTicks = pMt->sdTicks;
+ if ((sdCurrentTime < 0) || (sdTotalTicks > 0x07FFFFFFL))
+ {
+ return (AvSMW_ERROR_LONG_LENGTH);
+ }
+
+ dCmd = (UINT32)pMt->pbBase[pMt->dOffset++];
+
+ if (dCmd < 0xf0)
+ {
+ /*--- MidiMsg ---*/
+ if (dCmd < 0x80)
+ {
+ dCmd = pMt->dSmfCmd;
+ if (dCmd < 0x80) return (AvSMW_ERROR_SMF_CMD);
+ pMt->dOffset--;
+ } else {
+ pMt->dSmfCmd = dCmd;
+ }
+
+ dCh = dCmd & 0x0f;
+
+ switch (dCmd & 0xf0)
+ {
+ case 0x90: /* NoteOn */
+ /* Conductor Track Note Check */
+ if (sdTr == 0) dConductorNote |= 1;
+ switch (dCurrBank[dCh] >> 8)
+ {
+ case 0x79:
+ /* Melody */
+ break;
+
+ case 0x78:
+ /* Drum */
+ pI->bVoiceMap[DRUM_MAP][pMt->pbBase[pMt->dOffset] & 0x7F] = 1;
+ break;
+
+ default:
+ if (dCh == 9)
+ {
+ /* Unknown: default GM Drum */
+ pI->bVoiceMap[DRUM_MAP][pMt->pbBase[pMt->dOffset] & 0x7F] = 1;
+ }
+ }
+ pMt->dOffset += 2;
+ break;
+
+ case 0xC0: /* Program change */
+ switch (dBank[dCh] >> 8)
+ {
+ case 0x79:
+ if (dBank[dCh] != 0x7906)
+ {
+ /* Melody */
+ pI->bVoiceMap[MELODY_MAP][pMt->pbBase[pMt->dOffset] & 0x7F] = 1;
+ }
+ else
+ {
+ /* Vibration Note */
+ pI->dVibNoteVoice = 1;
+ }
+ break;
+
+ case 0x78:
+ /* Drum */
+ break;
+
+ default:
+ /* default GM Melody */
+ if (dCh != 9)
+ {
+ pI->bVoiceMap[MELODY_MAP][pMt->pbBase[pMt->dOffset] & 0x7F] = 1;
+ }
+ }
+
+ dCurrBank[dCh] = dBank[dCh];
+ pMt->dOffset++;
+ break;
+
+ case 0xD0: /* Channel pressure */
+ pMt->dOffset++;
+ break;
+
+ case 0xB0: /* Control Change */
+ switch (pMt->pbBase[pMt->dOffset])
+ {
+ case 0x00: /* Bank select(MSB) */
+ dBank[dCh] = (dBank[dCh] & 0x00FF) | (pMt->pbBase[pMt->dOffset + 1] << 8);
+ break;
+
+ case 0x20: /* Bank select (LSB) */
+ dBank[dCh] = (dBank[dCh] & 0xFF00) | pMt->pbBase[pMt->dOffset + 1];
+ break;
+ }
+ pMt->dOffset += 2;
+ break;
+
+ default:
+ pMt->dOffset += 2;
+ }
+ }
+ else
+ {
+ switch (dCmd)
+ {
+ case 0xF0: /* SysEx */
+ case 0xF7: /* SysEx */
+ pMt->dSmfCmd = 0;
+ dSize = 0;
+ do
+ {
+ dTemp = (UINT32)pMt->pbBase[pMt->dOffset++];
+ dSize = (dSize << 7) + (dTemp & 0x7f);
+ } while (dTemp >= 0x80);
+
+ if ((dSize == 5) &&
+ (pMt->pbBase[pMt->dOffset] == 0x7e) &&
+ (pMt->pbBase[pMt->dOffset + 1] == 0x7f) &&
+ (pMt->pbBase[pMt->dOffset + 2] == 0x09) &&
+ (pMt->pbBase[pMt->dOffset + 3] == 0x01))
+ {
+ /* System On */
+ if (sdTotalTicks == 0)
+ {
+ dSetup |= 0x04;
+ }
+ }
+ else
+ {
+ if (pI->dSetupBar == 0)
+ {
+ if ((dSize == 22) &&
+ (pMt->pbBase[pMt->dOffset] == 0x43) &&
+ (pMt->pbBase[pMt->dOffset + 1] == 0x79) &&
+ (pMt->pbBase[pMt->dOffset + 2] == 0x06) &&
+ (pMt->pbBase[pMt->dOffset + 3] == 0x7C)&&
+ (pMt->pbBase[pMt->dOffset + 4] == 0x02))
+ {
+ /* Channel status */
+ for (dCh = 0; dCh < 16; dCh++)
+ {
+ pCh = &pI->ChInfo[dCh];
+ dTemp = pMt->pbBase[pMt->dOffset + 5 + dCh];
+ pCh->dKeyCon = (dTemp >> 2) & 0x03;
+ pCh->dVibSync = (dTemp >> 1) & 0x01;
+ pCh->dLedSync = dTemp & 0x01;
+ }
+ }
+ }
+ }
+
+ pMt->dOffset += dSize;
+ break;
+
+ case 0xF1: /* System Msg */
+ case 0xF3: /* System Msg */
+ pMt->dOffset++;
+ break;
+
+ case 0xF2: /* System Msg */
+ pMt->dOffset += 2;
+ break;
+
+ case 0xFF: /* Meta */
+ dCmd2 = (UINT32)pMt->pbBase[pMt->dOffset++]; /* Meta Command */
+ dSize = 0; /* Size */
+ do
+ {
+ dTemp = (UINT32)pMt->pbBase[pMt->dOffset++];
+ dSize = (dSize << 7) + (dTemp & 0x7f);
+ } while (dTemp >= 0x80);
+
+ switch (dCmd2)
+ {
+ case 0x01: /* Text */
+ if (pI->pbText == NULL)
+ {
+ pI->pbText = &pMt->pbBase[pMt->dOffset];
+ pI->dSizeText = dSize;
+ }
+ break;
+
+ case 0x02: /* Copyright */
+ if (pI->pbCopyright == NULL)
+ {
+ pI->pbCopyright = &pMt->pbBase[pMt->dOffset];
+ pI->dSizeCopyright = dSize;
+ }
+ break;
+
+ case 0x03: /* Title */
+ if (pI->pbTitle == NULL)
+ {
+ pI->pbTitle = &pMt->pbBase[pMt->dOffset];
+ pI->dSizeTitle = dSize;
+ }
+ break;
+
+ case 0x2f: /* End */
+ pI->dEndFlag &= ~(1L << sdTr);
+ break;
+
+ case 0x51: /* Set Tempo */
+ switch (dSize)
+ {
+ case 3:
+ case 4:
+ dTime = ((UINT32)pMt->pbBase[pMt->dOffset] << 16) +
+ ((UINT32)pMt->pbBase[pMt->dOffset + 1] << 8) +
+ (UINT32)pMt->pbBase[pMt->dOffset + 2];
+ if ((sdTotalTicks == 0) && (dTime == 250000)) dSetup |= 0x02;
+ if (sdTotalTicks == (UINT32)pI->dTimeResolution) dSetup |= 0x08;
+
+ /*<== I Think that Below Code is Trash!! and Erase it! (Actually I Don Know ^^)
+ dTime = (dTime << 7) / 125; */
+
+ sdDelta = (UINT32)(dTime / pI->dTimeResolution);
+ }
+ break;
+
+ case 0x58: /* Set TimeSignature */
+ if ((sdTotalTicks == 0) &&
+ (pMt->pbBase[pMt->dOffset] == 1) &&
+ (pMt->pbBase[pMt->dOffset + 1] == 2)) dSetup |= 0x01;
+ break;
+ }
+ pMt->dOffset += dSize;
+ break;
+ }
+ }
+
+ if((UINT32)sdTr >= MAX_SMF_TRACKS)
+ {
+ debug_error ("__AvGetSizeOfFileInfo: Num of tracks is over MAX track number. !!\n");
+ return AvSMW_ERROR_SMF_CMD;
+ }
+ __AvMidUpdateTrackTime(pI, (UINT32)sdTr);
+
+ if (dSetup == 0x0F)
+ {
+ dSetup |= 0x10;
+ sdCurrentTime = 0;
+ pI->dSetupBar = 1;
+ pI->dStart = pI->TrackInfo[0].dOffset;
+ }
+ }
+
+ if ((dConductorNote != 2) || (pI->dSmfFormat == 0))
+ {
+ pI->sdTotalTicks = sdTotalTicks;
+ pI->sdDataEndTime = sdCurrentTime;
+ }
+ else
+ {
+ pI->sdTotalTicks = sdNonConductorTicks;
+ pI->sdDataEndTime = sdNonConductorTime;
+ }
+
+ if (pI->dSetupBar == 0)
+ {
+ for (dCh = 0; dCh < 16; dCh++)
+ {
+ pCh = &pI->ChInfo[dCh];
+ pCh->dKeyCon = 0;
+ pCh->dVibSync = 0;
+ pCh->dLedSync = 0;
+ }
+ }
+ if ((pI->sdDataEndTime >> 10) <= MINIMUM_LENGTH) return (AvSMW_ERROR_SHORT_LENGTH);
+
+ // printf("__AvGetSizeOfFileInfo/Done\n");
+
+ return pI->sdDataEndTime;
+}
+
+
+/****************************************************************************
+ * __AvCheckSizeOfMidFile(UINT8* fp, UINT32 dFsize)
+ *
+ * Description:
+ * Check SMF structure
+ * Param:
+ * fp ... pointer to the data
+ * dFsize ... size fo the data
+ * dMode ... error check (0:No, 1:Yes, 2:ErrorCheck, 3:CNTI)
+ * Return:
+ * 0 : NoError, < 0 : Error
+ ****************************************************************************/
+static SINT32
+__AvCheckSizeOfMidFile(UINT8* src_fp, UINT32 dFsize)
+{
+ UINT32 dTemp;
+ UINT32 dSize;
+ PMIDINFO pI = NULL;
+ UINT32 dFormat;
+ UINT32 dNumOfTracks;
+ UINT32 i;
+ UINT8 *fp = src_fp;
+ // printf ("input param: %p, %d\n", fp , dFsize);
+ while (dFsize >= 22)
+ {
+ dTemp = ((UINT32)fp[0] << 24) + ((UINT32)fp[1] << 16) +
+ ((UINT32)fp[2] << 8) + (UINT32)fp[3];
+ if (dTemp == 0x4D546864) break; /* 'MThd' */
+ fp ++;
+ dFsize --;
+ }
+
+ // printf("__AvCheckSizeOfMidFile(): MThd Position is dFsize(%d)\n", dFsize);
+
+ if (dFsize < 22)
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error / Too small size\n");
+ return (AvSMW_ERROR_FILE);
+ }
+
+ fp += 4;
+ dFsize -= 4;
+
+ /*--- Check size ----------------------------------------------------*/
+ dTemp = ((UINT32)fp[0] << 24) + ((UINT32)fp[1] << 16) +
+ ((UINT32)fp[2] << 8) + (UINT32)fp[3];
+
+ if (dTemp != 6)
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error / Size != 6\n");
+ return (AvSMW_ERROR_CHUNK_SIZE);
+ }
+
+ fp += 4;
+ dFsize -= 4;
+
+ if (gpMidInfo->DataInfo[1].dValid == 1) return (AvSMW_ERROR);
+ pI = &gpMidInfo->DataInfo[1];
+
+ /**
+ * set global val
+ */
+
+ /*--- Check format -------------------------------------------------*/
+ dFormat = ((UINT32)fp[0] << 8) + (UINT32)fp[1];
+ if (dFormat > 1)
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error/ Not Format 0 or 1\n");
+ return (AvSMW_ERROR_SMF_FORMAT);
+ }
+
+ /*--- Check number of tracks ---------------------------------------*/
+ dNumOfTracks = (SINT32)((UINT32)fp[2] << 8) + (UINT32)fp[3];
+ if (dNumOfTracks == 0)
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error/ Number of Tracks = 0\n");
+ return (AvSMW_ERROR_SMF_TRACKNUM);
+ }
+ if ((dFormat == 0) && (dNumOfTracks != 1))
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error/ Number of Tracks > 1\n");
+ return (AvSMW_ERROR_SMF_TRACKNUM);
+ }
+
+ if (dNumOfTracks > MAX_SMF_TRACKS) dNumOfTracks = MAX_SMF_TRACKS;
+ pI->dNumOfTracks = (UINT8)dNumOfTracks;
+
+ /*--- Check Time unit --------------------------------------------*/
+ dTemp = ((UINT32)fp[4] << 8) + (UINT32)fp[5];
+ pI->dTimeResolution = dTemp & 0x7fff;
+ if (((dTemp & 0x8000) != 0) || (pI->dTimeResolution == 0))
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error/ Unknown TimeUnit\n");
+ return (AvSMW_ERROR_SMF_TIMEUNIT);
+ }
+ fp += 6;
+ dFsize -= 6;
+
+ for (i = 0; i < dNumOfTracks; i++)
+ {
+ /*--- Check chunk name --------------------------------------------*/
+ while (dFsize >= 8)
+ {
+ dTemp = ((UINT32)fp[0] << 24) + ((UINT32)fp[1] << 16) +
+ ((UINT32)fp[2] << 8) + (UINT32)fp[3];
+ if (dTemp == 0x4D54726B) break; /* 'MTrk' */
+ fp ++;
+ dFsize --;
+ }
+
+ if (dFsize < 8)
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error/ Bad size\n");
+ return (AvSMW_ERROR_CHUNK_SIZE);
+ }
+
+ /*--- Check size ----------------------------------------------------*/
+ dSize = ((UINT32)fp[4] << 24) + ((UINT32)fp[5] << 16) +
+ ((UINT32)fp[6] << 8) + (UINT32)fp[7];
+
+ if (dFsize < (dSize + 8))
+ {
+ debug_error ("__AvCheckSizeOfMidFile Error/ Bad size [%ld] vs [%ld]\n", dFsize, dSize + 22);
+ return (AvSMW_ERROR_CHUNK_SIZE);
+ }
+ pI->TrackInfo[i].pbBase = &fp[8];
+ pI->TrackInfo[i].dSize = dSize;
+ fp += (dSize + 8);
+ dFsize -= (dSize + 8);
+ }
+ pI->dSmfFormat = dFormat;
+
+ /**
+ * set global
+ */
+ gPi = pI;
+
+ return (__AvGetSizeOfFileInfo(pI));
+}
+
+static int
+__AvParseSkipXmf2Mid(UINT8* pbFile, UINT32 dFSize)
+{
+ UINT32 skipVal = 0, sizeOfpbFile= dFSize;
+ while(1)
+ {
+ if(pbFile[skipVal] == 'M' && pbFile[skipVal+1] == 'T' && pbFile[skipVal+2] == 'h' && pbFile[skipVal+3] == 'd')
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("__AvParseSkipForXMF : MThd Header found!\n");
+ #endif
+ break;
+ }
+ else
+ {
+ skipVal++;
+ if(skipVal >= sizeOfpbFile)
+ {
+ debug_error ("__AvParseSkipForXMF : MThd Header is not found!\n");
+ debug_error ("__AvParseSkipForXMF :skipVal(%d) sizeOfpbFile(%d) \n", skipVal, sizeOfpbFile);
+ return -1;
+ }
+ }
+ }
+
+ // printf("__AvParseSkipForXMF : skip value(%d)\n", skipVal);
+
+ return skipVal;
+}
+
diff --git a/formats/ffmpeg/mm_file_format_mmf.c b/formats/ffmpeg/mm_file_format_mmf.c
new file mode 100755
index 0000000..37a4bb1
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_mmf.c
@@ -0,0 +1,2934 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h> /*memcmp*/
+#include <stdlib.h> /*malloc*/
+
+#include "mm_debug.h"
+
+#include "mm_file_utils.h"
+#include "mm_file_format_mmf.h"
+#include "mm_file_format_private.h"
+
+
+/**
+ *MMF
+ *
+ */
+
+#define AV_MMF_CONTENTS_CLASS_0 0x00
+#define AV_MMF_CONTENTS_CLASS_1 0x20
+#define AV_MMF_CONTENTS_CLASS_2 0x10
+
+#define AV_MMF_CONTENTS_TYPE_0 0x00
+#define AV_MMF_CONTENTS_TYPE_1 0x10
+#define AV_MMF_CONTENTS_TYPE_2 0x20
+#define AV_MMF_CONTENTS_TYPE_3 0x30
+#define AV_MMF_CONTENTS_TYPE_4 0x40
+#define AV_MMF_CONTENTS_TYPE_5 0x50
+
+
+#define AVMASMW_SUCCESS (0) /* success */
+#define AVMASMW_ERROR (-1) /* error */
+#define AVMASMW_ERROR_ARGUMENT (-2) /* error of arguments */
+#define AVMASMW_ERROR_RESOURCE_OVER (-3) /* over specified resources */
+#define AVMASMW_ERROR_ID (-4) /* error id number */
+#define AVMASMW_ERROR_TIMEOUT (-5) /* timeout */
+#define AVMASMW_ERROR_SOFTRESET (-6) /* error of soft reset for MA-5 */
+
+#define AVMASMW_ERROR_FILE (-16) /* file error */
+#define AVMASMW_ERROR_CONTENTS_CLASS (-17) /* SAVMAF Contents Class shows can't play */
+#define AVMASMW_ERROR_CONTENTS_TYPE (-18) /* SAVMAF Contents Type shows can't play */
+#define AVMASMW_ERROR_CHUNK_SIZE (-19) /* illegal SMAF Chunk Size value */
+#define AVMASMW_ERROR_CHUNK (-20) /* illegal SMAF Track Chunk value */
+#define AVMASMW_ERROR_UNMATCHED_TAG (-21) /* unmathced specified TAG */
+#define AVMASMW_ERROR_SHORT_LENGTH (-22) /* short sequence */
+#define AVMASMW_ERROR_LONG_LENGTH (-23) /* long sequence */
+#define AVMASMW_ERROR_UNSUPPORTED (-24) /* unsupported format */
+#define AVMASMW_ERROR_NO_INFORMATION (-25) /* no specified information */
+#define AVMASMW_ERROR_HV_CONFLICT (-26) /* conflict about HV resource */
+
+#define AVMALIB_MAKEDWORD(a, b, c, d) (unsigned int)(((unsigned int)(a) << 24) | \
+ ((unsigned int)(b) << 16) | ((unsigned int)(c) << 8) | (unsigned int)(d))
+
+/****************************************************************************
+ * define
+ ****************************************************************************/
+#define AVMALIB_SIZE_OF_CHUNKHEADER (8)
+#define AVMALIB_SIZE_OF_CRC (2)
+#define AVMALIB_SIZE_OF_MIN_CNTI (5)
+/* for Phrase */
+#define AVMALIB_CNTI_CLASS_YAMAHA (0x00)
+#define AVMALIB_CNTI_TYPE_PHRASE (0xF0)
+#define AVMALIB_PHRASE_TIMEBASE (20)
+
+/* Chunk ID */
+#define AVMALIB_CHUNKID_MMMD 0x4D4D4D44
+#define AVMALIB_CHUNKID_CNTI 0x434E5449
+#define AVMALIB_CHUNKID_OPDA 0x4F504441
+#define AVMALIB_CHUNKID_DCH 0x44636800
+#define AVMALIB_CHUNKID_M5P 0x50726F00
+#define AVMALIB_CHUNKID_MTR 0x4D545200
+#define AVMALIB_CHUNKID_MSPI 0x4D737049
+#define AVMALIB_CHUNKID_MTSU 0x4D747375
+#define AVMALIB_CHUNKID_MTSQ 0x4D747371
+#define AVMALIB_CHUNKID_MTSP 0x4D747370
+#define AVMALIB_CHUNKID_MWA 0x4D776100
+#define AVMALIB_CHUNKID_ATR 0x41545200
+#define AVMALIB_CHUNKID_ASPI 0x41737049
+#define AVMALIB_CHUNKID_ATSU 0x41747375
+#define AVMALIB_CHUNKID_ATSQ 0x41747371
+#define AVMALIB_CHUNKID_AWA 0x41776100
+#define AVMALIB_CHUNKID_MTHV 0x4D746876
+#define AVMALIB_CHUNKID_MHVS 0x4D687673
+#define AVMALIB_CHUNKID_HVP 0x48565000
+#define AVMALIB_CHUNKID_MHSC 0x4D687363
+
+/****************************************************************************
+ * table
+ ****************************************************************************/
+static const unsigned short g_crc_tbl[256] = {
+ 0x0000U,0x1021U,0x2042U,0x3063U,0x4084U,0x50A5U,0x60C6U,0x70E7U,
+ 0x8108U,0x9129U,0xA14AU,0xB16BU,0xC18CU,0xD1ADU,0xE1CEU,0xF1EFU,
+ 0x1231U,0x0210U,0x3273U,0x2252U,0x52B5U,0x4294U,0x72F7U,0x62D6U,
+ 0x9339U,0x8318U,0xB37BU,0xA35AU,0xD3BDU,0xC39CU,0xF3FFU,0xE3DEU,
+ 0x2462U,0x3443U,0x0420U,0x1401U,0x64E6U,0x74C7U,0x44A4U,0x5485U,
+ 0xA56AU,0xB54BU,0x8528U,0x9509U,0xE5EEU,0xF5CFU,0xC5ACU,0xD58DU,
+ 0x3653U,0x2672U,0x1611U,0x0630U,0x76D7U,0x66F6U,0x5695U,0x46B4U,
+ 0xB75BU,0xA77AU,0x9719U,0x8738U,0xF7DFU,0xE7FEU,0xD79DU,0xC7BCU,
+ 0x48C4U,0x58E5U,0x6886U,0x78A7U,0x0840U,0x1861U,0x2802U,0x3823U,
+ 0xC9CCU,0xD9EDU,0xE98EU,0xF9AFU,0x8948U,0x9969U,0xA90AU,0xB92BU,
+ 0x5AF5U,0x4AD4U,0x7AB7U,0x6A96U,0x1A71U,0x0A50U,0x3A33U,0x2A12U,
+ 0xDBFDU,0xCBDCU,0xFBBFU,0xEB9EU,0x9B79U,0x8B58U,0xBB3BU,0xAB1AU,
+ 0x6CA6U,0x7C87U,0x4CE4U,0x5CC5U,0x2C22U,0x3C03U,0x0C60U,0x1C41U,
+ 0xEDAEU,0xFD8FU,0xCDECU,0xDDCDU,0xAD2AU,0xBD0BU,0x8D68U,0x9D49U,
+ 0x7E97U,0x6EB6U,0x5ED5U,0x4EF4U,0x3E13U,0x2E32U,0x1E51U,0x0E70U,
+ 0xFF9FU,0xEFBEU,0xDFDDU,0xCFFCU,0xBF1BU,0xAF3AU,0x9F59U,0x8F78U,
+ 0x9188U,0x81A9U,0xB1CAU,0xA1EBU,0xD10CU,0xC12DU,0xF14EU,0xE16FU,
+ 0x1080U,0x00A1U,0x30C2U,0x20E3U,0x5004U,0x4025U,0x7046U,0x6067U,
+ 0x83B9U,0x9398U,0xA3FBU,0xB3DAU,0xC33DU,0xD31CU,0xE37FU,0xF35EU,
+ 0x02B1U,0x1290U,0x22F3U,0x32D2U,0x4235U,0x5214U,0x6277U,0x7256U,
+ 0xB5EAU,0xA5CBU,0x95A8U,0x8589U,0xF56EU,0xE54FU,0xD52CU,0xC50DU,
+ 0x34E2U,0x24C3U,0x14A0U,0x0481U,0x7466U,0x6447U,0x5424U,0x4405U,
+ 0xA7DBU,0xB7FAU,0x8799U,0x97B8U,0xE75FU,0xF77EU,0xC71DU,0xD73CU,
+ 0x26D3U,0x36F2U,0x0691U,0x16B0U,0x6657U,0x7676U,0x4615U,0x5634U,
+ 0xD94CU,0xC96DU,0xF90EU,0xE92FU,0x99C8U,0x89E9U,0xB98AU,0xA9ABU,
+ 0x5844U,0x4865U,0x7806U,0x6827U,0x18C0U,0x08E1U,0x3882U,0x28A3U,
+ 0xCB7DU,0xDB5CU,0xEB3FU,0xFB1EU,0x8BF9U,0x9BD8U,0xABBBU,0xBB9AU,
+ 0x4A75U,0x5A54U,0x6A37U,0x7A16U,0x0AF1U,0x1AD0U,0x2AB3U,0x3A92U,
+ 0xFD2EU,0xED0FU,0xDD6CU,0xCD4DU,0xBDAAU,0xAD8BU,0x9DE8U,0x8DC9U,
+ 0x7C26U,0x6C07U,0x5C64U,0x4C45U,0x3CA2U,0x2C83U,0x1CE0U,0x0CC1U,
+ 0xEF1FU,0xFF3EU,0xCF5DU,0xDF7CU,0xAF9BU,0xBFBAU,0x8FD9U,0x9FF8U,
+ 0x6E17U,0x7E36U,0x4E55U,0x5E74U,0x2E93U,0x3EB2U,0x0ED1U,0x1EF0U
+};
+
+/* phase */
+#define AVMALIB_CHUNK_PHASE_MMMD 0
+#define AVMALIB_CHUNK_PHASE_CNTI 1
+#define AVMALIB_CHUNK_PHASE_MMMDSUB 2
+#define AVMALIB_CHUNK_PHASE_MTRSUB 3
+#define AVMALIB_CHUNK_PHASE_ATRSUB 4
+#define AVMALIB_CHUNK_PHASE_OPDASUB 5
+#define AVMALIB_CHUNK_PHASE_MTSPSUB 6
+#define AVMALIB_CHUNK_PHASE_MTHVSUB 7
+
+/* return value */
+#define AVMALIB_CHUNKCODE_MMMD 0x00
+#define AVMALIB_CHUNKCODE_CNTI 0x01
+#define AVMALIB_CHUNKCODE_OPDA 0x02
+#define AVMALIB_CHUNKCODE_DCH 0x20
+#define AVMALIB_CHUNKCODE_M5P 0x21
+#define AVMALIB_CHUNKCODE_MTR 0x03
+#define AVMALIB_CHUNKCODE_MSPI 0x30
+#define AVMALIB_CHUNKCODE_MTSU 0x31
+#define AVMALIB_CHUNKCODE_MTSQ 0x32
+#define AVMALIB_CHUNKCODE_MTSP 0x33
+#define AVMALIB_CHUNKCODE_MWA 0x3F
+#define AVMALIB_CHUNKCODE_ATR 0x04
+#define AVMALIB_CHUNKCODE_ASPI 0x40
+#define AVMALIB_CHUNKCODE_ATSU 0x41
+#define AVMALIB_CHUNKCODE_ATSQ 0x42
+#define AVMALIB_CHUNKCODE_AWA 0x43
+
+#define AVMALIB_CHUNKCODE_MTHV 0x35
+#define AVMALIB_CHUNKCODE_MHVS 0x36
+#define AVMALIB_CHUNKCODE_HVP 0x37
+#define AVMALIB_CHUNKCODE_MHSC 0x38
+
+#define AVMALIB_CHUNKCODE_UNKNOWN 0xFF
+
+#define AVMALIB_CHUNK_ID_ERROR -1
+#define AVMALIB_CHUNK_SIZE_ERROR -2
+
+#define AV_MMF_MAX_TRACK_NUM 8
+#define AV_MMF_MAX_PHRASE_INFO 7
+#define AV_MMF_MAX_EVENT_NUM 10
+#define AV_MMF_MAX_NOTE_OFF_NUM 256
+#define AV_MMF_MAX_STREAM_DATA_NUM2 62
+#define AV_MMF_MAX_STREAM_DATA_NUM3 32
+#define AV_MMF_MAX_VOICE_DATA_NUM2 16
+#define AV_MMF_MAX_WAVE_DATA_NUM3 127
+#define AV_MMF_CHANNEL_NUM 16
+
+#define AV_MMF_FUNC_SUCCESS AVMASMW_SUCCESS
+#define AV_MMF_FUNC_ERROR AVMASMW_ERROR
+
+#define AV_MMF_ERR_ARGUMENT AVMASMW_ERROR_ARGUMENT
+#define AV_MMF_ERR_FILE AVMASMW_ERROR_FILE
+#define AV_MMF_ERR_CLASS AVMASMW_ERROR_CONTENTS_CLASS
+#define AV_MMF_ERR_TYPE AVMASMW_ERROR_CONTENTS_TYPE
+#define AV_MMF_ERR_SIZE AVMASMW_ERROR_CHUNK_SIZE
+#define AV_MMF_ERR_CHUNK AVMASMW_ERROR_CHUNK
+#define AV_MMF_ERR_NOTAG AVMASMW_ERROR_UNMATCHED_TAG
+#define AV_MMF_ERR_SLENGTH AVMASMW_ERROR_SHORT_LENGTH
+#define AV_MMF_ERR_LLENGTH AVMASMW_ERROR_LONG_LENGTH
+#define AV_MMF_ERR_NODATA AVMASMW_ERROR_NO_INFORMATION
+
+#define AV_MMF_SEQ_ID_NULL -1
+
+#define AV_MMF_STATUS_IDLE 0
+#define AV_MMF_STATUS_SAT_PROFILE 1
+#define AV_MMF_STATUS_LOADED 2
+
+#define AV_MMF_CRC_NULL 0xFFFF0000
+#define AV_MMF_POSITION_OF_CCLASS 16
+#define AV_MMF_POSITION_OF_CTYPE 17
+#define AV_MMF_STSP_OFFSET_NULL 0xFFFFFFFF
+#define AV_MMF_STSP_TIME_NULL 0xFFFFFFFF
+#define AV_MMF_CHUNK_HEADER_SIZE 8
+#define AV_MMF_FILE_CRC_SIZE 2
+#define AV_MMF_ATR_TRACK_NO AV_MMF_MAX_TRACK_NUM - 1
+#define AV_MMF_MINIMUM_TRACKSIZE2 6
+#define AV_MMF_MINIMUM_TRACKSIZE3 20
+#define AV_MMF_PLAY_TIME_MIN 20
+#define AV_MMF_PLAY_TIME_MAX 0x00200000
+#define AV_MMF_MA2_VOICE_NOTFOUND 0
+#define AV_MMF_MA2_VOICE_FOUND 1
+#define AV_MMF_FM_VOICE_MODE_4OP 0
+#define AV_MMF_FM_VOICE_MODE_2OP 1
+
+#define AV_MMF_STREAM_ID_INI 0xFF
+#define AV_MMF_STREAM_ID_REGIST 0x00
+#define AV_MMF_MA2_VOICE_NULL 0xFF
+#define AV_MMF_MA3_WAVE_NULL 0xFF
+
+
+
+#define AV_MMF_HUFFMAN_TREE_FAILURE 0
+#define AV_MMF_HUFFMAN_TREE_SUCCESS 1
+
+#define AV_MMF_PHRAZE_SIZE_A 8
+#define AV_MMF_PHRAZE_SIZE_B 12
+
+#define AV_MMF_TAG_STARTPOINT 0x7374
+#define AV_MMF_TAG_STOPPOINT 0x7370
+#define AV_MMF_TAG_PHRASE_A 0x5041
+#define AV_MMF_TAG_PHRASE_B 0x5042
+#define AV_MMF_TAG_PHRASE_E 0x5045
+#define AV_MMF_TAG_PHRASE_I 0x5049
+#define AV_MMF_TAG_PHRASE_K 0x504B
+#define AV_MMF_TAG_PHRASE_R 0x5052
+#define AV_MMF_TAG_PHRASE_S 0x5053
+
+#define AV_MMF_SMAF_TYPE_NULL 0
+#define AV_MMF_SMAF_TYPE_MA1 1
+#define AV_MMF_SMAF_TYPE_MA2 2
+#define AV_MMF_SMAF_TYPE_MA3 3
+#define AV_MMF_SMAF_TYPE_MA5 5
+
+#define AV_MMF_FM_MODE_2OP32 0
+#define AV_MMF_FM_MODE_4OP16 1
+#define AV_MMF_P_SOUNDSET_GMX 0
+#define AV_MMF_P_SOUNDSET_GML1 2
+#define AV_MMF_WT_VOLUME_MA3 0
+#define AV_MMF_WT_VOLUME_MA5 4
+
+#define AV_MMF_RESOUCE_MODE_MA3 2
+#define AV_MMF_RESOUCE_MODE_MA12 3
+#define AV_MMF_RESOUCE_MODE_MA5 4
+#define AV_MMF_RESOUCE_MODE_MA5_64 5
+
+#define AV_MMF_SEQUENCETYPE_DERAYED 0
+#define AV_MMF_AL_CHANNEL_NULL 0xFF
+#define AV_MMF_HV_CHANNEL_NULL 16
+
+
+#define AV_MMF_BANK_NUMBER_DEF 0
+#define AV_MMF_PROGRAM_NUMBER_DEF 0
+#define AV_MMF_RESONANCE_DEF 0x40
+#define AV_MMF_BRIGHTNESS_DEF 0x40
+
+#define AV_MMF_SETVOLUME_3RD_PARAM 0x07
+
+#define AV_MMF_LED_SEQ_SYNC_OFF 0
+#define AV_MMF_LED_SEQ_SYNC_ON 1
+#define AV_MMF_VIB_SEQ_SYNC_OFF 0
+#define AV_MMF_VIB_SEQ_SYNC_ON 1
+#define AV_MMF_KEYCONTROL_ON 2
+#define AV_MMF_KEYCONTROL_OFF 1
+#define AV_MMF_KEYCONTROL_DEFAULT 0
+
+#define AV_MMF_EVNET_EOS 0xFF
+
+#define AV_MMF_CHANNEL_MODE_POLY 0
+#define AV_MMF_CHANNEL_MODE_MONO 1
+
+#define AV_MMF_BANK_NUMBER_DEF 0
+#define AV_MMF_PROGRAM_NUMBER_DEF 0
+#define AV_MMF_RPN_DEF 0x7F
+#define AV_MMF_MODULATION_DEF 0
+#define AV_MMF_CHANNEL_VOLUME_DEF 100
+#define AV_MMF_CHANNEL_PAN_DEF 0x40
+#define AV_MMF_EXPRESSION_DEF 0x7F
+#define AV_MMF_HOLD_DEF 0
+#define AV_MMF_MONO_POLY_MODE_DEF AV_MMF_CHANNEL_MODE_POLY
+#define AV_MMF_PITCH_BEND_DEF 0x40
+#define AV_MMF_BEND_RANGE_DEF 2
+#define AV_MMF_OCTAVE_SHIFT_DEF 4
+#define AV_MMF_VELOCITY_DEF_MA3 90
+#define AV_MMF_VELOCITY_DEF_MA5 100
+#define AV_MMF_BLOCK_FNUM_DEF 0
+#define AV_MMF_STREAM_PAIR_DEF 0xFF
+#define AV_MMF_STREAM_PAN_DEF 0xFF
+#define AV_MMF_STREAM_PAN_OFF 0x80
+
+#define SNDDRV_DEF_STREAM_PAN 255
+#define SNDDRV_DEF_RESONANCE 64
+#define SNDDRV_DEF_BRIGHTNESS 64
+#define SNDDRV_DEF_CHANNEL_VOLUME 100
+#define SNDDRV_DEF_CHANNEL_PANPOT 64
+#define SNDDRV_DEF_EXPRESSION 127
+#define SNDDRV_DEF_BENDRANGE 2
+#define SNDDRV_DEF_PITCHBEND 0x2000
+
+#define AV_MMF_CONVERT_PHASE_PLAY 0x00000000
+#define AV_MMF_CONVERT_PHASE_SEEK_G 0x00010000
+#define AV_MMF_CONVERT_PHASE_SEEK_C 0x00020000
+#define AV_MMF_CONVERT_PHASE_SEEK_END 0x00030000
+#define AV_MMF_CONVERT_PHASE_PLAY_END 0x00FF0000
+
+#define AV_MMF_SEEK_EVENT_END 0xFFFF
+
+/****************************************************************************
+ * definition of resources
+ ****************************************************************************/
+#define AVMAPLIB_MAX_LV2_VOICES (16)
+
+/****************************************************************************
+ * typedef
+ ****************************************************************************/
+
+/* OPDA infomation structure */
+typedef struct AvTagOptionInfo
+{
+ unsigned char *pbCnti; /* pointer to CNTI Body */
+ unsigned int dCntiSize; /* size of CNTI Body */
+ unsigned char *pbOpda; /* pointer to OPDA Body */
+ unsigned int dOpdaSize; /* size of OPDA Body */
+} OPTIONINFO, *POPTIONINFO;
+
+/* Track information structure */
+typedef struct AvTagTrackInfo
+{
+ unsigned char *pbMtr; /* pointer to MTR(ATR) Body */
+ unsigned int dMtrSize; /* size of MTR(ATR) Body */
+ unsigned char *pbMspi; /* pointer to MspI(AspI) Body */
+ unsigned int dMspiSize; /* size of MspI(AspI) Body */
+ unsigned char *pbMtsu; /* pointer to Mtsu Body */
+ unsigned int dMtsuSize; /* size of Mtsu Body */
+ unsigned char *pbMtsq; /* pointer to Mtsq(Atsq) Body */
+ unsigned int dMtsqSize; /* size of Mtsq(Atsq) Body */
+ unsigned char *pbMtsp; /* pointer to Mtsp Body */
+ unsigned int dMtspSize; /* size of Mtsp Body */
+ unsigned char *pbMthv; /* pointer to Mthv Body */
+ unsigned int dMthvSize; /* size of Mthv Body */
+ unsigned int dPlayTime; /* play time (tick) */
+ unsigned int dTimeBase; /* time base (msec/tick) */
+ unsigned int dStartPoint; /* start point(offset) */
+ unsigned int dStopPoint; /* stop point(offset) */
+ unsigned int dStartTick; /* start point(tick) */
+ unsigned int dStopTick; /* stop point(tick) */
+} TRACKINFO, *PTRACKINFO;
+
+/* Phrase information structure */
+typedef struct AvTagPhraseInfo
+{
+ unsigned int dStartPoint; /* start point of phrase(offset) */
+ unsigned int dStopPoint; /* stop point of phrase(offset) */
+ unsigned int dStartTick; /* start point of phrase(tick) */
+ unsigned int dStopTick; /* stop point of phrase(tick) */
+} PHRASEINFO, *PPHRASEINFO;
+
+/* Huffman information structure */
+typedef struct AvTagHuffmanInfo
+{
+ unsigned int dMtsqSize; /* size of Mtsq(Atsq) Body */
+ unsigned int dSeqSize; /* size of sequence data */
+ unsigned int dReadSize; /* read data size */
+ short swLeft[512]; /* Huffman Tree (Left) */
+ short swRight[512]; /* Huffman Tree (Right) */
+ unsigned char *psBuffer; /* pointer to reference area */
+ char sbBitC; /* counter of reference bit */
+ unsigned char bByte; /* value of reference byte */
+ unsigned char *psFBuf; /* pointer to sequence data top */
+ char sbFBit; /* counter of sequence data top bit */
+ unsigned char bFByte ; /* value of sequence data top byte */
+} HUFFMANINFO, *PHUFFMANINFO;
+
+/* HV information structure */
+typedef struct AvTagHvInfo
+{
+ unsigned char *pbVoice; /* pointer to HVP0 chunk header */
+ unsigned int dVoiceSize; /* size of HV voice parameter */
+ unsigned char *pbScript; /* pointer to Mhsc body */
+ unsigned int dScriptSize; /* size of Mhsc body */
+ unsigned char bHvChannel; /* HV channel # */
+} HVINFO, *PHVINFO;
+
+
+/* Load information structure */
+typedef struct AvTagLoadInfo
+{
+ unsigned char *pbMmmd; /* pointer to MMMD top */
+ unsigned int dMmmdSize; /* size of MMMD (whole) */
+ unsigned int dCrc; /* file CRC */
+ unsigned int dSmafType; /* SMAF Type */
+ unsigned int dPlayTime; /* play time (tick) */
+ unsigned int dStartTime; /* start time (start point tick) */
+ unsigned int dTimeBase; /* time base (msec/tick) */
+ unsigned char (*pfnGetByte)(PHUFFMANINFO psHuf);
+ OPTIONINFO sOption_Info;
+ TRACKINFO sTrack_Info[AV_MMF_MAX_TRACK_NUM];
+ PHRASEINFO sPhrase_Info[AV_MMF_MAX_PHRASE_INFO];
+ HUFFMANINFO sHuffman_Info;
+ HVINFO sHV_Info;
+} LOADINFO, *PLOADINFO;
+
+/* Stream information structure(for MA-2) */
+typedef struct AvTagStreamInfo2
+{
+ unsigned char bStrmID; /* key number of stream */
+ unsigned char *pbWave; /* pointer to Awa body */
+ unsigned int dWaveSize; /* size of Awa body */
+ unsigned int dFs; /* sampling frequency */
+} STREAMINFO2, *PSTREAMINFO2;
+
+/* Stream information structure(for MA-3/5) */
+typedef struct AvTagStreamInfo3
+{
+ unsigned char fbNote; /* stream data flag */
+ unsigned char bPairID; /* stream pair ID */
+ unsigned char bPan; /* stream pan */
+} STREAMINFO3, *PSTREAMINFO3;
+
+/* Stream information structure */
+typedef struct AvTagStreamInfo
+{
+ STREAMINFO2 sStream_Info2[AV_MMF_MAX_STREAM_DATA_NUM2];
+ STREAMINFO3 sStream_Info3[AV_MMF_MAX_STREAM_DATA_NUM3];
+} STREAMINFO, *PSTREAMINFO;
+
+/* Voice information structure(for MA-1/2) */
+typedef struct AvTagVoiceInfo2
+{
+ unsigned char bBank; /* bank number */
+ unsigned char bProg; /* program number */
+} VOICEINFO2, *PVOICEINFO2;
+
+/* Wave information structure(for MA-3/5) */
+typedef struct AvTagWaveInfo3
+{
+ unsigned int dAdrs; /* wave address */
+ unsigned int dSize; /* wave data size */
+} WAVEINFO3, *PWAVEINFO3;
+
+/* Voice information structure */
+typedef struct AvTagVoiceInfo
+{
+ VOICEINFO2 sVoice_Info2[AV_MMF_MAX_VOICE_DATA_NUM2];
+ WAVEINFO3 sWave_Info3[AV_MMF_MAX_WAVE_DATA_NUM3];
+} VOICEINFO, *PVOICEINFO;
+
+/* Channel information structure */
+typedef struct AvTagChannelInfo
+{
+ unsigned char bBankM; /* bank select MSB */
+ unsigned char bBankL; /* bank select LSB */
+ unsigned char bBank; /* bank number (sound driver) */
+ unsigned char bProg; /* program change */
+ unsigned char bRpnM; /* RPN MSB */
+ unsigned char bRpnL; /* RPN LSB */
+ unsigned char bMod; /* modulation */
+ unsigned char bChVol; /* channel volume */
+ unsigned char bPan; /* channel pan */
+ unsigned char bExp; /* expression */
+ unsigned char bHold; /* hold */
+ unsigned char bMono; /* channel mode mono/poly */
+ unsigned char bPitch; /* pitch bend (MSB) */
+ unsigned char bSens1; /* pitch bend lenge 1 */
+ unsigned char bSens2; /* pitch bend lenge 2 */
+ unsigned char bOct; /* octerve shift */
+ unsigned char bVel; /* note on velocity */
+ unsigned char bBlockFnum1; /* ma-2 pitch bend (0xB0) */
+ unsigned char bBlockFnum2; /* ma-2 pitch bend (0xC0) */
+ unsigned char fbLed; /* LED synchronous flag */
+ unsigned char fbVib; /* Motor synchronous flag */
+} CHANNELINFO, *PCHANNELINFO;
+
+/* Event information structure */
+typedef struct AvTagEventBlock
+{
+ unsigned int dEventTime; /* event activation time */
+ unsigned int dSeqID; /* sequencer ID (sound driver) */
+ unsigned int dCmd; /* command ID (sound driver) */
+ unsigned int dParam1; /* parameter 1 */
+ unsigned int dParam2; /* parameter 2 */
+ unsigned int dParam3; /* parameter 3 */
+ unsigned char *pbSeq; /* pointer to next event data */
+ unsigned int dIndex; /* index of next event */
+ unsigned int dTrackNo; /* track no. */
+ void * pvNext; /* pointer to next event block */
+} EVENTBLOCK, *PEVENTBLOCK;
+
+/* Note OFF information structure */
+typedef struct AvTagNoteOffBlock
+{
+ unsigned int dOffTime; /* note off activation time */
+ unsigned int dSeqID; /* sequencer ID (sound driver) */
+ unsigned int dCmd; /* command ID (sound driver) */
+ unsigned int dCh; /* channel no. */
+ unsigned int dKey; /* key no. */
+ void * pvNext; /* pointer to next note off block */
+} OFFBLOCK, *POFFBLOCK;
+
+/* Playback information structure */
+typedef struct AvTagPlayInfo
+{
+ PEVENTBLOCK psNextEvent; /* pointer to next event block */
+ PEVENTBLOCK psEmptyEvent; /* pointer to empty event block */
+ POFFBLOCK psNextOff; /* pointer to next note off block */
+ POFFBLOCK psEmptyOff; /* pointer to empty note off block */
+ unsigned int dSmafType; /* SMAF Type */
+ unsigned int dHWTimeBase; /* tick to H/W time base */
+ unsigned int dPlayTime; /* play time (tick) */
+ unsigned int dStartTime; /* start time (start point tick) */
+ unsigned int dSeekTime; /* seek time (msec) */
+ unsigned int dSeekError; /* seek time error (msec) */
+ unsigned int dRamAdrs; /* ram address */
+ unsigned int dRamSize; /* ram size */
+ unsigned int dSeekParam; /* seek event flag */
+ unsigned int dPastTime; /* past time (tick) */
+ unsigned char bMasterVol; /* master volume (sequence) */
+ unsigned char bEos; /* EOS flag */
+ unsigned short fwMono; /* channel mode change flag */
+ unsigned char bResonance; /* resonance */
+ unsigned char bBrightness; /* brightness */
+ unsigned char bStreamReserve; /* stream reserve */
+ unsigned char bAlChReserve; /* AL channel number */
+ unsigned char bHVChannel; /* HV channel number */
+ unsigned char bFmVoice; /* FM Voice Mode 0:4op, 1:2op */
+ unsigned char (*pfnGetByte)(void); /* pointer to byte get function */
+ int (*pfnGetEvent)(void); /* pointer to event get function */
+ STREAMINFO sStream_Info;
+ VOICEINFO sVoice_Info;
+ CHANNELINFO sChannel_Info[AV_MMF_CHANNEL_NUM + 1];
+ EVENTBLOCK sEvent_Block[AV_MMF_MAX_EVENT_NUM];
+ OFFBLOCK sNoteOff_Block[AV_MMF_MAX_NOTE_OFF_NUM];
+} PLAYINFO, *PPLAYINFO;
+
+/* SMAF information structure */
+typedef struct AvTagSmafInfo
+{
+ int sdMmfSeqID; /* sequence id (sound driver) */
+ unsigned int dStatus; /* converter status */
+ LOADINFO sLoad_Info[2];
+ PLAYINFO sPlay_Info;
+} SMAFINFO, *PSMAFINFO;
+
+static SMAFINFO g_sSmaf_Info;
+static const unsigned char g_abBitMaskTable1[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
+static const unsigned short g_awBitMaskTable2[8] = {0x00FF, 0x01FE, 0x03FC, 0x07F8, 0x0FF0, 0x1FE0, 0x3FC0, 0x7F80};
+static const unsigned char g_abTableA[16] = {0, 1, 1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15};
+static const unsigned char g_abTableD[16] = {0, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14};
+static const unsigned char g_abExpression2[16] = {0x80,0x00,0x1f,0x27,0x2f,0x37,0x3f,0x47,0x4f,0x57,0x5f,0x67,0x6f,0x77,0x7f,0x80};
+static const unsigned char g_abModulation2[16] = {0x80,0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38,0x40,0x48,0x50,0x60,0x70,0x7f,0x80};
+
+/**
+ * Define.
+ */
+#define MMF_FILE_MMF_HEADER_LEN 18
+
+#define MMF_FILE_MMF_MAGIC_STR_LEN 4
+#define MMF_FILE_MMF_MAGIC_STR "MMMD"
+
+#define MMF_FILE_MMF_TYPE_POSITION ((char)0x11)
+
+
+
+/* internals */
+static int mmf_file_mmf_get_duration (char *src, int is_xmf);
+
+
+
+/* mm plugin porting */
+/* plugin manadatory API */
+int mmfile_format_read_stream_mmf (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_mmf (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_mmf (MMFileFormatContext *formatContext);
+int mmfile_format_close_mmf (MMFileFormatContext *formatContext);
+
+
+EXPORT_API
+int mmfile_format_open_mmf (MMFileFormatContext *formatContext)
+{
+ int ret = 0;
+
+ if (NULL == formatContext) {
+ debug_error ("error: formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->pre_checked == 0) {
+ ret = MMFileFormatIsValidMMF (formatContext->uriFileName);
+ if (ret == 0) {
+ debug_error ("error: it is not MMF file\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+ }
+
+ formatContext->ReadStream = mmfile_format_read_stream_mmf;
+ formatContext->ReadFrame = mmfile_format_read_frame_mmf;
+ formatContext->ReadTag = mmfile_format_read_tag_mmf;
+ formatContext->Close = mmfile_format_close_mmf;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_stream_mmf (MMFileFormatContext *formatContext)
+{
+ int total = 0;
+
+ total = mmf_file_mmf_get_duration (formatContext->uriFileName, 0 /*not XMF*/);
+ if ( total < 0 )
+ {
+ debug_error ("error: get duration\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+
+ formatContext->duration = total;
+ formatContext->audioTotalTrackNum = 1;
+ formatContext->nbStreams = 1;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = mmfile_malloc (sizeof(MMFileFormatStream));
+ if (NULL == formatContext->streams[MMFILE_AUDIO_STREAM])
+ {
+ debug_error ("error: mmfile_malloc, audido stream\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId =MM_AUDIO_CODEC_MMF;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->nbChannel = 1;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_frame_mmf (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_tag_mmf (MMFileFormatContext *formatContext)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_close_mmf (MMFileFormatContext *formatContext)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_Get4Byte
+ *
+ * Description:
+ * SMAF data load (error check and regist)
+ * Argument:
+ * pbBuf pointer to top data
+ * Return:
+ * nothing
+ ********************************************************************************/
+static unsigned int
+_mmf_Get4Byte(unsigned char* pbBuf)
+{
+ return (unsigned int)( (((unsigned int)pbBuf[0]) << 24) +
+ (((unsigned int)pbBuf[1]) << 16) +
+ (((unsigned int)pbBuf[2]) << 8) +
+ ((unsigned int)pbBuf[3]));
+}
+
+
+/*********************************************************************************
+ * _mmf_CheckInitial
+ *
+ * Description:
+ * SMAF data load (error check and regist)
+ * Argument:
+ * psLoad pointer to load information structure
+ * Return:
+ * nothing
+ ********************************************************************************/
+static void
+_mmf_CheckInitial(PLOADINFO psLoad)
+{
+ unsigned char i;
+
+/* Initialize Load information structure */
+ psLoad->pbMmmd = NULL;
+ psLoad->dMmmdSize = 0;
+ psLoad->dCrc = AV_MMF_CRC_NULL;
+ psLoad->dSmafType = AV_MMF_SMAF_TYPE_NULL;
+ psLoad->dPlayTime = 0;
+ psLoad->dStartTime = 0;
+ psLoad->dTimeBase = 0;
+ psLoad->pfnGetByte = NULL;
+
+ psLoad->sOption_Info.pbCnti = NULL;
+ psLoad->sOption_Info.dCntiSize = 0;
+ psLoad->sOption_Info.pbOpda = NULL;
+ psLoad->sOption_Info.dOpdaSize = 0;
+
+ for ( i = 0; i < AV_MMF_MAX_TRACK_NUM; i++)
+ {
+ psLoad->sTrack_Info[i].pbMtr = NULL;
+ psLoad->sTrack_Info[i].dMtrSize = 0;
+ psLoad->sTrack_Info[i].pbMspi = NULL;
+ psLoad->sTrack_Info[i].dMspiSize = 0;
+ psLoad->sTrack_Info[i].pbMtsu = NULL;
+ psLoad->sTrack_Info[i].dMtsuSize = 0;
+ psLoad->sTrack_Info[i].pbMtsq = NULL;
+ psLoad->sTrack_Info[i].dMtsqSize = 0;
+ psLoad->sTrack_Info[i].pbMtsp = NULL;
+ psLoad->sTrack_Info[i].dMtspSize = 0;
+ psLoad->sTrack_Info[i].pbMthv = NULL;
+ psLoad->sTrack_Info[i].dMthvSize = 0;
+ psLoad->sTrack_Info[i].dPlayTime = 0;
+ psLoad->sTrack_Info[i].dTimeBase = 0;
+ psLoad->sTrack_Info[i].dStartPoint = AV_MMF_STSP_OFFSET_NULL;
+ psLoad->sTrack_Info[i].dStopPoint = AV_MMF_STSP_OFFSET_NULL;
+ psLoad->sTrack_Info[i].dStartTick = AV_MMF_STSP_TIME_NULL;
+ psLoad->sTrack_Info[i].dStopTick = AV_MMF_STSP_TIME_NULL;
+ }
+
+ for ( i = 0; i < AV_MMF_MAX_PHRASE_INFO; i++)
+ {
+ psLoad->sPhrase_Info[i].dStartPoint = AV_MMF_STSP_OFFSET_NULL;
+ psLoad->sPhrase_Info[i].dStopPoint = AV_MMF_STSP_OFFSET_NULL;
+ psLoad->sPhrase_Info[i].dStartTick = AV_MMF_STSP_TIME_NULL;
+ psLoad->sPhrase_Info[i].dStopTick = AV_MMF_STSP_TIME_NULL;
+ }
+
+ psLoad->sHV_Info.pbVoice = NULL;
+ psLoad->sHV_Info.dVoiceSize = 0;
+ psLoad->sHV_Info.pbScript = NULL;
+ psLoad->sHV_Info.dScriptSize = 0;
+ psLoad->sHV_Info.bHvChannel = AV_MMF_HV_CHANNEL_NULL;
+}
+
+
+/*********************************************************************************
+ * _mmf_CheckInitial
+ *
+ * Description:
+ * get time base (data value -> msec/tick)
+ * Argument:
+ * bData time base (data value)
+ * Return:
+ * >=0 success(time base (msec/tick))
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_GetTimebase(unsigned char bData)
+{
+ switch ( bData )
+ {
+ case 0x02: return 4; /* 4[msec/tick] */
+ case 0x03: return 5; /* 5[msec/tick] */
+ case 0x10: return 10; /* 10[msec/tick] */
+ case 0x11: return 20; /* 20[msec/tick] */
+ case 0x12: return 40; /* 40[msec/tick] */
+ case 0x13: return 50; /* 50[msec/tick] */
+ default: return AV_MMF_FUNC_ERROR; /* Time Base Error */
+ }
+}
+
+static int
+_mmf_MalibNextChunk(unsigned char* pbFile, unsigned int dSize, unsigned int dState, unsigned int* pdChunkID, unsigned int* pdChunkNo)
+{
+ unsigned int dChunkID, dChunkSize;
+
+ if (dSize < AVMALIB_SIZE_OF_CHUNKHEADER)
+ return AVMALIB_CHUNK_SIZE_ERROR;
+
+ dChunkID = AVMALIB_MAKEDWORD(pbFile[0], pbFile[1], pbFile[2], pbFile[3]);
+ dChunkSize = AVMALIB_MAKEDWORD(pbFile[4], pbFile[5], pbFile[6], pbFile[7]);
+
+ switch (dChunkID)
+ {
+ case AVMALIB_CHUNKID_MMMD :
+ *pdChunkID = AVMALIB_CHUNKCODE_MMMD;
+ if (dState != AVMALIB_CHUNK_PHASE_MMMD)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_CNTI :
+ *pdChunkID = AVMALIB_CHUNKCODE_CNTI;
+ if (dState != AVMALIB_CHUNK_PHASE_CNTI)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_OPDA :
+ *pdChunkID = AVMALIB_CHUNKCODE_OPDA;
+ if (dState != AVMALIB_CHUNK_PHASE_MMMDSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_MSPI :
+ *pdChunkID = AVMALIB_CHUNKCODE_MSPI;
+ if (dState != AVMALIB_CHUNK_PHASE_MTRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_MTSU :
+ *pdChunkID = AVMALIB_CHUNKCODE_MTSU;
+ if (dState != AVMALIB_CHUNK_PHASE_MTRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_MTSQ :
+ *pdChunkID = AVMALIB_CHUNKCODE_MTSQ;
+ if (dState != AVMALIB_CHUNK_PHASE_MTRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_MTSP :
+ *pdChunkID = AVMALIB_CHUNKCODE_MTSP;
+ if (dState != AVMALIB_CHUNK_PHASE_MTRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_ASPI :
+ *pdChunkID = AVMALIB_CHUNKCODE_ASPI;
+ if (dState != AVMALIB_CHUNK_PHASE_ATRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_ATSU :
+ *pdChunkID = AVMALIB_CHUNKCODE_ATSU;
+ if (dState != AVMALIB_CHUNK_PHASE_ATRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_ATSQ :
+ *pdChunkID = AVMALIB_CHUNKCODE_ATSQ;
+ if (dState != AVMALIB_CHUNK_PHASE_ATRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ case AVMALIB_CHUNKID_MTHV :
+ *pdChunkID = AVMALIB_CHUNKCODE_MTHV;
+ if (dState != AVMALIB_CHUNK_PHASE_MTRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_MHVS :
+ *pdChunkID = AVMALIB_CHUNKCODE_MHVS;
+ if (dState != AVMALIB_CHUNK_PHASE_MTHVSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_MHSC :
+ *pdChunkID = AVMALIB_CHUNKCODE_MHSC;
+ if (dState != AVMALIB_CHUNK_PHASE_MTHVSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ default :
+ *pdChunkNo = (unsigned char)(dChunkID & 0x000000FF);
+ switch (dChunkID & 0xFFFFFF00)
+ {
+ case AVMALIB_CHUNKID_MTR :
+ *pdChunkID = AVMALIB_CHUNKCODE_MTR;
+ if (dState != AVMALIB_CHUNK_PHASE_MMMDSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_ATR :
+ *pdChunkID = AVMALIB_CHUNKCODE_ATR;
+ if (dState != AVMALIB_CHUNK_PHASE_MMMDSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ case AVMALIB_CHUNKID_DCH :
+ *pdChunkID = AVMALIB_CHUNKCODE_DCH;
+ if (dState != AVMALIB_CHUNK_PHASE_OPDASUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+ case AVMALIB_CHUNKID_M5P :
+ *pdChunkID = AVMALIB_CHUNKCODE_M5P;
+ if (dState != AVMALIB_CHUNK_PHASE_OPDASUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ case AVMALIB_CHUNKID_MWA :
+ *pdChunkID = AVMALIB_CHUNKCODE_MWA;
+ if (dState != AVMALIB_CHUNK_PHASE_MTSPSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ case AVMALIB_CHUNKID_AWA :
+ *pdChunkID = AVMALIB_CHUNKCODE_AWA;
+ if (dState != AVMALIB_CHUNK_PHASE_ATRSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ case AVMALIB_CHUNKID_HVP :
+ *pdChunkID = AVMALIB_CHUNKCODE_HVP;
+ if (dState != AVMALIB_CHUNK_PHASE_MTHVSUB)
+ return AVMALIB_CHUNK_ID_ERROR;
+ break;
+
+ default :
+ *pdChunkID = AVMALIB_CHUNKCODE_UNKNOWN;
+ break;
+ }
+ break;
+ }
+
+ if (dChunkSize > (dSize - AVMALIB_SIZE_OF_CHUNKHEADER))
+ return AVMALIB_CHUNK_SIZE_ERROR;
+ else
+ return (int)dChunkSize;
+}
+
+
+
+/*********************************************************************************
+ * _mmf_MTRCheck
+ *
+ * Description:
+ * score track chunk check (header information and chunk construction)
+ * Argument:
+ * psTrack pointer to track information structure
+ * bSmafType SMAF type
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_MTRCheck(PTRACKINFO psTrack, unsigned char bSmafType)
+{
+ int sdResult, sdChunkSize;
+ unsigned int dSize, dIndex;
+ unsigned char* pbBuf;
+ unsigned int dChunkID, dChunkNo;
+
+/* Check Format Type */
+ switch (bSmafType)
+ {
+ case AV_MMF_SMAF_TYPE_MA1 :
+ case AV_MMF_SMAF_TYPE_MA2 :
+ if (psTrack->pbMtr[0] != 0x00)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ case AV_MMF_SMAF_TYPE_MA3 :
+ if ((psTrack->pbMtr[0] != 0x01) && (psTrack->pbMtr[0] != 0x02))
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ case AV_MMF_SMAF_TYPE_MA5 :
+ if (psTrack->pbMtr[0] != 0x02)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ }
+
+/* Check Sequence Type */
+ if (psTrack->pbMtr[1] != 0x00)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+
+/* Check Time Base */
+ if (psTrack->pbMtr[2] != psTrack->pbMtr[3])
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_GetTimebase(psTrack->pbMtr[2]);
+ if (sdResult == AV_MMF_FUNC_ERROR)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psTrack->dTimeBase = (unsigned int)sdResult;
+
+/* Check sub chunk disposition */
+ if ((bSmafType == AV_MMF_SMAF_TYPE_MA1) || (bSmafType == AV_MMF_SMAF_TYPE_MA2))
+ dIndex = AV_MMF_MINIMUM_TRACKSIZE2;
+ else
+ dIndex = AV_MMF_MINIMUM_TRACKSIZE3;
+ pbBuf = psTrack->pbMtr;
+ dSize = psTrack->dMtrSize;
+ while (dSize > (dIndex + AV_MMF_CHUNK_HEADER_SIZE))
+ {
+ sdChunkSize = _mmf_MalibNextChunk(&pbBuf[dIndex], (dSize-dIndex),
+ AVMALIB_CHUNK_PHASE_MTRSUB, &dChunkID, &dChunkNo);
+ if (sdChunkSize < 0)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ switch (dChunkID) {
+ case AVMALIB_CHUNKCODE_MSPI :
+ psTrack->pbMspi = &(pbBuf[dIndex]);
+ psTrack->dMspiSize = sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_MTSU :
+ psTrack->pbMtsu = &(pbBuf[dIndex]);
+ psTrack->dMtsuSize = sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_MTSQ :
+ psTrack->pbMtsq = &(pbBuf[dIndex]);
+ psTrack->dMtsqSize = sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_MTSP :
+ psTrack->pbMtsp = &(pbBuf[dIndex]);
+ psTrack->dMtspSize = sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_MTHV :
+ psTrack->pbMthv = &(pbBuf[dIndex]);
+ psTrack->dMthvSize = sdChunkSize;
+ break;
+ default :
+ break;
+ }
+ dIndex += sdChunkSize;
+ }
+
+ if ((psTrack->pbMtsq == NULL) ||(psTrack->dMtsqSize == 0))
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_ATRCheck
+ *
+ * Description:
+ * audio track chunk check (header information and chunk construction)
+ * Argument:
+ * psTrack pointer to track information structure
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_ATRCheck(PTRACKINFO psTrack)
+{
+ int sdResult, sdChunkSize;
+ unsigned int dSize, dIndex;
+ unsigned char* pbBuf;
+ unsigned int dChunkID, dChunkNo;
+ unsigned char fbWave;
+
+/* Check Format Type */
+ if (psTrack->pbMtr[0] != 0x00)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+
+/* Check Sequence Type */
+ if (psTrack->pbMtr[1] != 0x00)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+
+/* Check Wave Type */
+ if (((psTrack->pbMtr[2] != 0x10) && (psTrack->pbMtr[2] != 0x11)) ||
+ ((psTrack->pbMtr[3] & 0xF0) != 0x00))
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+
+/* Check Time Base */
+ if (psTrack->pbMtr[4] != psTrack->pbMtr[5])
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_GetTimebase(psTrack->pbMtr[4]);
+ if (sdResult == AV_MMF_FUNC_ERROR)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psTrack->dTimeBase = (unsigned int)sdResult;
+
+ pbBuf = psTrack->pbMtr;
+ dSize = psTrack->dMtrSize;
+ dIndex = 6;
+ fbWave = AV_MMF_MA2_VOICE_NULL;
+
+/* Check sub chunk disposition */
+ while (dSize > (dIndex + AV_MMF_CHUNK_HEADER_SIZE))
+ {
+ sdChunkSize = _mmf_MalibNextChunk(&pbBuf[dIndex], (dSize-dIndex),
+ AVMALIB_CHUNK_PHASE_ATRSUB, &dChunkID, &dChunkNo);
+ if (sdChunkSize < 0)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ switch (dChunkID)
+ {
+ case AVMALIB_CHUNKCODE_ASPI :
+ psTrack->pbMspi = &(pbBuf[dIndex]);
+ psTrack->dMspiSize = sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_ATSQ :
+ psTrack->pbMtsq = &(pbBuf[dIndex]);
+ psTrack->dMtsqSize = sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_AWA :
+ if ((0x01 <= dChunkNo) && (dChunkNo <= 0x3E))
+ fbWave = AV_MMF_MA2_VOICE_FOUND;
+ break;
+ default :
+ break;
+ }
+ dIndex += sdChunkSize;
+ }
+
+ if ((psTrack->pbMtsq == NULL) ||(psTrack->dMtsqSize == 0) ||(fbWave == AV_MMF_MA2_VOICE_NULL))
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_MspICheck
+ *
+ * Description:
+ * seek & phrase info chunk check (get phrase information)
+ * Argument:
+ * psTrack pointer to track information structure
+ * psPhrase pointer to phrase information structure
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static void
+_mmf_MspICheck(PTRACKINFO psTrack, PPHRASEINFO psPhrase)
+{
+ unsigned char* pbBuf;
+ unsigned int dSize, dIndex;
+ unsigned short wTag;
+
+ if (psTrack->pbMspi == NULL)
+ return;
+
+ pbBuf = psTrack->pbMspi;
+ dSize = psTrack->dMspiSize;
+ dIndex = 0;
+
+ while (dSize >= dIndex + AV_MMF_PHRAZE_SIZE_A)
+ {
+ wTag = (unsigned short)((((unsigned short)pbBuf[dIndex]) << 8) + (unsigned short)pbBuf[dIndex+1]);
+ switch (wTag) {
+ case AV_MMF_TAG_STARTPOINT : /* start point */
+ psTrack->dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ dIndex += AV_MMF_PHRAZE_SIZE_A;
+ break;
+ case AV_MMF_TAG_STOPPOINT : /* stop point */
+ psTrack->dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ dIndex += AV_MMF_PHRAZE_SIZE_A;
+ break;
+ case AV_MMF_TAG_PHRASE_A : /* A melody */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[0].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[0].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ case AV_MMF_TAG_PHRASE_B : /* B melody */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[1].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[1].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ case AV_MMF_TAG_PHRASE_E : /* Ending */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[2].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[2].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ case AV_MMF_TAG_PHRASE_I : /* Intro */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[3].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[3].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ case AV_MMF_TAG_PHRASE_K : /* Interlude */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[4].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[4].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ case AV_MMF_TAG_PHRASE_R : /* Refrain */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[5].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[5].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ case AV_MMF_TAG_PHRASE_S : /* Bridge */
+ if (dSize < dIndex + AV_MMF_PHRAZE_SIZE_B)
+ return ;
+ psPhrase[6].dStartPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 3]));
+ psPhrase[6].dStopPoint = _mmf_Get4Byte(&(pbBuf[dIndex + 7]));
+ dIndex += AV_MMF_PHRAZE_SIZE_B;
+ break;
+ default :
+ return;
+ }
+ }
+ return;
+}
+
+
+/*********************************************************************************
+ * _mmf_STSPCheck
+ *
+ * Description:
+ * track chunk check (offset of start point and stop point)
+ * Argument:
+ * psTrack pointer to track information structure
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_STSPCheck( PTRACKINFO psTrack)
+{
+ unsigned int dStart, dStop, dSize;
+
+ dSize = psTrack->dMtsqSize;
+
+ if (psTrack->dStartPoint == AV_MMF_STSP_OFFSET_NULL)
+ dStart = 0;
+ else
+ dStart = psTrack->dStartPoint;
+
+ if (psTrack->dStopPoint == AV_MMF_STSP_OFFSET_NULL)
+ dStop = dSize;
+ else
+ dStop = psTrack->dStopPoint;
+
+ if ((dStart >= dStop) || (dStart > dSize) || (dStop > dSize))
+ return AV_MMF_ERR_CHUNK;
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_MtsuCheck2
+ *
+ * Description:
+ * track chunk check (existence voice parameter)
+ * Argument:
+ * psTrack pointer to track information structure
+ * bSmafType SMAF type
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_MtsuCheck2(PTRACKINFO psTrack, unsigned char bSmafType)
+{
+ unsigned char* pbBuf;
+ unsigned int dSize, dIndex;
+
+ if (psTrack->pbMtsu == NULL)
+ {
+ return AV_MMF_MA2_VOICE_NOTFOUND;
+ }
+
+ pbBuf = psTrack->pbMtsu;
+ dSize = psTrack->dMtsuSize;
+ dIndex = 0;
+
+ while (dSize > dIndex + 20)
+ {
+ if ((pbBuf[dIndex] != 0xFF) || (pbBuf[dIndex + 1] != 0xF0))
+ {
+ return AV_MMF_MA2_VOICE_NOTFOUND;
+ }
+ if (pbBuf[dIndex + 3] == 0x43)
+ {
+ if ((bSmafType == AV_MMF_SMAF_TYPE_MA1) && (pbBuf[dIndex + 4] == 0x02))
+ return AV_MMF_MA2_VOICE_FOUND;
+ if ((bSmafType == AV_MMF_SMAF_TYPE_MA2) && (pbBuf[dIndex + 4] == 0x03))
+ return AV_MMF_MA2_VOICE_FOUND;
+ }
+ dIndex += (pbBuf[dIndex + 2] + 3);
+ }
+
+ return AV_MMF_MA2_VOICE_NOTFOUND;
+}
+
+
+/*********************************************************************************
+ * _mmf_GetFlex2L
+ *
+ * Description:
+ * get flex data (duration, gate time)
+ * Argument:
+ * pbBuf pointer to data top
+ * dSize size of data (remain)
+ * pdRead pointer to size of flex data
+ * Return:
+ * >=0 success(flex data value)
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_GetFlex2L(unsigned char* pbBuf, unsigned int dSize, unsigned int* pbRead)
+{
+ int sdTemp;
+
+ if ((dSize < 1) || ((dSize < 2) && (pbBuf[0] >= 0x80)))
+ return AV_MMF_FUNC_ERROR;
+ if (dSize >= 4)
+ {
+ sdTemp = pbBuf[0] + pbBuf[1] + pbBuf[2] + pbBuf[3];
+ if (sdTemp == 0)
+ return AV_MMF_FUNC_ERROR;
+ }
+ if (pbBuf[0] >= 0x80)
+ {
+ sdTemp = (int)( (((int)(pbBuf[0] & 0x7F)) << 7) +
+ ((int)(pbBuf[1] & 0x7F)) + 128 );
+ *pbRead = 2;
+ }
+ else
+ {
+ sdTemp = (int)(pbBuf[0] & 0x7F);
+ *pbRead = 1;
+ }
+ return sdTemp;
+}
+
+
+/*********************************************************************************
+ * _mmf_SeqDataCheck2
+ *
+ * Description:
+ * track chunk check (sequence massage)
+ * Argument:
+ * psTrack pointer to track information structure
+ * bSmafType SMAF type
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_SeqDataCheck2(PTRACKINFO psTrack, unsigned char bSmafType)
+{
+ unsigned char* pbBuf;
+ unsigned int dSize, dIndex;
+ int sdTemp;
+ unsigned int dPast, dGate, dFlexSize;
+
+ if (psTrack->pbMtsq == NULL)
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+
+ dPast = 0;
+ dGate = 0;
+ pbBuf = psTrack->pbMtsq;
+ dSize = psTrack->dMtsqSize;
+ dIndex = 0;
+
+/* scanning to EOS or stop point */
+ while ( dSize > dIndex )
+ {
+ if (psTrack->dStartPoint== dIndex) /* start point */
+ psTrack->dStartTick = dPast;
+ if (psTrack->dStopPoint == dIndex)
+ { /* stop point */
+ psTrack->dStopTick = dPast;
+ break;
+ }
+
+ if (dSize >= dIndex + 4)
+ {
+ sdTemp=pbBuf[dIndex]+pbBuf[dIndex+1]+pbBuf[dIndex+2]+pbBuf[dIndex+3];
+ if (sdTemp == 0)
+ { /* EOS */
+ if (bSmafType == AV_MMF_SMAF_TYPE_MA1)
+ psTrack->dStopTick = dPast + dGate;
+ else
+ psTrack->dStopTick = dPast;
+ break;
+ }
+ }
+
+ sdTemp = _mmf_GetFlex2L(&pbBuf[dIndex], (dSize - dIndex), &dFlexSize);
+ if (sdTemp < 0)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dPast += sdTemp;
+ if (dPast >= AV_MMF_PLAY_TIME_MAX)
+ {
+ return AV_MMF_ERR_LLENGTH;
+ }
+
+ if ((unsigned int)sdTemp >= dGate) /* calculate remain of GT */
+ dGate = 0;
+ else
+ dGate -= sdTemp;
+ dIndex += dFlexSize;
+
+ if (dSize < dIndex + 2)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+
+ switch (pbBuf[dIndex])
+ {
+ case 0x00 :
+ if ((pbBuf[dIndex + 1] & 0x30) != 0x30)
+ dIndex += 2;
+ else
+ dIndex += 3;
+ break;
+ case 0xFF :
+ switch (pbBuf[dIndex + 1])
+ {
+ case 0x00 :
+ dIndex += 2;
+ break;
+ case 0xF0 :
+ if (dSize < dIndex + 3)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dIndex += (pbBuf[dIndex + 2] + 3);
+ if (dSize < dIndex) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ if (pbBuf[dIndex - 1] != 0xF7)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ default :
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ default :
+ sdTemp = _mmf_GetFlex2L(&pbBuf[dIndex+1], (dSize - dIndex- 1), &dFlexSize);
+ if (sdTemp < 0)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ if (dGate < (unsigned int)sdTemp)
+ dGate = (unsigned int)sdTemp;
+ dIndex += (1 + dFlexSize);
+ break;
+ }
+ if (dSize < dIndex) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ }
+
+
+ if (psTrack->dStartTick == AV_MMF_STSP_TIME_NULL)
+ {
+ if (psTrack->dStartPoint != AV_MMF_STSP_OFFSET_NULL)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psTrack->dStartTick = 0;
+ }
+
+/* check start/stop point potision */
+ if (psTrack->dStopTick == AV_MMF_STSP_TIME_NULL)
+ {
+ if ((psTrack->dStopPoint != AV_MMF_STSP_OFFSET_NULL) && (psTrack->dStopPoint != dIndex))
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ if (bSmafType == AV_MMF_SMAF_TYPE_MA1)
+ psTrack->dStopTick = dPast + dGate;
+ else
+ psTrack->dStopTick = dPast;
+ }
+
+/* calculate playback time of this track */
+ psTrack->dPlayTime = psTrack->dStopTick - psTrack->dStartTick;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Play time: %ld\n", psTrack->dPlayTime);
+ #endif
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * TrackChunk_Check2
+ *
+ * Description:
+ * MA-1/2 track chunk check
+ * Argument:
+ * psLoad pointer to load information structure
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_TrackChunkCheck2(PLOADINFO psLoad)
+{
+ PTRACKINFO psTrack;
+ int sdResult;
+ unsigned char i, fbVoice;
+
+/* delete track information of MA-3/5 */
+ psLoad->sTrack_Info[5].pbMtr = NULL;
+ psLoad->sTrack_Info[5].dMtrSize = 0;
+ psLoad->sTrack_Info[6].pbMtr = NULL;
+ psLoad->sTrack_Info[6].dMtrSize = 0;
+
+/* fix SMAF Type */
+ psLoad->dSmafType = AV_MMF_SMAF_TYPE_MA1;
+ for (i = 1; i < 5; i++)
+ {
+ if (psLoad->sTrack_Info[i].pbMtr != NULL)
+ {
+ psLoad->dSmafType = AV_MMF_SMAF_TYPE_MA2;
+ break;
+ }
+ }
+ if (psLoad->sTrack_Info[AV_MMF_ATR_TRACK_NO].pbMtr != NULL)
+ psLoad->dSmafType = AV_MMF_SMAF_TYPE_MA2;
+
+ if (psLoad->dSmafType == AV_MMF_SMAF_TYPE_MA1)
+ { /* MA-1 */
+ if (psLoad->sTrack_Info[0].pbMtr == NULL)
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+ psTrack = &(psLoad->sTrack_Info[0]);
+ if (psTrack->dMtrSize <= AV_MMF_MINIMUM_TRACKSIZE2)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_MTRCheck(psTrack, AV_MMF_SMAF_TYPE_MA1);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ _mmf_MspICheck(psTrack, &(psLoad->sPhrase_Info[0]));
+ sdResult = _mmf_STSPCheck(psTrack);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ sdResult = _mmf_MtsuCheck2(psTrack, AV_MMF_SMAF_TYPE_MA1);
+ if (sdResult != AV_MMF_MA2_VOICE_FOUND)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_SeqDataCheck2(psTrack, AV_MMF_SMAF_TYPE_MA1);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ psLoad->dPlayTime = psTrack->dPlayTime;
+ psLoad->dStartTime = psTrack->dStartTick;
+ psLoad->dTimeBase = psTrack->dTimeBase;
+ return AV_MMF_FUNC_SUCCESS;
+ }
+ else
+ { /* MA-2 */
+ psLoad->sTrack_Info[0].pbMtr = NULL;
+ psLoad->sTrack_Info[0].dMtrSize = 0;
+
+ for (i = 1; i < 5; i++)
+ {
+ psTrack = &(psLoad->sTrack_Info[i]);
+ if (psTrack->pbMtr == NULL)
+ continue;
+ if (psTrack->dMtrSize <= AV_MMF_MINIMUM_TRACKSIZE2)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_MTRCheck(psTrack, AV_MMF_SMAF_TYPE_MA2);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ _mmf_MspICheck(psTrack, &(psLoad->sPhrase_Info[0]));
+ sdResult = _mmf_STSPCheck(psTrack);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ sdResult = _mmf_SeqDataCheck2(psTrack, AV_MMF_SMAF_TYPE_MA2);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ psLoad->dPlayTime = psTrack->dPlayTime;
+ psLoad->dStartTime = psTrack->dStartTick;
+ psLoad->dTimeBase = psTrack->dTimeBase;
+ }
+ if (psLoad->sTrack_Info[AV_MMF_ATR_TRACK_NO].pbMtr != NULL)
+ {
+ psTrack = &(psLoad->sTrack_Info[AV_MMF_ATR_TRACK_NO]);
+
+ if (psTrack->dMtrSize <= AV_MMF_MINIMUM_TRACKSIZE2)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_ATRCheck(psTrack);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ _mmf_MspICheck(psTrack, &(psLoad->sPhrase_Info[0]));
+ sdResult = _mmf_STSPCheck(psTrack);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ sdResult = _mmf_SeqDataCheck2(psTrack, AV_MMF_SMAF_TYPE_MA2);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ psLoad->dPlayTime = psTrack->dPlayTime;
+ psLoad->dStartTime = psTrack->dStartTick;
+ psLoad->dTimeBase = psTrack->dTimeBase;
+ }
+
+/* totaling of track information */
+ for (i = 1; i < AV_MMF_MAX_TRACK_NUM; i++)
+ {
+ psTrack = &(psLoad->sTrack_Info[i]);
+ if (psTrack->pbMtr == NULL)
+ continue;
+
+ if (psLoad->dPlayTime < psTrack->dPlayTime)
+ psLoad->dPlayTime = psTrack->dPlayTime;
+ if (psLoad->dTimeBase != psTrack->dTimeBase)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ if (psLoad->dStartTime != psTrack->dStartTick)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ if (_mmf_MtsuCheck2(psTrack, AV_MMF_SMAF_TYPE_MA2) == AV_MMF_FUNC_SUCCESS)
+ fbVoice = AV_MMF_MA2_VOICE_FOUND;
+ }
+
+ fbVoice = AV_MMF_MA2_VOICE_FOUND;
+ for (i = 1; i < 5; i++)
+ {
+ psTrack = &(psLoad->sTrack_Info[i]);
+ if (psTrack->pbMtr == NULL)
+ continue;
+ if (_mmf_MtsuCheck2(psTrack, AV_MMF_SMAF_TYPE_MA2) == AV_MMF_MA2_VOICE_FOUND)
+ {
+ fbVoice = AV_MMF_MA2_VOICE_FOUND;
+ break;
+ }
+ else
+ fbVoice = AV_MMF_MA2_VOICE_NOTFOUND;
+ }
+
+ if (fbVoice == AV_MMF_MA2_VOICE_NOTFOUND)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Play time: %ld\n", psLoad->dPlayTime);
+ #endif
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+static unsigned char
+_mmf_GetByte3L(PHUFFMANINFO psHuf)
+{
+ psHuf->dReadSize ++;
+ if (psHuf->dReadSize > psHuf->dMtsqSize)
+ {
+ return 0;
+ }
+ return *(psHuf->psBuffer++);
+}
+
+
+/*********************************************************************************
+ * _mmf_GetFlex3L
+ *
+ * Description:
+ * MA-3 sequence data check
+ * Argument:
+ * psLoad pointer to load information structure
+ * pdRead pointer to size of flex data
+ * Return:
+ * >=0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_GetFlex3L(PLOADINFO psLoad, unsigned int* pdRead)
+{
+ unsigned int dTemp, dRead;
+ unsigned char bTemp;
+
+ dRead = 1;
+ bTemp = psLoad->pfnGetByte( &(psLoad->sHuffman_Info) );
+ dTemp = (unsigned int)(bTemp & 0x7F);
+ while (bTemp & 0x80)
+ {
+ if (dRead >= 4)
+ return AV_MMF_FUNC_ERROR;
+ dRead ++;
+ bTemp = psLoad->pfnGetByte( &(psLoad->sHuffman_Info) );
+ dTemp = (dTemp << 7) + (unsigned int)(bTemp & 0x7F);
+ }
+ if (dTemp >= AV_MMF_PLAY_TIME_MAX)
+ return AV_MMF_FUNC_ERROR;
+ *pdRead = dRead;
+ return (int)dTemp;
+}
+
+
+/*********************************************************************************
+ * _mmf_SeqDataCheck3
+ *
+ * Description:
+ * MA-3 sequence data check
+ * Argument:
+ * psLoad pointer to load information structure
+ * bSmafType SMAF type
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_SeqDataCheck3(PLOADINFO psLoad, unsigned char bSmafType)
+{
+ PTRACKINFO psTrk;
+ PPHRASEINFO psPhr;
+ PHUFFMANINFO psHuf;
+ unsigned int dIndex, fdPhrase, dSize, dPast, dGate, dReadSize, i;
+ unsigned int dStartTick, dStopTick;
+ int sdTemp;
+ unsigned char bTemp;
+
+ if (bSmafType == AV_MMF_SMAF_TYPE_MA3)
+ { /* MA-3 */
+ psTrk = &(psLoad->sTrack_Info[5]);
+ dStartTick = AV_MMF_STSP_TIME_NULL;
+ dStopTick = AV_MMF_STSP_TIME_NULL;
+ }
+ else
+ { /* MA-5 */
+ psTrk = &(psLoad->sTrack_Info[6]);
+ dStartTick = psTrk->dStartTick;
+ dStopTick = psTrk->dStopTick;
+ psTrk->dStartTick = AV_MMF_STSP_TIME_NULL;
+ psTrk->dStopTick = AV_MMF_STSP_TIME_NULL;
+ }
+
+ psPhr = &(psLoad->sPhrase_Info[0]);
+ psHuf = &(psLoad->sHuffman_Info);
+ fdPhrase= 0;
+ dIndex = 0;
+ dPast = 0;
+ dGate = 0;
+ dSize = psHuf->dSeqSize;
+
+ if (psHuf->dSeqSize == 0)
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+
+ for (i = 0; i < AV_MMF_MAX_PHRASE_INFO; i++)
+ {
+ if (psPhr[i].dStartPoint != AV_MMF_STSP_OFFSET_NULL)
+ fdPhrase = 1;
+ }
+
+/* scanning sequence data to EOS or stop point */
+ while (dSize >= dIndex)
+ {
+
+ if (psTrk->dStartPoint == dIndex)
+ psTrk->dStartTick = dPast;
+ if (psTrk->dStopPoint == dIndex) /* stop point */
+ psTrk->dStopTick = dPast;
+ if (fdPhrase)
+ {
+ for (i = 0; i < AV_MMF_MAX_PHRASE_INFO; i++)
+ {
+ if (psPhr[i].dStartPoint== dIndex)
+ psPhr[i].dStartTick = dPast;
+ if (psPhr[i].dStopPoint == dIndex)
+ psPhr[i].dStopTick = dPast;
+ }
+ }
+
+ if ((psTrk->dStopTick != AV_MMF_STSP_TIME_NULL) || (dSize == dIndex))
+ break;
+
+ sdTemp = _mmf_GetFlex3L(psLoad, &dReadSize); /* Duration */
+ if (sdTemp < 0) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dPast += (unsigned int)sdTemp;
+ if (dPast >= AV_MMF_PLAY_TIME_MAX)
+ {
+ return AV_MMF_ERR_LLENGTH;
+ }
+
+ if ((unsigned int)sdTemp >= dGate)
+ dGate = 0;
+ else
+ dGate -= (unsigned int)sdTemp;
+ dIndex += dReadSize;
+
+ bTemp = psLoad->pfnGetByte(psHuf);
+ dIndex ++;
+
+ switch (bTemp & 0xF0)
+ {
+ case 0x90 :
+ psLoad->pfnGetByte(psHuf); /*Note number*/
+ dIndex ++;
+ psLoad->pfnGetByte(psHuf); /*Key Velocity*/
+ dIndex ++;
+ sdTemp = _mmf_GetFlex3L(psLoad, &dReadSize);
+ if (sdTemp < 0) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dIndex += dReadSize;
+ if ((unsigned int)sdTemp > dGate)
+ dGate = sdTemp;
+ break;
+ case 0x80 :
+ psLoad->pfnGetByte(psHuf); /*Note number*/
+ dIndex ++;
+ sdTemp = _mmf_GetFlex3L(psLoad, &dReadSize);
+ if (sdTemp < 0) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dIndex += dReadSize;
+ if ((unsigned int)sdTemp > dGate)
+ dGate = sdTemp;
+ break;
+ case 0xA0 :
+ case 0xB0 :
+ case 0xE0 :
+ bTemp = psLoad->pfnGetByte(psHuf); /*B0: Conrol number, E0:Pitch Bend Change LSB*/
+ dIndex ++;
+ bTemp = psLoad->pfnGetByte(psHuf); /*B0: Conrol value, E0:Pitch Bend Change MSB*/
+ dIndex ++;
+ break;
+ case 0xC0 :
+ case 0xD0 :
+ bTemp = psLoad->pfnGetByte(psHuf);
+ dIndex ++;
+ break;
+ default :
+ switch (bTemp)
+ {
+ case 0xF0 :
+ sdTemp = _mmf_GetFlex3L(psLoad, &dReadSize);
+ if (sdTemp < 0) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ for (i = 0; i < (unsigned int)sdTemp; i++)
+ bTemp = psLoad->pfnGetByte(psHuf);
+ if (bTemp != 0xF7) {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dIndex += (unsigned int)sdTemp + dReadSize;
+ break;
+ case 0xFF :
+ bTemp = psLoad->pfnGetByte(psHuf);
+ dIndex ++;
+ switch (bTemp)
+ {
+ case 0x00 :
+ break;
+ case 0x2F :
+ bTemp = psLoad->pfnGetByte(psHuf);
+ dIndex ++;
+ if (bTemp != 0x00)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ dGate = 0;
+ psTrk->dStopTick = dPast;
+ dIndex = dSize;
+ break;
+ default :
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ default :
+ return AV_MMF_ERR_CHUNK;
+ }
+ break;
+ }
+ if ((dSize < dIndex) || (psHuf->dReadSize > psHuf->dMtsqSize))
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ }
+
+ if (bSmafType == AV_MMF_SMAF_TYPE_MA3)
+ { /* MA-3 */
+/* check start point */
+ if (psTrk->dStartTick == AV_MMF_STSP_TIME_NULL)
+ {
+ if (psTrk->dStartPoint != AV_MMF_STSP_OFFSET_NULL)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psTrk->dStartPoint = 0;
+ psTrk->dStartTick = 0;
+ }
+/* check stop point */
+ if (psTrk->dStopTick == AV_MMF_STSP_TIME_NULL)
+ {
+ if (psTrk->dStopPoint != AV_MMF_STSP_OFFSET_NULL)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psTrk->dStopPoint = dSize;
+ psTrk->dStopTick = dPast + dGate;
+ }
+/* adjust phrase information */
+ for (i = 0; i < AV_MMF_MAX_PHRASE_INFO; i++)
+ {
+ if (psPhr[i].dStartPoint <= psTrk->dStartPoint)
+ psPhr[i].dStartTick = psTrk->dStartTick;
+ if (psPhr[i].dStopPoint >= psTrk->dStopPoint)
+ psPhr[i].dStopTick = psTrk->dStopTick;
+ if (psPhr[i].dStopPoint <= psTrk->dStartPoint)
+ psPhr[i].dStopTick = AV_MMF_STSP_TIME_NULL;
+ }
+ }
+ else
+ { /* MA-5 */
+/* check stop point */
+ if (dStopTick > dPast)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psTrk->dStartTick = dStartTick;
+ psTrk->dStopTick = dStopTick;
+ }
+
+/* calculate playback time of this track */
+ psTrk->dPlayTime = psTrk->dStopTick - psTrk->dStartTick;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Play time: %ld\n", psTrk->dPlayTime);
+ #endif
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+
+
+/*********************************************************************************
+ * _mmf_DecodeGetbitL
+ *
+ * Description:
+ * get 1 bit with error check
+ * Argument:
+ * psHuf pointer to huffman information structure
+ * Return:
+ * read data
+ ********************************************************************************/
+
+
+static unsigned char
+_mmf_DecodeGetbitL(PHUFFMANINFO psHuf)
+{
+ char czero = 0;
+
+ if (--psHuf->sbBitC < czero)
+ {
+ if (psHuf->dReadSize >= psHuf->dMtsqSize)
+ return 0;
+ psHuf->sbBitC = 7;
+ psHuf->bByte = *(psHuf->psBuffer++);
+ psHuf->dReadSize ++;
+ }
+ return (unsigned char)(psHuf->bByte & g_abBitMaskTable1[(int)(psHuf->sbBitC)]);
+}
+
+
+/*********************************************************************************
+ * _mmf_DecodeGetbits
+ *
+ * Description:
+ * get 8 bit
+ * Argument:
+ * psHuf pointer to huffman information structure
+ * Return:
+ * read data
+ ********************************************************************************/
+static unsigned char
+_mmf_DecodeGetbits(PHUFFMANINFO psHuf)
+{
+ unsigned short wTemp;
+ unsigned char bData1, bData2;
+
+ if (psHuf->dReadSize >= psHuf->dMtsqSize)
+ return 0;
+ bData1 = psHuf->bByte;
+ bData2 = *(psHuf->psBuffer++);
+ psHuf->bByte = bData2;
+ psHuf->dReadSize ++;
+ wTemp = (unsigned short)((((unsigned short)bData1) << 8) + ((unsigned short)bData2));
+ return (unsigned char)((wTemp & g_awBitMaskTable2[(int)(psHuf->sbBitC)]) >> psHuf->sbBitC);
+}
+
+
+/*********************************************************************************
+ * _mmf_DecodeTree
+ *
+ * Description:
+ * make MA-3 huffman decode tree
+ * Argument:
+ * psHuf pointer to huffman information structure
+ * Return:
+ * !0 success(sequence data size)
+ * 0 error
+ ********************************************************************************/
+static int
+_mmf_DecodeTree( PHUFFMANINFO psHuf)
+{
+ unsigned int dNode, dEmpty, dIndex, i;
+ short *pswLeft, *pswRight, *pswPNode;
+ unsigned char bTemp;
+
+ if (_mmf_DecodeGetbitL(psHuf))
+ {
+ if (psHuf->dReadSize >= psHuf->dMtsqSize)
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+
+ pswLeft = &(psHuf->swLeft[256]);
+ pswRight= &(psHuf->swRight[256]);
+ pswPNode= &(psHuf->swRight[0]);
+ for (i = 0; i < 256; i++)
+ {
+ pswLeft[i] = -1;
+ pswRight[i] = -1;
+ pswPNode[i] = 0;
+ }
+ dNode = 2;
+ dEmpty = 1;
+ dIndex = 0;
+ }
+ else
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+
+ while (dNode != 0)
+ {
+ if ((dEmpty >= 256) || (dNode >= 257))
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+
+ bTemp = _mmf_DecodeGetbitL(psHuf);
+ if (psHuf->dReadSize >= psHuf->dMtsqSize)
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+
+ if (bTemp)
+ {
+ dNode ++;
+ if (pswLeft[dIndex] == -1)
+ pswLeft[dIndex] = (short)(dEmpty + 256);
+ else
+ pswRight[dIndex]= (short)(dEmpty + 256);
+ pswPNode[dEmpty] = (short)dIndex;
+ dIndex = dEmpty;
+ dEmpty ++;
+ }
+ else
+ {
+ dNode --;
+ bTemp = _mmf_DecodeGetbits(psHuf);
+ if (psHuf->dReadSize >= psHuf->dMtsqSize)
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+
+ if (pswLeft[dIndex] == -1)
+ pswLeft[dIndex] = (short)bTemp;
+ else
+ {
+ pswRight[dIndex]= (short)bTemp;
+ while ((pswRight[dIndex] != -1) && (dIndex != 0))
+ dIndex = (unsigned int)pswPNode[dIndex];
+ }
+ }
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ if (pswLeft[i] == -1)
+ pswLeft[i] = 0;
+ if (pswRight[i] == -1)
+ pswRight[i] = 0;
+ }
+ return AV_MMF_HUFFMAN_TREE_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_DecodeInit
+ *
+ * Description:
+ * make MA-3 huffman decode tree
+ * Argument:
+ * psHuf pointer to huffman information structure
+ * Return:
+ * !0 success(sequence data size)
+ * 0 error
+ ********************************************************************************/
+static unsigned int
+_mmf_DecodeInit(PHUFFMANINFO psHuf)
+{
+ unsigned int dSeqSize;
+
+ if (psHuf->dMtsqSize <= 5)
+ {
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+ }
+
+ dSeqSize = _mmf_Get4Byte(psHuf->psBuffer);
+ psHuf->psBuffer += 4;
+ psHuf->dReadSize = 4;
+ psHuf->sbBitC = 0;
+ psHuf->bByte = 0;
+ if (_mmf_DecodeTree(psHuf) == AV_MMF_HUFFMAN_TREE_FAILURE)
+ return AV_MMF_HUFFMAN_TREE_FAILURE;
+ else
+ return dSeqSize;
+}
+
+
+/*********************************************************************************
+ * _mmf_DecodeByte3L
+ *
+ * Description:
+ * get 1 byte (from compressed data)
+ * Argument:
+ * psHuf pointer to huffman information structure
+ * Return:
+ * unsigned char success(read data)
+ * 0 error code
+ ********************************************************************************/
+static unsigned char
+_mmf_DecodeByte3L (PHUFFMANINFO psHuf)
+{
+ unsigned int bData, bIndex;
+ char czero = 0;
+ bIndex = 256;
+ while (bIndex >= 256)
+ {
+ if (--psHuf->sbBitC < czero)
+ {
+ psHuf->dReadSize ++;
+ if (psHuf->dReadSize > psHuf->dMtsqSize)
+ return 0;
+ psHuf->sbBitC = 7;
+ psHuf->bByte = *(psHuf->psBuffer++);
+ }
+ bData = (unsigned char)(psHuf->bByte & g_abBitMaskTable1[(int)(psHuf->sbBitC)]);
+ if (bData)
+ bIndex = psHuf->swRight[bIndex];
+ else
+ bIndex = psHuf->swLeft[bIndex];
+ }
+ return (unsigned char)bIndex;
+}
+
+
+/*********************************************************************************
+ * _mmf_TrackChunkCheck3
+ *
+ * Description:
+ * MA-3 track chunk check
+ * Argument:
+ * psLoad pointer to load information structure
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_TrackChunkCheck3(PLOADINFO psLoad)
+{
+ PTRACKINFO psTrack;
+ int sdResult;
+
+ if (psLoad->sTrack_Info[5].pbMtr == NULL)
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+ psTrack = &(psLoad->sTrack_Info[5]);
+ if (psTrack->dMtrSize <= AV_MMF_MINIMUM_TRACKSIZE3)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_MTRCheck(psTrack, AV_MMF_SMAF_TYPE_MA3);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ _mmf_MspICheck(psTrack, &(psLoad->sPhrase_Info[0]));
+
+ psLoad->sHuffman_Info.psBuffer = psTrack->pbMtsq;
+ psLoad->sHuffman_Info.dMtsqSize = psTrack->dMtsqSize;
+
+/* Initialize Huffman information structure */
+ if (psTrack->pbMtr[0] == 0x01)
+ { /* Compressed Foramt */
+ psLoad->sHuffman_Info.dSeqSize = _mmf_DecodeInit( &(psLoad->sHuffman_Info) );
+ if (psLoad->sHuffman_Info.dSeqSize == AV_MMF_HUFFMAN_TREE_FAILURE)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ psLoad->pfnGetByte = _mmf_DecodeByte3L;
+ psLoad->sHuffman_Info.psFBuf = psLoad->sHuffman_Info.psBuffer;
+ psLoad->sHuffman_Info.sbFBit = psLoad->sHuffman_Info.sbBitC;
+ psLoad->sHuffman_Info.bFByte = psLoad->sHuffman_Info.bByte;
+ }
+ else
+ { /* No Compressed Foramt */
+ psLoad->pfnGetByte = _mmf_GetByte3L;
+ psLoad->sHuffman_Info.dSeqSize = psTrack->dMtsqSize;
+ psLoad->sHuffman_Info.dReadSize = 0;
+ psLoad->sHuffman_Info.psFBuf = psTrack->pbMtsq;
+ psLoad->sHuffman_Info.sbFBit = 0;
+ psLoad->sHuffman_Info.bFByte = 0;
+ }
+
+ psTrack->dMtsqSize = psLoad->sHuffman_Info.dSeqSize;
+ sdResult = _mmf_STSPCheck(psTrack);
+ psTrack->dMtsqSize = psLoad->sHuffman_Info.dMtsqSize;
+
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ sdResult = _mmf_SeqDataCheck3(psLoad, AV_MMF_SMAF_TYPE_MA3);
+ if (sdResult != AV_MMF_FUNC_SUCCESS)
+ {
+ return sdResult;
+ }
+ psLoad->dPlayTime = psTrack->dPlayTime;
+ psLoad->dStartTime = psTrack->dStartTick;
+ psLoad->dTimeBase = psTrack->dTimeBase;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Play time: %ld\n", psLoad->dPlayTime);
+ #endif
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_CheckM5P
+ *
+ * Description:
+ * MA-5 profile data chunk check
+ * Argument:
+ * psLoad pointer to load information structure
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_CheckM5P(PLOADINFO psLoad)
+{
+ PTRACKINFO psTrk;
+ PPHRASEINFO psPhr;
+ POPTIONINFO psOptn;
+ unsigned char *pbOpda, *pbM5p;
+ unsigned int dOSize, dMSize, dIndex, dPhraseFlag, i;
+ unsigned int dChunkID, dChunkNo;
+ int sdChunkSize;
+
+ psOptn = &(psLoad->sOption_Info);
+ psTrk = &(psLoad->sTrack_Info[6]);
+ psPhr = &(psLoad->sPhrase_Info[0]);
+ pbOpda = psOptn->pbOpda;
+ dOSize = psOptn->dOpdaSize;
+ dIndex = 0;
+ pbM5p = NULL;
+ dMSize = 0;
+
+/* search Pro5 Chunk */
+ while (dOSize > (dIndex + AV_MMF_CHUNK_HEADER_SIZE))
+ {
+ sdChunkSize = _mmf_MalibNextChunk(&pbOpda[dIndex], (dOSize - dIndex),
+ AVMALIB_CHUNK_PHASE_OPDASUB, &dChunkID, &dChunkNo);
+ if (sdChunkSize < AVMASMW_SUCCESS) return AVMASMW_ERROR;
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ if ((dChunkID == AVMALIB_CHUNKCODE_M5P) && (dChunkNo == 0x05))
+ {
+ pbM5p = &pbOpda[dIndex];
+ dMSize = (unsigned int)sdChunkSize;
+ break;
+ }
+ dIndex += sdChunkSize;
+ }
+
+ if ((pbM5p == NULL) || (dMSize < 12)) return AVMASMW_ERROR;
+
+ dPhraseFlag = _mmf_Get4Byte(&pbM5p[0]);
+ psTrk->dStartTick = _mmf_Get4Byte(&pbM5p[4]); /* start point */
+ psTrk->dStopTick = _mmf_Get4Byte(&pbM5p[8]); /* stop point */
+ dIndex = 12;
+
+ if (psTrk->dStartTick >= psTrk->dStopTick) return AVMASMW_ERROR;
+
+ for (i = 0; i < AV_MMF_MAX_PHRASE_INFO; i ++)
+ {
+ if (dMSize < (dIndex + 8)) break;
+ if (dPhraseFlag & (0x80000000 >> i))
+ {
+ psPhr[i].dStartTick = _mmf_Get4Byte(&pbM5p[dIndex]);
+ psPhr[i].dStopTick = _mmf_Get4Byte(&pbM5p[dIndex + 4]);
+ if (psPhr[i].dStartTick >= psPhr[i].dStopTick)
+ {
+ psPhr[i].dStartTick = AV_MMF_STSP_TIME_NULL;
+ psPhr[i].dStopTick = AV_MMF_STSP_TIME_NULL;
+ }
+ if (psPhr[i].dStartTick < psTrk->dStartTick)
+ psPhr[i].dStartTick = psTrk->dStartTick;
+ if (psPhr[i].dStopTick > psTrk->dStopTick)
+ psPhr[i].dStopTick = psTrk->dStopTick;
+ dIndex += 8;
+ }
+ }
+ return AVMASMW_SUCCESS;
+}
+
+
+/*********************************************************************************
+ * _mmf_TrackChunkCheck5
+ *
+ * Description:
+ * MA-5 track chunk check
+ * Argument:
+ * psLoad pointer to load information structure
+ * dMode load mode
+ * Return:
+ * 0 success
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_TrackChunkCheck5(PLOADINFO psLoad)
+{
+ PTRACKINFO psTrack;
+ int sdResult;
+
+ if (psLoad->sTrack_Info[6].pbMtr == NULL)
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+ psTrack = &(psLoad->sTrack_Info[6]);
+ if (psTrack->dMtrSize <= AV_MMF_MINIMUM_TRACKSIZE3)
+ {
+ return AV_MMF_ERR_CHUNK;
+ }
+ sdResult = _mmf_MTRCheck(psTrack, AV_MMF_SMAF_TYPE_MA5);
+ if (sdResult != AV_MMF_FUNC_SUCCESS) return sdResult;
+
+ psLoad->sHuffman_Info.psBuffer = psTrack->pbMtsq;
+ psLoad->sHuffman_Info.dMtsqSize = psTrack->dMtsqSize;
+ psLoad->sHuffman_Info.dSeqSize = psTrack->dMtsqSize;
+ psLoad->sHuffman_Info.dReadSize = 0;
+ psLoad->pfnGetByte = _mmf_GetByte3L;
+
+
+ sdResult = _mmf_SeqDataCheck3(psLoad, AV_MMF_SMAF_TYPE_MA5);
+ if (sdResult != AV_MMF_FUNC_SUCCESS) return sdResult;
+
+ psLoad->dPlayTime = psTrack->dPlayTime;
+ psLoad->dStartTime = psTrack->dStartTick;
+ psLoad->dTimeBase = psTrack->dTimeBase;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Play time: %ld\n", psLoad->dPlayTime);
+ #endif
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+/*********************************************************************************
+ * _mmf_GetHvData
+ *
+ * Description:
+ * HV Data Chunk Check
+ * Argument:
+ * psLoad pointer to load information structure
+ * bCType Contents Type
+ * Return:
+ * nothing
+ ********************************************************************************/
+static void
+_mmf_GetHvData(PLOADINFO psLoad, unsigned char bCType)
+{
+ unsigned char* pbHvData;
+ unsigned int dHvDataSize;
+
+ unsigned char* pbVoice;
+ unsigned char* pbScript;
+ unsigned char* pbSetup;
+ unsigned int dVoiceSize, dScriptSize, dSetupSize, dIndex;
+ unsigned char bHvCh;
+ unsigned short wTag, wSize;
+
+ unsigned int dChunkID, dChunkNo;
+ int sdChunkSize;
+
+ if ((psLoad->dSmafType == AV_MMF_SMAF_TYPE_MA1) ||(psLoad->dSmafType == AV_MMF_SMAF_TYPE_MA2))
+ return ;
+
+ if ((bCType & 0x0F) == 0x08)
+ return ;
+
+ if (psLoad->dSmafType == AV_MMF_SMAF_TYPE_MA3)
+ {
+ pbHvData = psLoad->sTrack_Info[5].pbMthv;
+ dHvDataSize = psLoad->sTrack_Info[5].dMthvSize;
+ }
+ else
+ {
+ pbHvData = psLoad->sTrack_Info[6].pbMthv;
+ dHvDataSize = psLoad->sTrack_Info[6].dMthvSize;
+ }
+
+ if ((pbHvData == NULL) || (dHvDataSize < AV_MMF_CHUNK_HEADER_SIZE))
+ return ;
+
+ pbVoice = NULL;
+ pbScript = NULL;
+ pbSetup = NULL;
+ dVoiceSize = 0;
+ dScriptSize = 0;
+ dSetupSize = 0;
+ bHvCh = AV_MMF_HV_CHANNEL_NULL;
+ dIndex = 0;
+
+ while (dHvDataSize > (dIndex + AV_MMF_CHUNK_HEADER_SIZE))
+ {
+ sdChunkSize = _mmf_MalibNextChunk(&(pbHvData[dIndex]), (dHvDataSize - dIndex),
+ AVMALIB_CHUNK_PHASE_MTHVSUB, &dChunkID, &dChunkNo);
+ if (sdChunkSize < 0) return ;
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ switch (dChunkID)
+ {
+ case AVMALIB_CHUNKCODE_MHVS :
+ pbSetup = &(pbHvData[dIndex]);
+ dSetupSize = (unsigned int)sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_HVP :
+ if (dChunkNo != 0) break;
+ pbVoice = &(pbHvData[dIndex - AV_MMF_CHUNK_HEADER_SIZE]);
+ dVoiceSize = (unsigned int)(sdChunkSize + AV_MMF_CHUNK_HEADER_SIZE);
+ break;
+ case AVMALIB_CHUNKCODE_MHSC :
+ pbScript = &(pbHvData[dIndex]);
+ dScriptSize = (unsigned int)sdChunkSize;
+ break;
+ }
+ dIndex += sdChunkSize;
+ }
+
+ dIndex = 0;
+ while (dSetupSize >= dIndex + 4 )
+ {
+ wTag = (unsigned short)(((unsigned short)(pbSetup[dIndex ]) << 8) + pbSetup[dIndex + 1]);
+ wSize = (unsigned short)(((unsigned short)(pbSetup[dIndex + 2]) << 8) + pbSetup[dIndex + 3]);
+ dIndex += 4;
+ if (dSetupSize < (dIndex + wSize)) return ;
+ if ((wTag == 0x4348) && (wSize == 1)) bHvCh = pbSetup[dIndex];
+ dIndex += wSize;
+ }
+
+ if ((pbScript == NULL) || (bHvCh >= AV_MMF_HV_CHANNEL_NULL))
+ return ;
+
+ psLoad->sHV_Info.pbVoice = pbVoice;
+ psLoad->sHV_Info.dVoiceSize = dVoiceSize;
+ psLoad->sHV_Info.pbScript = pbScript;
+ psLoad->sHV_Info.dScriptSize = dScriptSize;
+ psLoad->sHV_Info.bHvChannel = bHvCh;
+
+ return ;
+}
+
+/*********************************************************************************
+ * Avdecode_byte3
+ *
+ * Description:
+ * get 1 byte (from compressed data)
+ * Argument:
+ * nothing
+ * Return:
+ * unsigned char success(read data)
+ ********************************************************************************/
+static unsigned short
+_mmf_MalibMakeCRC(unsigned int dSize, unsigned char* pbData)
+{
+ unsigned short wRes;
+ unsigned char bData;
+
+ wRes = 0xFFFFU;
+ while ( --dSize >= 2 )
+ {
+ bData = *pbData++;
+ wRes = (unsigned short)((wRes << 8) ^ g_crc_tbl[(unsigned char)(wRes >> 8) ^ bData]);
+ }
+ return (unsigned short)(~wRes & 0xFFFFU);
+}
+
+
+/*********************************************************************************
+ * _mmf_MALoad
+ *
+ * Description:
+ * SMAF data load (error check and regist)
+ * Argument:
+ * pbFile pointer to SMAF data
+ * dFsize size of SMAF data
+ * dMode load mode
+ * Return:
+ * 0 or 1 success(file id)
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_MALoad( unsigned char* pbFile, unsigned int dFSize)
+{
+ PLOADINFO psLoad_Info;
+ unsigned int bNo = 0;
+ unsigned int dChunkID = 0, dChunkNo = 0;
+ unsigned char* pbBuf = NULL;
+ unsigned int dSize = 0, dIndex = 0;
+ int sdChunkSize = 0, sdResult = 0;
+ unsigned int dCalcCrc = 0, dFileCrc = 0;
+ int rVal = 0;
+
+ pbBuf = pbFile;
+ dSize = dFSize;
+ psLoad_Info = &(g_sSmaf_Info.sLoad_Info[bNo]);
+ _mmf_CheckInitial( psLoad_Info );
+
+/* check File Chunk(ID/Size) */
+ sdChunkSize = _mmf_MalibNextChunk(pbBuf, dSize, AVMALIB_CHUNK_PHASE_MMMD,
+ &dChunkID, &dChunkNo);
+ if ((sdChunkSize < 0) || (dChunkID != AVMALIB_CHUNKCODE_MMMD))
+ {
+ return AV_MMF_ERR_FILE;
+ }
+ dSize = (unsigned int)(sdChunkSize + AV_MMF_CHUNK_HEADER_SIZE);
+ dCalcCrc = AV_MMF_CRC_NULL;
+
+ dCalcCrc = _mmf_MalibMakeCRC(dSize, pbBuf);
+ dFileCrc = (unsigned int)((((unsigned int)pbBuf[dSize - 2]) << 8) + pbBuf[dSize - 1]);
+ if (dCalcCrc != dFileCrc) {
+ return AV_MMF_ERR_FILE;
+ }
+
+
+/* check Contents Info Chunk */
+ dIndex = AV_MMF_CHUNK_HEADER_SIZE;
+ sdChunkSize = _mmf_MalibNextChunk(&pbBuf[dIndex], (dSize-dIndex),
+ AVMALIB_CHUNK_PHASE_CNTI, &dChunkID, &dChunkNo);
+ if ((sdChunkSize < 5) || (dChunkID != AVMALIB_CHUNKCODE_CNTI))
+ {
+ return AV_MMF_ERR_FILE;
+ }
+
+/* check Contents Class */
+ if ((pbBuf[AV_MMF_POSITION_OF_CCLASS] != AV_MMF_CONTENTS_CLASS_0) &&
+ (pbBuf[AV_MMF_POSITION_OF_CCLASS] != AV_MMF_CONTENTS_CLASS_1) &&
+ (pbBuf[AV_MMF_POSITION_OF_CCLASS] != AV_MMF_CONTENTS_CLASS_2) )
+ {
+ return AV_MMF_ERR_CLASS;
+ }
+
+/* check Contents Type */
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ if (((pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0xF0) == AV_MMF_CONTENTS_TYPE_0) ||
+ ((pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0xF0) == AV_MMF_CONTENTS_TYPE_1) ||
+ ((pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0xF0) == AV_MMF_CONTENTS_TYPE_2) )
+ {
+ psLoad_Info->dSmafType = AV_MMF_SMAF_TYPE_MA2;
+ }
+ else if (((pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0xF0) == AV_MMF_CONTENTS_TYPE_3) ||
+ ((pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0xF0) == AV_MMF_CONTENTS_TYPE_4) ||
+ ((pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0xF0) == AV_MMF_CONTENTS_TYPE_5) )
+ {
+ switch (pbBuf[AV_MMF_POSITION_OF_CTYPE] & 0x0F)
+ {
+ case 0x00 :
+ case 0x01 :
+ psLoad_Info->dSmafType = AV_MMF_SMAF_TYPE_MA2;
+ break;
+ case 0x02 :
+ case 0x03 :
+ psLoad_Info->dSmafType = AV_MMF_SMAF_TYPE_MA3;
+ break;
+ case 0x04 :
+ case 0x05 :
+ case 0x06 :
+ case 0x07 :
+ case 0x08 :
+ psLoad_Info->dSmafType = AV_MMF_SMAF_TYPE_MA5;
+ break;
+ default :
+ return AV_MMF_ERR_TYPE;
+ }
+ }
+ else
+ {
+ return AV_MMF_ERR_TYPE;
+ }
+
+/* get pointer & size of option information */
+ psLoad_Info->sOption_Info.pbCnti = &pbBuf[dIndex];
+ psLoad_Info->sOption_Info.dCntiSize = (unsigned int)(sdChunkSize);
+ dIndex += sdChunkSize;
+
+ if (pbBuf[AV_MMF_POSITION_OF_CTYPE] >= 0x30)
+ {
+ sdChunkSize = _mmf_MalibNextChunk(&pbBuf[dIndex], (dSize-dIndex),
+ AVMALIB_CHUNK_PHASE_MMMDSUB, &dChunkID, &dChunkNo);
+ if ((sdChunkSize >= 12) && (dChunkID == AVMALIB_CHUNKCODE_OPDA))
+ {
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ psLoad_Info->sOption_Info.pbOpda = &pbBuf[dIndex];
+ psLoad_Info->sOption_Info.dOpdaSize = (unsigned int)sdChunkSize;
+ dIndex += sdChunkSize;
+ }
+ }
+
+/* get Track Chunk information */
+ while (dSize > (dIndex + AV_MMF_CHUNK_HEADER_SIZE + AV_MMF_FILE_CRC_SIZE))
+ {
+ sdChunkSize = _mmf_MalibNextChunk(&pbBuf[dIndex], (dSize-dIndex),
+ AVMALIB_CHUNK_PHASE_MMMDSUB, &dChunkID, &dChunkNo);
+ if (sdChunkSize < 0)
+ {
+ if (sdChunkSize == AVMALIB_CHUNK_ID_ERROR)
+ {
+ return AV_MMF_ERR_FILE;
+ }
+ else {
+ return AV_MMF_ERR_SIZE;
+ }
+ }
+ dIndex += AV_MMF_CHUNK_HEADER_SIZE;
+ switch (dChunkID)
+ {
+ case AVMALIB_CHUNKCODE_MTR :
+ if (dChunkNo > 6)
+ break;
+ psLoad_Info->sTrack_Info[dChunkNo].pbMtr = &(pbBuf[dIndex]);
+ psLoad_Info->sTrack_Info[dChunkNo].dMtrSize = (unsigned int)sdChunkSize;
+ break;
+ case AVMALIB_CHUNKCODE_ATR :
+ if (dChunkNo != 0)
+ break;
+ psLoad_Info->sTrack_Info[AV_MMF_ATR_TRACK_NO].pbMtr = &(pbBuf[dIndex]);
+ psLoad_Info->sTrack_Info[AV_MMF_ATR_TRACK_NO].dMtrSize = (unsigned int)sdChunkSize;
+ break;
+ default :
+ break;
+ }
+ dIndex += sdChunkSize;
+ }
+
+
+
+/* Error Check of Track Chunk */
+ switch (psLoad_Info->dSmafType)
+ {
+ case AV_MMF_SMAF_TYPE_MA2 :
+ sdResult = _mmf_TrackChunkCheck2(psLoad_Info);
+ break;
+ case AV_MMF_SMAF_TYPE_MA3 :
+ sdResult = _mmf_TrackChunkCheck3(psLoad_Info);
+ break;
+ default :
+ if (_mmf_CheckM5P(psLoad_Info)!= AV_MMF_FUNC_SUCCESS) return AV_MMF_ERR_CHUNK;
+ sdResult = _mmf_TrackChunkCheck5(psLoad_Info);
+ break;
+ }
+
+/* check playback time */
+ if (sdResult != AV_MMF_FUNC_SUCCESS) return sdResult;
+
+ debug_msg ( "SUM %ld\n", psLoad_Info->dPlayTime * psLoad_Info->dTimeBase);
+
+ if ((psLoad_Info->dPlayTime * psLoad_Info->dTimeBase) <= AV_MMF_PLAY_TIME_MIN)
+ {
+ return AV_MMF_ERR_SLENGTH;
+ }
+ if ((psLoad_Info->dPlayTime * psLoad_Info->dTimeBase) >= AV_MMF_PLAY_TIME_MAX)
+ {
+ return AV_MMF_ERR_LLENGTH;
+ }
+ rVal = psLoad_Info->dPlayTime*psLoad_Info->dTimeBase;
+ _mmf_GetHvData(psLoad_Info, pbBuf[AV_MMF_POSITION_OF_CTYPE]);
+
+ psLoad_Info->pbMmmd = pbBuf;
+ psLoad_Info->dMmmdSize = dSize;
+ psLoad_Info->dCrc = (unsigned int)dCalcCrc;
+ return rVal;
+}
+
+
+/*********************************************************************************
+ * _mmf_RenewalProfile
+ *
+ * Description:
+ * renew profile data
+ * Argument:
+ * pbFile pointer to SMAF data
+ * Return:
+ * 0 or 1 success(file id)
+ * < 0 error code
+ ********************************************************************************/
+static int
+_mmf_RenewalProfile(unsigned char* pbFile)
+{
+ PLOADINFO psLoad;
+ POPTIONINFO psOptn;
+ PTRACKINFO psTrk;
+ PHUFFMANINFO psHuf;
+
+ psLoad = &(g_sSmaf_Info.sLoad_Info[1]);
+ psOptn = &(psLoad->sOption_Info);
+ psTrk = &(psLoad->sTrack_Info[5]);
+ psHuf = &(psLoad->sHuffman_Info);
+
+/* renew pointer offset to pointer */
+ psLoad->pbMmmd = pbFile;
+ psLoad->dCrc = AV_MMF_CRC_NULL;
+
+ psOptn->pbCnti = &(pbFile[(unsigned int)psOptn->pbCnti]);
+ psOptn->pbOpda = &(pbFile[(unsigned int)psOptn->pbOpda]);
+
+ psTrk->pbMtr = &(pbFile[(unsigned int)psTrk->pbMtr]);
+ psTrk->pbMspi = &(pbFile[(unsigned int)psTrk->pbMspi]);
+ psTrk->pbMtsu = &(pbFile[(unsigned int)psTrk->pbMtsu]);
+ psTrk->pbMtsq = &(pbFile[(unsigned int)psTrk->pbMtsq]);
+ psTrk->pbMtsp = &(pbFile[(unsigned int)psTrk->pbMtsp]);
+
+/* Initialize Huffman information structure */
+ psHuf->psBuffer = psTrk->pbMtsq;
+ psHuf->dMtsqSize = psTrk->dMtsqSize;
+
+ if (psTrk->pbMtr[0] == 0x01)
+ {
+ psHuf->dSeqSize = _mmf_DecodeInit(psHuf);
+ if (psHuf->dSeqSize == AV_MMF_HUFFMAN_TREE_FAILURE)
+ {
+ return AV_MMF_FUNC_ERROR;
+ }
+ }
+ psHuf->psFBuf = psHuf->psBuffer;
+ psHuf->sbFBit = psHuf->sbBitC;
+ psHuf->bFByte = psHuf->bByte;
+
+ return AV_MMF_FUNC_SUCCESS;
+}
+
+
+
+
+
+
+static int
+_mmf_ParseSkipXmf2Mmf(unsigned char* pbFile, unsigned int dFSize)
+{
+ unsigned int skipVal = 0, sizeOfpbFile= dFSize;
+ char cmpXmfCMMD[5];
+ if (pbFile)
+ memcpy(cmpXmfCMMD, pbFile, 4);
+ else
+ {
+ debug_msg ( "NULL pointer!\n");
+ return -1;
+ }
+
+ cmpXmfCMMD[4] = 0;
+
+ if (strncmp(cmpXmfCMMD, "CMMD", 4) == 0)
+ {
+ while (1)
+ {
+ if (pbFile[skipVal] == 'M' && pbFile[skipVal+1] == 'M' && pbFile[skipVal+2] == 'M' && pbFile[skipVal+3] == 'D')
+ {
+ debug_msg ( "MMMD Header found!\n");
+ break;
+ }
+ else
+ {
+ skipVal++;
+ if (skipVal >= sizeOfpbFile)
+ {
+ debug_msg ( "MMMD Header is not found!\n");
+ return -1;
+ }
+ }
+
+ }
+ }
+ else
+ debug_msg ( "File header is not started CMMD\n");
+
+ debug_msg ( "skip value: %d\n", skipVal);
+
+ return skipVal;
+}
+
+static int
+mmf_file_mmf_get_duration (char *src, int is_xmf)
+{
+ int readed = 0;
+ int xmf_skip_offset = 0;
+ MMFileIOHandle *fp = NULL;
+ unsigned char *buf = 0;
+ long long src_size = 0L;
+
+ PLOADINFO load_info;
+ unsigned char *p_crc = NULL;
+ unsigned int dCrc = 0;
+ int ret = 0;
+
+ /*total time (millisecond)*/
+ int ret_msec = 0;
+
+ debug_msg ( "\n");
+
+ /*open*/
+ ret = mmfile_open (&fp, src, MMFILE_RDONLY);
+ if (ret == MMFILE_UTIL_FAIL)
+ {
+ debug_error ( "open failed.\n");
+ return -1;
+ }
+
+ /*get file size*/
+ mmfile_seek (fp, 0L, MMFILE_SEEK_END);
+ src_size = mmfile_tell (fp);
+ mmfile_seek (fp, 0L, MMFILE_SEEK_SET);
+
+ if (src_size <= 0) {
+ debug_msg ( "failed to get file size.\n");
+ ret_msec = -1;
+ goto _RELEASE_RESOURCE;
+ }
+
+ /*alloc work buffer*/
+ buf = mmfile_malloc (src_size + 1);
+
+ /*read data*/
+ if ((readed = mmfile_read (fp, buf, src_size) ) <= 0 ) {
+ debug_error ( "read error. size = %d\n", readed);
+
+ ret_msec = -1;
+ goto _RELEASE_RESOURCE;
+ }
+
+ /*if XMF, get skip offset.*/
+ if (is_xmf) {
+ xmf_skip_offset = _mmf_ParseSkipXmf2Mmf (buf, src_size);
+ if (xmf_skip_offset == -1) {
+ ret_msec = -1;
+ goto _RELEASE_RESOURCE;
+ }
+ }
+
+ if (g_sSmaf_Info.dStatus == AV_MMF_STATUS_SAT_PROFILE) {
+ load_info = &(g_sSmaf_Info.sLoad_Info[1]);
+ if (load_info->dMmmdSize <= src_size) {
+ p_crc = &(buf[load_info->dMmmdSize -2+xmf_skip_offset]);
+ dCrc = (unsigned int)((((unsigned int)p_crc[0]) << 8) + (unsigned int)p_crc[1]);
+ } else {
+ dCrc = AV_MMF_CRC_NULL;
+ }
+
+ if (dCrc == load_info->dCrc) {
+ if (_mmf_RenewalProfile (buf + xmf_skip_offset) == AV_MMF_FUNC_SUCCESS) {
+ g_sSmaf_Info.dStatus = AV_MMF_STATUS_LOADED;
+ ret_msec = -1;
+ goto _RELEASE_RESOURCE;
+ }
+ }
+ }
+
+ ret_msec = _mmf_MALoad (buf + xmf_skip_offset, src_size);
+
+_RELEASE_RESOURCE:
+
+ mmfile_close (fp);
+
+ if (buf) mmfile_free (buf);
+
+ return ret_msec;
+}
+
diff --git a/formats/ffmpeg/mm_file_format_mp3.c b/formats/ffmpeg/mm_file_format_mp3.c
new file mode 100755
index 0000000..5d01e99
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_mp3.c
@@ -0,0 +1,1459 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h> /*memcmp*/
+
+#include <sys/types.h>
+#include <sys/stat.h> /*stat*/
+#include <unistd.h>
+
+#include <stdlib.h> /*malloc*/
+
+#include "mm_debug.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_private.h"
+#include "mm_file_format_audio.h"
+#include "mm_file_format_mp3.h"
+
+
+#define __MMFILE_NEW_FRAME_FUNC
+
+#ifdef __MMFILE_NEW_TAGLIBS__
+#include "mm_file_format_tags.h"
+#endif
+
+
+#define AV_MP3_FIND_SYNC_LEN 1024*30
+#undef MIN
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+
+static const unsigned char mp3FrameMasking[4] = {0xFF,0xFE,0x0C,0x00};
+static unsigned char mp3FrameDataValid[4];
+
+static const int mp3BitRateTable[2][3][16] = {
+ { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,},
+ {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,},
+ {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} },
+
+ { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,},
+ {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,},
+ {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} }
+};
+
+static const int mp3SamRateTable[3][3] =
+{ {44100, 48000, 32000},
+ {22050, 24000, 16000} ,
+ {11025, 12000, 8000}
+};
+
+#define IS_VALID_FRAME_MP3(x) \
+ ((((x)[0] & mp3FrameMasking[0]) == mp3FrameDataValid[0]) && \
+ (((x)[1] & mp3FrameMasking[1]) == mp3FrameDataValid[1]) && \
+ (((x)[2] & mp3FrameMasking[2]) == mp3FrameDataValid[2]) && \
+ (((x)[3] & mp3FrameMasking[3]) == mp3FrameDataValid[3]))
+
+
+
+/* interface functions */
+int mmfile_format_read_stream_mp3 (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_mp3 (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_mp3 (MMFileFormatContext *formatContext);
+int mmfile_format_close_mp3 (MMFileFormatContext *formatContext);
+
+/* internal */
+static int mmf_file_mp3_get_infomation (char *src, AvFileContentInfo* pInfo );
+
+EXPORT_API
+int mmfile_format_open_mp3 (MMFileFormatContext *formatContext)
+{
+ AvFileContentInfo *privateData = NULL;;
+ int ret = 0;
+
+ debug_fenter();
+
+ if (NULL == formatContext)
+ {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->pre_checked == 0) {
+ ret = MMFileFormatIsValidMP3 (formatContext->uriFileName,5);
+ if ( ret == 0 )
+ {
+ debug_error("It is not mp3 file\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+ }
+
+
+ formatContext->ReadStream = mmfile_format_read_stream_mp3;
+ formatContext->ReadFrame = mmfile_format_read_frame_mp3;
+ formatContext->ReadTag = mmfile_format_read_tag_mp3;
+ formatContext->Close = mmfile_format_close_mp3;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ privateData = mmfile_malloc (sizeof (AvFileContentInfo));
+ if (!privateData)
+ {
+ debug_error ("error: mmfile_malloc MP3 privateData\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->privateFormatData = privateData;
+
+ ret = mmf_file_mp3_get_infomation (formatContext->uriFileName, privateData);
+ if ( ret == -1 )
+ {
+ debug_error ("error: mmfile_format_read_stream_mp3\n");
+ goto exception;
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ mmfile_format_close_mp3 (formatContext);
+ return MMFILE_FORMAT_FAIL;
+}
+
+
+EXPORT_API
+int mmfile_format_read_stream_mp3 (MMFileFormatContext *formatContext)
+{
+ AvFileContentInfo *privateData = NULL;
+ debug_fenter();
+
+ if (!formatContext || !formatContext->privateFormatData)
+ {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ privateData = formatContext->privateFormatData;
+
+ formatContext->duration = privateData->duration;
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+ formatContext->nbStreams = 1;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = mmfile_malloc (sizeof (MMFileFormatStream));
+ if (NULL == formatContext->streams[MMFILE_AUDIO_STREAM])
+ {
+ debug_error ("formatContext->streams[MMFILE_AUDIO_STREAM] is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->streams[MMFILE_AUDIO_STREAM]->streamType = MMFILE_AUDIO_STREAM;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_MP3;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->bitRate = (privateData->bitRate*1000);
+ formatContext->streams[MMFILE_AUDIO_STREAM]->framePerSec = (privateData->duration == 0 ? 0 : privateData->frameNum/privateData->duration);
+ formatContext->streams[MMFILE_AUDIO_STREAM]->width = 0;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->height = 0;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->nbChannel = privateData->channels;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->samplePerSec = privateData->sampleRate;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_frame_mp3 (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_read_tag_mp3 (MMFileFormatContext *formatContext)
+{
+ AvFileContentInfo *privateData = NULL;
+ debug_fenter();
+
+ if (!formatContext || !formatContext->privateFormatData)
+ {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ privateData = formatContext->privateFormatData;
+
+ if (privateData->pTitle) formatContext->title = mmfile_strdup(privateData->pTitle);
+ if (privateData->pArtist) formatContext->artist = mmfile_strdup(privateData->pArtist);
+ if (privateData->pAuthor) formatContext->author = mmfile_strdup(privateData->pAuthor);
+ if (privateData->pCopyright) formatContext->copyright = mmfile_strdup(privateData->pCopyright);
+ if (privateData->pDescription) formatContext->comment = mmfile_strdup(privateData->pDescription);
+ if (privateData->pAlbum) formatContext->album = mmfile_strdup(privateData->pAlbum);
+ if (privateData->pYear) formatContext->year = mmfile_strdup(privateData->pYear);
+ if (privateData->pGenre) formatContext->genre = mmfile_strdup(privateData->pGenre);
+ if (privateData->pTrackNum) formatContext->tagTrackNum = mmfile_strdup(privateData->pTrackNum);
+ if (privateData->pComposer) formatContext->composer = mmfile_strdup(privateData->pComposer);
+ if (privateData->pContentGroup) formatContext->classification = mmfile_strdup(privateData->pContentGroup);
+ if (privateData->pConductor) formatContext->conductor = mmfile_strdup(privateData->pConductor);
+ if (privateData->pUnsyncLyrics) formatContext->unsyncLyrics= mmfile_strdup(privateData->pUnsyncLyrics);
+ if (privateData->pSyncLyrics) formatContext->syncLyrics= privateData->pSyncLyrics;
+ if (privateData->syncLyricsNum) formatContext->syncLyricsNum= privateData->syncLyricsNum;
+ if (privateData->pRecDate) formatContext->recDate= mmfile_strdup(privateData->pRecDate);
+
+ if(privateData->imageInfo.imageLen > 0)
+ {
+ formatContext->artwork = mmfile_malloc (privateData->imageInfo.imageLen);
+ if(formatContext->artwork)
+ {
+ formatContext->artworkSize = privateData->imageInfo.imageLen;
+ memcpy (formatContext->artwork, privateData->imageInfo.pImageBuf, privateData->imageInfo.imageLen);
+ if (strlen(privateData->imageInfo.imageMIMEType) > 0)
+ formatContext->artworkMime= mmfile_strdup(privateData->imageInfo.imageMIMEType);
+ else if(strlen(privateData->imageInfo.imageExt) > 0) {
+ debug_msg("ID3 tag V2 File");
+ formatContext->artworkMime= mmfile_strdup(privateData->imageInfo.imageExt);
+ }
+ else {
+ debug_error("Album art image exist but there is no type information of album art\n");
+ }
+ }
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+EXPORT_API
+int mmfile_format_close_mp3 (MMFileFormatContext *formatContext)
+{
+ AvFileContentInfo *privateData = NULL;
+
+ if (formatContext)
+ {
+ privateData = formatContext->privateFormatData;
+ if (privateData)
+ {
+ mm_file_free_AvFileContentInfo (privateData);
+ mmfile_free (privateData);
+ formatContext->privateFormatData = NULL;
+ }
+ }
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+static int
+__AvExtractI4(unsigned char *buf)
+{
+ int I4;
+
+ I4 = buf[0];
+ I4 <<= 8;
+ I4 |= buf[1];
+ I4 <<= 8;
+ I4 |= buf[2];
+ I4 <<= 8;
+ I4 |= buf[3];
+
+ return I4;
+}
+
+static int
+__AvExtractI2(unsigned char *buf)
+{
+ int I2;
+
+ I2 = buf[0];
+ I2 <<= 8;
+ I2 |= buf[1];
+ I2 <<= 8;
+
+ return I2;
+}
+
+static int
+__AvGetXingHeader( AvXHeadData* headData, unsigned char *buf )
+{
+ int index, headFlags;
+ int hId, hMode, hSrIndex;
+ static int mp3SamRateTable[4] = { 44100, 48000, 32000, 99999 };
+
+ // get Xing header data
+ headData->flags = 0;
+
+ // get selected MP3 header data
+ hId = (buf[1] >> 3) & 1;
+ hSrIndex = (buf[2] >> 2) & 3;
+ hMode = (buf[3] >> 6) & 3;
+
+
+ // determine offset of header
+ if( hId ) // mpeg1
+ {
+ if( hMode != 3 )
+ buf += (32+4);
+ else
+ buf += (17+4);
+ }
+ else // mpeg2
+ {
+ if( hMode != 3 )
+ buf += (17+4);
+ else
+ buf += (9+4);
+ }
+
+ if( buf[0] != 'X' ) return 0; // fail
+ if( buf[1] != 'i' ) return 0; // header not found
+ if( buf[2] != 'n' ) return 0;
+ if( buf[3] != 'g' ) return 0;
+ buf += 4;
+
+ headData->hId = hId;
+ headData->sampRate = mp3SamRateTable[hSrIndex];
+ if( hId == 0 )
+ headData->sampRate >>= 1;
+
+ headFlags = headData->flags = __AvExtractI4( buf ); // get flags
+ buf+=4;
+
+ if( headFlags & FRAMES_FLAG )
+ {
+ headData->frames = __AvExtractI4( buf );
+ buf+=4;
+ }
+ if( headFlags & BYTES_FLAG )
+ {
+ headData->bytes = __AvExtractI4( buf );
+ buf+=4;
+ }
+
+ if( headFlags & TOC_FLAG )
+ {
+ if( headData->toc != NULL )
+ {
+ for( index = 0; index < 100; index++ )
+ headData->toc[index] = buf[index];
+ }
+ buf+=100;
+ }
+
+ headData->vbrScale = -1;
+ if( headFlags & VBR_SCALE_FLAG )
+ {
+ headData->vbrScale = __AvExtractI4( buf );
+ buf+=4;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("Xing header: sampling-rate:%d, stream-size:%d, frame-number:%d\n",
+ headData->sampRate, headData->bytes, headData->frames);
+ #endif
+
+ return 1; // success
+}
+
+static int
+__AvGetVBRIHeader( AvVBRIHeadData* headData, unsigned char *buf )
+{
+ int hId, hSrIndex;
+ static int mp3SamRateTable[4] = { 44100, 48000, 32000, 99999 };
+
+
+ // get selected MP3 header data
+ hId = (buf[1] >> 3) & 1;
+ hSrIndex = (buf[2] >> 2) & 3;
+
+ buf += (32+4);
+
+ if( buf[0] != 'V' ) return 0; // fail
+ if( buf[1] != 'B' ) return 0; // header not found
+ if( buf[2] != 'R' ) return 0;
+ if( buf[3] != 'I' ) return 0;
+ buf += 4;
+
+ headData->hId = hId;
+ headData->sampRate = mp3SamRateTable[hSrIndex];
+ if( hId == 0 )
+ headData->sampRate >>= 1;
+
+ headData->vID = __AvExtractI2( buf ); // get ver ID
+ buf+=2;
+ headData->delay = __AvExtractI2( buf );
+ buf+=2;
+ headData->qualityIndicator = buf[0];
+ buf+=2;
+ headData->bytes = __AvExtractI4( buf );
+ buf+=4;
+ headData->frames= __AvExtractI4( buf );
+ buf+=4;
+ headData->numOfTOC = __AvExtractI2( buf );
+ buf+=2;
+ headData->vbriScale = __AvExtractI2( buf );
+ buf+=2;
+ headData->sizePerTable = __AvExtractI2( buf );
+ buf+=2;
+ headData->framesPerTable = __AvExtractI2( buf );
+ buf+=2;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("Vbri header: sampling-rate:%d, stream-size:%d, frame-number:%d\n",
+ headData->sampRate, headData->bytes, headData->frames);
+ #endif
+
+ return true; // success
+}
+static bool
+__AvIsValidHeader(AvFileContentInfo* pInfo, unsigned char *buf)
+{
+ bool bSync = false;
+
+ if (VALID_SYNC(buf))
+ {
+ mp3FrameDataValid[0] = (0xFF) & (mp3FrameMasking[0]);
+ mp3FrameDataValid[1] = (0xE0 | (buf[AV_MP3HDR_VERSION_OFS] & AV_MP3HDR_VERSION_M)
+ | (buf[AV_MP3HDR_LAYER_OFS] & AV_MP3HDR_LAYER_M)) & (mp3FrameMasking[1]);
+ mp3FrameDataValid[2] = (buf[AV_MP3HDR_SAMPLERATE_OFS] & AV_MP3HDR_SAMPLERATE_M) &
+ (mp3FrameMasking[2]);
+ mp3FrameDataValid[3] = (buf[AV_MP3HDR_CHANNEL_OFS] & AV_MP3HDR_CHANNEL_M) &
+ (mp3FrameMasking[3]);
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("*** [%02x][%02x][%02x][%02x] : [%02x][%02x][%02x][%02x]",
+ buf[0], buf[1], buf[2],buf[3],
+ mp3FrameDataValid[0], mp3FrameDataValid[1], mp3FrameDataValid[2],mp3FrameDataValid[3]);
+ #endif
+
+ /*
+ * MPEG Audio Layer I/II/III frame header
+ * from : http://www.mp3-tech.org/programmer/frame_header.html *
+ *
+ * AAAAAAAA AAABBCCD EEEEFFGH IIJJKLMM
+ *
+ * A 11 (31-21) Frame sync (all bits must be set)
+ * B 2 (20,19) MPEG Audio version ID
+ * C 2 (18,17) Layer description
+ * D 1 (16) Protection bit
+ * E 4 (15,12) Bitrate index
+ * F 2 (11,10) Sampling rate frequency index
+ * G 1 (9) Padding bit
+ * H 1 (8) Private bit. This one is only informative.
+ * I 2 (7,6) Channel Mode
+ * J 2 (5,4) Mode extension (Only used in Joint stereo)
+ * K 1 (3) Copyright
+ * L 1 (2) Original
+ * M 2 (1,0) Emphasis
+ *
+ */
+
+ /* Simple check for version, layer, bitrate, samplerate */
+ if ( (buf[1] & 0x18) != 0x08 && /* 000XX000 : MPEG Audio version ID, XX=01 - reserved => 00001000(0x08) */
+ (buf[1] & 0x06) != 0x00 && /* 00000XX0 : Layer description, XX=00 - reserved => 00000000(0x00) */
+ (buf[2] & 0xF0) != 0xF0 && /* XXXX0000 : Bitrate index, XX=1111 - bad => 11110000(0xF0) */
+ (buf[2] & 0x0C) != 0x0C) /* 0000XX00 : Sampling rate frequency index , XX=11 -reserved => 00001100(0x0C) */
+ {
+ bSync = true;
+ }
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("=> %s\n", bSync? "Good!":"Bad...");
+ #endif
+ }
+
+ if(bSync == true)
+ return true;
+ else
+ return false;
+}
+
+static bool
+__AvParseMp3Header( AvFileContentInfo* pInfo, unsigned char* header )
+{
+ unsigned char result;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("### [%02x][%02x][%02x][%02x] ###\n", header[0], header[1], header[2],header[3]);
+ #endif
+
+ // 1. Check the version of mp3
+ result = header[1] & MASK_MPEG;
+ switch (result)
+ {
+ case MASK_MPEG_1:
+ pInfo->mpegVersion = AV_MPEG_VER_1;
+ break;
+ case MASK_MPEG_2:
+ pInfo->mpegVersion = AV_MPEG_VER_2;
+ break;
+ case MASK_MPEG_25:
+ pInfo->mpegVersion = AV_MPEG_VER_25;
+ break;
+ default:
+ return false;
+ }
+
+ // 2. Get a layer
+ result = header[1] & MASK_LAYER;
+ switch (result)
+ {
+ case MASK_LAYER_1:
+ pInfo->layer = AV_MP3_LAYER_1;
+ break;
+ case MASK_LAYER_2:
+ pInfo->layer = AV_MP3_LAYER_2;
+ break;
+ case MASK_LAYER_3:
+ pInfo->layer = AV_MP3_LAYER_3;
+ break;
+ default:
+ return false;
+ }
+
+ // 3. bitrate
+ result = header[2] >> 4;
+ if ( pInfo->mpegVersion == AV_MPEG_VER_1 )
+ pInfo->bitRate = mp3BitRateTable[0][pInfo->layer-1][(int)result] ;
+ else
+ pInfo->bitRate = mp3BitRateTable[1][pInfo->layer-1][(int)result] ;
+
+ // 4. samplerate
+ result = ( header[2] & MASK_SAMPLERATE ) >> 2;
+ if ( result == 0x03 )
+ return false;
+ else
+ pInfo->sampleRate = mp3SamRateTable[pInfo->mpegVersion - 1][(int)result];
+
+ // 5. channel
+ result = header[3] & MASK_CHANNEL;
+ switch (result)
+ {
+ case MASK_CHANNEL_ST:
+ pInfo->channelIndex = 0;
+ pInfo->channels = 2;
+ break;
+ case MASK_CHANNEL_JS:
+ pInfo->channelIndex = 1;
+ pInfo->channels = 2;
+ break;
+ case MASK_CHANNEL_DC:
+ pInfo->channelIndex = 2;
+ pInfo->channels = 2;
+ break;
+ case MASK_CHANNEL_MN:
+ pInfo->channelIndex = 3;;
+ pInfo->channels = 1;
+ break;
+ default:
+ return false;
+ }
+
+ // 6. padding
+ result = header[2] & MASK_PADDING;
+ if ( result == MASK_PADDING )
+ pInfo->bPadding = true;
+ else
+ pInfo->bPadding = false;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("=> samplerate=%d, bitrate=%d, layer=%d, version=%d, channel=%d, padding=%d",
+ pInfo->sampleRate, pInfo->bitRate, pInfo->layer, pInfo->mpegVersion, pInfo->channels, pInfo->bPadding );
+ #endif
+
+ return true;
+}
+
+static bool
+__AvParseXingHeader( AvFileContentInfo* pInfo, unsigned char* buf )
+{
+ AvXHeadData data;
+ memset( &data, 0x00, sizeof(AvXHeadData) );
+
+ // 1. Xing Header üũ
+ if((pInfo->mpegVersion == AV_MPEG_VER_1) && (pInfo->channels == 2))
+ {
+ if( buf[36] != 'X' ) return false;
+ if( buf[37] != 'i' ) return false;
+ if( buf[38] != 'n' ) return false;
+ if( buf[39] != 'g' ) return false;
+ }
+ else
+ if((pInfo->mpegVersion == AV_MPEG_VER_2) && (pInfo->channels == 1))
+ {
+ if( buf[13] != 'X' ) return false;
+ if( buf[14] != 'i' ) return false;
+ if( buf[15] != 'n' ) return false;
+ if( buf[16] != 'g' ) return false;
+ }
+ else
+ {
+ if( buf[21] != 'X' ) return false;
+ if( buf[22] != 'i' ) return false;
+ if( buf[23] != 'n' ) return false;
+ if( buf[24] != 'g' ) return false;
+ }
+
+ // 2. TOC�� ����ұ�
+ if ( pInfo->pToc )
+ data.toc = (unsigned char *)(pInfo->pToc);
+
+ if ( __AvGetXingHeader( &data, (unsigned char *)buf ) == 1 ) // VBR�̴�.
+ {
+ if (data.sampRate == 0 || data.bytes == 0 || data.frames == 0) {
+ debug_error ("invalid Xing header\n");
+ return false;
+ }
+
+ pInfo->sampleRate = data.sampRate;
+ pInfo->datafileLen = data.bytes;
+ pInfo->frameNum = data.frames;
+ pInfo->frameSize = (int) ( (float) data.bytes / (float) data.frames ) ;
+ pInfo->bVbr = true;
+ return true;
+ }
+ else
+ return false;
+}
+
+static bool
+__AvParseVBRIHeader( AvFileContentInfo* pInfo, unsigned char* buf )
+{
+ AvVBRIHeadData data;
+ memset( &data, 0x00, sizeof(AvVBRIHeadData) );
+
+ // 1. Xing Header üũ
+ if((pInfo->mpegVersion == AV_MPEG_VER_1) && (pInfo->channels == 2))
+ {
+ if( buf[36] != 'V' ) return false;
+ if( buf[37] != 'B' ) return false;
+ if( buf[38] != 'R' ) return false;
+ if( buf[39] != 'I' ) return false;
+ }
+ else
+ if((pInfo->mpegVersion == AV_MPEG_VER_2) && (pInfo->channels == 1))
+ {
+ if( buf[36] != 'V' ) return false;
+ if( buf[37] != 'B' ) return false;
+ if( buf[38] != 'R' ) return false;
+ if( buf[39] != 'I' ) return false;
+ }
+ else
+ {
+ if( buf[36] != 'V' ) return false;
+ if( buf[37] != 'B' ) return false;
+ if( buf[38] != 'R' ) return false;
+ if( buf[39] != 'I' ) return false;
+ }
+
+ // 2. TOC�� ����ұ�
+ if ( pInfo->pToc )
+ data.toc = (unsigned char*)(pInfo->pToc);
+
+ if ( __AvGetVBRIHeader( &data, (unsigned char*)buf ) == 1 ) // VBR�̴�.
+ {
+ if (data.sampRate == 0 || data.bytes == 0 || data.frames == 0) {
+ debug_error ("invalid Vbri header\n");
+ return false;
+ }
+
+ pInfo->sampleRate = data.sampRate;
+ pInfo->datafileLen = data.bytes;
+ pInfo->frameNum = data.frames;
+ pInfo->frameSize = (int) ( (float) data.bytes / (float) data.frames ) ;
+ pInfo->bVbr = true;
+ return true;
+ }
+ else
+ return false;
+}
+
+#ifdef __MMFILE_NEW_FRAME_FUNC // from gst
+static bool
+__AvGetMp3FrameSize( AvFileContentInfo* pInfo )
+{
+ unsigned int frameSize = 0;
+ if ( pInfo == NULL )
+ return false;
+
+ frameSize = pInfo->bPadding;
+ if (pInfo->bitRate == 0) {
+ if (pInfo->layer == 1) {
+ frameSize *= 4;
+ frameSize += 0/* FIXME: possible_free_framelen*/;
+ pInfo->bitRate = frameSize * pInfo->sampleRate / 48000;
+ } else {
+ frameSize += 0/* FIXME: possible_free_framelen*/;
+ pInfo->bitRate = frameSize * pInfo->sampleRate /
+ ((pInfo->layer == AV_MP3_LAYER_3 && pInfo->mpegVersion != AV_MPEG_VER_1) ? 72000 : 144000);
+ }
+ } else {
+ /* calculating */
+ if (pInfo->layer == 1) {
+ frameSize = ((12000 * pInfo->bitRate / pInfo->sampleRate) + frameSize) * 4;
+ } else {
+ frameSize += ((pInfo->layer == AV_MP3_LAYER_3
+ && pInfo->mpegVersion != AV_MPEG_VER_1) ? 72000 : 144000) * pInfo->bitRate / pInfo->sampleRate;
+ }
+ }
+
+ pInfo->frameSize = (int)frameSize;
+
+ return true;
+}
+#endif
+
+
+static bool
+__AvGetXingBitrate( AvFileContentInfo* pInfo )
+{
+ float br, factor;
+ int padding;
+
+ if ( pInfo == NULL || pInfo->bVbr == false )
+ return false;
+
+ if ( pInfo->bPadding )
+ padding = 1;
+ else
+ padding = 0;
+
+ if (pInfo->mpegVersion == AV_MPEG_VER_1 ) // MPEG version 1
+ {
+ if (pInfo->layer == AV_MP3_LAYER_1 ) // Layer 1
+ factor = 48000.0;
+ else // Layer 2, 3
+ factor = 144000.0;
+ }
+ else // MPEG version 2
+ {
+ if (pInfo->layer == AV_MP3_LAYER_1 ) // Layer 1
+ factor = 24000.0;
+ else // Layer 2, 3
+ factor = 72000.0;
+ }
+
+ br = ( pInfo->frameSize - padding ) * pInfo->sampleRate / factor;
+
+ pInfo->bitRate = (int) br;
+
+ return true;
+}
+
+static bool
+__AvGetVBRIBitrate( AvFileContentInfo* pInfo )
+{
+ float br, factor;
+ int padding;
+
+ if ( pInfo == NULL || pInfo->bVbr == false )
+ return false;
+
+ if ( pInfo->bPadding )
+ padding = 1;
+ else
+ padding = 0;
+
+ if (pInfo->mpegVersion == AV_MPEG_VER_1 ) // MPEG version 1
+ {
+ if (pInfo->layer == AV_MP3_LAYER_1 ) // Layer 1
+ factor = 48000.0;
+ else // Layer 2, 3
+ factor = 144000.0;
+ }
+ else // MPEG version 2
+ {
+ if (pInfo->layer == AV_MP3_LAYER_1 ) // Layer 1
+ factor = 24000.0;
+ else // Layer 2, 3
+ factor = 72000.0;
+ }
+
+ br = ( pInfo->frameSize - padding ) * pInfo->sampleRate / factor;
+
+ pInfo->bitRate = (int) br;
+
+ return true;
+}
+
+static int __AvGetLastID3offset (MMFileIOHandle *fp, unsigned int *offset)
+{
+#define _MMFILE_MP3_TAGV2_HEADER_LEN 10
+#define _MMFILE_GET_INT_NUMBER(buff) (int)( (((int)(buff)[0]) << 24) | (((int)(buff)[1]) << 16) | (((int)(buff)[2]) << 8) | (((int)(buff)[3])))
+
+ unsigned char tagHeader[_MMFILE_MP3_TAGV2_HEADER_LEN] = {0,};
+ unsigned int tagInfoSize = 0;
+ unsigned int acc_tagsize = 0;
+ int tagVersion = 0;
+ int encSize = 0;
+ int readed = 0;
+
+ /*init offset*/
+ *offset = 0;
+
+ mmfile_seek(fp, 0, MMFILE_SEEK_SET);
+
+_START_TAG_SEARCH:
+
+ readed = mmfile_read (fp, tagHeader, _MMFILE_MP3_TAGV2_HEADER_LEN);
+ if (readed != _MMFILE_MP3_TAGV2_HEADER_LEN) {
+ debug_error ("read error occured.\n");
+ return 0;
+ }
+
+ if (memcmp (tagHeader, "ID3", 3) == 0) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("'ID3' found.\n");
+ #endif
+ } else {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("'ID3' not found.\n");
+ #endif
+ goto search_end;
+ }
+
+ /**@note weak id3v2 tag checking*/
+ if (tagHeader[3] != 0xFF && tagHeader[4] != 0xFF &&
+ (tagHeader[6] & 0x80) == 0 && (tagHeader[7] & 0x80) == 0 &&
+ (tagHeader[8] & 0x80) == 0 && (tagHeader[9] & 0x80) == 0) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("good ID3V2 tag.\n");
+ #endif
+ } else {
+ debug_warning ("It's bad ID3V2 tag.\n");
+ goto search_end;
+ }
+
+ tagVersion = tagHeader[3];
+
+ if (tagVersion > 4) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg("Tag version not supported\n");
+ #endif
+ goto search_end;
+ }
+
+ encSize = _MMFILE_GET_INT_NUMBER(&tagHeader[6]);
+ tagInfoSize = _MMFILE_MP3_TAGV2_HEADER_LEN;
+ tagInfoSize += (((encSize & 0x0000007F) >> 0) | ((encSize & 0x00007F00) >> 1) | ((encSize & 0x007F0000) >> 2) | ((encSize & 0x7F000000) >> 3));
+
+ /**@note unfortunately, some contents has many id3 tag.*/
+ acc_tagsize += tagInfoSize;
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg("tag size: %u, offset: %u\n", tagInfoSize, acc_tagsize);
+ #endif
+
+ mmfile_seek(fp, acc_tagsize, MMFILE_SEEK_SET);
+ *offset = acc_tagsize;
+ goto _START_TAG_SEARCH;
+
+search_end:
+ return 1;
+}
+
+
+
+/*
+ * This fuction retrieves the start position of header.
+ * Param _pFile [in] Specifies the file pointer of mp3 file.
+ * This function returns the start position of header.
+ */
+static int
+__AvFindStartOfMp3Header(MMFileIOHandle *hFile, unsigned char *buf, AvFileContentInfo* pInfo)
+{
+ int index=0;
+ long readLen;
+ unsigned long id3v2TagLen = 0;
+ unsigned char *pHeader = NULL;
+ unsigned long preHeaderGap = 0;
+ unsigned long frameLen = 0;
+ unsigned long nextFrameOff = 0; /* Offset to the start of the next frame */
+ unsigned long nextFrameOffEnd = 0;
+ unsigned long bufLen = 0;
+ bool bFoundSync = false;
+ unsigned long minLen;
+
+
+
+ if(pInfo->fileLen > (_AV_MP3_HEADER_POSITION_MAX+ pInfo->tagV2Info.tagLen))
+ bufLen = _AV_MP3_HEADER_POSITION_MAX;
+ else
+ bufLen = pInfo ->fileLen - pInfo->tagV2Info.tagLen;
+
+ if(IS_ID3V2_TAG(buf))
+ {
+
+
+ if(pInfo->tagV2Info.tagVersion == 0x02)
+ {
+
+ if(!mm_file_id3tag_parse_v222(pInfo, buf))
+ pInfo->tagV2Info.tagLen = 0;
+ }
+ else if (pInfo->tagV2Info.tagVersion == 0x03)
+ {
+
+ if(!mm_file_id3tag_parse_v223(pInfo, buf))
+ pInfo->tagV2Info.tagLen = 0;
+ }
+ else if (pInfo->tagV2Info.tagVersion == 0x04)
+ {
+
+ if(!mm_file_id3tag_parse_v224(pInfo, buf)) // currently 2.4 ver pased by 2.3 routine
+ pInfo->tagV2Info.tagLen = 0;
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "pInfo->tagV2Info.tagVersion(%d)\n", pInfo->tagV2Info.tagVersion);
+ #endif
+ }
+
+ id3v2TagLen = pInfo->tagV2Info.tagLen;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "id3v2TagLen(%d)\n", id3v2TagLen);
+ #endif
+
+ if(id3v2TagLen)
+ {
+ if (mmfile_seek (hFile, id3v2TagLen, SEEK_SET) < 0) {
+ debug_error ( "seek failed.\n");
+ return -1;
+ }
+ if ((readLen = mmfile_read (hFile, buf, bufLen)) <= 0) {
+ debug_error ( "seek failed.\n");
+ return -1;
+ }
+ }
+ while(1)
+ {
+ if (preHeaderGap == bufLen -2)
+ break;
+ if(__AvIsValidHeader(pInfo, buf+preHeaderGap))
+ break;
+ preHeaderGap++;
+ }
+
+ }
+ else
+ {
+ while(1)
+ {
+ if (preHeaderGap == bufLen -2)
+ break;
+ if(__AvIsValidHeader(pInfo, buf+preHeaderGap))
+ break;
+ preHeaderGap++;
+ }
+
+ }
+ minLen = 4;
+
+ buf += preHeaderGap;
+ index += preHeaderGap;
+ while (index <= (bufLen - minLen))
+ {
+ if(buf[0] == 0xff)
+ {
+ if(VALID_SYNC(buf))
+ {
+ if(bufLen - index > 256)
+ {
+ pHeader = mmfile_malloc (256);
+ if (pHeader == NULL)
+ {
+ debug_error ( "malloc failed.\n");
+ return -1;
+ }
+ strncpy((char *)pHeader, (char *)buf, 256);
+ }
+ else
+ {
+ debug_error ( "Header field is not exist\n");
+ return -1;
+ }
+ if ( __AvParseMp3Header( pInfo, pHeader ) == false)
+ {
+ //return -1;
+ if(pHeader)
+ _FREE_EX(pHeader);
+ debug_warning ( "Mp3 parse header failed & index(%d)\n", index);
+ buf++;
+ index++;
+ continue;
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "This header is valid. index(%d)\n", index);
+ #endif
+ }
+
+ if ( __AvParseXingHeader( pInfo, pHeader ) )
+ {
+ __AvGetXingBitrate( pInfo );
+ }
+ else if(__AvParseVBRIHeader( pInfo, pHeader ))
+ {
+ __AvGetVBRIBitrate( pInfo );
+ }
+
+ if (pInfo->bVbr)
+ {
+ if(pHeader)
+ _FREE_EX(pHeader);
+ bFoundSync = true;
+ break;
+ }
+ else
+ {
+ if(__AvIsValidHeader(pInfo, pHeader))
+ {
+ if(pHeader)
+ _FREE_EX(pHeader);
+
+ __AvGetMp3FrameSize( pInfo );
+ pInfo->datafileLen = pInfo->fileLen - pInfo->headerPos;
+ frameLen = pInfo->frameSize;
+ if (frameLen)
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("<<< frameLen=[%d] >>> \n", frameLen);
+ #endif
+
+ #ifndef __MMFILE_NEW_FRAME_FUNC // FIXME : what purpose to do this?
+ /* Account for loss of precision in the frame length calculation*/
+ frameLen--;
+ #endif
+
+ /* Check if the remaining buffer size is large enough to
+ * look for another sync */
+ if ((index + frameLen) < (bufLen - (minLen - 1)))
+ {
+ nextFrameOff = frameLen;
+ nextFrameOffEnd = nextFrameOff +MIN(6, bufLen - (index+frameLen) - (minLen - 1));
+
+ /* Search the next few bytes for the next sync */
+ while (nextFrameOff < nextFrameOffEnd)
+ {
+ if (VALID_SYNC(buf+nextFrameOff))
+ {
+ if(IS_VALID_FRAME_MP3(buf+nextFrameOff))
+ {
+ bFoundSync = true;
+ break;
+ }
+ }
+ nextFrameOff++;
+ }
+ if (bFoundSync == true)
+ break;
+ }
+ else
+ {
+ /* Assume that the first sync is valid, since there is not
+ * enough data in the buffer to look for the next sync */
+ bFoundSync = true;
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ debug_warning ( "Is not vaild header pHeader\n");
+ }
+ }
+ if(pHeader)
+ _FREE_EX(pHeader);
+ }
+ else
+ {
+ debug_warning ( "Mp3 file frist byte is 0xff, but not header sync\n");
+ }
+ }
+ buf++;
+ index++;
+ }
+
+ _FREE_EX (pHeader);
+
+ if (mmfile_seek(hFile, 0, SEEK_SET) < 0) {
+ debug_error ( "seek error!\n");
+ return -1;
+ }
+ if(index > (bufLen - minLen))
+ {
+ debug_warning ( "Mp3 file sync is not found : index(%d) bufLen(%d), minLen(%d)\n", index, bufLen, minLen);
+ return -1;
+ }
+
+ if(bFoundSync == true)
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Mp3 file found a sync Success!\n");
+ #endif
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Mp3 file found a sync Failed!\n");
+ #endif
+ return -1;
+ }
+
+ return index+id3v2TagLen;
+}
+
+/*
+ * This function retrieves the mp3 information.
+ * Param szFileName [in] Specifies a mp3 file path.
+ * Param _frame [out] Specifies a struct pointer for mp3 information.
+ * This function returns true on success, or false on failure.
+ */
+static int mmf_file_mp3_get_infomation (char *filename, AvFileContentInfo* pInfo )
+{
+ MMFileIOHandle *hFile;
+ unsigned char header[256];
+ unsigned long numOfFrames=0;
+ unsigned long frameSamples=0;
+ unsigned char *buf = NULL;
+ unsigned char* v2TagExistCheck = NULL;
+ unsigned int tempNumFrames = 0;
+ int readAmount = 0, readedDataLen = 0;
+ unsigned long long tempduration = 0;
+ unsigned char TagBuff[MP3TAGINFO_SIZE + TAGV1_SEEK_GAP];
+ unsigned char TagV1ID[4] = { 0x54, 0x41, 0x47}; //TAG
+ int tagHeaderPos = 0;
+ int ret = 0;
+ unsigned int head_offset = 0;
+ debug_fenter();
+
+ if (pInfo == NULL || filename == NULL)
+ return -1;
+
+ memset( pInfo, 0x00, sizeof(AvFileContentInfo) );
+
+ pInfo->tagV2Info.tagLen = 0;
+ pInfo->headerPos = 0;
+ pInfo->genre = 148;
+
+ /*open*/
+ ret = mmfile_open (&hFile, filename, MMFILE_RDONLY);
+ if (ret == MMFILE_UTIL_FAIL)
+ {
+ debug_error ( "open failed.\n");
+ return -1;
+ }
+
+ mmfile_seek (hFile, 0L, SEEK_END);
+ pInfo->fileLen = mmfile_tell (hFile);
+ if (pInfo->fileLen <= 0)
+ {
+ debug_error ( "file is too small.\n");
+ goto EXCEPTION;
+ }
+ mmfile_seek (hFile, 0L, SEEK_SET);
+
+ v2TagExistCheck = mmfile_malloc (MP3_TAGv2_HEADER_LEN);
+ if (v2TagExistCheck == NULL) {
+ debug_error ( "malloc failed.\n");
+ goto EXCEPTION;
+ }
+
+ if (mmfile_read (hFile, v2TagExistCheck, MP3_TAGv2_HEADER_LEN) > 0)
+ {
+ if(IS_ID3V2_TAG(v2TagExistCheck))
+ {
+ if(!(v2TagExistCheck[3] == 0xFF || v2TagExistCheck[4] == 0xFF ||v2TagExistCheck[6] >= 0x80 || v2TagExistCheck[7] >= 0x80 || v2TagExistCheck[8] >= 0x80 || v2TagExistCheck[9] >= 0x80))
+ {
+ if(!(v2TagExistCheck[3] > 0x04))
+ {
+ pInfo->tagV2Info.tagVersion = v2TagExistCheck[3];
+ pInfo->tagV2Info.tagLen = MP3_TAGv2_HEADER_LEN;
+ pInfo->tagV2Info.tagLen += (unsigned long)v2TagExistCheck[6] << 21 | (unsigned long)v2TagExistCheck[7] << 14 |(unsigned long)v2TagExistCheck[8] << 7 | (unsigned long)v2TagExistCheck[9];
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "pInfo->tagV2Info.tagLen(%d), pInfo->tagV2Info.tagVersion(%d)\n", pInfo->tagV2Info.tagLen, pInfo->tagV2Info.tagVersion);
+ #endif
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "tag is a not supported version(%d)\n", v2TagExistCheck[3]);
+ #endif
+ }
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "tag is a tag data is valid.\n");
+ #endif
+ }
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "this mp3 file is not included ID3v2 tag info!\n");
+ #endif
+ }
+ }
+ else
+ {
+ debug_error ( "v2TagExistCheck value read fail!\n");
+ if(v2TagExistCheck)
+ _FREE_EX(v2TagExistCheck);
+ goto EXCEPTION;
+ }
+
+ if(v2TagExistCheck)
+ _FREE_EX(v2TagExistCheck);
+
+ if(!(pInfo->fileLen > pInfo->tagV2Info.tagLen ))
+ pInfo->tagV2Info.tagLen = 0;
+
+ if (mmfile_seek(hFile, 0L, SEEK_SET) < 0)
+ goto EXCEPTION;
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "pInfo->fileLen(%lld)\n", pInfo->fileLen);
+ #endif
+
+ if(pInfo->fileLen > (_AV_MP3_HEADER_POSITION_MAX + pInfo->tagV2Info.tagLen))
+ {
+ readAmount = _AV_MP3_HEADER_POSITION_MAX + pInfo->tagV2Info.tagLen;
+ buf = mmfile_malloc (readAmount);
+ if (buf == NULL) {
+ debug_error ( "malloc failed.\n");
+ goto EXCEPTION;
+ }
+
+ while(readAmount > 0)
+ {
+ if(readAmount >= AV_MP3_HEADER_READ_MAX)
+ {
+ if ((readedDataLen <= _AV_MP3_HEADER_POSITION_MAX + pInfo->tagV2Info.tagLen)
+ &&(mmfile_read(hFile, buf+readedDataLen, AV_MP3_HEADER_READ_MAX) <= 0))
+ {
+ if(buf)
+ _FREE_EX(buf);
+
+ goto EXCEPTION;
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Reading buf readedDataLen(%d) readAmount (%d)\n", readedDataLen,readAmount);
+ #endif
+ }
+ }
+ else
+ {
+ if ((readedDataLen <= _AV_MP3_HEADER_POSITION_MAX + pInfo->tagV2Info.tagLen)
+ &&(mmfile_read(hFile, buf+readedDataLen, readAmount) <= 0))
+ {
+ if(buf)
+ _FREE_EX(buf);
+
+ goto EXCEPTION;
+ }
+ else
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "The remained buf readed! readedDataLen(%d) readAmount (%d)\n", readedDataLen,readAmount);
+ #endif
+ }
+ }
+
+ readAmount -= AV_MP3_HEADER_READ_MAX;
+ readedDataLen += AV_MP3_HEADER_READ_MAX;
+
+ if(readAmount <= 0)
+ break;
+ }
+ }
+ else
+ {
+ buf = mmfile_malloc (pInfo->fileLen);
+ if (buf == NULL)
+ {
+ goto EXCEPTION;
+ }
+
+ if (mmfile_read(hFile, buf, pInfo->fileLen) <= 0)
+ {
+ if(buf)
+ _FREE_EX(buf);
+ goto EXCEPTION;
+ }
+ }
+
+
+ if (__AvGetLastID3offset (hFile, &head_offset)) {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "search start offset: %u\n", head_offset);
+ #endif
+ pInfo->tagV2Info.tagLen = head_offset;
+ }
+
+ pInfo->headerPos = (long) __AvFindStartOfMp3Header(hFile, buf, pInfo);
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Header Pos: %ld\n", pInfo->headerPos);
+ #endif
+
+ if(buf)
+ _FREE_EX(buf);
+
+ if (pInfo->headerPos == -1)
+ goto EXCEPTION;
+
+ if (mmfile_seek(hFile, pInfo->headerPos, SEEK_SET) < 0)
+ goto EXCEPTION;
+
+ if (mmfile_read (hFile, header, 256) <= 0)
+ goto EXCEPTION;
+
+ if ( __AvParseMp3Header( pInfo, header ) == false)
+ goto EXCEPTION;
+
+ if ( __AvParseXingHeader( pInfo, header ) )
+ {
+ __AvGetXingBitrate( pInfo );
+ }
+ else if(__AvParseVBRIHeader( pInfo, header ))
+ {
+ __AvGetVBRIBitrate( pInfo );
+ }
+ else
+ {
+ __AvGetMp3FrameSize( pInfo );
+ pInfo->datafileLen = pInfo->fileLen - pInfo->headerPos;
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Mp3 File FrameSize (%d) pInfo->headerPos(%d)\n", pInfo->frameSize,pInfo->headerPos);
+ #endif
+ }
+
+ if (mmfile_seek (hFile, -(MP3TAGINFO_SIZE + TAGV1_SEEK_GAP), SEEK_END) < 0)
+ goto EXCEPTION;
+
+
+ pInfo ->bV1tagFound = false;
+
+ if (mmfile_read (hFile, TagBuff, MP3TAGINFO_SIZE + TAGV1_SEEK_GAP) <= 0)
+ goto EXCEPTION;
+
+ if ((tagHeaderPos = __AvMemstr(TagBuff, TagV1ID, 3, TAGV1_SEEK_GAP+5)) >= 0)
+ {
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Mp3 File Tag is existing\n");
+ #endif
+
+ pInfo ->bV1tagFound = true;
+ memcpy(TagBuff, (TagBuff + tagHeaderPos), MP3TAGINFO_SIZE);
+
+ if(!mm_file_id3tag_parse_v110(pInfo, TagBuff))
+ goto EXCEPTION;
+ }
+
+ mm_file_id3tag_restore_content_info (pInfo);
+
+ if(pInfo->bVbr)
+ numOfFrames = pInfo->frameNum*10;
+ else
+ {
+ numOfFrames = ((pInfo->fileLen
+ -(pInfo->headerPos + (pInfo ->bV1tagFound ? MP3TAGINFO_SIZE : 0) ) )*10) / pInfo->frameSize;
+ }
+ tempNumFrames = (unsigned int)(numOfFrames/10);
+
+
+
+ if((numOfFrames - tempNumFrames * 10 ) > 5)
+ numOfFrames = (numOfFrames/10) + 1;
+ else
+ numOfFrames = numOfFrames/10;
+
+
+
+ tempduration = (unsigned long long)(numOfFrames *1000);
+
+ if(pInfo->mpegVersion== 1)
+ {
+ if(pInfo->layer== 1)
+ frameSamples = MPEG_1_SIZE_LAYER_1;
+ else
+ frameSamples = MPEG_1_SIZE_LAYER_2_3;
+ }
+ else
+ {
+ if(pInfo->layer == 1)
+ frameSamples = MPEG_2_SIZE_LAYER_1;
+ else
+ frameSamples = MPEG_2_SIZE_LAYER_2_3;
+ }
+
+ if(tempduration < (unsigned long long)pInfo->sampleRate)
+ {
+ tempduration = (tempduration*frameSamples*10)/pInfo->sampleRate;
+ tempduration = (tempduration/10);
+ }
+ else
+ tempduration = (tempduration*frameSamples)/pInfo->sampleRate;
+
+ pInfo->duration = tempduration;
+
+ mmfile_close(hFile);
+
+ /*debug print*/
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "Mp3 File pInfo->duration (%lld) \n", pInfo->duration);
+ debug_msg ( "** MP3 **\n");
+ debug_msg ( "Version : %u\n", pInfo->mpegVersion);
+ debug_msg ( "Layer : %u\n", pInfo->layer);
+ debug_msg ( "Channel idx: %u\n", pInfo->channelIndex);
+ debug_msg ( "Is VBR : %d\n", (pInfo->bVbr == true ? 1 : 0));
+ debug_msg ( "Bitrate : %u\n", pInfo->bitRate);
+ debug_msg ( "SampleRate : %u\n", pInfo->sampleRate);
+ debug_msg ( "Channels : %u\n", pInfo->channels);
+ debug_msg ( "**** Info #1 ****\n");
+ debug_msg ( "Title : %s\n", pInfo->pTitle);
+ debug_msg ( "Artist : %s\n", pInfo->pArtist);
+ debug_msg ( "Album : %s\n", pInfo->pAlbum);
+ debug_msg ( "Year : %s\n", pInfo->pYear);
+ debug_msg ( "Comment : %s\n", pInfo->pComment);
+ debug_msg ( "TrackNum : %s\n", pInfo->pTrackNum);
+ debug_msg ( "Genre : %s\n", pInfo->pGenre);
+ debug_msg ( "**** Info #2 ****\n");
+ debug_msg ( "Author : %s\n", pInfo->pAuthor);
+ debug_msg ( "Copyright : %s\n", pInfo->pCopyright);
+ debug_msg ( "Description : %s\n", pInfo->pDescription);
+ debug_msg ( "Rating : %s\n", pInfo->pRating);
+ debug_msg ( "RecDate : %s\n", pInfo->pRecDate);
+ debug_msg ( "Encoded by : %s\n", pInfo->pEncBy);
+ debug_msg ( "URL : %s\n", pInfo->pURL);
+ debug_msg ( "Ori. Artist : %s\n", pInfo->pOriginArtist);
+ debug_msg ( "Composer : %s\n", pInfo->pComposer);
+ debug_msg ( "Conductor : %s\n", pInfo->pConductor);
+ debug_msg ( "Artwork : mime(%s) addr(%p) size(%d)\n", pInfo->imageInfo.imageMIMEType, pInfo->imageInfo.pImageBuf, pInfo->imageInfo.imageLen);
+ debug_msg ( "UnsyncLyrics : %s\n", pInfo->pUnsyncLyrics);
+ debug_msg ( "SyncLyrics size : %d\n", pInfo->syncLyricsNum);
+
+ #endif
+
+ return 0;
+
+EXCEPTION:
+ debug_error ("Error occured!\n");
+ mmfile_close(hFile);
+ return -1;
+}
diff --git a/formats/ffmpeg/mm_file_format_tag_id3.c b/formats/ffmpeg/mm_file_format_tag_id3.c
new file mode 100755
index 0000000..9a96ca7
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_tag_id3.c
@@ -0,0 +1,198 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "mm_debug.h"
+#include "mm_file_format_tag_id3.h"
+
+#define MMFILE_ID3V1TAG_SIZE 128
+#define MMFILE_ID3V2TAG_HEADER_SIZE 10
+
+static unsigned int GetSynchsafeInteger (unsigned int value);
+
+EXPORT_API
+int MMFileID3V1TagFind (MMFileIOHandle *fp, unsigned char bAppended, unsigned int startOffset, unsigned int endOffset, tMMFileTags *out)
+{
+ int ret = 0;
+
+ if (!fp || !out)
+ {
+ debug_error ("Invalid input\n");
+ return MMFILE_ID3TAG_FAIL;
+ }
+
+ if (bAppended)
+ {
+ unsigned char tagSymbol[3] = {0,};
+
+ unsigned int offset = endOffset - MMFILE_ID3V1TAG_SIZE;
+
+ mmfile_seek (fp, offset, MMFILE_SEEK_SET);
+
+ ret = mmfile_read (fp, tagSymbol, 3);
+ if (MMFILE_UTIL_FAIL == ret)
+ {
+ debug_error ("read error\n");
+ return MMFILE_ID3TAG_FAIL;
+ }
+
+ if (memcmp ("TAG", tagSymbol, 3) == 0)
+ {
+ unsigned char versionBuf[2] = {0,};
+
+ out->typeOfTag = MMFILE_TAG_ID3V1;
+ out->startOffset = offset;
+ out->endOffset = endOffset;
+ out->bAppendedTag = 1;
+ out->tagSize = MMFILE_ID3V1TAG_SIZE;
+
+ offset += 125; // byte delimiter offset: ID3V1.1 spec.
+ mmfile_seek (fp, offset, MMFILE_SEEK_SET);
+
+ ret = mmfile_read (fp, versionBuf, 2);
+ if (MMFILE_UTIL_FAIL == ret)
+ {
+ debug_error ("read error\n");
+ return MMFILE_ID3TAG_FAIL;
+ }
+
+ if (versionBuf[0] == '\0' && versionBuf[1] != '\0')
+ {
+ out->version = MMFILE_ID3TAG_V1_1;
+ }
+ else
+ {
+ out->version = MMFILE_ID3TAG_V1_0;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("typeOfTag = %d\n", out->typeOfTag);
+ debug_msg ("startOffset = %d\n", out->startOffset);
+ debug_msg ("endOffset = %d\n", out->endOffset);
+ debug_msg ("bAppendedTag = %d\n", out->bAppendedTag);
+ debug_msg ("tagSize = %d\n", out->tagSize);
+ debug_msg ("version = %d\n", out->version);
+ #endif
+
+ return MMFILE_ID3TAG_SUCCESS;
+ }
+ }
+
+ return MMFILE_ID3TAG_FAIL;
+}
+
+
+EXPORT_API
+int MMFileID3V2TagFind (MMFileIOHandle *fp, unsigned char bAppended, unsigned int startOffset, unsigned int endOffset, tMMFileTags *out)
+{
+ unsigned char *id3v2ID = NULL;
+ unsigned char header[MMFILE_ID3V2TAG_HEADER_SIZE] = {0,};
+ unsigned int offset = 0;
+ unsigned int index = 0;
+ int ret = 0;
+
+ if (!fp || !out)
+ {
+ debug_error ("Invalid input\n");
+ return MMFILE_ID3TAG_FAIL;
+ }
+
+ if (bAppended)
+ {
+ id3v2ID = "3DI";
+ offset = endOffset - MMFILE_ID3V2TAG_HEADER_SIZE;
+ }
+ else
+ {
+ id3v2ID = "ID3";
+ offset = startOffset;
+ }
+
+ mmfile_seek (fp, offset, MMFILE_SEEK_SET);
+
+ ret = mmfile_read (fp, header, MMFILE_ID3V2TAG_HEADER_SIZE);
+ if (MMFILE_UTIL_FAIL == ret)
+ {
+ debug_error ("read error\n");
+ return MMFILE_ID3TAG_FAIL;
+ }
+
+ if (memcmp (id3v2ID, header, 3) == 0)
+ {
+ index += 3;
+ out->typeOfTag = MMFILE_TAG_ID3V2;
+ out->bAppendedTag = bAppended;
+ out->startOffset = offset;
+
+ //version check
+ switch (header[index])
+ {
+ case 0:
+ out->version = MMFILE_ID3TAG_V2_0;
+ break;
+ case 2:
+ out->version = MMFILE_ID3TAG_V2_2;
+ break;
+ case 3:
+ out->version = MMFILE_ID3TAG_V2_3;
+ break;
+ case 4:
+ out->version = MMFILE_ID3TAG_V2_4;
+ break;
+ default:
+ debug_warning ("unknown version of id3v2\n");
+ break;
+ }
+
+ index += 2;
+ //check footer
+ unsigned char footer = (header[index] & 0x10) ? 1 : 0;
+
+ index += 1;
+ //out->tagSize = GetSynchsafeInteger () + (footer ? 20 : 10)
+
+ if (bAppended)
+ {
+// out->endOffset
+ }
+ out->endOffset = endOffset;
+ }
+
+
+ return MMFILE_ID3TAG_FAIL;
+}
+
+
+static unsigned int GetSynchsafeInteger (unsigned int value)
+{
+ int i = 0;
+ const unsigned int mask = 0x7F000000;
+ unsigned int ret = 0;
+
+ for (i = 0; i < sizeof(unsigned int); i++)
+ {
+ ret = (ret << 7) | ((value & mask) >> 24);
+ value <<= 8;
+ }
+ return ret;
+}
+
diff --git a/formats/ffmpeg/mm_file_format_tags.c b/formats/ffmpeg/mm_file_format_tags.c
new file mode 100755
index 0000000..f1c2bf2
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_tags.c
@@ -0,0 +1,250 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "mm_debug.h"
+#include "mm_file_utils.h"
+#include "mm_file_format_tag_id3.h"
+#include "mm_file_format_tags.h"
+
+#define MMFILE_TAGS_NUMBER_OF_ELEMENTS(X) (sizeof X / sizeof X[0])
+
+typedef int (*MMFileFindTagFunc)(MMFileIOHandle *fp, unsigned char bAppended, unsigned int startOffset, unsigned int endOffset, tMMFileTags *out);
+
+
+typedef struct mmfiletagsdata
+{
+ MMFileIOHandle *fp;
+ unsigned int filesize;
+ unsigned int startOffset;
+ unsigned int endOffset;
+ MMFileList tagList;
+} tMMFileTagsData;
+
+
+MMFileFindTagFunc gFindPreprendTagFuncs[] =
+{
+ MMFileID3V2TagFind,
+};
+
+MMFileFindTagFunc gFindAppendTagFuncs[] =
+{
+ MMFileID3V1TagFind,
+ MMFileID3V2TagFind,
+};
+
+
+int _MMFileFindTags (tMMFileTagsData *privateData, MMFileFindTagFunc FindTag, unsigned char bAppended);
+int _MMFileFindPrependTags (tMMFileTagsData *privateData);
+int _MMFileFindAppendTags (tMMFileTagsData *privateData);
+
+
+
+EXPORT_API
+int MMFileOpenTags (MMFileTagsHandle *tagsHandle, const char *uriName)
+{
+ tMMFileTagsData *privateData = NULL;
+ int ret = 0;
+
+ privateData = mmfile_malloc (sizeof(tMMFileTagsData));
+ if (!privateData)
+ {
+ debug_error ("mmfile_malloc: tMMFileTagsData\n");
+ return MMFILE_TAGS_FAIL;
+ }
+
+ *tagsHandle = privateData;
+
+ ret = mmfile_open (&privateData->fp, uriName, MMFILE_RDONLY);
+ if (MMFILE_UTIL_FAIL == ret)
+ {
+ debug_error ("mmfile_open\n");
+ ret = MMFILE_TAGS_FAIL;
+ goto exception;
+ }
+
+ ret = mmfile_seek (privateData->fp, 0, MMFILE_SEEK_END);
+ if (MMFILE_UTIL_FAIL == ret)
+ {
+ debug_error ("mmfile_seek\n");
+ ret = MMFILE_TAGS_FAIL;
+ goto exception;
+ }
+
+ privateData->filesize = mmfile_tell (privateData->fp);
+
+ mmfile_seek (privateData->fp, 0, MMFILE_SEEK_SET);
+
+ privateData->startOffset = 0;
+ privateData->endOffset = privateData->filesize;
+
+ /* Find all of tags */
+ while (MMFILE_TAGS_SUCCESS == _MMFileFindPrependTags (privateData)) ;
+ while (MMFILE_TAGS_SUCCESS == _MMFileFindAppendTags (privateData)) ;
+
+ if (!privateData->tagList)
+ {
+ debug_error ("there is no tags\n");
+ ret = MMFILE_TAGS_FAIL;
+ goto exception;
+ }
+
+ return MMFILE_TAGS_SUCCESS;
+
+exception:
+ if (*tagsHandle)
+ {
+ MMFileTagsClose (*tagsHandle);
+ *tagsHandle = NULL;
+ }
+
+ return ret;
+}
+
+EXPORT_API
+int MMFileTagsClose (MMFileTagsHandle tagsHandle)
+{
+ tMMFileTagsData *privateData = tagsHandle;
+
+ if (privateData)
+ {
+ if (privateData->fp)
+ {
+ mmfile_close (privateData->fp);
+ }
+
+ if (privateData->tagList)
+ {
+ mmfile_free (privateData->tagList);
+ }
+
+ mmfile_free (privateData);
+ }
+
+ return MMFILE_TAGS_SUCCESS;
+}
+
+
+
+EXPORT_API
+int MMFileGetFirstTag (MMFileTagsHandle tagsHandle, tMMFileTags *out)
+{
+
+}
+
+EXPORT_API
+int MMFileGetNextTag (MMFileTagsHandle tagsHandle, tMMFileTags *out)
+{
+}
+
+int _MMFileFindPrependTags (tMMFileTagsData *privateData)
+{
+ int i = 0;
+ int res = 0;
+
+ if (!privateData || !privateData->fp)
+ {
+ debug_error ("Invalid argument\n");
+ return MMFILE_TAGS_FAIL;
+ }
+
+ for (i = 0; i < MMFILE_TAGS_NUMBER_OF_ELEMENTS(gFindPreprendTagFuncs); i++)
+ {
+ if (gFindPreprendTagFuncs[i])
+ {
+ if (MMFILE_TAGS_SUCCESS == _MMFileFindTags (privateData, gFindPreprendTagFuncs[i], 0))
+ {
+ return MMFILE_TAGS_SUCCESS;
+ }
+ }
+ }
+
+ return MMFILE_TAGS_FAIL;
+}
+
+int _MMFileFindAppendTags (tMMFileTagsData *privateData)
+{
+ int i = 0;
+ int res = 0;
+
+ if (!privateData || !privateData->fp)
+ {
+ debug_error ("Invalid argument\n");
+ return MMFILE_TAGS_FAIL;
+ }
+
+ for (i = 0; i < MMFILE_TAGS_NUMBER_OF_ELEMENTS(gFindAppendTagFuncs); i++)
+ {
+ if (gFindAppendTagFuncs[i])
+ {
+ if (MMFILE_TAGS_SUCCESS == _MMFileFindTags (privateData, gFindAppendTagFuncs[i], 1))
+ {
+ return MMFILE_TAGS_SUCCESS;
+ }
+ }
+ }
+
+ return MMFILE_TAGS_FAIL;
+}
+
+int _MMFileFindTags (tMMFileTagsData *privateData, MMFileFindTagFunc FindTag, unsigned char bAppended)
+{
+ tMMFileTags *tagData = NULL;
+ int ret = 0;
+
+ if (!privateData || !privateData->fp)
+ {
+ debug_error ("Invalid argument\n");
+ return MMFILE_TAGS_FAIL;
+ }
+
+ tagData = mmfile_malloc (sizeof(tMMFileTags));
+ if (!tagData)
+ {
+ debug_error ("mmfile_malloc tagData\n");
+ return MMFILE_TAGS_FAIL;
+ }
+
+ ret = FindTag (privateData->fp, bAppended, privateData->startOffset, privateData->endOffset, tagData);
+ if (ret)
+ {
+ if (bAppended)
+ {
+ privateData->endOffset = tagData->startOffset;
+ }
+ else
+ {
+ privateData->startOffset = tagData->endOffset;
+ }
+
+ /* add tagData into privateData->tagList */
+
+ //privateData->tagList = mmfile_list_append (privateData->tagList, tagData);
+
+ ret = MMFILE_TAGS_SUCCESS;
+ }
+
+ mmfile_free(tagData);
+
+ return ret;
+}
+
diff --git a/formats/ffmpeg/mm_file_format_wav.c b/formats/ffmpeg/mm_file_format_wav.c
new file mode 100755
index 0000000..38ff860
--- /dev/null
+++ b/formats/ffmpeg/mm_file_format_wav.c
@@ -0,0 +1,505 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdlib.h> /*malloc*/
+
+#include <mm_error.h>
+#include "mm_debug.h"
+
+#include "mm_file_utils.h"
+#include "mm_file_format_private.h"
+#include "mm_file_format_wav.h"
+
+
+/**
+ * Wave File Header.
+ *
+ * Offset Size Endian Description Value
+ * 0 4 big Chunk ID "RIFF" (0x52494646)
+ * 4 4 little Chunk Data Size (file size) - 8
+ * 8 4 big Format "WAVE" (0x57415645)
+ * 12 4 big Sub Chunk1 ID "fmt " (0x666d7420)
+ * 16 4 little Sub Chunk1 Size
+ * 20 2 little Audio Format
+ * 22 2 little Channel number
+ * 24 4 little Sampling rate
+ * 28 4 little Byte rate
+ * 32 2 little Block align
+ * 34 2 little Bit per sample
+ */
+
+
+#define MMF_FILE_WAVE_CHUNK_LEN 12
+#define MMF_FILE_WAVE_SUBCHUNK_LEN 24
+#define MMF_FILE_WAVE_HEADER_LEN (MMF_FILE_WAVE_CHUNK_LEN + MMF_FILE_WAVE_SUBCHUNK_LEN)
+
+#ifdef __MMFILE_TEST_MODE__
+typedef struct {
+ short codec; /**< WAVE form Registration Number*/
+ char *name; /**< WAVE form wFormatTag ID*/
+} MMF_FILE_WAVE_CODEC_NAME;
+
+MMF_FILE_WAVE_CODEC_NAME g_audio_cdc_tbl [] = {
+ { 0x0000, "WAVE_FORMAT_UNKNOWN" },
+ { 0x0001, "WAVE_FORMAT_PCM" },
+ { 0x0002, "WAVE_FORMAT_ADPCM" },
+ { 0x0003, "WAVE_FORMAT_IEEE_FLOAT" },
+ { 0x0004, "WAVE_FORMAT_VSELP" },
+ { 0x0005, "WAVE_FORMAT_IBM_CVSD" },
+ { 0x0006, "WAVE_FORMAT_ALAW" },
+ { 0x0007, "WAVE_FORMAT_MULAW" },
+ { 0x0010, "WAVE_FORMAT_OKI_ADPCM" },
+ { 0x0011, "WAVE_FORMAT_DVI_ADPCM" },
+ { 0x0012, "WAVE_FORMAT_MEDIASPACE_ADPCM" },
+ { 0x0013, "WAVE_FORMAT_SIERRA_ADPCM" },
+ { 0x0014, "WAVE_FORMAT_G723_ADPCM" },
+ { 0x0015, "WAVE_FORMAT_DIGISTD" },
+ { 0x0016, "WAVE_FORMAT_DIGIFIX" },
+ { 0x0017, "WAVE_FORMAT_DIALOGIC_OKI_ADPCM" },
+ { 0x0018, "WAVE_FORMAT_MEDIAVISION_ADPCM" },
+ { 0x0019, "WAVE_FORMAT_CU_CODEC" },
+ { 0x0020, "WAVE_FORMAT_YAMAHA_ADPCM" },
+ { 0x0021, "WAVE_FORMAT_SONARC" },
+ { 0x0022, "WAVE_FORMAT_DSPGROUP_TRUESPEECH" },
+ { 0x0023, "WAVE_FORMAT_ECHOSC1" },
+ { 0x0024, "WAVE_FORMAT_AUDIOFILE_AF36" },
+ { 0x0025, "WAVE_FORMAT_APTX" },
+ { 0x0026, "WAVE_FORMAT_AUDIOFILE_AF10" },
+ { 0x0027, "WAVE_FORMAT_PROSODY_1612" },
+ { 0x0028, "WAVE_FORMAT_LRC" },
+ { 0x0030, "WAVE_FORMAT_DOLBY_AC2" },
+ { 0x0031, "WAVE_FORMAT_GSM610" },
+ { 0x0032, "WAVE_FORMAT_MSNAUDIO" },
+ { 0x0033, "WAVE_FORMAT_ANTEX_ADPCME" },
+ { 0x0034, "WAVE_FORMAT_CONTROL_RES_VQLPC" },
+ { 0x0035, "WAVE_FORMAT_DIGIREAL" },
+ { 0x0036, "WAVE_FORMAT_DIGIADPCM" },
+ { 0x0037, "WAVE_FORMAT_CONTROL_RES_CR10" },
+ { 0x0038, "WAVE_FORMAT_NMS_VBXADPCM" },
+ { 0x0039, "WAVE_FORMAT_ROLAND_RDAC" },
+ { 0x003A, "WAVE_FORMAT_ECHOSC3" },
+ { 0x003B, "WAVE_FORMAT_ROCKWELL_ADPCM" },
+ { 0x003C, "WAVE_FORMAT_ROCKWELL_DIGITALK" },
+ { 0x003D, "WAVE_FORMAT_XEBEC" },
+ { 0x0040, "WAVE_FORMAT_G721_ADPCM" },
+ { 0x0041, "WAVE_FORMAT_G728_CELP" },
+ { 0x0042, "WAVE_FORMAT_MSG723" },
+ { 0x0050, "WAVE_FORMAT_MPEG" },
+ { 0x0052, "WAVE_FORMAT_RT24" },
+ { 0x0053, "WAVE_FORMAT_PAC" },
+ { 0x0055, "WAVE_FORMAT_MPEGLAYER3" },
+ { 0x0059, "WAVE_FORMAT_LUCENT_G723" },
+ { 0x0060, "WAVE_FORMAT_CIRRUS" },
+ { 0x0061, "WAVE_FORMAT_ESPCM" },
+ { 0x0062, "WAVE_FORMAT_VOXWARE" },
+ { 0x0063, "WAVE_FORMAT_CANOPUS_ATRAC" },
+ { 0x0064, "WAVE_FORMAT_G726_ADPCM" },
+ { 0x0065, "WAVE_FORMAT_G722_ADPCM" },
+ { 0x0066, "WAVE_FORMAT_DSAT" },
+ { 0x0067, "WAVE_FORMAT_DSAT_DISPLAY" },
+ { 0x0069, "WAVE_FORMAT_VOXWARE_BYTE_ALIGNED" },
+ { 0x0070, "WAVE_FORMAT_VOXWARE_AC8" },
+ { 0x0071, "WAVE_FORMAT_VOXWARE_AC10" },
+ { 0x0072, "WAVE_FORMAT_VOXWARE_AC16" },
+ { 0x0073, "WAVE_FORMAT_VOXWARE_AC20" },
+ { 0x0074, "WAVE_FORMAT_VOXWARE_RT24" },
+ { 0x0075, "WAVE_FORMAT_VOXWARE_RT29" },
+ { 0x0076, "WAVE_FORMAT_VOXWARE_RT29HW" },
+ { 0x0077, "WAVE_FORMAT_VOXWARE_VR12" },
+ { 0x0078, "WAVE_FORMAT_VOXWARE_VR18" },
+ { 0x0079, "WAVE_FORMAT_VOXWARE_TQ40" },
+ { 0x0080, "WAVE_FORMAT_SOFTSOUND" },
+ { 0x0081, "WAVE_FORMAT_VOXWARE_TQ60" },
+ { 0x0082, "WAVE_FORMAT_MSRT24" },
+ { 0x0083, "WAVE_FORMAT_G729A" },
+ { 0x0084, "WAVE_FORMAT_MVI_MV12" },
+ { 0x0085, "WAVE_FORMAT_DF_G726" },
+ { 0x0086, "WAVE_FORMAT_DF_GSM610" },
+ { 0x0088, "WAVE_FORMAT_ISIAUDIO" },
+ { 0x0089, "WAVE_FORMAT_ONLIVE" },
+ { 0x0091, "WAVE_FORMAT_SBC24" },
+ { 0x0092, "WAVE_FORMAT_DOLBY_AC3_SPDIF" },
+ { 0x0097, "WAVE_FORMAT_ZYXEL_ADPCM" },
+ { 0x0098, "WAVE_FORMAT_PHILIPS_LPCBB" },
+ { 0x0099, "WAVE_FORMAT_PACKED" },
+ { 0x0100, "WAVE_FORMAT_RHETOREX_ADPCM" },
+ { 0x0101, "WAVE_FORMAT_IRAT" },
+ { 0x0111, "WAVE_FORMAT_VIVO_G723" },
+ { 0x0112, "WAVE_FORMAT_VIVO_SIREN" },
+ { 0x0123, "WAVE_FORMAT_DIGITAL_G723" },
+ { 0x0200, "WAVE_FORMAT_CREATIVE_ADPCM" },
+ { 0x0202, "WAVE_FORMAT_CREATIVE_FASTSPEECH8" },
+ { 0x0203, "WAVE_FORMAT_CREATIVE_FASTSPEECH10" },
+ { 0x0220, "WAVE_FORMAT_QUARTERDECK" },
+ { 0x0300, "WAVE_FORMAT_FM_TOWNS_SND" },
+ { 0x0400, "WAVE_FORMAT_BTV_DIGITAL" },
+ { 0x0680, "WAVE_FORMAT_VME_VMPCM" },
+ { 0x1000, "WAVE_FORMAT_OLIGSM" },
+ { 0x1001, "WAVE_FORMAT_OLIADPCM" },
+ { 0x1002, "WAVE_FORMAT_OLICELP" },
+ { 0x1003, "WAVE_FORMAT_OLISBC" },
+ { 0x1004, "WAVE_FORMAT_OLIOPR" },
+ { 0x1100, "WAVE_FORMAT_LH_CODEC" },
+ { 0x1400, "WAVE_FORMAT_NORRIS" },
+ { 0x1401, "WAVE_FORMAT_ISIAUDIO" },
+ { 0x1500, "WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS" },
+ { 0x2000, "WAVE_FORMAT_DVM" },
+};
+#endif
+
+typedef struct {
+ int size; /**< Chunk size*/
+ short format; /**< Wave form Resistration Number*/
+ short channel; /**< Number of channels*/
+ int sample_rate; /**< Sampling-rate per second*/
+ int byte_rate; /**< Byte per second (== Sampling-rate * Channels * Bit per Sample / 8)*/
+ short block_align; /**< Block align(== Channels * Bit per Sample / 8)*/
+ short bits_per_sample; /**< Bit per sample*/
+
+} MM_FILE_WAVE_INFO;
+
+
+/* internal */
+static unsigned char *mmf_file_wave_get_header (char *src);
+static int mmf_file_wave_get_info (unsigned char *header, MM_FILE_WAVE_INFO *info);
+
+
+/* mm plugin porting */
+int mmfile_format_read_stream_wav (MMFileFormatContext *formatContext);
+int mmfile_format_read_frame_wav (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame);
+int mmfile_format_read_tag_wav (MMFileFormatContext *formatContext);
+int mmfile_format_close_wav (MMFileFormatContext *formatContext);
+
+
+EXPORT_API
+int mmfile_format_open_wav (MMFileFormatContext *formatContext)
+{
+ int ret = 0;
+
+ if (NULL == formatContext) {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->pre_checked == 0) {
+ ret = MMFileFormatIsValidWAV (formatContext->uriFileName);
+ if ( ret == 0 )
+ {
+ debug_error("It is not wav file\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+ }
+
+ formatContext->ReadStream = mmfile_format_read_stream_wav;
+ formatContext->ReadFrame = mmfile_format_read_frame_wav;
+ formatContext->ReadTag = mmfile_format_read_tag_wav;
+ formatContext->Close = mmfile_format_close_wav;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 1;
+
+ formatContext->privateFormatData = NULL;
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_stream_wav (MMFileFormatContext *formatContext)
+{
+ unsigned char *header = NULL;
+ MM_FILE_WAVE_INFO *waveinfo = NULL;
+ int ret = 0;
+
+ if (formatContext == NULL) {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ header = mmf_file_wave_get_header (formatContext->uriFileName);
+ if (header == NULL) {
+ debug_error("error: mmf_file_wave_get_header\n");
+ goto exception;
+ }
+
+ waveinfo = mmfile_malloc (sizeof(MM_FILE_WAVE_INFO));
+ if (waveinfo == NULL) {
+ debug_error("error: mmfile_malloc\n");
+ goto exception;
+ }
+
+ ret = mmf_file_wave_get_info (header, waveinfo);
+ if (ret == -1) {
+ debug_error("error: mmf_file_wave_get_info\n");
+ goto exception;
+ }
+
+ mmfile_free (header);
+
+ formatContext->privateFormatData = waveinfo;
+
+ formatContext->duration = (int)(((float)(waveinfo->size) / (float)(waveinfo->byte_rate)) * 1000.0F);
+ formatContext->audioTotalTrackNum = 1;
+ formatContext->nbStreams = 1;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = mmfile_malloc (sizeof(MMFileFormatStream));
+
+ if (!formatContext->streams[MMFILE_AUDIO_STREAM]) {
+ debug_error("error: mmfile_malloc audio stream for wav\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ formatContext->streams[MMFILE_AUDIO_STREAM]->streamType = MMFILE_AUDIO_STREAM;
+
+ switch (waveinfo->format) {
+ case 0x0001:
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_PCM;
+ break;
+ case 0x0002:
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_MS_ADPCM;
+ break;
+ case 0x0006:
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_ALAW;
+ break;
+ case 0x0007:
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_MULAW;
+ break;
+ case 0x0011:
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_ADPCM;
+ break;
+ default:
+ formatContext->streams[MMFILE_AUDIO_STREAM]->codecId = MM_AUDIO_CODEC_INVALID;
+ break;
+ }
+
+ formatContext->streams[MMFILE_AUDIO_STREAM]->bitRate = waveinfo->byte_rate*8;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->nbChannel = waveinfo->channel;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->framePerSec = 0;
+ formatContext->streams[MMFILE_AUDIO_STREAM]->samplePerSec = waveinfo->sample_rate;
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ mmfile_free (header);
+ mmfile_free (waveinfo);
+
+ return MMFILE_FORMAT_FAIL;
+}
+
+
+EXPORT_API
+int mmfile_format_read_frame_wav (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_read_tag_wav (MMFileFormatContext *formatContext)
+{
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_close_wav (MMFileFormatContext *formatContext)
+{
+ if (formatContext == NULL) {
+ debug_error("formatContext is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->privateFormatData)
+ mmfile_free (formatContext->privateFormatData);
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+static char*
+_dump_codec_name (short codec)
+{
+#ifdef __MMFILE_TEST_MODE__
+ int sz = sizeof (g_audio_cdc_tbl) / sizeof (MMF_FILE_WAVE_CODEC_NAME);
+ int i;
+
+ for (i = 0; i < sz; i++) {
+ if (g_audio_cdc_tbl[i].codec == codec) {
+ return g_audio_cdc_tbl[i].name;
+ }
+ }
+#endif
+ return NULL;
+}
+
+static int _get_fmt_subchunk_offset (MMFileIOHandle *fp, long long limit, long long *offset)
+{
+ long long fmt_offset;
+ int readed;
+ int i;
+ unsigned char buf[4];
+
+ fmt_offset = mmfile_tell (fp);
+ if (fmt_offset < 0)
+ return 0;
+
+ for (i = 0; i < limit; i++) {
+ mmfile_seek (fp, fmt_offset + i, MMFILE_SEEK_SET);
+ readed = mmfile_read (fp, buf, 4);
+ if (readed != 4) {
+ debug_error ( "failed to read. size = %d\n", readed);
+ return 0;
+ }
+
+ if (buf[0] == 'f' && buf[1] == 'm' && buf[2] == 't' && buf[3] == ' ') {
+ *offset = fmt_offset + i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned char *
+mmf_file_wave_get_header (char *src)
+{
+ int readed = 0;
+ MMFileIOHandle *fp = NULL;
+ int ret = 0;
+ long long src_size = 0L;
+ unsigned char *header = NULL;
+ long long offset = 0;
+ long long limit;
+
+ header = mmfile_malloc (MMF_FILE_WAVE_HEADER_LEN);
+ if (!header)
+ return NULL;
+
+ /*open*/
+ ret = mmfile_open (&fp, src, MMFILE_RDONLY);
+ if (ret == MMFILE_UTIL_FAIL) {
+ debug_error ( "open failed.\n");
+ goto failed;
+ }
+
+
+ /*get file size*/
+ mmfile_seek (fp, 0L, MMFILE_SEEK_END);
+ src_size = mmfile_tell (fp);
+ mmfile_seek (fp, 0L, MMFILE_SEEK_SET);
+
+ if (src_size < MMF_FILE_WAVE_HEADER_LEN) {
+ debug_error ( "header is too small.\n");
+ goto failed;
+ }
+
+ /*read chunk data*/
+ readed = mmfile_read (fp, header, MMF_FILE_WAVE_CHUNK_LEN);
+ if (readed != MMF_FILE_WAVE_CHUNK_LEN) {
+ debug_error ( "read error. size = %d\n", readed);
+ goto failed;
+ }
+
+ /*seach 'fmt ' sub chunk*/
+ limit = (src_size - MMF_FILE_WAVE_HEADER_LEN > 10240 ? 10240 : src_size - MMF_FILE_WAVE_HEADER_LEN);
+ ret = _get_fmt_subchunk_offset (fp, limit, &offset);
+ if (ret == 0) {
+ debug_error ( "failed to seach 'fmt ' chunk\n");
+ goto failed;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("fmt offset: %lld\n", offset);
+ #endif
+
+ mmfile_seek (fp, offset, MMFILE_SEEK_SET);
+
+ /*read sub chunk data*/
+ readed = mmfile_read (fp, header + MMF_FILE_WAVE_CHUNK_LEN, MMF_FILE_WAVE_SUBCHUNK_LEN);
+ if (readed != MMF_FILE_WAVE_SUBCHUNK_LEN) {
+ debug_error ( "read error. size = %d\n", readed);
+ goto failed;
+ }
+
+ mmfile_close (fp);
+
+ return header;
+
+failed:
+ if (header) mmfile_free (header);
+ if (fp) mmfile_close (fp);
+
+ return NULL;
+}
+
+static int
+mmf_file_wave_get_info (unsigned char *header, MM_FILE_WAVE_INFO *info)
+{
+ if (!header || !info) {
+ return -1;
+ }
+
+ /*get chunk size*/
+ info->size = *((int*)(header + 4));
+
+ /*get format*/
+ info->format = *((short*)(header + 20));
+
+ /*get channel*/
+ info->channel = *((short*)(header + 22));
+
+ /*get sampling-rate*/
+ info->sample_rate = *((int*)(header + 24));
+
+ /*get byte rate*/
+ info->byte_rate = *((int*)(header + 28));
+
+ /*get byte align*/
+ info->block_align = *((short*)(header + 32));
+
+ /*get bits per sample*/
+ info->bits_per_sample = *((short*)(header + 34));
+
+ info->size = mmfile_io_le_int32 (info->size);
+ info->format = mmfile_io_le_int16 (info->format);
+ info->channel = mmfile_io_le_int16 (info->channel);
+ info->sample_rate = mmfile_io_le_int32 (info->sample_rate);
+ info->byte_rate = mmfile_io_le_int32 (info->byte_rate);
+ info->block_align = mmfile_io_le_int16 (info->block_align);
+ info->bits_per_sample = mmfile_io_le_int16 (info->bits_per_sample);
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ( "----------------------------------------------\n");
+ debug_msg ( "chunk size: %d\n", info->size);
+ debug_msg ( "WAVE form Registration Number: 0x%04X\n", info->format);
+ debug_msg ( "WAVE form wFormatTag ID: %s\n", _dump_codec_name (info->format));
+ debug_msg ( "channel: %d\n", info->channel);
+ debug_msg ( "sampling-rate: %d\n", info->sample_rate);
+ debug_msg ( "byte-rate: %d\n", info->byte_rate);
+ debug_msg ( "byte align: %d\n", info->block_align);
+ debug_msg ( "bit per sample: %d\n", info->bits_per_sample);
+ debug_msg ( "----------------------------------------------\n");
+ #endif
+
+ return 0;
+
+}
+
+
diff --git a/formats/ffmpeg/mm_file_formats.c b/formats/ffmpeg/mm_file_formats.c
new file mode 100755
index 0000000..bae06fe
--- /dev/null
+++ b/formats/ffmpeg/mm_file_formats.c
@@ -0,0 +1,1049 @@
+/*
+ * libmm-fileinfo
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: Haejeong Kim <backto.kim@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef DRM_SUPPORT
+#include <drm_client.h>
+#endif
+
+
+#include "mm_debug.h"
+#include "mm_file_format_private.h"
+#include "mm_file_utils.h"
+
+#define _MMF_FILE_FILEEXT_MAX 128
+
+int (*MMFileOpenFunc[MM_FILE_FORMAT_NUM+1]) (MMFileFormatContext *fileContext) = {
+ mmfile_format_open_ffmpg, /* 3GP */
+ mmfile_format_open_ffmpg, /* ASF */
+ mmfile_format_open_ffmpg, /* AVI */
+ mmfile_format_open_ffmpg, /* MATROSAK */
+ mmfile_format_open_ffmpg, /* MP4 */
+ mmfile_format_open_ffmpg, /* OGG */
+ NULL, /* NUT */
+ mmfile_format_open_ffmpg, /* QT */
+ NULL, /* REAL */
+ mmfile_format_open_amr, /* AMR */
+ mmfile_format_open_aac, /* AAC */
+ mmfile_format_open_mp3, /* MP3 */
+ NULL, /* AIFF */
+ NULL, /* AU */
+ mmfile_format_open_wav, /* WAV */
+ mmfile_format_open_mid, /* MID */
+ mmfile_format_open_mmf, /* MMF */
+ mmfile_format_open_ffmpg, /* DIVX */
+ mmfile_format_open_ffmpg, /* FLV */
+ NULL, /* VOB */
+ mmfile_format_open_imy, /* IMY */
+ mmfile_format_open_ffmpg, /* WMA */
+ mmfile_format_open_ffmpg, /* WMV */
+ NULL, /* JPG */
+ mmfile_format_open_ffmpg, /* FLAC */
+ NULL,
+};
+
+static int _CleanupFrameContext (MMFileFormatContext *formatContext)
+{
+ if (formatContext) {
+ formatContext->ReadFrame = NULL;
+ formatContext->ReadStream = NULL;
+ formatContext->ReadTag = NULL;
+ formatContext->Close = NULL;
+
+ if (formatContext->title) mmfile_free(formatContext->title);
+ if (formatContext->artist) mmfile_free(formatContext->artist);
+ if (formatContext->author) mmfile_free(formatContext->author);
+ if (formatContext->composer) mmfile_free(formatContext->composer);
+ if (formatContext->album) mmfile_free(formatContext->album);
+ if (formatContext->year) mmfile_free(formatContext->year);
+ if (formatContext->copyright) mmfile_free(formatContext->copyright);
+ if (formatContext->comment) mmfile_free(formatContext->comment);
+ if (formatContext->genre) mmfile_free(formatContext->genre);
+ if (formatContext->artwork) mmfile_free(formatContext->artwork);
+ if (formatContext->classification) mmfile_free(formatContext->classification);
+ if (formatContext->conductor) mmfile_free(formatContext->conductor);
+
+ if (formatContext->privateFormatData) mmfile_free(formatContext->privateFormatData);
+ if (formatContext->privateCodecData) mmfile_free(formatContext->privateCodecData);
+
+
+ if (formatContext->nbStreams > 0) {
+ int i = 0;
+ for (i = 0; (i < formatContext->nbStreams) && (i < MAXSTREAMS); i++) {
+ if (formatContext->streams[i]) mmfile_free(formatContext->streams[i]);
+ }
+ }
+
+ if (formatContext->thumbNail) {
+ if (formatContext->thumbNail->frameData)
+ mmfile_free (formatContext->thumbNail->frameData);
+
+ if (formatContext->thumbNail->configData)
+ mmfile_free (formatContext->thumbNail->configData);
+
+ mmfile_free (formatContext->thumbNail);
+ }
+
+ formatContext->title = NULL;
+ formatContext->artist = NULL;
+ formatContext->author = NULL;
+ formatContext->composer = NULL;
+ formatContext->album = NULL;
+ formatContext->copyright = NULL;
+ formatContext->comment = NULL;
+ formatContext->genre = NULL;
+ formatContext->artwork = NULL;
+
+ formatContext->privateFormatData = NULL;
+ formatContext->privateCodecData = NULL;
+ formatContext->classification = NULL;
+
+ formatContext->videoTotalTrackNum = 0;
+ formatContext->audioTotalTrackNum = 0;
+
+ formatContext->nbStreams = 0;
+ formatContext->streams[MMFILE_AUDIO_STREAM] = NULL;
+ formatContext->streams[MMFILE_VIDEO_STREAM] = NULL;
+ formatContext->thumbNail = NULL;
+ }
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+static int
+_PreprocessFile (MMFileSourceType *fileSrc, char **urifilename, int *formatEnum, int *isdrm)
+{
+ const char *fileName = NULL;
+ char extansion_name[_MMF_FILE_FILEEXT_MAX];
+ int pos = 0;
+ int filename_len = 0;
+ int index = 0, skip_index = 0;
+
+ if (fileSrc->type == MM_FILE_SRC_TYPE_FILE) {
+ fileName = (const char *)(fileSrc->file.path);
+ filename_len = strlen (fileName);
+ pos = filename_len;
+
+ /**
+ * Get file extension from file's name
+ */
+ while (pos > 0) {
+ pos--;
+ if (fileName[pos] == '.')
+ break;
+ }
+
+ memset (extansion_name, 0x00, _MMF_FILE_FILEEXT_MAX);
+
+ /*extract metadata for all file. ex)a , a. , a.mp3*/
+ if (pos == 0) {
+ /*even though there is no file extension, extracto metadata*/
+ debug_msg ("no file extension");
+ }
+ else if (_MMF_FILE_FILEEXT_MAX > (filename_len - pos - 1)) {
+ strncpy (extansion_name, fileName + pos +1 , (filename_len - pos - 1));
+ extansion_name[filename_len - pos - 1] = '\0';
+ } else {
+ debug_error ("invalid filename. destination length: %d, source length: %d.\n", _MMF_FILE_FILEEXT_MAX, (filename_len - pos - 1));
+ return MMFILE_FORMAT_FAIL; /*invalid file name*/
+ }
+
+#ifdef DRM_SUPPORT
+ /**
+ * Make URI name with file name
+ */
+ drm_bool_type_e res = DRM_TRUE;
+ drm_file_type_e file_type = DRM_TYPE_UNDEFINED;
+ int ret = 0;
+ bool is_drm = FALSE;
+
+ ret = drm_is_drm_file (fileSrc->file.path, &res);
+ if (ret == DRM_RETURN_SUCCESS && DRM_TRUE == res)
+ {
+ ret = drm_get_file_type(fileSrc->file.path, &file_type);
+ if((ret == DRM_RETURN_SUCCESS) && ((file_type == DRM_TYPE_OMA_V1) ||(file_type == DRM_TYPE_OMA_V2)))
+ {
+ is_drm = TRUE;
+ }
+ }
+
+ if (is_drm)
+ {
+ *isdrm = MM_FILE_DRM_OMA;
+ debug_error ("OMA DRM detected. Not Support DRM Content\n");
+ return MMFILE_FORMAT_FAIL; /*Not Support DRM Content*/
+ }
+ else
+#endif // DRM_SUPPORT
+ {
+ *isdrm = MM_FILE_DRM_NONE;
+#ifdef __MMFILE_MMAP_MODE__
+ *urifilename = mmfile_malloc (MMFILE_MMAP_URI_LEN + filename_len + 1);
+ if (!*urifilename) {
+ debug_error ("error: mmfile_malloc uriname\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ memset (*urifilename, 0x00, MMFILE_MMAP_URI_LEN + filename_len + 1);
+ strncpy (*urifilename, MMFILE_MMAP_URI, MMFILE_MMAP_URI_LEN);
+ strncat (*urifilename, fileName, filename_len);
+ (*urifilename)[MMFILE_MMAP_URI_LEN + filename_len] = '\0';
+
+#else
+ *urifilename = mmfile_malloc (MMFILE_FILE_URI_LEN + filename_len + 1);
+ if (!*urifilename) {
+ debug_error ("error: mmfile_malloc uriname\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ memset (*urifilename, 0x00, MMFILE_FILE_URI_LEN + filename_len + 1);
+ strncpy (*urifilename, MMFILE_FILE_URI, MMFILE_FILE_URI_LEN+1);
+ strncat (*urifilename, fileName, filename_len);
+ (*urifilename)[MMFILE_FILE_URI_LEN + filename_len] = '\0';
+#endif
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ // Check File format //
+ ///////////////////////////////////////////////////////////////////////
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("Get codec type of [%s].\n", extansion_name);
+ #endif
+
+ if (strcasecmp (extansion_name, "mp4") == 0 ||
+ strcasecmp (extansion_name, "mpeg4") == 0 ||
+ strcasecmp (extansion_name, "m4a") == 0 ||
+ strcasecmp (extansion_name, "mpg") == 0 ||
+ strcasecmp (extansion_name, "mpg4") == 0 ||
+ strcasecmp (extansion_name, "m4v") == 0 ) {
+
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MP4;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MP4;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "3gp") == 0) {
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_3GP;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_3GP;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "amr") == 0 ||
+ strcasecmp (extansion_name, "awb") == 0) {
+
+ if (MMFileFormatIsValidAMR (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AMR;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_AMR;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "wav") == 0) {
+ if (MMFileFormatIsValidWAV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WAV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_WAV;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "mid") == 0 ||
+ strcasecmp (extansion_name, "midi") == 0 ||
+ strcasecmp (extansion_name, "spm") == 0 ) {
+
+ if (MMFileFormatIsValidMID (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MID;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MID;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "mp3") == 0) {
+ if (MMFileFormatIsValidMP3 (*urifilename,5)) {
+ *formatEnum = MM_FILE_FORMAT_MP3;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MP3;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "aac") == 0) {
+ if (MMFileFormatIsValidAAC (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AAC;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_AAC;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "xmf") == 0 ||
+ strcasecmp (extansion_name, "mxmf") == 0) {
+ if (MMFileFormatIsValidMID (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MID;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MID;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (!strcasecmp (extansion_name, "mmf") ||
+ !strcasecmp (extansion_name, "ma2")) {
+ if (MMFileFormatIsValidMMF (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MMF;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MMF;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "imy") == 0) {
+ if (MMFileFormatIsValidIMY (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_IMELODY;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_IMELODY;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "avi") == 0) {
+ if (MMFileFormatIsValidAVI (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AVI;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_AVI;
+ goto PROBE_PROPER_FILE_TYPE;
+ } else if (strcasecmp (extansion_name, "divx") == 0) {
+ if (MMFileFormatIsValidAVI (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_DIVX;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_DIVX;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "asf") == 0 ||
+ strcasecmp (extansion_name, "asx") == 0 ) {
+ if (MMFileFormatIsValidASF (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_ASF;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_ASF;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "wma") == 0) {
+ if (MMFileFormatIsValidWMA (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WMA;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_WMA;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "wmv") == 0) {
+ if (MMFileFormatIsValidWMV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WMV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_WMV;
+ goto PROBE_PROPER_FILE_TYPE;
+
+ } else if (strcasecmp (extansion_name, "ogg") == 0) {
+ if (MMFileFormatIsValidOGG (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_OGG;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_OGG;
+ goto PROBE_PROPER_FILE_TYPE;
+ } else if (strcasecmp (extansion_name, "mkv") == 0 ||
+ strcasecmp (extansion_name, "mka") == 0) {
+ if (MMFileFormatIsValidMatroska (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MATROSKA;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MATROSKA;
+ goto PROBE_PROPER_FILE_TYPE;
+ } else if (strcasecmp (extansion_name, "mov") == 0) {
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_QT;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_QT;
+ goto PROBE_PROPER_FILE_TYPE;
+ } else if (strcasecmp (extansion_name, "flac") == 0) {
+ if (MMFileFormatIsValidFLAC (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_FLAC;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_FLAC;
+ goto PROBE_PROPER_FILE_TYPE;
+ } else if (strcasecmp (extansion_name, "flv") == 0) {
+ if (MMFileFormatIsValidFLV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_FLV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_FLV;
+ goto PROBE_PROPER_FILE_TYPE;
+ } else {
+ debug_warning ("probe file type=%s\n", fileName);
+ skip_index = -1;
+ goto PROBE_PROPER_FILE_TYPE;
+ }
+ } else if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) {
+ char tempURIBuffer[MMFILE_URI_MAX_LEN] = {0,};
+
+ sprintf (tempURIBuffer, "%s%u:%u", MMFILE_MEM_URI, (unsigned int)fileSrc->memory.ptr, fileSrc->memory.size);
+ *urifilename = mmfile_strdup (tempURIBuffer);
+ if (!*urifilename) {
+ debug_error ("error: uri is NULL\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ #ifdef __MMFILE_TEST_MODE__
+ debug_msg ("uri: %s\n", *urifilename);
+ #endif
+
+ switch (fileSrc->memory.format) {
+ case MM_FILE_FORMAT_3GP: {
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_3GP;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_3GP;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_MP4: {
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MP4;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MP4;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_AMR: {
+ if (MMFileFormatIsValidAMR (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AMR;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_AMR;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_WAV: {
+ if (MMFileFormatIsValidWAV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WAV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_WAV;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_MID: {
+ if (MMFileFormatIsValidMID (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MID;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MID;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_MP3: {
+ if (MMFileFormatIsValidMP3 (*urifilename,5)) {
+ *formatEnum = MM_FILE_FORMAT_MP3;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MP3;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_AAC: {
+ if (MMFileFormatIsValidAAC (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AAC;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_AAC;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_MMF: {
+ if (MMFileFormatIsValidMMF (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MMF;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MMF;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_IMELODY: {
+ if (MMFileFormatIsValidIMY (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_IMELODY;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_IMELODY;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_AVI: {
+ if (MMFileFormatIsValidAVI (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AVI;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_AVI;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_DIVX: {
+ if (MMFileFormatIsValidAVI (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_DIVX;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_DIVX;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_ASF: {
+ if (MMFileFormatIsValidASF (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_ASF;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_ASF;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_WMA: {
+ if (MMFileFormatIsValidWMA (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WMA;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_WMA;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_WMV: {
+ if (MMFileFormatIsValidWMV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WMV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_WMV;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+
+ case MM_FILE_FORMAT_OGG: {
+ if (MMFileFormatIsValidOGG (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_OGG;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_OGG;
+ goto PROBE_PROPER_FILE_TYPE;
+ }
+
+ case MM_FILE_FORMAT_MATROSKA: {
+ if (MMFileFormatIsValidMatroska (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MATROSKA;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_MATROSKA;
+ goto PROBE_PROPER_FILE_TYPE;
+ }
+
+ case MM_FILE_FORMAT_QT: {
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_QT;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_QT;
+ goto PROBE_PROPER_FILE_TYPE;
+ }
+
+ case MM_FILE_FORMAT_FLAC: {
+ if (MMFileFormatIsValidFLAC (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_FLAC;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_FLAC;
+ goto PROBE_PROPER_FILE_TYPE;
+ }
+
+ case MM_FILE_FORMAT_FLV: {
+ if (MMFileFormatIsValidFLV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_FLV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ skip_index = MM_FILE_FORMAT_FLV;
+ goto PROBE_PROPER_FILE_TYPE;
+ }
+
+ default: {
+ debug_warning ("probe fileformat type=%d (%d: autoscan)\n", fileSrc->memory.format, MM_FILE_FORMAT_INVALID);
+ skip_index = -1;
+ goto PROBE_PROPER_FILE_TYPE;
+ break;
+ }
+ }
+ } else {
+ debug_error ("error: invaild input type[memory|file]\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+PROBE_PROPER_FILE_TYPE:
+ for (index = 0; index < MM_FILE_FORMAT_NUM; index++) {
+ if (index == skip_index)
+ continue;
+
+ debug_msg ("search index = [%d]\n", index);
+ switch (index) {
+ case MM_FILE_FORMAT_QT:
+ case MM_FILE_FORMAT_3GP:
+ case MM_FILE_FORMAT_MP4: {
+ if (skip_index == MM_FILE_FORMAT_QT || skip_index == MM_FILE_FORMAT_3GP || skip_index == MM_FILE_FORMAT_MP4)
+ break;
+
+ if (MMFileFormatIsValidMP4 (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_3GP;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_3GP;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_ASF:
+ case MM_FILE_FORMAT_WMA:
+ case MM_FILE_FORMAT_WMV: {
+ if (skip_index == MM_FILE_FORMAT_ASF || skip_index == MM_FILE_FORMAT_WMA || skip_index == MM_FILE_FORMAT_WMV)
+ break;
+
+ if (MMFileFormatIsValidASF (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_ASF;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_ASF;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_DIVX:
+ case MM_FILE_FORMAT_AVI: {
+ if (skip_index == MM_FILE_FORMAT_DIVX || skip_index == MM_FILE_FORMAT_AVI)
+ break;
+
+ if (MMFileFormatIsValidAVI(*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AVI;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_AVI;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_OGG: {
+ if (MMFileFormatIsValidOGG (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_OGG;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_OGG;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_AMR: {
+ if (MMFileFormatIsValidAMR (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AMR;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_AMR;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_AAC: {
+ if (MMFileFormatIsValidAAC (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_AAC;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_AAC;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_MP3: {
+ if (MMFileFormatIsValidMP3 (*urifilename,50)) {
+ *formatEnum = MM_FILE_FORMAT_MP3;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_MP3;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_WAV: {
+ if (MMFileFormatIsValidWAV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_WAV;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_WAV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_MID: {
+ if (MMFileFormatIsValidMID (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MID;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_MID;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_MMF: {
+ if (MMFileFormatIsValidMMF (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MMF;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_MMF;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_IMELODY: {
+ if (MMFileFormatIsValidIMY (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_IMELODY;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_IMELODY;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_MATROSKA: {
+ if (MMFileFormatIsValidMatroska (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_MATROSKA;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_MATROSKA;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_FLAC: {
+ if (MMFileFormatIsValidFLAC (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_FLAC;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_FLAC;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ case MM_FILE_FORMAT_FLV: {
+ if (MMFileFormatIsValidFLV (*urifilename)) {
+ *formatEnum = MM_FILE_FORMAT_FLV;
+ if (fileSrc->type == MM_FILE_SRC_TYPE_MEMORY) fileSrc->memory.format = MM_FILE_FORMAT_FLV;
+ return MMFILE_FORMAT_SUCCESS;
+ }
+ break;
+ }
+
+ /* not supported file */
+ case MM_FILE_FORMAT_NUT:
+ case MM_FILE_FORMAT_REAL:
+ case MM_FILE_FORMAT_AIFF:
+ case MM_FILE_FORMAT_AU:
+ case MM_FILE_FORMAT_VOB:
+ case MM_FILE_FORMAT_JPG:
+ break;
+ default: {
+ debug_error ("error: invaild format enum[%d]\n", index);
+ break;
+ }
+ }
+ }
+
+ if (index == MM_FILE_FORMAT_NUM)
+ debug_error("Can't probe file type\n");
+
+ *formatEnum = -1;
+ return MMFILE_FORMAT_FAIL;
+
+}
+
+static int _mmfile_format_close (MMFileFormatContext *formatContext)
+{
+ if (NULL == formatContext) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->Close) {
+ formatContext->Close(formatContext);
+ formatContext->Close = NULL;
+ }
+
+ if (formatContext->ReadFrame) formatContext->ReadFrame = NULL;
+ if (formatContext->ReadStream) formatContext->ReadStream = NULL;
+ if (formatContext->ReadTag) formatContext->ReadTag = NULL;
+ if (formatContext->Close) formatContext->Close = NULL;
+
+ if (formatContext->uriFileName) mmfile_free(formatContext->uriFileName);
+ if (formatContext->title) mmfile_free(formatContext->title);
+ if (formatContext->artist) mmfile_free(formatContext->artist);
+ if (formatContext->author) mmfile_free(formatContext->author);
+ if (formatContext->copyright) mmfile_free(formatContext->copyright);
+ if (formatContext->comment) mmfile_free(formatContext->comment);
+ if (formatContext->album) mmfile_free(formatContext->album);
+ if (formatContext->year) mmfile_free(formatContext->year);
+ if (formatContext->genre) mmfile_free(formatContext->genre);
+ if (formatContext->composer) mmfile_free(formatContext->composer);
+ if (formatContext->classification) mmfile_free(formatContext->classification);
+ if (formatContext->artwork) mmfile_free(formatContext->artwork);
+ if (formatContext->conductor) mmfile_free(formatContext->conductor);
+ if (formatContext->unsyncLyrics) mmfile_free(formatContext->unsyncLyrics);
+ if (formatContext->syncLyrics) mm_file_free_synclyrics_list(formatContext->syncLyrics);
+ if (formatContext->artworkMime) mmfile_free(formatContext->artworkMime);
+ if (formatContext->recDate) mmfile_free(formatContext->recDate);
+
+ if (formatContext->privateFormatData) mmfile_free(formatContext->privateFormatData);
+ if (formatContext->privateCodecData) mmfile_free(formatContext->privateCodecData);
+
+ if (formatContext->nbStreams > 0) {
+ int i = 0;
+ for (i = 0; i < MAXSTREAMS; i++)
+ if (formatContext->streams[i]) mmfile_free(formatContext->streams[i]);
+ }
+
+ if (formatContext->thumbNail) {
+ if (formatContext->thumbNail->frameData)
+ mmfile_free (formatContext->thumbNail->frameData);
+
+ if (formatContext->thumbNail->configData)
+ mmfile_free (formatContext->thumbNail->configData);
+
+ mmfile_free (formatContext->thumbNail);
+ }
+
+ if (formatContext)
+ mmfile_free (formatContext);
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+
+
+EXPORT_API
+int mmfile_format_open (MMFileFormatContext **formatContext, MMFileSourceType *fileSrc)
+{
+ int index = 0;
+ int ret = 0;
+ MMFileFormatContext *formatObject = NULL;
+
+ if (NULL == fileSrc) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ /* create formatContext object */
+ formatObject = mmfile_malloc (sizeof (MMFileFormatContext));
+ if (NULL == formatObject) {
+ debug_error ("error: mmfile_malloc fail for formatObject\n");
+ *formatContext = NULL;
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ memset (formatObject, 0x00, sizeof (MMFileFormatContext));
+
+ mmfile_register_io_all();
+
+ /* parsing file extension */
+ formatObject->filesrc = fileSrc;
+
+ formatObject->pre_checked = 0; /*not yet format checked.*/
+
+ /**
+ * Format detect and validation check.
+ */
+ ret = _PreprocessFile (fileSrc, &formatObject->uriFileName, &formatObject->formatType, &formatObject->isdrm);
+ if (MMFILE_FORMAT_SUCCESS != ret) {
+ debug_error ("error: _PreprocessFile fail\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ formatObject->pre_checked = 1; /*already file format checked.*/
+
+ /**
+ * Open format function.
+ */
+ if (NULL == MMFileOpenFunc[formatObject->formatType]) {
+ debug_error ("error: Not implemented \n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto find_valid_handler;
+ }
+
+ ret = MMFileOpenFunc[formatObject->formatType] (formatObject);
+ if (MMFILE_FORMAT_FAIL == ret) {
+ debug_error ("error: Try other formats\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto find_valid_handler;
+ }
+
+ *formatContext = formatObject;
+ return MMFILE_FORMAT_SUCCESS;
+
+find_valid_handler:
+ formatObject->pre_checked = 0; /*do check file format*/
+
+ for (index = 0; index < MM_FILE_FORMAT_NUM+1; index++) {
+ if (NULL == MMFileOpenFunc[index]) {
+ debug_error ("error: Not implemented \n");
+ ret = MMFILE_FORMAT_FAIL;
+ continue;
+ }
+
+ if (formatObject->formatType == index)
+ continue;
+
+ ret = MMFileOpenFunc[index] (formatObject);
+ if (MMFILE_FORMAT_FAIL == ret) {
+ _CleanupFrameContext (formatObject);
+ continue;
+ }
+
+ break;
+ }
+
+ formatObject->formatType = index;
+
+ if (index == MM_FILE_FORMAT_NUM + 1 && MMFILE_FORMAT_FAIL == ret) {
+ debug_error ("can't find file format handler\n");
+ ret = MMFILE_FORMAT_FAIL;
+ goto exception;
+ }
+
+ formatObject->formatType = index;
+ *formatContext = formatObject;
+
+ return MMFILE_FORMAT_SUCCESS;
+
+exception:
+ _mmfile_format_close (formatObject);
+ *formatContext = NULL;
+
+ return ret;
+}
+
+EXPORT_API
+int mmfile_format_read_stream (MMFileFormatContext *formatContext)
+{
+ if (NULL == formatContext || NULL == formatContext->ReadStream) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ return formatContext->ReadStream (formatContext);
+}
+
+EXPORT_API
+int mmfile_format_read_frame (MMFileFormatContext *formatContext, unsigned int timestamp, MMFileFormatFrame *frame)
+{
+ if (NULL == formatContext || NULL == frame || NULL == formatContext->ReadFrame ) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ return formatContext->ReadFrame (formatContext, timestamp, frame);
+}
+
+EXPORT_API
+int mmfile_format_read_tag (MMFileFormatContext *formatContext)
+{
+ if (NULL == formatContext || NULL == formatContext->ReadTag) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ return formatContext->ReadTag (formatContext);
+}
+
+
+EXPORT_API
+int mmfile_format_close (MMFileFormatContext *formatContext)
+{
+ if (NULL == formatContext) {
+ debug_error ("error: invalid params\n");
+ return MMFILE_FORMAT_FAIL;
+ }
+
+ if (formatContext->Close) {
+ formatContext->Close(formatContext);
+ formatContext->Close = NULL;
+ }
+
+ if (formatContext->ReadFrame) formatContext->ReadFrame = NULL;
+ if (formatContext->ReadStream) formatContext->ReadStream = NULL;
+ if (formatContext->ReadTag) formatContext->ReadTag = NULL;
+ if (formatContext->Close) formatContext->Close = NULL;
+
+ if (formatContext->uriFileName) mmfile_free(formatContext->uriFileName);
+
+ if (formatContext->title) mmfile_free(formatContext->title);
+ if (formatContext->artist) mmfile_free(formatContext->artist);
+ if (formatContext->author) mmfile_free(formatContext->author);
+ if (formatContext->copyright) mmfile_free(formatContext->copyright);
+ if (formatContext->comment) mmfile_free(formatContext->comment);
+ if (formatContext->album) mmfile_free(formatContext->album);
+ if (formatContext->year) mmfile_free(formatContext->year);
+ if (formatContext->genre) mmfile_free(formatContext->genre);
+ if (formatContext->composer) mmfile_free(formatContext->composer);
+ if (formatContext->classification) mmfile_free(formatContext->classification);
+ if (formatContext->artwork) mmfile_free(formatContext->artwork);
+ if (formatContext->artworkMime) mmfile_free(formatContext->artworkMime);
+ if (formatContext->tagTrackNum) mmfile_free(formatContext->tagTrackNum);
+ if (formatContext->rating) mmfile_free(formatContext->rating);
+ if (formatContext->conductor) mmfile_free(formatContext->conductor);
+ if (formatContext->unsyncLyrics) mmfile_free(formatContext->unsyncLyrics);
+ if (formatContext->recDate) mmfile_free(formatContext->recDate);
+
+ if (formatContext->privateFormatData) mmfile_free(formatContext->privateFormatData);
+ if (formatContext->privateCodecData) mmfile_free(formatContext->privateCodecData);
+
+ if (formatContext->nbStreams > 0) {
+ int i = 0;
+ for (i = 0; i < MAXSTREAMS; i++)
+ if (formatContext->streams[i]) mmfile_free(formatContext->streams[i]);
+ }
+
+ if (formatContext->thumbNail) {
+ if (formatContext->thumbNail->frameData)
+ mmfile_free (formatContext->thumbNail->frameData);
+
+ if (formatContext->thumbNail->configData)
+ mmfile_free (formatContext->thumbNail->configData);
+
+ mmfile_free (formatContext->thumbNail);
+ }
+
+ if (formatContext)
+ mmfile_free (formatContext);
+
+ return MMFILE_FORMAT_SUCCESS;
+}
+