Logo Search packages:      
Sourcecode: faad2 version File versions

QCDFAAD.c

/*
** FAAD - Freeware Advanced Audio Decoder
** Copyright (C) 2002 M. Bakker
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
** $Id: QCDFAAD.c,v 1.2 2003/04/28 19:04:35 menno Exp $
** based on menno's in_faad.dll plugin for Winamp
**
** The tag function has been removed because QCD supports ID3v1 & ID3v2 very well
** About how to tagging: Please read the "ReadMe.txt" first
**/

#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <mmreg.h>
#include <commctrl.h>
#include <shellapi.h>
#include <stdlib.h>
#include <stdio.h>
#include "QCDInputDLL.h"

#include "resource.h"

#include <faad.h>
#include <aacinfo.h>
#include <filestream.h>
//#include <id3v2tag.h>

static char app_name[] = "QCDFAAD";

faadAACInfo file_info;

faacDecHandle hDecoder;
faacDecFrameInfo frameInfo;

HINSTANCE         hInstance;
HWND              hwndPlayer, hwndConfig, hwndAbout;
QCDModInitIn      sQCDCallbacks, *QCDCallbacks;
BOOL              oldAPIs = 0;
static char lastfn[MAX_PATH]; // currently playing file (used for getting info on the current file)
int file_length; // file length, in bytes
int paused; // are we paused?
int seek_needed; // if != -1, it is the point that the decode thread should seek to, in ms.

char *sample_buffer; // sample buffer
unsigned char *buffer; // input buffer
unsigned char *memmap_buffer; // input buffer for whole file
long memmap_index;

long buffercount, fileread, bytecount;

// seek table for ADTS header files
unsigned long *seek_table = NULL;
int seek_table_length=0;

int killPlayThread = 0; // the kill switch for the decode thread
HANDLE play_thread_handle = INVALID_HANDLE_VALUE; // the handle to the decode thread
FILE_STREAM *infile;

/* Function definitions */
int id3v2_tag(unsigned char *buffer);
DWORD WINAPI PlayThread(void *b); // the decode thread procedure

// general funcz
static void show_error(const char *message,...)
{
      char foo[512];
      va_list args;
      va_start(args, message);
      vsprintf(foo, message, args);
      va_end(args);
      MessageBox(hwndPlayer, foo, "FAAD Plug-in Error", MB_ICONSTOP);
}


// 1= use vbr display, 0 = use average bitrate. This value only controls what shows up in the
// configuration form. Also- Streaming uses an on-the-fly bitrate display regardless of this value.
long m_variable_bitrate_display=0;
long m_priority = 5;
long m_memmap_file = 0;
static char INI_FILE[MAX_PATH];

char *priority_text[] = {     "",
                                          "Decode Thread Priority: Lowest",
                                          "Decode Thread Priority: Lower",
                                          "Decode Thread Priority: Normal",
                                          "Decode Thread Priority: Higher",
                                          "Decode Thread Priority: Highest (default)"
                                    };

long priority_table[] = {0, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST};

long current_file_mode = 0;

int PlayThread_memmap();
int PlayThread_file();

static void _r_s(char *name,char *data, int mlen)
{
      char buf[10];
      strcpy(buf,data);
      GetPrivateProfileString(app_name,name,buf,data,mlen,INI_FILE);
}

#define RS(x) (_r_s(#x,x,sizeof(x)))
#define WS(x) (WritePrivateProfileString(app_name,#x,x,INI_FILE))

void config_read()
{
    char variable_bitrate_display[10];
    char priority[10];
    char memmap_file[10];
    char local_buffer_size[10];
    char stream_buffer_size[10];

    strcpy(variable_bitrate_display, "1");
    strcpy(priority, "5");
    strcpy(memmap_file, "0");
    strcpy(local_buffer_size, "128");
    strcpy(stream_buffer_size, "64");

    RS(variable_bitrate_display);
    RS(priority);
    RS(memmap_file);
    RS(local_buffer_size);
    RS(stream_buffer_size);

    m_priority = atoi(priority);
    m_variable_bitrate_display = atoi(variable_bitrate_display);
    m_memmap_file = atoi(memmap_file);
    m_local_buffer_size = atoi(local_buffer_size);
    m_stream_buffer_size = atoi(stream_buffer_size);
}

void config_write()
{
    char variable_bitrate_display[10];
    char priority[10];
    char memmap_file[10];
    char local_buffer_size[10];
    char stream_buffer_size[10];

    itoa(m_priority, priority, 10);
    itoa(m_variable_bitrate_display, variable_bitrate_display, 10);
    itoa(m_memmap_file, memmap_file, 10);
    itoa(m_local_buffer_size, local_buffer_size, 10);
    itoa(m_stream_buffer_size, stream_buffer_size, 10);

    WS(variable_bitrate_display);
    WS(priority);
    WS(memmap_file);
    WS(local_buffer_size);
    WS(stream_buffer_size);
}

//-----------------------------------------------------------------------------

BOOL WINAPI DllMain(HINSTANCE hInst, DWORD fdwReason, LPVOID pRes)
{
      if (fdwReason == DLL_PROCESS_ATTACH)
            hInstance = hInst;
      return TRUE;
}

//-----------------------------------------------------------------------------
//old entrypoint api
PLUGIN_API BOOL QInputModule(QCDModInitIn *ModInit, QCDModInfo *ModInfo)
{
      ModInit->version                          = PLUGIN_API_VERSION;
      ModInit->toModule.ShutDown                = ShutDown;
      ModInit->toModule.GetTrackExtents   = GetTrackExtents;
      ModInit->toModule.GetMediaSupported = GetMediaSupported;
      ModInit->toModule.GetCurrentPosition= GetCurrentPosition;
      ModInit->toModule.Play                    = Play;
      ModInit->toModule.Pause                   = Pause;
      ModInit->toModule.Stop                    = Stop;
      ModInit->toModule.SetVolume               = SetVolume;
      ModInit->toModule.About                   = About;
      ModInit->toModule.Configure               = Configure;
      QCDCallbacks = ModInit;

      ModInfo->moduleString = "FAAD Plugin v1.0b";
      /* read config */
      QCDCallbacks->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);

      config_read();
      ModInfo->moduleExtensions = "AAC";

      hwndPlayer = (HWND)ModInit->Service(opGetParentWnd, 0, 0, 0);
      lastfn[0] = 0;
      play_thread_handle = INVALID_HANDLE_VALUE;

      oldAPIs = 1;

      return TRUE;
}

//-----------------------------------------------------------------------------

PLUGIN_API QCDModInitIn* INPUTDLL_ENTRY_POINT()
{
      sQCDCallbacks.version                                 = PLUGIN_API_VERSION;
      sQCDCallbacks.toModule.Initialize               = Initialize;
      sQCDCallbacks.toModule.ShutDown                       = ShutDown;
      sQCDCallbacks.toModule.GetTrackExtents          = GetTrackExtents;
      sQCDCallbacks.toModule.GetMediaSupported  = GetMediaSupported;
      sQCDCallbacks.toModule.GetCurrentPosition = GetCurrentPosition;
      sQCDCallbacks.toModule.Play                           = Play;
      sQCDCallbacks.toModule.Pause                    = Pause;
      sQCDCallbacks.toModule.Stop                           = Stop;
      sQCDCallbacks.toModule.SetVolume                = SetVolume;
      sQCDCallbacks.toModule.About                    = About;
      sQCDCallbacks.toModule.Configure                = Configure;

      QCDCallbacks = &sQCDCallbacks;
      return &sQCDCallbacks;
}

//----------------------------------------------------------------------------

BOOL CALLBACK config_dialog_proc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
      char tmp[10];

    switch (message)
      {
    case WM_INITDIALOG:
        /* Set priority slider range and previous position */
            SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_SETRANGE, TRUE, MAKELONG(1, 5)); 
            SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_SETPOS, TRUE, m_priority);
            SetDlgItemText(hwndDlg, IDC_STATIC2, priority_text[m_priority]);
            
            /* Put a limit to the amount of characters allowed in the buffer boxes */
            SendMessage(GetDlgItem(hwndDlg, LOCAL_BUFFER_TXT), EM_LIMITTEXT, 4, 0);
            SendMessage(GetDlgItem(hwndDlg, STREAM_BUFFER_TXT), EM_LIMITTEXT, 4, 0);

          if(m_variable_bitrate_display)
                  SendMessage(GetDlgItem(hwndDlg, VARBITRATE_CHK), BM_SETCHECK, BST_CHECKED, 0);
          if(m_memmap_file)
                  SendMessage(GetDlgItem(hwndDlg, IDC_MEMMAP), BM_SETCHECK, BST_CHECKED, 0);

            itoa(m_local_buffer_size, tmp, 10);
            SetDlgItemText(hwndDlg, LOCAL_BUFFER_TXT, tmp);

            itoa(m_stream_buffer_size, tmp, 10);
            SetDlgItemText(hwndDlg, STREAM_BUFFER_TXT, tmp);

            return TRUE;

      case WM_HSCROLL:

            /* Thread priority slider moved */
            if(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER) == (HWND) lParam)
            {
                  int tmp;
                  tmp = SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_GETPOS, 0, 0);

                  if(tmp > 0)
                  {
                        m_priority = tmp;

                SetDlgItemText(hwndDlg, IDC_STATIC2, priority_text[m_priority]);

                        if(play_thread_handle)
                              SetThreadPriority(play_thread_handle, priority_table[m_priority]);
                  }
            }

            return TRUE;

    case WM_COMMAND:

            if(HIWORD(wParam) == BN_CLICKED)
            {
                  if(GetDlgItem(hwndDlg, VARBITRATE_CHK) == (HWND) lParam)
                  {
                        /* Variable Bitrate checkbox hit */
                        m_variable_bitrate_display = SendMessage(GetDlgItem(hwndDlg, VARBITRATE_CHK), BM_GETCHECK, 0, 0); 
                  }
                  if(GetDlgItem(hwndDlg, IDC_MEMMAP) == (HWND) lParam)
                  {
                        /* Variable Bitrate checkbox hit */
                        m_memmap_file = SendMessage(GetDlgItem(hwndDlg, IDC_MEMMAP), BM_GETCHECK, 0, 0); 
                  }
            }

        switch (LOWORD(wParam))
            {
                  case OK_BTN:
                        /* User hit OK, save buffer settings (all others are set on command) */
                        GetDlgItemText(hwndDlg, LOCAL_BUFFER_TXT, tmp, 5);
                        m_local_buffer_size = atol(tmp);

                        GetDlgItemText(hwndDlg, STREAM_BUFFER_TXT, tmp, 5);
                        m_stream_buffer_size = atol(tmp);

                config_write();

                        EndDialog(hwndDlg, wParam);
                        return TRUE;
                  case RESET_BTN:
                        SendMessage(GetDlgItem(hwndDlg, VARBITRATE_CHK), BM_SETCHECK, BST_CHECKED, 0);
                        m_variable_bitrate_display = 1;
                        SendMessage(GetDlgItem(hwndDlg, IDC_MEMMAP), BM_SETCHECK, BST_UNCHECKED, 0);
                        m_memmap_file = 0;
                        SendMessage(GetDlgItem(hwndDlg, THREAD_PRIORITY_SLIDER), TBM_SETPOS, TRUE, 5);
                        m_priority = 5;
                        SetDlgItemText(hwndDlg, IDC_STATIC2, priority_text[5]);
                        SetDlgItemText(hwndDlg, LOCAL_BUFFER_TXT, "128");
                        m_local_buffer_size = 128;
                        SetDlgItemText(hwndDlg, STREAM_BUFFER_TXT, "64");
                        m_stream_buffer_size = 64;
                        return TRUE;
                  case IDCANCEL:
                  case CANCEL_BTN:
                        /* User hit Cancel or the X, just close without saving buffer settings */
                        DestroyWindow(hwndDlg);
                        return TRUE;
        }
    }
    return FALSE;
}


void Configure(int flags)
{
      if(!IsWindow(hwndConfig))
            hwndConfig = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_CONFIG), hwndPlayer, config_dialog_proc);
      ShowWindow(hwndConfig, SW_NORMAL);
}

//-----------------------------------------------------------------------------
// proc of "About Dialog"
INT_PTR CALLBACK about_dialog_proc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
      static RECT rcLOGO, rcMail1, rcMail2/*, rcMail3*/;
      POINT ptMouse;
      static char szPluginVer[] = "QCD FAAD Input Plug-in v1.0b\nCompiled on " __TIME__ ", " __DATE__;
      static char szFLACVer[] = "Using: FAAD2 v "FAAD2_VERSION" by";

      switch (uMsg)
      {
      case WM_INITDIALOG:
      case WM_MOVE:
            GetWindowRect(GetDlgItem(hwndDlg, IDC_LOGO), &rcLOGO);
            GetWindowRect(GetDlgItem(hwndDlg, IDC_MAIL1), &rcMail1);
            GetWindowRect(GetDlgItem(hwndDlg, IDC_MAIL2), &rcMail2);
//          GetWindowRect(GetDlgItem(hwndDlg, IDC_MAIL2), &rcMail3);

            SetDlgItemText(hwndDlg, IDC_PLUGINVER, szPluginVer);
            SetDlgItemText(hwndDlg, IDC_FAADVER, szFLACVer);
            
            return TRUE;
      case WM_MOUSEMOVE:
            ptMouse.x = LOWORD(lParam);
            ptMouse.y = HIWORD(lParam);
            ClientToScreen(hwndDlg, &ptMouse);
            if( (ptMouse.x >= rcLOGO.left && ptMouse.x <= rcLOGO.right && 
                  ptMouse.y >= rcLOGO.top && ptMouse.y<= rcLOGO.bottom) 
                  ||
                  (ptMouse.x >= rcMail1.left && ptMouse.x <= rcMail1.right && 
                  ptMouse.y >= rcMail1.top && ptMouse.y<= rcMail1.bottom) 
                  ||
                  (ptMouse.x >= rcMail2.left && ptMouse.x <= rcMail2.right && 
                  ptMouse.y >= rcMail2.top && ptMouse.y<= rcMail2.bottom) 
/*                ||
                  (ptMouse.x >= rcMail3.left && ptMouse.x <= rcMail3.right && 
                  ptMouse.y >= rcMail3.top && ptMouse.y<= rcMail3.bottom)*/ )
                  SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(32649)));
            else
                  SetCursor(LoadCursor(NULL, IDC_ARROW));

            return TRUE;
      case WM_LBUTTONDOWN:
            ptMouse.x = LOWORD(lParam);
            ptMouse.y = HIWORD(lParam);
            ClientToScreen(hwndDlg, &ptMouse);
            if(ptMouse.x >= rcLOGO.left && ptMouse.x <= rcLOGO.right && 
                  ptMouse.y >= rcLOGO.top && ptMouse.y<= rcLOGO.bottom)
                  ShellExecute(0, NULL, "http://www.audiocoding.com", NULL,NULL, SW_NORMAL);
            else if(ptMouse.x >= rcMail1.left && ptMouse.x <= rcMail1.right && 
                  ptMouse.y >= rcMail1.top && ptMouse.y<= rcMail1.bottom)
                  ShellExecute(0, NULL, "mailto:shaohao@elong.com", NULL,NULL, SW_NORMAL);
            else if(ptMouse.x >= rcMail2.left && ptMouse.x <= rcMail2.right && 
                  ptMouse.y >= rcMail2.top && ptMouse.y<= rcMail2.bottom)
                  ShellExecute(0, NULL, "mailto:menno@audiocoding.com", NULL,NULL, SW_NORMAL);
/*          else if(ptMouse.x >= rcMail3.left && ptMouse.x <= rcMail3.right && 
                  ptMouse.y >= rcMail3.top && ptMouse.y<= rcMail3.bottom)
                  ShellExecute(0, NULL, "I don't know", NULL,NULL, SW_NORMAL);
*/
            return TRUE;
      case WM_COMMAND:
            switch(LOWORD(wParam))
            {
            case IDOK:
            default:
                  DestroyWindow(hwndDlg);
                  return TRUE;
            }
      }
      return FALSE;
}

void About(int flags)
{
      if(!IsWindow(hwndAbout))
            hwndAbout = CreateDialog(hInstance, MAKEINTRESOURCE(IDD_ABOUT), hwndPlayer, about_dialog_proc); 
      ShowWindow(hwndAbout, SW_SHOW);
}

//-----------------------------------------------------------------------------

BOOL Initialize(QCDModInfo *ModInfo, int flags)
{
      hwndPlayer = (HWND)QCDCallbacks->Service(opGetParentWnd, 0, 0, 0);

      lastfn[0] = 0;
      seek_needed = -1;
      paused = 0;
      play_thread_handle = INVALID_HANDLE_VALUE;

      /* read config */
      QCDCallbacks->Service(opGetPluginSettingsFile, INI_FILE, MAX_PATH, 0);
    config_read();

      ModInfo->moduleString = "FAAD Plugin v1.0b";
      ModInfo->moduleExtensions = "AAC";

    /* Initialize winsock, necessary for streaming */
    WinsockInit();

      // insert menu item into plugin menu
//    QCDCallbacks->Service(opSetPluginMenuItem, hInstance, IDD_CONFIG, (long)"FAAD Plug-in");

      return TRUE;
}

//----------------------------------------------------------------------------

void ShutDown(int flags)
{
      Stop(lastfn, STOPFLAG_FORCESTOP);

    if(buffer)
            LocalFree(buffer);

    /* Deallocate winsock */
    WinsockDeInit();

      // delete the inserted plugin menu
//    QCDCallbacks->Service(opSetPluginMenuItem, hInstance, 0, 0);
}

//-----------------------------------------------------------------------------

BOOL GetMediaSupported(LPCSTR medianame, MediaInfo *mediaInfo)
{
      FILE_STREAM *in;
      faadAACInfo tmp;
      char *ch = strrchr(medianame, '.');

      if (!medianame || !*medianame)
            return FALSE;

      if(!ch)
            return (lstrlen(medianame) > 2); // no extension defaults to me (if not drive letter)

   /* Finally fixed */
    if(StringComp(ch, ".aac", 4) == 0)
    {
            in = open_filestream((char *)medianame);
            
            if(in != NULL && mediaInfo)
            {
                  if(in->http)
                  {
                        /* No seeking in http streams */
                        mediaInfo->mediaType = DIGITAL_STREAM_MEDIA;
                        mediaInfo->op_canSeek = FALSE;
                  }
                  else
                  {
                        mediaInfo->mediaType = DIGITAL_FILE_MEDIA;
                      get_AAC_format((char *)medianame, &tmp, NULL, NULL, 1);
                        if(tmp.headertype == 2) /* ADTS header - seekable */
                              mediaInfo->op_canSeek = TRUE;
                        else
                              mediaInfo->op_canSeek = FALSE; /* ADIF or Headerless - not seekable */
                  }
                  
                  close_filestream(in);
                  return TRUE;
            }
            else
            {
                  close_filestream(in);
                  return FALSE;
            }
      }
      else
            return FALSE;           
}

unsigned long samplerate, channels;

int play_memmap(char *fn)
{
    int tagsize = 0;

    infile = open_filestream(fn);
    
      if (infile == NULL)
        return 1;

    fileread = filelength_filestream(infile);

    memmap_buffer = (char*)LocalAlloc(LPTR, fileread);
    read_buffer_filestream(infile, memmap_buffer, fileread);

    /* skip id3v2 tag */
    memmap_index = id3v2_tag(memmap_buffer);

    hDecoder = faacDecOpen();

      /* Copy the configuration dialog setting and use it as the default */
      /* initialize the decoder, and get samplerate and channel info */

    if( (buffercount = faacDecInit(hDecoder, memmap_buffer + memmap_index,
        fileread - memmap_index - 1, &samplerate, &channels)) < 0 )
    {
            show_error("Error opening input file");
            return 1;
    }

    memmap_index += buffercount;

    PlayThread_memmap();

    return 0;
}

int play_file(char *fn)
{
    int k;
    int tagsize;

    ZeroMemory(buffer, 768*2);

     infile = open_filestream(fn);
    
      if (infile == NULL)
        return 1;

      fileread = filelength_filestream(infile);

    buffercount = bytecount = 0;
    read_buffer_filestream(infile, buffer, 768*2);

    tagsize = id3v2_tag(buffer);

      /* If we find a tag, run right over it */
    if(tagsize)
      {
        if(infile->http)
        {
            int i;
            /* Crude way of doing this, but I believe its fast enough to not make a big difference */
            close_filestream(infile);
            infile = open_filestream(fn);

            for(i=0; i < tagsize; i++)
                read_byte_filestream(infile);
        }
        else
            seek_filestream(infile, tagsize, FILE_BEGIN);

        bytecount = tagsize;
        buffercount = 0;
        read_buffer_filestream(infile, buffer, 768*2);
    }

    hDecoder = faacDecOpen();

      /* Copy the configuration dialog setting and use it as the default */
      /* initialize the decoder, and get samplerate and channel info */

    if((buffercount = faacDecInit(hDecoder, buffer, 768*2, &samplerate, &channels)) < 0)
    {
            show_error("Error opening input file");
            return 1;
    }

    if(buffercount > 0)
      {
            bytecount += buffercount;

            for (k = 0; k < (768*2 - buffercount); k++)
                  buffer[k] = buffer[k + buffercount];

            read_buffer_filestream(infile, buffer + (768*2) - buffercount, buffercount);
            buffercount = 0;
      }

    PlayThread_file();

    return 0;
}


//-----------------------------------------------------------------------------

BOOL Play(LPCSTR medianame, int playfrom, int playto, int flags)
{
      if(stricmp(lastfn, medianame) != 0)
      {
            sQCDCallbacks.toPlayer.OutputStop(STOPFLAG_PLAYDONE);
            Stop(lastfn, STOPFLAG_PLAYDONE);
      }

      if(paused)
      {
            // Update the player controls to reflect the new unpaused state
            sQCDCallbacks.toPlayer.OutputPause(0);

            Pause(medianame, PAUSE_DISABLED);

            if (playfrom >= 0)
                  seek_needed = playfrom;
      }
      else if(play_thread_handle != INVALID_HANDLE_VALUE)
      {
            seek_needed = playfrom;
            return TRUE;
      }
      else
      {
            int thread_id;

            // alloc the input buffer
            buffer = (unsigned char*)LocalAlloc(LPTR, 768*2);

            current_file_mode = m_memmap_file;
            
            if(current_file_mode)
            {
                  if(play_memmap((char *)medianame))
                        return FALSE;
            }
            else
            {
                  if(play_file((char *)medianame))
                        return FALSE;
            }
            
            if(seek_table)
            {
                  free(seek_table);
                  seek_table = NULL;
                  seek_table_length = 0;
            }
            
            get_AAC_format((char *)medianame, &file_info, &seek_table, &seek_table_length, 0);
            
            seek_needed = playfrom > 0 ? playfrom : -1;
            killPlayThread = 0;
            strcpy(lastfn,medianame);

            /*
            To RageAmp: This is really needed, because aacinfo isn't very accurate on ADIF files yet.
            Can be fixed though :-)
            */
            file_info.sampling_rate = samplerate;
            file_info.channels = frameInfo.channels;

            play_thread_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) PlayThread, (void *) &killPlayThread, 0, &thread_id);
            if(!play_thread_handle)
                  return FALSE;
            
            // Note: This line seriously slows down start up time
            if(m_priority != 3) // if the priority in config window is set to normal, there is nothing to reset!
                  SetThreadPriority(play_thread_handle, priority_table[m_priority]);
            
    }

      return TRUE;
}

//-----------------------------------------------------------------------------

BOOL Pause(LPCSTR medianame, int flags)
{
      if(QCDCallbacks->toPlayer.OutputPause(flags))
      {
            // send back pause/unpause notification
            QCDCallbacks->toPlayer.PlayPaused(medianame, flags);
            paused = flags;
            return TRUE;
      }
      return FALSE;
}

//-----------------------------------------------------------------------------

BOOL Stop(LPCSTR medianame, int flags)
{
      if(medianame && *medianame && stricmp(lastfn, medianame) == 0)
      {
            sQCDCallbacks.toPlayer.OutputStop(flags);
            
            killPlayThread = 1;
            if(play_thread_handle != INVALID_HANDLE_VALUE)
            {
                  if(WaitForSingleObject(play_thread_handle, INFINITE) == WAIT_TIMEOUT)
                  {
//                      MessageBox(hwndPlayer, "FAAD thread kill timeout", "debug", 0);
                        TerminateThread(play_thread_handle,0);
                  }
                  CloseHandle(play_thread_handle);
                  play_thread_handle = INVALID_HANDLE_VALUE;
            }

            if (oldAPIs)
                  QCDCallbacks->toPlayer.PlayStopped(lastfn);
            
            lastfn[0] = 0;
      }

      return TRUE;
}

int aac_seek(int pos_ms, int *sktable)
{
    double offset_sec;

    offset_sec = pos_ms / 1000.0;
    if(!current_file_mode)
    {
        seek_filestream(infile, sktable[(int)(offset_sec+0.5)], FILE_BEGIN);

        bytecount = sktable[(int)(offset_sec+0.5)];
        buffercount = 0;
        read_buffer_filestream(infile, buffer, 768*2);
    }
      else
      {
        memmap_index = sktable[(int)(offset_sec+0.5)];
    }

    return 0;
}

//-----------------------------------------------------------------------------

void SetVolume(int levelleft, int levelright, int flags)
{
      QCDCallbacks->toPlayer.OutputSetVol(levelleft, levelright, flags);
}

//-----------------------------------------------------------------------------

BOOL GetCurrentPosition(LPCSTR medianame, long *track, long *offset)
{
      return QCDCallbacks->toPlayer.OutputGetCurrentPosition((UINT*)offset, 0);
}

//-----------------------------------------------------------------------------

BOOL GetTrackExtents(LPCSTR medianame, TrackExtents *ext, int flags)
{
    faadAACInfo tmp;

    if(get_AAC_format((char*)medianame, &tmp, NULL, NULL, 1))
            return FALSE;

      ext->track = 1;
      ext->start = 0;
      ext->end = tmp.length;
      ext->bytesize = tmp.bitrate * tmp.length;
      ext->unitpersec = 1000;

      return TRUE;
}

//--------------------------for play thread-------------------------------------

int last_frame;

DWORD WINAPI PlayThread(void *b)
{
    BOOL done = FALSE, updatePos = FALSE;
      int decode_pos_ms = 0; // current decoding position, in milliseconds
    int l;
      int decoded_frames=0;
      int br_calc_frames=0;
      int br_bytes_consumed=0;
    unsigned long bytesconsumed;

    last_frame = 0;

      if(!done)
      {
            // open outputdevice
            WAVEFORMATEX wf;
            wf.wFormatTag = WAVE_FORMAT_PCM;
            wf.cbSize = 0;
            wf.nChannels = file_info.channels;
            wf.wBitsPerSample = 16;
            wf.nSamplesPerSec = file_info.sampling_rate;
            wf.nBlockAlign = wf.nChannels * wf.wBitsPerSample / 8;
            wf.nAvgBytesPerSec = wf.nSamplesPerSec * wf.nBlockAlign;
            if (!QCDCallbacks->toPlayer.OutputOpen(lastfn, &wf))
            {
                  show_error("Error: Failed openning output plugin!");
                  done = TRUE; // cannot open sound device
            }
      }

    while (! *((int *)b) )
    {
            /********************** SEEK ************************/
       if (!done && seek_needed >= 0)
         {
            int seconds;

            // Round off to a second
            seconds = seek_needed - (seek_needed%1000);
                  QCDCallbacks->toPlayer.OutputFlush(decode_pos_ms);
            aac_seek(seconds, seek_table);
            decode_pos_ms = seconds;
                  decoded_frames = 0;
                  br_calc_frames = 0;
                  br_bytes_consumed = 0;

                  seek_needed = -1;
                  updatePos = 1;
         }

            /********************* QUIT *************************/
            if (done)
            {
                  if (QCDCallbacks->toPlayer.OutputDrain(0) && !(seek_needed >= 0))
                  {
                        play_thread_handle = INVALID_HANDLE_VALUE;
                        QCDCallbacks->toPlayer.OutputStop(STOPFLAG_PLAYDONE);
                        QCDCallbacks->toPlayer.PlayDone(lastfn);
                  }
                  else if (seek_needed >= 0)
                  {
                        done = FALSE;
                        continue;
                  }
                  break;
            }

        /******************* DECODE TO BUFFER ****************/
            else
        {
                  if (current_file_mode)
                        bytesconsumed = PlayThread_memmap();
                  else
                        bytesconsumed = PlayThread_file();

                  if(last_frame)
                        done = TRUE;
                  else
                  {

                        decoded_frames++;
                        br_calc_frames++;
                        br_bytes_consumed += bytesconsumed;

                        /* Update the variable bitrate about every second */
                        if(m_variable_bitrate_display && br_calc_frames == 43)
                        {
                              AudioInfo vai;
                              vai.struct_size = sizeof(AudioInfo);
                              vai.frequency = file_info.sampling_rate;
                              vai.bitrate = (int)((br_bytes_consumed * 8) / (decoded_frames / 43.07));
                              vai.mode = (channels == 2) ? 0 : 3;
                              vai.layer = 0;
                              vai.level = file_info.version;
                              QCDCallbacks->Service(opSetAudioInfo, &vai, sizeof(AudioInfo), 0);

                              br_calc_frames = 0;
                        }

                if (!killPlayThread && (frameInfo.samples > 0))
                {
                    //update the time display
                              if (updatePos)
                              {
                                    QCDCallbacks->toPlayer.PositionUpdate(decode_pos_ms);
                                    updatePos = 0;
                              }
                              
                              {
                                    WriteDataStruct wd;

                                    l = frameInfo.samples * sizeof(short);

                                    decode_pos_ms += (1024*1000)/file_info.sampling_rate;
                                    
                                    wd.bytelen = l;
                                    wd.data = sample_buffer;
                                    wd.markerend = 0;
                                    wd.markerstart = decode_pos_ms;
                                    wd.bps = 16;
                                    wd.nch = frameInfo.channels;
                                    wd.numsamples =l/file_info.channels/(16/8);
                                    wd.srate = file_info.sampling_rate;
                                    
                                    if (!QCDCallbacks->toPlayer.OutputWrite(&wd))
                                          done = TRUE;
                              }
                        }
                  }
            }
        Sleep(10);
    }

      // close up
      play_thread_handle = INVALID_HANDLE_VALUE;

      faacDecClose(hDecoder);
      hDecoder = INVALID_HANDLE_VALUE;
      close_filestream(infile);
      infile = NULL;

      if(seek_table)
      {
            free(seek_table);
            seek_table = NULL;
            seek_table_length = 0;
      }

      if(buffer)
      {
            LocalFree(buffer);
            buffer = NULL;
      }
      if(memmap_buffer)
      {
            LocalFree(memmap_buffer);
            memmap_buffer = NULL;
      }

    return 0;
}

// thread play funcs
int PlayThread_memmap()
{
    sample_buffer = (char*)faacDecDecode(hDecoder, &frameInfo,
        memmap_buffer + memmap_index, fileread - memmap_index - 1);
    if (frameInfo.error)
    {
//        show_error(faacDecGetErrorMessage(frameInfo.error));
        last_frame = 1;
    }

    memmap_index += frameInfo.bytesconsumed;
    if (memmap_index >= fileread)
        last_frame = 1;

    return frameInfo.bytesconsumed;
}

int PlayThread_file()
{
    int k;

    if (buffercount > 0)
      {
        for (k = 0; k < (768*2 - buffercount); k++)
            buffer[k] = buffer[k + buffercount];

        read_buffer_filestream(infile, buffer + (768*2) - buffercount, buffercount);
        buffercount = 0;
    }

    sample_buffer = (char*)faacDecDecode(hDecoder, &frameInfo, buffer, 768*2);
    if (frameInfo.error)
    {
//        show_error(faacDecGetErrorMessage(frameInfo.error));
        last_frame = 1;
    }

    buffercount += frameInfo.bytesconsumed;

    bytecount += frameInfo.bytesconsumed;
    if (bytecount >= fileread)
        last_frame = 1;

    return frameInfo.bytesconsumed;
}

// tag
int id3v2_tag(unsigned char *buffer)
{
    if (StringComp(buffer, "ID3", 3) == 0)
      {
        unsigned long tagsize;

        /* high bit is not used */
        tagsize = (buffer[6] << 21) | (buffer[7] << 14) |
            (buffer[8] <<  7) | (buffer[9] <<  0);

        tagsize += 10;

        return tagsize;
    }
      else
      {
        return 0;
    }
}

Generated by  Doxygen 1.6.0   Back to index