diff options
Diffstat (limited to 'Src/Plugins/Input/in_flv/FLVCOM.cpp')
-rw-r--r-- | Src/Plugins/Input/in_flv/FLVCOM.cpp | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_flv/FLVCOM.cpp b/Src/Plugins/Input/in_flv/FLVCOM.cpp new file mode 100644 index 00000000..5d6b4cc5 --- /dev/null +++ b/Src/Plugins/Input/in_flv/FLVCOM.cpp @@ -0,0 +1,189 @@ +#include "FLVCOM.h" +#include "AMFDispatch.h" +FLVCOM flvCOM; +extern bool mute; + +static HANDLE DuplicateCurrentThread() +{ + HANDLE fakeHandle = GetCurrentThread(); + HANDLE copiedHandle = 0; + HANDLE processHandle = GetCurrentProcess(); + DuplicateHandle(processHandle, fakeHandle, processHandle, &copiedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS); + return copiedHandle; +} + +enum +{ + DISP_FLV_REGISTER_CALLBACK, + DISP_FLV_UNREGISTER_CALLBACK, + DISP_FLV_SETMUTE, +}; + +#define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; } +HRESULT FLVCOM::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid) +{ + bool unknowns = false; + for (unsigned int i = 0;i != cNames;i++) + { + CHECK_ID("RegisterCallback", DISP_FLV_REGISTER_CALLBACK) + CHECK_ID("UnregisterCallback", DISP_FLV_UNREGISTER_CALLBACK) + CHECK_ID("SetMute", DISP_FLV_SETMUTE) + rgdispid[i] = DISPID_UNKNOWN; + unknowns = true; + } + if (unknowns) + return DISP_E_UNKNOWNNAME; + else + return S_OK; +} + +HRESULT FLVCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) +{ + return E_NOTIMPL; +} + +HRESULT FLVCOM::GetTypeInfoCount(unsigned int FAR * pctinfo) +{ + return E_NOTIMPL; +} + +HRESULT FLVCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr) +{ + if (pvarResult) + VariantInit(pvarResult); + + switch (dispid) + { + case DISP_FLV_SETMUTE: + { + if (pdispparams->rgvarg[0].boolVal) + mute = true; + else + mute = false; + } + return S_OK; + case DISP_FLV_REGISTER_CALLBACK: + { + IDispatch *callback = pdispparams->rgvarg[0].pdispVal; + + callbacks.push_back(DispatchCallbackInfo(callback, GetCurrentThreadId(), DuplicateCurrentThread())); + return S_OK; + } + break; + case DISP_FLV_UNREGISTER_CALLBACK: + { + IDispatch *callback = pdispparams->rgvarg[0].pdispVal; + size_t numCallbacks = callbacks.size(); + while (numCallbacks--) + { + if (callbacks[numCallbacks].dispatch == callback) + { + CloseHandle(callbacks[numCallbacks].threadHandle); + callbacks.erase(callbacks.begin() + numCallbacks); + } + } + return S_OK; + } + break; + } + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP FLVCOM::QueryInterface(REFIID riid, PVOID *ppvObject) +{ + if (!ppvObject) + return E_POINTER; + + else if (IsEqualIID(riid, IID_IDispatch)) + *ppvObject = (IDispatch *)this; + else if (IsEqualIID(riid, IID_IUnknown)) + *ppvObject = this; + else + { + *ppvObject = NULL; + return E_NOINTERFACE; + } + + AddRef(); + return S_OK; +} + +ULONG FLVCOM::AddRef(void) +{ + return 0; +} + +ULONG FLVCOM::Release(void) +{ + return 0; +} + +static void CallDispatchMethod(IDispatch *dispatch, DISPPARAMS ¶ms, OLECHAR *name) +{ + try + { + unsigned int ret; + DISPID dispid; + if (SUCCEEDED(dispatch->GetIDsOfNames(IID_NULL, &name, 1, LOCALE_SYSTEM_DEFAULT, &dispid))) + dispatch->Invoke(dispid, GUID_NULL, 0, DISPATCH_METHOD, ¶ms, 0, 0, &ret); + } + catch (...) + {} +} + +struct APCdata +{ + IDispatch *disp; + wchar_t *name; + AMFDispatch *amf; +}; + +static VOID CALLBACK MetadataAPC(ULONG_PTR param) +{ + APCdata *data = (APCdata *)param; + + DISPPARAMS params; + VARIANT argument; + params.cArgs = 1; + params.cNamedArgs = 0; + params.rgdispidNamedArgs = 0; + params.rgvarg = &argument; + VariantInit(&argument); + V_VT(&argument) = VT_DISPATCH; + V_DISPATCH(&argument) = data->amf; + + CallDispatchMethod(data->disp, params, data->name); + + data->disp->Release(); + data->amf->Release(); + free(data->name); + delete data; +} + +void FLVCOM::MetadataCallback(FLVMetadata::Tag *tag) +{ + if (!callbacks.empty()) + { + AMFDispatch *disp = new AMFDispatch(tag->parameters); // we're newing this we can refcount + + DWORD curThreadId = GetCurrentThreadId(); + for (size_t i = 0;i != callbacks.size();i++) + { + APCdata *data = new APCdata; + data->disp = callbacks[i].dispatch; + data->disp->AddRef(); + data->name = _wcsdup(tag->name.str); + data->amf = disp; + data->amf->AddRef(); + + if (curThreadId == callbacks[i].threadId) + MetadataAPC((ULONG_PTR)data); + else + { + if (callbacks[i].threadHandle) + QueueUserAPC(MetadataAPC, callbacks[i].threadHandle, (ULONG_PTR)data); + } + } + disp->Release(); + } +}
\ No newline at end of file |