-
Notifications
You must be signed in to change notification settings - Fork 199
Add feature to detect device's remove/insert events. #30
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -30,13 +30,24 @@ namespace DShow { | |||||||||||
|
|
||||||||||||
| bool SetRocketEnabled(IBaseFilter *encoder, bool enable); | ||||||||||||
|
|
||||||||||||
| HDevice::HDevice() : initialized(false), active(false) {} | ||||||||||||
| HDevice::HDevice(IDeviceCallback *cb) | ||||||||||||
| : initialized(false), | ||||||||||||
| active(false), | ||||||||||||
| callback(cb), | ||||||||||||
| msgEvt(0), | ||||||||||||
| msgThread(0) | ||||||||||||
| { | ||||||||||||
| exitEvt = ::CreateEvent(NULL, TRUE, FALSE, NULL); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| HDevice::~HDevice() | ||||||||||||
| { | ||||||||||||
| if (active) | ||||||||||||
| Stop(); | ||||||||||||
|
|
||||||||||||
| StopEventThread(); | ||||||||||||
| CloseHandle(exitEvt); | ||||||||||||
|
|
||||||||||||
| DisconnectFilters(); | ||||||||||||
|
|
||||||||||||
| /* | ||||||||||||
|
|
@@ -53,6 +64,90 @@ HDevice::~HDevice() | |||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| unsigned __stdcall HDevice::EventThread(void *pParam) | ||||||||||||
| { | ||||||||||||
| HDevice *self = reinterpret_cast<HDevice *>(pParam); | ||||||||||||
| CoInitialize(nullptr); | ||||||||||||
| self->EventThreadInner(); | ||||||||||||
| CoUninitialize(); | ||||||||||||
| return 0; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| void HDevice::EventThreadInner() | ||||||||||||
| { | ||||||||||||
| HANDLE events[] = { | ||||||||||||
| exitEvt, // must be first one | ||||||||||||
| msgEvt, | ||||||||||||
| }; | ||||||||||||
|
|
||||||||||||
| DWORD count = sizeof(events) / sizeof(HANDLE); | ||||||||||||
|
Comment on lines
+78
to
+83
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The array is static and the count never changes, so an |
||||||||||||
|
|
||||||||||||
| while (true) { | ||||||||||||
| DWORD res = | ||||||||||||
| WaitForMultipleObjects(count, events, FALSE, INFINITE); | ||||||||||||
| if (res == WAIT_OBJECT_0) | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per Microsoft's documentation states this should use the logic |
||||||||||||
| break; // exitEvt is set for exiting thread | ||||||||||||
|
|
||||||||||||
| if (!ReadAllEvents()) | ||||||||||||
| break; | ||||||||||||
|
Comment on lines
+91
to
+92
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Needs to use curly braces for all blocks per current code style guidelines. Applies throughout. |
||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| #define FLAG_REMOVE_DEVICE 0 | ||||||||||||
| #define FLAG_INSERT_DEVICE 1 | ||||||||||||
|
Comment on lines
+96
to
+97
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace with |
||||||||||||
|
|
||||||||||||
| bool HDevice::ReadAllEvents() | ||||||||||||
| { | ||||||||||||
| long eventCode = 0; | ||||||||||||
| LONG_PTR param1 = 0; | ||||||||||||
| LONG_PTR param2 = 0; | ||||||||||||
|
|
||||||||||||
| while (SUCCEEDED(eventEx->GetEvent(&eventCode, ¶m1, ¶m2, 0))) { | ||||||||||||
| if (EC_DEVICE_LOST == eventCode) { | ||||||||||||
| if (FLAG_REMOVE_DEVICE == param2) { | ||||||||||||
| Warning(L"Device is removed."); | ||||||||||||
| callback->OnDeviceRemoved(); | ||||||||||||
| } else if (FLAG_INSERT_DEVICE == param2) { | ||||||||||||
| Info(L"Device is inserted again."); | ||||||||||||
| callback->OnDeviceInserted(); | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| eventEx->FreeEventParams(eventCode, param1, param2); | ||||||||||||
|
|
||||||||||||
| if (WAIT_OBJECT_0 == WaitForSingleObject(exitEvt, 0)) | ||||||||||||
| return false; | ||||||||||||
|
Comment on lines
+118
to
+119
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The idea here is to check whether the exit event was signalled after the current media event and thus make the media event thread exit? |
||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| return true; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| void HDevice::StartEventThread() | ||||||||||||
| { | ||||||||||||
| if (msgThread && (msgThread != INVALID_HANDLE_VALUE)) { | ||||||||||||
| Warning(L"Message thread is running!"); | ||||||||||||
| return; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if (!callback) { | ||||||||||||
| Info(L"Won't create message thread because no callback."); | ||||||||||||
| return; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| ::ResetEvent(exitEvt); | ||||||||||||
| msgThread = (HANDLE)_beginthreadex(0, 0, EventThread, this, 0, 0); | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| void HDevice::StopEventThread() | ||||||||||||
| { | ||||||||||||
| ::SetEvent(exitEvt); | ||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is it necessary to use the global scope identifier explicitly here and for other functions like |
||||||||||||
| if (msgThread && (msgThread != INVALID_HANDLE_VALUE)) { | ||||||||||||
| WaitForSingleObject(msgThread, INFINITE); | ||||||||||||
| CloseHandle(msgThread); | ||||||||||||
| msgThread = 0; | ||||||||||||
| } | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| bool HDevice::EnsureInitialized(const wchar_t *func) | ||||||||||||
| { | ||||||||||||
| if (!initialized) { | ||||||||||||
|
|
@@ -601,9 +696,19 @@ bool HDevice::CreateGraph() | |||||||||||
| return false; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| if (!CreateFilterGraph(&graph, &builder, &control)) | ||||||||||||
| StopEventThread(); | ||||||||||||
|
|
||||||||||||
| if (!CreateFilterGraph(&graph, &builder, &control, &eventEx)) | ||||||||||||
| return false; | ||||||||||||
|
|
||||||||||||
| HRESULT hr = eventEx->GetEventHandle((OAEVENT *)&msgEvt); | ||||||||||||
| if (FAILED(hr)) { | ||||||||||||
| ErrorHR(L"Failed to get event handle", hr); | ||||||||||||
| return false; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| StartEventThread(); | ||||||||||||
|
|
||||||||||||
| initialized = true; | ||||||||||||
| return true; | ||||||||||||
| } | ||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -21,7 +21,8 @@ | |||||
|
|
||||||
| #include "../dshowcapture.hpp" | ||||||
| #include "capture-filter.hpp" | ||||||
|
|
||||||
| #include <Windows.h> | ||||||
| #include <process.h> | ||||||
| #include <string> | ||||||
| #include <vector> | ||||||
| using namespace std; | ||||||
|
|
@@ -50,6 +51,7 @@ struct HDevice { | |||||
| ComPtr<IGraphBuilder> graph; | ||||||
| ComPtr<ICaptureGraphBuilder2> builder; | ||||||
| ComPtr<IMediaControl> control; | ||||||
| ComPtr<IMediaEventEx> eventEx; | ||||||
|
|
||||||
| ComPtr<IBaseFilter> videoFilter; | ||||||
| ComPtr<IBaseFilter> audioFilter; | ||||||
|
|
@@ -70,9 +72,22 @@ struct HDevice { | |||||
| EncodedData encodedVideo; | ||||||
| EncodedData encodedAudio; | ||||||
|
|
||||||
| HDevice(); | ||||||
| // handle insert/remove events | ||||||
| HANDLE msgEvt; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| HANDLE exitEvt; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| HANDLE msgThread; | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| IDeviceCallback *callback; | ||||||
|
|
||||||
| HDevice(IDeviceCallback *cb); | ||||||
| ~HDevice(); | ||||||
|
|
||||||
| // handle insert/remove events | ||||||
| static unsigned __stdcall EventThread(void *pParam); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why use a static class function rather than a free-standing function in an anonymous namespace for this? Also why use |
||||||
| void EventThreadInner(); | ||||||
| bool ReadAllEvents(); | ||||||
| void StartEventThread(); | ||||||
| void StopEventThread(); | ||||||
|
|
||||||
| void ConvertVideoSettings(); | ||||||
| void ConvertAudioSettings(); | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -39,11 +39,12 @@ using namespace std; | |||||
| namespace DShow { | ||||||
|
|
||||||
| bool CreateFilterGraph(IGraphBuilder **pgraph, ICaptureGraphBuilder2 **pbuilder, | ||||||
| IMediaControl **pcontrol) | ||||||
| IMediaControl **pcontrol, IMediaEventEx **pevent) | ||||||
| { | ||||||
| ComPtr<IGraphBuilder> graph; | ||||||
| ComPtr<ICaptureGraphBuilder2> builder; | ||||||
| ComPtr<IMediaControl> control; | ||||||
| ComPtr<IMediaEventEx> event; | ||||||
| HRESULT hr; | ||||||
|
|
||||||
| hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, | ||||||
|
|
@@ -73,6 +74,16 @@ bool CreateFilterGraph(IGraphBuilder **pgraph, ICaptureGraphBuilder2 **pbuilder, | |||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| if (pevent) { | ||||||
| hr = graph->QueryInterface(IID_IMediaEventEx, (void **)&event); | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Use |
||||||
| if (FAILED(hr)) { | ||||||
| ErrorHR(L"Failed to get media event interface", hr); | ||||||
| return false; | ||||||
| } | ||||||
|
|
||||||
| *pevent = event.Detach(); | ||||||
| } | ||||||
|
|
||||||
| *pgraph = graph.Detach(); | ||||||
| *pbuilder = builder.Detach(); | ||||||
| *pcontrol = control.Detach(); | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
| #include "log.hpp" | ||
|
|
||
| #include <strsafe.h> | ||
| #include <stdint.h> | ||
|
|
||
| namespace DShow { | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to use
reinterpret_casthere? Wouldstatic_castsuffice?