Skip to content
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

Add feature to detect device's remove/insert events. #30

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion dshowcapture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,11 +204,20 @@ struct AudioConfig : Config {
AudioMode mode = AudioMode::Capture;
};

class IDeviceCallback {
public:
virtual ~IDeviceCallback() {}

virtual void OnDeviceRemoved() = 0;
virtual void OnDeviceInserted() = 0;
};

class DSHOWCAPTURE_EXPORT Device {
HDevice *context;
IDeviceCallback *callback;

public:
Device(InitGraph initialize = InitGraph::False);
Device(InitGraph initialize = InitGraph::False, IDeviceCallback *cb = NULL);
~Device();

bool Valid() const;
Expand Down
109 changes: 107 additions & 2 deletions source/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();

/*
Expand All @@ -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);

while (true) {
DWORD res =
WaitForMultipleObjects(count, events, FALSE, INFINITE);
if (res == WAIT_OBJECT_0)
break; // exitEvt is set for exiting thread

if (!ReadAllEvents())
break;
}
}

#define FLAG_REMOVE_DEVICE 0
#define FLAG_INSERT_DEVICE 1

bool HDevice::ReadAllEvents()
{
long eventCode = 0;
LONG_PTR param1 = 0;
LONG_PTR param2 = 0;

while (SUCCEEDED(eventEx->GetEvent(&eventCode, &param1, &param2, 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;
}

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);
if (msgThread && (msgThread != INVALID_HANDLE_VALUE)) {
WaitForSingleObject(msgThread, INFINITE);
CloseHandle(msgThread);
msgThread = 0;
}
}

bool HDevice::EnsureInitialized(const wchar_t *func)
{
if (!initialized) {
Expand Down Expand Up @@ -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;
}
Expand Down
19 changes: 17 additions & 2 deletions source/device.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@

#include "../dshowcapture.hpp"
#include "capture-filter.hpp"

#include <Windows.h>
#include <process.h>
#include <string>
#include <vector>
using namespace std;
Expand Down Expand Up @@ -50,6 +51,7 @@ struct HDevice {
ComPtr<IGraphBuilder> graph;
ComPtr<ICaptureGraphBuilder2> builder;
ComPtr<IMediaControl> control;
ComPtr<IMediaEventEx> eventEx;

ComPtr<IBaseFilter> videoFilter;
ComPtr<IBaseFilter> audioFilter;
Expand All @@ -70,9 +72,22 @@ struct HDevice {
EncodedData encodedVideo;
EncodedData encodedAudio;

HDevice();
// handle insert/remove events
HANDLE msgEvt;
HANDLE exitEvt;
HANDLE msgThread;
IDeviceCallback *callback;

HDevice(IDeviceCallback *cb);
~HDevice();

// handle insert/remove events
static unsigned __stdcall EventThread(void *pParam);
void EventThreadInner();
bool ReadAllEvents();
void StartEventThread();
void StopEventThread();

void ConvertVideoSettings();
void ConvertAudioSettings();

Expand Down
13 changes: 12 additions & 1 deletion source/dshow-base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -73,6 +74,16 @@ bool CreateFilterGraph(IGraphBuilder **pgraph, ICaptureGraphBuilder2 **pbuilder,
return false;
}

if (pevent) {
hr = graph->QueryInterface(IID_IMediaEventEx, (void **)&event);
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();
Expand Down
2 changes: 1 addition & 1 deletion source/dshow-base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ using namespace std;
namespace DShow {

bool CreateFilterGraph(IGraphBuilder **graph, ICaptureGraphBuilder2 **builder,
IMediaControl **control);
IMediaControl **control, IMediaEventEx **pevent);

void LogFilters(IGraphBuilder *graph);

Expand Down
7 changes: 4 additions & 3 deletions source/dshowcapture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@

namespace DShow {

Device::Device(InitGraph initialize) : context(new HDevice)
Device::Device(InitGraph initialize, IDeviceCallback *cb)
: context(new HDevice(cb)), callback(cb)
{
if (initialize == InitGraph::True)
context->CreateGraph();
Expand All @@ -48,15 +49,15 @@ bool Device::ResetGraph()
{
/* cheap and easy way to clear all the filters */
delete context;
context = new HDevice;
context = new HDevice(callback);

return context->CreateGraph();
}

void Device::ShutdownGraph()
{
delete context;
context = new HDevice;
context = new HDevice(callback);
}

bool Device::SetVideoConfig(VideoConfig *config)
Expand Down
2 changes: 1 addition & 1 deletion source/encoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace DShow {

HVideoEncoder::HVideoEncoder()
{
initialized = CreateFilterGraph(&graph, &builder, &control);
initialized = CreateFilterGraph(&graph, &builder, &control, NULL);
}

HVideoEncoder::~HVideoEncoder()
Expand Down
1 change: 1 addition & 0 deletions source/output-filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "log.hpp"

#include <strsafe.h>
#include <stdint.h>

namespace DShow {

Expand Down