From 7efc118a466de433f27800e04766bf6183c60b46 Mon Sep 17 00:00:00 2001 From: "MSDN.WhiteKnight" <35516665+MSDN-WhiteKnight@users.noreply.github.com> Date: Sun, 4 Apr 2021 18:49:05 +0500 Subject: [PATCH] Add sources --- .gitignore | 4 + README.md | 29 +- SmallMediaPlayer/DirectShowStuff.cpp | 315 +++ SmallMediaPlayer/DirectShowStuff.h | 67 + SmallMediaPlayer/PictureManager.cpp | 240 +++ SmallMediaPlayer/PictureManager.h | 27 + SmallMediaPlayer/PlayListEditor.cpp | 1340 +++++++++++++ SmallMediaPlayer/PlayListEditor.h | 227 +++ SmallMediaPlayer/RegistryModule.cpp | 224 +++ SmallMediaPlayer/RegistryModule.h | 17 + SmallMediaPlayer/SMPSettings.cpp | 180 ++ SmallMediaPlayer/SMPSettings.h | 29 + SmallMediaPlayer/ScrollbarControl.h | 62 + SmallMediaPlayer/SmallMediaPlayer.sln | 20 + SmallMediaPlayer/SmallMediaPlayer.vcxproj | 107 ++ .../SmallMediaPlayer.vcxproj.filters | 74 + SmallMediaPlayer/generic.h | 135 ++ SmallMediaPlayer/main.cpp | 1705 +++++++++++++++++ SmallMediaPlayer/player.cpp | 1170 +++++++++++ SmallMediaPlayer/player.h | 58 + SmallMediaPlayer/resource.h | 73 + SmallMediaPlayer/smp.rc | 244 +++ SmallMediaPlayer/smpconfig.bin | Bin 0 -> 552 bytes docs/ReadMe.htm | 40 + scripts/shortcut.cmd | 11 + scripts/smp.ico | Bin 0 -> 9662 bytes 26 files changed, 6396 insertions(+), 2 deletions(-) create mode 100644 SmallMediaPlayer/DirectShowStuff.cpp create mode 100644 SmallMediaPlayer/DirectShowStuff.h create mode 100644 SmallMediaPlayer/PictureManager.cpp create mode 100644 SmallMediaPlayer/PictureManager.h create mode 100644 SmallMediaPlayer/PlayListEditor.cpp create mode 100644 SmallMediaPlayer/PlayListEditor.h create mode 100644 SmallMediaPlayer/RegistryModule.cpp create mode 100644 SmallMediaPlayer/RegistryModule.h create mode 100644 SmallMediaPlayer/SMPSettings.cpp create mode 100644 SmallMediaPlayer/SMPSettings.h create mode 100644 SmallMediaPlayer/ScrollbarControl.h create mode 100644 SmallMediaPlayer/SmallMediaPlayer.sln create mode 100644 SmallMediaPlayer/SmallMediaPlayer.vcxproj create mode 100644 SmallMediaPlayer/SmallMediaPlayer.vcxproj.filters create mode 100644 SmallMediaPlayer/generic.h create mode 100644 SmallMediaPlayer/main.cpp create mode 100644 SmallMediaPlayer/player.cpp create mode 100644 SmallMediaPlayer/player.h create mode 100644 SmallMediaPlayer/resource.h create mode 100644 SmallMediaPlayer/smp.rc create mode 100644 SmallMediaPlayer/smpconfig.bin create mode 100644 docs/ReadMe.htm create mode 100644 scripts/shortcut.cmd create mode 100644 scripts/smp.ico diff --git a/.gitignore b/.gitignore index dfcfd56..310cd29 100644 --- a/.gitignore +++ b/.gitignore @@ -348,3 +348,7 @@ MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ + +########################################################################################## +distr/ +Info/ diff --git a/README.md b/README.md index a1ec59c..02d194a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,27 @@ -# media-player -Small audio and video player for Windows +# Small Media Player + +Лицензия: [BSD 2.0](LICENSE) + +Легкий проигрыватель мультимедиа файлов для Windows без встроенных кодеков. Основные особенности программы: +- воспроизведение аудиофайлов: WAV, WMA, MP3 и др. +- воспроизведение видеофайлов: WMV, AVI, MPEG и др. +- воспроизведение Audio CD (только WinXP) +- совместим с любыми DirectShow-декодерами сторонних разработчиков, обеспечивающими поддержку других форматов +- просмотр изображений (BMP, JPEG, GIF, PNG) с автоматической прокруткой слайдов +- небольшой размер и потребление системных ресурсов +- оконный и полноэкранный режим при просмотре видео +- редактирование списка воспроизведения +- режимы воспроизведения: повтор списка, повтор одного файла, случайный порядок +- загрузка и сохранение списков воспроизведения в формате M3U +- поддержка информационных тэгов ID3V1, ID3V2, APE, FLAC +- автоматическое отображение обложек альбомов из файлов JPEG, BMP, PNG +- запоминание позиции последнего воспроизведенного файла при закрытии +- возможность создания ассоциаций с файлами и папками в проводнике Windows +- управление горячими клавишами +- отображение информации о используемых кодеках и характеристиках аудио- и видеопотоков воспроизводимого файла +- возможность свернуть в значок системной панели +- простой и понятный интерфейс + +Поддерживаемые ОС: Windows XP, Vista, 7, 8, 10 + +Для запуска требуется Visual C++ 2012 Redistributable (x86). diff --git a/SmallMediaPlayer/DirectShowStuff.cpp b/SmallMediaPlayer/DirectShowStuff.cpp new file mode 100644 index 0000000..c1dedec --- /dev/null +++ b/SmallMediaPlayer/DirectShowStuff.cpp @@ -0,0 +1,315 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#define UNICODE +#include "DirectShowStuff.h" +IBaseFilter* FindFilter(TCHAR* FilterName){ + HRESULT hr; +// Create the System Device Enumerator. +ICreateDevEnum *pSysDevEnum = NULL; +hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + IID_ICreateDevEnum, (void **)&pSysDevEnum); +if (FAILED(hr)) +{ return NULL;} + +// Obtain a class enumerator for the dshow filters category. +IEnumMoniker *pEnumCat = NULL; +hr = pSysDevEnum->CreateClassEnumerator(CLSID_LegacyAmFilterCategory, &pEnumCat, 0); + +if (hr == S_OK) +{ + // Enumerate the monikers. + IMoniker *pMoniker = NULL; + ULONG cFetched; + while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) + { + IPropertyBag *pPropBag; + hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, + (void **)&pPropBag); + if (SUCCEEDED(hr)) + { + // To retrieve the filter's friendly name, do the following: + VARIANT varName; + VariantInit(&varName); + hr = pPropBag->Read(L"FriendlyName", &varName, 0); + if (SUCCEEDED(hr)){ + if(wcscmp(FilterName,varName.bstrVal)==0){ + + // To create an instance of the filter, do the following: + IBaseFilter *pFilter; + hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, + (void**)&pFilter); + // Now add the filter to the graph. + //Remember to release pFilter later. + VariantClear(&varName); + pPropBag->Release(); + pMoniker->Release(); + pEnumCat->Release(); + pSysDevEnum->Release(); + return pFilter; + + } + } + + pPropBag->Release(); + } + pMoniker->Release(); + } + pEnumCat->Release(); +} +pSysDevEnum->Release(); +return NULL; + +} +void MyFreeMediaType(AM_MEDIA_TYPE& mt) +{ + if (mt.cbFormat != 0) + { + CoTaskMemFree((PVOID)mt.pbFormat); + mt.cbFormat = 0; + mt.pbFormat = NULL; + } + if (mt.pUnk != NULL) + { + // Unecessary because pUnk should not be used, but safest. + mt.pUnk->Release(); + mt.pUnk = NULL; + } +} +void MyDeleteMediaType(AM_MEDIA_TYPE *pmt) +{ + if (pmt != NULL) + { + MyFreeMediaType(*pmt); + CoTaskMemFree(pmt); + } +} +void ShowError(HRESULT hr,ERROR_TYPE et){ + TCHAR buf[MAX_ERROR_TEXT_LEN]=L""; + TCHAR message[256]=L""; + +switch(et){ + case SYSTEM_ERROR:AMGetErrorTextW(hr,buf,sizeof(buf)); + lstrcpy(message,L"Системная ошибка");break; + case PLAY_ERROR:AMGetErrorTextW(hr,buf,sizeof(buf)); + lstrcpy(message,L"Ошибка воспроизведения");break; + case ERROR_NOTSUPPORTED:lstrcpy(message,L"Ошибка"); + lstrcpy(buf,L"Операция не поддерживается");break; + case ERROR_NOPROPERTIES:lstrcpy(message,L"Ошибка"); + lstrcpy(buf,L"Декодер не имеет настраиваемых свойств");break; + +} +MessageBox(NULL,buf,message,MB_OK|MB_ICONERROR); +} +HRESULT GetUnconnectedPin( + IBaseFilter *pFilter, // Pointer to the filter. + PIN_DIRECTION PinDir, // Direction of the pin to find. + IPin **ppPin) // Receives a pointer to the pin. +{ + *ppPin = 0; + IEnumPins *pEnum = 0; + IPin *pPin = 0; + HRESULT hr = pFilter->EnumPins(&pEnum); + if (FAILED(hr)) + { + return hr; + + } + while (pEnum->Next(1, &pPin, NULL) == S_OK) + { + PIN_DIRECTION ThisPinDir; + pPin->QueryDirection(&ThisPinDir); + if (ThisPinDir == PinDir) + { + IPin *pTmp = 0; + hr = pPin->ConnectedTo(&pTmp); + if (SUCCEEDED(hr)) // Already connected, not the pin we want. + { + pTmp->Release(); + } + else // Unconnected, this is the pin we want. + { + pEnum->Release(); + *ppPin = pPin; + return S_OK; + } + } + pPin->Release(); + } + pEnum->Release(); + // Did not find a matching pin. + return E_FAIL; +} + +IPin* GetOutputPin( IBaseFilter *pFilter ) +{ + + IEnumPins *pEnum = 0; + IPin *pPin = 0; + HRESULT hr = pFilter->EnumPins(&pEnum); + if (FAILED(hr)) + { + return NULL; + + } + while (pEnum->Next(1, &pPin, NULL) == S_OK) + { + PIN_DIRECTION ThisPinDir; + pPin->QueryDirection(&ThisPinDir); + if (ThisPinDir == PINDIR_OUTPUT) + { + pEnum->Release(); + return pPin; + } + pPin->Release(); + } + pEnum->Release(); + // Did not find a matching pin. + return NULL; +} + +HRESULT FindPin( + IBaseFilter *pFilter, // Pointer to the filter. + TCHAR* name, + IPin **ppPin) // Receives a pointer to the pin. +{ + + IEnumPins *pEnum = 0; + IPin *pPin = 0; + PIN_INFO pi={0}; + HRESULT hr = pFilter->EnumPins(&pEnum); + if (FAILED(hr)) + { + return hr; + + } + while (pEnum->Next(1, &pPin, NULL) == S_OK) + { + pPin->QueryPinInfo(&pi); + if(lstrcmp(pi.achName,name)==0){ + pEnum->Release(); + *ppPin=pPin; + return S_OK; + } + pPin->Release(); + } + pEnum->Release(); + // Did not find a matching pin. + return E_FAIL; +} + + +BOOL CheckMediaType(IPin* pin,GUID mediatype){ +IEnumMediaTypes* pEnum; +AM_MEDIA_TYPE* mt=NULL; + + +pin->EnumMediaTypes(&pEnum); +while(pEnum->Next(1,&mt,NULL)==S_OK){ + if(mt->majortype==mediatype){ + MyDeleteMediaType(mt); + pEnum->Release(); + return TRUE;} + MyDeleteMediaType(mt); + +} +pEnum->Release(); + +return FALSE; + +} + +BOOL GetSubType(IPin* pin,GUID* pGuid){ +IEnumMediaTypes* pEnum; +AM_MEDIA_TYPE* mt=NULL; +HRESULT hr; + +pin->EnumMediaTypes(&pEnum); +hr=pEnum->Next(1,&mt,NULL); +if(FAILED(hr)){pEnum->Release();return FALSE;} + *pGuid=mt->subtype; + MyDeleteMediaType(mt); + pEnum->Release(); + return TRUE; +} + +BOOL ShowFilterProperties(IBaseFilter* pFilter){ +ISpecifyPropertyPages *pProp; +HRESULT hr = pFilter->QueryInterface(IID_ISpecifyPropertyPages, (void **)&pProp); +if (SUCCEEDED(hr)) +{ + // Get the filter's name and IUnknown pointer. + FILTER_INFO FilterInfo; + hr = pFilter->QueryFilterInfo(&FilterInfo); + IUnknown *pFilterUnk; + pFilter->QueryInterface(IID_IUnknown, (void **)&pFilterUnk); + + // Show the page. + CAUUID caGUID; + pProp->GetPages(&caGUID); + pProp->Release(); + OleCreatePropertyFrame( + NULL, // Parent window + 0, 0, // Reserved + FilterInfo.achName, // Caption for the dialog box + 1, // Number of objects (just the filter) + &pFilterUnk, // Array of object pointers. + caGUID.cElems, // Number of property pages + caGUID.pElems, // Array of property page CLSIDs + 0, // Locale identifier + 0, NULL // Reserved + ); + + // Clean up. + pFilterUnk->Release(); + FilterInfo.pGraph->Release(); + CoTaskMemFree(caGUID.pElems); + return TRUE; +} +return FALSE; +} + +IBaseFilter* GetDownstreamFilter(IPin* PinOut){ +IPin* pin=NULL; + +HRESULT hr; +PIN_INFO pi={0}; + +hr=PinOut->ConnectedTo(&pin); +if(FAILED(hr))return NULL; +hr=pin->QueryPinInfo(&pi); +if(FAILED(hr))goto end_fail; +if(pi.pFilter==NULL)goto end_fail; +return pi.pFilter; + +end_fail: +if(pi.pFilter!=NULL)pi.pFilter->Release(); +if(pin!=NULL)pin->Release(); +return NULL; + +} + +IBaseFilter* FindFileSource(IGraphBuilder* pGraph) +{ + IEnumFilters *pEnum = NULL; + IBaseFilter *pFilter=NULL; + IFileSourceFilter* pSrc=NULL; + ULONG cFetched; + + HRESULT hr = pGraph->EnumFilters(&pEnum); + if (FAILED(hr)) return NULL; + + while(pEnum->Next(1, &pFilter, &cFetched) == S_OK) + { + hr=pFilter->QueryInterface(IID_IFileSourceFilter,(void**)&pSrc); + if(hr==E_NOINTERFACE||pSrc==NULL){ + pFilter->Release(); + continue;} + pSrc->Release(); + pEnum->Release(); + return pFilter; + } + + pEnum->Release(); + return NULL; +} diff --git a/SmallMediaPlayer/DirectShowStuff.h b/SmallMediaPlayer/DirectShowStuff.h new file mode 100644 index 0000000..3b81e2b --- /dev/null +++ b/SmallMediaPlayer/DirectShowStuff.h @@ -0,0 +1,67 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#ifndef DSHOW_STUFF_H +#define DSHOW_STUFF_H + +#include +#include +#include +#include +#include + +#define SOURCE_FILTER L"WM ASF Reader" + +typedef enum { + SYSTEM_ERROR, + PLAY_ERROR, + ERROR_NOPROPERTIES, + ERROR_NOTSUPPORTED + } + ERROR_TYPE; +typedef enum { + MT_AUDIO, + MT_AVI, + MT_MPEG, + MT_MKV}MEDIATYPE; + +typedef struct{ + TCHAR* FilterName; + bool IsSource;} +SPLITTER_DATA; + +const SPLITTER_DATA sdAsfReader={SOURCE_FILTER,true}; +const SPLITTER_DATA sdBassSource={L"DC-Bass Source",true}; +const SPLITTER_DATA sdGretechMp3={L"Gretech MP3 Source Filter",true}; +const SPLITTER_DATA sdAviSource={L"AVI/WAV File Source",true}; +const SPLITTER_DATA sdAviSplitter={L"AVI Splitter",false}; +const SPLITTER_DATA sdGretechAvi={L"Gretech AVI Source Filter",true}; +const SPLITTER_DATA sdMpeg1Splitter={L"MPEG-I Stream Splitter",false}; +const SPLITTER_DATA sdMpeg2Splitter={L"MPEG-2 Splitter",false}; +const SPLITTER_DATA sdMpegSource={L"Mpeg Source",true}; +const SPLITTER_DATA sdMpegSrcGabest={L"MPC - Mpeg Source (Gabest)",true}; +const SPLITTER_DATA sdHaaliSplitter={L"Haali Media Splitter",true}; +const SPLITTER_DATA sdMkvSource={L"Matroska Source",true}; +const SPLITTER_DATA sdNeroSplitter={L"Nero Splitter",false}; + +//this module +void ShowError(HRESULT hr,ERROR_TYPE et); +void MyDeleteMediaType(AM_MEDIA_TYPE *pmt); +void MyFreeMediaType(AM_MEDIA_TYPE& mt); +BOOL ShowFilterProperties(IBaseFilter* pFilter); +BOOL CheckMediaType(IPin* pin,GUID mediatype); +IBaseFilter* FindFilter(TCHAR* FilterName); +HRESULT GetUnconnectedPin( + IBaseFilter *pFilter, // Pointer to the filter. + PIN_DIRECTION PinDir, // Direction of the pin to find. + IPin **ppPin); +HRESULT FindPin( + IBaseFilter *pFilter, // Pointer to the filter. + TCHAR* name, + IPin **ppPin); +IBaseFilter* FindFileSource(IGraphBuilder* pGraph); +IBaseFilter* GetDownstreamFilter(IPin* PinOut); +IPin* GetOutputPin( IBaseFilter *pFilter ) ; +BOOL GetSubType(IPin* pin,GUID* pGuid); + +#endif \ No newline at end of file diff --git a/SmallMediaPlayer/PictureManager.cpp b/SmallMediaPlayer/PictureManager.cpp new file mode 100644 index 0000000..f1b50e5 --- /dev/null +++ b/SmallMediaPlayer/PictureManager.cpp @@ -0,0 +1,240 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#include "PictureManager.h" + +#define COUNT_COVER_MASKS (sizeof(arrCoverMasks)/sizeof(arrCoverMasks[0])) +#define COUNT_PATTERN_MASKS (sizeof(arrPatternMasks)/sizeof(arrPatternMasks[0])) +#define COUNT_WALL_MASKS (sizeof(arrWallMasks)/sizeof(arrWallMasks[0])) + +Bitmap* CurrentCover; +Bitmap* CurrentPattern; +bool fCoverLoaded=false; +bool fPatternLoaded=false; + +TCHAR* arrCoverMasks[]={ + L"cover.jpg", + L"cover.jpeg", + L"*front*.jpg", + L"*front*.jpeg", + L"AlbumArt*Large.jpg", + L"AlbumArt*Large.jpeg", + L"folder.jpg", + L"folder.jpeg", + L"*.jpg", + L"*.jpeg", + L"*.bmp", + L"*.png"}; + +TCHAR* arrPatternMasks[]={ + L"*Ночной ковыль*.bmp", + L"Сиреневый пух.bmp", + L"Японский мотив.bmp", + L"На рыбалку.bmp", +}; + + +BOOL FindPicture(TCHAR* dir,TCHAR* mask,TCHAR* out){ + +HANDLE hSearch; +WIN32_FIND_DATA fd={0}; +TCHAR find[MAX_PATH]; + +lstrcpy(find,dir); + +lstrcat(find,mask); +hSearch=FindFirstFile(find,&fd); +if(hSearch==INVALID_HANDLE_VALUE)return FALSE; +lstrcpy(out,dir); + +lstrcat(out,fd.cFileName); +return TRUE; + +} + +void GetFileDirectory(wchar_t* path,wchar_t* out){ + int i=0; + int k=0; + int LastIndex=0; + TCHAR buf[MAX_PATH]; + StringCchCopy(buf,MAX_PATH,path); + while(1){ + if(buf[i]==L'\\')LastIndex=i; + if(buf[i]==0)break; + i++; + } + lstrcpy(out,L""); + buf[LastIndex+1]=0; + lstrcat(out,buf); + +} + +void GetFileDirectoryA(char* path,char* out){ + int i=0; + int k=0; + int LastIndex=0; + char buf[MAX_PATH]; + lstrcpyA(buf,path); + while(1){ + if(buf[i]=='\\')LastIndex=i; + if(buf[i]==0)break; + i++; + } + lstrcpyA(out,""); + buf[LastIndex+1]=0; + lstrcatA(out,buf); + +} + + +void LoadCover(TCHAR* file){ + + UnloadCover(); + if(lstrcmp(file,L"")==0){return;} + + CurrentCover=new Bitmap(file); + fCoverLoaded=true; + +} + +bool DrawCover(HDC hDC,RECT* rc){ + Graphics* g; + int w,h; + int wd,hd; + float factor; +if(fCoverLoaded==false)return false; +g=new Graphics(hDC); +w=CurrentCover->GetWidth(); +h=CurrentCover->GetHeight(); + +wd=rc->right; +factor=wd/(float)w; +hd=h*factor; +if(hd>(rc->bottom)){ +hd=rc->bottom; +factor=hd/(float)h; +wd=w*factor; +} + g->DrawImage(CurrentCover,0,0,wd,hd); + +delete g; +return true; + +} + +void UnloadCover(){ +if(fCoverLoaded==false)return; +delete CurrentCover; +fCoverLoaded=false; +} + +void LoadPattern(TCHAR* file){ + + UnloadPattern(); + + if(lstrcmp(file,L"")==0){return;} + + CurrentPattern=Bitmap::FromFile(file); + + if(CurrentPattern->GetHeight()==0||CurrentPattern->GetWidth()==0)return; + + fPatternLoaded=true; + +} + +void UnloadPattern(){ +if(fPatternLoaded==false)return; +delete CurrentPattern; +fPatternLoaded=false; +} + +void DrawPattern(HDC hDC,RECT* rc){ + +Graphics* g; + int w,h; + int wd,hd; + float factor; +if(fPatternLoaded==false)return; +g=new Graphics(hDC); +w=CurrentPattern->GetWidth(); +h=CurrentPattern->GetHeight(); + +wd=rc->right; +factor=wd/(float)w; +hd=h*factor; +if(hd>(rc->bottom)){ +hd=rc->bottom; +factor=hd/(float)h; +wd=w*factor; +} + g->DrawImage(CurrentPattern,0,0,wd,hd); + +delete g; +} + +void GetFileCover(TCHAR* file,TCHAR* out){ +TCHAR dir[MAX_PATH]; +TCHAR buf[MAX_PATH]; +TCHAR srcdir[MAX_PATH]; +BOOL res; +int i; + +GetFileDirectory(file,srcdir); +lstrcpy(dir,srcdir); + +for(i=0;i +#define STRSAFE_NO_DEPRECATE +#include +#include +#include +using namespace Gdiplus; + +//this module!!! +extern Bitmap* CurrentCover; +extern bool fCoverLoaded; + +BOOL FindPicture(TCHAR* dir,TCHAR* mask,TCHAR* out); + +void LoadCover(TCHAR* file); +bool DrawCover(HDC hDC,RECT* rc); +void UnloadCover(); +void GetFileCover(TCHAR* file,TCHAR* out); +void GetPattern(TCHAR* out); +void DrawPattern(HDC hDC,RECT* rc); +void UnloadPattern(); +void LoadPattern(TCHAR* file); diff --git a/SmallMediaPlayer/PlayListEditor.cpp b/SmallMediaPlayer/PlayListEditor.cpp new file mode 100644 index 0000000..144e6c9 --- /dev/null +++ b/SmallMediaPlayer/PlayListEditor.cpp @@ -0,0 +1,1340 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ + +#include "PlayListEditor.h" +/* +10.09.2017 - Выделение текущего элемента в списке воспроизведения '>' +*/ + +extern void ProcessMessages(); +extern void GetFileDirectoryA(char* path,char* out); +extern bool pls_SortReverse; +extern HWND hPlaybackDlg; + +HWND PlayList; +HWND hlstBuffer=NULL; +UINT CountTracks=0; +UINT CurrentTrack=0; +bool fIncludeImages=false; +TCHAR* Extensions[COUNT_EXTENSIONS]; +PLAYBACK_MODE CurrMode=NORMAL; +TAGS_GENERIC CurrFileTags; +bool fCurrFileTags=false; +TAGS_GENERIC OpenedFileTags; +bool fOpenedFileTags=false; +HICON hDirIcon=NULL; +HICON hMusicIcon=NULL; +int indexDirIcon=0; +int indexMusicIcon=0; +HIMAGELIST ImageList=NULL; + +TCHAR* ImageExtensions[]={ + L"jpg", L"jpeg",L"bmp",L"png",L"gif"}; + + TYPE_ICON_INFO arrTypeIcons[COUNT_TYPE_ICONS]={ + {L"mp3",0,0},{L"flac",0,0},{L"wv",0,0},{L"wma"}, + {L"mpg",0,0},{L"mpeg",0,0},{L"wmv"}, + {L"avi",0,0},{L"mkv",0,0},{L"flv",0,0}, + {L"cda",0,0}, + {L"bmp",0,0},{L"jpg",0,0},{L"jpeg",0,0},{L"gif",0,0},{L"png",0,0} + }; + +TCHAR* GetShortName(TCHAR* fullname){ +TCHAR* p; +int i; +p=fullname; +for(i=0;i=(int)CountTracks||n<0)return FALSE; + +item.iItem=n; +item.iSubItem=4; +item.mask=LVIF_TEXT; +item.pszText=out; +item.cchTextMax=MAX_PATH; +//EnterCriticalSection(&csPlaylistAccess); +res=ListView_GetItem( PlayList, &item); +//LeaveCriticalSection(&csPlaylistAccess); +return (res); +} + +BOOL GetPlaylistElementA(int n,char* out){ +BOOL res; +TCHAR buf[MAX_PATH]=L""; +res=GetPlaylistElement(n,buf); +if(res==FALSE)return FALSE; +res=WideCharToMultiByte(CP_ACP,0,buf,MAX_PATH,out,MAX_PATH,NULL,NULL); +if(res==FALSE)return FALSE; +return TRUE; +} + +void AddPlaylistElement(WCHAR* fname){ + if(CountTracks>=1000000)return; +InsertPlaylistElement(fname,CountTracks); +} + + + +void InsertPlaylistElement(WCHAR* fname,UINT pos){ + + TAGS_GENERIC info={0}; + LVITEM item={0}; + int iIcon; + BOOL res=FALSE; + WCHAR buf[1000]=L""; + TCHAR ext[10]; + LONG lRes; + + if(pos>CountTracks)pos=CountTracks; + if(pos<0)pos=0; + if(pos<=CurrentTrack)CurrentTrack++; + GetFileExtension(fname,ext); +if(lstrcmp(ext,L"M3U")==0||lstrcmp(ext,L"m3u")==0||lstrcmp(ext,L"lst")==0||lstrcmp(ext,L"LST")==0){ +LoadTextPlaylist(fname); +return; +} + + +iIcon=GetTypeIcon(ext); + +if(fCurrFileTags==true){ +info=CurrFileTags;fCurrFileTags=false; +goto Use_tags; +} + res=ReadTagsv2(fname,&info); + if(lstrcmpi(ext,L"flac")==0&&(res==FALSE)){ + res=ReadFlacTags(fname,&info); + } + + if(res==FALSE)res=ReadApeTags(fname,&info); + if(res==FALSE){ res=ReadTagsV1(fname,&info);} + + + +if(res==FALSE){//if there's no data... +item.iItem=pos; +item.mask=LVIF_TEXT|LVIF_IMAGE; +item.iImage=iIcon; +item.pszText=GetShortName(fname); +if(lstrcmp(item.pszText,L"")==0)item.pszText=fname; + +lRes=ListView_InsertItem(PlayList,&item); +if(lRes==-1){return;} + + } + +else{//read tags +Use_tags: + StringCchCopyN(buf,1000,info.title,512); + if(lstrcmp(buf,L"")==0){ + item.iItem=pos; +item.mask=LVIF_TEXT|LVIF_IMAGE; +item.iImage=iIcon; +item.pszText=GetShortName(fname); +if(lstrcmp(item.pszText,L"")==0)item.pszText=fname; +lRes=ListView_InsertItem(PlayList,&item); +if(lRes==-1){return;} + } + else{ +item.iItem=pos; +item.mask=LVIF_TEXT|LVIF_IMAGE; +item.iImage=iIcon; +item.pszText=buf; +lRes=SendMessage(PlayList,LVM_INSERTITEM,0,(LPARAM)&item); +if(lRes==-1){return;} + } +StringCchCopyN(buf,1000,info.artist,512); +item.iItem=pos; +item.iSubItem=1; +item.mask=LVIF_TEXT; +item.pszText=buf; +res=SendMessage(PlayList,LVM_SETITEM,0,(LPARAM)&item); +StringCchCopyN(buf,1000,info.album,512); +item.iItem=pos; +item.iSubItem=2; +item.mask=LVIF_TEXT; +item.pszText=buf; +res=SendMessage(PlayList,LVM_SETITEM,0,(LPARAM)&item); +StringCchCopyN(buf,1000,info.year,10); +item.iItem=pos; +item.iSubItem=3; +item.mask=LVIF_TEXT; +item.pszText=buf; +res=SendMessage(PlayList,LVM_SETITEM,0,(LPARAM)&item); +} + + +//insert full path +item.iItem=pos; +item.iSubItem=4; +item.mask=LVIF_TEXT; +item.pszText=fname; +res=ListView_SetItem(PlayList,&item); +if(res==FALSE){return;} +CountTracks++; + +} + +void AddPlaylistElementA(char* fname){ +TCHAR filename[MAX_PATH]=L""; + MultiByteToWideChar(CP_ACP,0,fname,MAX_PATH,filename,MAX_PATH); + AddPlaylistElement(filename); +} + +/* +void InsertPlaylistGroup(WCHAR* fname,int pos,bool fShortName=false){ + LVITEM item={0}; + WCHAR buf[MAX_PATH]; + int c; +StringCchCopy(buf,MAX_PATH,fname); +c=lstrlen(buf); +if(buf[c-1]==L'\\'||buf[c-1]==L'/')buf[c-1]=0; +item.iItem=pos; +item.mask=LVIF_TEXT|LVIF_IMAGE; +item.iImage=indexDirIcon; +if(fShortName==false){ + item.pszText=GetShortName(buf); +} +else{ + item.pszText=buf; +} +if(lstrcmp(item.pszText,L"")==0)item.pszText=fname; +ListView_InsertItem(PlayList,&item); +CountTracks++; +}*/ + +int GetPlaylistSelectedElement(){ + int res; + //EnterCriticalSection(&csPlaylistAccess); +res=ListView_GetSelectionMark(PlayList); +//LeaveCriticalSection(&csPlaylistAccess); +return res; +} + +BOOL IsPlaylistItemSelected(int n){ +UINT res; +if(n>=(int)CountTracks||n<0)return FALSE; + +res=ListView_GetItemState(PlayList,n,LVIS_SELECTED); + +if(res&LVIS_SELECTED)return TRUE; +else return FALSE; + +} +void SetPlaylistHighlight(int i){ + if(i>=(int)CountTracks||i<0)return; +int j; + +ListView_SetItemState(PlayList,i,LVIS_SELECTED,LVIS_SELECTED); +for(j=0;j<(int)CountTracks;j++){ +if(j==i)continue; +ListView_SetItemState(PlayList,j,0,LVIS_SELECTED); +} +} +void SetPlaylistSelectedElement(int i){ + if(i>=(int)CountTracks||i<0)return; +ListView_SetItemState(PlayList,i,LVIS_SELECTED,LVIS_SELECTED); +} + +void ClearPlaylist(){ + + ListView_DeleteAllItems(PlayList); +CountTracks=0; +CurrentTrack=0; +} + +void DeletePlaylistElement(int n){ +if(((UINT)n)>=CountTracks||n<0)return; +ListView_DeleteItem( PlayList, n); +if(n<=(int)CurrentTrack)CurrentTrack--; +CountTracks--; + +} + + +void GetCurrTrackShortName(TCHAR* str){ +LVITEM item={0}; +TCHAR buf[256]; +TCHAR * p = NULL; +StringCchCopy(str,256,L""); +if(PlayerState==FILE_NOT_LOADED)return; +if(CountTracks==0)return; + item.mask=LVIF_TEXT; + item.pszText=buf; + item.cchTextMax=256; + item.iItem=CurrentTrack; + item.iSubItem=0; + + ListView_GetItem(PlayList,&item); + + //*** + if(buf[0]=='>')p=buf+1;//удалить символ текущего трека + else p=buf; + StringCchCopy(str,256,p); + //*** + + item.iSubItem=1; + StringCchCopy(buf,256,L""); + + if(ListView_GetItem(PlayList,&item)!=FALSE && lstrcmp(buf,L"")!=0){ + StringCchCat(str,256,L" - "); + StringCchCat(str,256,buf); + } + + +} + +void SetCurrentTrackIndicator(BOOL add) +{ + LVITEM item={0}; +TCHAR str[256]; +TCHAR buf[256]; +TCHAR * p = NULL; + +if(CountTracks==0)return; + + //получить имя текущего трека + item.mask=LVIF_TEXT; + item.pszText=buf; + item.cchTextMax=256; + item.iItem=CurrentTrack; + item.iSubItem=0; + ListView_GetItem(PlayList,&item); + + if(add==FALSE){ + //удалить знак + if(buf[0]=='>')p=buf+1; + else p = buf; + StringCchCopy(str,256,p); + + }else{ + //добавить знак + StringCchCopy(str,256,L""); + if(buf[0]!='>')StringCchCat(str,256,L">"); + StringCchCat(str,256,buf); + } + + //установить имя текущего трека + item.pszText=str; + ListView_SetItem(PlayList,&item); + +} + + +void PlayTrackByNumber(int n){ + TCHAR str[256]; + TCHAR ext[10]=L""; + BOOL res=FALSE; + +if(n<0)return; +if(((UINT)n)>=CountTracks)return; + if(fOpenedFileTags==true){ + fOpenedFileTags=false; + memset(&OpenedFileTags,0,sizeof(TAGS_GENERIC)); + } + + //*** + SetCurrentTrackIndicator(FALSE); + //*** + + CurrentTrack=n; + + SetPlaylistHighlight(CurrentTrack); + GetPlaylistElement(n,str); + if(lstrcmp(str,L"")==0){PlayNextTrack();return;} + GetFileExtension(str,ext); + res=ReadTagsv2(str,&OpenedFileTags); + if(lstrcmpi(ext,L"flac")==0&&res==FALSE){ + res=ReadFlacTags(str,&OpenedFileTags); + } + if(res==FALSE)res=ReadApeTags(str,&OpenedFileTags); + if(res==FALSE){ res=ReadTagsV1(str,&OpenedFileTags);} + if(res!=FALSE){fOpenedFileTags=true;} else {fOpenedFileTags=false;} + + + PlayFile(str); + if(IsPlayingCDA==true)EnableWindow(hVolume,FALSE); + else EnableWindow(hVolume,TRUE); + UpdateLength(); + + //*** + SetCurrentTrackIndicator(TRUE); + //*** + + RunTimer(); + + Progress.SetTrackPosition(0); + +} + +void PlayNextTrack(){ + int size; + RECT rc={0}; + TCHAR str[MAX_PATH]=L""; + + //*** + SetCurrentTrackIndicator(FALSE); + //*** + ProcessMessages(); + + switch(CurrMode){ +case NORMAL:case REPEAT_LIST:InterlockedIncrement((volatile LONG*)&CurrentTrack);break; +case REPEAT_FILE: PlayTrackByNumber(CurrentTrack);return; +case RANDOM:CurrentTrack=rand()%CountTracks;break; + } + + + if(CurrentTrack>=CountTracks){ + + CurrentTrack=0; + if(CurrMode==REPEAT_LIST){PlayTrackByNumber(CurrentTrack);} + else {StopTimer(); + DisableFullScreen(); + } + return;} + + //scroll playlist + ListView_GetItemRect(PlayList,0,&rc,LVIR_SELECTBOUNDS); + size=rc.bottom-rc.top; + ListView_Scroll(PlayList,0,size); + + SetPlaylistHighlight(CurrentTrack); + PlayTrackByNumber(CurrentTrack); + +} + + +void AddDirectory(wchar_t* dir,wchar_t* ext,HWND hlbt){ + + wchar_t mask[1024]; + TCHAR fname[1024]; + + HANDLE hSearch; + + WIN32_FIND_DATAW fd={0}; + int c=0; + LONG lRes; + + + StringCchCopy(mask,1024,dir); + StringCchCat(mask,1024,L"*."); + StringCchCat(mask,1024,ext); + +//find items and insert into temp list + hSearch=FindFirstFileW(mask,&fd); + if(hSearch==INVALID_HANDLE_VALUE){return;} + StringCchCopy(fname,1024,dir); + StringCchCat(fname,1024,fd.cFileName); + + SendMessage(hlbt,LB_ADDSTRING,0,(LONG)fname); + + c++; + + while(FindNextFileW(hSearch,&fd)){ + StringCchCopy(fname,1024,dir); + StringCchCat(fname,1024,fd.cFileName); + +lRes=SendMessage(hlbt,LB_ADDSTRING,0,(LONG)fname); +if(lRes==LB_ERR){FindClose(hSearch);return;} +if(lRes==LB_ERRSPACE){FindClose(hSearch);return;} +c++; + } + FindClose(hSearch); + + } + + + +void Playlist_AddDirectory(TCHAR* dir){ +HANDLE hSearch; + +WIN32_FIND_DATA fd={0}; +int i,c; +LRESULT res; +TCHAR mask[MAX_PATH]=L""; +TCHAR buf[MAX_PATH]=L""; + +HWND hlbt=CreateWindowW(L"LISTBOX",L"TEMP",LBS_SORT,0,0,200,200,NULL,NULL,GetModuleHandle(NULL),0); +if(hlbt==NULL){MessageBox(0,L"Не удалось создать список",0,MB_OK|MB_ICONERROR);return;} +for(i=0;i=1000000)return; +StringCchCopy(mask,MAX_PATH,dir); +StringCchCat(mask,MAX_PATH,L"*"); +hSearch=FindFirstFile(mask,&fd); +if(hSearch==INVALID_HANDLE_VALUE)return; +while(1){ + + if(lstrcmp(fd.cFileName,L".")!=0 && lstrcmp(fd.cFileName,L"..")!=0 ){ + + if(fd.dwFileAttributes & (DWORD)FILE_ATTRIBUTE_DIRECTORY){ + StringCchCopy(buf,MAX_PATH,dir); + StringCchCat(buf,MAX_PATH,fd.cFileName); + StringCchCat(buf,MAX_PATH,L"\\"); + + Playlist_AddDirectory(buf); + + } + } + if(FindNextFile(hSearch,&fd)==FALSE)break; + +} +FindClose(hSearch); + +} + + + +BOOL ReadTagsV1(TCHAR* file,TAGS_GENERIC* out){ + +HANDLE hFile; +DWORD dwCount; +BOOL res; +int i; +MP3TAG_V1 tags={0}; + +memset(&tags,0,sizeof(MP3TAG_V1)); +hFile=CreateFile(file,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); +if(hFile==INVALID_HANDLE_VALUE)return FALSE; + + +SetFilePointer(hFile,-128,NULL,FILE_END); +res=ReadFile(hFile,&tags,sizeof(MP3TAG_V1),&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +CloseHandle(hFile); + +if(tags.title[0]==0)return FALSE; +if(tags.sig[0]=='T'&&tags.sig[1]=='A'&&tags.sig[2]=='G'){ + //delete spaces + for(i=29;i>=0;i--){ + if(tags.title[i]==' '){tags.title[i]=0;continue;} + if(tags.title[i]!=0)break; + } + for(i=29;i>=0;i--){ + if(tags.artist[i]==' '){tags.artist[i]=0;continue;} + if(tags.artist[i]!=0)break; + } + for(i=29;i>=0;i--){ + if(tags.album[i]==' '){tags.album[i]=0;continue;} + if(tags.album[i]!=0)break; + } + for(i=3;i>=0;i--){ + if(tags.year[i]==' '){tags.year[i]=0;continue;} + if(tags.year[i]!=0)break; + } + MultiByteToWideChar(CP_ACP,0,tags.title,30,out->title,512); + MultiByteToWideChar(CP_ACP,0,tags.artist,30,out->artist,512); + MultiByteToWideChar(CP_ACP,0,tags.album,30,out->album,512); + MultiByteToWideChar(CP_ACP,0,tags.year,4,out->year,10); + MultiByteToWideChar(CP_ACP,0,tags.comment,30,out->comments,1024); + out->type=TAG_ID3V1; + return TRUE; +} +else return FALSE; + +} + +BOOL ReadTagsV1A(char* file,TAGS_GENERIC* out){ +WCHAR filename[MAX_PATH]=L""; +if(MultiByteToWideChar(CP_ACP,0,file,MAX_PATH,filename,MAX_PATH)==0) +return FALSE; +else return ReadTagsV1(filename,out); +} + +BOOL IsPathAbsolute(char* path){ +int i,c; +c=lstrlenA(path); +for(i=0;i=MAX_PATH-2)continue; +str[i]=c; +i++; +} + +str[i]=0; +if(lstrcmpA(str,"")==0)goto end; +if(str[0]=='#')goto end; + +if(IsPathAbsolute(str)==FALSE){ +StringCchCopyA(str_path,520,str_dir); +StringCchCatA(str_path,520,str); +AddPlaylistElementA(str_path); +}else{ + AddPlaylistElementA(str); +} + +end: +CloseHandle(hFile); +} + +void LoadTextPlaylistA(char* file){ +TCHAR filename[MAX_PATH]=L""; + MultiByteToWideChar(CP_ACP,0,file,MAX_PATH,filename,MAX_PATH); + LoadTextPlaylist(filename); +} + + +void ReadPlaylistTags(char* _str){ + +char* p; +char str[512]=""; + +memset(&CurrFileTags,0,sizeof(TAGS_GENERIC)); +StringCchCopyA(str,512,_str); +p=strtok(str,"~"); +if(p==NULL)return; +if(lstrcmpA(p,"#TAGS")!=0)return; +p=strtok(NULL,"~"); +if(p==NULL)return; +MultiByteToWideChar(CP_ACP,0,p,512,CurrFileTags.title,512); +fCurrFileTags=true; +p=strtok(NULL,"~"); +if(p==NULL)return; +MultiByteToWideChar(CP_ACP,0,p,512,CurrFileTags.artist,512); +p=strtok(NULL,"~"); +if(p==NULL)return; +MultiByteToWideChar(CP_ACP,0,p,512,CurrFileTags.album,512); +p=strtok(NULL,"~"); +if(p==NULL)return; +MultiByteToWideChar(CP_ACP,0,p,512,CurrFileTags.year,512); +} + +void WritePlaylistTags(HANDLE hFile,int index){ +char str[300]=""; +char * p = NULL; +LVITEMA item={0}; +DWORD dwCount; + +WriteFile(hFile,"#TAGS~",6,&dwCount,NULL); +item.iItem=index; +item.iSubItem=0; +item.mask=LVIF_TEXT; +item.pszText=str; +item.cchTextMax=300; + +SendMessageA(PlayList,LVM_GETITEMTEXTA,index,(LPARAM)&item); + +//*** +if(str[0]=='>')p=str+1;//удалить символ текущего трека +else p=str; +WriteFile(hFile,p,lstrlenA(p),&dwCount,NULL); +//*** + +if(lstrlenA(str)==0)WriteFile(hFile," ",1,&dwCount,NULL); +StringCchCopyA(str,300,""); +WriteFile(hFile,"~",1,&dwCount,NULL); +item.iSubItem=1; +SendMessageA(PlayList,LVM_GETITEMTEXTA,index,(LPARAM)&item); +WriteFile(hFile,str,lstrlenA(str),&dwCount,NULL); +if(lstrlenA(str)==0)WriteFile(hFile," ",1,&dwCount,NULL); +StringCchCopyA(str,300,""); +WriteFile(hFile,"~",1,&dwCount,NULL); +item.iSubItem=2; +SendMessageA(PlayList,LVM_GETITEMTEXTA,index,(LPARAM)&item); +WriteFile(hFile,str,lstrlenA(str),&dwCount,NULL); +if(lstrlenA(str)==0)WriteFile(hFile," ",1,&dwCount,NULL); +StringCchCopyA(str,300,""); +WriteFile(hFile,"~",1,&dwCount,NULL); +item.iSubItem=3; +SendMessageA(PlayList,LVM_GETITEMTEXTA,index,(LPARAM)&item); +WriteFile(hFile,str,lstrlenA(str),&dwCount,NULL); +if(lstrlenA(str)==0)WriteFile(hFile," ",1,&dwCount,NULL); +WriteFile(hFile,"\r\n",2,&dwCount,NULL); + +} + + +void SaveTextPlaylist(TCHAR* file){ +HANDLE hFile; +DWORD dwCount; +char str[MAX_PATH]=""; +BOOL res; +char c; +UINT i=0; +int j=0; +hFile=CreateFile(file,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); +if(hFile==INVALID_HANDLE_VALUE)return; + +for(i=0;iitem_count;i++){ + ReadFile(hFile,&item,sizeof(APE_ITEM),&dwCount,NULL); + j=0; + while(1){//read key + ReadFile(hFile,&(key[j]),1,&dwCount,NULL); + if(key[j]==0)break; + j++; + if(j>=256)break; + } + //read value + if(item.len>=511)item.len=510; + ReadFile(hFile,value,item.len,&dwCount,NULL); + value[item.len]=0; + //what we have: + + if(lstrcmpiA(key,"Title")==0){ + MultiByteToWideChar(CP_UTF8,0,value,512,out->title,512); + continue; + } + if(lstrcmpiA(key,"Artist")==0){ + MultiByteToWideChar(CP_UTF8,0,value,512,out->artist,512); + continue; + } + if(lstrcmpiA(key,"Album")==0){ + MultiByteToWideChar(CP_UTF8,0,value,512,out->album,512); + continue; + } + if(lstrcmpiA(key,"Composer")==0){ + MultiByteToWideChar(CP_UTF8,0,value,512,out->composer,512); + continue; + } + if(lstrcmpiA(key,"Comment")==0){ + MultiByteToWideChar(CP_UTF8,0,value,512,out->comments,512); + continue; + } + + if(lstrcmpiA(key,"Year")==0){ + MultiByteToWideChar(CP_UTF8,0,value,10,out->year,10); + continue; + } + if(lstrcmpiA(key,"Related")==0){ + MultiByteToWideChar(CP_UTF8,0,value,512,out->URL,512); + continue; + } + +} +} + + +BOOL ReadApeTagsA(char* file,TAGS_GENERIC* out){ + TCHAR fname[MAX_PATH]=L""; + if(MultiByteToWideChar(CP_ACP,0,file,MAX_PATH,fname,MAX_PATH)!=0) + {return ReadApeTags(fname,out);} + else return FALSE; +} + + +BOOL ReadApeTags(TCHAR* file,TAGS_GENERIC* out){ +HANDLE hFile; +DWORD dwCount; +BOOL res; +APE_HEADER header; + +hFile=CreateFile(file,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); +if(hFile==INVALID_HANDLE_VALUE)return FALSE; +SetFilePointer(hFile,-(int)sizeof(APE_HEADER),NULL,FILE_END); +res=ReadFile(hFile,&header,sizeof(APE_HEADER),&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +if(dwCount!=sizeof(APE_HEADER)){CloseHandle(hFile);return FALSE;} +if((header.sig[0]=='A'&&header.sig[1]=='P'&&header.sig[2]=='E'&& +header.sig[3]=='T'&&header.sig[4]=='A'&&header.sig[5]=='G'&&header.sig[6]=='E'&& +header.sig[7]=='X')==false){goto Read_from_begin;} +SetFilePointer(hFile,-(int)header.size,NULL,FILE_END); +ReadApeItems(hFile,&header,out); +CloseHandle(hFile); +out->type=TAG_APE; +return TRUE; + //end read tags(end) +Read_from_begin: + +SetFilePointer(hFile,0,NULL,FILE_BEGIN); +res=ReadFile(hFile,&header,sizeof(APE_HEADER),&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +if(dwCount!=sizeof(APE_HEADER)){CloseHandle(hFile);return FALSE;} +if((header.sig[0]=='A'&&header.sig[1]=='P'&&header.sig[2]=='E'&& +header.sig[3]=='T'&&header.sig[4]=='A'&&header.sig[5]=='G'&&header.sig[6]=='E'&& +header.sig[7]=='X')==false){CloseHandle(hFile);return FALSE;} +ReadApeItems(hFile,&header,out); + +CloseHandle(hFile); +out->type=TAG_APE; +return TRUE; +} + +BOOL ReadFlacTagsA(char* file,TAGS_GENERIC* out){ +TCHAR fname[MAX_PATH]=L""; + if(MultiByteToWideChar(CP_ACP,0,file,MAX_PATH,fname,MAX_PATH)!=0) + {return ReadFlacTags(fname,out);} + else return FALSE; +} + +BOOL ReadFlacTags(TCHAR* file,TAGS_GENERIC* out){ +HANDLE hFile; +DWORD dwCount; +BOOL res; +char buf[1024]=""; +char name[1024]=""; +char value[1024]=""; +FLAC_BLOCK_HEADER header={0}; +char sig[5]=""; +int i,j; +ULONG c,n; +DWORD_UNION length={0}; + +hFile=CreateFile(file,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); +if(hFile==INVALID_HANDLE_VALUE)return FALSE; +i=0; +while(1){ +res=ReadFile(hFile,sig,4,&dwCount,NULL); +SetFilePointer(hFile,i,NULL,FILE_BEGIN); +res=ReadFile(hFile,sig,4,&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +if(dwCount!=4){CloseHandle(hFile);return FALSE;} +if(lstrcmpA(sig,FLAC_SIGNATURE)==0)break; +i++; +if(i>=99999999){CloseHandle(hFile);return FALSE;} +} + +res=ReadFile(hFile,&header,sizeof(header),&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +length.bytes[2]=header.length[0]; +length.bytes[1]=header.length[1]; +length.bytes[0]=header.length[2]; +SetFilePointer(hFile,(LONG)length.dword,NULL,FILE_CURRENT); + +while(1){ +res=ReadFile(hFile,&header,sizeof(header),&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +if(dwCount!=sizeof(header)){CloseHandle(hFile);return FALSE;} +length.dword=0; +length.bytes[2]=header.length[0]; +length.bytes[1]=header.length[1]; +length.bytes[0]=header.length[2]; + +if(header.type==FLAC_VORBISCOMMENT||header.type==FLAC_VORBISCOMMENT2){break;} +SetFilePointer(hFile,length.dword,NULL,FILE_CURRENT); +} +ReadFile(hFile,&n,sizeof(n),&dwCount,NULL); +SetFilePointer(hFile,n,NULL,FILE_CURRENT); +ReadFile(hFile,&n,sizeof(n),&dwCount,NULL); + +for(i=0;i=1024)break; + name[j]=buf[j]; + j++; + } + name[j]=0; + + if(j>=1024)continue; + StringCchCopyA(value,1024,&(buf[j+1])); + + if(lstrcmpiA(name,"title")==0){ + MultiByteToWideChar(CP_UTF8,0,value,1024,out->title,512); + continue; + } + if(lstrcmpiA(name,"artist")==0){ + MultiByteToWideChar(CP_UTF8,0,value,1024,out->artist,512); + continue; + } + if(lstrcmpiA(name,"album")==0){ + MultiByteToWideChar(CP_UTF8,0,value,1024,out->album,512); + continue; + } + if(lstrcmpiA(name,"date")==0){ + MultiByteToWideChar(CP_UTF8,0,value,10,out->year,10); + continue; + } + if(lstrcmpiA(name,"description")==0){ + MultiByteToWideChar(CP_UTF8,0,value,1024,out->comments,1024); + continue; + } + if(lstrcmpiA(name,"contact")==0){ + MultiByteToWideChar(CP_UTF8,0,value,1024,out->URL,512); + continue; + } + +} +CloseHandle(hFile); +out->type=TAG_FLAC; +return TRUE; +} + + +void ReverseWCHAR(WCHAR* c){ + WORD_UNION extractor={0}; + WORD_UNION packer={0}; + extractor.w=(WORD)*c; + packer.b[0]=extractor.b[1]; + packer.b[1]=extractor.b[0]; + *c=(WCHAR)packer.w; +} + + +BOOL ReadTagsv2A(char* file,TAGS_GENERIC* out){ +TCHAR fname[MAX_PATH]=L""; + if(MultiByteToWideChar(CP_ACP,0,file,MAX_PATH,fname,MAX_PATH)!=0) + {return ReadTagsv2(fname,out);} + else return FALSE; +} +BOOL ReadTagsv2(TCHAR* fname,TAGS_GENERIC* out){ +HANDLE hFile=0; +DWORD dwCount=0; +BOOL res=0; +BOOL unsync=FALSE; +ID32_HEADER header={0}; +DWORD_UNION extractor={0}; +DWORD_UNION packer={0}; +ID32_EXTHEADER* pextheader=0; +ID32_FRAME_HEADER fh={0}; +char* pSourceTags=NULL;DWORD SourceSize=0; +char* pOutputTags=NULL;DWORD OutputRealSize=0; +char buf[1024]=""; +TCHAR wbuf[1024]=L""; +WORD BOM=0; + +DWORD i=0,j=0; +//fwprintf(f,L"start read tags, file: %s\n",fname); +memset(&extractor,0,sizeof(DWORD));memset(&packer,0,sizeof(DWORD)); +memset(out,0,sizeof(TAGS_GENERIC)); + +hFile=CreateFile(fname,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0); +if(hFile==INVALID_HANDLE_VALUE)return FALSE; +res=ReadFile(hFile,&header,sizeof(ID32_HEADER),&dwCount,NULL); +if(res==FALSE){CloseHandle(hFile);return FALSE;} +if((header.sig[0]=='I'&&header.sig[1]=='D'&&header.sig[2]=='3')==FALSE) +{CloseHandle(hFile);return FALSE;} +if(header.ver[0]>0x03){CloseHandle(hFile);return FALSE;} +extractor.bytes[0]=header.size[0]; +extractor.bytes[1]=header.size[1]; +extractor.bytes[2]=header.size[2]; +extractor.bytes[3]=header.size[3]; + +packer.bfe.byte1=extractor.bf.byte4;packer.bfe.byte2=extractor.bf.byte3; +packer.bfe.byte3=extractor.bf.byte2;packer.bfe.byte4=extractor.bf.byte1; +packer.bfe.dummy=0; + +SourceSize=packer.dword; + +pSourceTags=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SourceSize); +if(pSourceTags==NULL){CloseHandle(hFile);return FALSE;} +ReadFile(hFile,pSourceTags,SourceSize,&dwCount,NULL); +pOutputTags=(char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,SourceSize); +if(pOutputTags==NULL){ + CloseHandle(hFile); + HeapFree(GetProcessHeap(),0,pSourceTags); + return FALSE;} + +j=0; +for(i=0;i<=SourceSize-3;i++){ + if((header.flags&ID32F_SYNC)>0){ + if(pSourceTags[i]==0xFF&&pSourceTags[i+1]==0&&((pSourceTags[i+2]&ID32_SYNC_MASK)>0)){ + pOutputTags[j]=pSourceTags[i];pOutputTags[j+1]=pSourceTags[i+2]; + i+=2;j+=2;continue; + } + if(pSourceTags[i]==0xFF&&pSourceTags[i+1]==0&&pSourceTags[i+2]==0){ + pOutputTags[j]=(char)0xFF;pOutputTags[j+1]=0; + i+=2;j+=2;continue; + } + + } + pOutputTags[j]=pSourceTags[i];j++; + +} +pOutputTags[j]=pSourceTags[i];j++;i++; +pOutputTags[j]=pSourceTags[i];j++;i++; + +OutputRealSize=j; + +HeapFree(GetProcessHeap(),0,pSourceTags);pSourceTags=0; +i=0; +if((header.flags&ID32F_EXTHEADER)!=0){ +pextheader=(ID32_EXTHEADER*)&(pOutputTags[i]); +extractor.dword=pextheader->size; +packer.bytes[0]=extractor.bytes[3];packer.bytes[1]=extractor.bytes[2]; +packer.bytes[2]=extractor.bytes[1];packer.bytes[3]=extractor.bytes[0]; +if(packer.dword>=20)packer.dword=10; +i+=(4+packer.dword); +} + +while(1){//read frames + +if(i>=OutputRealSize)break; +memcpy(&fh,&(pOutputTags[i]),sizeof(ID32_FRAME_HEADER)); +StringCchCopyNA(buf,1024,(char*)fh.ID,4); +//fprintf(f,"Frame:%s\n",fh.ID); +if(lstrcmpA((char*)fh.ID,"")==0)break; +extractor.dword=fh.size; +packer.bytes[0]=extractor.bytes[3]; +packer.bytes[1]=extractor.bytes[2]; +packer.bytes[2]=extractor.bytes[1]; +packer.bytes[3]=extractor.bytes[0]; +if(i+packer.dword>OutputRealSize+1)break; +i+=10; + + +if(strncmp((char*)fh.ID,"TALB",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i++; + MultiByteToWideChar(CP_ACP,0,&(pOutputTags[i]),packer.dword-1,out->album,512); + i+=packer.dword-1;continue; + } + else{ + i++; + memcpy(&BOM,&(pOutputTags[i]),2);i+=2; + if(BOM==UNICODE_BOM_DIRECT){ + for(j=i;jalbum,sizeof(out->album), + (WCHAR*)&(pOutputTags[i]),packer.dword-3); + i+=packer.dword-3; + continue; + } +} + +if(strncmp((char*)fh.ID,"TCOM",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i++; + MultiByteToWideChar(CP_ACP,0,&(pOutputTags[i]),packer.dword-1,out->composer,512); + i+=packer.dword-1;continue; + } + else{ + i++; + memcpy(&BOM,&(pOutputTags[i]),2);i+=2; + if(BOM==UNICODE_BOM_DIRECT){ + for(j=i;jcomposer,sizeof(out->composer), + (WCHAR*)&(pOutputTags[i]),packer.dword-3); + i+=packer.dword-3; + continue; + } +} +if(strncmp((char*)fh.ID,"TYER",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i++; + MultiByteToWideChar(CP_ACP,0,&(pOutputTags[i]),packer.dword-1,out->year,10); + i+=packer.dword-1;continue; + } + else{ + i++; + memcpy(&BOM,&(pOutputTags[i]),2);i+=2; + if(BOM==UNICODE_BOM_DIRECT){ + for(j=i;jyear,sizeof(out->year), + (WCHAR*)&(pOutputTags[i]),packer.dword-3); + i+=packer.dword-3; + continue; + } +} +if(strncmp((char*)fh.ID,"TPE1",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i++; + MultiByteToWideChar(CP_ACP,0,&(pOutputTags[i]),packer.dword-1,out->artist,512); + i+=packer.dword-1;continue; + } + else{ + i++; + memcpy(&BOM,&(pOutputTags[i]),2);i+=2; + if(BOM==UNICODE_BOM_DIRECT){ + for(j=i;jartist,sizeof(out->artist), + (WCHAR*)&(pOutputTags[i]),packer.dword-3); + i+=packer.dword-3; + continue; + } +} +if(strncmp((char*)fh.ID,"TIT2",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i++; + MultiByteToWideChar(CP_ACP,0,&(pOutputTags[i]),packer.dword-1,out->title,512); + i+=packer.dword-1;continue; + } + else{ + i++; + memcpy(&BOM,&(pOutputTags[i]),2);i+=2; + if(BOM==UNICODE_BOM_DIRECT){ + for(j=i;jtitle,sizeof(out->title), + (WCHAR*)&(pOutputTags[i]),packer.dword-3); + i+=packer.dword-3; + continue; + } +} +if(strncmp((char*)fh.ID,"TLEN",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i++; + StringCchCopyNA(buf,1024,&(pOutputTags[i]),packer.dword-1); + out->length=0; + sscanf(buf,"%u",&(out->length)); + i+=packer.dword-1;continue; + } + i+=packer.dword;continue; +} + + +if(strncmp((char*)fh.ID,"COMM",4)==0){ + if(pOutputTags[i]==ID32_ENCODING_ISO){ + i+=4; + memset(buf,0,sizeof(buf)); + if((packer.dword-4)>1023){memcpy(buf,&(pOutputTags[i]),1023);buf[1023]=0;} + else{memcpy(buf,&(pOutputTags[i]),packer.dword-4);buf[packer.dword-4]=0;} + for(j=0;j<1023;j++){ + if(buf[j]==0){buf[j]='\n';break;} + } + MultiByteToWideChar(CP_ACP,0,buf,1024,out->comments,1024); + i+=packer.dword-4;continue; + } + i+=packer.dword;continue; +} + +i+=packer.dword; +} + +HeapFree(GetProcessHeap(),0,pOutputTags); +CloseHandle(hFile); +out->type=TAG_ID3V2; +//fwprintf(f,L"end read tags, file: %s\n",fname); +return TRUE; +} +void Playlist_Clearbuffer(){ +int i;int c; +c=SendMessage(hlstBuffer,LB_GETCOUNT,0,0); +for(i=0;i=0;i--){ + if(IsPlaylistItemSelected(i)!=FALSE){ + if(CurrentTrack==i){Stop();Close();CurrentTrack=0;} + res=GetPlaylistElement(i,buf); + if(res==FALSE)continue; + DeletePlaylistElement(i); + SendMessage(hlstBuffer,LB_ADDSTRING,0,(LPARAM)buf); + } + } +} + +void Playlist_Copy(){ + int i; + BOOL res; + Playlist_Clearbuffer(); + TCHAR buf[MAX_PATH]=L""; + for(i=CountTracks-1;i>=0;i--){ + if(IsPlaylistItemSelected(i)!=FALSE){ + res=GetPlaylistElement(i,buf); + if(res==FALSE)continue; + SendMessage(hlstBuffer,LB_ADDSTRING,0,(LPARAM)buf); + } + } +} +void Playlist_Paste(){ +int i;int p;int c; +TCHAR buf[MAX_PATH]=L""; +p=GetPlaylistSelectedElement(); +if(p<0)p=0; +if(p>(int)CountTracks)p=CountTracks; +c=SendMessage(hlstBuffer,LB_GETCOUNT,0,0); +for(i=c-1;i>=0;i--){ +SendMessage(hlstBuffer,LB_GETTEXT,i,(LONG)buf); +InsertPlaylistElement(buf,p); +p++; +} + + +} + +void Playlist_SelectAll(){ + int i; + for(i=0;i<(int)CountTracks;i++){ +ListView_SetItemState(PlayList,i,LVIS_SELECTED,LVIS_SELECTED); + } +} + +void InitImageList(){ + SHFILEINFO si={0}; + DWORD_PTR res; + TCHAR dir[MAX_PATH]=L"c:\\windows"; + TCHAR ext[MAX_PATH]=L"c:\\x.mp3"; + int i; +/*GetWindowsDirectory(dir,MAX_PATH); +res=SHGetFileInfo(dir,0,&si,sizeof(SHFILEINFO),SHGFI_ICON|SHGFI_SMALLICON); +if(res==FALSE)hDirIcon=LoadIcon(NULL,MAKEINTRESOURCE(IDI_APPLICATION)); +else hDirIcon=si.hIcon;*/ + +ImageList=ImageList_Create(16, 16, ILC_MASK| ILC_COLOR32, COUNT_TYPE_ICONS+1, 30); +for(i=0;i +#include +#include +#include "resource.h" +#include "player.h" +#include "ScrollbarControl.h" +#include +#define STRSAFE_NO_DEPRECATE +#include + +#define COUNT_EXTENSIONS 18 +#define COUNT_IMAGE_EXTENSIONS (sizeof(ImageExtensions)/sizeof(ImageExtensions[0])) + +typedef struct { + char sig[3]; + char title[30]; +char artist[30]; +char album[30]; +char year[4]; +char comment[30]; +BYTE genre;}MP3TAG_V1; + +typedef struct { + BYTE type; + char sig[6]; +}VORBIS_PACKET_HEADER; + +typedef struct { + ULONG ver; + BYTE chans; + ULONG sample_rate; + long bitrate_max; + long bitrate; + long bitrate_min; + BYTE blocksize; + BYTE end; +}VORBIS_ID; + +#define APE_SIGNATURE ("APETAGEX") +#define APEF_HEADER 0xE0000000 +#define APEF_BINARY 0x00000002 +#define APEF_URL 0x00000004 + +typedef struct { +char sig[8]; +char ver[4]; +DWORD size; +DWORD item_count; +DWORD flags; +BYTE reserved[8]; +}APE_HEADER; + +typedef struct { + ULONG len; + DWORD flags; +}APE_ITEM; + +#define FLAC_SIGNATURE "fLaC" +#define FLAC_LASTBLOCK 0x80 +#define FLAC_VORBISCOMMENT 0x04 +#define FLAC_VORBISCOMMENT2 0x84 + +typedef struct{ + + UINT byte1:7; + UINT dummy1:1; + + UINT byte2:7; + UINT dummy2:1; + + UINT byte3:7; + UINT dummy3:1; + + UINT byte4:7; + UINT dummy4:1; +}BIT_FIELDS; + +typedef struct{ + + UINT byte1:7; + UINT byte2:7; + UINT byte3:7; + UINT byte4:7; + UINT dummy:4; + +}BIT_FIELDS_EXTRACTOR; + +typedef union{ + BYTE bytes[4]; + DWORD dword; + BIT_FIELDS bf; + BIT_FIELDS_EXTRACTOR bfe; +}DWORD_UNION; + +typedef struct { + BYTE type; + BYTE length[3]; +}FLAC_BLOCK_HEADER; + + + + + +#define ID32F_SYNC 0x80 +#define ID32F_EXTHEADER 0x40 +#define ID32_SIGNATURE "ID3" +#define ID32_SYNC_MASK 0xE0 + +typedef struct { +BYTE sig[3]; +BYTE ver[2]; +BYTE flags; +BYTE size[4]; +}ID32_HEADER; + +typedef struct { + DWORD size; + WORD flags; + BYTE padding[4]; +}ID32_EXTHEADER; + +typedef struct { + BYTE ID[4]; + DWORD size; + BYTE flags[2]; +}ID32_FRAME_HEADER; + +#define ID32_FRAME_COMPRESSED 0x0080 +#define ID32_FRAME_ENCRYPTED 0x0040 +#define ID32_ENCODING_ISO 0x00 +#define ID32_ENCODING_UNICODE 1 +#define UNICODE_BOM_DIRECT 0xFFFE +#define UNICODE_BOM_REVERSE 0xFEFF + + +typedef union { + WORD w; + char b[2]; +}WORD_UNION; + +typedef enum {TAG_NO=0,TAG_ID3V1,TAG_ID3V2,TAG_APE,TAG_FLAC}TAG_TYPE; + + +typedef struct{ + WCHAR title[512]; + WCHAR album[512]; + WCHAR artist[512]; + WCHAR year[10]; + WCHAR comments[1024]; + WCHAR composer[512]; + WCHAR URL[512]; + DWORD length; + TAG_TYPE type; +}TAGS_GENERIC; + +typedef struct{ + TCHAR ext[10]; + int iIcon; + HICON hIcon; +}TYPE_ICON_INFO; + +#define COUNT_TYPE_ICONS 16 + +//EXTERN FUNCTIONS +extern void UpdateLength(); +extern void RunTimer(); +extern void StopTimer(); +extern void GetFileExtension(TCHAR* fname,TCHAR* ext); +extern void GetFileExtensionA(char* fname,char* ext); +extern void GetFileDirectory(wchar_t* path,wchar_t* out); + +//EXTERN VARS +extern ScrollbarControl Progress; +extern HWND hVolume; + +//THIS MODULE DECL. +extern HWND PlayList; +extern UINT CountTracks; +extern UINT CurrentTrack; +extern TCHAR* Extensions[COUNT_EXTENSIONS]; +extern PLAYBACK_MODE CurrMode; +extern bool fIncludeImages; +extern HICON hDirIcon; +extern HICON hMusicIcon; +extern int indexDirIcon; +extern int indexMusicIcon; +extern HIMAGELIST ImageList; + +BOOL GetPlaylistElement(int n,TCHAR* out); +BOOL GetPlaylistElementA(int n,char* out); +void AddPlaylistElement(TCHAR* fname); +void ClearPlaylist(); +void DeletePlaylistElement(int n); +void PlayTrackByNumber(int n); +void PlayNextTrack(); +void GetCurrTrackShortName(TCHAR* str); +void AddDirectory(wchar_t* dir,wchar_t* ext); +void DoDirectoryAdd(TCHAR* dir,HWND hlbt); +void Playlist_AddDirectory(TCHAR* dir); +BOOL ReadTagsV1(TCHAR* file,TAGS_GENERIC* out); +BOOL ReadTagsV1A(char* file,TAGS_GENERIC* out); +int GetPlaylistSelectedElement(); +BOOL IsPlaylistItemSelected(int n); +void SetPlaylistHighlight(int i); +void SetPlaylistSelectedElement(int i); +void LoadTextPlaylist(TCHAR* file); +void LoadTextPlaylistA(char* file); +void SaveTextPlaylist(TCHAR* file); +void ReadPlaylistTags(char* str); +int FindTrack(TCHAR* fname); +BOOL ReadApeTags(TCHAR* file,TAGS_GENERIC* out); +BOOL ReadApeTagsA(char* file,TAGS_GENERIC* out); +BOOL ReadFlacTags(TCHAR* file,TAGS_GENERIC* out); +BOOL ReadFlacTagsA(char* file,TAGS_GENERIC* out); +BOOL ReadTagsv2(TCHAR* fname,TAGS_GENERIC* out); +void InsertPlaylistElement(WCHAR* fname,UINT pos); +void Playlist_Paste();void Playlist_Cut();void Playlist_Copy(); +void Playlist_SelectAll(); + +void InitImageList(); +int GetTypeIcon(TCHAR* ext); +#endif \ No newline at end of file diff --git a/SmallMediaPlayer/RegistryModule.cpp b/SmallMediaPlayer/RegistryModule.cpp new file mode 100644 index 0000000..a720f75 --- /dev/null +++ b/SmallMediaPlayer/RegistryModule.cpp @@ -0,0 +1,224 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#include "RegistryModule.h" + + +WCHAR ProgramFileName[256]=L""; + +BOOL RegisterFolderAssociation(){ + HKEY hKey; + LONG lRes; + WCHAR buf[456]; + WCHAR txt[400]; + +lstrcpy(buf,L"(SMP)Добавить в список"); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,L"Folder\\shell\\smp_add",&hKey); + if(lRes!=ERROR_SUCCESS){ + StringCchPrintf(txt,400,L"Ошибка доступа к реестру: CreateKey вернул 0x%04x",lRes); + MessageBoxW(0,txt,L"Ошибка",MB_OK|MB_ICONERROR); + return FALSE; + } + + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + + RegCloseKey(hKey); + if(lRes!=ERROR_SUCCESS){ + StringCchPrintf(txt,400,L"Ошибка записи в реестр: RegSetValueEx вернул 0x%04x",lRes); + MessageBoxW(0,txt,L"Ошибка",MB_OK|MB_ICONERROR); + return FALSE; + } + + + lstrcpy(buf,L"\""); + lstrcat(buf,ProgramFileName); + lstrcat(buf,L"\" /f \"%1\""); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,L"Folder\\shell\\smp_add\\command",&hKey); + if(lRes!=ERROR_SUCCESS){MessageBoxW(0,L"Ошибка работы с реестром",0,0);return FALSE;} + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + RegCloseKey(hKey); + if(lRes!=ERROR_SUCCESS) + return FALSE; + + MessageBox(0,L"Операция выполнена!",L"Успех",MB_OK|MB_ICONINFORMATION); + return TRUE; +} + +void DestroyFolderAssociation(){ + + TCHAR buf[256]; + LONG lRes; + + lstrcpy(buf,L"Folder\\shell\\smp_add\\command"); + lRes=RegDeleteKey(HKEY_CLASSES_ROOT,buf); + if(lRes!=ERROR_SUCCESS){MessageBoxW(0,L"Ошибка работы с реестром",0,0);} + + lstrcpy(buf,L"Folder\\shell\\smp_add"); + lRes=RegDeleteKey(HKEY_CLASSES_ROOT,buf); + if(lRes!=ERROR_SUCCESS){MessageBoxW(0,L"Ошибка работы с реестром",0,0);return;} + + MessageBox(0,L"Операция выполнена!",L"Успех",MB_OK|MB_ICONINFORMATION); +} + + +void RegisterFileAssociation(WCHAR* ext){ + LONG lRes; + HKEY hKey=NULL; + WCHAR buf[256]; + WCHAR type_name[256]; + WCHAR key_name[256]; + DWORD size=256; + WCHAR txt[400]; + + if(lstrcmp(ext,L"")==0){MessageBox(0,L"Введите расширение",0,0);return;} + + size=sizeof(type_name); + lstrcpy(buf,L"."); + lstrcat(buf,ext); + + lRes=RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&hKey); + + if(lRes==ERROR_SUCCESS){ + lRes=RegQueryValueEx(hKey,NULL,NULL,NULL,(LPBYTE)type_name,&size); + if(lRes!=ERROR_SUCCESS){ + lstrcpy(type_name,L"mediafile"); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)type_name,wcslen(type_name)*2+1); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Cannot set type name",0,0);goto Cleanup;} + } + } + else { + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,buf,&hKey); + if(lRes!=ERROR_SUCCESS){ + StringCchPrintf(txt,400,L"Ошибка доступа к реестру: RegCreateKey вернул 0x%04x",lRes); + MessageBoxW(0,txt,L"Ошибка",MB_OK|MB_ICONERROR); + goto Cleanup; + } + lstrcpy(type_name,L"mediafile"); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)type_name,wcslen(type_name)*2+1); + if(lRes!=ERROR_SUCCESS){ + StringCchPrintf(txt,400,L"Ошибка записи в реестр: RegSetValueEx вернул 0x%04x",lRes); + MessageBoxW(0,txt,L"Ошибка",MB_OK|MB_ICONERROR); + goto Cleanup; + } + } + + RegCloseKey(hKey);hKey=NULL; + + + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_open"); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,key_name,&hKey); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Cant create smp_open key",0,0);goto Cleanup;} + lstrcpy(buf,L"Открыть в SMP"); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + if(lRes!=ERROR_SUCCESS){ + StringCchPrintf(txt,400,L"Ошибка записи в реестр: RegSetValueEx вернул 0x%04x",lRes); + MessageBoxW(0,txt,L"Ошибка",MB_OK|MB_ICONERROR); + goto Cleanup; + } + RegCloseKey(hKey);hKey=NULL; + + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_open\\command"); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,key_name,&hKey); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + lstrcpy(buf,L"\""); + lstrcat(buf,ProgramFileName); + lstrcat(buf,L"\" \"%1\""); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + RegCloseKey(hKey);hKey=NULL; + + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_add"); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,key_name,&hKey); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + lstrcpy(buf,L"(SMP)Добавить в список"); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + RegCloseKey(hKey);hKey=NULL; + +lstrcpy(key_name,type_name); +lstrcat(key_name,L"\\shell\\smp_add\\command"); +lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,key_name,&hKey); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + lstrcpy(buf,L"\""); + lstrcat(buf,ProgramFileName); + lstrcat(buf,L"\"/a \"%1\""); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + RegCloseKey(hKey);hKey=NULL; + + //set default action + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell"); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,key_name,&hKey); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + lstrcpy(buf,L"smp_open"); + + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + + MessageBox(0,L"Операция выполнена!",L"Успех",MB_OK|MB_ICONINFORMATION); + + Cleanup:; + if(hKey!=NULL)RegCloseKey(hKey); + } + +void DestroyFileAssociation(TCHAR* ext){ +LONG lRes; + HKEY hKey=NULL; + WCHAR buf[256]; + WCHAR type_name[256]; + WCHAR key_name[256]; + WCHAR txt[400]; + DWORD size=256; + + if(lstrcmp(ext,L"")==0){MessageBox(0,L"Введите расширение",0,0);return;} +//find type name + size=sizeof(type_name); + lstrcpy(buf,L"."); + lstrcat(buf,ext); + lRes=RegOpenKeyW(HKEY_CLASSES_ROOT,buf,&hKey); + if(lRes==ERROR_SUCCESS){ + lRes=RegQueryValueEx(hKey,NULL,NULL,NULL,(LPBYTE)type_name,&size); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + } + else + { + StringCchPrintf(txt,400,L"Ошибка доступа к реестру: RegOpenKey вернул 0x%04x",lRes); + MessageBoxW(0,txt,L"Ошибка",MB_OK|MB_ICONERROR); + goto Cleanup; + } + RegCloseKey(hKey);hKey=NULL; + + //delete our subkey + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_open\\command"); + RegDeleteKey(HKEY_CLASSES_ROOT,key_name); + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_add\\command"); + RegDeleteKey(HKEY_CLASSES_ROOT,key_name); + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_open"); + RegDeleteKey(HKEY_CLASSES_ROOT,key_name); + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell\\smp_add"); + RegDeleteKey(HKEY_CLASSES_ROOT,key_name); + + //reset dafault action + lstrcpy(key_name,type_name); + lstrcat(key_name,L"\\shell"); + lRes=RegCreateKeyW(HKEY_CLASSES_ROOT,key_name,&hKey); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + + lstrcpy(buf,L"open"); + lRes=RegSetValueExW(hKey,NULL,0,REG_SZ,(BYTE*)buf,wcslen(buf)*2+1); + if(lRes!=ERROR_SUCCESS){MessageBox(0,L"Ошибка работы с реестром!",0,0);goto Cleanup;} + + MessageBox(0,L"Операция выполнена!",L"Успех",MB_OK|MB_ICONINFORMATION); + +Cleanup: + if(hKey!=NULL)RegCloseKey(hKey); + +} \ No newline at end of file diff --git a/SmallMediaPlayer/RegistryModule.h b/SmallMediaPlayer/RegistryModule.h new file mode 100644 index 0000000..2e73b16 --- /dev/null +++ b/SmallMediaPlayer/RegistryModule.h @@ -0,0 +1,17 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#ifndef UNICODE +#define UNICODE +#endif +#include +#include +#include + +//this module +extern WCHAR ProgramFileName[256]; + +BOOL RegisterFolderAssociation(); +void DestroyFolderAssociation(); +void RegisterFileAssociation(WCHAR* ext); +void DestroyFileAssociation(TCHAR* ext); \ No newline at end of file diff --git a/SmallMediaPlayer/SMPSettings.cpp b/SmallMediaPlayer/SMPSettings.cpp new file mode 100644 index 0000000..66c780f --- /dev/null +++ b/SmallMediaPlayer/SMPSettings.cpp @@ -0,0 +1,180 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#include "SMPSettings.h" + +SMPSETTINGS Settings = +{ + sizeof(SMPSETTINGS), + SMPVER_MAJOR, + SMPVER_MINOR, + true,//show pls + true,//show cover + true,//load pls + false,//remember pos + true,//load wallpaper + true,//load def wallpaper + L"",//wallpaper file name + 5000,//image delay + CW_USEDEFAULT, + 0, + CW_USEDEFAULT, + 0, + false,//is window maximized + FILE_NOT_LOADED,//state + NORMAL,//playback mode + 0, + 0, + 100 //volume +}; + +void LoadSettings() +{ + HANDLE hFile; + DWORD dwCount; + SMPSETTINGS t; + TCHAR fname[MAX_PATH]=L""; + BOOL res; + + HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, fname); + + if(result!=S_OK)GetFileDirectory(ProgramFileName,fname); + else StringCchCat(fname,MAX_PATH,L"\\Small Media Player\\"); + + CreateDirectory(fname,NULL); + StringCchCat(fname,MAX_PATH,L"smpdata.bin"); + + hFile=CreateFile(fname,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); + if(hFile==INVALID_HANDLE_VALUE)return; + res=ReadFile(hFile,&t,sizeof(SMPSETTINGS),&dwCount,NULL); + if(res==FALSE){CloseHandle(hFile);return;} + if(dwCount!=sizeof(SMPSETTINGS)){CloseHandle(hFile);return;} + Settings=t; + CloseHandle(hFile); +} + +void WriteSettings() +{ + HANDLE hFile; + DWORD dwCount; + + TCHAR fname[MAX_PATH]=L""; + BOOL res; + + HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, fname); + + if(result!=S_OK)GetFileDirectory(ProgramFileName,fname); + else StringCchCat(fname,MAX_PATH,L"\\Small Media Player\\"); + + StringCchCat(fname,MAX_PATH,L"smpdata.bin"); + + hFile=CreateFile(fname,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); + if(hFile==INVALID_HANDLE_VALUE)return; + res=WriteFile(hFile,&Settings,sizeof(SMPSETTINGS),&dwCount,NULL); + CloseHandle(hFile); +} + +void RestoreLastPosition() +{ + CurrMode=Settings.LastPlaybackMode; + CurrVolume=Settings.LastVolume; + UpdateVolume(); + + if(Settings.LastPlayerState==FILE_NOT_LOADED)return; + PlayTrackByNumber(Settings.LastFileIndex); + switch(Settings.LastPlayerState) + { + case STOPPED:Stop();break; + case PAUSED: + SetPosition(Settings.LastPosition); + Pause();break; + case PLAYING:SetPosition(Settings.LastPosition); + + break; + } +} + +void SaveLastPosition() +{ + Settings.LastFileIndex=CurrentTrack; + Settings.LastPlayerState=PlayerState; + Settings.LastPosition=GetPosition(); + Settings.LastPlaybackMode=CurrMode; + Settings.LastVolume=CurrVolume; +} + +BOOL CALLBACK SettingsDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){ + + wchar_t buf[256]=L""; + HWND hw; + OPENFILENAME ofn={0}; + BOOL success; + UINT i; + static SMPSETTINGS t; + +switch(uMsg){ +case WM_INITDIALOG: + t=Settings; + if(Settings.fLoadDefaultPls==true){CheckDlgButton(hDlg,IDC_REMEMBER_PLAYLIST,BST_CHECKED);} + else{CheckDlgButton(hDlg,IDC_REMEMBER_PLAYLIST,BST_UNCHECKED);} + if(Settings.fLoadDefaultPls==false){ + hw=GetDlgItem(hDlg,IDC_REMEMBER_POSITION); + EnableWindow(hw,FALSE);} + if(Settings.fRememberPosition==true){CheckDlgButton(hDlg,IDC_REMEMBER_POSITION,BST_CHECKED);} + else{CheckDlgButton(hDlg,IDC_REMEMBER_POSITION,BST_UNCHECKED);} + if(Settings.fLoadWallpaper==true){CheckDlgButton(hDlg,IDC_SHOW_WALLPAPER,BST_CHECKED);} + else{CheckDlgButton(hDlg,IDC_SHOW_WALLPAPER,BST_UNCHECKED);} + if(Settings.fLoadDefWallpaper==true){SetDlgItemText(hDlg,IDC_FILENAME,L"");} + else{SetDlgItemText(hDlg,IDC_FILENAME,Settings.WallpaperFilePath);} + StringCchPrintf(buf,256,L"%u",(UINT)Settings.ImageDelay); + SetDlgItemText(hDlg,IDC_DELAY,buf); + + return TRUE; + +case WM_COMMAND:switch(LOWORD(wParam)){ +case IDC_REMEMBER_PLAYLIST:t.fLoadDefaultPls=!t.fLoadDefaultPls; + if(t.fLoadDefaultPls==false){ + CheckDlgButton(hDlg,IDC_REMEMBER_POSITION,BST_UNCHECKED); + t.fRememberPosition=false; + hw=GetDlgItem(hDlg,IDC_REMEMBER_POSITION); + EnableWindow(hw,FALSE); + } + else{ + hw=GetDlgItem(hDlg,IDC_REMEMBER_POSITION); + EnableWindow(hw,TRUE); + } + break; +case IDC_REMEMBER_POSITION:t.fRememberPosition=!t.fRememberPosition;break; +case IDC_SHOW_WALLPAPER:t.fLoadWallpaper=!t.fLoadWallpaper;break; +case ID_OPEN:ofn.lStructSize=sizeof(OPENFILENAME); + ofn.lpstrFile=buf; + ofn.nMaxFile=sizeof(buf); + success=GetOpenFileName(&ofn); + if(success==FALSE){break;} + SetDlgItemText(hDlg,IDC_FILENAME,buf); + StringCchCopy(Settings.WallpaperFilePath,MAX_PATH,buf); + break; + +case IDOK: + Settings=t; + GetDlgItemText(hDlg,IDC_FILENAME,Settings.WallpaperFilePath,MAX_PATH); + if(lstrcmp(Settings.WallpaperFilePath,L"")==0){Settings.fLoadDefWallpaper=true;} + else {Settings.fLoadDefWallpaper=false;} + i=GetDlgItemInt(hDlg,IDC_DELAY,&success,FALSE); + if(success!=FALSE)Settings.ImageDelay=i; + UnloadPattern(); + if(Settings.fLoadWallpaper==true){ + if(Settings.fLoadDefWallpaper==true){ + GetPattern(buf); + LoadPattern(buf);} + else{LoadPattern(Settings.WallpaperFilePath);} +} + WriteSettings(); + case IDCANCEL:EndDialog(hDlg,0);return TRUE; + + }break; +case WM_CLOSE:EndDialog(hDlg,0);return TRUE; + + } +return FALSE; +} diff --git a/SmallMediaPlayer/SMPSettings.h b/SmallMediaPlayer/SMPSettings.h new file mode 100644 index 0000000..80a3822 --- /dev/null +++ b/SmallMediaPlayer/SMPSettings.h @@ -0,0 +1,29 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#ifndef SMPSETTINGS_H +#define SMPSETTINGS_H + +#ifndef UNICODE +#define UNICODE +#endif + +#include "player.h" +#include "PlaylistEditor.h" +#include "generic.h" +#include "PictureManager.h" + +//extern +extern WCHAR ProgramFileName[256]; +extern long CurrVolume; +extern void UpdateVolume(); + +//this module +extern SMPSETTINGS Settings; +void RestoreLastPosition(); +void SaveLastPosition(); +void WriteSettings(); +void LoadSettings(); +BOOL CALLBACK SettingsDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam); + +#endif diff --git a/SmallMediaPlayer/ScrollbarControl.h b/SmallMediaPlayer/ScrollbarControl.h new file mode 100644 index 0000000..524451d --- /dev/null +++ b/SmallMediaPlayer/ScrollbarControl.h @@ -0,0 +1,62 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#ifndef SCROLL_H +#define SCROLL_H + +#ifndef UNICODE +#define UNICODE +#endif +#include + +class ScrollbarControl{ +public: + ScrollbarControl(){;} + ScrollbarControl(int type,HWND handle,int min,int max,UINT page){ + si.cbSize=sizeof(SCROLLINFO); + si.nMin=min;si.nMax=max; + si.nPage=page; + si.fMask=SIF_PAGE|SIF_RANGE; + SetScrollInfo(handle,type,&si,TRUE); + hwnd=handle; + BarType=type; + Inc=10; + }; + + void SetTrackPosition(int pos){ + si.nPos=pos; + si.fMask=SIF_POS; + SetScrollInfo(hwnd,BarType,&si,TRUE); + } + void SetIncrement(int value){ + Inc=value;} + void ProcessScrollEvent(short EventType,short TrackPos){ + switch(EventType){ + + case SB_LINEUP:SetTrackPosition(si.nPos-Inc);break; + + case SB_LINEDOWN:SetTrackPosition(si.nPos+Inc);break; + + case SB_PAGEUP:SetTrackPosition(si.nPos-si.nPage);break; + + case SB_PAGEDOWN:SetTrackPosition(si.nPos+si.nPage);break; + case SB_THUMBTRACK: + case SB_THUMBPOSITION:SetTrackPosition(TrackPos);break; + + }; + + } + int GetTrackPos(){ + si.fMask=SIF_POS; + GetScrollInfo(hwnd,BarType,&si); + return si.nPos;} + +private:SCROLLINFO si; +HWND hwnd; +int BarType; +int Inc; + + + }; + +#endif diff --git a/SmallMediaPlayer/SmallMediaPlayer.sln b/SmallMediaPlayer/SmallMediaPlayer.sln new file mode 100644 index 0000000..78d574d --- /dev/null +++ b/SmallMediaPlayer/SmallMediaPlayer.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SmallMediaPlayer", "SmallMediaPlayer.vcxproj", "{BC55783B-BD4F-4314-B27A-C590FFBE46A9}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BC55783B-BD4F-4314-B27A-C590FFBE46A9}.Debug|Win32.ActiveCfg = Debug|Win32 + {BC55783B-BD4F-4314-B27A-C590FFBE46A9}.Debug|Win32.Build.0 = Debug|Win32 + {BC55783B-BD4F-4314-B27A-C590FFBE46A9}.Release|Win32.ActiveCfg = Release|Win32 + {BC55783B-BD4F-4314-B27A-C590FFBE46A9}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/SmallMediaPlayer/SmallMediaPlayer.vcxproj b/SmallMediaPlayer/SmallMediaPlayer.vcxproj new file mode 100644 index 0000000..7f938b5 --- /dev/null +++ b/SmallMediaPlayer/SmallMediaPlayer.vcxproj @@ -0,0 +1,107 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {BC55783B-BD4F-4314-B27A-C590FFBE46A9} + Win32Proj + SmallMediaPlayer + + + + Application + true + v110 + Unicode + + + Application + false + v110_xp + true + Unicode + + + + + + + + + + + + + true + + + false + + + + + + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + + + Windows + true + winmm.lib;strmiids.lib;quartz.lib;comctl32.lib;gdiplus.lib;%(AdditionalDependencies) + + + + + Level3 + + + MinSpace + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + Neither + + + Windows + true + true + true + winmm.lib;strmiids.lib;quartz.lib;comctl32.lib;gdiplus.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SmallMediaPlayer/SmallMediaPlayer.vcxproj.filters b/SmallMediaPlayer/SmallMediaPlayer.vcxproj.filters new file mode 100644 index 0000000..7781483 --- /dev/null +++ b/SmallMediaPlayer/SmallMediaPlayer.vcxproj.filters @@ -0,0 +1,74 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Файлы исходного кода + + + Файлы исходного кода + + + Файлы исходного кода + + + Файлы исходного кода + + + Файлы исходного кода + + + Файлы исходного кода + + + Файлы исходного кода + + + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + Заголовочные файлы + + + + + Файлы ресурсов + + + \ No newline at end of file diff --git a/SmallMediaPlayer/generic.h b/SmallMediaPlayer/generic.h new file mode 100644 index 0000000..1909c68 --- /dev/null +++ b/SmallMediaPlayer/generic.h @@ -0,0 +1,135 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#ifndef GENERIC_H +#define GENERIC_H + +enum PLAYER_STATE +{ + FILE_NOT_LOADED, + STOPPED, + PAUSED, + PLAYING +}; + +typedef enum {NORMAL,REPEAT_LIST,REPEAT_FILE,RANDOM} PLAYBACK_MODE; + +const int SMPVER_MAJOR = 2; +const int SMPVER_MINOR = 0; + +typedef struct +{ + int size; + BYTE verMajor; + BYTE verMinor; + //settings + bool fShowPlaylist; + bool fShowCover; + bool fLoadDefaultPls; + bool fRememberPosition; + bool fLoadWallpaper; + bool fLoadDefWallpaper; + TCHAR WallpaperFilePath[MAX_PATH]; + DWORD ImageDelay; + //remembered window state + int WndX; + int WndY; + int WndWidth; + int WndHeight; + bool WndMaximized; + //remembered player state + PLAYER_STATE LastPlayerState; + PLAYBACK_MODE LastPlaybackMode; + UINT LastFileIndex; + DWORD LastPosition; + long LastVolume; +} +SMPSETTINGS; + +typedef enum {VIDEOTYPE_VIDEO=0,VIDEOTYPE_MPEG1=1,VIDEOTYPE_MPEG2=2}SMP_VIDEOTYPE; +typedef enum {STREAM_UNKNOWN=0,STREAM_AVI,STREAM_MPEG1,STREAM_MPEG1VCD,STREAM_MPEG2, +STREAM_QUICKTIME,STREAM_WAVE,STREAM_MIDI,STREAM_ASF}SMP_STREAM; + +typedef struct { + DWORD dwVideoCodec; + int width; + int height; + int BitsPerPixel; + int FramesPerSecond; + SMP_VIDEOTYPE VideoType; + RECT rcSource; +}SMP_VIDEOINFO; + +typedef struct { +BYTE chans; +int BitsPerSample; +int nFreq; +int BitsPerSecond; +WORD wFormatTag; + +}SMP_AUDIOINFO; + +typedef union{ +WORD word; +char chars[4]; +}FOURCC_EXTRACTOR; + +#define VIDEO_YUV (0x56595559) +#define VIDEO_XVID (MAKEFOURCC('X','V','I','D')) +#define VIDEO_DIVX (MAKEFOURCC('D','I','V','X')) +#define VIDEO_MPEG4_1 (MAKEFOURCC('D','I','V','1')) +#define VIDEO_MPEG4_2 (MAKEFOURCC('D','I','V','2')) +#define VIDEO_DIV3 (MAKEFOURCC('D','I','V','3')) +#define VIDEO_DIV4 (MAKEFOURCC('D','I','V','4')) +#define VIDEO_DIV5 (MAKEFOURCC('D','I','V','5')) +#define VIDEO_DIV6 (MAKEFOURCC('D','I','V','6')) +#define VIDEO_H264 (MAKEFOURCC('H','2','6','4')) +#define VIDEO_HFYU (MAKEFOURCC('H','F','Y','U')) +#define VIDEO_MJPEG (MAKEFOURCC('M','J','P','G')) +#define VIDEO_MPEG1 (MAKEFOURCC('M','P','E','G')) +#define VIDEO_MPEG4VIDEO (MAKEFOURCC('M','P','4','V')) + +#define AUDIO_MPEG1 (0x0050) +#define AUDIO_MPEG2AAC (0x0180) +#define AUDIO_AAC4 (0x00FF) +#define AUDIO_AAC3 (0x706D) +#define AUDIO_AAC2 (0x0AAC) +#define AUDIO_AAC (0xA106) +#define AUDIO_MPEG4AAC (0x4143) +#define AUDIO_WAVEPACK (0x5756) +#define AUDIO_OGG (0x674F) +#define AUDIO_OGG2 (0x6750) +#define AUDIO_OGG3 (0x6751) +#define AUDIO_OGG1P (0x676F) +#define AUDIO_OGG2P (0x6770) +#define AUDIO_OGG3P (0x6771) +#define AUDIO_FLAC (0xF1AC) +#define AUDIO_AMR (0x0136) +#define AUDIO_AC3 (0x2000) +#define AUDIO_DVI_ADPCM (0x0011) + +#define INFORES_NO 0 +#define INFORES_AUDIO 1 +#define INFORES_VIDEO 2 +#define INFORES_BOTH 3 + +#define MNUM_MAINMENU (0) +#define MNUM_PLAYLISTMENU (1) + +#define UM_TRAYICON (WM_USER+1) + +//timers +#define TM_NEXT_IMAGE 3 +#define TM_HIDE_CURSOR 4 + +BOOL inline IsCursorShown(){ + CURSORINFO ci={0}; + ci.cbSize=sizeof(CURSORINFO); + GetCursorInfo(&ci); + if(ci.flags==0)return FALSE; + else return TRUE; + +} + + +#endif diff --git a/SmallMediaPlayer/main.cpp b/SmallMediaPlayer/main.cpp new file mode 100644 index 0000000..5fa4319 --- /dev/null +++ b/SmallMediaPlayer/main.cpp @@ -0,0 +1,1705 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#define _CRT_SECURE_NO_WARNINGS + +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' "\ +"version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +#pragma comment(linker,"/MERGE:.rdata=.text") +#pragma comment(linker,"/SECTION:.text,EWR") +#pragma comment(linker,"/ENTRY:New_WinMain") + +#include +#include +#include +#include + +#include "resource.h" +#include "player.h" +#include "ScrollbarControl.h" + +#include "PlayListEditor.h" +#include "PictureManager.h" +#include "RegistryModule.h" +#include "SMPSettings.h" +#include + +#define S_TRACK_SIZE 20 +#define TIMER_UPDATE_POSITION 2 +#define VOLUME_INCREMENT 10 + +DWORD WINAPI DirThreadFunc(TCHAR* dir); +void DisplayOpenedFileTags(); +extern int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2,LPARAM lParamSort); +extern TAGS_GENERIC OpenedFileTags; +extern bool fOpenedFileTags; +extern HWND hlstBuffer; + +//GLOBAL VARIABLES +HWND hMainWnd; +HWND hMainDlg; +HWND hPlaybackDlg; +ScrollbarControl Progress; +HWND hScrollbar; +HWND hVolume; +HWND hVideoWindow; +HWND hCoverWnd; +HACCEL hAccel; +HICON hSMPIcon=NULL; +HMENU hcMainMenu=NULL; +HMENU hcPlaylistMenu=NULL; + +RECT rcInfoBox={0}; +TCHAR txtMediaInfo[1000]={0}; + +HANDLE hPipe=NULL; +HANDLE hMutex; +HANDLE hThread; + +BOOL IsTimerWorking=FALSE; +bool fPlaylistBlocked=FALSE; + +TCHAR strInputURL[500]=L""; +TCHAR strInputFiles[5000]=L""; +bool fInputURL=false; +TCHAR strInputFolder[MAX_PATH]=L""; +bool IsTrayIcon=false; +bool fCursorShown=true; +int pls_LastSortColumn=99; +bool pls_SortReverse=false; +bool fBlockContextMenu=false; +long CurrVolume=0; + +TCHAR strMediafileFilter[]=L"All files\0*.*\0\ +Audio files\0*.wav;*.mp1;*.mp2;*.mp3;*.wma;*.cda;*.aac;*.ogg;*.flac;*.m4a\0\ +Video files\0*.wmv;*.avi;*.mpg;*.mpeg;*.mkv;*.mov;*.qt;*.ts\0\ +Images\0*.jpg;*.jpeg;*.bmp;*.png;*.gif\0\ +MIDI\0*.mid;*.midi\0\ +Playlist\0*.m3u;*.lst\0\ +MPEG Audio\0*.mp1;*.mp2;*.mp3\0\ +Waveform Audio\0*.wav\0\ +Advanced systems format (Windows Media)\0*.wma;*.wmv;*.asf\0\ +CD Digital Audio Tracks\0*.cda\0\ +Advanced audio coding\0*.aac\0\ +Vorbis OGG\0*.ogg\0\ +Free lossless audio codec\0*.flac\0\ +Audio-Video Interleaved\0*.avi\0\ +Motion picture experts group\0*.mpg;*.mpeg;*.ts;*.mp4\0"; + +TCHAR strPlaylistFilter[]=L"Playlist\0*.m3u;*.lst\0LST playlist\0*.lst\0M3U playlist\0*.m3u\0All files\0*.*\0"; + +//settings + +DWORD UpdatePosTimerPeriod=1000; + + +//======================================== +void UpdatePlaylist(){ + int pw,ph; + RECT rc; + BOOL res; + res=GetClientRect(hMainDlg,&rc); + if(res==FALSE)return; + pw=rc.right-rc.left; + ph=rc.bottom-rc.top; + + SetWindowPos(PlayList,HWND_TOP,0,40,pw,ph-40,SWP_SHOWWINDOW|SWP_NOZORDER); +} + +void UpdateView(){ + int w,h; + int w_playlist,h_playlist; + int w_cover,h_cover; + int w_total,h_total; + int x_cover; + + int right=0,bottom=0; + RECT rc; + RECT rc2; + RECT rc_cover; + POINT pt; + + GetClientRect(hMainWnd,&rc);//get main window size + w_total=rc.right-rc.left; + h_total=rc.bottom-rc.top; + + GetWindowRect(hPlaybackDlg,&rc);//get playback window size + w=rc.right-rc.left; + h=rc.bottom-rc.top; + right=w; + bottom=h; + w_playlist=w;//playlist width is the same + + /*calculate others*/ + w_cover=w_total-w_playlist; + h_playlist=h_total-h; + h_cover=h_playlist; + rcInfoBox.top=4;rcInfoBox.bottom=h; + rcInfoBox.left=w+4;rcInfoBox.right=w_total; + + if(Settings.fShowPlaylist==false){x_cover=0;w_cover=w_total;}//if no playlist, cover takes all width + else x_cover=w; + + if(Settings.fShowPlaylist==true && Settings.fShowCover==false)w_playlist=w_total;//if no cover, playlist takes all width + + /*adjust subwindows positions...*/ + SetWindowPos(hPlaybackDlg,HWND_TOP,0,0,w,h,SWP_SHOWWINDOW); + + if(Settings.fShowPlaylist==true) + { + SetWindowPos(hMainDlg,HWND_TOP,0,h,w_playlist,h_playlist,SWP_NOACTIVATE); + ShowWindow(hMainDlg,SW_SHOW); + UpdatePlaylist(); + } + else + { + ShowWindow(hMainDlg,SW_HIDE); + } + + if(Settings.fShowCover==true) + { + SetWindowPos(hCoverWnd,HWND_TOP,x_cover,h,w_cover,h_cover,SWP_NOACTIVATE); + ShowWindow(hCoverWnd,SW_SHOW); + } + else + { + ShowWindow(hCoverWnd,SW_HIDE); + } + +} + +void SaveWindowSize() +{ + RECT rc2; + /*Set window size in settings*/ + GetWindowRect(hMainWnd,&rc2); + Settings.WndX=rc2.left; + Settings.WndY=rc2.top; + Settings.WndWidth=rc2.right-rc2.left; + Settings.WndHeight=rc2.bottom-rc2.top; + Settings.WndMaximized=IsZoomed(hMainWnd); +} + + + +void ProcessMessages(){ + MSG msg; + while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ + if(IsIconic(hMainWnd)==FALSE){ + if(TranslateAccelerator(hMainWnd,hAccel,&msg))continue; + } + else{ + if(TranslateAccelerator(hVideoWindow,hAccel,&msg))continue; + } + if(IsDialogMessage(hMainDlg,&msg))continue; + if(IsDialogMessage(hPlaybackDlg,&msg))continue; + TranslateMessage(&msg); + DispatchMessage(&msg); + } + +} + + +void UpdateGUI(){ +int id; +MENUITEMINFO mi={0}; +switch(CurrMode){ +case NORMAL:id=ID_MODE_NORMAL;break; +case REPEAT_FILE: id=ID_MODE_REPEATFILE;break; +case REPEAT_LIST: id=ID_MODE_REPEATLIST;break; +case RANDOM: id=ID_MODE_RANDOM;break; +} +CheckMenuRadioItem(GetMenu(hMainWnd),ID_MODE_NORMAL,ID_MODE_RANDOM,id,MF_BYCOMMAND); + +mi.cbSize=sizeof(mi); + mi.fMask=MIIM_STATE; + if(Settings.fShowPlaylist==true)mi.fState=MFS_CHECKED; + else mi.fState=MFS_UNCHECKED; + SetMenuItemInfo(GetMenu(hMainWnd),ID_SHOWPLAYLIST,FALSE,&mi); +mi.cbSize=sizeof(mi); + mi.fMask=MIIM_STATE; + if(Settings.fShowCover==true)mi.fState=MFS_CHECKED; + else mi.fState=MFS_UNCHECKED; + SetMenuItemInfo(GetMenu(hMainWnd),ID_SHOWCOVER,FALSE,&mi); +} + + + +void ShowContextMenu(BYTE nMenuNum,int x,int y){ + MENUITEMINFO mi={0}; + if(nMenuNum==MNUM_MAINMENU){ + mi.cbSize=sizeof(mi); + mi.fMask=MIIM_STRING; + if(IsTrayIcon==false){ + mi.dwTypeData=L"Свернуть в значок"; + } + else{mi.dwTypeData=L"Развернуть в окно";} + SetMenuItemInfo(hcMainMenu,ID_MINIMIZE,FALSE,&mi); + TrackPopupMenu(hcMainMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON,x,y,0,hMainWnd,NULL); + } + else{ + TrackPopupMenu(hcPlaylistMenu,TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON,x,y,0,hMainWnd,NULL); + } +} + +void SwitchTrayIcon(){ + TCHAR str[256]=L""; + int i,c; + NOTIFYICONDATA nd={0}; + nd.cbSize=sizeof(nd); + nd.hWnd=hMainWnd; + nd.uID=1; + nd.uCallbackMessage=UM_TRAYICON; + nd.hIcon=hSMPIcon; + if(PlayerState==FILE_NOT_LOADED){ + StringCchCopy(nd.szTip,128,L"Small Media Player");} + else{ + GetCurrTrackShortName(str);StringCchCat(str,256,L" / Small Media Player"); + c=lstrlen(str); + for(i=0;i<126;i++){ + if(i>=c)break; + nd.szTip[i]=str[i]; + } + nd.szTip[i]=0; + } + nd.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP; + if(IsTrayIcon==false){ + IsTrayIcon=true; + ShowWindow(hMainWnd,SW_HIDE); + Shell_NotifyIcon(NIM_ADD,&nd); + }else{ + IsTrayIcon=false; + ShowWindow(hMainWnd,SW_SHOW); + Shell_NotifyIcon(NIM_DELETE,&nd);} +} + +void UpdateTrayIconText(){ +TCHAR str[256]=L""; + int i,c; + NOTIFYICONDATA nd={0}; + + if(IsTrayIcon==false){return;} + nd.cbSize=sizeof(nd); + nd.hWnd=hMainWnd; + nd.uID=1; + if(PlayerState==FILE_NOT_LOADED){ + StringCchCopy(nd.szTip,128,L"Small Media Player");} + else{ + GetCurrTrackShortName(str);StringCchCat(str,256,L" / Small Media Player"); + c=lstrlen(str); + for(i=0;i<126;i++){ + if(i>=c)break; + nd.szTip[i]=str[i]; + } + nd.szTip[i]=0; + } + nd.uFlags=NIF_TIP; + Shell_NotifyIcon(NIM_MODIFY,&nd); +} + +void DisplayFileInfo(int n){ + if(n==CurrentTrack&&PlayerState!=FILE_NOT_LOADED){DisplayOpenedFileTags();return;} + WCHAR text[5000]=L""; + TCHAR ext[10]=L""; + WCHAR buf[MAX_PATH]=L""; + TAGS_GENERIC info={0}; + BOOL res=FALSE; + int h,sec,min; +GetPlaylistElement(n,buf); +GetFileExtension(buf,ext); +res=ReadTagsv2(buf,&info); +if(res==FALSE&&lstrcmpi(ext,L"flac")==0){res=ReadFlacTags(buf,&info);} +if(res==FALSE)ReadApeTags(buf,&info); +if(res==FALSE)ReadTagsV1(buf,&info); +StringCchCopy(text,5000,buf); +StringCchCat(text,5000,L"\n\nНазвание: "); + StringCchCat(text,5000,info.title); + StringCchCat(text,5000,L"\nИсполнитель: "); + StringCchCat(text,5000,info.artist); + StringCchCat(text,5000,L"\nАльбом: "); + StringCchCat(text,5000,info.album); + StringCchCat(text,5000,L"\nГод: "); + StringCchCat(text,5000,info.year); + StringCchCat(text,5000,L"\n\nКомпозитор: "); + StringCchCat(text,5000,info.composer); + StringCchCat(text,5000,L"\nОписание: "); + StringCchCat(text,5000,info.comments); + StringCchCat(text,5000,L"\nURL: "); + StringCchCat(text,5000,info.URL); + if(info.length!=0){ + sec=info.length/1000; + h=sec/3600; + sec=sec%3600; + min=sec/60;sec=sec%60; + StringCchCat(text,5000,L"\nДлина: "); + StringCchPrintf(buf,256,L"%02d:%02d:%02d\n",h,min,sec); + StringCchCat(text,5000,buf); + } + StringCchCat(text,5000,L"\n\nТип метаданных:"); +switch(info.type){ + case TAG_ID3V1:StringCchCat(text,5000,L"ID3V1");break; + case TAG_ID3V2:StringCchCat(text,5000,L"ID3V2");break; + case TAG_APE:StringCchCat(text,5000,L"APE");break; + case TAG_FLAC:StringCchCat(text,5000,L"FLAC (Vorbis comment)");break; + case TAG_NO: + default:StringCchCat(text,5000,L"Нет");break; +} +MessageBox(hMainWnd,text,L"Информация о файле",MB_OK); +} + +void DisplayOpenedFileTags(){ +WCHAR text[5000]=L""; +WCHAR buf[MAX_PATH]=L""; +int min,h,sec; +GetPlaylistElement(CurrentTrack,buf); +StringCchCopy(text,5000,buf); +if(fOpenedFileTags==true){ + StringCchCat(text,5000,L"\n\nНазвание: "); + StringCchCat(text,5000,OpenedFileTags.title); + StringCchCat(text,5000,L"\nИсполнитель: "); + StringCchCat(text,5000,OpenedFileTags.artist); + StringCchCat(text,5000,L"\nАльбом: "); + StringCchCat(text,5000,OpenedFileTags.album); + StringCchCat(text,5000,L"\nГод: "); + StringCchCat(text,5000,OpenedFileTags.year); + StringCchCat(text,5000,L"\n\nКомпозитор: "); + StringCchCat(text,5000,OpenedFileTags.composer); + StringCchCat(text,5000,L"\nОписание: "); + StringCchCat(text,5000,OpenedFileTags.comments); + StringCchCat(text,5000,L"\nURL: "); + StringCchCat(text,5000,OpenedFileTags.URL); + if(OpenedFileTags.length!=0){ + sec=OpenedFileTags.length/1000; + h=sec/3600; + sec=sec%3600; + min=sec/60;sec=sec%60; + StringCchCat(text,5000,L"\nДлина: "); + StringCchPrintf(buf,256,L"%02d:%02d:%02d\n",h,min,sec); + StringCchCat(text,5000,buf); + } +} + +StringCchCat(text,5000,L"\n\nТип метаданных:"); +switch(OpenedFileTags.type){ + case TAG_ID3V1:StringCchCat(text,5000,L"ID3V1");break; + case TAG_ID3V2:StringCchCat(text,5000,L"ID3V2");break; + case TAG_APE:StringCchCat(text,5000,L"APE");break; + case TAG_FLAC:StringCchCat(text,5000,L"FLAC (Vorbis comment)");break; + case TAG_NO: + default:StringCchCat(text,5000,L"Нет");break; +} +MessageBox(hMainWnd,text,L"Информация о файле",MB_OK); +} + +void DisplayMultimediaInfo(){ +WORD wRes=0; +SMP_AUDIOINFO ai={0}; +SMP_VIDEOINFO vi={0}; +FOURCC_EXTRACTOR* fcc=NULL; +TCHAR text[5000]=L""; +TCHAR buf[MAX_PATH]; +SMP_STREAM stream=STREAM_UNKNOWN; + +wRes=GetMultimediaInfo(&ai,&vi,&stream); +StringCchCopy(text,5000,L"\n==ВХОДНОЙ ПОТОК:==\n"); +StringCchCat(text,5000,L"Формат: "); +switch(stream){ +case STREAM_AVI:StringCchCat(text,5000,L"Audio-Video Interleaved\n");break; +case STREAM_ASF:StringCchCat(text,5000,L"Advanced Systems Format\n");break; +case STREAM_MPEG1:StringCchCat(text,5000,L"MPEG1\n");break; +case STREAM_MPEG1VCD:StringCchCat(text,5000,L"MPEG1 VideoCD\n");break; +case STREAM_MPEG2:StringCchCat(text,5000,L"MPEG2\n");break; +case STREAM_WAVE:StringCchCat(text,5000,L"Waveform Audio\n");break; +case STREAM_QUICKTIME:StringCchCat(text,5000,L"Apple(tm) Quick Time Movie\n");break; +case STREAM_UNKNOWN:default:StringCchCat(text,5000,L"[нет данных]\n");break; +} +StringCchCat(text,5000,L"==АУДИО:==\n"); +if(wRes==INFORES_AUDIO||wRes==INFORES_BOTH){ + StringCchCat(text,5000,L"Формат:"); + switch(ai.wFormatTag){ + case WAVE_FORMAT_PCM:StringCchCat(text,5000,L"PCM Waveform Audio");break; + case AUDIO_DVI_ADPCM:StringCchCat(text,5000,L"DVI ADPCM");break; + case AUDIO_MPEG1:StringCchCat(text,5000,L"MPEG1 Layer 1/2");break; + case WAVE_FORMAT_MPEGLAYER3:StringCchCat(text,5000,L"MPEG1 Layer3");break; + case WAVE_FORMAT_DOLBY_AC3_SPDIF: + case AUDIO_AC3 :StringCchCat(text,5000,L"DOLBY AC3");break; + case WAVE_FORMAT_WMAVOICE9: case WAVE_FORMAT_WMAVOICE10: case WAVE_FORMAT_MSAUDIO1: + case WAVE_FORMAT_WMAUDIO2: case WAVE_FORMAT_WMAUDIO3: case WAVE_FORMAT_WMAUDIO_LOSSLESS: + case WAVE_FORMAT_WMASPDIF: StringCchCat(text,5000,L"Windows Media Audio");break; + case AUDIO_AAC4:case AUDIO_AAC3:case AUDIO_AAC2 :case AUDIO_AAC : + case AUDIO_MPEG4AAC: + case WAVE_FORMAT_MPEG_ADTS_AAC:case WAVE_FORMAT_MPEG_RAW_AAC:case WAVE_FORMAT_NOKIA_MPEG_ADTS_AAC: + case WAVE_FORMAT_NOKIA_MPEG_RAW_AAC:case WAVE_FORMAT_VODAFONE_MPEG_ADTS_AAC: + case WAVE_FORMAT_VODAFONE_MPEG_RAW_AAC: + StringCchCat(text,5000,L"Advanced Audio Coding (AAC)");break; + case AUDIO_FLAC:StringCchCat(text,5000,L"Free Lossless Audio Codec (FLAC)");break; + case AUDIO_WAVEPACK:StringCchCat(text,5000,L"WavePack");break; + case AUDIO_AMR:StringCchCat(text,5000,L"VOICEAGE AMR");break; + case AUDIO_MPEG2AAC:StringCchCat(text,5000,L"MPEG2");break; + default:StringCchCat(text,5000,L"неизвестен");break; + } + StringCchPrintf(buf,256,L"\nКаналов: %d\nРазрешение: %d бит\nЧастота: %d Гц\n",(int)ai.chans,(int)ai.BitsPerSample,(int)ai.nFreq); + StringCchCat(text,5000,buf); + StringCchPrintf(buf,256,L"Скорость: %d кбит/с\n",(int)(ai.BitsPerSecond/1000.0));StringCchCat(text,5000,buf); +} +else{StringCchCat(text,5000,L"[Нет данных]\n");} +StringCchCat(text,5000,L"==ВИДЕО:==\n"); +if(wRes==INFORES_VIDEO||wRes==INFORES_BOTH){ +fcc=(FOURCC_EXTRACTOR*)&vi.dwVideoCodec; +StringCchCat(text,5000,L"Кодек:"); + +if(vi.dwVideoCodec==BI_RGB){ + switch(vi.VideoType){ + case VIDEOTYPE_MPEG1:StringCchCat(text,5000,L"MPEG1\n");break; + case VIDEOTYPE_MPEG2:StringCchCat(text,5000,L"MPEG2\n");break; + case VIDEOTYPE_VIDEO:default:StringCchCat(text,5000,L"RGB\n"); + } +} +else{ + StringCchPrintf(buf,256,L"%c%c%c%c\n",fcc->chars[0],fcc->chars[1],fcc->chars[2],fcc->chars[3]); + StringCchCat(text,5000,buf); +} +StringCchPrintf(buf,256,L"Глубина цвета: %d бит\nКадров в секунду: %d\n",(int)vi.BitsPerPixel,(int)vi.FramesPerSecond); +StringCchCat(text,5000,buf); +StringCchPrintf(buf,256,L"Разрешение: %d x %d \n",(int)vi.width,(int)vi.height); +StringCchCat(text,5000,buf); +StringCchPrintf(buf,256,L"Разрешение(эфф.): %d x %d \n",(int)(vi.rcSource.right-vi.rcSource.left),(int)(vi.rcSource.bottom-vi.rcSource.top)); +StringCchCat(text,5000,buf); +} +else{StringCchCat(text,5000,L"[Нет данных]\n");} +MessageBox(hMainWnd,text,L"Информация о файле",MB_OK); +} + +void GetMultimediaInfo(TCHAR* text,int len){ +WORD wRes=0; +SMP_AUDIOINFO ai={0}; +SMP_VIDEOINFO vi={0}; +FOURCC_EXTRACTOR* fcc=NULL; +TCHAR buf[MAX_PATH]; +SMP_STREAM stream=STREAM_UNKNOWN; + +GetPlaylistElement(CurrentTrack,buf); +StringCchCopy(text,len,buf); + +wRes=GetMultimediaInfo(&ai,&vi,&stream); + +StringCchCat(text,len,L"\n\nФормат: "); +switch(stream){ +case STREAM_AVI:StringCchCat(text,len,L"Audio-Video Interleaved\n");break; +case STREAM_ASF:StringCchCat(text,len,L"Advanced Systems Format\n");break; +case STREAM_MPEG1:StringCchCat(text,len,L"MPEG1\n");break; +case STREAM_MPEG1VCD:StringCchCat(text,len,L"MPEG1 VideoCD\n");break; +case STREAM_MPEG2:StringCchCat(text,len,L"MPEG2\n");break; +case STREAM_WAVE:StringCchCat(text,len,L"Waveform Audio\n");break; +case STREAM_QUICKTIME:StringCchCat(text,len,L"Apple(tm) Quick Time Movie\n");break; +case STREAM_UNKNOWN:default:StringCchCat(text,len,L"[неизвестно]\n");break; +} +StringCchCat(text,len,L"Аудио: "); +if(wRes==INFORES_AUDIO||wRes==INFORES_BOTH){ + + switch(ai.wFormatTag){ + case WAVE_FORMAT_PCM:StringCchCat(text,len,L"PCM Waveform Audio");break; + case AUDIO_DVI_ADPCM:StringCchCat(text,len,L"DVI ADPCM");break; + case AUDIO_MPEG1:StringCchCat(text,len,L"MPEG1 Layer 1/2");break; + case WAVE_FORMAT_MPEGLAYER3:StringCchCat(text,len,L"MPEG1 Layer3");break; + case WAVE_FORMAT_DOLBY_AC3_SPDIF: + case AUDIO_AC3 :StringCchCat(text,len,L"DOLBY AC3");break; + case WAVE_FORMAT_WMAVOICE9: case WAVE_FORMAT_WMAVOICE10: case WAVE_FORMAT_MSAUDIO1: + case WAVE_FORMAT_WMAUDIO2: case WAVE_FORMAT_WMAUDIO3: case WAVE_FORMAT_WMAUDIO_LOSSLESS: + case WAVE_FORMAT_WMASPDIF: StringCchCat(text,len,L"Windows Media Audio");break; + case AUDIO_AAC4:case AUDIO_AAC3:case AUDIO_AAC2 :case AUDIO_AAC : + case AUDIO_MPEG4AAC: + case WAVE_FORMAT_MPEG_ADTS_AAC:case WAVE_FORMAT_MPEG_RAW_AAC:case WAVE_FORMAT_NOKIA_MPEG_ADTS_AAC: + case WAVE_FORMAT_NOKIA_MPEG_RAW_AAC:case WAVE_FORMAT_VODAFONE_MPEG_ADTS_AAC: + case WAVE_FORMAT_VODAFONE_MPEG_RAW_AAC: + StringCchCat(text,len,L"Advanced Audio Coding (AAC)");break; + case AUDIO_FLAC:StringCchCat(text,len,L"Free Lossless Audio Codec (FLAC)");break; + case AUDIO_WAVEPACK:StringCchCat(text,len,L"WavePack");break; + case AUDIO_AMR:StringCchCat(text,len,L"VOICEAGE AMR");break; + case AUDIO_MPEG2AAC:StringCchCat(text,len,L"MPEG2");break; + default:StringCchCat(text,len,L"неизвестен");break; + } + StringCchPrintf(buf,256,L" | %d кан. | %d Гц |",(int)ai.chans,(int)ai.nFreq); + StringCchCat(text,len,buf); + StringCchPrintf(buf,256,L" %d кбит/с\n",(int)(ai.BitsPerSecond/1000.0));StringCchCat(text,5000,buf); +} +else{StringCchCat(text,len,L"[Нет]\n");} +StringCchCat(text,5000,L"Видео: "); +if(wRes==INFORES_VIDEO||wRes==INFORES_BOTH){ +fcc=(FOURCC_EXTRACTOR*)&vi.dwVideoCodec; + +if(vi.dwVideoCodec==BI_RGB){ + switch(vi.VideoType){ + case VIDEOTYPE_MPEG1:StringCchCat(text,len,L"MPEG1 ");break; + case VIDEOTYPE_MPEG2:StringCchCat(text,len,L"MPEG2 ");break; + case VIDEOTYPE_VIDEO:default:StringCchCat(text,len,L"RGB "); + } +} +else{ + StringCchPrintf(buf,256,L"%c%c%c%c ",fcc->chars[0],fcc->chars[1],fcc->chars[2],fcc->chars[3]); + StringCchCat(text,len,buf); +} +StringCchPrintf(buf,256,L" | %d бит | %d кадр./с ",(int)vi.BitsPerPixel,(int)vi.FramesPerSecond); +StringCchCat(text,5000,buf); +StringCchPrintf(buf,256,L"[%d x %d]\n",(int)vi.width,(int)vi.height); +StringCchCat(text,len,buf); + +} +else{StringCchCat(text,len,L"[Нет]\n");} +} + + +void RunTimer(){ + if(IsTimerWorking!=FALSE)return; + SetTimer(hMainWnd,TIMER_UPDATE_POSITION,UpdatePosTimerPeriod,NULL); + IsTimerWorking=TRUE;} + +void StopTimer(){ +if(IsTimerWorking==FALSE)return; + +KillTimer(hMainWnd,TIMER_UPDATE_POSITION); + +IsTimerWorking=FALSE;} + +void ProcessOFNString(TCHAR* str,WORD nFileOffset){ +int i,n; +TCHAR* p=NULL; +TCHAR FileName[MAX_PATH+10]=L""; + +i=lstrlen(str); +if(str[i+1]==0){ + AddPlaylistElement(str); + return; +} +p=&(str[nFileOffset]); +n=nFileOffset; + while(1){ +StringCchCopy(FileName,MAX_PATH+10,str); +StringCchCat(FileName,MAX_PATH+10,L"\\"); +StringCchCat(FileName,MAX_PATH+10,p); +AddPlaylistElement(FileName); +i=lstrlen(p)+1; +n+=i; +if(str[n]==0)break; +if(n>=5000)break; +p=&(str[n]); + } +} + +int CALLBACK BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData){ + + switch(uMsg){ +case BFFM_VALIDATEFAILED:return TRUE; +case BFFM_INITIALIZED: + if(lstrcmp(strInputFolder,L"")==0)break; + SendMessage(hwnd,BFFM_SETSELECTION,TRUE,(LONG)strInputFolder); + + break; + } + +return 0; +} + +void ProcessCommandLine(wchar_t* cmd){ + int i,j=0; + + BOOL fOpenFolder=FALSE; + BOOL fAddFile=FALSE; + BOOL FirstFile=TRUE; + + wchar_t filename[MAX_PATH]=L""; + LPWSTR* args=NULL; + int NumArgs=0; + + args=CommandLineToArgvW(cmd,&NumArgs); +if(args==NULL)return; +if(NumArgs==1){ + if(IsTrayIcon==true)SwitchTrayIcon(); + LocalFree(args);return;} +for(i=1;iGetEvent(&EventCode,¶m1,¶m2,100); +if(hr==E_ABORT)break; +switch(EventCode){ + case EC_USERABORT:Close();break; + //errors + case EC_FILE_CLOSED: + case EC_ERRORABORT:MessageBeep(MB_ICONERROR); + //complete + case EC_COMPLETE:Close(); + SetThreadExecutionState (ES_CONTINUOUS); + + PlayNextTrack();break; + +} + +if(pEvent!=NULL){ + + pEvent->FreeEventParams(EventCode,param1,param2); +} + +} + +} + +void StartPlayingPlaylist(){ + + int n=0; + if(CurrMode==RANDOM)n=rand()%CountTracks; + if(n>=CountTracks)n=0; + PlayTrackByNumber(n); + +} +void PlayClick(){ + RunTimer(); + if(PlayerState==FILE_NOT_LOADED){ + + StartPlayingPlaylist(); + + } + else{ + Play();} + + +} + +void PauseClick() +{ + +if(PlayerState==PLAYING) Pause(); +else if(PlayerState==PAUSED)Resume(); + +} + +BOOL CALLBACK URLDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){ + +switch(uMsg){ +case WM_INITDIALOG: + + return TRUE; + +case WM_COMMAND:switch(LOWORD(wParam)){ + +case IDOK:GetDlgItemText(hDlg,IDC_URL,strInputURL,sizeof(strInputURL)); + fInputURL=true;EndDialog(hDlg,0);return TRUE; + case IDCANCEL:fInputURL=false; + EndDialog(hDlg,0);return TRUE; + + }break; +case WM_CLOSE:EndDialog(hDlg,0);return TRUE; + + } +return FALSE; +} + +BOOL CALLBACK IntegrDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){ + + wchar_t buf[256]; + + +switch(uMsg){ +case WM_INITDIALOG: + + return TRUE; + +case WM_COMMAND:switch(LOWORD(wParam)){ +case ID_ASSOCF: + if(RegisterFolderAssociation()==FALSE)MessageBox(0,L"Не удалось ассоциировать с папками",0,0); + + break; +case ID_DELDIRA: + DestroyFolderAssociation();break; +case IDC_ASSOCFILE:GetDlgItemText(hDlg,IDC_EXT,buf,sizeof(buf)); + RegisterFileAssociation(buf); + break; +case ID_DELFILEA:GetDlgItemText(hDlg,IDC_EXT,buf,sizeof(buf)); + DestroyFileAssociation(buf);break; +case IDOK: + case IDCANCEL:EndDialog(hDlg,0);return TRUE; + + }break; +case WM_CLOSE:EndDialog(hDlg,0);return TRUE; + + } +return FALSE; +} + +BOOL CALLBACK PlaybackDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){ + + DWORD pos; + +switch(uMsg){ +case WM_INITDIALOG: + + return TRUE; + +case WM_HSCROLL: + +if(lParam==(LPARAM)hScrollbar) { + Progress.ProcessScrollEvent((short)LOWORD(wParam),(short)HIWORD(wParam)); + pos=Progress.GetTrackPos()*1000; + SetPosition(pos); + UpdatePosition(); +} +break; + +case WM_VSCROLL: + if(lParam==(LPARAM)hVolume) { + /*if(PlayerState!=FILE_NOT_LOADED)*/ + CurrVolume=SendMessage(hVolume,TBM_GETPOS,0,0); + SetVolume(100-CurrVolume); + } + break; + +case WM_COMMAND: +switch(LOWORD(wParam)){ +case ID_PLAY:PlayClick();break; +case ID_PAUSE:PauseClick();break; +case ID_STOP: + Rewind(); + UpdatePosition(); + Stop(); + StopTimer(); + fShowNextImage=false; + break; +case ID_REWIND:Rewind();break; +case ID_NEXTTRACK:PlayTrackByNumber(CurrentTrack+1);break; +case ID_PREVTRACK:PlayTrackByNumber(CurrentTrack-1);break; + }break; + + } +return FALSE; +} + +BOOL CALLBACK MainDlgProc(HWND hDlg,UINT uMsg,WPARAM wParam,LPARAM lParam){ +OPENFILENAMEW ofn={0}; +POINT pt={0,0}; + wchar_t FileName[MAX_PATH]=L""; + BOOL success=FALSE; + LPNMITEMACTIVATE lpnmitem; + LPNMLVKEYDOWN pnkd; + BROWSEINFO bi={0}; + PIDLIST_ABSOLUTE pidres=NULL; + DWORD id; + + int i,n; + +switch(uMsg){ +case WM_INITDIALOG:return TRUE; +case WM_CHILDACTIVATE: + RedrawWindow(hDlg,NULL,NULL,RDW_ERASE|RDW_FRAME|RDW_INVALIDATE); + ShowWindow(hDlg,SW_SHOW);break; +case WM_SIZE: + UpdatePlaylist(); + RedrawWindow(hDlg,NULL,NULL,RDW_ERASE|RDW_FRAME|RDW_INVALIDATE); + ShowWindow(hDlg,SW_SHOW); + break; +case WM_NOTIFY: + lpnmitem = (LPNMITEMACTIVATE) lParam; + switch(lpnmitem->hdr.code){ +case NM_DBLCLK: +i=GetPlaylistSelectedElement(); +Stop(); + +PlayTrackByNumber(i); +RunTimer();break; +case NM_RCLICK: + pt.x=(LONG)lpnmitem->ptAction.x; + pt.y=(LONG)lpnmitem->ptAction.y; + ClientToScreen(PlayList,&pt); +ShowContextMenu(MNUM_PLAYLISTMENU,pt.x,pt.y); +fBlockContextMenu=true; + return TRUE; +case LVN_KEYDOWN: + pnkd = (LPNMLVKEYDOWN) lParam; +//KEYBOARD EVENT + switch(pnkd->wVKey){ +case VK_SPACE: +i=GetPlaylistSelectedElement(); +Stop(); +PlayTrackByNumber(i); +RunTimer();break; +case VK_DELETE: +n=ListView_GetSelectionMark(PlayList); + +for(i=CountTracks;i>=0;i--){ + if(IsPlaylistItemSelected(i))DeletePlaylistElement(i); +} + + +if(((UINT)n)>=CountTracks)n=CountTracks-1; +if(n==-1)break; +SetPlaylistSelectedElement(n); +break; + + }break; +//END OF KEYBOARD EVENT +case LVN_COLUMNCLICK://click column to sort +LPNMLISTVIEW pclick=(LPNMLISTVIEW) lParam; +TCHAR buf[MAX_PATH]=L""; +GetPlaylistElement(CurrentTrack,buf); +if(pls_LastSortColumn==pclick->iSubItem){pls_SortReverse=!pls_SortReverse;} +pls_LastSortColumn=pclick->iSubItem; +ListView_SortItemsEx(PlayList,CompareFunc,pclick->iSubItem); + +CurrentTrack=FindTrack(buf); +if(CurrentTrack==-1)CurrentTrack=0; + break; + } + +break; + +case WM_COMMAND:switch(LOWORD(wParam)){ + +case ID_ADDFILE: + if(fPlaylistBlocked)break; + for(i=0;i=0;i--){ + if(IsPlaylistItemSelected(i))DeletePlaylistElement(i); +} + +if(((UINT)n)>=CountTracks)n=CountTracks-1; +if(n==-1)break; +SetPlaylistSelectedElement(n); +break; + +case ID_CLEAR:if(fPlaylistBlocked)break; + Close(); + ClearPlaylist();break; + +case ID_ADDFOLDER:if(fPlaylistBlocked)break; + +bi.hwndOwner=hMainWnd; +bi.pidlRoot=NULL; + +bi.pszDisplayName=FileName; +bi.lpfn=BrowseCallbackProc; +pidres=SHBrowseForFolder(&bi); +if(pidres==NULL)break; +SHGetPathFromIDList(pidres,strInputFolder); +CoTaskMemFree(pidres); +StringCchCat(strInputFolder,MAX_PATH,L"\\"); +//ADD FOLDER IN ASYNC MODE +CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DirThreadFunc,(LPVOID)strInputFolder,0,&id); + +break; + +case IDC_INTEGR: + DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_INTEGR),hMainWnd, + IntegrDlgProc); + break; + + + + + }break; + + + } +return FALSE; +} + +LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){ + OPENFILENAME ofn={0}; + +HDC hDC;PAINTSTRUCT ps;RECT rc; +wchar_t FileName[MAX_PATH]=L""; +int i,n; + BOOL success=FALSE; + BROWSEINFO bi={0}; + PIDLIST_ABSOLUTE pidres=NULL; + DWORD id; + POINT pt={0}; + int d; + +switch(uMsg){ + + case WM_MOUSEWHEEL:d=GET_WHEEL_DELTA_WPARAM(wParam); + SetVolume(GetVolume()+(d/WHEEL_DELTA)*VOLUME_INCREMENT); + SendMessage(hVolume,TBM_SETPOS,TRUE,100-GetVolume());break; + case WM_SIZE: UpdateView();SaveWindowSize();break; + +case WM_COMMAND:switch(LOWORD(wParam)){ + +case ID_ADDFILE:case ID_ADDFOLDER:case ID_CLEAR: + SendMessage(hMainDlg,uMsg,wParam,lParam);break; + +case ID_ADDURL:DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_URL),hWnd,URLDlgProc); + if(fInputURL==false)break; + AddPlaylistElement(strInputURL); + break; + +case ID_ADDDIR_IMAGES:if(fPlaylistBlocked)break; + fIncludeImages=true; +bi.hwndOwner=hMainWnd; +bi.pidlRoot=NULL; +bi.pszDisplayName=FileName; +bi.lpfn=BrowseCallbackProc; +pidres=SHBrowseForFolder(&bi); +if(pidres==NULL)break; +SHGetPathFromIDList(pidres,strInputFolder); +CoTaskMemFree(pidres); +StringCchCat(strInputFolder,MAX_PATH,L"\\"); +//ADD FOLDER IN ASYNC MODE +CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DirThreadFunc,(LPVOID)strInputFolder,0,&id); + break; + +case ID_VOLUMEUP:SetVolume(GetVolume()+VOLUME_INCREMENT); + SendMessage(hVolume,TBM_SETPOS,TRUE,100-GetVolume());break; +case ID_VOLUMEDOWN:SetVolume(GetVolume()-VOLUME_INCREMENT); + SendMessage(hVolume,TBM_SETPOS,TRUE,100-GetVolume());break; +case ID_PLAYPAUSE:if(PlayerState==PLAYING)Pause(); + else PlayClick(); +break; + +case ID_PLAY:case ID_PAUSE:case ID_STOP:case ID_REWIND: +case ID_NEXTTRACK:case ID_PREVTRACK: + SendMessage(hPlaybackDlg,uMsg,wParam,lParam);break; + +case ID_LOADLIST:if(fPlaylistBlocked)break; + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.lpstrFile=FileName; + ofn.nMaxFile=sizeof(FileName); + ofn.lpstrFilter=strPlaylistFilter; + ofn.nFilterIndex=1; + ofn.lpstrTitle=L"Загрузить список воспроизведения"; + ofn.Flags=OFN_HIDEREADONLY|OFN_FILEMUSTEXIST|OFN_LONGNAMES; + success=GetOpenFileNameW(&ofn); + if(!success){break;} + ClearPlaylist(); + LoadTextPlaylist(FileName); + break; +case ID_SAVELIST: + ofn.lStructSize=sizeof(OPENFILENAME); + ofn.lpstrFile=FileName; + ofn.nMaxFile=sizeof(FileName); + ofn.lpstrFilter=strPlaylistFilter; + ofn.nFilterIndex=1; + ofn.lpstrTitle=L"Сохранить список воспроизведения"; + ofn.Flags=OFN_HIDEREADONLY|OFN_LONGNAMES; + ofn.lpstrDefExt=L"lst"; + StringCchCopy(FileName,MAX_PATH,L"playlist.lst"); + success=GetSaveFileNameW(&ofn); + if(!success){break;} + SaveTextPlaylist(FileName); + break; +case ID_SETTINGS:DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_SETTINGS),hWnd,SettingsDlgProc); + InvalidateRect(hCoverWnd,NULL,TRUE); + break; +case IDC_INTEGR:DialogBox(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_INTEGR),hWnd,IntegrDlgProc); + break; +case ID_OPEN:if(fPlaylistBlocked)break; + for(i=0;i=0;i--){ + if(IsPlaylistItemSelected(i))DeletePlaylistElement(i); +} +if(((UINT)n)>=CountTracks)n=CountTracks-1; +if(n==-1)break; +SetPlaylistSelectedElement(n); +break; +case ID_MINIMIZE:SwitchTrayIcon();break; +case ID_ABOUT: + MessageBox(hMainWnd,TEXT("\ +Small Media Player v2.0\n\ +Разработчик: SmallSoft\n\ +E-Mail: vadim--111@yandex.ru\n\ +Сайт: http://smallsoft2.blogspot.ru/\n\ +"), +TEXT("О программе"),MB_OK|MB_ICONINFORMATION);break; +case ID_EXIT:SendMessage(hMainWnd,WM_CLOSE,0,0);break; + + } + //after WM_COMMAND + if(HIWORD(wParam)==0){InvalidateRect(hPlaybackDlg,NULL,TRUE); + UpdateWindow(hPlaybackDlg);} + break; +case WM_SYSCOMMAND: + if(wParam==SC_SCREENSAVE){ +if(IsPlayingVideo==true)return 0; + } + return DefWindowProc(hWnd,uMsg,wParam,lParam); + case MM_MCINOTIFY: + ProcessNotify(wParam);break; + case WM_CONTEXTMENU: + if(fBlockContextMenu==true){fBlockContextMenu=false;break;} + ShowContextMenu(MNUM_MAINMENU,(int)GET_X_LPARAM(lParam),(int)GET_Y_LPARAM(lParam)); + break; + case UM_TRAYICON: + if(lParam==WM_RBUTTONDOWN||lParam==WM_CONTEXTMENU){ + if(GetCursorPos(&pt)==FALSE){ + GetClientRect(GetDesktopWindow(),&rc); + pt.x=rc.right;pt.y=rc.bottom;} + SetForegroundWindow(hMainWnd); + ShowContextMenu(MNUM_MAINMENU,pt.x,pt.y); + PostMessage(hMainWnd, WM_NULL, 0, 0); + } + if(lParam==WM_LBUTTONDBLCLK){SwitchTrayIcon();} + break; + case WM_TIMER: + UpdatePosition(); + break; + case WM_PAINT:hDC=BeginPaint(hWnd,&ps); + + GetClientRect(hWnd,&rc); + DrawText(hDC,txtMediaInfo,wcslen(txtMediaInfo),&rcInfoBox,0); + + EndPaint(hWnd,&ps);break; + + case WM_CLOSE: + SaveWindowSize(); + if(IsTrayIcon==true)SwitchTrayIcon(); + + if(Settings.fLoadDefaultPls==true){ + TCHAR buf[MAX_PATH]; + + HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, buf); + if(result!=S_OK)GetFileDirectory(ProgramFileName,buf); + else StringCchCat(buf,MAX_PATH,L"\\Small Media Player\\"); + + StringCchCat(buf,MAX_PATH,L"default.lst"); + SaveTextPlaylist(buf); + } + + if(Settings.fRememberPosition==true)SaveLastPosition(); + WriteSettings(); + + Close(); + TerminateThread(hThread,0); + CloseHandle(hThread); + CloseHandle(hPipe); + ReleaseMutex(hMutex); + DestroyWindow(hWnd);break; + case WM_DESTROY:PostQuitMessage(0);break; + default: return DefWindowProc(hWnd,uMsg,wParam,lParam);} +return 0; + +} + +LRESULT CALLBACK VideoWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){ + +int pos; + +switch(uMsg){ + +case WM_MOUSEWHEEL:pos=GET_WHEEL_DELTA_WPARAM(wParam); + SetVolume(GetVolume()+(pos/WHEEL_DELTA)*VOLUME_INCREMENT); + SendMessage(hVolume,TBM_SETPOS,TRUE,100-GetVolume());break; + + case WM_SIZE:case WM_MOVE: + SetVideoRect(); + UpdateWindow(hWnd); + break; +case WM_SYSCOMMAND: + if(wParam==SC_SCREENSAVE){ +if(IsPlayingVideo==true)return 0; + } + return DefWindowProc(hWnd,uMsg,wParam,lParam); +case WM_CONTEXTMENU: + if(IsCursorShown()==FALSE){ShowCursor(TRUE);} + ShowContextMenu(MNUM_MAINMENU,(int)GET_X_LPARAM(lParam),(int)GET_Y_LPARAM(lParam)); + break; +case WM_LBUTTONDBLCLK: + if(FullScreen==true){DisableFullScreen(); + ShowWindow(hVideoWindow,SW_SHOW); + SetFocus(hVideoWindow);} + else{EnableFullScreen();} + break; + case WM_MOUSEMOVE:case WM_LBUTTONDOWN: + if(FullScreen==true)SetTimer(hVideoWindow,TM_HIDE_CURSOR,1000,NULL); + if(IsCursorShown()==FALSE){ShowCursor(TRUE);} + break; + //===accelarator redirect==== + case WM_COMMAND:if(HIWORD(wParam)==1){SendMessage(hMainWnd,uMsg,wParam,lParam);return 0;} + else {return DefWindowProc(hWnd,uMsg,wParam,lParam);} + //=================== + case WM_TIMER: + switch(wParam){ + case TM_NEXT_IMAGE:KillTimer(hWnd,TM_NEXT_IMAGE); + if(fShowNextImage==false)break; + fShowNextImage=false; + if(CurrMode!=REPEAT_FILE)PlayNextTrack(); + break; + case TM_HIDE_CURSOR:KillTimer(hWnd,TM_HIDE_CURSOR); + if(FullScreen==false)break; + if(IsCursorShown()!=FALSE){ShowCursor(FALSE);} + } + break; + case WM_KEYDOWN: + switch(wParam){ + case VK_RETURN: + if(FullScreen==true){DisableFullScreen(); + SetFocus(hVideoWindow);} + else{EnableFullScreen();} + break; + case VK_LEFT: + pos=(Progress.GetTrackPos()-20)*1000; + SetPosition(pos); + UpdatePosition(); +break; + case VK_RIGHT: + pos=(Progress.GetTrackPos()+20)*1000; + SetPosition(pos); + UpdatePosition(); +break; + case VK_UP: + SetVolume(GetVolume()+VOLUME_INCREMENT); + SendMessage(hVolume,TBM_SETPOS,TRUE,100-GetVolume());break; + case VK_DOWN: + SetVolume(GetVolume()-VOLUME_INCREMENT); + SendMessage(hVolume,TBM_SETPOS,TRUE,100-GetVolume());break; + }break; + + case WM_CLOSE: + ShowWindow(hWnd,SW_HIDE); + break; + + default: return DefWindowProc(hWnd,uMsg,wParam,lParam);} +return 0; + +} + +LRESULT CALLBACK CoverWndProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam){ +HDC hDC;PAINTSTRUCT ps;RECT rc; +switch(uMsg){ + case WM_CLOSE: + ShowWindow(hWnd,SW_HIDE); + Settings.fShowCover=false; + UpdateView(); + break; + + case WM_CHILDACTIVATE:case WM_SIZE: + RedrawWindow(hWnd,NULL,NULL,RDW_ERASE|RDW_FRAME|RDW_INVALIDATE|RDW_UPDATENOW); + //ShowWindow(hWnd,SW_SHOW); + break; + + case WM_PAINT: +hDC=BeginPaint(hWnd,&ps); + GetClientRect(hWnd,&rc); + //drawing... + if(DrawCover(hDC,&rc)==false) + { + DrawPattern(hDC,&rc);//if no cover, draw image + } + EndPaint(hWnd,&ps);break; + + default: return DefWindowProc(hWnd,uMsg,wParam,lParam);} +return 0;} + +void New_WinMain(void){ + + wchar_t wclass_name[]=L"MyClass";MSG msg;WNDCLASSEX wc; +TCHAR* cmd; +RECT rc={0}; +int w=0; +int h=0; + +int i=0,j=0; +BOOL skip=FALSE; + +DWORD id; +DWORD dwCount; +ULONG_PTR gdip_code; +TCHAR buf[256]=L""; + +INITCOMMONCONTROLSEX ic; +LVCOLUMN col={0}; +HANDLE hDestPipe; +HMENU hm=NULL; + +OSVERSIONINFO osver={0}; +osver.dwOSVersionInfoSize=sizeof(OSVERSIONINFO); +DWORD exStyle; + +//determine OS version, to avoid WinXP visual bugs +if(GetVersionEx(&osver)==FALSE){exStyle=0;} +else { + if(osver.dwMajorVersion<=5)exStyle=0; //WinXP + else exStyle=WS_EX_COMPOSITED;//new systems +} + +//CHECK IF PROGRAM ALREADY RAN +hMutex=CreateMutexW(NULL,TRUE,L"SmallMediaPlayer"); +if (GetLastError()==ERROR_ALREADY_EXISTS){ +//program already run +hDestPipe=CreateFileW(L"\\\\.\\pipe\\SmallMediaPlayer", +GENERIC_WRITE,0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + cmd=GetCommandLineW(); +WriteFile(hDestPipe,cmd,2*wcslen(cmd)+1, +&dwCount, NULL); +CloseHandle(hDestPipe); +CloseHandle(hMutex); +ExitProcess(0);} + +CoInitialize(NULL); +srand(GetTickCount()); +ic.dwSize=sizeof(ic); +ic.dwICC=ICC_WIN95_CLASSES; +InitCommonControlsEx(&ic); +GdiplusStartup(&gdip_code, new GdiplusStartupInput(),NULL); + + +GetModuleFileName(NULL,ProgramFileName,sizeof(ProgramFileName)); +LoadSettings(); +hAccel=LoadAccelerators(GetModuleHandle(NULL),MAKEINTRESOURCE(ID_ACCEL)); +hm=LoadMenu(NULL,MAKEINTRESOURCE(IDR_CONTEXT_MENU)); +hcMainMenu=GetSubMenu(hm,0); +hcPlaylistMenu=GetSubMenu(hm,1); + +HMODULE hLib=LoadLibrary(L"shell32.dll"); +if(hLib==NULL)MessageBox(0,L"Unable to load SHELL32.DLL",0,MB_OK|MB_ICONERROR); +hSMPIcon=LoadIcon(hLib, MAKEINTRESOURCE(228)); +if(hSMPIcon==NULL)hSMPIcon=LoadIcon(NULL,IDI_APPLICATION); + +wc.hIcon=hSMPIcon; + //create wclass structure + wc.cbSize=sizeof(wc); + wc.style=0; + wc.lpfnWndProc=WndProc; + wc.cbClsExtra=0; + wc.cbWndExtra=0; + wc.hInstance=GetModuleHandle(NULL); + + wc.hCursor=LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH); + wc.lpszMenuName=MAKEINTRESOURCE(IDR_MENU1); + wc.lpszClassName=wclass_name; + wc.hIconSm=wc.hIcon; + //register class + if(!RegisterClassEx(&wc)){ + MessageBox(NULL,L"Fail to create class",L"Error",MB_ICONEXCLAMATION|MB_OK); + ExitProcess(-1);} + + //create wclass structure VIDEO WINDOW + wc.cbSize=sizeof(wc); + wc.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS; + wc.lpfnWndProc=VideoWndProc; + wc.cbClsExtra=0; + wc.cbWndExtra=0; + wc.hInstance=GetModuleHandle(NULL); + wc.hIcon=LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor=LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); + wc.lpszMenuName=NULL; + wc.lpszClassName=L"VIDEOWINDOW"; + wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION); + //register class + if(!RegisterClassEx(&wc)){ + MessageBox(NULL,L"Fail to create class",L"Error",MB_ICONEXCLAMATION|MB_OK); + ExitProcess( -1);} + //create wclass structure COVER WINDOW + wc.cbSize=sizeof(wc); + wc.style=CS_HREDRAW|CS_VREDRAW; + wc.lpfnWndProc=CoverWndProc; + wc.cbClsExtra=0; + wc.cbWndExtra=0; + wc.hInstance=GetModuleHandle(NULL); + wc.hIcon=LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor=LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground=(HBRUSH)GetStockObject(LTGRAY_BRUSH); + wc.lpszMenuName=NULL; + wc.lpszClassName=L"COVERWINDOW"; + wc.hIconSm=LoadIcon(NULL,IDI_APPLICATION); + + //register class + if(!RegisterClassEx(&wc)) + { + MessageBox(NULL,L"Fail to create class",L"Error",MB_ICONEXCLAMATION|MB_OK); + ExitProcess( -1); + } + + //determine window size + int ww=Settings.WndWidth,wh=Settings.WndHeight; + if(Settings.WndMaximized!=false){ww=CW_USEDEFAULT;wh=0;} + ; + //create window + hMainWnd=CreateWindowEx(0,wclass_name,L"SmallMediaPlayer",WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,Settings.WndX,Settings.WndY, + ww,wh,NULL,NULL,GetModuleHandle(NULL),NULL); + hWnd=hMainWnd; + if(hMainWnd==NULL) + { + MessageBox(NULL,L"Fail to create window",L"Error",MB_ICONEXCLAMATION|MB_OK); + ExitProcess( -1); + } + + if(Settings.WndMaximized != false)ShowWindow(hMainWnd,SW_MAXIMIZE); + else ShowWindow(hMainWnd,SW_SHOWNORMAL); + + +hMainDlg=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_MAIN),hMainWnd,MainDlgProc); +hPlaybackDlg=CreateDialog(GetModuleHandle(NULL),MAKEINTRESOURCE(IDD_PLAYBACK),hMainWnd,PlaybackDlgProc); +hScrollbar=GetDlgItem(hPlaybackDlg,IDC_SCROLLBAR); +Progress=ScrollbarControl(SB_CTL,hScrollbar,0,(int)(20+S_TRACK_SIZE),S_TRACK_SIZE); + +PlayList=CreateWindowEx(0,WC_LISTVIEW,L"СПИСОК",WS_CHILD|WS_VISIBLE|LVS_SHOWSELALWAYS|LVS_REPORT ,0,40, + 580,160,hMainDlg,NULL,GetModuleHandle(NULL),NULL); +ListView_SetExtendedListViewStyle(PlayList,LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER); +if(PlayList==NULL)Beep(300,100); +ShowWindow(PlayList,SW_SHOW); + +col.iSubItem=0; +col.pszText=L"песенка"; +col.cx=150; +col.mask=LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH; +ListView_InsertColumn(PlayList,0,&col); +col.iSubItem=1; +col.pszText=L"исполнитель"; +col.cx=100; +col.mask=LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH; +ListView_InsertColumn(PlayList,1,&col); +col.iSubItem=2; +col.pszText=L"альбом"; +col.cx=100; +col.mask=LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH; +ListView_InsertColumn(PlayList,2,&col); +col.iSubItem=3; +col.pszText=L"год"; +col.cx=45; +col.mask=LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH; +ListView_InsertColumn(PlayList,3,&col); + +col.iSubItem=4; +col.pszText=L"файл"; +col.cx=150; +col.mask=LVCF_TEXT|LVCF_SUBITEM|LVCF_WIDTH; +ListView_InsertColumn(PlayList,4,&col); +InitImageList(); + + +hlstBuffer=CreateWindow(L"LISTBOX",L"",0,CW_USEDEFAULT,0, + CW_USEDEFAULT,0,NULL,NULL,GetModuleHandle(NULL),NULL); +hVideoWindow=CreateWindow(L"VIDEOWINDOW",L"Окно видео",WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN,CW_USEDEFAULT,0, + CW_USEDEFAULT,0,NULL,NULL,GetModuleHandle(NULL),NULL); +hCoverWnd=CreateWindowEx(exStyle,L"COVERWINDOW",L"Обложка",WS_CHILD|WS_BORDER|WS_CLIPSIBLINGS,CW_USEDEFAULT,0, + 200,250,hMainWnd,NULL,GetModuleHandle(NULL),NULL); + +UpdateView(); +hVolume=GetDlgItem(hPlaybackDlg,IDC_VOLUME); +SendMessage(hVolume,TBM_SETRANGE,TRUE,(LPARAM)MAKELONG(0,100)); +CheckMenuRadioItem(GetMenu(hMainWnd),ID_MODE_NORMAL,ID_MODE_RANDOM,ID_MODE_NORMAL,MF_BYCOMMAND); + +CountTracks=0; +PlayerState=FILE_NOT_LOADED; +Extensions[0]=TEXT("mp3");Extensions[1]=TEXT("mid");Extensions[2]=TEXT("wav"); +Extensions[3]=TEXT("midi");Extensions[4]=TEXT("avi");Extensions[5]=TEXT("mpeg"); +Extensions[6]=TEXT("wma");Extensions[7]=TEXT("wmv");Extensions[8]=TEXT("mpg"); +Extensions[9]=TEXT("ogg");Extensions[10]=TEXT("cda");Extensions[11]=TEXT("aac"); +Extensions[12]=TEXT("mkv");Extensions[13]=TEXT("flac");Extensions[14]=TEXT("mov"); +Extensions[15]=TEXT("wv");Extensions[16]=TEXT("ape");Extensions[17]=TEXT("m4a"); + + hThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL, + THREAD_PRIORITY_NORMAL,&id); + +cmd=GetCommandLineW(); + +if(Settings.fLoadWallpaper==true){ + if(Settings.fLoadDefWallpaper==true){ + GetPattern(buf); + LoadPattern(buf);} + else{LoadPattern(Settings.WallpaperFilePath);} +} +InvalidateRect(hMainWnd,NULL,TRUE); +if(Settings.fLoadDefaultPls==true){ + TCHAR buf[MAX_PATH]; + + HRESULT result = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, buf); + if(result!=S_OK)GetFileDirectory(ProgramFileName,buf); + else StringCchCat(buf,MAX_PATH,L"\\Small Media Player\\"); + +StringCchCat(buf,MAX_PATH,L"default.lst"); + LoadTextPlaylist(buf);} +if(Settings.fRememberPosition==true)RestoreLastPosition(); + +UpdateGUI(); +ProcessCommandLine(cmd); + + while(GetMessage(&msg,NULL,0,0)){ + if(IsIconic(hMainWnd)==FALSE){ + if(TranslateAccelerator(hMainWnd,hAccel,&msg))continue; + } + else{ + if(TranslateAccelerator(hVideoWindow,hAccel,&msg))continue; + } + if(IsDialogMessage(hMainDlg,&msg))continue; + if(IsDialogMessage(hPlaybackDlg,&msg))continue; + TranslateMessage(&msg); + DispatchMessage(&msg);} + + + CoUninitialize(); + UnloadCover(); + GdiplusShutdown(gdip_code); + ExitProcess(0); + } + \ No newline at end of file diff --git a/SmallMediaPlayer/player.cpp b/SmallMediaPlayer/player.cpp new file mode 100644 index 0000000..2e01235 --- /dev/null +++ b/SmallMediaPlayer/player.cpp @@ -0,0 +1,1170 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#include "player.h" +#include "PlayListEditor.h" + +extern SMPSETTINGS Settings; +extern TCHAR* GetShortName(TCHAR* fullname); +extern TAGS_GENERIC OpenedFileTags; +extern bool fOpenedFileTags; + +HWND hWnd;//for notify + +PLAYER_STATE PlayerState=FILE_NOT_LOADED; +bool IsPlayingCDA=false; +DWORD DeviceID=0; +UINT TrackNumber=0; +DWORD pos; +long Volume=0; +bool IsPlayingVideo=false; + +bool fShowNextImage=false; +bool FullScreen=false; + +static IGraphBuilder *pGraph = NULL; +static IMediaControl *pControl = NULL; +static IMediaSeeking* pSeek =NULL; + IMediaEventEx *pEvent = NULL; + +static IBasicAudio* pAudio=NULL; +static IVideoWindow* pVideoWindow=NULL; +static IBasicVideo* pVideo=NULL; + +IBaseFilter* pSource=NULL; +IBaseFilter* pSplitter=NULL; +IBaseFilter* pAudioDecoder=NULL; +IBaseFilter* pAudioRenderer=NULL; +IBaseFilter* pVideoDecoder=NULL; +IBaseFilter* pVideoRenderer=NULL; +static bool fUseSplitter=false; +GUID guidStreamSubType=GUID_NULL; + +void GetFileExtension(TCHAR* fname,TCHAR* ext){ +int i=0,c=0; +TCHAR* s=NULL; +c=lstrlen(fname); +for(i=c-1;i>c-8;i--){ + if(fname[i]==L'.'||fname[i]==L'\\'||fname[i]==L'/'){s=&(fname[i+1]);break;} + +} +if(s==NULL){lstrcpy(ext,L"");return;} +lstrcpy(ext,s); +} + +void GetFileExtensionA(char* fname,char* ext){ +int i=0,c=0; +char* s=NULL; +c=lstrlenA(fname); +for(i=c-1;i>c-8;i--){ + if(fname[i]=='.'||fname[i]=='\\'||fname[i]=='/'){s=&(fname[i+1]);break;} + +} +if(s==NULL){lstrcpyA(ext,"");return;} +lstrcpyA(ext,s); +} + +BOOL IsURL(TCHAR* str){ +int i; +int c; +c=lstrlen(str)-4; +for(i=0;iIsSource==true){pSource=FindFilter(sd->FilterName);} +else{ + pSource=FindFilter(L"File Source (Async.)"); + + +} +if(pSource==NULL){goto end_fail;} + +hr=pGraph->AddFilter(pSource,L"source"); +if(FAILED(hr)){goto end_fail;} +hr=pSource->QueryInterface(IID_IFileSourceFilter,(void**)&fs); +if(FAILED(hr)){goto end_fail;} +hr=fs->Load(file,NULL); +fs->Release(); +if(FAILED(hr)){goto end_fail;} + +if(sd->IsSource==false){ + fUseSplitter=true; + hr=GetUnconnectedPin(pSource,PINDIR_OUTPUT,&pin1); + if(FAILED(hr)){goto end_fail;} + pSplitter=FindFilter(sd->FilterName); + if(pSplitter==NULL){goto end_fail;} + hr=pGraph->AddFilter(pSplitter,L"splitter"); +if(FAILED(hr)){goto end_fail;} + hr=GetUnconnectedPin(pSplitter,PINDIR_INPUT,&pin2); + if(FAILED(hr)){goto end_fail;} + hr=pGraph->ConnectDirect(pin1,pin2,NULL); + if(FAILED(hr)){goto end_fail;} + +} +else{ +fUseSplitter=false; +} + +if(pin1!=NULL)pin1->Release(); +if(pin2!=NULL)pin2->Release(); + +return TRUE; + +end_fail: + +if(pin1!=NULL)pin1->Release(); +if(pin2!=NULL)pin2->Release(); +if(pSplitter!=NULL){pGraph->RemoveFilter(pSplitter);pSplitter->Release();pSplitter=NULL;} +if(pSource!=NULL){pGraph->RemoveFilter(pSource);pSource->Release();pSource=NULL;} +return FALSE; + +} + +BOOL InsertAudioDecoder(IPin* pin,TCHAR* lpFilterName){ +HRESULT hr; +IBaseFilter* pf=NULL; +IPin* pin2=NULL; +IPin* pins[10]; +IEnumPins* pEnum=NULL; +ULONG c,i; +PIN_DIRECTION PinDir; + +pf=FindFilter(lpFilterName); +if(pf==NULL)goto end_fail; +hr=pGraph->AddFilter(pf,L"audiodecoder"); +if(FAILED(hr))goto end_fail; +hr=GetUnconnectedPin(pf,PINDIR_INPUT,&pin2); +if(FAILED(hr))goto end_fail; +hr=pGraph->ConnectDirect(pin,pin2,NULL); +if(FAILED(hr))goto end_fail; +pin2->Release();pin2=NULL; +hr=pf->EnumPins(&pEnum); +if(FAILED(hr))goto end_fail; +hr=pEnum->Next(10,pins,&c); +if(FAILED(hr))c=0; +for(i=0;iQueryDirection(&PinDir); + if(PinDir==PINDIR_OUTPUT)pGraph->Render(pins[i]); + pins[i]->Release(); +} + +if(pEnum!=NULL){pEnum->Release();} + +pAudioDecoder=pf; + +return TRUE; +end_fail: +if(pf!=NULL){pGraph->RemoveFilter(pf),pf->Release();} +if(pin2!=NULL){pin2->Release();} +if(pEnum!=NULL){pEnum->Release();} +return FALSE; + +} + +BOOL InsertVideoDecoder(IPin* pin,TCHAR* lpFilterName,TCHAR* lpPinName){ +HRESULT hr; +IBaseFilter* pf=NULL; +IPin* pin2=NULL; +IPin* pins[10]; +IEnumPins* pEnum=NULL; +ULONG c,i; +PIN_DIRECTION PinDir; + +pf=FindFilter(lpFilterName); +if(pf==NULL)goto end_fail; +hr=pGraph->AddFilter(pf,L"videodecoder"); +if(FAILED(hr))goto end_fail; +hr=FindPin(pf,lpPinName,&pin2); + +if(hr==E_FAIL){goto end_fail;} +hr=pGraph->Connect(pin,pin2); +if(FAILED(hr)){goto end_fail;} +pin2->Release();pin2=NULL; +hr=pf->EnumPins(&pEnum); +if(FAILED(hr))goto end_fail; +hr=pEnum->Next(10,pins,&c); +if(FAILED(hr))c=0; +for(i=0;iQueryDirection(&PinDir); + if(PinDir==PINDIR_OUTPUT)pGraph->Render(pins[i]); + pins[i]->Release(); +} + +if(pEnum!=NULL){pEnum->Release();} +if(pin2!=NULL){pin2->Release();} +pVideoDecoder=pf; + + +return TRUE; +end_fail: +if(pEnum!=NULL){pEnum->Release();} +if(pf!=NULL){pGraph->RemoveFilter(pf),pf->Release();} +if(pin2!=NULL){pin2->Release();} +return FALSE; + +} + +BOOL pin_GetAudioInfo(IPin* pin,SMP_AUDIOINFO* pAudioInfo){ +IEnumMediaTypes * pEnum=NULL; +AM_MEDIA_TYPE* amt=NULL; +WAVEFORMATEX* wf=NULL; +HRESULT hr; +ULONG res=0; + +hr=pin->EnumMediaTypes(&pEnum); +if(FAILED(hr))return FALSE; +hr=pEnum->Next(1,&amt,&res); +if(FAILED(hr)||res==0){pEnum->Release();return FALSE;} +if(amt->formattype!=FORMAT_WaveFormatEx){pEnum->Release();return FALSE;} +wf=(WAVEFORMATEX*)amt->pbFormat; +pAudioInfo->chans=wf->nChannels; +pAudioInfo->BitsPerSample=wf->wBitsPerSample; +pAudioInfo->BitsPerSecond=wf->nAvgBytesPerSec*8; +pAudioInfo->nFreq=wf->nSamplesPerSec; +pAudioInfo->wFormatTag=wf->wFormatTag; +if(amt->subtype==MEDIASUBTYPE_DOLBY_AC3){ + pAudioInfo->wFormatTag=AUDIO_AC3;} +if(amt->subtype==MEDIASUBTYPE_MPEG2_AUDIO){ + pAudioInfo->wFormatTag=AUDIO_MPEG2AAC;} +pEnum->Release(); +MyDeleteMediaType(amt); +return TRUE; + +} + +BOOL pin_GetVideoInfo(IPin* pin,SMP_VIDEOINFO* pVideoInfo){ +IEnumMediaTypes * pEnum=NULL; +AM_MEDIA_TYPE* amt=NULL; +BITMAPINFOHEADER* bi=NULL; +REFERENCE_TIME time=0; +double t=0; +HRESULT hr; +ULONG res=0; +RECT rcSource={0}; + +pVideoInfo->VideoType=VIDEOTYPE_VIDEO; +hr=pin->EnumMediaTypes(&pEnum); +if(FAILED(hr))return FALSE; +hr=pEnum->Next(1,&amt,&res); +if(FAILED(hr)||res==0){pEnum->Release();return FALSE;} +if(amt->subtype==MEDIASUBTYPE_MPEG1Packet||amt->subtype==MEDIASUBTYPE_MPEG1Payload||amt->subtype==MEDIASUBTYPE_MPEG1Video){ + pVideoInfo->VideoType=VIDEOTYPE_MPEG1; +} +if(amt->subtype==MEDIASUBTYPE_MPEG2_VIDEO){ + pVideoInfo->VideoType=VIDEOTYPE_MPEG2; +} + +if(amt->formattype==FORMAT_VideoInfo){ +bi=(BITMAPINFOHEADER*)&(((VIDEOINFOHEADER*)(amt->pbFormat))->bmiHeader); +time=((VIDEOINFOHEADER*)(amt->pbFormat))->AvgTimePerFrame; +rcSource=((VIDEOINFOHEADER*)(amt->pbFormat))->rcSource; +} +if(amt->formattype==FORMAT_VideoInfo2){ +bi=(BITMAPINFOHEADER*)&(((VIDEOINFOHEADER2*)(amt->pbFormat))->bmiHeader); +time=((VIDEOINFOHEADER2*)(amt->pbFormat))->AvgTimePerFrame; +rcSource=((VIDEOINFOHEADER2*)(amt->pbFormat))->rcSource; +} +if(amt->formattype==FORMAT_MPEGVideo){ +bi=(BITMAPINFOHEADER*)&(((MPEG1VIDEOINFO*)(amt->pbFormat))->hdr.bmiHeader); +time=((MPEG1VIDEOINFO*)(amt->pbFormat))->hdr.AvgTimePerFrame; +rcSource=((MPEG1VIDEOINFO*)(amt->pbFormat))->hdr.rcSource; +} +if(amt->formattype==FORMAT_MPEG2Video){ +bi=(BITMAPINFOHEADER*)&(((MPEG2VIDEOINFO*)(amt->pbFormat))->hdr.bmiHeader); +time=((MPEG2VIDEOINFO*)(amt->pbFormat))->hdr.AvgTimePerFrame; +rcSource=((MPEG2VIDEOINFO*)(amt->pbFormat))->hdr.rcSource; +} +if(bi==NULL){pEnum->Release();return FALSE;} +t=time/10000000.0; +pVideoInfo->width=bi->biWidth; +pVideoInfo->height=bi->biHeight; +pVideoInfo->BitsPerPixel=bi->biBitCount; +pVideoInfo->dwVideoCodec=bi->biCompression; +if(t!=0){ + pVideoInfo->FramesPerSecond=1.0/t;} +else{pVideoInfo->FramesPerSecond=0;} +pVideoInfo->rcSource=rcSource; +pEnum->Release(); +MyDeleteMediaType(amt); +return TRUE; + +} + +WORD GetMultimediaInfo(SMP_AUDIOINFO* pAudioInfo,SMP_VIDEOINFO* pVideoInfo,SMP_STREAM* pStreamType){ +HRESULT hr; +IEnumPins* pEnum=NULL; +IBaseFilter* pf=NULL; +IPin* pins[10]; +UINT i; +ULONG c=0; +PIN_DIRECTION PinDir; +bool fAudio=false; +bool fVideo=false; + +if(pSplitter!=NULL)pf=pSplitter; +else pf=pSource; +if(pf==NULL)return INFORES_NO; + +hr=pf->EnumPins(&pEnum); +if(FAILED(hr))return INFORES_NO; +if(SUCCEEDED(hr))hr=pEnum->Next(10,pins,&c); +if(FAILED(hr))c=0; +for(i=0;iQueryDirection(&PinDir); + if(PinDir==PINDIR_INPUT)continue; + if(CheckMediaType(pins[i],MEDIATYPE_Audio)!=FALSE){ + if(fAudio==true)continue; + fAudio=pin_GetAudioInfo(pins[i],pAudioInfo); + continue; + } + + if(CheckMediaType(pins[i],MEDIATYPE_Video)!=FALSE){ + if(fVideo==true)continue; + fVideo=pin_GetVideoInfo(pins[i],pVideoInfo); + continue;} +} + +for(i=0;iRelease(); +} +pEnum->Release(); +*pStreamType=STREAM_UNKNOWN; +if(guidStreamSubType==MEDIASUBTYPE_Avi)*pStreamType=STREAM_AVI; +if(guidStreamSubType==MEDIASUBTYPE_Asf)*pStreamType=STREAM_ASF; +if(guidStreamSubType==MEDIASUBTYPE_MPEG1System||guidStreamSubType==MEDIASUBTYPE_MPEG1Audio + ||guidStreamSubType==MEDIASUBTYPE_MPEG1Video)*pStreamType=STREAM_MPEG1; +if(guidStreamSubType==MEDIASUBTYPE_MPEG1VideoCD)*pStreamType=STREAM_MPEG1VCD; +if(guidStreamSubType==MEDIASUBTYPE_WAVE)*pStreamType=STREAM_WAVE; +if(guidStreamSubType==MEDIASUBTYPE_MPEG2_PROGRAM|| + guidStreamSubType==MEDIASUBTYPE_MPEG2_TRANSPORT|| + guidStreamSubType==MEDIASUBTYPE_MPEG2_VIDEO + )*pStreamType=STREAM_MPEG2; +if(guidStreamSubType==MEDIASUBTYPE_QTMovie)*pStreamType=STREAM_QUICKTIME; +if(guidStreamSubType==GUID_NULL)*pStreamType=STREAM_UNKNOWN; + +if(fAudio==false){ + if(fVideo==false)return INFORES_NO; + else return INFORES_VIDEO; +} +else{ + if(fVideo==false)return INFORES_AUDIO; + else return INFORES_BOTH; +} +return INFORES_BOTH; + +} + + + +void SearchFilters(){ +HRESULT hr; +ULONG c,i; +IPin* pins[10]; +IPin* pin=NULL; +PIN_DIRECTION PinDir; +IEnumPins* pEnum=NULL; + + +guidStreamSubType=GUID_NULL; +if(pSource==NULL){ +pSource=FindFileSource(pGraph); +if(pSource==NULL){return;} +} + +//resaecrh sourcefilter pins +hr=pSource->EnumPins(&pEnum); + if(SUCCEEDED(hr))hr=pEnum->Next(10,pins,&c); +if(FAILED(hr))c=0; +for(i=0;iQueryDirection(&PinDir); + if(PinDir==PINDIR_INPUT)continue; + if(CheckMediaType(pins[i],MEDIATYPE_Audio)!=FALSE){ + if(pAudioDecoder==NULL)pAudioDecoder=GetDownstreamFilter(pins[i]); + continue; + } + if(CheckMediaType(pins[i],MEDIATYPE_Video)!=FALSE){ + if(pVideoDecoder==NULL)pVideoDecoder=GetDownstreamFilter(pins[i]); + continue;} + if(CheckMediaType(pins[i],MEDIATYPE_Stream)!=FALSE){ + if(pSplitter==NULL){pSplitter=GetDownstreamFilter(pins[i]);} + continue;} + +} + +for(i=0;iRelease(); +} +pEnum->Release(); +if(pSplitter==NULL)goto check_render; +//ressearch splitter pins + +hr=pSplitter->EnumPins(&pEnum); + if(SUCCEEDED(hr))hr=pEnum->Next(10,pins,&c); +if(FAILED(hr))c=0; +for(i=0;iQueryDirection(&PinDir); + if(PinDir==PINDIR_INPUT)continue; + if(CheckMediaType(pins[i],MEDIATYPE_Audio)!=FALSE){ + if(pAudioDecoder==NULL)pAudioDecoder=GetDownstreamFilter(pins[i]); + continue; + } + if(CheckMediaType(pins[i],MEDIATYPE_Video)!=FALSE){ + if(pVideoDecoder==NULL)pVideoDecoder=GetDownstreamFilter(pins[i]); + continue;} +} +for(i=0;iRelease(); +} +pEnum->Release(); +//get stream subtype +if(pSplitter!=NULL&&pSource!=NULL){ + if(pin!=NULL)pin->Release(); + pin=NULL; + pin=GetOutputPin(pSource); + if(pin!=NULL){GetSubType(pin,&guidStreamSubType);} + pin->Release(); +} + +check_render: +IAMAudioRendererStats* pRnd=NULL; +IBasicVideo* pVid=NULL; + +if(pAudioDecoder!=NULL){ + hr=pAudioDecoder->QueryInterface(IID_IAMAudioRendererStats,(void**)&pRnd); + if(hr==S_OK){ + pAudioRenderer=pAudioDecoder;pAudioDecoder=NULL; + pRnd->Release(); + } +} + +if(pVideoDecoder!=NULL){ + hr=pVideoDecoder->QueryInterface(IID_IBasicVideo,(void**)&pVid); + if(hr==S_OK){ + pVideoRenderer=pVideoDecoder;pVideoDecoder=NULL; + pVid->Release(); + } +} + + +if(pAudioDecoder!=NULL){ +pin=GetOutputPin(pAudioDecoder); +if(pin!=NULL){ + pAudioRenderer=GetDownstreamFilter(pin); + pin->Release();pin=NULL;} +} + +if(pVideoDecoder!=NULL){ +pin=GetOutputPin(pVideoDecoder); +if(pin!=NULL){ + pVideoRenderer=GetDownstreamFilter(pin); + pin->Release();pin=NULL;} +} + +} + +BOOL BuildGraph(MEDIATYPE mt,TCHAR* file){ + IPin* pin=NULL; + IPin* pins[10]; +IEnumPins* pEnum=NULL; +ULONG c,i; +HRESULT hr; +BOOL res; +IBaseFilter* pf; +AM_MEDIA_TYPE* amt=NULL; +PIN_DIRECTION PinDir; + +switch(mt){ + case MT_AUDIO: + res=InsertSplitter(file,&sdBassSource); + if(res==FALSE)res=InsertSplitter(file,&sdAsfReader); + if(res==FALSE)res=InsertSplitter(file,&sdGretechMp3); + if(res==FALSE)res=InsertSplitter(file,&sdNeroSplitter); + if(res==FALSE)res=InsertSplitter(file,&sdMpeg1Splitter); + if(res==FALSE)goto end_fail; + break; + case MT_AVI: +res=InsertSplitter(file,&sdAviSplitter); +if(res==FALSE)res=InsertSplitter(file,&sdGretechAvi); +if(res==FALSE)res=InsertSplitter(file,&sdNeroSplitter); +if(res==FALSE)res=InsertSplitter(file,&sdAviSource); +if(res==FALSE)goto end_fail; +break; + case MT_MPEG: +res=InsertSplitter(file,&sdMpegSource); +if(res==FALSE)res=InsertSplitter(file,&sdMpeg1Splitter); +if(res==FALSE)res=InsertSplitter(file,&sdMpeg2Splitter); +if(res==FALSE)res=InsertSplitter(file,&sdMpegSrcGabest); +if(res==FALSE)res=InsertSplitter(file,&sdNeroSplitter); +if(res==FALSE)goto end_fail; +break; + case MT_MKV: +res=InsertSplitter(file,&sdMkvSource); +if(res==FALSE){res=InsertSplitter(file,&sdHaaliSplitter);} +if(res==FALSE){goto end_fail;} +break; + + default:goto end_fail; + +} + + if(fUseSplitter==true)pf=pSplitter; + else pf=pSource; +//connect splitter to decoders +bool fVideoRendered=false; +bool fAudioRendered=false; + + hr=pf->EnumPins(&pEnum); + if(SUCCEEDED(hr))hr=pEnum->Next(10,pins,&c); +if(FAILED(hr))c=0; +for(i=0;iQueryDirection(&PinDir); + if(PinDir==PINDIR_INPUT)continue; + if(CheckMediaType(pins[i],MEDIATYPE_Audio)!=FALSE){ + if(fAudioRendered==true)goto next; + res=InsertAudioDecoder(pins[i],L"ffdshow Audio Decoder"); + + if(res==FALSE){pGraph->Render(pins[i]);} + else {fAudioRendered=true;} + continue; + } + + if(CheckMediaType(pins[i],MEDIATYPE_Video)!=FALSE){ + if(fVideoRendered==true)goto next; + res=InsertVideoDecoder(pins[i],L"ffdshow Video Decoder",L"In"); + + if(res==FALSE){pGraph->Render(pins[i]);} + else {fAudioRendered=true;} + continue;} + next: + pGraph->Render(pins[i]); + +} + +for(i=0;iRelease(); +} + + + if(pEnum!=NULL){pEnum->Release();pEnum=NULL;} + if(pin!=NULL){pin->Release();pin=NULL;} + + return TRUE; + +end_fail: + +if(pSource!=NULL){pGraph->RemoveFilter(pSource);pSource->Release();pSource=NULL;} +if(pSplitter!=NULL){pGraph->RemoveFilter(pSplitter);pSplitter->Release();pSplitter=NULL;} +if(pEnum!=NULL){pEnum->Release();} + + return FALSE; +} + +void Close(){ + + Stop(); + + + if(IsPlayingCDA==true){ +DWORD dwRes; +MCI_GENERIC_PARMS p={0}; + +if(PlayerState==FILE_NOT_LOADED)return; +dwRes=mciSendCommand(DeviceID,MCI_CLOSE,0,(DWORD)&p); +PlayerState=FILE_NOT_LOADED; +IsPlayingVideo=false; +IsPlayingCDA=false; +DeviceID=0; +return; + } + + if(pSource!=NULL){pSource->Release();pSource=NULL;} + if(pSplitter!=NULL){pSplitter->Release();pSplitter=NULL;} + if(pAudioDecoder!=NULL){pAudioDecoder->Release();pAudioDecoder=NULL;} + if(pAudioRenderer!=NULL){pAudioRenderer->Release();pAudioRenderer=NULL;} + if(pVideoDecoder!=NULL){pVideoDecoder->Release();pVideoDecoder=NULL;} + if(pVideoRenderer!=NULL){pVideoRenderer->Release();pVideoRenderer=NULL;} + + if(pControl!=NULL){pControl->Release();pControl=NULL;} + if(pSeek!=NULL){pSeek->Release();pSeek=NULL;} + + + if(pEvent!=NULL){ + pEvent->SetNotifyWindow(NULL, 0, 0); + pEvent->Release(); + pEvent=NULL; + } + if(pAudio!=NULL){pAudio->Release();pAudio=NULL;} + if(pVideoWindow!=NULL){pVideoWindow->Release();pVideoWindow=NULL;} + if(pVideo!=NULL){pVideo->Release();pVideo=NULL;} + if(pGraph!=NULL){pGraph->Release();pGraph=NULL;} + + PlayerState=FILE_NOT_LOADED; + +} + + +void PlayFile(TCHAR* filename){ +HRESULT hr; +GUID tf=TIME_FORMAT_MEDIA_TIME; +TCHAR ext[8]=L""; +int i; + +bool res; +BOOL success=FALSE; + + +if(PlayerState!=FILE_NOT_LOADED){Close();} +fShowNextImage=false; + + +GetFileExtension(filename,ext); +if(lstrcmp(ext,L"cda")==0){ + PlayCDATrack(filename); +return;} + +// Create the filter graph manager and query for interfaces. +hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, + IID_IGraphBuilder, (void **)&pGraph); + +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} +hr = pGraph->QueryInterface(IID_IMediaControl, (void **)&pControl); +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} +hr = pGraph->QueryInterface(IID_IMediaEventEx, (void **)&pEvent); +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} +hr = pGraph->QueryInterface(IID_IMediaSeeking, (void **)&pSeek); +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} +hr = pGraph->QueryInterface(IID_IBasicAudio, (void **)&pAudio); +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} +hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVideoWindow); +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} +hr = pGraph->QueryInterface(IID_IBasicVideo, (void **)&pVideo); +if(FAILED(hr)){ShowError(hr,SYSTEM_ERROR);Close();return;} + +//handle URL +if(IsURL(filename)!=FALSE){ +hr = pGraph->RenderFile(filename, NULL); +if(FAILED(hr)){ShowError(hr,PLAY_ERROR);Close();return;} +goto play; +} + +//Try dynamic build filter graph +if(lstrcmp(ext,L"mp3")==0||lstrcmp(ext,L"MP3")==0||lstrcmp(ext,L"Mp3")==0){ + success=BuildGraph(MT_AUDIO,filename); + if(success!=FALSE)goto play; + +} +if(lstrcmp(ext,L"avi")==0||lstrcmp(ext,L"AVI")==0){ + success=BuildGraph(MT_AVI,filename); + if(success!=FALSE)goto play; + } +if(lstrcmp(ext,L"mpg")==0||lstrcmp(ext,L"MPG")==0||lstrcmp(ext,L"MPEG")==0||lstrcmp(ext,L"mpeg")==0){ + success=BuildGraph(MT_MPEG,filename); + if(success!=FALSE)goto play; + } +if(lstrcmp(ext,L"mkv")==0||lstrcmp(ext,L"MKV")==0){ + success=BuildGraph(MT_MKV,filename); + if(success!=FALSE)goto play; + } + +if(lstrcmp(ext,L"jpg")==0||lstrcmp(ext,L"JPG")==0|| + lstrcmp(ext,L"jpeg")==0||lstrcmp(ext,L"JPEG")==0|| + lstrcmp(ext,L"bmp")==0||lstrcmp(ext,L"BMP")==0|| + lstrcmp(ext,L"png")==0||lstrcmp(ext,L"PNG")==0|| + lstrcmp(ext,L"gif")==0||lstrcmp(ext,L"GIF")==0 + ){ + fShowNextImage=true; + SetTimer(hVideoWindow,TM_NEXT_IMAGE,Settings.ImageDelay,NULL); + + } + + +//try auto build +hr = pGraph->RenderFile(filename, NULL); +if(FAILED(hr)){ShowError(hr,PLAY_ERROR);Close();return;} +play: +SearchFilters(); +PlayerState=STOPPED; + +pSeek->SetTimeFormat(&tf); + +res=SetVideoWindow(hVideoWindow); +if(res==false){ + DisableFullScreen(); + IsPlayingVideo=false; + ShowWindow(hVideoWindow,SW_HIDE); + SetThreadExecutionState (ES_CONTINUOUS|ES_SYSTEM_REQUIRED); +} +else { + IsPlayingVideo=true; + ShowWindow(hVideoWindow,SW_SHOW); + SetThreadExecutionState (ES_CONTINUOUS|ES_DISPLAY_REQUIRED|ES_SYSTEM_REQUIRED); +} + +hr = pControl->Run(); +if(FAILED(hr)){ + ShowError(hr,PLAY_ERROR); + Close(); + return;} + +PlayerState=PLAYING; +pAudio->put_Volume(Volume); + +pEvent->SetNotifyWindow((LONG_PTR)hWnd,MM_MCINOTIFY,0L); + +} + +void PlayCDAFrom(DWORD pos){ //pos in TMSF + +DWORD dwReturn; + MCI_PLAY_PARMS mciPlayParms; + DWORD len,min,sec; + + if(PlayerState==FILE_NOT_LOADED){ + MessageBox(hWnd,L"Файл не загружен",NULL,MB_OK|MB_ICONERROR); + return ;} + + // Begin playback. The window procedure function for the parent + // window will be notified with an MM_MCINOTIFY message when + // playback is complete. At this time, the window procedure closes + // the device. +len=GetLength(); +sec=len/1000; +min=sec/60; +sec=sec-min*60; + + mciPlayParms.dwCallback = (DWORD) hWnd; +mciPlayParms.dwFrom = pos; + mciPlayParms.dwTo = MCI_MAKE_TMSF(TrackNumber, min, sec, 0); + if (dwReturn = mciSendCommand(DeviceID, MCI_PLAY, MCI_FROM|MCI_TO |MCI_NOTIFY, + (DWORD)(LPVOID) &mciPlayParms)) + { + Close(); + PlayerState=FILE_NOT_LOADED; + IsPlayingCDA=false; + return ;} + +PlayerState=PLAYING; +return; + +} + +void Play(){ +HRESULT hr; +DWORD dwReturn; + MCI_PLAY_PARMS mciPlayParms; +DWORD len,min,sec; + + if(PlayerState==FILE_NOT_LOADED){ + MessageBox(hWnd,L"Файл не загружен",NULL,MB_OK|MB_ICONERROR); + return ;} + if(IsPlayingCDA==true){ + PlayCDAFrom(MCI_MAKE_TMSF(TrackNumber,0,0,0)); + return; + } +hr = pControl->Run(); +if(FAILED(hr)){ + ShowError(hr,PLAY_ERROR); + Close(); + PlayerState=FILE_NOT_LOADED; + return;} + +PlayerState=PLAYING; + +pEvent->SetNotifyWindow((LONG_PTR)hWnd,MM_MCINOTIFY,0L); + +} + +void Pause(){ +HRESULT hRes; +DWORD dwRes; +MCI_GENERIC_PARMS p={0}; + +if(PlayerState!=PLAYING)return; + +if(IsPlayingCDA==true){ + pos=GetPosition(); +dwRes=mciSendCommand(DeviceID,MCI_PAUSE,0,(DWORD)&p); + +PlayerState=PAUSED; +return; +} +hRes=pControl->Pause(); +if(FAILED(hRes)){ + + return; +} +PlayerState=PAUSED; +} + +void Resume(){ +HRESULT hRes; +DWORD dwRes; +MCI_GENERIC_PARMS p={0}; + +if(PlayerState!=PAUSED)return; +if(IsPlayingCDA==true){ + + PlayerState=PLAYING; +SetPosition(pos); + +return; +} +hRes=pControl->Run(); +if(FAILED(hRes)){ + + return; +} +PlayerState=PLAYING; +} + +void Stop(){ +HRESULT hRes; +DWORD dwRes; +MCI_GENERIC_PARMS p={0}; +if(PlayerState!=PLAYING)return; +if(IsPlayingCDA==true){ +dwRes=mciSendCommand(DeviceID,MCI_STOP,0,(DWORD)&p); +PlayerState=STOPPED; +return; +} +Pause(); +hRes=pControl->Stop(); +if(FAILED(hRes)){ + Close(); + PlayerState=FILE_NOT_LOADED; + return; +} + +PlayerState=STOPPED; +SetThreadExecutionState (ES_CONTINUOUS); +} + +DWORD GetLength(){ + + HRESULT hRes; + LONGLONG dur={0}; + MCI_STATUS_PARMS params={0}; + DWORD dwRes; + DWORD len; + + if(PlayerState==FILE_NOT_LOADED)return 0; + if(fShowNextImage==true)return Settings.ImageDelay; + +if(IsPlayingCDA==true){ +params.dwItem=MCI_STATUS_LENGTH; +params.dwTrack=TrackNumber; + dwRes=mciSendCommand(DeviceID,MCI_STATUS,MCI_STATUS_ITEM|MCI_TRACK,(DWORD)¶ms); + if(dwRes!=0){ + return 0; +} + len=MCI_MSF_MINUTE((params.dwReturn))*60+MCI_MSF_SECOND((params.dwReturn)); +return len*(DWORD)1000; + +} + hRes=pSeek->GetDuration(&dur); + if(FAILED(hRes)){ + return 0; + } +return dur/TIME_KOEFF; +} + +DWORD GetPosition(){ + HRESULT hRes; + LONGLONG pos; + LONGLONG stoppos; + MCI_STATUS_PARMS params={0}; + DWORD dwRes; + DWORD pos_msec; + + if(PlayerState==FILE_NOT_LOADED||PlayerState==STOPPED)return 0; +if(IsPlayingCDA==true){ +params.dwItem=MCI_STATUS_POSITION; + dwRes=mciSendCommand(DeviceID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)¶ms); + if(dwRes!=0){ + return 0; +} + pos_msec=(MCI_TMSF_MINUTE(params.dwReturn)*60+MCI_TMSF_SECOND(params.dwReturn))*1000; + +return pos_msec; +} + hRes=pSeek->GetPositions(&pos,&stoppos); + if(FAILED(hRes)){ + + return 0; +} +return pos/TIME_KOEFF; +} + +void Rewind(){ + HRESULT hRes; +LONGLONG pos=0; +MCI_SEEK_PARMS params={0}; + DWORD dwRes; + if(PlayerState==FILE_NOT_LOADED)return ; +if(IsPlayingCDA==true){ + params.dwTo=MCI_MAKE_TMSF(TrackNumber,0,0,0); +dwRes=mciSendCommand(DeviceID,MCI_SEEK,MCI_TO,(DWORD)¶ms); + if(dwRes!=0){ return;} +PlayCDAFrom(MCI_MAKE_TMSF(TrackNumber,0,0,0));return; +} +hRes=pSeek->SetPositions(&pos,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning); + + if(FAILED(hRes)){ + + return; +} + +if(PlayerState==PLAYING)Play(); +if(PlayerState==PAUSED)PlayerState=STOPPED; +} + +void SetPosition(LONGLONG pos){ + HRESULT hRes; +DWORD dur; +MCI_SEEK_PARMS params={0}; +UINT min; +UINT sec; + DWORD dwRes; + if(PlayerState==FILE_NOT_LOADED)return ; + dur=GetLength(); + if(((DWORD)pos)>dur)return; + +if(IsPlayingCDA==true){ +sec=pos/1000; +min=sec/60; +sec=sec-60*min; + +params.dwTo=MCI_MAKE_TMSF(TrackNumber,min,sec,0); + dwRes=mciSendCommand(DeviceID,MCI_SEEK,MCI_TO,(DWORD)¶ms); + if(dwRes!=0){return;} + PlayCDAFrom(params.dwTo); + return; +} + + pos*=TIME_KOEFF; +hRes=pSeek->SetPositions(&pos,AM_SEEKING_AbsolutePositioning,NULL,AM_SEEKING_NoPositioning); + + if(FAILED(hRes)){ + ShowError(hRes,PLAY_ERROR); + return; +} + +if(PlayerState==PLAYING)Play(); +} + +int GetVolume() +{ + long x; + x=Volume; + if(x<-5000)x=-5000; + if(x>0)x=0; +return (((x+5000)*100)/5000.0f); +} + +void SetVolume(long vol) +{ + long x; + +x=((vol)/100.0f)*(5000)-5000; +if(x<-5000)x=-5000; +if(x>0)x=0; +Volume=x; + +if(PlayerState==FILE_NOT_LOADED)return; +if(pAudio==NULL)return; +if(IsPlayingCDA!=false){return;} +pAudio->put_Volume(x); + +} + +bool SetVideoWindow(HWND hParent){ + HRESULT hr; + RECT rc; +long DestWidth; +long DestHeight; +long SourceHeight; +long SourceWidth; +double factor; +long res; + + if(PlayerState==FILE_NOT_LOADED)return false; + + if(pVideoWindow==NULL)return false; + +hr=pVideoWindow->put_WindowStyle(WS_CHILD|WS_VISIBLE); +if(hr!=S_OK){return false;} +hr=pVideoWindow->put_Owner((LONG_PTR)hParent); +if(hr!=S_OK){return false;} +hr=pVideoWindow->put_MessageDrain((LONG_PTR)hVideoWindow); +if(hr!=S_OK){return false;} + +SetVideoRect(); +pVideoWindow->put_Visible(OATRUE); +pVideoWindow->NotifyOwnerMessage((LONG_PTR)hParent,WM_PAINT,0,0); + +return true; +} + +void SetVideoRect(){ +HRESULT hr; + RECT rc; +long DestWidth; +long DestHeight; +long SourceHeight; +long SourceWidth; +double factor; +long res; + +if(PlayerState==FILE_NOT_LOADED)return ; +if(pVideoWindow==NULL)return ; +if(pVideo==NULL)return ; +pVideoWindow->get_FullScreenMode(&res); +if(res==OATRUE)return; + +GetClientRect(hVideoWindow,&rc); + +hr=pVideoWindow->put_Height(rc.bottom); + +hr=pVideoWindow->put_Width(rc.right); + +hr=pVideoWindow->put_Left(0); + +hr=pVideoWindow->put_Top(0); + + +pVideo->get_VideoHeight(&SourceHeight); +pVideo->get_VideoWidth(&SourceWidth); + +DestWidth=rc.right; +factor=DestWidth/(double)SourceWidth; +DestHeight=factor*SourceHeight; +if(DestHeight>rc.bottom){ +DestHeight=rc.bottom; +factor=DestHeight/(double)SourceHeight; +DestWidth=factor*SourceWidth;} + +pVideo->SetDestinationPosition((rc.right-DestWidth)*0.5f,(rc.bottom-DestHeight)*0.5f,DestWidth,DestHeight); +} + +RECT VRect={0}; + +void EnableFullScreen(){ + + FullScreen=true; + GetWindowRect(hVideoWindow,&VRect); + +SetWindowLong(hVideoWindow,GWL_STYLE,WS_POPUP|WS_CLIPCHILDREN); + SetWindowPos(hVideoWindow,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED); + ShowWindow(hVideoWindow,SW_SHOWMAXIMIZED); + + SetVideoWindow(hVideoWindow); + SetTimer(hVideoWindow,TM_HIDE_CURSOR,1000,NULL); + +} +void DisableFullScreen(){ + +if(FullScreen==false)return; +FullScreen=false; + + +ShowWindow(hVideoWindow,SW_RESTORE); +SetWindowLong(hVideoWindow,GWL_STYLE,WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN); + + SetWindowPos(hVideoWindow,HWND_TOP,VRect.left,VRect.top,VRect.right-VRect.left,VRect.bottom-VRect.top, + SWP_FRAMECHANGED| SWP_NOZORDER ); + InvalidateRect(HWND_DESKTOP,NULL,TRUE); +UpdateWindow(HWND_DESKTOP); + +SetVideoWindow(hVideoWindow); + + ShowWindow(hVideoWindow,SW_RESTORE); + InvalidateRect(hVideoWindow,NULL,TRUE); + UpdateWindow(hVideoWindow); + if(IsCursorShown()==FALSE){ShowCursor(TRUE);} + +} diff --git a/SmallMediaPlayer/player.h b/SmallMediaPlayer/player.h new file mode 100644 index 0000000..2ddafcd --- /dev/null +++ b/SmallMediaPlayer/player.h @@ -0,0 +1,58 @@ +/* Small Media Player + * Copyright (c) 2021, MSDN.WhiteKnight (https://github.com/smallsoft-rus/media-player) + * License: BSD 2.0 */ +#ifndef PLAYER_H + +#define PLAYER_H + +#ifndef UNICODE +#define UNICODE +#endif + +#include "DirectShowStuff.h" +#include +#include "generic.h" + +#define TIME_KOEFF 10000 + +//extern vars +extern HWND hVideoWindow; + + + +//declaraations of vars +extern HWND hWnd; +extern PLAYER_STATE PlayerState; +extern IMediaEventEx *pEvent; +extern bool IsPlayingCDA; +extern long Volume; +extern bool IsPlayingVideo; +extern bool fShowNextImage; +extern bool FullScreen; +extern RECT VRect; +extern IBaseFilter* pSource; +extern IBaseFilter* pSplitter; +extern IBaseFilter* pAudioDecoder; +extern IBaseFilter* pAudioRenderer; +extern IBaseFilter* pVideoDecoder; +extern IBaseFilter* pVideoRenderer; + +void PlayFile(TCHAR* lpstrFileName); +void Play(); +void Pause(); +void Resume(); +void Stop(); +void Close(); +DWORD GetLength(); +DWORD GetPosition(); +void Rewind(); +void SetPosition(LONGLONG dwPos); +void SetVolume(long vol); +bool SetVideoWindow(HWND hParent); +void SetVideoRect(); +void DisableFullScreen(); +void EnableFullScreen(); +WORD GetMultimediaInfo(SMP_AUDIOINFO* pAudioInfo,SMP_VIDEOINFO* pVideoInfo,SMP_STREAM* pStreamType); +int GetVolume(); + +#endif diff --git a/SmallMediaPlayer/resource.h b/SmallMediaPlayer/resource.h new file mode 100644 index 0000000..020e8fb --- /dev/null +++ b/SmallMediaPlayer/resource.h @@ -0,0 +1,73 @@ +#ifndef IDC_STATIC +#define IDC_STATIC (-1) +#endif + +#define IDD_MAIN 101 +#define IDD_PLAYBACK 103 +#define IDD_INTEGR 105 +#define IDR_MENU1 106 +#define ID_ACCEL 107 +#define IDD_SETTINGS 111 +#define IDD_URL 113 +#define IDR_CONTEXT_MENU 115 +#define IDC_URL 1001 +#define ID_DELETE 1002 +#define ID_MINIMIZE 1003 +#define IDC_VOLUME 1005 +#define IDC_SCROLLBAR 1006 +#define ID_ADDFILE 1007 +#define IDC_EXT 1008 +#define IDC_ASSOCFILE 1010 +#define ID_PLAY 1012 +#define ID_PAUSE 1014 +#define ID_STOP 1016 +#define ID_CLEAR 1018 +#define ID_ADDFOLDER 1019 +#define IDC_INTEGR 1021 +#define ID_REWIND 1022 +#define ID_NEXTTRACK 1024 +#define ID_DELDIRA 1025 +#define ID_ABOUT 1026 +#define ID_PREVTRACK 1027 +#define ID_OPEN 40000 +#define ID_EXIT 40001 +#define ID_CUT 40002 +#define ID_MODE_NORMAL 40003 +#define ID_SHOWVIDEO 40004 +#define ID_FULLSCREEN 40005 +#define ID_MODE_REPEATLIST 40006 +#define ID_MODE_REPEATFILE 40007 +#define ID_HOMEPAGE 40008 +#define ID_VOLUMEDOWN 40009 +#define ID_SHOWCOVER 40011 +#define ID_PROP_AUDIO 40012 +#define ID_PROP_VIDEO 40013 +#define ID_PROP_SPLITTER 40014 +#define ID_LOADLIST 40015 +#define ID_SAVELIST 40016 +#define ID_SETTINGS 40017 +#define ID_PROP_AUDIOOUT 40018 +#define ID_PROP_VIDEOOUT 40019 +#define ID_ADDDIR_IMAGES 40020 +#define ID_ADDURL 40021 +#define ID_FILEINFO 40022 +#define IDC_POSITION 40023 +#define IDC_LENGTH 40025 +#define ID_DELFILEA 40026 +#define IDC_REMEMBER_PLAYLIST 40027 +#define ID_ASSOCF 40028 +#define IDC_REMEMBER_POSITION 40029 +#define IDC_SHOW_WALLPAPER 40030 +#define IDC_FILENAME 40031 +#define IDC_DELAY 40032 +#define IDC_CURRENTFILE 40033 +#define ID_MODE_RANDOM 40034 +#define ID_FEEDBACK 40035 +#define ID_PLAY_SELECTED 40036 +#define ID_SHOWPLAYLIST 40037 +#define ID_PASTE 40038 +#define ID_SELECTALL 40039 +#define ID_FILE_INFORMATION 40040 +#define ID_COPY 40041 +#define ID_PLAYPAUSE 40042 +#define ID_VOLUMEUP 40043 diff --git a/SmallMediaPlayer/smp.rc b/SmallMediaPlayer/smp.rc new file mode 100644 index 0000000..e82791d --- /dev/null +++ b/SmallMediaPlayer/smp.rc @@ -0,0 +1,244 @@ +// Generated by ResEdit 1.5.8 +// Copyright (C) 2006-2011 +// http://www.resedit.net + +#include +#include +#include +#include "resource.h" + + + + +// +// Menu resources +// +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDR_CONTEXT_MENU MENUEX +{ + POPUP "Main menu", 0, 0, 0 + { + MENUITEM " ", ID_MINIMIZE, 0, 0 + MENUITEM "", 0, MFT_SEPARATOR, 0 + MENUITEM "", ID_PLAY, 0, 0 + MENUITEM "", ID_PAUSE, 0, 0 + MENUITEM "", ID_STOP, 0, 0 + MENUITEM "", ID_REWIND, 0, 0 + MENUITEM "", ID_PREVTRACK, 0, 0 + MENUITEM "", ID_NEXTTRACK, 0, 0 + MENUITEM "", 0, MFT_SEPARATOR, 0 + MENUITEM " ..", ID_OPEN, 0, 0 + MENUITEM " ..", ID_ADDFILE, 0, 0 + MENUITEM " ..", ID_ADDFOLDER, 0, 0 + MENUITEM "", 0, MFT_SEPARATOR, 0 + MENUITEM " ", ID_ABOUT, 0, 0 + MENUITEM "", ID_EXIT, 0, 0 + } + POPUP "PLaylist menu", 0, 0, 0 + { + MENUITEM "", ID_PLAY_SELECTED, 0, MFS_DEFAULT + MENUITEM "", 0, MFT_SEPARATOR, 0 + MENUITEM "", ID_CUT, 0, 0 + MENUITEM "", ID_COPY, 0, 0 + MENUITEM "", ID_PASTE, 0, 0 + MENUITEM "", ID_DELETE, 0, 0 + MENUITEM " ", ID_SELECTALL, 0, 0 + MENUITEM "", 0, MFT_SEPARATOR, 0 + MENUITEM "", ID_FILE_INFORMATION, 0, 0 + } +} + + + +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDR_MENU1 MENU +{ + POPUP "" + { + MENUITEM "..\tCtrl+O", ID_OPEN + MENUITEM "..\tCtrl+F", ID_ADDFILE + MENUITEM " ..\tCtrl+D", ID_ADDFOLDER + MENUITEM " ( )", ID_ADDDIR_IMAGES + MENUITEM " URL...", ID_ADDURL + MENUITEM SEPARATOR + MENUITEM " ", ID_LOADLIST + MENUITEM " ", ID_SAVELIST + MENUITEM " ", ID_CLEAR + MENUITEM SEPARATOR + MENUITEM "", ID_SETTINGS + MENUITEM "", ID_EXIT + MENUITEM SEPARATOR + } + POPUP "" + { + MENUITEM " \tCtrl+L", ID_SHOWPLAYLIST, CHECKED + MENUITEM "\tCtrl+C", ID_SHOWCOVER, CHECKED + MENUITEM SEPARATOR + MENUITEM " \tCtrl+V", ID_SHOWVIDEO + MENUITEM " \tAlt+ENTER", ID_FULLSCREEN + MENUITEM SEPARATOR + MENUITEM " \tCtrl+M", ID_MINIMIZE + } + POPUP "" + { + MENUITEM " ", ID_MODE_NORMAL + MENUITEM " ", ID_MODE_REPEATLIST + MENUITEM " ", ID_MODE_REPEATFILE + MENUITEM " ", ID_MODE_RANDOM + MENUITEM SEPARATOR + MENUITEM "\tF2", ID_PLAY + MENUITEM "/\tF3", ID_PAUSE + MENUITEM "\tF4", ID_STOP + MENUITEM "\tF5", ID_REWIND + MENUITEM "\tCtrl+", ID_PREVTRACK + MENUITEM "\tCtrl+", ID_NEXTTRACK + MENUITEM " \tCtrl+", ID_VOLUMEUP + MENUITEM " \tCtrl+", ID_VOLUMEDOWN + } + POPUP "" + { + MENUITEM " ", ID_FILEINFO + MENUITEM SEPARATOR + MENUITEM " ", ID_PROP_SPLITTER + MENUITEM " -", ID_PROP_AUDIO + MENUITEM " -", ID_PROP_VIDEO + MENUITEM " -", ID_PROP_AUDIOOUT + MENUITEM " -", ID_PROP_VIDEOOUT + } + POPUP "" + { + MENUITEM " ..", IDC_INTEGR + MENUITEM SEPARATOR + MENUITEM " ", ID_HOMEPAGE + MENUITEM " ", ID_FEEDBACK + MENUITEM " ..\tF1", ID_ABOUT + } +} + + + +// +// Dialog resources +// +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDD_INTEGR DIALOG 0, 0, 215, 108 +STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU +CAPTION " " +FONT 8, "Ms Shell Dlg 2" +{ + DEFPUSHBUTTON "OK", IDOK, 26, 81, 50, 14 + PUSHBUTTON "", IDCANCEL, 92, 81, 50, 14 + LTEXT ":", IDC_STATIC, 9, 9, 52, 15, SS_LEFT + EDITTEXT IDC_EXT, 68, 7, 65, 16, ES_AUTOHSCROLL + PUSHBUTTON " ", IDC_ASSOCFILE, 30, 29, 89, 14 + PUSHBUTTON ". ", ID_ASSOCF, 29, 52, 88, 14 + DEFPUSHBUTTON ".", ID_DELFILEA, 143, 28, 25, 14 + PUSHBUTTON ".", ID_DELDIRA, 144, 52, 25, 14 +} + + + +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDD_MAIN DIALOG 0, 0, 406, 148 +STYLE DS_3DLOOK | DS_CENTER | DS_SHELLFONT | WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS +EXSTYLE WS_EX_CLIENTEDGE +FONT 8, "Ms Shell Dlg 2" +{ + DEFPUSHBUTTON " ..", ID_ADDFILE, 5, 5, 63, 15 + PUSHBUTTON " ..", ID_ADDFOLDER, 75, 5, 66, 15 + PUSHBUTTON "", ID_CLEAR, 165, 5, 50, 15 + PUSHBUTTON " ", ID_DELETE, 220, 5, 80, 15 +} + + + +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDD_PLAYBACK DIALOG 0, 0, 398, 69 +STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CHILDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS +EXSTYLE WS_EX_WINDOWEDGE +FONT 8, "Ms Shell Dlg 2" +{ + LTEXT "00:00:00", IDC_POSITION, 46, 19, 30, 8, SS_LEFT, WS_EX_RIGHT + LTEXT ":", IDC_STATIC, 10, 19, 32, 8, SS_LEFT + LTEXT ":", IDC_STATIC, 10, 28, 25, 8, SS_LEFT + LTEXT "00:00:00", IDC_LENGTH, 46, 28, 30, 8, SS_LEFT, WS_EX_RIGHT + LTEXT ":", IDC_STATIC, 8, 5, 28, 8, SS_LEFT + LTEXT "< >", IDC_CURRENTFILE, 33, 5, 340, 8, SS_LEFT + SCROLLBAR IDC_SCROLLBAR, 11, 46, 362, 20 + PUSHBUTTON "", ID_PLAY, 99, 18, 37, 20 + PUSHBUTTON "", ID_PAUSE, 147, 18, 32, 20 + PUSHBUTTON "", ID_STOP, 191, 18, 31, 20 + PUSHBUTTON "|<<", ID_REWIND, 260, 18, 28, 21 + PUSHBUTTON "<", ID_PREVTRACK, 295, 18, 26, 20 + PUSHBUTTON ">", ID_NEXTTRACK, 330, 18, 23, 20 + CONTROL "", IDC_VOLUME, TRACKBAR_CLASS, WS_TABSTOP | TBS_VERT | TBS_BOTH | TBS_NOTICKS, 377, 9, 28, 59 +} + + + +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDD_SETTINGS DIALOG 0, 0, 242, 148 +STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU +CAPTION "" +FONT 8, "Ms Shell Dlg 2" +{ + DEFPUSHBUTTON "OK", IDOK, 15, 130, 50, 14 + PUSHBUTTON "", IDCANCEL, 75, 130, 50, 14 + AUTOCHECKBOX " ", IDC_REMEMBER_PLAYLIST, 10, 10, 142, 10 + AUTOCHECKBOX " ", IDC_REMEMBER_POSITION, 10, 25, 152, 10 + AUTOCHECKBOX " ", IDC_SHOW_WALLPAPER, 10, 50, 170, 10 + LTEXT ":", IDC_STATIC, 10, 65, 21, 8, SS_LEFT + EDITTEXT IDC_FILENAME, 35, 65, 170, 15, ES_AUTOHSCROLL + PUSHBUTTON "", ID_OPEN, 210, 65, 26, 14 + LTEXT " , :", IDC_STATIC, 15, 90, 148, 8, SS_LEFT + EDITTEXT IDC_DELAY, 15, 103, 60, 14, ES_AUTOHSCROLL +} + + + +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +IDD_URL DIALOG 0, 0, 304, 55 +STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_SYSMENU +CAPTION " URL" +FONT 8, "Ms Shell Dlg 2" +{ + DEFPUSHBUTTON "OK", IDOK, 45, 30, 50, 14 + PUSHBUTTON "", IDCANCEL, 110, 30, 50, 14 + LTEXT "URL:", IDC_STATIC, 10, 5, 16, 8, SS_LEFT + EDITTEXT IDC_URL, 33, 3, 255, 15, ES_AUTOHSCROLL +} + + + +// +// Accelerator resources +// +LANGUAGE LANG_RUSSIAN, SUBLANG_RUSSIAN_RUSSIA +ID_ACCEL ACCELERATORS +{ + "O", ID_OPEN, VIRTKEY, CONTROL + VK_F2, ID_PLAY, VIRTKEY + VK_F3, ID_PAUSE, VIRTKEY + VK_F4, ID_STOP, VIRTKEY + VK_RETURN, ID_FULLSCREEN, VIRTKEY, ALT + "F", ID_ADDFILE, VIRTKEY, CONTROL + VK_RIGHT, ID_NEXTTRACK, VIRTKEY, CONTROL + VK_LEFT, ID_PREVTRACK, VIRTKEY, CONTROL + "D", ID_ADDFOLDER, VIRTKEY, CONTROL + "L", ID_SHOWPLAYLIST, VIRTKEY, CONTROL + "V", ID_SHOWVIDEO, VIRTKEY, CONTROL + VK_F1, ID_ABOUT, VIRTKEY + VK_F5, ID_REWIND, VIRTKEY + "C", ID_SHOWCOVER, VIRTKEY, CONTROL + "M", ID_MINIMIZE, VIRTKEY, CONTROL + VK_MEDIA_STOP, ID_STOP, VIRTKEY + VK_MEDIA_PLAY_PAUSE, ID_PLAYPAUSE, VIRTKEY + VK_MEDIA_NEXT_TRACK, ID_NEXTTRACK, VIRTKEY + VK_MEDIA_PREV_TRACK, ID_PREVTRACK, VIRTKEY + VK_UP, ID_VOLUMEUP, VIRTKEY, CONTROL + VK_DOWN, ID_VOLUMEDOWN, VIRTKEY, CONTROL + VK_VOLUME_DOWN, ID_VOLUMEDOWN, VIRTKEY + VK_VOLUME_UP, ID_VOLUMEUP, VIRTKEY + VK_BROWSER_FORWARD, ID_NEXTTRACK, VIRTKEY + VK_BROWSER_BACK, ID_PREVTRACK, VIRTKEY +} diff --git a/SmallMediaPlayer/smpconfig.bin b/SmallMediaPlayer/smpconfig.bin new file mode 100644 index 0000000000000000000000000000000000000000..646db3c5031ecce43196135732e7f25cb3ad81b1 GIT binary patch literal 552 bcmZQ%WMp7uKn3W0RM}D9ND6@tVTf-55t;y@ literal 0 HcmV?d00001 diff --git a/docs/ReadMe.htm b/docs/ReadMe.htm new file mode 100644 index 0000000..a1a181e --- /dev/null +++ b/docs/ReadMe.htm @@ -0,0 +1,40 @@ +

+Small Media Player

+Разработчик: SmallSoft
+Страница программы
+

+Описание программы:

+Легкий проигрыватель мультимедиа файлов для Windows без встроенных кодеков. Обладает простым интерфейсом, не требует установки.
+Основные возможности:
+
    +
  • редактирование списка воспроизведения
  • +
  • режимы воспроизведения: повтор списка, повтор одного файла, случайный порядок
  • +
  • загрузка и сохранение списков воспроизведения в формате M3U
  • +
  • поддержка информационных тэгов ID3V1, ID3V2, APE, FLAC
  • +
  • автоматическое отображение обложек альбомов из файлов JPEG, BMP, PNG
  • +
  • запоминание позиции последнего воспроизведенного файла при закрытии
  • +
  • возможность создания ассоциаций с файлами и папками в проводнике Windows
  • +
  • управление горячими клавишами
  • +
  • отображение информации о кодеках, используемых при воспроизведении файла
  • +
  • сворачивается в значок на системной панели
+Поддерживаемые ОС: Windows XP / Vista / 7 / 10.
+Для запуска требуется Visual C++ 2012 Redistributable (x86).
+
+ +

Рекомендации по использованию

+Для воспроизведения некоторых типов файлов могут потребоваться декодеры. Поддерживаются любые декодеры, основанные на технологии DirectShow. Для качественного воспроизведения аудиофайлов рекомендуется установить и включить декодер DC-Bass Source
+ +

Изменения в v2.0 (19.09.2017)

+
    +
  • Добавлена поддержка Windows 10
  • +
  • Изменен интерфейс, теперь список воспроизведения и обложка автоматически изменяют размер при изменении размеров главного окна
  • +
  • В главном окне добавлена краткая информация о форматах аудио и видео в воспроизводимом файле
  • +
  • Добавлено выделение стрелкой текущего файла в списке воспроизведения
  • +
  • Опция отображения фонового рисунка заменена на аналогичную опцию отображения рисунка при отсутствии обложки
  • +
  • Настройки программы и список воспроизведения теперь хранятся в папке "Мои документы"
  • +
  • Если включено запоминание позиции, запоминается также громкость.
  • +
  • m4a добавлен в список обрабатываемых расширений
  • +
  • Программа теперь собрана с помощью Visual C++ 2012
+
+Используйте файл shortcut.cmd для создания ярлыка на рабочем столе текущего пользователя
+
\ No newline at end of file diff --git a/scripts/shortcut.cmd b/scripts/shortcut.cmd new file mode 100644 index 0000000..5962f1d --- /dev/null +++ b/scripts/shortcut.cmd @@ -0,0 +1,11 @@ +@echo off +chcp 1251 +echo Set oWS = WScript.CreateObject("WScript.Shell") > CreateShortcut.vbs +echo sLinkFile = "%USERPROFILE%\Desktop\SmallMediaPlayer.LNK" >> CreateShortcut.vbs +echo Set oLink = oWS.CreateShortcut(sLinkFile) >> CreateShortcut.vbs +echo oLink.TargetPath = "%~dp0SmallMediaPlayer.exe" >> CreateShortcut.vbs +echo oLink.IconLocation = "%~dp0smp.ico" >> CreateShortcut.vbs +echo oLink.Save >> CreateShortcut.vbs +cscript CreateShortcut.vbs +del CreateShortcut.vbs + diff --git a/scripts/smp.ico b/scripts/smp.ico new file mode 100644 index 0000000000000000000000000000000000000000..ff7207b7afa945498221de429a74a151926c0974 GIT binary patch literal 9662 zcmd5>2Y8ibvQE@1DuNW<)nyeFB25vLBE?08gf4=(^r93&kRkygbdV+l2np$=hjh}D z({pN0PdQ0W!bv5CVnT@^Anm;~zZ`FLvFx+E_uh|Z_)huH|GzWy&U`Zy7Z+FhH*k>) z{olhS-p$43PcAMleMkn9(8t2(w7Kl0@BV|!mG1or$)hBXk^EO1;rIMGf6v$be_4!& zu{}ZZ^h;ejzOZCOzghb~92%_LJh{lUebRaJc8^Pz?Gu{x+dnLd{N%k8^M>@9HoA9@ zS4O#YfBM01Y5QMYY(KUoV}6F@d6HND+Ns0Xt&@jHN)AlDd-LRU+>Drp8`0BoD`p1m zBoWi`UD!vkADw>h@XV1GkN&-OOdRm))DPe6`|5*x(e@u-jQdHFt|UE3Mm_n&6N^R; zdfoTvf{FE){Ac2d?*yDb;(^A)?r1vffpgv-xNvL&nomqb>&XvrH~wSXNn3>YFDG0c z+pp)Tv9GypoG`#`^r&7hcBcEWKmQYpZT>h3KclCstLwx*eR}WO;Q6IAB`KlK7_k3d z<=$DS+A&86#|yr$}BP`P;w&Z|pt1?|@mAr}(bGVu8tQhI#)N zDBU;)MJooO=<~rSUNrpycjwHQ0cj~lw-P+YTvGtm3Vygx+ zkpwcC3~IF+noaXySvnY|MX$rM_ze^+BRy8Uh2oWiVOvdltR+3Z90vP_;i%X&Qt$`s za5M5FsP-*}DNlyHtn`)zvu7kd`iScX^t^5)Y_nhL&~BB-h)%1=jo{el{PtUm{mA|t zG;GM=y-{JI_0sGdL>9{s;ZPwbD+@A-6iTHMO3(Sw&Upj6nSEfG*B_>Zq{pYE$I^i) zT=6D~$tNYNhoF>wLb_BC$IgEJ9!mZCe_uLA4ZZDGd zB!azHx(|Pf;C;o%4;iH?p&Jn4|3ltS((K(;6cQmGV* z;A4<38V9+@U!j=N6RHp0p#7*f^2s0ix&2_8{~9cd2Ea<(Dr9age-mXC8|M#?pRae8PYK{(S*=fmV$o zotpS$g1F8t-VcRK--LSJ5ZI#v1pNHpkJww$!oFx~LPJ9%E;lvYnK;h<5aHvz%6ajZi*4U! z*pMNc4Tk*d*;(00O-+T6b7Er=5fOpFz(Dx=`U>Lo1IL3-r-Q@c0CPyCQo&?0!Dgj% zEj9#-O)DT>JO!fZ!y)=`FvK6d4fz6h=+-ZQVXr5Ow=aZp_7D_D1q%2X`_-#gaq;3s z!rg%Csw&va%1~2VOFqu5>CnFYRKoc%AMklMFz|$*w%ArkSfoN+W@Katdc?=a3$e?% zo$(M75+eA4zpJdQ6mYW+`uu#@Y&KNUv+JuWQESwqPOCtJjwC-1O(rc`>#A_`atriZ zKZD}qw@?(}j~h2`;L4RNIDh^;Y6-8Sq5>slrLdNl!`OHZC8Xip1@nUm=P!N0G2LuPFh9-PM-6chgH>Keh0 zH*ek)Z2PeP41`}YbpTA1e_L8w(Ae03DzZhHy&T15j$@u{cA z5nkrHb8$?+d|=z5)0YZbpqA!CA{RlXptDs?XDh`e=lCo-Z<$kUZ;lDhNi6IW<`Ktn z8Tp#dvwMvHQcLsqPPu;lyZaBruiv}`qDlRs@jXB`uR%qH110tf6gui)X}AhwE1;nt z%1N?G)OYUO@}KXXcfh^>YlPXEOWSqs(%C&DF}4<9zvGcDuvji|UNBqt_AmaavKxE9rlX4sVtFe{6pR#MGIx=0mbh{PhK zrKSmd@~8Yt`0r(9rj}bx`C_}RNNg{&DN2g0dBp|hyi(fBY=!ayi(X_lsO8^YIM>8F zT)A=?d28k(XMA5s4(x@a>@vj+P(|NXl9u*cK;b>WNY}Ctq$KjDS`-{weRr3~8($NC zq5gUFu}8Zs{$x>DN^%Z} z4l=VckPx46KRYwMyrj^aQ&~|aFDfuA^3{2Al|m|0%EdA@?FOwL7!C!hm`Vz`U=W* z_0Vg~kV(ZCEo67cnKGHxsFSJWVrjlgDzlQUEhJW>MyAP=%G64!%vQ)cSfx63o~q7v z?xuF#Qe?T)nY`a0Eu}!co$Ow68%9eD4Tbc8|Z|d;C}l$DxmpkHBZnFU}mp92X>rYKV{kL`Fm+Js}5{Y&)v*F5WdLb><3t zk+`JL${3~jN*U2CCowTD)+^#<$jXHHm^}uqB3VOz(5mE8dudT#p;ez-rngrYe!Use znIj?Fb_gbMC8Xr*lmrpwgLrxt=LmnobR0g%j^V`NZ;-!t8H%>d#-a7AL- zx{QvEiK>nWj}Yw6dhi*`G0EpHV|V77GbV}#j2un>UFkFgk<|_Y}x23 zr)RwQ0RM!Pl$1t3YiUO^^(ValTvCPHpO%&?)I4eFX-K1dnU;3Cp~z|$JIWcqia2Ca z&zm=I4c(V}POek9E_u9b*Js@V{d^Bt47xm%UL&opD3cO?mBe$=J;j3e;s4n@!NzSd zJ732i@WNTYg*bO`JS=M_B4PI?Y~Q+->p21cv(G;Jer`s_Ss9)EeAbFYB0;zwW8qpt zO5e$(a>%LQRmkaFqa3PJWI~yn)J(mStjbX)wHUNw%Aa{bCr#$4mWVve5`i1uu3&uPYzwdD$oIbD_=YkgDO6Y8qdAcKi z>vBZ;cw^I78<_t*PjKnbp~G96Y;i?_HlJ`QD9@{eI!xI4HTSnlIpuy4<^D8CWzkTG zj>44g3G=BHH}dmx)YX*^sja{)Hc@Ug=#*(IR<7LqbcYV_(Cr7fxw%a`did}GgHDyk zKC+h-$;v6-^F)dQndfrI=6m4yl9}*6dI-mSjtYJVIC2QtyI0|2;C!@3E`Y;p91JTz zK-!*7#NiNZ-Qtx(_vU`UrE}LV-Ls?Ot+l2?DCG*FpOsSmoUN1~Rh5MVbrPaA5eQcw zLzL1B@sh>J%9sLm!cdsQ2j7>boG7!|O2k!X$Ok4}4)H@$V9ZZDog5z)5)^P$nwu42 z)@xD;zqrtB6xCE#$jnBK=ycra2Gv*VAXzXGsb0Gf9TG>_eGssFGZb4E;$qN3d>ga? z6J^8c%Dy*m5tKa^pzm=LAThQBEb2MbfNwKNv% zDuS`v@eS5ge1(lAOR(EK9ezr8#AJCOIbk}|BbOs3+WR}XM69klV;4K@CE^0JKF4Cz zF_&b;RwH56O3en1sMuo6t#Opg%8IR`oQyQH-wD4vxt`0AxBTzO-mweTBr_Cy4nwnc zF3uiZg!-ckP_k({VIPP5bqjIo>n#-HK9pOcFn8|kErj1WKY9G~B}?{uUsBzjdMO$2 zTua1&AEMFswm)9KwI6R^`w9~-euhO=^Rdw~7v9n(2u|66$k_dqe*%$^5QDVSiRV=^ ziQHkgiEFDWq?8{;rM80Hl0r)^ow>Ob-{P98a%pjaQ6$aH)Mccnw#HIlA@W*o1QSIpSl&&$)ru zBQ)Qc;eI!>)dlfzK{QDii7z^0Klow4Q5~0nbjn*? zpGtCbFA`UDlpiJKB}L-Oic$#)>q59qVy#*(Rmj9vgTZi3M?C`foQj?6aVFpZ?8o=O zwto|B)YBC0S`Dk$GMLuQhjr^p=nfu&BF>1!kW2*nhtjzeP|&{plYI%dv;K7L_uPwa z6VHSex*&;gN0CI31mUl@eK4->2v+Nk;b6KS0%L;_LA69&TpaZS$>3U)dlsI-S*=!B zES8&UrJ_zD6BXo1b9D--NUKyx3?{wSR$X05l@0D*Y;HzjVIedc4K$qBBaXvy@+itr z>__R*9kA`&h@#zJqG<01WbN}pu-^%!MT%jJuS2ckI`-|@7e?6Io-gc!C+6&1d+1SQ z3iw?~hkmW$_`59xo5fUD#D^j*Dgx1TzQrfR3ugoO1B{*f1HE34;^JadQUS^RQ*(3k z-InHWZ?HV5{i%}taoxRpSLm5p2ZQ$x)Fzxn&8c8ih95^oz(GL|>;A8hc6bl`=a}UNndt2=J#09oJ_b%LnUAS;T=mnj4AGWu)whBG7g?Lk+8Hcl}F{p_PK~l)6z;(kvEGkx>+IwtY*j`Ht_Qr<@xVct~jV7B@ z&&B65_b7~=&o!PK^1Q)J^JngNxrgVTn{1Ek*RMYe_Rl_RqS-N($z8SqW9NIdwL4?ycy;ooq@;xU z)(X_s)d}3;8NzS%>}~b36XtKVQrJ%g!K$J87sWKsYysxdT#kq6m1nw~RZ{NQCtC-tuMw1S8^>sr0 zurJvz><2zm%rpy&2oF8grAuf28{t2*TxZUhK0&8aIFyPX=O>Jv*KW|Pvr)(a6{JH$Lmkck zGP0*kp45l%{4VF)VE*Mx*J)FyzAqN#8jFi?fJ~&`5AMcW0z+;e|Yhw zG%IOoZV_g-*U1KP^hX8{cXzjc5xY|t*8#7;?shsQG4xDD*|o|_nlnAHJ)c(`w~YVt z<;%Es?V2z@{=?Ym!nV4$G+$`gxqZv#Zr!?daz6auwJ%+~`016OFJDA|H!UE(-mfRl zvoLp<4?;*yIOnywS>-wa&({x-$Q6^qGeO^Q3^J>#S4lRuh1jr-*P%k}8+;lq1w+2ZBC zX7v}#jvn#;nrfAx)Rg2?X{o1^va>T{Qd5#n?A!bG_Kh39oWFIe*T`OOZogLt{9%1) zy4wzLalw5O-mkj2jOM+L{s7GTPCEE_r#rfyb#bA~TwG|s%R4dk)`OjXCY+FUywhKf zox76Xw{vlE?mPKCoutm4-~M#6(*1<>d;8BWddRW-d%yqX_iga(^bz#z p?&2csqaWzM