Setup Development Environment
- To compile mplayer under Windows, we can use MinGW or Cygwin, here I use MinGW, which can be downloaded from http://sourceforge.net/projects/mplayer-ww/files/MinGW-full/MinGW-full-20101119.7z/download, unpack it to C:\MinGW when complete.
- Download the latest source code of mplayer from http://www.mplayerhq.hu/design7/dload.html, I use TortoiseSVN to download the latest source code from svn://svn.mplayerhq.hu/mplayer/trunk, store it in C:\mplayer-yyyy-mm-dd, ‘yyyy-mm-dd’ could be defined as ‘2011-11-11’.
- Download the latest source code of ffmpeg cause source code of mplayer does not include it, download link is http://git.videolan.org/?p=ffmpeg.git;a=snapshot;h=HEAD;sf=tgz, a single tgz file could be downloaded, unpacked it to C:\mplayer-2011-11-11\ffmpeg when complete.
Create Executable Configure File and Run It
Create a file named ‘autoconf’ in c:\mplayer-2011-11-11, and input some configure options into it, I use below:
./configure --disable-mencoder --enable-static
--disable-sdl --disable-pthreads --enable-w32threads
Run C:\MinGW\msys_consolas.bat to display MinGW environment, execute ‘autoconf
’ to configure mplayer.
Modify mplayer.c
Here, we will do some coding works by ourselves.
- Hide main function through define
DISABLE_MAIN
.
Find the line ‘int main
’, and define DISABLE_MAIN
top of it.
- Define a structure to hold some functions passed by external program.
typedef struct
{
int (*open)(int samplerate, int channels, int bits, void* data);
int (*close)(void* data);
int (*start)(void* data);
int (*play)(void* pcmdata, int size, void* data);
int (*seek)(off_t pos, void* data);
int (*pause)(void* data);
int (*stop)(void* data);
int decode_size;
void* user_data;
} callback_t;
- Define a function named
mplayer_dll_main
and export it and call it by external program.
int mplayer_dll_main(int argc, char* argv[], callback_t* callback)
{
common_preinit();
common_init();
mpctx->stream = NULL;
mpctx->demuxer = NULL;
mpctx->sh_audio = NULL;
mpctx->sh_video = NULL;
filename = argv[1];
mpctx->stream = open_stream(filename, 0, &mpctx->file_format);
if (!mpctx->stream)
return 0;
mpctx->demuxer = demux_open(mpctx->stream, mpctx->file_format,
audio_id, video_id, dvdsub_id, filename);
if (!mpctx->demuxer)
return 0;
mpctx->d_audio = mpctx->demuxer->audio;
mpctx->d_video = mpctx->demuxer->video;
mpctx->d_sub = mpctx->demuxer->sub;
select_audio(mpctx->demuxer, audio_id, audio_lang);
mpctx->sh_audio = mpctx->d_audio->sh;
mpctx->sh_video = mpctx->d_video->sh;
if (!mpctx->sh_audio)
return 0;
demux_info_print(mpctx->demuxer);
reinit_audio_chain();
if (callback && callback->open)
callback->open(ao_data.samplerate, ao_data.channels,
af_fmt2bits(ao_data.format), callback);
if (callback && callback->start)
callback->start(callback);
while (!mpctx->eof)
{
new_fill_audio_out_buffers(callback);
}
if (callback && callback->stop)
callback->stop(callback);
if (callback && callback->close)
callback->close(callback);
return 0;
}
- Modify function
reinit_audio_chain
to fit our request.
void reinit_audio_chain(void)
{
if (!mpctx->sh_audio)
return;
if (!(initialized_flags & INITIALIZED_ACODEC)) {
current_module = "init_audio_codec";
mp_msg(MSGT_CPLAYER, MSGL_INFO,
"==========================================================================\n");
if (!init_best_audio_codec(mpctx->sh_audio, audio_codec_list, audio_fm_list))
goto init_error;
initialized_flags |= INITIALIZED_ACODEC;
mp_msg(MSGT_CPLAYER, MSGL_INFO,
"==========================================================================\n");
}
if (!(initialized_flags & INITIALIZED_AO)) {
current_module = "af_preinit";
ao_data.samplerate = force_srate;
ao_data.channels = 0;
ao_data.format = audio_output_format;
if (!init_audio_filters(mpctx->sh_audio, mpctx->sh_audio->samplerate,
&ao_data.samplerate, &ao_data.channels,
&ao_data.format)) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_AudioFilterChainPreinitError);
exit_player(EXIT_ERROR);
}
int format = ao_data.format;
if (AF_FORMAT_IS_AC3(format))
format = AF_FORMAT_AC3_NE;
switch(format) {
case AF_FORMAT_AC3_NE:
case AF_FORMAT_S24_LE:
case AF_FORMAT_S16_LE:
case AF_FORMAT_U8:
break;
default:
format = AF_FORMAT_S16_LE;
}
ao_data.format = format;
ao_data.bps = ao_data.channels * ao_data.samplerate *
(af_fmt2bits(ao_data.format)>>3);
ao_data.buffersize = ao_data.bps;
ao_data.outburst = ao_data.channels *
(af_fmt2bits(ao_data.format)>>3) * 512;
}
current_module = "af_init";
if (!build_afilter_chain(mpctx->sh_audio, &ao_data)) {
mp_msg(MSGT_CPLAYER, MSGL_ERR, MSGTR_NoMatchingFilter);
goto init_error;
}
mpctx->mixer.volstep = volstep;
return;
init_error:
uninit_player(INITIALIZED_ACODEC | INITIALIZED_AO); mpctx->sh_audio = mpctx->d_audio->sh = NULL; mpctx->d_audio->id = -2;
}
- Create a new function to decode audio data:
static int new_fill_audio_out_buffers(callback_t* callback)
{
int playsize;
int audio_eof = 0;
int bytes_to_write;
int format_change = 0;
sh_audio_t *const sh_audio = mpctx->sh_audio;
bytes_to_write = callback->decode_size;
while (bytes_to_write) {
int res;
playsize = bytes_to_write;
if (playsize > MAX_OUTBURST)
playsize = MAX_OUTBURST;
bytes_to_write -= playsize;
if (!format_change) {
res = mp_decode_audio(sh_audio, playsize);
format_change = res == -2;
}
if (!format_change && res < 0) if (mpctx->d_audio->eof) {
mpctx->eof = audio_eof = 1;
if (sh_audio->a_out_buffer_len == 0)
return 0;
}
if (playsize > sh_audio->a_out_buffer_len) {
playsize = sh_audio->a_out_buffer_len;
}
if (!playsize)
break;
if (callback && callback->play)
{
playsize = callback->play
(sh_audio->a_out_buffer, playsize, callback);
sh_audio->a_out_buffer_len -= playsize;
memmove(sh_audio->a_out_buffer,
&sh_audio->a_out_buffer[playsize],
sh_audio->a_out_buffer_len);
}
}
if (format_change) {
uninit_player(INITIALIZED_AO);
reinit_audio_chain();
}
return 1;
}
- Compile
mplayer
.
Type command ‘make
’ to compile mplayer
, we will get an error in the end because here is no main function defined in mplayer.c, ignore it.
Create a Makefile to Generate mplayer.dll
Create a Makefile
named ‘Makefile_dll’, content listed below:
include config.mak
DIRS = input libaf libao2 libass libdvdcss libdvdnav libdvdnav/vm
libdvdread4 libmpcodecs libmpdemux libmpeg2 libvo loader loader/dmo
loader/dshow mp3lib osdep stream
stream/freesdp stream/librtsp stream/realrtsp sub tremor vidix
ALL_OBJS = $(foreach DIR, $(DIRS), $(wildcard $(DIR)
Type command ‘make –f Makefile_dll’ to generate mplayer.dll and copy it to D:\SoftDevelop\C++\mplayerdll.
Using the Code - Create a Project to Use mplayer.dll
- Load
mplayer
by Windows API ‘LoadLibrary
’ - Load exported function ‘
mplayer_dll_main
’ by Windows API ‘GetProcAddress
’ - Write proxy functions and pass them to structure
callback_t
typedef struct
{
int (*open)(int samplerate, int channels, int bits, void* data);
int (*close)(void* data);
int (*start)(void* data);
int (*play)(void* pcmdata, int size, void* data);
int (*seek)(long long pos, void* data);
int (*pause)(void* data);
int (*stop)(void* data);
int decode_size;
void* user_data;
} callback_t;
typedef int (*mplayer_dll_main)(int argc, char* argv[], callback_t* callback);
mplayer_dll_main mplayer_dll_main_ptr = NULL;
static int open(int samplerate, int channels, int bits, void* data)
{
if (!data)
return 0;
printf("samplerate=%d, channels=%d, bits=%d\n", samplerate, channels, bits);
callback_t* callback = reinterpret_cast<callback_t*>(data);
callback->user_data = DAUDIO_Open(0, 0, TRUE, DAUDIO_PCM,
(float)samplerate, bits, channels * (bits >> 3),
channels, TRUE, FALSE, 88200);
if (!callback->user_data)
return 0;
return 1;
}
static int close(void* data)
{
if (!data)
return 0;
callback_t* callback = reinterpret_cast<callback_t*>(data);
if (!callback->user_data)
return 0;
DAUDIO_Close(callback->user_data, TRUE);
callback->user_data = NULL;
return 1;
}
static int start(void* data)
{
if (!data)
return 0;
callback_t* callback = reinterpret_cast<callback_t*>(data);
if (!callback->user_data)
return 0;
return DAUDIO_Start(callback->user_data, TRUE);
}
static int stop(void* data)
{
if (!data)
return 0;
callback_t* callback = reinterpret_cast<callback_t*>(data);
if (!callback->user_data)
return 0;
Sleep(200); return DAUDIO_Stop(callback->user_data, TRUE);
}
static int play(void* buf, int size, void* data)
{
if (!data)
return 0;
callback_t* callback = reinterpret_cast<callback_t*>(data);
if (!callback->user_data)
return 0;
DWORD len = size;
DWORD offset = 0;
DWORD written = 0;
char* decode_buf = reinterpret_cast<char*>(buf);
for( ; ; )
{
int thisWritten = DAUDIO_Write(callback->user_data,
decode_buf + offset, len);
if(thisWritten < 0)
break;
len -= thisWritten;
written += thisWritten;
if(len > 0)
{
offset += thisWritten;
Sleep(125);
}
else break;
}
return written;
}
int _tmain(int argc, _TCHAR* argv[])
{
HMODULE hModule = LoadLibrary("mplayer.dll");
if (!hModule)
return 0;
mplayer_dll_main_ptr = (mplayer_dll_main)GetProcAddress
(hModule, "mplayer_dll_main");
if (!mplayer_dll_main_ptr)
{
FreeLibrary(hModule);
return 0;
}
char szFile[MAX_PATH];
OPENFILENAME ofn = {0};
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = GetDesktopWindow();
ofn.lpstrFile = szFile;
ofn.lpstrFile[0] = _T('\0');
ofn.nMaxFile = sizeof(szFile) / sizeof(char);
ofn.lpstrFilter = "All 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) == FALSE)
return 0;
int _argc = 2;
char* _argv[2] = {"", szFile};
int ret = 0;
callback_t callback = {open, close, start, play,
NULL , NULL, stop, BLOCK_SIZE, NULL};
int count = DAUDIO_GetDirectAudioDeviceCount();
ret = mplayer_dll_main_ptr(_argc, _argv, &callback);
FreeLibrary(hModule);
return 0;
}
History
- First release on 2011-12-07