-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
016f155
commit 7efc118
Showing
26 changed files
with
6,396 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Oops, something went wrong.