Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

Use mplayer as our Audio Decoder – Part 2

5.00/5 (7 votes)
12 Dec 2011CPOL1 min read 29.3K   2.4K  
This article demonstrates how to use mplayer as an audio decoder and display real time spectrum during playback process
Sample Image - maximum width is 668 pixels

Introduction

The article ‘Use mplayer as our audio decoder’ introduces how to set compile environment and how to build mplayer as a single DLL library, and use it as a decoder to decode more audio format and playback.

This article will go to the next step – add real time spectrum analyzer feature to display spectrum during the play process.

Modify libao2

In Windows, we could use DSound or WaveOut for audio playback, the DSound play is the first choice in mplayer.

First, we define a few control flags for spectrum analyzer.

C++
#define AOCONTROL_START 913
#define AOCONTROL_GET_POSITION 914
#define AOCONTROL_FLUSH	915
  • The flag AOCONTROL_START for start spectrum analyzer.
  • The flag AOCONTROL_GET_POSITION for get play position in DSound’s play buffer.
  • The flag AOCONTROL_FLUSH for seek is called in playback process.

Second, we should modify libao2/ao_dsound.c and libao2/ao_win32.c.

libao2/ao_dsound.c

C++
/**
\brief destroy the direct sound buffer
*/
static void DestroyBuffer(void)
{
    if (hdsbuf) {
        IDirectSoundBuffer_Release(hdsbuf);
        hdsbuf = NULL;
    }
    if (hdspribuf) {
        IDirectSoundBuffer_Release(hdspribuf);
        hdspribuf = NULL;
    }
}

/**
\brief fill sound buffer
\param data pointer to the sound data to copy
\param len length of the data to copy in bytes
\return number of copied bytes
*/
static int write_buffer(unsigned char *data, int len)
{
    HRESULT res;
    LPVOID lpvPtr1;
    DWORD dwBytes1;
    LPVOID lpvPtr2;
    DWORD dwBytes2;

    // Lock the buffer
    res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, 
		&lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
    // If the buffer was lost, restore and retry lock.
    if (DSERR_BUFFERLOST == res)
    {
        IDirectSoundBuffer_Restore(hdsbuf);
        res = IDirectSoundBuffer_Lock(hdsbuf,write_offset, len, 
		&lpvPtr1, &dwBytes1, &lpvPtr2, &dwBytes2, 0);
    }


    if (SUCCEEDED(res))
    {
        if( (ao_data.channels == 6) && !AF_FORMAT_IS_AC3(ao_data.format) ) {
            // reorder channels while writing to pointers.
            // it's this easy because buffer size and len are always
            // aligned to multiples of channels*bytespersample
            // there's probably some room for speed improvements here
            const int chantable[6] = {0, 1, 4, 5, 2, 3}; // reorder "matrix"
            int i, j;
            int numsamp,sampsize;

            sampsize = af_fmt2bits(ao_data.format)>>3; // bytes per sample
            numsamp = dwBytes1 / (ao_data.channels * sampsize);  // number of samples 
						// for each channel in this buffer

            for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) {
                    memcpy(lpvPtr1+(i*ao_data.channels*sampsize)+
			(chantable[j]*sampsize),data+(i*ao_data.channels*sampsize)+
			(j*sampsize),sampsize);
                }

            if (NULL != lpvPtr2 )
            {
                numsamp = dwBytes2 / (ao_data.channels * sampsize);
                for( i = 0; i < numsamp; i++ ) for( j = 0; j < ao_data.channels; j++ ) {
                        memcpy(lpvPtr2+(i*ao_data.channels*sampsize)+
			(chantable[j]*sampsize),data+dwBytes1+
			(i*ao_data.channels*sampsize)+(j*sampsize),sampsize);
                    }
            }

            write_offset+=dwBytes1+dwBytes2;
            //if(write_offset>=buffer_size)write_offset=dwBytes2;
            if (write_offset>=buffer_size)write_offset-=buffer_size; 	// jacky_zz
								// [2010-12-28]
        } else {
            // Write to pointers without reordering.
            fast_memcpy(lpvPtr1,data,dwBytes1);
            if (NULL != lpvPtr2 )fast_memcpy(lpvPtr2,data+dwBytes1,dwBytes2);
            write_offset+=dwBytes1+dwBytes2;
            //if(write_offset>=buffer_size)write_offset=dwBytes2;
            if (write_offset>=buffer_size)write_offset-=buffer_size; 	// jacky_zz
								// [2010-12-28]
        }

        // Release the data back to DirectSound.
        res = IDirectSoundBuffer_Unlock(hdsbuf,lpvPtr1,dwBytes1,lpvPtr2,dwBytes2);
        if (SUCCEEDED(res))
        {
            // Success.
            DWORD status;
            IDirectSoundBuffer_GetStatus(hdsbuf, &status);
            if (!(status & DSBSTATUS_PLAYING)) {
                res = IDirectSoundBuffer_Play(hdsbuf, 0, 0, DSBPLAY_LOOPING);
            }
            return dwBytes1+dwBytes2;
        }
    }
    // Lock, Unlock, or Restore failed.
    return 0;
}

/***************************************************************************************/

/**
\brief handle control commands
\param cmd command
\param arg argument
\return CONTROL_OK or -1 in case the command can't be handled
*/
static int control(int cmd, void *arg)
{
    DWORD volume;
    switch (cmd) {
    case AOCONTROL_GET_VOLUME: {
        ao_control_vol_t* vol = (ao_control_vol_t*)arg;
        IDirectSoundBuffer_GetVolume(hdsbuf, &volume);
        vol->left = vol->right = pow(10.0, (float)(volume+10000) / 5000.0);
        //printf("ao_dsound: volume: %f\n",vol->left);
        return CONTROL_OK;
    }
    case AOCONTROL_SET_VOLUME: {
        ao_control_vol_t* vol = (ao_control_vol_t*)arg;
        volume = (DWORD)(log10(vol->right) * 5000.0) - 10000;
        IDirectSoundBuffer_SetVolume(hdsbuf, volume);
        //printf("ao_dsound: volume: %f\n",vol->left);
        return CONTROL_OK;
    }
	// jacky_zz[2010-12-28]
	case AOCONTROL_START:
	{
		return CONTROL_OK;
	}
	case AOCONTROL_FLUSH:
	{
		return CONTROL_OK;
	}
	case AOCONTROL_GET_POSITION:
	{
		DWORD playCursor, writeCursor;
		int count = 0;
		long long* pos = NULL;

		if(!arg) return -1;
		pos = (long long*)arg;

		if(FAILED(IDirectSoundBuffer_GetCurrentPosition
				(hdsbuf, &playCursor, &writeCursor)))
		{
			return -1;
		}

		count = write_offset / ao_data.bps;
		*pos = playCursor + count * ao_data.bps;
		return CONTROL_OK;
	}
	// jacky_zz[2010-12-28]
    }
    return -1;
}

libao2/ao_win32.c

C++
// jacky_zz[2011-01-28]
static int play_cursor = 0;
// jacky_zz[2011-01-28]

// to set/get/query special features/parameters
static int control(int cmd,void *arg)
{
    DWORD volume;
    switch (cmd)
    {
    case AOCONTROL_GET_VOLUME:
    {
        ao_control_vol_t* vol = (ao_control_vol_t*)arg;
        waveOutGetVolume(hWaveOut,&volume);
        vol->left = (float)(LOWORD(volume)/655.35);
        vol->right = (float)(HIWORD(volume)/655.35);
        mp_msg(MSGT_AO, MSGL_DBG2,"ao_win32: volume left:%f 
			volume right:%f\n",vol->left,vol->right);
        return CONTROL_OK;
    }
    case AOCONTROL_SET_VOLUME:
    {
        ao_control_vol_t* vol = (ao_control_vol_t*)arg;
        volume = MAKELONG(vol->left*655.35,vol->right*655.35);
        waveOutSetVolume(hWaveOut,volume);
        return CONTROL_OK;
    }
	// jacky_zz[2011-01-28]
	case AOCONTROL_START:
	{
		play_cursor = 0;
		return CONTROL_OK;
	}
	case AOCONTROL_FLUSH:
	{
		play_cursor = 0;
		return CONTROL_OK;
	}
	case AOCONTROL_GET_POSITION:
	{
		long long* pos = NULL;
		DWORD dwPosition = 0;

		if(!arg) return -1;
		pos = (long long*)arg;

		dwPosition = play_cursor;
		while(dwPosition > ao_data.bps)
			dwPosition -= ao_data.bps;

		*pos = dwPosition;
		return CONTROL_OK;
	}
	// jacky_zz[2011-01-28]
    }
    return -1;
}

The Spectrum Analyzer Component

This component was developed for mplayer, which use libao2’s functions that are included in mplayer’s source code, and we should make some modifications to it for spectrum analyzer component.

First, we should define a structure to hold an interface (pointer to ao_functions_t, which is defined in audio_out.h) that is instanced by function ‘init_best_audio_out’.

C++
#ifndef INCLUDE_SPECTRUM_ANALYZER
#define INCLUDE_SPECTRUM_ANALYZER

#include <windows.h>
#include <mmsystem.h>
#include <dsound.h>
#include "audio_out.h"

typedef struct
{
	int sample_rate;
	int channels;
	int bits_per_sample;
	int frame_size;
	long buffer_size;
	unsigned long long write_bytes;
	const ao_functions_t* funcs;
} ao_infoex_t;

#ifdef __cplusplus
extern "C" {
#endif

	int		spectrum_analyzer_init(HWND);
	void*	spectrum_analyzer_new(HWND, int, BOOL, ao_infoex_t*);
	int		spectrum_analyzer_writedata(void*, void*, long, long);
	int		spectrum_analyzer_render(void*, int);
	int		spectrum_analyzer_flush(void*);
	int		spectrum_analyzer_free(void*);
	int		spectrum_analyzer_uninit(void);

#ifdef __cplusplus
}
#endif

#endif

Use the Code – Display Spectrum Analyzer

  • Create a window as spectrum analyzer window.
  • Call function ‘spectrum_analyzer_init’ to initialize spectrum analyzer when creating window success.
  • Call function ‘spectrum_analyzer_uninit’ to uninitialized spectrum analyzer when window holds the WM_DESTROY message.
  • Call function ‘spectrum_analyzer_new’ to instance an new spectrum analyzer.
  • Call function ‘spectrum_analyzer_writedata’ to write PCM data to feed spectrum analyzer after PCM data write to sound card.
  • Call function ‘spectrum_analyzer_render’ to render memory bitmap to spectrum analyzer window.
C++
#include "wnd.h"
#include "spectrum_analyzer.h"

HWND hMainWindow;

ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= NULL;
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= NULL;
	wcex.lpszClassName	= _T("SpectrumAnalyzer");
	wcex.hIconSm		= LoadIcon(wcex.hInstance, 
						MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	HWND hWnd;

	DWORD dwStyle = WS_POPUPWINDOW & (~WS_SYSMENU) | WS_CAPTION;
	hWnd = CreateWindow(_T("SpectrumAnalyzer"), 
		_T("Spectrum Analyzer for MPlayer - by jacky_zz"), dwStyle,
		0, 0, 402, 120, NULL, NULL, hInstance, NULL);

	if (!hWnd)
	{
		return FALSE;
	}

	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);
	spectrum_analyzer_init(hWnd);
	hMainWindow = hWnd;

	return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	PAINTSTRUCT ps;
	HDC hdc;

	switch (message)
	{
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		EndPaint(hWnd, &ps);
		break;
	case WM_DESTROY:
		spectrum_analyzer_uninit();
		PostQuitMessage(0);
		break;


	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
C++
#include "stdafx.h"
#include "DirectAudio.h"
#include "wnd.h"
#include "spectrum_analyzer.h"

typedef const void* /* ao_functions_t* */ (*init_best_audio_out)
	(char** ao_list, int use_plugin, int rate, int channels, int format, int flags);
typedef int (*usec_sleep)(int usec_delay);
typedef int (*mp_decode_audio)(void* sh_audio /* sh_audio_t* */, int minlen);
typedef void* /* MPContext* */ (*mp_dll_open)(const char* fileName);
typedef void (*mp_dll_close)(void* _mpctx /* MPContext* */);
typedef void* /*sh_audio_t* */ (*mp_dll_get_sh_audio)(void* _mpctx /* MPContext* */);
typedef int (*mp_dll_get_audio_attributes)(int* samplerate, 
			int* channels, int* bits, int* format);
typedef void (*mp_dll_set_audio_attributes)(int samplerate, int channels, int bits);
typedef const void* /* ao_functions_t* */ (*mp_dll_get_audio_out)
				(void* _mpctx/* MPContext* */);
typedef void (*mp_dll_set_audio_out)(void* _mpctx /* MPContext* */, 
				const void* /* ao_functions_t* */ ao_out);
typedef int (*mp_dll_get_eof)(void* _mpctx /* MPContext* */);
typedef void (*mp_dll_set_eof)(void* _mpctx /* MPContext* */, int eof);
typedef int (*mp_dll_audio_out_get_space)(const void* audio_out /* ao_functions_t* */);
typedef int (*mp_dll_audio_out_play)(const void* audio_out /* 
		ao_functions_t* */, char* buf, int size, int flag);
typedef int (*mp_dll_audio_eof)(void* _mpctx /* MPContext* */);
typedef char* (*mp_dll_sh_audio_get_out_buffer)(void* sh_audio /* sh_audio_t* */);
typedef int (*mp_dll_sh_audio_get_out_buffer_len)(void* sh_audio /* sh_audio_t* */);
typedef void (*mp_dll_sh_audio_set_out_buffer_len)(void* sh_audio /* 
				sh_audio_t* */, int len);
typedef int (*mp_dll_audio_out_get_info)(const void* audio_out /* 
	ao_functions_t* */, char* name, char* short_name, char* author, char* comment);
typedef int (*mp_dll_fill_buffer)(void* _mpctx /* MPContext* */, char* buf, int size);

DECLARE_FUNC_PTR_VAR(init_best_audio_out)
DECLARE_FUNC_PTR_VAR(usec_sleep)
DECLARE_FUNC_PTR_VAR(mp_decode_audio)
DECLARE_FUNC_PTR_VAR(mp_dll_open)
DECLARE_FUNC_PTR_VAR(mp_dll_close)
DECLARE_FUNC_PTR_VAR(mp_dll_get_sh_audio)
DECLARE_FUNC_PTR_VAR(mp_dll_get_audio_attributes)
DECLARE_FUNC_PTR_VAR(mp_dll_set_audio_attributes)
DECLARE_FUNC_PTR_VAR(mp_dll_get_audio_out)
DECLARE_FUNC_PTR_VAR(mp_dll_set_audio_out)
DECLARE_FUNC_PTR_VAR(mp_dll_get_eof)
DECLARE_FUNC_PTR_VAR(mp_dll_set_eof)
DECLARE_FUNC_PTR_VAR(mp_dll_audio_out_get_space)
DECLARE_FUNC_PTR_VAR(mp_dll_audio_out_play)
DECLARE_FUNC_PTR_VAR(mp_dll_audio_eof)
DECLARE_FUNC_PTR_VAR(mp_dll_sh_audio_get_out_buffer)
DECLARE_FUNC_PTR_VAR(mp_dll_sh_audio_get_out_buffer_len)
DECLARE_FUNC_PTR_VAR(mp_dll_sh_audio_set_out_buffer_len)
DECLARE_FUNC_PTR_VAR(mp_dll_audio_out_get_info)
DECLARE_FUNC_PTR_VAR(mp_dll_fill_buffer);

typedef struct
{
	void* data;
	void* data1;
	void* data2;
} callback_t;

static void* handle = NULL;

void init(HMODULE hModule)
{
	_init_best_audio_out = (init_best_audio_out)GetProcAddress
				(hModule, "init_best_audio_out");
	_usec_sleep = (usec_sleep)GetProcAddress(hModule, "usec_sleep");
	_mp_decode_audio = (mp_decode_audio)GetProcAddress(hModule, "mp_decode_audio");
	_mp_dll_open = (mp_dll_open)GetProcAddress(hModule, "mp_dll_open");
	_mp_dll_close = (mp_dll_close)GetProcAddress(hModule, "mp_dll_close");
	_mp_dll_get_sh_audio = (mp_dll_get_sh_audio)GetProcAddress
				(hModule, "mp_dll_get_sh_audio");
	_mp_dll_get_audio_attributes = (mp_dll_get_audio_attributes)
			GetProcAddress(hModule, "mp_dll_get_audio_attributes");
	_mp_dll_set_audio_attributes = (mp_dll_set_audio_attributes)
			GetProcAddress(hModule, "mp_dll_set_audio_attributes");
	_mp_dll_get_audio_out = (mp_dll_get_audio_out)
			GetProcAddress(hModule, "mp_dll_get_audio_out");
	_mp_dll_set_audio_out = (mp_dll_set_audio_out)
			GetProcAddress(hModule, "mp_dll_set_audio_out");
	_mp_dll_get_eof = (mp_dll_get_eof)GetProcAddress(hModule, "mp_dll_get_eof");
	_mp_dll_set_eof = (mp_dll_set_eof)GetProcAddress(hModule, "mp_dll_set_eof");
	_mp_dll_audio_out_get_space = (mp_dll_audio_out_get_space)
			GetProcAddress(hModule, "mp_dll_audio_out_get_space");
	_mp_dll_audio_out_play = (mp_dll_audio_out_play)
			GetProcAddress(hModule, "mp_dll_audio_out_play");
	_mp_dll_audio_eof = (mp_dll_audio_eof)
			GetProcAddress(hModule, "mp_dll_audio_eof");
	_mp_dll_sh_audio_get_out_buffer = (mp_dll_sh_audio_get_out_buffer)
			GetProcAddress(hModule, "mp_dll_sh_audio_get_out_buffer");
	_mp_dll_sh_audio_get_out_buffer_len = (mp_dll_sh_audio_get_out_buffer_len)
			GetProcAddress(hModule, "mp_dll_sh_audio_get_out_buffer_len");
	_mp_dll_sh_audio_set_out_buffer_len = (mp_dll_sh_audio_set_out_buffer_len)
			GetProcAddress(hModule, "mp_dll_sh_audio_set_out_buffer_len");
	_mp_dll_audio_out_get_info = (mp_dll_audio_out_get_info)
			GetProcAddress(hModule, "mp_dll_audio_out_get_info");
	_mp_dll_fill_buffer = (mp_dll_fill_buffer)
			GetProcAddress(hModule, "mp_dll_fill_buffer");
}

DWORD CALLBACK GUIThread(void* lpParam)
{
	callback_t* callback = reinterpret_cast<callback_t* />(lpParam);
	HINSTANCE hInstance = reinterpret_cast<hinstance />(GetModuleHandle(NULL));

	MyRegisterClass(hInstance);

	if (!InitInstance(hInstance, SW_SHOW))
	{
		if (callback->data1)
			SetEvent(callback->data1);
		return 0;
	}

	MSG msg = {0};
	HACCEL hAccelTable = {0};

	ao_infoex_t* ao_infoex = reinterpret_cast<ao_infoex_t* />(callback->data);
	handle = spectrum_analyzer_new(hMainWindow, 0, FALSE, ao_infoex);
	if (callback->data2)
		SetEvent(callback->data2);

	while (GetMessage(&msg, NULL, 0, 0))
	{
		if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	spectrum_analyzer_free(handle);
	handle = NULL;

	if (callback->data1)
		SetEvent(callback->data1);

	return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
	TCHAR szFile[50 * MAX_PATH] = {0};
	OPENFILENAME ofn = {0};

	ofn.lStructSize = sizeof(ofn);
	ofn.hwndOwner = GetDesktopWindow();
	ofn.lpstrFile = szFile;
	ofn.lpstrFile[0] = _T('\0');
	ofn.nMaxFile = sizeof(szFile);
	ofn.lpstrFilter = _T("Audio Files\0*.*\0");
	ofn.nFilterIndex = 1;
	ofn.lpstrFileTitle = NULL;
	ofn.nMaxFileTitle = 0;
	ofn.lpstrInitialDir = NULL;
	ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_EXPLORER;
	if (!GetOpenFileName(&ofn))
		return 0;

	HMODULE hModule = LoadLibrary("mplayer.dll");
	if (!hModule)
		return 0;

	init(hModule);

	void* mpctx = _mp_dll_open(szFile);
	if (!mpctx)
	{
		FreeLibrary(hModule);
		return 0;
	}

	int samplerate, channels, bits, format;
	void* sh_audio = NULL;

	sh_audio = _mp_dll_get_sh_audio(mpctx);
	_mp_dll_get_audio_attributes(&samplerate, &channels, &bits, &format);

	// initialize audio_out
	const void* audio_out = _init_best_audio_out
				(NULL, 0, samplerate, channels, format, 0);
	if (!audio_out)
	{
		_mp_dll_close(mpctx);
		FreeLibrary(hModule);
		return 0;
	}

	char name[MAX_PATH] = {0};
	char short_name[MAX_PATH] = {0};
	char author[MAX_PATH] = {0};
	char comment[MAX_PATH] = {0};

	_mp_dll_audio_out_get_info(audio_out, name, short_name, author, comment);
	_mp_dll_set_audio_out(mpctx, audio_out);

	int bytes_to_write = 0;
	int sleep_time = 0;
	int outburst = channels * (bits >> 3) * 512;
	int bps = channels * (bits >> 3) * samplerate;
	char buf[MAX_OUTBURST] = {0};
	int playsize = 0;
	int a_out_buffer_len = 0;
	char* a_out_buffer = NULL;

	HANDLE hThread = INVALID_HANDLE_VALUE;
	DWORD dwThreadID = 0;

	callback_t callback = {0};
	ao_infoex_t ao_infoex = {0};
	DWORD start_count = 0, end_count = 0;

	ao_infoex.sample_rate = samplerate;
	ao_infoex.channels = channels;
	ao_infoex.bits_per_sample = bits;
	ao_infoex.frame_size = (channels == 1) ? 2 : 4;
	ao_infoex.buffer_size = samplerate * ao_infoex.frame_size;
	ao_infoex.funcs = (const ao_functions_t*)audio_out;

	callback.data = &ao_infoex;
	callback.data1 = CreateEvent(NULL, FALSE, FALSE, _T("WaitCompleteEvent"));
	callback.data2 = CreateEvent(NULL, FALSE, FALSE, _T("GUIReadyEvent"));

	hThread = CreateThread(NULL, 0, GUIThread, &callback, 0, &dwThreadID);
	WaitForSingleObject(callback.data2, INFINITE);

	start_count = GetTickCount();

	while (!_mp_dll_get_eof(mpctx))
	{
		while (1)
		{
			bytes_to_write = _mp_dll_audio_out_get_space(audio_out);
			if (bytes_to_write >= outburst)
				break;

			sleep_time = (outburst - bytes_to_write) * 1000 / bps;
			if (sleep_time < 10)
				sleep_time = 10;
			_usec_sleep(sleep_time * 1000);
		}

		while (bytes_to_write)
		{
			int res = 0;
			playsize = bytes_to_write;
			if (playsize > MAX_OUTBURST)
				playsize = MAX_OUTBURST;
			bytes_to_write -= playsize;

			res = _mp_decode_audio(sh_audio, playsize);
			if (res < 0)
			{
				if (_mp_dll_audio_eof(mpctx))
					_mp_dll_set_eof(mpctx, 1);

				a_out_buffer_len = 
				_mp_dll_sh_audio_get_out_buffer_len(sh_audio);
				if (a_out_buffer_len == 0)
					break;
			}

			a_out_buffer_len = 
				_mp_dll_sh_audio_get_out_buffer_len(sh_audio);
			if (playsize > a_out_buffer_len)
				playsize = a_out_buffer_len;

			a_out_buffer = _mp_dll_sh_audio_get_out_buffer(sh_audio);
			playsize = _mp_dll_audio_out_play
					(audio_out, a_out_buffer, playsize, 0);

			spectrum_analyzer_writedata(handle, a_out_buffer, 0L, 
						(long)playsize);

			if (playsize > 0)
			{
				a_out_buffer_len -= playsize;
				memmove(a_out_buffer, &a_out_buffer[playsize], 
						a_out_buffer_len);
				_mp_dll_sh_audio_set_out_buffer_len
						(sh_audio, a_out_buffer_len);
			}

			end_count = GetTickCount();
			if(end_count - start_count >= 25)
			{
				spectrum_analyzer_render(handle, 60);
				start_count = end_count;
			}
		}
	}

	SendMessage(hMainWindow, WM_DESTROY, 0, 0);
	WaitForSingleObject(hThread, INFINITE);

	CloseHandle(hThread);
	hThread = INVALID_HANDLE_VALUE;

	CloseHandle(callback.data1);
	callback.data1 = NULL;

	CloseHandle(callback.data2);
	callback.data2 = NULL;

	_mp_dll_close(mpctx);
	return 0;
}

History

  • First release on 2011-12-12

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)