shithub: aacdec

Download patch

ref: 181682e90ddb6f6975f6651f5d8e05b985b198b9
parent: 0447babcc4d9b003817bc68e61650e60f0efdc5c
author: ca5e <ca5e>
date: Fri Oct 10 09:29:38 EDT 2003

Fixes

--- a/plugins/in_mp4/in_mp4.c
+++ b/plugins/in_mp4/in_mp4.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: in_mp4.c,v 1.40 2003/09/04 17:43:40 menno Exp $
+** $Id: in_mp4.c,v 1.41 2003/10/10 13:29:38 ca5e Exp $
 **/
 
 //#define DEBUG_OUTPUT
@@ -239,6 +239,221 @@
 {
 }
 
+/* Convert UNICODE to UTF-8
+   Return number of bytes written */
+int unicodeToUtf8 ( const WCHAR* lpWideCharStr, char* lpMultiByteStr, int cwcChars )
+{
+    const unsigned short*   pwc = (unsigned short *)lpWideCharStr;
+    unsigned char*          pmb = (unsigned char  *)lpMultiByteStr;
+    const unsigned short*   pwce;
+    size_t  cBytes = 0;
+
+    if ( cwcChars >= 0 ) {
+        pwce = pwc + cwcChars;
+    } else {
+        pwce = (unsigned short *)((size_t)-1);
+    }
+
+    while ( pwc < pwce ) {
+        unsigned short  wc = *pwc++;
+
+        if ( wc < 0x00000080 ) {
+            *pmb++ = (char)wc;
+            cBytes++;
+        } else
+        if ( wc < 0x00000800 ) {
+            *pmb++ = (char)(0xC0 | ((wc >>  6) & 0x1F));
+            cBytes++;
+            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
+            cBytes++;
+        } else
+        if ( wc < 0x00010000 ) {
+            *pmb++ = (char)(0xE0 | ((wc >> 12) & 0x0F));
+            cBytes++;
+            *pmb++ = (char)(0x80 | ((wc >>  6) & 0x3F));
+            cBytes++;
+            *pmb++ = (char)(0x80 |  (wc        & 0x3F));
+            cBytes++;
+        }
+        if ( wc == L'\0' )
+            return cBytes;
+    }
+
+    return cBytes;
+}
+
+/* Convert UTF-8 coded string to UNICODE
+   Return number of characters converted */
+int utf8ToUnicode ( const char* lpMultiByteStr, WCHAR* lpWideCharStr, int cmbChars )
+{
+    const unsigned char*    pmb = (unsigned char  *)lpMultiByteStr;
+    unsigned short*         pwc = (unsigned short *)lpWideCharStr;
+    const unsigned char*    pmbe;
+    size_t  cwChars = 0;
+
+    if ( cmbChars >= 0 ) {
+        pmbe = pmb + cmbChars;
+    } else {
+        pmbe = (unsigned char *)((size_t)-1);
+    }
+
+    while ( pmb < pmbe ) {
+        char            mb = *pmb++;
+        unsigned int    cc = 0;
+        unsigned int    wc;
+
+        while ( (cc < 7) && (mb & (1 << (7 - cc)))) {
+            cc++;
+        }
+
+        if ( cc == 1 || cc > 6 )                    // illegal character combination for UTF-8
+            continue;
+
+        if ( cc == 0 ) {
+            wc = mb;
+        } else {
+            wc = (mb & ((1 << (7 - cc)) - 1)) << ((cc - 1) * 6);
+            while ( --cc > 0 ) {
+                if ( pmb == pmbe )                  // reached end of the buffer
+                    return cwChars;
+                mb = *pmb++;
+                if ( ((mb >> 6) & 0x03) != 2 )      // not part of multibyte character
+                    return cwChars;
+                wc |= (mb & 0x3F) << ((cc - 1) * 6);
+            }
+        }
+
+        if ( wc & 0xFFFF0000 )
+            wc = L'?';
+        *pwc++ = wc;
+        cwChars++;
+        if ( wc == L'\0' )
+            return cwChars;
+    }
+
+    return cwChars;
+}
+
+/* convert Windows ANSI to UTF-8 */
+int ConvertANSIToUTF8 ( const char* ansi, char* utf8 )
+{
+    WCHAR*  wszValue;          // Unicode value
+    size_t  ansi_len;
+    size_t  len;
+
+    *utf8 = '\0';
+    if ( ansi == NULL )
+        return 0;
+
+    ansi_len = strlen ( ansi );
+
+    if ( (wszValue = (WCHAR *)malloc ( (ansi_len + 1) * 2 )) == NULL )
+        return 0;
+
+    /* Convert ANSI value to Unicode */
+    if ( (len = MultiByteToWideChar ( CP_ACP, 0, ansi, ansi_len + 1, wszValue, (ansi_len + 1) * 2 )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    /* Convert Unicode value to UTF-8 */
+    if ( (len = unicodeToUtf8 ( wszValue, utf8, -1 )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    free ( wszValue );
+
+    return len-1;
+}
+
+/* convert UTF-8 to Windows ANSI */
+int ConvertUTF8ToANSI ( const char* utf8, char* ansi )
+{
+    WCHAR*  wszValue;          // Unicode value
+    size_t  utf8_len;
+    size_t  len;
+
+    *ansi = '\0';
+    if ( utf8 == NULL )
+        return 0;
+
+    utf8_len = strlen ( utf8 );
+
+    if ( (wszValue = (WCHAR *)malloc ( (utf8_len + 1) * 2 )) == NULL )
+        return 0;
+
+    /* Convert UTF-8 value to Unicode */
+    if ( (len = utf8ToUnicode ( utf8, wszValue, utf8_len + 1 )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    /* Convert Unicode value to ANSI */
+    if ( (len = WideCharToMultiByte ( CP_ACP, 0, wszValue, -1, ansi, (utf8_len + 1) * 2, NULL, NULL )) == 0 ) {
+        free ( wszValue );
+        return 0;
+    }
+
+    free ( wszValue );
+
+    return len-1;
+}
+
+BOOL uSetDlgItemText(HWND hwnd, int id, const char *str)
+{
+    char *temp;
+    size_t len;
+    int r;
+
+    if (!str) return FALSE;
+    len = strlen(str);
+    temp = malloc(len+1);
+    if (!temp) return FALSE;
+    r = ConvertUTF8ToANSI(str, temp);
+    if (r > 0)
+        SetDlgItemText(hwnd, id, temp);
+    free(temp);
+
+    return r>0 ? TRUE : FALSE;
+}
+
+UINT uGetDlgItemText(HWND hwnd, int id, char *str, int max)
+{
+    char *temp, *utf8;
+    int len;
+    HWND w;
+
+    if (!str) return 0;
+    w = GetDlgItem(hwnd, id);
+    len = GetWindowTextLength(w);
+    temp = malloc(len+1);
+    if (!temp) return 0;
+    utf8 = malloc((len+1)*4);
+    if (!utf8)
+    {
+        free(temp);
+        return 0;
+    }
+
+    len = GetWindowText(w, temp, len+1);
+    if (len > 0)
+    {
+        len = ConvertANSIToUTF8(temp, utf8);
+        if (len > max-1)
+        {
+            len = max-1;
+            utf8[max] = '\0';
+        }
+        memcpy(str, utf8, len+1);
+    }
+
+    free(temp);
+    free(utf8);
+
+    return len;
+}
+
 BOOL CALLBACK mp4_info_dialog_proc(HWND hwndDlg, UINT message,
                                    WPARAM wParam, LPARAM lParam)
 {
@@ -274,27 +489,27 @@
 
         pVal = NULL;
         MP4GetMetadataName(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METANAME, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METANAME, pVal);
 
         pVal = NULL;
         MP4GetMetadataArtist(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METAARTIST, pVal);
 
         pVal = NULL;
         MP4GetMetadataWriter(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METAWRITER, pVal);
 
         pVal = NULL;
         MP4GetMetadataComment(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METACOMMENTS, pVal);
 
         pVal = NULL;
         MP4GetMetadataAlbum(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METAALBUM, pVal);
 
         pVal = NULL;
         MP4GetMetadataGenre(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METAGENRE, pVal);
 
         dummy = 0;
         MP4GetMetadataTempo(file, &dummy);
@@ -317,7 +532,7 @@
 
         pVal = NULL;
         MP4GetMetadataYear(file, &pVal);
-        SetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
+        uSetDlgItemText(hwndDlg,IDC_METAYEAR, pVal);
 
         dummy3 = 0;
         MP4GetMetadataCompilation(file, &dummy3);
@@ -346,25 +561,25 @@
                 return FALSE;
             }
 
-            GetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METANAME, dummy1, 1024);
             MP4SetMetadataName(file, dummy1);
 
-            GetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METAWRITER, dummy1, 1024);
             MP4SetMetadataWriter(file, dummy1);
 
-            GetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METAARTIST, dummy1, 1024);
             MP4SetMetadataArtist(file, dummy1);
 
-            GetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METAALBUM, dummy1, 1024);
             MP4SetMetadataAlbum(file, dummy1);
 
-            GetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METACOMMENTS, dummy1, 1024);
             MP4SetMetadataComment(file, dummy1);
 
-            GetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METAGENRE, dummy1, 1024);
             MP4SetMetadataGenre(file, dummy1);
 
-            GetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
+            uGetDlgItemText(hwndDlg, IDC_METAYEAR, dummy1, 1024);
             MP4SetMetadataYear(file, dummy1);
 
             GetDlgItemText(hwndDlg, IDC_METATRACK1, dummy1, 1024);
@@ -547,13 +762,15 @@
 
     return 0;
 }
+
 /* Get the title from the file */
 void ConstructTitle(MP4FileHandle file, char *filename, char *title, char *format)
 {
+    char temp[4096];
     int some_info = 0;
     char *in = format;
-    char *out = title;
-    char *bound = out + (MAX_PATH - 10 - 1);
+    char *out = temp;//title;
+    char *bound = out + sizeof(temp) - 256; //out + (MAX_PATH - 10 - 1);
     char *pVal, dummy1[1024];
     short dummy, dummy2;
 
@@ -578,7 +795,7 @@
             dummy = 0; dummy2 = 0;
             if (MP4GetMetadataTrack(file, &dummy, &dummy2))
             {
-                out += wsprintf("%d", (int)dummy);
+                out += wsprintf(out, "%d", (int)dummy);
                 some_info = 1;
             }
             break;
@@ -587,7 +804,7 @@
             pVal = NULL;
             if (MP4GetMetadataArtist(file, &pVal))
             {
-                out += wsprintf("%s", pVal);
+                out += wsprintf(out, "%s", pVal);
                 some_info = 1;
             }
             break;
@@ -596,7 +813,7 @@
             pVal = NULL;
             if (MP4GetMetadataName(file, &pVal))
             {
-                out += wsprintf("%s", pVal);
+                out += wsprintf(out, "%s", pVal);
                 some_info = 1;
             }
             break;
@@ -605,7 +822,7 @@
             pVal = NULL;
             if (MP4GetMetadataAlbum(file, &pVal))
             {
-                out += wsprintf("%s", pVal);
+                out += wsprintf(out, "%s", pVal);
                 some_info = 1;
             }
             break;
@@ -614,7 +831,7 @@
             pVal = NULL;
             if (MP4GetMetadataYear(file, &pVal))
             {
-                out += wsprintf("%s", pVal);
+                out += wsprintf(out, "%s", pVal);
                 some_info = 1;
             }
             break;
@@ -623,7 +840,7 @@
             pVal = NULL;
             if (MP4GetMetadataComment(file, &pVal))
             {
-                out += wsprintf("%s", pVal);
+                out += wsprintf(out, "%s", pVal);
                 some_info = 1;
             }
             break;
@@ -632,7 +849,7 @@
             pVal = NULL;
             if (MP4GetMetadataGenre(file, &pVal))
             {
-                out += wsprintf("%s", pVal);
+                out += wsprintf(out, "%s", pVal);
                 some_info = 1;
             }
             break;
@@ -639,13 +856,15 @@
 
         case '7':
             {
-                char *p=filename+lstrlen(filename);
-                int len = 0;
-                while (*p != '\\' && p >= filename) { p--; len++; }
-                lstrcpy(out, ++p); out += len;
+                const char *p=strrchr(filename,'\\');
+                if (!p) p=filename;
+                out += ConvertANSIToUTF8(p, out);
                 some_info = 1;
                 break;
             }
+
+        default:
+            break;
         }
     }
 
@@ -657,6 +876,13 @@
         while (*p != '\\' && p >= filename) p--;
         lstrcpy(title,++p);
     }
+    else
+    {
+        int len = ConvertUTF8ToANSI(temp, dummy1);
+        if (len > (MAX_PATH - 10 - 1)) len = (MAX_PATH - 10 - 1);
+        memcpy(title, dummy1, len);
+        title[len] = '\0';
+    }
 }
 
 BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message,
@@ -859,6 +1085,28 @@
     return 1;
 }
 
+int skip_id3v2_tag()
+{
+    unsigned char buf[10];
+    int bread, tagsize = 0;
+
+    bread = fread(buf, 1, 10, mp4state.aacfile);
+    if (bread != 10) return -1;
+
+    if (!memcmp(buf, "ID3", 3))
+    {
+        /* high bit is not used */
+        tagsize = (buf[6] << 21) | (buf[7] << 14) | (buf[8] << 7) | (buf[9] << 0);
+
+        tagsize += 10;
+        fseek(mp4state.aacfile, tagsize, SEEK_SET);
+    } else {
+        fseek(mp4state.aacfile, 0, SEEK_SET);
+    }
+
+    return tagsize;
+}
+
 int play(char *fn)
 {
     int maxlatency;
@@ -884,6 +1132,336 @@
         mp4state.filetype = 0;
     }
 
+    if (mp4state.filetype)
+    {
+        int tagsize = 0, tmp = 0, init;
+        int bread = 0;
+        double length = 0.;
+        __int64 bitrate = 128;
+        faacDecFrameInfo frameInfo;
+
+        module.is_seekable = 1;
+
+        if (!(mp4state.aacfile = fopen(mp4state.filename, "rb")))
+        {
+            // error
+            return -1;
+        }
+
+        tagsize = skip_id3v2_tag();
+        if (tagsize<0) return 0;
+
+        if (!(mp4state.m_aac_buffer = (unsigned char*)malloc(768*6)))
+        {
+            show_error(module.hMainWindow, "Memory allocation error.");
+            return -1;
+        }
+
+        for (init=0; init<2; init++)
+        {
+            mp4state.hDecoder = faacDecOpen();
+            if (!mp4state.hDecoder)
+            {
+                show_error(module.hMainWindow, "Unable to open decoder library.");
+                return -1;
+            }
+
+            config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
+            config->outputFormat = m_resolution + 1;
+            config->downMatrix = m_downmix;
+            faacDecSetConfiguration(mp4state.hDecoder, config);
+
+            memset(mp4state.m_aac_buffer, 0, 768*6);
+            bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
+            mp4state.m_aac_bytes_into_buffer = bread;
+            mp4state.m_aac_bytes_consumed = 0;
+            mp4state.m_file_offset = 0;
+            mp4state.m_at_eof = (bread != 768*6) ? 1 : 0;
+
+            if (init==0)
+            {
+                faacDecFrameInfo frameInfo;
+
+                fill_buffer(&mp4state);
+
+                if ((mp4state.m_aac_bytes_consumed = faacDecInit(mp4state.hDecoder,
+                    mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
+                    &mp4state.samplerate, &mp4state.channels)) < 0)
+                {
+                    show_error(module.hMainWindow, "Can't initialize decoder library.");
+                    return -1;
+                }
+                advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
+
+                do {
+                    memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
+                    fill_buffer(&mp4state);
+                    faacDecDecode(mp4state.hDecoder, &frameInfo, mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer);
+                } while (!frameInfo.samples && !frameInfo.error);
+
+                if (frameInfo.error)
+                {
+                    show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
+                    return -1;
+                }
+
+                mp4state.channels = frameInfo.channels;
+                mp4state.samplerate = frameInfo.samplerate;
+                mp4state.framesize = (frameInfo.channels != 0) ? frameInfo.samples/frameInfo.channels : 0;
+                /*
+                sbr = frameInfo.sbr;
+                profile = frameInfo.object_type;
+                header_type = frameInfo.header_type;
+                */
+
+                faacDecClose(mp4state.hDecoder);
+                fseek(mp4state.aacfile, tagsize, SEEK_SET);
+            }
+        }
+
+        mp4state.m_head = (struct seek_list*)malloc(sizeof(struct seek_list));
+        mp4state.m_tail = mp4state.m_head;
+        mp4state.m_tail->next = NULL;
+
+        mp4state.m_header_type = 0;
+        if ((mp4state.m_aac_buffer[0] == 0xFF) && ((mp4state.m_aac_buffer[1] & 0xF6) == 0xF0))
+        {
+            if (1) //(can_seek)
+            {
+                adts_parse(&mp4state, &bitrate, &length);
+                fseek(mp4state.aacfile, tagsize, SEEK_SET);
+
+                bread = fread(mp4state.m_aac_buffer, 1, 768*6, mp4state.aacfile);
+                if (bread != 768*6)
+                    mp4state.m_at_eof = 1;
+                else
+                    mp4state.m_at_eof = 0;
+                mp4state.m_aac_bytes_into_buffer = bread;
+                mp4state.m_aac_bytes_consumed = 0;
+
+                mp4state.m_header_type = 1;
+            }
+        } else if (memcmp(mp4state.m_aac_buffer, "ADIF", 4) == 0) {
+            int skip_size = (mp4state.m_aac_buffer[4] & 0x80) ? 9 : 0;
+            bitrate = ((unsigned int)(mp4state.m_aac_buffer[4 + skip_size] & 0x0F)<<19) |
+                ((unsigned int)mp4state.m_aac_buffer[5 + skip_size]<<11) |
+                ((unsigned int)mp4state.m_aac_buffer[6 + skip_size]<<3) |
+                ((unsigned int)mp4state.m_aac_buffer[7 + skip_size] & 0xE0);
+
+            length = (double)file_length(mp4state.aacfile);
+            if (length == -1)
+            {
+                module.is_seekable = 0;
+                length = 0;
+            } else {
+                length = ((double)length*8.)/((double)bitrate) + 0.5;
+            }
+
+            mp4state.m_header_type = 2;
+        } else {
+            length = (double)file_length(mp4state.aacfile);
+            length = ((double)length*8.)/((double)bitrate*1000.) + 0.5;
+
+            module.is_seekable = 1;
+        }
+
+        mp4state.m_length = (int)(length*1000.);
+
+        fill_buffer(&mp4state);
+        if ((mp4state.m_aac_bytes_consumed = faacDecInit(mp4state.hDecoder,
+            mp4state.m_aac_buffer, mp4state.m_aac_bytes_into_buffer,
+            &mp4state.samplerate, &mp4state.channels)) < 0)
+        {
+            show_error(module.hMainWindow, "Can't initialize decoder library.");
+            return -1;
+        }
+        advance_buffer(&mp4state, mp4state.m_aac_bytes_consumed);
+
+        if (mp4state.m_header_type == 2)
+            avg_bitrate = bitrate;
+        else
+            avg_bitrate = bitrate*1000;
+    } else {
+        mp4state.hDecoder = faacDecOpen();
+        if (!mp4state.hDecoder)
+        {
+            show_error(module.hMainWindow, "Unable to open decoder library.");
+            return -1;
+        }
+
+        config = faacDecGetCurrentConfiguration(mp4state.hDecoder);
+        config->outputFormat = m_resolution + 1;
+        config->downMatrix = m_downmix;
+        faacDecSetConfiguration(mp4state.hDecoder, config);
+
+        mp4state.mp4file = MP4Read(mp4state.filename, 0);
+        if (!mp4state.mp4file)
+        {
+            show_error(module.hMainWindow, "Unable to open file.");
+            faacDecClose(mp4state.hDecoder);
+            return -1;
+        }
+
+        if ((mp4state.mp4track = GetAACTrack(mp4state.mp4file)) < 0)
+        {
+            show_error(module.hMainWindow, "Unsupported Audio track type.");
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
+
+        buffer = NULL;
+        buffer_size = 0;
+        MP4GetTrackESConfiguration(mp4state.mp4file, mp4state.mp4track,
+            &buffer, &buffer_size);
+        if (!buffer)
+        {
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
+
+        if(faacDecInit2(mp4state.hDecoder, buffer, buffer_size,
+            &mp4state.samplerate, &mp4state.channels) < 0)
+        {
+            /* If some error initializing occured, skip the file */
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            if (buffer) free (buffer);
+            return -1;
+        }
+
+        /* for gapless decoding */
+        {
+            mp4AudioSpecificConfig mp4ASC;
+
+            mp4state.timescale = MP4GetTrackTimeScale(mp4state.mp4file, mp4state.mp4track);
+            mp4state.framesize = 1024;
+            mp4state.useAacLength = 0;
+
+            if (buffer)
+            {
+                if (AudioSpecificConfig(buffer, buffer_size, &mp4ASC) >= 0)
+                {
+                    if (mp4ASC.frameLengthFlag == 1) mp4state.framesize = 960;
+                    if (mp4ASC.sbr_present_flag == 1) mp4state.framesize *= 2;
+                }
+            }
+        }
+
+        free(buffer);
+
+        avg_bitrate = MP4GetTrackIntegerProperty(mp4state.mp4file, mp4state.mp4track,
+            "mdia.minf.stbl.stsd.mp4a.esds.decConfigDescr.avgBitrate");
+
+        mp4state.numSamples = MP4GetTrackNumberOfSamples(mp4state.mp4file, mp4state.mp4track);
+        mp4state.sampleId = 1;
+
+        module.is_seekable = 1;
+    }
+
+    if (mp4state.channels == 0)
+    {
+        show_error(module.hMainWindow, "Number of channels not supported for playback.");
+        faacDecClose(mp4state.hDecoder);
+        if (mp4state.filetype)
+            fclose(mp4state.aacfile);
+        else
+            MP4Close(mp4state.mp4file);
+        return -1;
+    }
+
+    if (m_downmix && (mp4state.channels == 5 || mp4state.channels == 6))
+        mp4state.channels = 2;
+
+    maxlatency = module.outMod->Open(mp4state.samplerate, (int)mp4state.channels,
+        res_table[m_resolution], -1, -1);
+
+    if (maxlatency < 0) // error opening device
+    {
+        faacDecClose(mp4state.hDecoder);
+        if (mp4state.filetype)
+            fclose(mp4state.aacfile);
+        else
+            MP4Close(mp4state.mp4file);
+        return -1;
+    }
+
+    mp4state.paused        =  0;
+    mp4state.decode_pos_ms =  0;
+    mp4state.seek_needed   = -1;
+
+    // initialize vis stuff
+    module.SAVSAInit(maxlatency, mp4state.samplerate);
+    module.VSASetInfo((int)mp4state.channels, mp4state.samplerate);
+
+    br = (int)floor(((float)avg_bitrate + 500.0)/1000.0 + 0.5);
+    sr = (int)floor((float)mp4state.samplerate/1000.0 + 0.5);
+    module.SetInfo(br, sr, (int)mp4state.channels, 1);
+
+    module.outMod->SetVolume(-666); // set the output plug-ins default volume
+
+    killPlayThread = 0;
+
+    if (mp4state.filetype)
+    {
+        if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)AACPlayThread,
+            (void *)&killPlayThread, 0, &thread_id)) == NULL)
+        {
+            show_error(module.hMainWindow, "Cannot create playback thread");
+            faacDecClose(mp4state.hDecoder);
+            fclose(mp4state.aacfile);
+            return -1;
+        }
+    } else {
+        if ((play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MP4PlayThread,
+            (void *)&killPlayThread, 0, &thread_id)) == NULL)
+        {
+            show_error(module.hMainWindow, "Cannot create playback thread");
+            faacDecClose(mp4state.hDecoder);
+            MP4Close(mp4state.mp4file);
+            return -1;
+        }
+    }
+
+    SetThreadAffinityMask(play_thread_handle, 1);
+
+    SetThreadPriority(play_thread_handle, priority_table[m_priority]);
+
+    return 0;
+}
+
+
+
+
+
+
+#if 0
+int play(char *fn)
+{
+    int maxlatency;
+    int thread_id;
+    int avg_bitrate, br, sr;
+    unsigned char *buffer;
+    int buffer_size;
+    faacDecConfigurationPtr config;
+
+#ifdef DEBUG_OUTPUT
+    in_mp4_DebugOutput("play");
+#endif
+
+    memset(&mp4state, 0, sizeof(state));
+
+    lstrcpy(mp4state.filename, fn);
+
+    if (!(mp4state.mp4file = MP4Read(mp4state.filename, 0)))
+    {
+        mp4state.filetype = 1;
+    } else {
+        MP4Close(mp4state.mp4file);
+        mp4state.filetype = 0;
+    }
+
     mp4state.hDecoder = faacDecOpen();
     if (!mp4state.hDecoder)
     {
@@ -1142,7 +1720,15 @@
 
     return 0;
 }
+#endif
 
+
+
+
+
+
+
+
 void pause()
 {
 #ifdef DEBUG_OUTPUT
@@ -1538,14 +2124,15 @@
                 } else {
                     sample_count = (unsigned int)(dur * frameInfo.channels);
 
-                    if (!mp4state.useAacLength && !mp4state.initial && (mp4state.sampleId < mp4state.numSamples/2) && (sample_count != frameInfo.samples))
+                    if (!mp4state.useAacLength && !mp4state.initial && (mp4state.sampleId < mp4state.numSamples/2) && (dur*frameInfo.channels != frameInfo.samples))
                     {
                         //fprintf(stderr, "MP4 seems to have incorrect frame duration, using values from AAC data.\n");
                         mp4state.useAacLength = 1;
+                        sample_count = frameInfo.samples;
                     }
                 }
 
-                if (mp4state.initial && (sample_count < mp4state.framesize*frameInfo.channels))
+                if (mp4state.initial && (sample_count < mp4state.framesize*mp4state.channels) && (frameInfo.samples > sample_count))
                 {
                     delay = frameInfo.samples - sample_count;
                 }
@@ -1673,7 +2260,7 @@
 
     if (1 /*can_seek*/ && ((st->m_header_type == 1) || (seconds < st->cur_pos_sec)))
     {
-        frames = (int)(seconds*((double)st->samplerate/1024.0) + 0.5);
+        frames = (int)(seconds*((double)st->samplerate/(double)st->framesize) + 0.5);
 
         for (i = 0; i < frames; i++)
         {
@@ -1680,10 +2267,10 @@
             if (target->next)
                 target = target->next;
             else
-                return 1;
+                return 0;
         }
         if (target->offset == 0 && frames > 0)
-            return 1;
+            return 0;
         fseek(st->aacfile, target->offset, SEEK_SET);
 
         bread = fread(st->m_aac_buffer, 1, 768*6, st->aacfile);
@@ -1699,17 +2286,17 @@
         if (seconds > st->cur_pos_sec)
         {
             faacDecFrameInfo frameInfo;
-            memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
 
-            frames = (int)((seconds - st->cur_pos_sec)*((double)st->samplerate/1024.0) + 0.5);
+            frames = (int)((seconds - st->cur_pos_sec)*((double)st->samplerate/(double)st->framesize));
 
             if (frames > 0)
             {
                 for (i = 0; i < frames; i++)
                 {
+                    memset(&frameInfo, 0, sizeof(faacDecFrameInfo));
                     decode_aac_frame(st, &frameInfo);
 
-                    if (frameInfo.error || (mp4state.m_aac_bytes_into_buffer == 0))
+                    if (frameInfo.error || (st->m_aac_bytes_into_buffer == 0))
                     {
                         if (frameInfo.error)
                         {
@@ -1716,7 +2303,7 @@
                             if (faacDecGetErrorMessage(frameInfo.error) != NULL)
                                 show_error(module.hMainWindow, faacDecGetErrorMessage(frameInfo.error));
                         }
-                        return 1;
+                        return 0;
                     }
                 }
             }
@@ -1750,10 +2337,12 @@
             double ms;
 
             ms = mp4state.seek_needed/1000;
-            module.outMod->Flush(mp4state.decode_pos_ms);
-            aac_seek(&mp4state, ms);
-            mp4state.cur_pos_sec = ms;
-            mp4state.decode_pos_ms = mp4state.seek_needed;
+            if (aac_seek(&mp4state, ms)!=0)
+            {
+                module.outMod->Flush(mp4state.decode_pos_ms);
+                mp4state.cur_pos_sec = ms;
+                mp4state.decode_pos_ms = mp4state.seek_needed;
+            }
             mp4state.seek_needed = -1;
         }
 
@@ -1841,9 +2430,8 @@
                 }
             }
 
-            mp4state.samplerate = frameInfo.samplerate;
-
-            mp4state.cur_pos_sec += ((double)(frameInfo.samples/frameInfo.channels)*1024.0)/(double)mp4state.samplerate;
+            if (frameInfo.channels > 0 && mp4state.samplerate > 0)
+                mp4state.cur_pos_sec += ((double)(frameInfo.samples/frameInfo.channels))/(double)mp4state.samplerate;
         } else {
             Sleep(10);
         }
--- a/plugins/in_mp4/in_mp4.dsp
+++ b/plugins/in_mp4/in_mp4.dsp
@@ -43,7 +43,7 @@
 # PROP Ignore_Export_Lib 0
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
-# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /I "..\..\common\mp4v2" /I "..\..\common\mp4av" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O1 /I "..\..\include" /I "..\..\common\mp4v2" /I "..\..\common\mp4av" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /FD /c
 # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
 # ADD BASE RSC /l 0x413 /d "NDEBUG"