shithub: aacdec

Download patch

ref: 976c310f1d8d21d5f76415d124522dbda55f0b79
parent: 054797bf657887d453b7d2ad8fb24fe385ef287b
author: rjamorim <rjamorim>
date: Fri Dec 5 23:24:17 EST 2003

Latest modifications by shaohao

--- a/plugins/QCDMp4/QCDMp4.c
+++ b/plugins/QCDMp4/QCDMp4.c
@@ -22,7 +22,7 @@
 ** Commercial non-GPL licensing of this software is possible.
 ** For more info contact Ahead Software through Mpeg4AAClicense@nero.com.
 **
-** $Id: QCDMp4.c,v 1.3 2003/11/16 19:52:41 menno Exp $
+** $Id: QCDMp4.c,v 1.4 2003/12/06 04:24:17 rjamorim Exp $
 **/
 
 //#define DEBUG_OUTPUT
@@ -40,7 +40,7 @@
 #include "QCDInputDLL.h"
 #include "utils.h"
 #include "config.h"
-#include "aacinfo.h"
+//#include "aacinfo.h"
 //#include "aac2mp4.h"
 //
 //const char *long_ext_list = "MP4\0MPEG-4 Files (*.MP4)\0M4A\0MPEG-4 Files (*.M4A)\0AAC\0AAC Files (*.AAC)\0";
@@ -71,8 +71,8 @@
     16
 };
 //static char info_fn[_MAX_PATH];
-
-// post this to the main window at end of file (after playback has stopped)
+//
+//// post this to the main window at end of file (after playback has stopped)
 //#define WM_WA_AAC_EOF WM_USER+2
 
 struct seek_list
@@ -125,7 +125,7 @@
 
 //static In_Module module; // the output module (declared near the bottom of this file)
 struct {
-	HINSTANCE		hInstance;
+	HINSTANCE		hDllInstance;
 	HWND			hMainWindow;
 	QCDModInitIn	QCDCallbacks;
 } module;
@@ -141,6 +141,295 @@
 DWORD WINAPI AACPlayThread(void *b); // the decode thread procedure
 
 
+//typedef struct tag
+//{
+//    char *item;
+//    char *value;
+//} tag;
+//
+//typedef struct medialib_tags
+//{
+//    struct tag *tags;
+//    unsigned int count;
+//} medialib_tags;
+//
+//int tag_add_field(medialib_tags *tags, const char *item, const char *value)
+//{
+//    void *backup = (void *)tags->tags;
+//
+//    if (!item || (item && !*item) || !value) return 0;
+//
+//    tags->tags = (struct tag *)realloc(tags->tags, (tags->count+1) * sizeof(tag));
+//    if (!tags->tags) {
+//        if (backup) free(backup);
+//        return 0;
+//    }
+//    else
+//    {
+//        int i_len = strlen(item);
+//        int v_len = strlen(value);
+//
+//        tags->tags[tags->count].item = (char *)malloc(i_len+1);
+//        tags->tags[tags->count].value = (char *)malloc(v_len+1);
+//
+//        if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
+//        {
+//            if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
+//            if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
+//            tags->tags[tags->count].item = NULL;
+//            tags->tags[tags->count].value = NULL;
+//            return 0;
+//        }
+//
+//        memcpy(tags->tags[tags->count].item, item, i_len);
+//        memcpy(tags->tags[tags->count].value, value, v_len);
+//        tags->tags[tags->count].item[i_len] = '\0';
+//        tags->tags[tags->count].value[v_len] = '\0';
+//
+//        tags->count++;
+//        return 1;
+//    }
+//}
+//
+//int tag_set_field(medialib_tags *tags, const char *item, const char *value)
+//{
+//    unsigned int i;
+//
+//    if (!item || (item && !*item) || !value) return 0;
+//
+//    for (i = 0; i < tags->count; i++)
+//    {
+//        if (!stricmp(tags->tags[i].item, item))
+//        {
+//            void *backup = (void *)tags->tags[i].value;
+//            int v_len = strlen(value);
+//
+//            tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
+//            if (!tags->tags[i].value)
+//            {
+//                if (backup) free(backup);
+//                return 0;
+//            }
+//
+//            memcpy(tags->tags[i].value, value, v_len);
+//            tags->tags[i].value[v_len] = '\0';
+//
+//            return 1;
+//        }
+//    }
+//
+//    return tag_add_field(tags, item, value);
+//}
+//
+//int tag_delete(medialib_tags *tags)
+//{
+//    unsigned int i;
+//
+//    for (i = 0; i < tags->count; i++)
+//    {
+//        if (tags->tags[i].item) free(tags->tags[i].item);
+//        if (tags->tags[i].value) free(tags->tags[i].value);
+//    }
+//
+//    if (tags->tags) free(tags->tags);
+//
+//    tags->tags = NULL;
+//    tags->count = 0;
+//}
+//
+//int ReadMP4Tag(MP4FileHandle file, medialib_tags *tags)
+//{
+//    unsigned __int32 valueSize;
+//    unsigned __int8 *pValue;
+//    char *pName;
+//    unsigned int i = 0;
+//
+//    do {
+//        pName = 0;
+//        pValue = 0;
+//        valueSize = 0;
+//
+//        MP4GetMetadataByIndex(file, i, (const char **)&pName, &pValue, &valueSize);
+//
+//        if (valueSize > 0)
+//        {
+//            char *val = (char *)malloc(valueSize+1);
+//            if (!val) return 0;
+//            memcpy(val, pValue, valueSize);
+//            val[valueSize] = '\0';
+//
+//            if (pName[0] == '\xa9')
+//            {
+//                if (memcmp(pName, "�nam", 4) == 0)
+//                {
+//                    tag_add_field(tags, "title", val);
+//                } else if (memcmp(pName, "�ART", 4) == 0) {
+//                    tag_add_field(tags, "artist", val);
+//                } else if (memcmp(pName, "�wrt", 4) == 0) {
+//                    tag_add_field(tags, "writer", val);
+//                } else if (memcmp(pName, "�alb", 4) == 0) {
+//                    tag_add_field(tags, "album", val);
+//                } else if (memcmp(pName, "�day", 4) == 0) {
+//                    tag_add_field(tags, "date", val);
+//                } else if (memcmp(pName, "�too", 4) == 0) {
+//                    tag_add_field(tags, "tool", val);
+//                } else if (memcmp(pName, "�cmt", 4) == 0) {
+//                    tag_add_field(tags, "comment", val);
+//                } else if (memcmp(pName, "�gen", 4) == 0) {
+//                    tag_add_field(tags, "genre", val);
+//                } else {
+//                    tag_add_field(tags, pName, val);
+//                }
+//            } else if (memcmp(pName, "gnre", 4) == 0) {
+//                char *t=0;
+//                if (MP4GetMetadataGenre(file, &t))
+//                {
+//                    tag_add_field(tags, "genre", t);
+//                }
+//            } else if (memcmp(pName, "trkn", 4) == 0) {
+//                unsigned __int16 trkn = 0, tot = 0;
+//                char t[200];
+//                if (MP4GetMetadataTrack(file, &trkn, &tot))
+//                {
+//                    if (tot > 0)
+//                        wsprintf(t, "%d/%d", trkn, tot);
+//                    else
+//                        wsprintf(t, "%d", trkn);
+//                    tag_add_field(tags, "tracknumber", t);
+//                }
+//            } else if (memcmp(pName, "disk", 4) == 0) {
+//                unsigned __int16 disk = 0, tot = 0;
+//                char t[200];
+//                if (MP4GetMetadataDisk(file, &disk, &tot))
+//                {
+//                    if (tot > 0)
+//                        wsprintf(t, "%d/%d", disk, tot);
+//                    else
+//                        wsprintf(t, "%d", disk);
+//                    tag_add_field(tags, "disc", t);
+//                }
+//            } else if (memcmp(pName, "cpil", 4) == 0) {
+//                unsigned __int8 cpil = 0;
+//                char t[200];
+//                if (MP4GetMetadataCompilation(file, &cpil))
+//                {
+//                    wsprintf(t, "%d", cpil);
+//                    tag_add_field(tags, "compilation", t);
+//                }
+//            } else if (memcmp(pName, "tmpo", 4) == 0) {
+//                unsigned __int16 tempo = 0;
+//                char t[200];
+//                if (MP4GetMetadataTempo(file, &tempo))
+//                {
+//                    wsprintf(t, "%d BPM", tempo);
+//                    tag_add_field(tags, "tempo", t);
+//                }
+//            } else if (memcmp(pName, "NDFL", 4) == 0) {
+//                /* Removed */
+//            } else {
+//                tag_add_field(tags, pName, val);
+//            }
+//
+//            free(val);
+//        }
+//
+//        i++;
+//    } while (valueSize > 0);
+//
+//    return 1;
+//}
+//
+//int mp4_set_metadata(MP4FileHandle file, const char *item, const char *val)
+//{
+//    if (!item || (item && !*item) || !val || (val && !*val)) return 0;
+//
+//    if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
+//    {
+//        unsigned __int16 trkn, tot;
+//        int t1 = 0, t2 = 0;
+//        sscanf(val, "%d/%d", &t1, &t2);
+//        trkn = t1, tot = t2;
+//        if (!trkn) return 1;
+//        if (MP4SetMetadataTrack(file, trkn, tot)) return 1;
+//    }
+//    else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
+//    {
+//        unsigned __int16 disk, tot;
+//        int t1 = 0, t2 = 0;
+//        sscanf(val, "%d/%d", &t1, &t2);
+//        disk = t1, tot = t2;
+//        if (!disk) return 1;
+//        if (MP4SetMetadataDisk(file, disk, tot)) return 1;
+//    }
+//    else if (!stricmp(item, "compilation"))
+//    {
+//        unsigned __int8 cpil = atoi(val);
+//        if (!cpil) return 1;
+//        if (MP4SetMetadataCompilation(file, cpil)) return 1;
+//    }
+//    else if (!stricmp(item, "tempo"))
+//    {
+//        unsigned __int16 tempo = atoi(val);
+//        if (!tempo) return 1;
+//        if (MP4SetMetadataTempo(file, tempo)) return 1;
+//    }
+//    else if (!stricmp(item, "artist"))
+//    {
+//        if (MP4SetMetadataArtist(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "writer"))
+//    {
+//        if (MP4SetMetadataWriter(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "title"))
+//    {
+//        if (MP4SetMetadataName(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "album"))
+//    {
+//        if (MP4SetMetadataAlbum(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "date") || !stricmp(item, "year"))
+//    {
+//        if (MP4SetMetadataYear(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "comment"))
+//    {
+//        if (MP4SetMetadataComment(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "genre"))
+//    {
+//        if (MP4SetMetadataGenre(file, val)) return 1;
+//    }
+//    else if (!stricmp(item, "tool"))
+//    {
+//        if (MP4SetMetadataTool(file, val)) return 1;
+//    }
+//    else
+//    {
+//        if (MP4SetMetadataFreeForm(file, (char *)item, (u_int8_t *)val, (u_int32_t)strlen(val))) return 1;
+//    }
+//
+//    return 0;
+//}
+//
+//int WriteMP4Tag(MP4FileHandle file, const medialib_tags *tags)
+//{
+//    unsigned int i;
+//
+//    for (i = 0; i < tags->count; i++)
+//    {
+//        const char *item = tags->tags[i].item;
+//        const char *value = tags->tags[i].value;
+//
+//        if (value && *value)
+//        {
+//            mp4_set_metadata(file, item, value);
+//        }
+//    }
+//}
+
+
 #ifdef DEBUG_OUTPUT
 void in_mp4_DebugOutput(char *message)
 {
@@ -428,6 +717,7 @@
 //    int r;
 //
 //    if (!str) return FALSE;
+//    if (!*str) return TRUE;
 //    len = strlen(str);
 //    temp = malloc(len+1);
 //    if (!temp) return FALSE;
@@ -445,7 +735,8 @@
 //    int len;
 //    HWND w;
 //
-//    if (!str) return 0;
+//    if (!str || !max) return 0;
+//    *str = '\0';
 //    w = GetDlgItem(hwnd, id);
 //    len = GetWindowTextLength(w);
 //    temp = malloc(len+1);
@@ -482,6 +773,10 @@
 //    MP4FileHandle file;
 //    char *pVal, dummy1[1024], dummy3;
 //    short dummy, dummy2;
+//    char temp[1024];
+//    struct medialib_tags tags;
+//    tags.count = 0;
+//    tags.tags = NULL;
 //
 //#ifdef DEBUG_OUTPUT
 //    in_mp4_DebugOutput("mp4_info_dialog_proc");
@@ -496,7 +791,6 @@
 //        EnableWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), FALSE);
 //        ShowWindow(GetDlgItem(hwndDlg,IDC_CONVERT2), SW_HIDE);
 //
-//
 //        file = MP4Read(info_fn, 0);
 //
 //        if (file == MP4_INVALID_FILE_HANDLE)
@@ -509,51 +803,66 @@
 //        /* get Metadata */
 //
 //        pVal = NULL;
-//        MP4GetMetadataName(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
+//        if (MP4GetMetadataName(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
 //
 //        pVal = NULL;
-//        MP4GetMetadataArtist(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
+//        if (MP4GetMetadataArtist(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
 //
 //        pVal = NULL;
-//        MP4GetMetadataWriter(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
+//        if (MP4GetMetadataWriter(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
 //
 //        pVal = NULL;
-//        MP4GetMetadataComment(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
+//        if (MP4GetMetadataComment(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
 //
 //        pVal = NULL;
-//        MP4GetMetadataAlbum(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
+//        if (MP4GetMetadataAlbum(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
 //
 //        pVal = NULL;
-//        MP4GetMetadataGenre(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
+//        if (MP4GetMetadataGenre(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
 //
 //        dummy = 0;
 //        MP4GetMetadataTempo(file, &dummy);
-//        wsprintf(dummy1, "%d", dummy);
-//        SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+//        if (dummy)
+//        {
+//            wsprintf(dummy1, "%d", dummy);
+//            SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+//        }
 //
 //        dummy = 0; dummy2 = 0;
 //        MP4GetMetadataTrack(file, &dummy, &dummy2);
-//        wsprintf(dummy1, "%d", dummy);
-//        SetDlgItemText(hwndDlg,IDC_METATRACK1, dummy1);
-//        wsprintf(dummy1, "%d", dummy2);
-//        SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+//        if (dummy)
+//        {
+//            wsprintf(dummy1, "%d", dummy);
+//            SetDlgItemText(hwndDlg,IDC_METATRACK1, dummy1);
+//        }
+//        if (dummy2)
+//        {
+//            wsprintf(dummy1, "%d", dummy2);
+//            SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+//        }
 //
 //        dummy = 0; dummy2 = 0;
 //        MP4GetMetadataDisk(file, &dummy, &dummy2);
-//        wsprintf(dummy1, "%d", dummy);
-//        SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
-//        wsprintf(dummy1, "%d", dummy2);
-//        SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+//        if (dummy)
+//        {
+//            wsprintf(dummy1, "%d", dummy);
+//            SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
+//        }
+//        if (dummy2)
+//        {
+//            wsprintf(dummy1, "%d", dummy2);
+//            SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+//        }
 //
 //        pVal = NULL;
-//        MP4GetMetadataYear(file, &pVal);
-//        uSetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
+//        if (MP4GetMetadataYear(file, &pVal))
+//            uSetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
 //
 //        dummy3 = 0;
 //        MP4GetMetadataCompilation(file, &dummy3);
@@ -575,53 +884,72 @@
 //
 //            /* save Metadata changes */
 //
+//            tag_delete(&tags);
+//            file = MP4Read(info_fn, 0);
+//            if (file != MP4_INVALID_FILE_HANDLE)
+//            {
+//                ReadMP4Tag(file, &tags);
+//                MP4Close(file);
+//
+//                file = MP4Modify(info_fn, 0, 0);
+//                if (file != MP4_INVALID_FILE_HANDLE)
+//                {
+//                    MP4MetadataDelete(file);
+//                    MP4Close(file);
+//                }
+//            }
+//
 //            file = MP4Modify(info_fn, 0, 0);
 //            if (file == MP4_INVALID_FILE_HANDLE)
 //            {
+//                tag_delete(&tags);
 //                EndDialog(hwndDlg, wParam);
 //                return FALSE;
 //            }
 //
 //            uGetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
-//            MP4SetMetadataName(file, dummy1);
+//            tag_set_field(&tags, "title", dummy1);
 //
 //            uGetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
-//            MP4SetMetadataWriter(file, dummy1);
+//            tag_set_field(&tags, "writer", dummy1);
 //
 //            uGetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
-//            MP4SetMetadataArtist(file, dummy1);
+//            tag_set_field(&tags, "artist", dummy1);
 //
 //            uGetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
-//            MP4SetMetadataAlbum(file, dummy1);
+//            tag_set_field(&tags, "album", dummy1);
 //
 //            uGetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
-//            MP4SetMetadataComment(file, dummy1);
+//            tag_set_field(&tags, "comment", dummy1);
 //
 //            uGetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
-//            MP4SetMetadataGenre(file, dummy1);
+//            tag_set_field(&tags, "genre", dummy1);
 //
 //            uGetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
-//            MP4SetMetadataYear(file, dummy1);
+//            tag_set_field(&tags, "year", dummy1);
 //
 //            GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
 //            dummy = atoi(dummy1);
 //            GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
 //            dummy2 = atoi(dummy1);
-//            MP4SetMetadataTrack(file, dummy, dummy2);
+//            wsprintf(temp, "%d/%d", dummy, dummy2);
+//            tag_set_field(&tags, "track", temp);
 //
 //            GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
 //            dummy = atoi(dummy1);
 //            GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
 //            dummy2 = atoi(dummy1);
-//            MP4SetMetadataDisk(file, dummy, dummy2);
+//            wsprintf(temp, "%d/%d", dummy, dummy2);
+//            tag_set_field(&tags, "disc", temp);
 //
 //            GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
-//            dummy = atoi(dummy1);
-//            MP4SetMetadataTempo(file, dummy);
+//            tag_set_field(&tags, "tempo", dummy1);
 //
 //            dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
-//            MP4SetMetadataCompilation(file, dummy3);
+//            tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"));
 //
+//            WriteMP4Tag(file, &tags);
+//
 //            MP4Close(file);
 //
 //            MP4Optimize(info_fn, NULL, 0);
@@ -795,7 +1123,6 @@
 //    char *pVal, dummy1[1024];
 //    short dummy, dummy2;
 //
-//
 //    while (*in && out < bound)
 //    {
 //        switch (*in)
@@ -968,7 +1295,7 @@
 
 void Configure(int flags)
 {
-	DialogBox(module.hInstance, MAKEINTRESOURCE(IDD_CONFIG),
+    DialogBox(module.hDllInstance, MAKEINTRESOURCE(IDD_CONFIG),
 		module.hMainWindow, config_dialog_proc);
 }
 
@@ -1179,6 +1506,8 @@
 	return 0;
 }
 
+//-----------------------------------------------------------------------------
+
 int Play(const char* medianame, int playfrom, int playto, int flags)
 {
     WAVEFORMATEX wf;
@@ -1231,7 +1560,6 @@
         int bread = 0;
         double length = 0.;
         __int64 bitrate = 128;
-        faacDecFrameInfo frameInfo;
 
         //module.is_seekable = 1;
 
@@ -1488,7 +1816,7 @@
     mp4state.decode_pos_ms =  0;
     mp4state.seek_needed   = -1;
 
-    // initialize vis stuff
+    //// initialize vis stuff
     //module.SAVSAInit(maxlatency, mp4state.samplerate);
     //module.VSASetInfo((int)mp4state.channels, mp4state.samplerate);
 
@@ -1596,15 +1924,15 @@
 
 int Stop(const char* medianame, int flags)
 {
-	struct seek_list *target = mp4state.m_head;
+    struct seek_list *target = mp4state.m_head;
 
 #ifdef DEBUG_OUTPUT
-	in_mp4_DebugOutput("stop");
+    in_mp4_DebugOutput("stop");
 #endif
 
 	if (medianame && *medianame && stricmp(mp4state.filename, medianame) == 0)
 	{
-		module.QCDCallbacks.toPlayer.OutputStop(flags);
+	module.QCDCallbacks.toPlayer.OutputStop(flags);
     killPlayThread = 1;
 
     if (play_thread_handle != INVALID_HANDLE_VALUE)
@@ -1633,14 +1961,14 @@
 
     //module.outMod->Close();
     //module.SAVSADeInit();
-		mp4state.filename[0] = '\0';
-		mp4state.paused = 0;
+	mp4state.filename[0] = '\0';
+	mp4state.paused = 0;
 	}
 
 	return 1;
 }
 
-int getsonglength(char *fn)
+int getsonglength(const char *fn)
 {
     long msDuration = 0;
 
@@ -1950,6 +2278,7 @@
 
             mp4state.decode_pos_ms = mp4state.seek_needed;
             mp4state.seek_needed = -1;
+			updatepos = 1;
         }
 
         if (done)
@@ -2267,6 +2596,7 @@
                 mp4state.decode_pos_ms = mp4state.seek_needed;
             }
             mp4state.seek_needed = -1;
+			updatepos = 1;
         }
 
         if (done)
@@ -2341,7 +2671,7 @@
 				if (!module.QCDCallbacks.toPlayer.OutputWrite(&wd))
 					done = 1;
 
-				//if (module.dsp_isactive())
+                //if (module.dsp_isactive())
                 //{
                 //    void *dsp_buffer = malloc(l*2);
                 //    memcpy(dsp_buffer, sample_buffer, l);
@@ -2399,9 +2729,9 @@
 {
 	if (fdwReason == DLL_PROCESS_ATTACH)
 	{
-		module.hInstance = hInst;
+		module.hDllInstance = hInst;
 	}
-	return TRUE;
+	return 1;
 }
 
 //-----------------------------------------------------------------------------
@@ -2424,3 +2754,239 @@
 
 	return &module.QCDCallbacks;
 }
+
+///* new Media Library interface */
+//
+//int mp4_get_metadata(MP4FileHandle file, const char *item, char *dest, int dlen)
+//{
+//    char *pVal = NULL, dummy1[4096];
+//    short dummy = 0, dummy2 = 0;
+//
+//    if (dlen < 1) return 0;
+//
+//    if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
+//    {
+//        if (MP4GetMetadataTrack(file, &dummy, &dummy2))
+//        {
+//            wsprintf(dummy1, "%d", (int)dummy);
+//            strncpy(dest, dummy1, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
+//    {
+//        if (MP4GetMetadataDisk(file, &dummy, &dummy2))
+//        {
+//            wsprintf(dummy1, "%d", (int)dummy);
+//            strncpy(dest, dummy1, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "compilation"))
+//    {
+//        u_int8_t cpil = 0;
+//        if (MP4GetMetadataCompilation(file, &cpil))
+//        {
+//            wsprintf(dummy1, "%d", (int)cpil);
+//            strncpy(dest, dummy1, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "tempo"))
+//    {
+//        u_int16_t tempo = 0;
+//        if (MP4GetMetadataTempo(file, &tempo))
+//        {
+//            wsprintf(dummy1, "%d", (int)tempo);
+//            strncpy(dest, dummy1, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "artist"))
+//    {
+//        if (MP4GetMetadataArtist(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "writer"))
+//    {
+//        if (MP4GetMetadataWriter(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "title"))
+//    {
+//        if (MP4GetMetadataName(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "album"))
+//    {
+//        if (MP4GetMetadataAlbum(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "date") || !stricmp(item, "year"))
+//    {
+//        if (MP4GetMetadataYear(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "comment"))
+//    {
+//        if (MP4GetMetadataComment(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "genre"))
+//    {
+//        if (MP4GetMetadataGenre(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else if (!stricmp(item, "tool"))
+//    {
+//        if (MP4GetMetadataTool(file, &pVal))
+//        {
+//            strncpy(dest, pVal, dlen-1);
+//            dest[dlen-1] = '\0';
+//            return 1;
+//        }
+//    }
+//    else
+//    {
+//        u_int32_t valueSize = 0;
+//        u_int8_t *pValue = NULL;
+//
+//        if (MP4GetMetadataFreeForm(file, (char *)item, &pValue, &valueSize))
+//        {
+//            unsigned int len = (valueSize < (unsigned int)(dlen-1)) ? valueSize : (unsigned int)(dlen-1);
+//            memcpy(dest, pValue, len);
+//            dest[len] = '\0';
+//            return 1;
+//        }
+//    }
+//
+//    return 0;
+//}
+//
+//__declspec(dllexport) int winampGetExtendedFileInfo(const char *fn, const char *data, char *dest, int destlen)
+//{
+//    if (!fn || (fn && !*fn) || !destlen) return 0;
+//
+//    dest[0] = '\0';
+//
+//    if (!stricmp(data, "length"))
+//    {
+//        char temp[32];
+//        int len = getsonglength(fn);
+//        itoa(len, temp, 10);
+//        strncpy(dest, temp, destlen-1);
+//        dest[destlen-1] = '\0';
+//    }
+//    else
+//    {
+//        char temp[2048], temp2[2048];
+//        MP4FileHandle file = MP4Read(fn, 0);
+//        if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//
+//        if (mp4_get_metadata(file, data, temp, sizeof(temp)))
+//        {
+//            int len = ConvertUTF8ToANSI(temp, temp2);
+//            if (len > destlen-1) len = destlen-1;
+//            memcpy(dest, temp2, len);
+//            dest[len] = '\0';
+//        }
+//
+//        MP4Close(file);
+//    }
+//
+//    return 1;
+//}
+//
+//static struct medialib_tags mltags = {0, 0};
+//static BOOL medialib_init = FALSE;
+//static char medialib_lastfn[2048] = "";
+//
+//__declspec(dllexport) int winampSetExtendedFileInfo(const char *fn, const char *data, char *val)
+//{
+//    int len, ret = 0;
+//    char *temp;
+//
+//    if (!medialib_init || (medialib_init && stricmp(fn, medialib_lastfn))) {
+//        MP4FileHandle file;
+//        strcpy(medialib_lastfn, fn);
+//
+//        if (medialib_init) tag_delete(&mltags);
+//
+//        file = MP4Read(fn, 0);
+//        if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//        ReadMP4Tag(file, &mltags);
+//        MP4Close(file);
+//        medialib_init = TRUE;
+//    }
+//
+//    len = strlen(val);
+//    temp = (char *)malloc((len+1)*4);
+//    if (!temp) return 0;
+//
+//    if (ConvertANSIToUTF8(val, temp))
+//    {
+//        ret = 1;
+//        tag_set_field(&mltags, data, temp);
+//    }
+//
+//    free(temp);
+//
+//    return ret;
+//}    
+//
+//__declspec(dllexport) int winampWriteExtendedFileInfo()
+//{
+//    if (medialib_init)
+//    {
+//        MP4FileHandle file = MP4Modify(medialib_lastfn, 0, 0);
+//        if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//
+//        MP4MetadataDelete(file);
+//        MP4Close(file);
+//
+//        file = MP4Modify(medialib_lastfn, 0, 0);
+//        if (file == MP4_INVALID_FILE_HANDLE) return 0;
+//
+//        WriteMP4Tag(file, &mltags);
+//
+//        MP4Close(file);
+//
+//        return 1;
+//    }
+//    else
+//    {
+//        return 0;
+//    }
+//}
--- a/plugins/QCDMp4/QCDMp4.rc
+++ b/plugins/QCDMp4/QCDMp4.rc
@@ -13,6 +13,76 @@
 #undef APSTUDIO_READONLY_SYMBOLS
 
 /////////////////////////////////////////////////////////////////////////////
+// ����(�л����񹲺͹�) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
+#ifdef _WIN32
+LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED
+#pragma code_page(936)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_CONFIG DIALOGEX 0, 0, 242, 93
+STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | 
+    WS_SYSMENU
+CAPTION "Configuration"
+FONT 9, "����", 400, 0, 0x86
+BEGIN
+    CONTROL         "Slider1",IDC_PRIORITY,"msctls_trackbar32",TBS_VERT | 
+                    TBS_NOTICKS | WS_TABSTOP,13,15,18,46
+    CONTROL         "16 λ",IDC_16BITS,"Button",BS_AUTORADIOBUTTON,77,18,37,
+                    10
+    CONTROL         "16 λ��Ƶ����",IDC_16BITS_DITHERED,"Button",
+                    BS_AUTORADIOBUTTON | WS_DISABLED,77,29,64,10
+    CONTROL         "24 λ",IDC_24BITS,"Button",BS_AUTORADIOBUTTON,77,40,37,
+                    10
+    CONTROL         "32 λ",IDC_32BITS,"Button",BS_AUTORADIOBUTTON,77,51,37,
+                    10
+    CONTROL         "���»�Ƶ��������",IDC_DOWNMIX,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,13,80,10
+    CONTROL         "֧�� AAC ��ʽ",IDC_USEFORAAC,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,26,68,10
+    CONTROL         "��ʾ�ɱ�������",IDC_VBR,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,39,72,10
+    CONTROL         "��ʾ������Ϣ",IDC_ERROR,"Button",BS_AUTOCHECKBOX | 
+                    WS_TABSTOP,152,52,64,10
+    DEFPUSHBUTTON   "ȷ��",IDOK,185,72,50,14
+    PUSHBUTTON      "ȡ��",IDCANCEL,127,72,50,14
+    GROUPBOX        "���ȼ�",IDC_STATIC,7,7,57,58
+    LTEXT           "��",IDC_STATIC,34,18,25,8
+    LTEXT           "��׼",IDC_STATIC,34,35,23,8
+    LTEXT           "��",IDC_STATIC,34,52,24,8
+    GROUPBOX        "������",IDC_STATIC,71,7,73,58
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO 
+BEGIN
+    IDD_CONFIG, DIALOG
+    BEGIN
+        LEFTMARGIN, 7
+        RIGHTMARGIN, 235
+        TOPMARGIN, 7
+        BOTTOMMARGIN, 86
+    END
+END
+#endif    // APSTUDIO_INVOKED
+
+#endif    // ����(�л����񹲺͹�) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
 // ������(����) resources
 
 #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NLD)
--- a/plugins/QCDMp4/QCDMp4.vcproj
+++ b/plugins/QCDMp4/QCDMp4.vcproj
@@ -83,6 +83,7 @@
 			ATLMinimizesCRunTimeLibraryUsage="FALSE">
 			<Tool
 				Name="VCCLCompilerTool"
+				Optimization="1"
 				GlobalOptimizations="TRUE"
 				InlineFunctionExpansion="1"
 				EnableIntrinsicFunctions="TRUE"
@@ -91,7 +92,7 @@
 				AdditionalIncludeDirectories="..\..\include,..\..\common\mp4v2,..\..\common\mp4av"
 				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
 				StringPooling="TRUE"
-				RuntimeLibrary="0"
+				RuntimeLibrary="2"
 				EnableFunctionLevelLinking="TRUE"
 				UsePrecompiledHeader="2"
 				PrecompiledHeaderFile=".\Release/QCDMp4.pch"
@@ -110,6 +111,7 @@
 				OutputFile=".\Release/QCDMp4.dll"
 				LinkIncremental="1"
 				SuppressStartupBanner="TRUE"
+				IgnoreDefaultLibraryNames=""
 				ProgramDatabaseFile=".\Release/QCDMp4.pdb"
 				SubSystem="2"
 				ImportLibrary=".\Release/QCDMp4.lib"/>
@@ -149,12 +151,6 @@
 			Name="Source Files"
 			Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
 			<File
-				RelativePath="aac2mp4.cpp">
-			</File>
-			<File
-				RelativePath="aacinfo.c">
-			</File>
-			<File
 				RelativePath=".\config.c">
 			</File>
 			<File
@@ -170,12 +166,6 @@
 		<Filter
 			Name="Header Files"
 			Filter="h;hpp;hxx;hm;inl">
-			<File
-				RelativePath="aac2mp4.h">
-			</File>
-			<File
-				RelativePath="aacinfo.h">
-			</File>
 			<File
 				RelativePath=".\config.h">
 			</File>
--- a/plugins/QCDMp4/QCDMp4Tag.cpp
+++ b/plugins/QCDMp4/QCDMp4Tag.cpp
@@ -6,7 +6,298 @@
 //..............................................................................
 // Global Variables
 
+typedef struct tag
+{
+    char *item;
+    char *value;
+} tag;
+
+typedef struct medialib_tags
+{
+    struct tag *tags;
+    unsigned int count;
+} medialib_tags;
+
+int tag_add_field(medialib_tags *tags, const char *item, const char *value)
+{
+    void *backup = (void *)tags->tags;
+
+    if (!item || (item && !*item) || !value) return 0;
+
+    tags->tags = (struct tag *)realloc(tags->tags, (tags->count+1) * sizeof(tag));
+    if (!tags->tags) {
+        if (backup) free(backup);
+        return 0;
+    }
+    else
+    {
+        int i_len = strlen(item);
+        int v_len = strlen(value);
+
+        tags->tags[tags->count].item = (char *)malloc(i_len+1);
+        tags->tags[tags->count].value = (char *)malloc(v_len+1);
+
+        if (!tags->tags[tags->count].item || !tags->tags[tags->count].value)
+        {
+            if (!tags->tags[tags->count].item) free (tags->tags[tags->count].item);
+            if (!tags->tags[tags->count].value) free (tags->tags[tags->count].value);
+            tags->tags[tags->count].item = NULL;
+            tags->tags[tags->count].value = NULL;
+            return 0;
+        }
+
+        memcpy(tags->tags[tags->count].item, item, i_len);
+        memcpy(tags->tags[tags->count].value, value, v_len);
+        tags->tags[tags->count].item[i_len] = '\0';
+        tags->tags[tags->count].value[v_len] = '\0';
+
+        tags->count++;
+        return 1;
+    }
+}
+
+int tag_set_field(medialib_tags *tags, const char *item, const char *value)
+{
+    unsigned int i;
+
+    if (!item || (item && !*item) || !value) return 0;
+
+    for (i = 0; i < tags->count; i++)
+    {
+        if (!stricmp(tags->tags[i].item, item))
+        {
+            void *backup = (void *)tags->tags[i].value;
+            int v_len = strlen(value);
+
+            tags->tags[i].value = (char *)realloc(tags->tags[i].value, v_len+1);
+            if (!tags->tags[i].value)
+            {
+                if (backup) free(backup);
+                return 0;
+            }
+
+            memcpy(tags->tags[i].value, value, v_len);
+            tags->tags[i].value[v_len] = '\0';
+
+            return 1;
+        }
+    }
+
+    return tag_add_field(tags, item, value);
+}
+
+void tag_delete(medialib_tags *tags)
+{
+    unsigned int i;
+
+    for (i = 0; i < tags->count; i++)
+    {
+        if (tags->tags[i].item) free(tags->tags[i].item);
+        if (tags->tags[i].value) free(tags->tags[i].value);
+    }
+
+    if (tags->tags) free(tags->tags);
+
+    tags->tags = NULL;
+    tags->count = 0;
+}
+
+int ReadMP4Tag(MP4FileHandle file, medialib_tags *tags)
+{
+    unsigned __int32 valueSize;
+    unsigned __int8 *pValue;
+    char *pName;
+    unsigned int i = 0;
+
+    do {
+        pName = 0;
+        pValue = 0;
+        valueSize = 0;
+
+        MP4GetMetadataByIndex(file, i, (const char **)&pName, &pValue, &valueSize);
+
+        if (valueSize > 0)
+        {
+            char *val = (char *)malloc(valueSize+1);
+            if (!val) return 0;
+            memcpy(val, pValue, valueSize);
+            val[valueSize] = '\0';
+
+            if (pName[0] == '\xa9')
+            {
+                if (memcmp(pName, "�nam", 4) == 0)
+                {
+                    tag_add_field(tags, "title", val);
+                } else if (memcmp(pName, "�ART", 4) == 0) {
+                    tag_add_field(tags, "artist", val);
+                } else if (memcmp(pName, "�wrt", 4) == 0) {
+                    tag_add_field(tags, "writer", val);
+                } else if (memcmp(pName, "�alb", 4) == 0) {
+                    tag_add_field(tags, "album", val);
+                } else if (memcmp(pName, "�day", 4) == 0) {
+                    tag_add_field(tags, "date", val);
+                } else if (memcmp(pName, "�too", 4) == 0) {
+                    tag_add_field(tags, "tool", val);
+                } else if (memcmp(pName, "�cmt", 4) == 0) {
+                    tag_add_field(tags, "comment", val);
+                } else if (memcmp(pName, "�gen", 4) == 0) {
+                    tag_add_field(tags, "genre", val);
+                } else {
+                    tag_add_field(tags, pName, val);
+                }
+            } else if (memcmp(pName, "gnre", 4) == 0) {
+                char *t=0;
+                if (MP4GetMetadataGenre(file, &t))
+                {
+                    tag_add_field(tags, "genre", t);
+                }
+            } else if (memcmp(pName, "trkn", 4) == 0) {
+                unsigned __int16 trkn = 0, tot = 0;
+                char t[200];
+                if (MP4GetMetadataTrack(file, &trkn, &tot))
+                {
+                    if (tot > 0)
+                        wsprintf(t, "%d/%d", trkn, tot);
+                    else
+                        wsprintf(t, "%d", trkn);
+                    tag_add_field(tags, "tracknumber", t);
+                }
+            } else if (memcmp(pName, "disk", 4) == 0) {
+                unsigned __int16 disk = 0, tot = 0;
+                char t[200];
+                if (MP4GetMetadataDisk(file, &disk, &tot))
+                {
+                    if (tot > 0)
+                        wsprintf(t, "%d/%d", disk, tot);
+                    else
+                        wsprintf(t, "%d", disk);
+                    tag_add_field(tags, "disc", t);
+                }
+            } else if (memcmp(pName, "cpil", 4) == 0) {
+                unsigned __int8 cpil = 0;
+                char t[200];
+                if (MP4GetMetadataCompilation(file, &cpil))
+                {
+                    wsprintf(t, "%d", cpil);
+                    tag_add_field(tags, "compilation", t);
+                }
+            } else if (memcmp(pName, "tmpo", 4) == 0) {
+                unsigned __int16 tempo = 0;
+                char t[200];
+                if (MP4GetMetadataTempo(file, &tempo))
+                {
+                    wsprintf(t, "%d BPM", tempo);
+                    tag_add_field(tags, "tempo", t);
+                }
+            } else if (memcmp(pName, "NDFL", 4) == 0) {
+                /* Removed */
+            } else {
+                tag_add_field(tags, pName, val);
+            }
+
+            free(val);
+        }
+
+        i++;
+    } while (valueSize > 0);
+
+    return 1;
+}
+
+int mp4_set_metadata(MP4FileHandle file, const char *item, const char *val)
+{
+    if (!item || (item && !*item) || !val || (val && !*val)) return 0;
+
+    if (!stricmp(item, "track") || !stricmp(item, "tracknumber"))
+    {
+        unsigned __int16 trkn, tot;
+        int t1 = 0, t2 = 0;
+        sscanf(val, "%d/%d", &t1, &t2);
+        trkn = t1, tot = t2;
+        if (!trkn) return 1;
+        if (MP4SetMetadataTrack(file, trkn, tot)) return 1;
+    }
+    else if (!stricmp(item, "disc") || !stricmp(item, "disknumber"))
+    {
+        unsigned __int16 disk, tot;
+        int t1 = 0, t2 = 0;
+        sscanf(val, "%d/%d", &t1, &t2);
+        disk = t1, tot = t2;
+        if (!disk) return 1;
+        if (MP4SetMetadataDisk(file, disk, tot)) return 1;
+    }
+    else if (!stricmp(item, "compilation"))
+    {
+        unsigned __int8 cpil = atoi(val);
+        if (!cpil) return 1;
+        if (MP4SetMetadataCompilation(file, cpil)) return 1;
+    }
+    else if (!stricmp(item, "tempo"))
+    {
+        unsigned __int16 tempo = atoi(val);
+        if (!tempo) return 1;
+        if (MP4SetMetadataTempo(file, tempo)) return 1;
+    }
+    else if (!stricmp(item, "artist"))
+    {
+        if (MP4SetMetadataArtist(file, val)) return 1;
+    }
+    else if (!stricmp(item, "writer"))
+    {
+        if (MP4SetMetadataWriter(file, val)) return 1;
+    }
+    else if (!stricmp(item, "title"))
+    {
+        if (MP4SetMetadataName(file, val)) return 1;
+    }
+    else if (!stricmp(item, "album"))
+    {
+        if (MP4SetMetadataAlbum(file, val)) return 1;
+    }
+    else if (!stricmp(item, "date") || !stricmp(item, "year"))
+    {
+        if (MP4SetMetadataYear(file, val)) return 1;
+    }
+    else if (!stricmp(item, "comment"))
+    {
+        if (MP4SetMetadataComment(file, val)) return 1;
+    }
+    else if (!stricmp(item, "genre"))
+    {
+        if (MP4SetMetadataGenre(file, val)) return 1;
+    }
+    else if (!stricmp(item, "tool"))
+    {
+        if (MP4SetMetadataTool(file, val)) return 1;
+    }
+    else
+    {
+        if (MP4SetMetadataFreeForm(file, (char *)item, (u_int8_t *)val, (u_int32_t)strlen(val) + 1)) return 1;
+    }
+
+    return 0;
+}
+
+void WriteMP4Tag(MP4FileHandle file, const medialib_tags *tags)
+{
+    unsigned int i;
+
+    for (i = 0; i < tags->count; i++)
+    {
+        const char *item = tags->tags[i].item;
+        const char *value = tags->tags[i].value;
+
+        if (value && *value)
+        {
+            mp4_set_metadata(file, item, value);
+        }
+    }
+}
+
 QCDModInitTag	ModInitTag;
+
+medialib_tags tags;
+
 BOOL uSetDlgItemText(void *tagHandle, int fieldId, const char *str);
 UINT uGetDlgItemText(void *tagHandle, int fieldId, char *str, int max);
 
@@ -35,6 +326,7 @@
 	// TODO:
 	// prepare plugin to be unloaded. All allocations should be freed.
 	// flags param is unused
+	tag_delete(&tags);
 }
 
 //-----------------------------------------------------------------------------
@@ -56,9 +348,8 @@
 	MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
 	char *pVal, dummy1[1024];
 	short dummy, dummy2;
+	u_int32_t valueSize = 0;
 
-	unsigned __int32 valueSize = 0;
-
 #ifdef DEBUG_OUTPUT
 	in_mp4_DebugOutput("mp4_tag_read");
 #endif
@@ -96,26 +387,41 @@
 
 	//dummy = 0;
 	//MP4GetMetadataTempo(file, &dummy);
-	//wsprintf(dummy1, "%d", dummy);
-	//SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+	//if (dummy)
+	//{
+	//	wsprintf(dummy1, "%d", dummy);
+	//	SetDlgItemText(hwndDlg,IDC_METATEMPO, dummy1);
+	//}
 
 	dummy = 0; dummy2 = 0;
 	MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
-	wsprintf(dummy1, "%d", dummy);
-	ModInitTag.SetFieldA(tagHandle, TAGFIELD_TRACK, dummy1);
-	//wsprintf(dummy1, "%d", dummy2);
-	//SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+	if (dummy)
+	{
+		wsprintf(dummy1, "%d", dummy);
+		ModInitTag.SetFieldA(tagHandle, TAGFIELD_TRACK, dummy1);
+	}
+	//if (dumm2)
+	//{
+	//	wsprintf(dummy1, "%d", dummy2);
+	//	SetDlgItemText(hwndDlg,IDC_METATRACK2, dummy1);
+	//}
 
 	//dummy = 0; dummy2 = 0;
 	//MP4GetMetadataDisk(file, &dummy, &dummy2);
-	//wsprintf(dummy1, "%d", dummy);
-	//SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
-	//wsprintf(dummy1, "%d", dummy2);
-	//SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+	//if (dummy)
+	//{
+	//	wsprintf(dummy1, "%d", dummy);
+	//	SetDlgItemText(hwndDlg,IDC_METADISK1, dummy1);
+	//}
+	//if (dummy)
+	//{
+	//	wsprintf(dummy1, "%d", dummy2);
+	//	SetDlgItemText(hwndDlg,IDC_METADISK2, dummy1);
+	//}
 
 	pVal = NULL;
-	MP4GetMetadataYear(file, &pVal);
-	uSetDlgItemText(tagHandle, TAGFIELD_YEAR, pVal);
+	if (MP4GetMetadataYear(file, &pVal))
+		uSetDlgItemText(tagHandle, TAGFIELD_YEAR, pVal);
 
 	//dummy3 = 0;
 	//MP4GetMetadataCompilation(file, &dummy3);
@@ -179,6 +485,7 @@
 
 	MP4FileHandle file = MP4_INVALID_FILE_HANDLE;
     char dummy1[1024];
+    char temp[1024];
     short dummy, dummy2;
 
 #ifdef DEBUG_OUTPUT
@@ -187,77 +494,96 @@
 
 	/* save Metadata changes */
 
+	tag_delete(&tags);
+	file = MP4Read(filename, 0);
+	if (file != MP4_INVALID_FILE_HANDLE)
+	{
+		ReadMP4Tag(file, &tags);
+		MP4Close(file);
+
+		file = MP4Modify(filename, 0, 0);
+		if (file != MP4_INVALID_FILE_HANDLE)
+		{
+			MP4MetadataDelete(file);
+			MP4Close(file);
+		}
+	}
+
 	file = MP4Modify(filename, 0, 0);
 	if (file == MP4_INVALID_FILE_HANDLE)
+	{
+		tag_delete(&tags);
+		//EndDialog(hwndDlg, wParam);
 		return false;
+	}
 
 	uGetDlgItemText(tagHandle, TAGFIELD_TITLE, dummy1, 1024);
-	MP4SetMetadataName(file, dummy1);
+	tag_set_field(&tags, "title", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_COMPOSER, dummy1, 1024);
-	MP4SetMetadataWriter(file, dummy1);
+	tag_set_field(&tags, "writer", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_ARTIST, dummy1, 1024);
-	MP4SetMetadataArtist(file, dummy1);
+	tag_set_field(&tags, "artist", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_ALBUM, dummy1, 1024);
-	MP4SetMetadataAlbum(file, dummy1);
+	tag_set_field(&tags, "album", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_COMMENT, dummy1, 1024);
-	MP4SetMetadataComment(file, dummy1);
+	tag_set_field(&tags, "comment", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_GENRE, dummy1, 1024);
-	MP4SetMetadataGenre(file, dummy1);
+	tag_set_field(&tags, "genre", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_YEAR, dummy1, 1024);
-	MP4SetMetadataYear(file, dummy1);
+	tag_set_field(&tags, "year", dummy1);
 
-	dummy = 0; dummy2 = 0;
+	dummy = 0;
 	MP4GetMetadataTrack(file, (unsigned __int16*)&dummy, (unsigned __int16*)&dummy2);
 	memcpy(dummy1, ModInitTag.GetFieldA(tagHandle, TAGFIELD_TRACK), sizeof(dummy1));
-	//GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
 	dummy = atoi(dummy1);
-	//GetDlgItemText(hwndDlg, IDC_METATRACK2, dummy1, 1024);
-	//dummy2 = atoi(dummy1);
-	MP4SetMetadataTrack(file, dummy, dummy2);
+	wsprintf(temp, "%d/%d", dummy, dummy2);
+	tag_set_field(&tags, "track", temp);
 
 	//GetDlgItemText(hwndDlg, IDC_METADISK1, dummy1, 1024);
 	//dummy = atoi(dummy1);
 	//GetDlgItemText(hwndDlg, IDC_METADISK2, dummy1, 1024);
 	//dummy2 = atoi(dummy1);
-	//MP4SetMetadataDisk(file, dummy, dummy2);
+	//wsprintf(temp, "%d/%d", dummy, dummy2);
+	//tag_set_field(&tags, "disc", temp);
 
 	//GetDlgItemText(hwndDlg, IDC_METATEMPO, dummy1, 1024);
-	//dummy = atoi(dummy1);
-	//MP4SetMetadataTempo(file, dummy);
+	//tag_set_field(&tags, "tempo", dummy1);
 
 	//dummy3 = SendMessage(GetDlgItem(hwndDlg, IDC_METACOMPILATION), BM_GETCHECK, 0, 0);
-	//MP4SetMetadataCompilation(file, dummy3);
+	//tag_set_field(&tags, "compilation", (dummy3 ? "1" : "0"));
 
 	uGetDlgItemText(tagHandle, TAGFIELD_ENCODER, dummy1, 1024);
-	MP4SetMetadataTool(file, dummy1);
+	tag_set_field(&tags, "tool", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_CONDUCTOR, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "CONDUCTOR", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "CONDUCTOR", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_ORCHESTRA, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "ORCHESTRA", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "ORCHESTRA", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_YEARCOMPOSED, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "YEARCOMPOSED", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "YEARCOMPOSED", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_ORIGARTIST, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "ORIGARTIST", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "ORIGARTIST", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_LABEL, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "LABEL", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "LABEL", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_COPYRIGHT, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "COPYRIGHT", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "COPYRIGHT", dummy1);
 
 	uGetDlgItemText(tagHandle, TAGFIELD_CDDBTAGID, dummy1, 1024);
-	MP4SetMetadataFreeForm(file, "CDDBTAGID", (unsigned __int8*)dummy1, strlen(dummy1) + 1);
+	tag_set_field(&tags, "CDDBTAGID", dummy1);
 
+	WriteMP4Tag(file, &tags);
+
 	MP4Close(file);
 
 	MP4Optimize(filename, NULL, 0);
@@ -459,6 +785,7 @@
     int r;
 
     if (!str) return FALSE;
+	if (!*str) return FALSE;
     len = strlen(str);
     temp = (char *)malloc(len+1);
     if (!temp) return FALSE;
@@ -478,7 +805,7 @@
 
 	const char *p;
 
-    if (!str) return 0;
+    if (!str || !max) return 0;
     len = strlen( ModInitTag.GetFieldA(tagHandle, fieldId) );
     temp = (char *)malloc(len+1);
     if (!temp) return 0;
@@ -491,6 +818,7 @@
 
 	memset(temp, '\0', len+1);
 	memset(utf8, '\0', (len+1)*4);
+	memset(str, '\0', max);
 	p = ModInitTag.GetFieldA(tagHandle, fieldId);
 	memcpy(temp, p, len+1);
     if (len > 0)