diff options
author | Sébastien Moutte <sebastien@moutte.net> | 2007-05-23 22:44:12 +0000 |
---|---|---|
committer | Sébastien Moutte <sebastien@moutte.net> | 2007-05-23 22:44:12 +0000 |
commit | 0a0c13670a4e4e08d1f21ebf5ca03e810491e991 (patch) | |
tree | 61c1b4433965e68da0bf7c8a97ef8ab21187d978 | |
parent | 7935a424b1932e83c18cd1a34a82f3ca4121bca6 (diff) | |
download | gst-plugins-bad-0a0c13670a4e4e08d1f21ebf5ca03e810491e991.tar.gz gst-plugins-bad-0a0c13670a4e4e08d1f21ebf5ca03e810491e991.tar.bz2 gst-plugins-bad-0a0c13670a4e4e08d1f21ebf5ca03e810491e991.zip |
docs/plugins/gst-plugins-bad-plugins.args: Remove directsoundsink property doc as this sink use the mixer interface now.
Original commit message from CVS:
* docs/plugins/gst-plugins-bad-plugins.args:
Remove directsoundsink property doc as this sink use the mixer
interface now.
* docs/plugins/gst-plugins-bad-plugins.interfaces:
Add interfaces implemented by Windows sinks.
* sys/directsound/gstdirectsoundsink.c:
* sys/directsound/gstdirectsoundsink.h:
Remove directsoundsink property and implement the mixer interface.
* win32/vs6/gst_plugins_bad.dsw:
* win32/vs6/libgstdirectsound.dsp:
Update project files.
* gst-libs/gst/dshow/gstdshow.cpp:
* gst-libs/gst/dshow/gstdshow.h:
* gst-libs/gst/dshow/gstdshowfakesink.cpp:
* gst-libs/gst/dshow/gstdshowfakesink.h:
* gst-libs/gst/dshow/gstdshowfakesrc.cpp:
* gst-libs/gst/dshow/gstdshowfakesrc.h:
* gst-libs/gst/dshow/gstdshowinterface.cpp:
* gst-libs/gst/dshow/gstdshowinterface.h:
* win32/common/libgstdshow.def:
* win32/vs6/libgstdshow.dsp:
Add a new gst library which allow to create internal Direct Show
graph (pipelines) to wrap Windows sources, decoders or encoders.
It includes a DirectShow fake source and sink and utility functions.
* sys/dshowsrcwrapper/gstdshowaudiosrc.c:
* sys/dshowsrcwrapper/gstdshowaudiosrc.h:
* sys/dshowsrcwrapper/gstdshowsrcwrapper.c:
* sys/dshowsrcwrapper/gstdshowsrcwrapper.h:
* sys/dshowsrcwrapper/gstdshowvideosrc.c:
* sys/dshowsrcwrapper/gstdshowvideosrc.h:
* win32/vs6/libdshowsrcwrapper.dsp:
Add a new plugin to wrap DirectShow sources on Windows.
It gets data from any webcam, dv cam, micro. We could add
tv tunner card later.
24 files changed, 3729 insertions, 90 deletions
@@ -1,3 +1,40 @@ +2007-05-24 Sebastian Moutte <sebastien@moutte.net> + + * docs/plugins/gst-plugins-bad-plugins.args: + Remove directsoundsink property doc as this sink use the mixer + interface now. + * docs/plugins/gst-plugins-bad-plugins.interfaces: + Add interfaces implemented by Windows sinks. + * sys/directsound/gstdirectsoundsink.c: + * sys/directsound/gstdirectsoundsink.h: + Remove directsoundsink property and implement the mixer interface. + * win32/vs6/gst_plugins_bad.dsw: + * win32/vs6/libgstdirectsound.dsp: + Update project files. + * gst-libs/gst/dshow/gstdshow.cpp: + * gst-libs/gst/dshow/gstdshow.h: + * gst-libs/gst/dshow/gstdshowfakesink.cpp: + * gst-libs/gst/dshow/gstdshowfakesink.h: + * gst-libs/gst/dshow/gstdshowfakesrc.cpp: + * gst-libs/gst/dshow/gstdshowfakesrc.h: + * gst-libs/gst/dshow/gstdshowinterface.cpp: + * gst-libs/gst/dshow/gstdshowinterface.h: + * win32/common/libgstdshow.def: + * win32/vs6/libgstdshow.dsp: + Add a new gst library which allow to create internal Direct Show + graph (pipelines) to wrap Windows sources, decoders or encoders. + It includes a DirectShow fake source and sink and utility functions. + * sys/dshowsrcwrapper/gstdshowaudiosrc.c: + * sys/dshowsrcwrapper/gstdshowaudiosrc.h: + * sys/dshowsrcwrapper/gstdshowsrcwrapper.c: + * sys/dshowsrcwrapper/gstdshowsrcwrapper.h: + * sys/dshowsrcwrapper/gstdshowvideosrc.c: + * sys/dshowsrcwrapper/gstdshowvideosrc.h: + * win32/vs6/libdshowsrcwrapper.dsp: + Add a new plugin to wrap DirectShow sources on Windows. + It gets data from any webcam, dv cam, micro. We could add + tv tunner card later. + 2007-05-23 Sebastian Dröge <slomo@circular-chaos.org> Patch by René Stadler <mail at renestadler dot de>: diff --git a/docs/plugins/gst-plugins-bad-plugins.args b/docs/plugins/gst-plugins-bad-plugins.args index 3a1f1605..3315db1d 100644 --- a/docs/plugins/gst-plugins-bad-plugins.args +++ b/docs/plugins/gst-plugins-bad-plugins.args @@ -17096,16 +17096,6 @@ </ARG> <ARG> -<NAME>GstDirectSoundSink::attenuation</NAME> -<TYPE>glong</TYPE> -<RANGE>[-1000,0]</RANGE> -<FLAGS>rw</FLAGS> -<NICK>Attenuation of the sound</NICK> -<BLURB>The attenuation for the directsound buffer (default is 0 so the directsound buffer will not be attenuated).</BLURB> -<DEFAULT>0</DEFAULT> -</ARG> - -<ARG> <NAME>GstOSXVideoSink::embed</NAME> <TYPE>gboolean</TYPE> <RANGE></RANGE> diff --git a/docs/plugins/gst-plugins-bad-plugins.interfaces b/docs/plugins/gst-plugins-bad-plugins.interfaces index 2f8eee20..78d069f2 100644 --- a/docs/plugins/gst-plugins-bad-plugins.interfaces +++ b/docs/plugins/gst-plugins-bad-plugins.interfaces @@ -4,3 +4,5 @@ GstSDLVideoSink GstImplementsInterface GstXOverlay GstNavigation GstDfbVideoSink GstImplementsInterface GstNavigation GstNeonhttpSrc GstURIHandler GstMMS GstURIHandler +GstDirectDrawSink GstImplementsInterface GstXOverlay +GstDirectSoundSink GstImplementsInterface GstMixer diff --git a/gst-libs/gst/dshow/gstdshow.cpp b/gst-libs/gst/dshow/gstdshow.cpp new file mode 100644 index 00000000..4d419d16 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshow.cpp @@ -0,0 +1,355 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshow.cpp: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshow.h" +#include "gstdshowfakesink.h" +#include "gstdshowfakesrc.h" + +CFactoryTemplate g_Templates[]= +{ + { + L"DSHOW fake sink filter" + , &CLSID_DshowFakeSink + , CDshowFakeSink::CreateInstance + , NULL + , NULL + }, + { + L"DSHOW fake src filter" + , &CLSID_DshowFakeSrc + , CDshowFakeSrc::CreateInstance + , NULL + , NULL + }, + +}; + +int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]); +static HINSTANCE g_hModule = NULL; + +extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID); +BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) +{ + if (!g_hModule) + g_hModule = (HINSTANCE)hModule; + + return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved); +} + +STDAPI DllRegisterServer() +{ + return AMovieDllRegisterServer2 (TRUE); +} + +STDAPI DllUnregisterServer() +{ + return AMovieDllRegisterServer2 (FALSE); +} + +BOOL gst_dshow_register_fakefilters () +{ + return (DllRegisterServer() == S_OK) ? TRUE : FALSE; +} + +void +gst_dshow_free_mediatype (AM_MEDIA_TYPE *pmt) +{ + if (pmt != NULL) { + if (pmt->cbFormat != 0) { + CoTaskMemFree((PVOID)pmt->pbFormat); + pmt->cbFormat = 0; + pmt->pbFormat = NULL; + } + if (pmt->pUnk != NULL) { + /* Unecessary because pUnk should not be used, but safest. */ + pmt->pUnk->Release(); + pmt->pUnk = NULL; + } + + CoTaskMemFree(pmt); + } +} + +void +gst_dshow_free_pin_mediatype (gpointer pt) +{ + GstCapturePinMediaType * pin_mediatype = (GstCapturePinMediaType *) pt; + if (pin_mediatype) { + if (pin_mediatype->capture_pin) { + pin_mediatype->capture_pin->Release(); + pin_mediatype->capture_pin = NULL; + } + if (pin_mediatype->mediatype) { + gst_dshow_free_mediatype (pin_mediatype->mediatype); + pin_mediatype->mediatype = NULL; + } + } +} + + +void +gst_dshow_free_pins_mediatypes (GList *pins_mediatypes) +{ + guint i = 0; + for (; i < g_list_length (pins_mediatypes); i++) { + GList *mylist = g_list_nth (pins_mediatypes, i); + if (mylist && mylist->data) + gst_dshow_free_pin_mediatype ((GstCapturePinMediaType *)mylist->data); + } + g_list_free (pins_mediatypes); +} + +gboolean +gst_dshow_get_pin_from_filter (IBaseFilter *filter, PIN_DIRECTION pindir, IPin **pin) +{ + gboolean ret = FALSE; + IEnumPins *enumpins = NULL; + IPin *pintmp = NULL; + HRESULT hres; + *pin = NULL; + + hres = filter->EnumPins (&enumpins); + if (FAILED(hres)) { + return ret; + } + + while (enumpins->Next (1, &pintmp, NULL) == S_OK) + { + PIN_DIRECTION pindirtmp; + hres = pintmp->QueryDirection (&pindirtmp); + if (hres == S_OK && pindir == pindirtmp) { + *pin = pintmp; + ret = TRUE; + break; + } + pintmp->Release (); + } + enumpins->Release (); + + return ret; +} + +gboolean gst_dshow_find_filter(CLSID input_majortype, CLSID input_subtype, + CLSID output_majortype, CLSID output_subtype, + gchar * prefered_filter_name, IBaseFilter **filter) +{ + gboolean ret = FALSE; + HRESULT hres; + GUID arrayInTypes[2]; + GUID arrayOutTypes[2]; + IFilterMapper2 *mapper = NULL; + IEnumMoniker *enum_moniker = NULL; + IMoniker *moniker = NULL; + ULONG fetched; + gchar *prefered_filter_upper = NULL; + gboolean exit = FALSE; + + /* initialize output parameter */ + if (filter) + *filter = NULL; + + /* create a private copy of prefered filter substring in upper case */ + if (prefered_filter_name) { + prefered_filter_upper = g_strdup (prefered_filter_name); + strupr (prefered_filter_upper); + } + + hres = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC, + IID_IFilterMapper2, (void **) &mapper); + if (FAILED(hres)) + goto clean; + + memcpy(&arrayInTypes[0], &input_majortype, sizeof (CLSID)); + memcpy(&arrayInTypes[1], &input_subtype, sizeof (CLSID)); + memcpy(&arrayOutTypes[0], &output_majortype, sizeof (CLSID)); + memcpy(&arrayOutTypes[1], &output_subtype, sizeof (CLSID)); + + hres = mapper->EnumMatchingFilters (&enum_moniker, 0, FALSE, MERIT_DO_NOT_USE+1, + TRUE, 1, arrayInTypes, NULL, NULL, FALSE, + TRUE, 1, arrayOutTypes, NULL, NULL); + if (FAILED(hres)) + goto clean; + + enum_moniker->Reset (); + + while(hres = enum_moniker->Next (1, &moniker, &fetched),hres == S_OK + && !exit) { + IBaseFilter *filter_temp = NULL; + IPropertyBag *property_bag = NULL; + gchar * friendly_name = NULL; + + hres = moniker->BindToStorage (NULL, NULL, IID_IPropertyBag, (void **)&property_bag); + if(SUCCEEDED(hres) && property_bag) { + VARIANT varFriendlyName; + VariantInit (&varFriendlyName); + + hres = property_bag->Read (L"FriendlyName", &varFriendlyName, NULL); + if(hres == S_OK && varFriendlyName.bstrVal) { + friendly_name = g_utf16_to_utf8((const gunichar2*)varFriendlyName.bstrVal, + wcslen(varFriendlyName.bstrVal), NULL, NULL, NULL); + if (friendly_name) + strupr (friendly_name); + SysFreeString (varFriendlyName.bstrVal); + } + property_bag->Release (); + } + + hres = moniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)&filter_temp); + if(SUCCEEDED(hres) && filter_temp) { + ret = TRUE; + if (filter) { + if (*filter) + (*filter)->Release (); + + *filter = filter_temp; + (*filter)->AddRef (); + + if (prefered_filter_upper && friendly_name && + strstr(friendly_name, prefered_filter_upper)) + exit = TRUE; + } + + /* if we just want to know if the formats are supported OR + if we don't care about what will be the filter used + => we can stop enumeration */ + if (!filter || !prefered_filter_upper) + exit = TRUE; + + filter_temp->Release (); + } + + if (friendly_name) + g_free (friendly_name); + moniker->Release (); + } + +clean: + if (prefered_filter_upper) + g_free (prefered_filter_upper); + if (enum_moniker) + enum_moniker->Release (); + if (mapper) + mapper->Release (); + + return ret; +} + + +gchar * +gst_dshow_getdevice_from_devicename (GUID *device_category, gchar **device_name) +{ + gchar *ret = NULL; + ICreateDevEnum *devices_enum = NULL; + IEnumMoniker *enum_moniker = NULL; + IMoniker *moniker = NULL; + HRESULT hres = S_FALSE; + ULONG fetched; + gboolean bfound = FALSE; + + hres = CoCreateInstance (CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + IID_ICreateDevEnum, (void**)&devices_enum); + if(hres != S_OK) { + /*error*/ + goto clean; + } + + hres = devices_enum->CreateClassEnumerator (*device_category, + &enum_moniker, 0); + if (hres != S_OK || !enum_moniker) { + /*error*/ + goto clean; + } + + enum_moniker->Reset (); + + while(hres = enum_moniker->Next (1, &moniker, &fetched),hres == S_OK + && !bfound) { + IPropertyBag *property_bag = NULL; + hres = moniker->BindToStorage(NULL, NULL, IID_IPropertyBag, (void **)&property_bag); + if(SUCCEEDED(hres) && property_bag) { + VARIANT varFriendlyName; + VariantInit (&varFriendlyName); + + hres = property_bag->Read (L"FriendlyName", &varFriendlyName, NULL); + if(hres == S_OK && varFriendlyName.bstrVal) { + gchar * friendly_name = g_utf16_to_utf8((const gunichar2*)varFriendlyName.bstrVal, + wcslen(varFriendlyName.bstrVal), NULL, NULL, NULL); + + if (!*device_name) { + *device_name = g_strdup (friendly_name); + } + + if (_stricmp(*device_name, friendly_name) == 0) { + WCHAR *wszDisplayName = NULL; + hres = moniker->GetDisplayName (NULL, NULL, &wszDisplayName); + if(hres == S_OK && wszDisplayName) { + ret = g_utf16_to_utf8((const gunichar2*)wszDisplayName, + wcslen(wszDisplayName), NULL, NULL, NULL); + CoTaskMemFree (wszDisplayName); + } + bfound = TRUE; + } + SysFreeString (varFriendlyName.bstrVal); + } + property_bag->Release (); + } + moniker->Release (); + } + +clean: + if (enum_moniker) { + enum_moniker->Release (); + } + + if (devices_enum) { + devices_enum->Release (); + } + + return ret; +} + +gboolean +gst_dshow_show_propertypage (IBaseFilter *base_filter) +{ + gboolean ret = FALSE; + ISpecifyPropertyPages *pProp = NULL; + HRESULT hres = base_filter->QueryInterface (IID_ISpecifyPropertyPages, (void **)&pProp); + if (SUCCEEDED(hres)) + { + /* Get the filter's name and IUnknown pointer.*/ + FILTER_INFO FilterInfo; + CAUUID caGUID; + IUnknown *pFilterUnk = NULL; + hres = base_filter->QueryFilterInfo (&FilterInfo); + base_filter->QueryInterface (IID_IUnknown, (void **)&pFilterUnk); + + /* Show the page. */ + pProp->GetPages (&caGUID); + pProp->Release (); + OleCreatePropertyFrame(GetDesktopWindow(), 0, 0, FilterInfo.achName, + 1, &pFilterUnk, caGUID.cElems, caGUID.pElems, 0, 0, NULL); + + pFilterUnk->Release (); + FilterInfo.pGraph->Release (); + CoTaskMemFree(caGUID.pElems); + } + return ret; +} diff --git a/gst-libs/gst/dshow/gstdshow.h b/gst-libs/gst/dshow/gstdshow.h new file mode 100644 index 00000000..3d1520d5 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshow.h @@ -0,0 +1,79 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshow.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef _GSTDSHOW_ +#define _GSTDSHOW_ + +#include <windows.h> + +#include <glib.h> + +#ifdef LIBDSHOW_EXPORTS +#include <streams.h> +#include <atlbase.h> +#define DSHOW_API __declspec(dllexport) +#else +#define DSHOW_API __declspec(dllimport) +#endif + +typedef struct _GstCapturePinMediaType +{ + AM_MEDIA_TYPE *mediatype; + IPin *capture_pin; +} GstCapturePinMediaType; + +#ifdef __cplusplus +extern "C" { +#endif + +/* register fake filters as COM object and as Direct Show filters in the registry */ +BOOL gst_dshow_register_fakefilters (); + +/* free memory of the input pin mediatype */ +void gst_dshow_free_pin_mediatype (gpointer pt); + +/* free memory of the input dshow mediatype */ +void gst_dshow_free_mediatype (AM_MEDIA_TYPE *pmt); + +/* free the memory of all mediatypes of the input list if pin mediatype */ +void gst_dshow_free_pins_mediatypes (GList *mediatypes); + +/* get a pin from directshow filter */ +gboolean gst_dshow_get_pin_from_filter (IBaseFilter *filter, PIN_DIRECTION pindir, IPin **pin); + +/* find and return a filter according to the input and output types */ +gboolean gst_dshow_find_filter(CLSID input_majortype, CLSID input_subtype, + CLSID output_majortype, CLSID output_subtype, + gchar * prefered_filter_name, IBaseFilter **filter); + +/* get the dshow device path from device friendly name. +If friendly name is not set, it will return the first available device */ +gchar *gst_dshow_getdevice_from_devicename (GUID *device_category, gchar **device_name); + +/* show the capture filter property page (generally used to setup the device). the page is modal*/ +gboolean gst_dshow_show_propertypage (IBaseFilter *base_filter); + + +#ifdef __cplusplus +} +#endif + +#endif /* _GSTDSHOW_ */
\ No newline at end of file diff --git a/gst-libs/gst/dshow/gstdshowfakesink.cpp b/gst-libs/gst/dshow/gstdshowfakesink.cpp new file mode 100644 index 00000000..58b23718 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshowfakesink.cpp @@ -0,0 +1,125 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowfakesink.cpp: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowfakesink.h" + + +CDshowFakeSink::CDshowFakeSink():CBaseRenderer(CLSID_DshowFakeSink, "DshowFakeSink", NULL, NULL) +{ + m_callback = NULL; +} + +CDshowFakeSink::~CDshowFakeSink() +{ + +} + +//Object creation. +CUnknown* WINAPI CDshowFakeSink::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr) +{ + CDshowFakeSink *pNewObject = new CDshowFakeSink(); + if (pNewObject == NULL) { + *pHr = E_OUTOFMEMORY; + } + return pNewObject; +} + +STDMETHODIMP CDshowFakeSink::QueryInterface(REFIID riid, void **ppvObject) +{ + if (riid == IID_IGstDshowInterface) { + *ppvObject = (IGstDshowInterface*) this; + AddRef(); + return S_OK; + } + else + return CBaseRenderer::QueryInterface (riid, ppvObject); +} + +ULONG STDMETHODCALLTYPE CDshowFakeSink::AddRef() +{ + return CBaseRenderer::AddRef(); +} + +ULONG STDMETHODCALLTYPE CDshowFakeSink::Release() +{ + return CBaseRenderer::Release(); +} + + +STDMETHODIMP CDshowFakeSink::gst_set_media_type (AM_MEDIA_TYPE *pmt) +{ + m_MediaType.Set (*pmt); + return S_OK; +} + +STDMETHODIMP CDshowFakeSink::gst_set_buffer_callback (push_buffer_func push, byte *data) +{ + m_callback = push; + m_data = data; + return S_OK; +} + +STDMETHODIMP CDshowFakeSink::gst_push_buffer (byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CDshowFakeSink::gst_flush () +{ + return E_NOTIMPL; +} + +STDMETHODIMP CDshowFakeSink::gst_set_sample_size(unsigned int size) +{ + return E_NOTIMPL; +} + +HRESULT CDshowFakeSink::CheckMediaType(const CMediaType *pmt) +{ + VIDEOINFOHEADER *p1; + VIDEOINFOHEADER *p2; + if(pmt != NULL) + { + p1 = (VIDEOINFOHEADER *)pmt->Format(); + p2 = (VIDEOINFOHEADER *)m_MediaType.Format(); + if (*pmt == m_MediaType) + return S_OK; + } + + return S_FALSE; +} + +HRESULT CDshowFakeSink::DoRenderSample(IMediaSample *pMediaSample) +{ + if(pMediaSample && m_callback) + { + BYTE *pBuffer = NULL; + LONGLONG lStart = 0, lStop = 0; + pMediaSample->GetPointer(&pBuffer); + long size = pMediaSample->GetActualDataLength(); + pMediaSample->GetTime(&lStart, &lStop); + lStart*=100; + lStop*=100; + m_callback(pBuffer, size, m_data, lStart, lStop); + } + + return S_OK; +} diff --git a/gst-libs/gst/dshow/gstdshowfakesink.h b/gst-libs/gst/dshow/gstdshowfakesink.h new file mode 100644 index 00000000..b53a6898 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshowfakesink.h @@ -0,0 +1,49 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowfakesink.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowinterface.h" + +class CDshowFakeSink : public CBaseRenderer, + public IGstDshowInterface +{ +public: + CDshowFakeSink (); + virtual ~CDshowFakeSink (); + + static CUnknown * WINAPI CreateInstance (LPUNKNOWN pUnk, HRESULT *pHr); + + virtual HRESULT CheckMediaType (const CMediaType *pmt); + virtual HRESULT DoRenderSample (IMediaSample *pMediaSample); + + STDMETHOD (QueryInterface)(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + STDMETHOD (gst_set_media_type) (AM_MEDIA_TYPE *pmt); + STDMETHOD (gst_set_buffer_callback) (push_buffer_func push, byte *data); + STDMETHOD (gst_push_buffer) (byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount); + STDMETHOD (gst_flush) (); + STDMETHOD (gst_set_sample_size) (unsigned int size); + +protected: + CMediaType m_MediaType; + push_buffer_func m_callback; + byte *m_data; +};
\ No newline at end of file diff --git a/gst-libs/gst/dshow/gstdshowfakesrc.cpp b/gst-libs/gst/dshow/gstdshowfakesrc.cpp new file mode 100644 index 00000000..2c6bcc88 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshowfakesrc.cpp @@ -0,0 +1,205 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowfakesrc.cpp: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowfakesrc.h" + +static CCritSec g_pCriticSec; + +/* output pin*/ +CDshowFakeOutputPin::CDshowFakeOutputPin (CBaseFilter *pFilter, CCritSec *sec): + CBaseOutputPin("FakeOutputPin", pFilter, sec, &m_hres, L"output") +{ +} + +CDshowFakeOutputPin::~CDshowFakeOutputPin() +{ + +} + +HRESULT CDshowFakeOutputPin::GetMediaType(int iPosition, CMediaType *pMediaType) +{ + if(iPosition == 0) { + *pMediaType = m_MediaType; + return S_OK; + } + + return VFW_S_NO_MORE_ITEMS; +} + +HRESULT CDshowFakeOutputPin::CheckMediaType(const CMediaType *pmt) +{ + if (m_MediaType == *pmt) { + return S_OK; + } + + return S_FALSE; +} + +HRESULT CDshowFakeOutputPin::DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) +{ + ALLOCATOR_PROPERTIES properties; + ppropInputRequest->cbBuffer = m_SampleSize; + ppropInputRequest->cBuffers = 1; + HRESULT hres = pAlloc->SetProperties(ppropInputRequest, &properties); + pAlloc->Commit(); + + return S_OK; +} + +STDMETHODIMP CDshowFakeOutputPin::SetMediaType (AM_MEDIA_TYPE *pmt) +{ + m_MediaType.Set (*pmt); + m_SampleSize = m_MediaType.GetSampleSize(); + return S_OK; +} + +STDMETHODIMP CDshowFakeOutputPin::PushBuffer(byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount) +{ + IMediaSample *pSample = NULL; + + if (start != -1) { + start /= 100; + stop /= 100; + } + + HRESULT hres = GetDeliveryBuffer(&pSample, NULL, NULL, 0); + if (hres == S_OK && pSample) + { + BYTE *sample_buffer; + pSample->GetPointer(&sample_buffer); + if(sample_buffer) + { + memcpy (sample_buffer, buffer, size); + pSample->SetActualDataLength(size); + } + if (discount) + pSample->SetDiscontinuity(TRUE); + else + pSample->SetDiscontinuity(FALSE); + + pSample->SetSyncPoint(TRUE); + pSample->SetPreroll(FALSE); + + if (start != -1) + pSample->SetTime(&start, &stop); + + hres = Deliver(pSample); + pSample->Release(); + } + + return S_OK; +} + +STDMETHODIMP CDshowFakeOutputPin::Flush () +{ + DeliverBeginFlush(); + DeliverEndFlush(); + return S_OK; +} + +STDMETHODIMP CDshowFakeOutputPin::SetSampleSize (unsigned int size) +{ + m_SampleSize = size; + return S_OK; +} + +/* filter */ +CDshowFakeSrc::CDshowFakeSrc():CBaseFilter("DshowFakeSink", NULL, &g_pCriticSec, CLSID_DshowFakeSrc) +{ + m_pOutputPin = new CDshowFakeOutputPin((CSource *)this, m_pLock); +} + +CDshowFakeSrc::~CDshowFakeSrc() +{ + if (m_pOutputPin) + delete m_pOutputPin; +} + +//Object creation. +CUnknown* WINAPI CDshowFakeSrc::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr) +{ + CDshowFakeSrc *pNewObject = new CDshowFakeSrc(); + if (pNewObject == NULL) { + *pHr = E_OUTOFMEMORY; + } + return pNewObject; +} + +int CDshowFakeSrc::GetPinCount() +{ + return 1; +} + +CBasePin *CDshowFakeSrc::GetPin(int n) +{ + return (CBasePin *)m_pOutputPin; +} + + +STDMETHODIMP CDshowFakeSrc::QueryInterface(REFIID riid, void **ppvObject) +{ + if (riid == IID_IGstDshowInterface) { + *ppvObject = (IGstDshowInterface*) this; + AddRef(); + return S_OK; + } + else + return CBaseFilter::QueryInterface (riid, ppvObject); +} + +ULONG STDMETHODCALLTYPE CDshowFakeSrc::AddRef() +{ + return CBaseFilter::AddRef(); +} + +ULONG STDMETHODCALLTYPE CDshowFakeSrc::Release() +{ + return CBaseFilter::Release(); +} + +STDMETHODIMP CDshowFakeSrc::gst_set_media_type (AM_MEDIA_TYPE *pmt) +{ + m_pOutputPin->SetMediaType(pmt); + return S_OK; +} + +STDMETHODIMP CDshowFakeSrc::gst_set_buffer_callback (push_buffer_func push, byte *data) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CDshowFakeSrc::gst_push_buffer (byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount) +{ + m_pOutputPin->PushBuffer(buffer, start, stop, size, discount); + return S_OK; +} + +STDMETHODIMP CDshowFakeSrc::gst_flush () +{ + m_pOutputPin->Flush(); + return S_OK; +} + +STDMETHODIMP CDshowFakeSrc::gst_set_sample_size(unsigned int size) +{ + m_pOutputPin->SetSampleSize(size); + return S_OK; +}
\ No newline at end of file diff --git a/gst-libs/gst/dshow/gstdshowfakesrc.h b/gst-libs/gst/dshow/gstdshowfakesrc.h new file mode 100644 index 00000000..06884313 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshowfakesrc.h @@ -0,0 +1,72 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowfakesrc.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowinterface.h" +#include <gst/gst.h> + +class CDshowFakeOutputPin : public CBaseOutputPin +{ +protected: +/* members */ + HRESULT m_hres; + CMediaType m_MediaType; + unsigned int m_SampleSize; + +public: +/* methods */ + CDshowFakeOutputPin (CBaseFilter *pFilter, CCritSec *sec); + ~CDshowFakeOutputPin (); + + virtual HRESULT CheckMediaType(const CMediaType *pmt); + HRESULT GetMediaType(int iPosition, CMediaType *pMediaType); + virtual HRESULT DecideBufferSize (IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest); + STDMETHOD (SetMediaType) (AM_MEDIA_TYPE *pmt); + STDMETHOD (PushBuffer) (byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount); + STDMETHOD (Flush) (); + STDMETHOD (SetSampleSize) (unsigned int size); +}; + +class CDshowFakeSrc : public CBaseFilter, + public IGstDshowInterface +{ +public: +/* members */ + CDshowFakeOutputPin *m_pOutputPin; + +/* methods */ + CDshowFakeSrc (); + virtual ~CDshowFakeSrc (); + + static CUnknown * WINAPI CreateInstance (LPUNKNOWN pUnk, HRESULT *pHr); + + virtual int GetPinCount(); + virtual CBasePin *GetPin(int n); + + STDMETHOD (QueryInterface)(REFIID riid, void **ppvObject); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + STDMETHOD (gst_set_media_type) (AM_MEDIA_TYPE *pmt); + STDMETHOD (gst_set_buffer_callback) (push_buffer_func push, byte *data); + STDMETHOD (gst_push_buffer) (byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount); + STDMETHOD (gst_flush) (); + STDMETHOD (gst_set_sample_size) (unsigned int size); +};
\ No newline at end of file diff --git a/gst-libs/gst/dshow/gstdshowinterface.cpp b/gst-libs/gst/dshow/gstdshowinterface.cpp new file mode 100644 index 00000000..3dba7c25 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshowinterface.cpp @@ -0,0 +1,35 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowinterface.cpp: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowinterface.h" + + +//{6A780808-9725-4d0b-8695-A4DD8D210773} +const GUID CLSID_DshowFakeSink + = { 0x6a780808, 0x9725, 0x4d0b, { 0x86, 0x95, 0xa4, 0xdd, 0x8d, 0x21, 0x7, 0x73 } }; + +// {1E38DAED-8A6E-4DEA-A482-A878761D11CB} +const GUID CLSID_DshowFakeSrc = +{ 0x1e38daed, 0x8a6e, 0x4dea, { 0xa4, 0x82, 0xa8, 0x78, 0x76, 0x1d, 0x11, 0xcb } }; + +// {FC36764C-6CD4-4C73-900F-3F40BF3F191A} +static const GUID IID_IGstDshowInterface = +{ 0xfc36764c, 0x6cd4, 0x4c73, { 0x90, 0xf, 0x3f, 0x40, 0xbf, 0x3f, 0x19, 0x1a } }; diff --git a/gst-libs/gst/dshow/gstdshowinterface.h b/gst-libs/gst/dshow/gstdshowinterface.h new file mode 100644 index 00000000..1a19a611 --- /dev/null +++ b/gst-libs/gst/dshow/gstdshowinterface.h @@ -0,0 +1,169 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowinterface.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_DHOW_INTERFACE_H__ +#define __GST_DHOW_INTERFACE_H__ + +#include "gstdshow.h" + +#ifdef LIBDSHOW_EXPORTS +typedef bool (*push_buffer_func) (byte *buffer, long size, byte *src_object, UINT64 start, UINT64 stop); +#endif /* LIBDSHOW_EXPORTS */ + +/* verify that the <rpcndr.h> version is high enough to compile this file*/ +#ifndef __REQUIRED_RPCNDR_H_VERSION__ +#define __REQUIRED_RPCNDR_H_VERSION__ 440 +#endif + +#include "rpc.h" +#include "rpcndr.h" + +#ifndef __RPCNDR_H_VERSION__ +#error this stub requires an updated version of <rpcndr.h> +#endif // __RPCNDR_H_VERSION__ + +#ifndef COM_NO_WINDOWS_H +#include "windows.h" +#include "ole2.h" +#endif /*COM_NO_WINDOWS_H*/ + +#ifdef __cplusplus +extern "C"{ +#endif + + +extern DSHOW_API const GUID CLSID_DshowFakeSink; +extern DSHOW_API const GUID CLSID_DshowFakeSrc; +extern DSHOW_API const GUID IID_IGstDshowInterface; + +#define CLSID_DSHOWFAKESINK_STRING "{6A780808-9725-4d0b-8695-A4DD8D210773}" +#define CLSID_DSHOWFAKESRC_STRING "{1E38DAED-8A6E-4DEA-A482-A878761D11CB}" + +typedef interface IGstDshowInterface IGstDshowInterface; + +/* header files for imported files */ +#include "oaidl.h" +#include "ocidl.h" + +void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t); +void __RPC_USER MIDL_user_free( void __RPC_FAR * ); + +#ifndef __IGstDshowInterface_INTERFACE_DEFINED__ +#define __IGstDshowInterface_INTERFACE_DEFINED__ + +#if defined(__cplusplus) && !defined(CINTERFACE) + + MIDL_INTERFACE("542C0A24-8BD1-46cb-AA57-3E46D006D2F3") + IGstDshowInterface : public IUnknown + { + public: + virtual HRESULT STDMETHODCALLTYPE gst_set_media_type( + AM_MEDIA_TYPE __RPC_FAR *pmt) = 0; + + virtual HRESULT STDMETHODCALLTYPE gst_set_buffer_callback( + push_buffer_func push, byte *data) = 0; + + virtual HRESULT STDMETHODCALLTYPE gst_push_buffer( + byte *buffer, __int64 start, __int64 stop, unsigned int size, bool discount) = 0; + + virtual HRESULT STDMETHODCALLTYPE gst_flush() = 0; + + virtual HRESULT STDMETHODCALLTYPE gst_set_sample_size(unsigned int size) = 0; + }; + +#else /* C style interface */ + + typedef struct IGstDshowInterfaceVtbl + { + BEGIN_INTERFACE + + HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( + IGstDshowInterface __RPC_FAR * This, + REFIID riid, + void __RPC_FAR *__RPC_FAR *ppvObject); + + ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( + IGstDshowInterface __RPC_FAR * This); + + ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( + IGstDshowInterface __RPC_FAR * This); + + HRESULT (STDMETHODCALLTYPE *gst_set_media_type )( + IGstDshowInterface __RPC_FAR * This, + AM_MEDIA_TYPE *pmt); + + HRESULT (STDMETHODCALLTYPE *gst_set_buffer_callback) ( + IGstDshowInterface __RPC_FAR * This, + byte * push, byte *data); + + HRESULT (STDMETHODCALLTYPE *gst_push_buffer) ( + IGstDshowInterface __RPC_FAR * This, + byte *buffer, __int64 start, __int64 stop, + unsigned int size, boolean discount); + + HRESULT (STDMETHODCALLTYPE *gst_flush) ( + IGstDshowInterface __RPC_FAR * This); + + HRESULT (STDMETHODCALLTYPE *gst_set_sample_size) ( + IGstDshowInterface __RPC_FAR * This, + unsigned int size); + + END_INTERFACE + } IGstDshowInterfaceVtbl; + + interface IGstDshowInterface + { + CONST_VTBL struct IGstDshowInterfaceVtbl __RPC_FAR *lpVtbl; + }; + +#define IGstDshowInterface_QueryInterface(This,riid,ppvObject) \ + (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) + +#define IGstDshowInterface_AddRef(This) \ + (This)->lpVtbl -> AddRef(This) + +#define IGstDshowInterface_Release(This) \ + (This)->lpVtbl -> Release(This) + +#define IGstDshowInterface_gst_set_media_type(This, mediatype) \ + (This)->lpVtbl -> gst_set_media_type(This, mediatype) + +#define IGstDshowInterface_gst_set_buffer_callback(This, push, data) \ + (This)->lpVtbl -> gst_set_buffer_callback(This, push, data) + +#define IGstDshowInterface_gst_push_buffer(This, buffer, start, stop, size, discount) \ + (This)->lpVtbl -> gst_push_buffer(This, buffer, start, stop, size, discount) + +#define IGstDshowInterface_gst_flush(This) \ + (This)->lpVtbl -> gst_flush(This) + +#define IGstDshowInterface_gst_set_sample_size(This, size) \ + (This)->lpVtbl -> gst_set_sample_size(This, size) + +#endif /* C style interface */ + +#endif /* __IGstDshowInterface_INTERFACE_DEFINED__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* __GST_DSHOW_INTERFACE_H__ */
\ No newline at end of file diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c index e0b262ed..97127bdb 100644 --- a/sys/directsound/gstdirectsoundsink.c +++ b/sys/directsound/gstdirectsoundsink.c @@ -76,13 +76,8 @@ static void gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass); static void gst_directsound_sink_init (GstDirectSoundSink * dsoundsink, GstDirectSoundSinkClass * g_class); static void gst_directsound_sink_finalise (GObject * object); -static void gst_directsound_sink_set_property (GObject * object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_directsound_sink_get_property (GObject * object, - guint prop_id, GValue * value, GParamSpec * pspec); static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink); - static gboolean gst_directsound_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec); static gboolean gst_directsound_sink_unprepare (GstAudioSink * asink); @@ -94,6 +89,12 @@ static guint gst_directsound_sink_write (GstAudioSink * asink, gpointer data, static guint gst_directsound_sink_delay (GstAudioSink * asink); static void gst_directsound_sink_reset (GstAudioSink * asink); +/* interfaces */ +static void gst_directsound_sink_interfaces_init (GType type); +static void +gst_directsound_sink_implements_interface_init (GstImplementsInterfaceClass * + iface); +static void gst_directsound_sink_mixer_interface_init (GstMixerClass * iface); static GstStaticPadTemplate directsoundsink_sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", @@ -110,22 +111,108 @@ static GstStaticPadTemplate directsoundsink_sink_factory = "depth = (int) 8, " "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")); -enum +GST_BOILERPLATE_FULL (GstDirectSoundSink, gst_directsound_sink, GstAudioSink, + GST_TYPE_AUDIO_SINK, gst_directsound_sink_interfaces_init); + +/* interfaces stuff */ +static void +gst_directsound_sink_interfaces_init (GType type) +{ + static const GInterfaceInfo implements_interface_info = { + (GInterfaceInitFunc) gst_directsound_sink_implements_interface_init, + NULL, + NULL, + }; + + static const GInterfaceInfo mixer_interface_info = { + (GInterfaceInitFunc) gst_directsound_sink_mixer_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info); + g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_interface_info); +} + +static gboolean +gst_directsound_sink_interface_supported (GstImplementsInterface * iface, + GType iface_type) { - PROP_0, - PROP_ATTENUATION -}; + g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE); + + /* for the sake of this example, we'll always support it. However, normally, + * you would check whether the device you've opened supports mixers. */ + return TRUE; +} static void -_do_init (GType directsoundsink_type) +gst_directsound_sink_implements_interface_init (GstImplementsInterfaceClass * + iface) { - GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0, - "DirectSound sink"); + iface->supported = gst_directsound_sink_interface_supported; } -GST_BOILERPLATE_FULL (GstDirectSoundSink, gst_directsound_sink, GstAudioSink, - GST_TYPE_AUDIO_SINK, _do_init); +/* + * This function returns the list of support tracks (inputs, outputs) + * on this element instance. Elements usually build this list during + * _init () or when going from NULL to READY. + */ + +static const GList * +gst_directsound_sink_mixer_list_tracks (GstMixer * mixer) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer); + return dsoundsink->tracks; +} + +/* + * Set volume. volumes is an array of size track->num_channels, and + * each value in the array gives the wanted volume for one channel + * on the track. + */ + +static void +gst_directsound_sink_mixer_set_volume (GstMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer); + + if (volumes[0] != dsoundsink->volume) { + dsoundsink->volume = volumes[0]; + + if (dsoundsink->pDSBSecondary) { + /* DirectSound is using attenuation in the following range + * (DSBVOLUME_MIN=-10000, DSBVOLUME_MAX=0) */ + glong ds_attenuation = DSBVOLUME_MIN + (dsoundsink->volume * 100); + + IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, ds_attenuation); + } + } +} + +static void +gst_directsound_sink_mixer_get_volume (GstMixer * mixer, + GstMixerTrack * track, gint * volumes) +{ + GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer); + + volumes[0] = dsoundsink->volume; +} + +static void +gst_directsound_sink_mixer_interface_init (GstMixerClass * iface) +{ + /* the mixer interface requires a definition of the mixer type: + * hardware or software? */ + GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE; + + /* virtual function pointers */ + iface->list_tracks = gst_directsound_sink_mixer_list_tracks; + iface->set_volume = gst_directsound_sink_mixer_set_volume; + iface->get_volume = gst_directsound_sink_mixer_get_volume; +} static void gst_directsound_sink_finalise (GObject * object) @@ -134,6 +221,12 @@ gst_directsound_sink_finalise (GObject * object) g_mutex_free (dsoundsink->dsound_lock); + if (dsoundsink->tracks) { + g_list_foreach (dsoundsink->tracks, (GFunc) g_object_unref, NULL); + g_list_free (dsoundsink->tracks); + dsoundsink->tracks = NULL; + } + G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -162,13 +255,12 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass) gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; gstaudiosink_class = (GstAudioSinkClass *) klass; + GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0, + "DirectSound sink"); + parent_class = g_type_class_peek_parent (klass); gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_directsound_sink_finalise); - gobject_class->get_property = - GST_DEBUG_FUNCPTR (gst_directsound_sink_get_property); - gobject_class->set_property = - GST_DEBUG_FUNCPTR (gst_directsound_sink_set_property); gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_directsound_sink_getcaps); @@ -182,69 +274,28 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass) gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_directsound_sink_write); gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_directsound_sink_delay); gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_directsound_sink_reset); - - g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_ATTENUATION, - g_param_spec_long ("attenuation", "Attenuation of the sound", - "The attenuation for the directsound buffer (default is 0 so the directsound buffer will not be attenuated)", - -10000, 0, 0, G_PARAM_READWRITE)); -} - -static void -gst_directsound_sink_set_property (GObject * object, guint prop_id, - const GValue * value, GParamSpec * pspec) -{ - GstDirectSoundSink *dsoundsink; - - dsoundsink = GST_DIRECTSOUND_SINK (object); - - switch (prop_id) { - case PROP_ATTENUATION: - { - glong attenuation = g_value_get_long (value); - - if (attenuation != dsoundsink->attenuation) { - dsoundsink->attenuation = attenuation; - - if (dsoundsink->pDSBSecondary) - IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, - dsoundsink->attenuation); - } - - break; - } - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gst_directsound_sink_get_property (GObject * object, guint prop_id, - GValue * value, GParamSpec * pspec) -{ - GstDirectSoundSink *dsoundsink; - - dsoundsink = GST_DIRECTSOUND_SINK (object); - - switch (prop_id) { - case PROP_ATTENUATION: - g_value_set_long (value, dsoundsink->attenuation); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } } static void gst_directsound_sink_init (GstDirectSoundSink * dsoundsink, GstDirectSoundSinkClass * g_class) { + GstMixerTrack *track = NULL; + + dsoundsink->tracks = NULL; + track = g_object_new (GST_TYPE_MIXER_TRACK, NULL); + track->label = g_strdup ("DSoundTrack"); + track->num_channels = 2; + track->min_volume = 0; + track->max_volume = 100; + track->flags = GST_MIXER_TRACK_OUTPUT; + dsoundsink->tracks = g_list_append (dsoundsink->tracks, track); + dsoundsink->pDS = NULL; dsoundsink->pDSBSecondary = NULL; dsoundsink->current_circular_offset = 0; dsoundsink->buffer_size = DSBSIZE_MIN; - dsoundsink->attenuation = 0; + dsoundsink->volume = 100; dsoundsink->dsound_lock = g_mutex_new (); dsoundsink->first_buffer_after_reset = FALSE; } @@ -335,10 +386,6 @@ gst_directsound_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) return FALSE; } - if (dsoundsink->attenuation != 0) - IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, - dsoundsink->attenuation); - return TRUE; } diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h index ea7ccbdf..6acf92b4 100644 --- a/sys/directsound/gstdirectsoundsink.h +++ b/sys/directsound/gstdirectsoundsink.h @@ -30,6 +30,7 @@ #include <gst/gst.h> #include <gst/audio/gstaudiosink.h> +#include <gst/interfaces/mixer.h> #include <windows.h> #include <dxerr9.h> @@ -51,20 +52,27 @@ struct _GstDirectSoundSink { GstAudioSink sink; + /* directsound object interface pointer */ LPDIRECTSOUND pDS; + /* directsound sound object interface pointer */ LPDIRECTSOUNDBUFFER pDSBSecondary; - /*DirectSound buffer size */ + /* directSound buffer size */ guint buffer_size; - /*Offset of the circular buffer where we must write next */ + /* offset of the circular buffer where we must write next */ guint current_circular_offset; guint bytes_per_sample; - glong attenuation; + /* current volume setup by mixer interface */ + glong volume; + /* tracks list of our mixer interface implementation */ + GList *tracks; + + /* lock used to protect writes and resets */ GMutex *dsound_lock; gboolean first_buffer_after_reset; diff --git a/sys/dshowsrcwrapper/gstdshowaudiosrc.c b/sys/dshowsrcwrapper/gstdshowaudiosrc.c new file mode 100644 index 00000000..87c12789 --- /dev/null +++ b/sys/dshowsrcwrapper/gstdshowaudiosrc.c @@ -0,0 +1,879 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowaudiosrc.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowaudiosrc.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +static const GstElementDetails gst_dshowaudiosrc_details = +GST_ELEMENT_DETAILS ("Directshow audio capture source", + "Source/Audio", + "Receive data from a directshow audio capture graph", + "Sebastien Moutte <sebastien@moutte.net>"); + +GST_DEBUG_CATEGORY_STATIC (dshowaudiosrc_debug); +#define GST_CAT_DEFAULT dshowaudiosrc_debug + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 16, " + "depth = (int) 16, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; " + "audio/x-raw-int, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 8, " + "depth = (int) 8, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") + ); + +static void gst_dshowaudiosrc_init_interfaces (GType type); + +GST_BOILERPLATE_FULL (GstDshowAudioSrc, gst_dshowaudiosrc, GstAudioSrc, + GST_TYPE_AUDIO_SRC, gst_dshowaudiosrc_init_interfaces); + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME +}; + +static void gst_dshowaudiosrc_probe_interface_init (GstPropertyProbeInterface * + iface); +static const GList *gst_dshowaudiosrc_probe_get_properties (GstPropertyProbe * + probe); +static GValueArray *gst_dshowaudiosrc_probe_get_values (GstPropertyProbe * + probe, guint prop_id, const GParamSpec * pspec); +static GValueArray *gst_dshowaudiosrc_get_device_name_values (GstDshowAudioSrc * + src); + + +static void gst_dshowaudiosrc_dispose (GObject * gobject); +static void gst_dshowaudiosrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_dshowaudiosrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static GstCaps *gst_dshowaudiosrc_get_caps (GstBaseSrc * src); +static GstStateChangeReturn gst_dshowaudiosrc_change_state (GstElement * + element, GstStateChange transition); + +static gboolean gst_dshowaudiosrc_open (GstAudioSrc * asrc); +static gboolean gst_dshowaudiosrc_prepare (GstAudioSrc * asrc, + GstRingBufferSpec * spec); +static gboolean gst_dshowaudiosrc_unprepare (GstAudioSrc * asrc); +static gboolean gst_dshowaudiosrc_close (GstAudioSrc * asrc); +static guint gst_dshowaudiosrc_read (GstAudioSrc * asrc, gpointer data, + guint length); +static guint gst_dshowaudiosrc_delay (GstAudioSrc * asrc); +static void gst_dshowaudiosrc_reset (GstAudioSrc * asrc); + +/* utils */ +static GstCaps *gst_dshowaudiosrc_getcaps_from_streamcaps (GstDshowAudioSrc * + src, IPin * pin, IAMStreamConfig * streamcaps); +static gboolean gst_dshowaudiosrc_push_buffer (byte * buffer, long size, + byte * src_object, UINT64 start, UINT64 stop); + +static void +gst_dshowaudiosrc_init_interfaces (GType type) +{ + static const GInterfaceInfo dshowaudiosrc_info = { + (GInterfaceInitFunc) gst_dshowaudiosrc_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_PROPERTY_PROBE, &dshowaudiosrc_info); +} + +static void +gst_dshowaudiosrc_probe_interface_init (GstPropertyProbeInterface * iface) +{ + iface->get_properties = gst_dshowaudiosrc_probe_get_properties; +/* iface->needs_probe = gst_dshowaudiosrc_probe_needs_probe; + iface->probe_property = gst_dshowaudiosrc_probe_probe_property;*/ + iface->get_values = gst_dshowaudiosrc_probe_get_values; +} + +static void +gst_dshowaudiosrc_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details (element_class, &gst_dshowaudiosrc_details); +} + +static void +gst_dshowaudiosrc_class_init (GstDshowAudioSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + GstAudioSrcClass *gstaudiosrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstaudiosrc_class = (GstAudioSrcClass *) klass; + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_dispose); + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_get_property); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_change_state); + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_get_caps); + + gstaudiosrc_class->open = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_open); + gstaudiosrc_class->prepare = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_prepare); + gstaudiosrc_class->unprepare = + GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_unprepare); + gstaudiosrc_class->close = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_close); + gstaudiosrc_class->read = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_read); + gstaudiosrc_class->delay = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_delay); + gstaudiosrc_class->reset = GST_DEBUG_FUNCPTR (gst_dshowaudiosrc_reset); + + g_object_class_install_property + (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "Directshow device reference (classID/name)", + NULL, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_DEVICE_NAME, + g_param_spec_string ("device_name", "Device name", + "Human-readable name of the sound device", NULL, G_PARAM_READWRITE)); + + GST_DEBUG_CATEGORY_INIT (dshowaudiosrc_debug, "dshowaudiosrc", 0, + "Directshow audio source"); +} + +static void +gst_dshowaudiosrc_init (GstDshowAudioSrc * src, GstDshowAudioSrcClass * klass) +{ + src->device = NULL; + src->device_name = NULL; + src->audio_cap_filter = NULL; + src->dshow_fakesink = NULL; + src->media_filter = NULL; + src->filter_graph = NULL; + src->caps = NULL; + src->pins_mediatypes = NULL; + + src->gbarray = g_byte_array_new (); + src->gbarray_lock = g_mutex_new (); + + src->is_running = FALSE; + + CoInitializeEx (NULL, COINIT_MULTITHREADED); +} + +static void +gst_dshowaudiosrc_dispose (GObject * gobject) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (gobject); + + if (src->device) { + g_free (src->device); + src->device = NULL; + } + + if (src->device_name) { + g_free (src->device_name); + src->device_name = NULL; + } + + if (src->caps) { + gst_caps_unref (src->caps); + src->caps = NULL; + } + + if (src->pins_mediatypes) { + gst_dshow_free_pins_mediatypes (src->pins_mediatypes); + src->pins_mediatypes = NULL; + } + + if (src->gbarray) { + g_byte_array_free (src->gbarray, TRUE); + src->gbarray = NULL; + } + + if (src->gbarray_lock) { + g_mutex_free (src->gbarray_lock); + src->gbarray_lock = NULL; + } + + /* clean dshow */ + if (src->audio_cap_filter) { + IBaseFilter_Release (src->audio_cap_filter); + } + + CoUninitialize (); +} + + +static const GList * +gst_dshowaudiosrc_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *props = NULL; + + if (!props) { + GParamSpec *pspec; + + pspec = g_object_class_find_property (klass, "device_name"); + props = g_list_append (props, pspec); + } + + return props; +} + +static GValueArray * +gst_dshowaudiosrc_get_device_name_values (GstDshowAudioSrc * src) +{ + GValueArray *array = g_value_array_new (0); + GValue value = { 0 }; + ICreateDevEnum *devices_enum = NULL; + IEnumMoniker *moniker_enum = NULL; + IMoniker *moniker = NULL; + HRESULT hres = S_FALSE; + ULONG fetched; + + g_value_init (&value, G_TYPE_STRING); + + hres = CoCreateInstance (&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ICreateDevEnum, (void **) &devices_enum); + if (hres != S_OK) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't create an instance of the system device enumerator (error=%d)", + hres); + array = NULL; + goto clean; + } + + hres = + ICreateDevEnum_CreateClassEnumerator (devices_enum, + &CLSID_AudioInputDeviceCategory, &moniker_enum, 0); + if (hres != S_OK || !moniker_enum) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't get enumeration of audio devices (error=%d)", hres); + array = NULL; + goto clean; + } + + IEnumMoniker_Reset (moniker_enum); + + while (hres = IEnumMoniker_Next (moniker_enum, 1, &moniker, &fetched), + hres == S_OK) { + IPropertyBag *property_bag = NULL; + + hres = + IMoniker_BindToStorage (moniker, NULL, NULL, &IID_IPropertyBag, + (void **) &property_bag); + if (SUCCEEDED (hres) && property_bag) { + VARIANT varFriendlyName; + + VariantInit (&varFriendlyName); + hres = + IPropertyBag_Read (property_bag, L"FriendlyName", &varFriendlyName, + NULL); + if (hres == S_OK && varFriendlyName.bstrVal) { + gchar *friendly_name = + g_utf16_to_utf8 ((const gunichar2 *) varFriendlyName.bstrVal, + wcslen (varFriendlyName.bstrVal), NULL, NULL, NULL); + + g_value_set_string (&value, friendly_name); + g_value_array_append (array, &value); + g_value_unset (&value); + g_free (friendly_name); + SysFreeString (varFriendlyName.bstrVal); + } + IPropertyBag_Release (property_bag); + } + IMoniker_Release (moniker); + } + +clean: + if (moniker_enum) { + IEnumMoniker_Release (moniker_enum); + } + + if (devices_enum) { + ICreateDevEnum_Release (devices_enum); + } + + return array; +} + +static GValueArray * +gst_dshowaudiosrc_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case PROP_DEVICE_NAME: + array = gst_dshowaudiosrc_get_device_name_values (src); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +static void +gst_dshowaudiosrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (object); + + switch (prop_id) { + case PROP_DEVICE: + { + if (src->device) { + g_free (src->device); + src->device = NULL; + } + if (g_value_get_string (value)) { + src->device = g_strdup (g_value_get_string (value)); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_dshowaudiosrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + +} + +static GstCaps * +gst_dshowaudiosrc_get_caps (GstBaseSrc * basesrc) +{ + HRESULT hres = S_OK; + IBindCtx *lpbc = NULL; + IMoniker *audiom = NULL; + DWORD dwEaten; + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (basesrc); + gunichar2 *unidevice = NULL; + + if (src->device) { + g_free (src->device); + src->device = NULL; + } + + src->device = + gst_dshow_getdevice_from_devicename (&CLSID_AudioInputDeviceCategory, + &src->device_name); + if (!src->device) { + GST_CAT_ERROR (dshowaudiosrc_debug, "No audio device found."); + return NULL; + } + unidevice = + g_utf8_to_utf16 (src->device, strlen (src->device), NULL, NULL, NULL); + + if (!src->audio_cap_filter) { + hres = CreateBindCtx (0, &lpbc); + if (SUCCEEDED (hres)) { + hres = MkParseDisplayName (lpbc, unidevice, &dwEaten, &audiom); + if (SUCCEEDED (hres)) { + hres = + IMoniker_BindToObject (audiom, lpbc, NULL, &IID_IBaseFilter, + &src->audio_cap_filter); + IMoniker_Release (audiom); + } + IBindCtx_Release (lpbc); + } + } + + if (src->audio_cap_filter && !src->caps) { + /* get the capture pins supported types */ + IPin *capture_pin = NULL; + IEnumPins *enumpins = NULL; + HRESULT hres; + + hres = IBaseFilter_EnumPins (src->audio_cap_filter, &enumpins); + if (SUCCEEDED (hres)) { + while (IEnumPins_Next (enumpins, 1, &capture_pin, NULL) == S_OK) { + IKsPropertySet *pKs = NULL; + + hres = + IPin_QueryInterface (capture_pin, &IID_IKsPropertySet, + (void **) &pKs); + if (SUCCEEDED (hres) && pKs) { + DWORD cbReturned; + GUID pin_category; + RPC_STATUS rpcstatus; + + hres = + IKsPropertySet_Get (pKs, &ROPSETID_Pin, + AMPROPERTY_PIN_CATEGORY, NULL, 0, &pin_category, sizeof (GUID), + &cbReturned); + + /* we only want capture pins */ + if (UuidCompare (&pin_category, &PIN_CATEGORY_CAPTURE, + &rpcstatus) == 0) { + IAMStreamConfig *streamcaps = NULL; + + if (SUCCEEDED (IPin_QueryInterface (capture_pin, + &IID_IAMStreamConfig, (void **) &streamcaps))) { + src->caps = + gst_dshowaudiosrc_getcaps_from_streamcaps (src, capture_pin, + streamcaps); + IAMStreamConfig_Release (streamcaps); + } + } + IKsPropertySet_Release (pKs); + } + IPin_Release (capture_pin); + } + IEnumPins_Release (enumpins); + } + } + + if (unidevice) { + g_free (unidevice); + } + + if (src->caps) { + return gst_caps_ref (src->caps); + } + + return NULL; +} + +static GstStateChangeReturn +gst_dshowaudiosrc_change_state (GstElement * element, GstStateChange transition) +{ + HRESULT hres = S_FALSE; + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + if (src->media_filter) + hres = IMediaFilter_Run (src->media_filter, 0); + if (hres != S_OK) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't RUN the directshow capture graph (error=%d)", hres); + src->is_running = FALSE; + return GST_STATE_CHANGE_FAILURE; + } else { + src->is_running = TRUE; + } + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + if (src->media_filter) + hres = IMediaFilter_Stop (src->media_filter); + if (hres != S_OK) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't STOP the directshow capture graph (error=%d)", hres); + return GST_STATE_CHANGE_FAILURE; + } + src->is_running = FALSE; + + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + default: + break; + } + + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); +} + +static gboolean +gst_dshowaudiosrc_open (GstAudioSrc * asrc) +{ + HRESULT hres = S_FALSE; + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + + hres = CoCreateInstance (&CLSID_FilterGraph, NULL, CLSCTX_INPROC, + &IID_IFilterGraph, (LPVOID *) & src->filter_graph); + if (hres != S_OK || !src->filter_graph) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't create an instance of the directshow graph manager (error=%d)", + hres); + goto error; + } + + hres = IFilterGraph_QueryInterface (src->filter_graph, &IID_IMediaFilter, + (void **) &src->media_filter); + if (hres != S_OK || !src->media_filter) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't get IMediacontrol interface from the graph manager (error=%d)", + hres); + goto error; + } + + hres = CoCreateInstance (&CLSID_DshowFakeSink, NULL, CLSCTX_INPROC, + &IID_IBaseFilter, (LPVOID *) & src->dshow_fakesink); + if (hres != S_OK || !src->dshow_fakesink) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't create an instance of the directshow fakesink (error=%d)", hres); + goto error; + } + + hres = + IFilterGraph_AddFilter (src->filter_graph, src->audio_cap_filter, + L"capture"); + if (hres != S_OK) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't add the directshow capture filter to the graph (error=%d)", + hres); + goto error; + } + + hres = + IFilterGraph_AddFilter (src->filter_graph, src->dshow_fakesink, + L"fakesink"); + if (hres != S_OK) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't add our fakesink filter to the graph (error=%d)", hres); + goto error; + } + + return TRUE; + +error: + if (src->dshow_fakesink) { + IBaseFilter_Release (src->dshow_fakesink); + src->dshow_fakesink = NULL; + } + + if (src->media_filter) { + IMediaFilter_Release (src->media_filter); + src->media_filter = NULL; + } + if (src->filter_graph) { + IFilterGraph_Release (src->filter_graph); + src->filter_graph = NULL; + } + + return FALSE; +} + +static gboolean +gst_dshowaudiosrc_prepare (GstAudioSrc * asrc, GstRingBufferSpec * spec) +{ + HRESULT hres; + IGstDshowInterface *srcinterface = NULL; + IPin *input_pin = NULL; + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + + /* search the negociated caps in our caps list to get its index and the corresponding mediatype */ + if (gst_caps_is_subset (spec->caps, src->caps)) { + guint i = 0; + gint res = -1; + + for (; i < gst_caps_get_size (src->caps) && res == -1; i++) { + GstCaps *capstmp = gst_caps_copy_nth (src->caps, i); + + if (gst_caps_is_subset (spec->caps, capstmp)) { + res = i; + } + gst_caps_unref (capstmp); + } + + if (res != -1 && src->pins_mediatypes) { + /*get the corresponding media type and build the dshow graph */ + GstCapturePinMediaType *pin_mediatype = NULL; + GList *type = g_list_nth (src->pins_mediatypes, res); + + if (type) { + pin_mediatype = (GstCapturePinMediaType *) type->data; + + hres = + IBaseFilter_QueryInterface (src->dshow_fakesink, + &IID_IGstDshowInterface, (void **) &srcinterface); + if (hres != S_OK || !srcinterface) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't get IGstDshowInterface interface from our dshow fakesink filter (error=%d)", + hres); + goto error; + } + + IGstDshowInterface_gst_set_media_type (srcinterface, + pin_mediatype->mediatype); + IGstDshowInterface_gst_set_buffer_callback (srcinterface, + gst_dshowaudiosrc_push_buffer, (byte *) src); + + if (srcinterface) { + IGstDshowInterface_Release (srcinterface); + } + + gst_dshow_get_pin_from_filter (src->dshow_fakesink, PINDIR_INPUT, + &input_pin); + if (!input_pin) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't get input pin from our directshow fakesink filter"); + goto error; + } + + hres = + IFilterGraph_ConnectDirect (src->filter_graph, + pin_mediatype->capture_pin, input_pin, NULL); + IPin_Release (input_pin); + + if (hres != S_OK) { + GST_CAT_ERROR (dshowaudiosrc_debug, + "Can't connect capture filter with fakesink filter (error=%d)", + hres); + goto error; + } + + spec->segsize = spec->rate * spec->channels; + spec->segtotal = 1; + } + } + } + + return TRUE; + +error: + if (srcinterface) { + IGstDshowInterface_Release (srcinterface); + } + + return FALSE; +} + +static gboolean +gst_dshowaudiosrc_unprepare (GstAudioSrc * asrc) +{ + IPin *input_pin = NULL, *output_pin = NULL; + HRESULT hres = S_FALSE; + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + + /* disconnect filters */ + gst_dshow_get_pin_from_filter (src->audio_cap_filter, PINDIR_OUTPUT, + &output_pin); + if (output_pin) { + hres = IFilterGraph_Disconnect (src->filter_graph, output_pin); + IPin_Release (output_pin); + } + + gst_dshow_get_pin_from_filter (src->dshow_fakesink, PINDIR_INPUT, &input_pin); + if (input_pin) { + hres = IFilterGraph_Disconnect (src->filter_graph, input_pin); + IPin_Release (input_pin); + } + + return TRUE; +} + +static gboolean +gst_dshowaudiosrc_close (GstAudioSrc * asrc) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + + if (!src->filter_graph) + return TRUE; + + /*remove filters from the graph */ + IFilterGraph_RemoveFilter (src->filter_graph, src->audio_cap_filter); + IFilterGraph_RemoveFilter (src->filter_graph, src->dshow_fakesink); + + /*release our gstreamer dshow sink */ + IBaseFilter_Release (src->dshow_fakesink); + src->dshow_fakesink = NULL; + + /*release media filter interface */ + IMediaFilter_Release (src->media_filter); + src->media_filter = NULL; + + /*release the filter graph manager */ + IFilterGraph_Release (src->filter_graph); + src->filter_graph = NULL; + + return TRUE; +} + +static guint +gst_dshowaudiosrc_read (GstAudioSrc * asrc, gpointer data, guint length) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + guint ret = 0; + + if (!src->is_running) + return -1; + + if (src->gbarray) { + test: + if (src->gbarray->len >= length) { + g_mutex_lock (src->gbarray_lock); + memcpy (data, src->gbarray->data + (src->gbarray->len - length), length); + g_byte_array_remove_range (src->gbarray, src->gbarray->len - length, + length); + ret = length; + g_mutex_unlock (src->gbarray_lock); + } else { + if (src->is_running) { + Sleep (100); + goto test; + } + } + } + + return ret; +} + +static guint +gst_dshowaudiosrc_delay (GstAudioSrc * asrc) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + guint ret = 0; + + if (src->gbarray) { + g_mutex_lock (src->gbarray_lock); + if (src->gbarray->len) { + ret = src->gbarray->len / 4; + } + g_mutex_unlock (src->gbarray_lock); + } + + return ret; +} + +static void +gst_dshowaudiosrc_reset (GstAudioSrc * asrc) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (asrc); + + g_mutex_lock (src->gbarray_lock); + g_byte_array_remove_range (src->gbarray, 0, src->gbarray->len); + g_mutex_unlock (src->gbarray_lock); +} + +static GstCaps * +gst_dshowaudiosrc_getcaps_from_streamcaps (GstDshowAudioSrc * src, IPin * pin, + IAMStreamConfig * streamcaps) +{ + GstCaps *caps = NULL; + HRESULT hres = S_OK; + RPC_STATUS rpcstatus; + int icount = 0; + int isize = 0; + AUDIO_STREAM_CONFIG_CAPS ascc; + int i = 0; + + if (!streamcaps) + return NULL; + + IAMStreamConfig_GetNumberOfCapabilities (streamcaps, &icount, &isize); + + if (isize != sizeof (ascc)) + return NULL; + + for (; i < icount; i++) { + GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1); + + IPin_AddRef (pin); + pin_mediatype->capture_pin = pin; + + hres = + IAMStreamConfig_GetStreamCaps (streamcaps, i, &pin_mediatype->mediatype, + (BYTE *) & ascc); + if (hres == S_OK && pin_mediatype->mediatype) { + GstCaps *mediacaps = NULL; + + if (!caps) + caps = gst_caps_new_empty (); + + if ((UuidCompare (&pin_mediatype->mediatype->subtype, &MEDIASUBTYPE_PCM, + &rpcstatus) == 0 && rpcstatus == RPC_S_OK) + && (UuidCompare (&pin_mediatype->mediatype->formattype, + &FORMAT_WaveFormatEx, &rpcstatus) == 0 + && rpcstatus == RPC_S_OK)) { + WAVEFORMATEX *wavformat = + (WAVEFORMATEX *) pin_mediatype->mediatype->pbFormat; + mediacaps = + gst_caps_new_simple ("audio/x-raw-int", "width", G_TYPE_INT, + wavformat->wBitsPerSample, "depth", G_TYPE_INT, + wavformat->wBitsPerSample, "endianness", G_TYPE_INT, G_BYTE_ORDER, + "signed", G_TYPE_BOOLEAN, TRUE, "channels", G_TYPE_INT, + wavformat->nChannels, "rate", G_TYPE_INT, wavformat->nSamplesPerSec, + NULL); + + if (mediacaps) { + src->pins_mediatypes = + g_list_append (src->pins_mediatypes, pin_mediatype); + gst_caps_append (caps, mediacaps); + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + } + + if (caps && gst_caps_is_empty (caps)) { + gst_caps_unref (caps); + caps = NULL; + } + + return caps; +} + +static gboolean +gst_dshowaudiosrc_push_buffer (byte * buffer, long size, byte * src_object, + UINT64 start, UINT64 stop) +{ + GstDshowAudioSrc *src = GST_DSHOWAUDIOSRC (src_object); + + if (!buffer || size == 0 || !src) { + return FALSE; + } + + g_mutex_lock (src->gbarray_lock); + g_byte_array_prepend (src->gbarray, (guint8 *) buffer, size); + g_mutex_unlock (src->gbarray_lock); + + return TRUE; +} diff --git a/sys/dshowsrcwrapper/gstdshowaudiosrc.h b/sys/dshowsrcwrapper/gstdshowaudiosrc.h new file mode 100644 index 00000000..fb571015 --- /dev/null +++ b/sys/dshowsrcwrapper/gstdshowaudiosrc.h @@ -0,0 +1,82 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowaudiosrc.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#ifndef __GST_DSHOWAUDIOSRC_H__ +#define __GST_DSHOWAUDIOSRC_H__ + +#include <gst/gst.h> +#include <gst/audio/gstaudiosrc.h> +#include <gst/interfaces/propertyprobe.h> + +#include "gstdshowsrcwrapper.h" + +G_BEGIN_DECLS +#define GST_TYPE_DSHOWAUDIOSRC (gst_dshowaudiosrc_get_type()) +#define GST_DSHOWAUDIOSRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DSHOWAUDIOSRC,GstDshowAudioSrc)) +#define GST_DSHOWAUDIOSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DSHOWAUDIOSRC,GstDshowAudioSrcClass)) +#define GST_IS_DSHOWAUDIOSRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DSHOWAUDIOSRC)) +#define GST_IS_DSHOWAUDIOSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DSHOWAUDIOSRC)) +typedef struct _GstDshowAudioSrc GstDshowAudioSrc; +typedef struct _GstDshowAudioSrcClass GstDshowAudioSrcClass; + +struct _GstDshowAudioSrc +{ + GstAudioSrc src; + + /* device dshow reference (generally classid/name) */ + gchar *device; + + /* device friendly name */ + gchar *device_name; + + /* list of caps created from the list of supported media types of the dshow capture filter */ + GstCaps *caps; + + /* list of dshow media types filter's pins mediatypes */ + GList *pins_mediatypes; + + /* dshow audio capture filter */ + IBaseFilter *audio_cap_filter; + + /* dshow fakesink filter */ + IBaseFilter *dshow_fakesink; + + /* graph manager interfaces */ + IMediaFilter *media_filter; + IFilterGraph *filter_graph; + + /* bytes array*/ + GByteArray *gbarray; + GMutex *gbarray_lock; + + gboolean is_running; +}; + +struct _GstDshowAudioSrcClass +{ + GstAudioSrcClass parent_class; +}; + +GType gst_dshowaudiosrc_get_type (void); + +G_END_DECLS +#endif /* __GST_DSHOWAUDIOSRC_H__ */ diff --git a/sys/dshowsrcwrapper/gstdshowsrcwrapper.c b/sys/dshowsrcwrapper/gstdshowsrcwrapper.c new file mode 100644 index 00000000..803fd807 --- /dev/null +++ b/sys/dshowsrcwrapper/gstdshowsrcwrapper.c @@ -0,0 +1,59 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowsrcwrapper.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstdshowaudiosrc.h" +#include "gstdshowvideosrc.h" + +const GUID CLSID_GstreamerSrcFilter + = + { 0x6a780808, 0x9725, 0x4d0b, {0x86, 0x95, 0xa4, 0xdd, 0x8d, 0x21, 0x7, + 0x73} }; + +const GUID IID_IGstSrcInterface = + { 0x542c0a24, 0x8bd1, 0x46cb, {0xaa, 0x57, 0x3e, 0x46, 0xd0, 0x6, 0xd2, + 0xf3} }; + + +static gboolean +plugin_init (GstPlugin * plugin) +{ + /* register fake filters */ + gst_dshow_register_fakefilters (); + + if (!gst_element_register (plugin, "dshowaudiosrc", + GST_RANK_NONE, + GST_TYPE_DSHOWAUDIOSRC) || + !gst_element_register (plugin, "dshowvideosrc", + GST_RANK_NONE, GST_TYPE_DSHOWVIDEOSRC)) + return FALSE; + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "dshowsrcwrapper", + "DirectShow sources wrapper plugin", + plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) diff --git a/sys/dshowsrcwrapper/gstdshowsrcwrapper.h b/sys/dshowsrcwrapper/gstdshowsrcwrapper.h new file mode 100644 index 00000000..d94d49f7 --- /dev/null +++ b/sys/dshowsrcwrapper/gstdshowsrcwrapper.h @@ -0,0 +1,34 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowsrcwrapper.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_DSHOW_H__ +#define __GST_DSHOW_H__ + +#include <windows.h> +#include <objbase.h> +#include <dshow.h> +#include <Rpc.h> + +#include <gst/dshow/gstdshowinterface.h> + +#pragma warning( disable : 4090 4024) + +#endif /* __GST_DSHOW_H__ */ diff --git a/sys/dshowsrcwrapper/gstdshowvideosrc.c b/sys/dshowsrcwrapper/gstdshowvideosrc.c new file mode 100644 index 00000000..38b779dd --- /dev/null +++ b/sys/dshowsrcwrapper/gstdshowvideosrc.c @@ -0,0 +1,996 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowvideosrc.c: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstdshowvideosrc.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +static const GstElementDetails gst_dshowvideosrc_details = +GST_ELEMENT_DETAILS ("DirectShow video capture source", + "Source/Video", + "Receive data from a directshow video capture graph", + "Sebastien Moutte <sebastien@moutte.net>"); + +GST_DEBUG_CATEGORY_STATIC (dshowvideosrc_debug); +#define GST_CAT_DEFAULT dshowvideosrc_debug + +const GUID MEDIASUBTYPE_I420 + = + { 0x30323449, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, + 0x71} }; + +static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw-rgb," + "bpp = (int) 24," + "depth = (int) 24," + "width = (int) [ 1, MAX ]," + "height = (int) [ 1, MAX ]," + "framerate = (fraction) [ 0, MAX ];" + "video/x-dv," + "systemstream = (boolean) FALSE," + "width = (int) [ 1, MAX ]," + "height = (int) [ 1, MAX ]," + "framerate = (fraction) [ 0, MAX ]," + "format = (fourcc) dvsd;" + "video/x-dv," + "systemstream = (boolean) TRUE;" + "video/x-raw-yuv," + "width = (int) [ 1, MAX ]," + "height = (int) [ 1, MAX ]," + "framerate = (fraction) [ 0, MAX ]," "format = (fourcc) I420") + ); + +static void gst_dshowvideosrc_init_interfaces (GType type); + +GST_BOILERPLATE_FULL (GstDshowVideoSrc, gst_dshowvideosrc, GstPushSrc, + GST_TYPE_PUSH_SRC, gst_dshowvideosrc_init_interfaces); + +enum +{ + PROP_0, + PROP_DEVICE, + PROP_DEVICE_NAME +}; + +static void gst_dshowvideosrc_probe_interface_init (GstPropertyProbeInterface * + iface); +static const GList *gst_dshowvideosrc_probe_get_properties (GstPropertyProbe * + probe); +static GValueArray *gst_dshowvideosrc_probe_get_values (GstPropertyProbe * + probe, guint prop_id, const GParamSpec * pspec); +static GValueArray *gst_dshowvideosrc_get_device_name_values (GstDshowVideoSrc * + src); +static gboolean gst_dshowvideosrc_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec); +static void gst_dshowvideosrc_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec); + + +static void gst_dshowvideosrc_dispose (GObject * gobject); +static void gst_dshowvideosrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_dshowvideosrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static GstCaps *gst_dshowvideosrc_get_caps (GstBaseSrc * src); +static GstStateChangeReturn gst_dshowvideosrc_change_state (GstElement * + element, GstStateChange transition); + + +static gboolean gst_dshowvideosrc_start (GstBaseSrc * bsrc); +static gboolean gst_dshowvideosrc_stop (GstBaseSrc * bsrc); +static gboolean gst_dshowvideosrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps); +static GstCaps *gst_dshowvideosrc_get_caps (GstBaseSrc * bsrc); +static GstFlowReturn gst_dshowvideosrc_create (GstPushSrc * psrc, + GstBuffer ** buf); + +/*utils*/ +static GstCaps *gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * + src, IPin * pin, IAMStreamConfig * streamcaps); +static gboolean gst_dshowvideosrc_push_buffer (byte * buffer, long size, + byte * src_object, UINT64 start, UINT64 stop); + +static void +gst_dshowvideosrc_init_interfaces (GType type) +{ + static const GInterfaceInfo dshowvideosrc_info = { + (GInterfaceInitFunc) gst_dshowvideosrc_probe_interface_init, + NULL, + NULL, + }; + + g_type_add_interface_static (type, + GST_TYPE_PROPERTY_PROBE, &dshowvideosrc_info); +} + +static void +gst_dshowvideosrc_probe_interface_init (GstPropertyProbeInterface * iface) +{ + iface->get_properties = gst_dshowvideosrc_probe_get_properties; + iface->needs_probe = gst_dshowvideosrc_probe_needs_probe; + iface->probe_property = gst_dshowvideosrc_probe_probe_property; + iface->get_values = gst_dshowvideosrc_probe_get_values; +} + +static void +gst_dshowvideosrc_base_init (gpointer klass) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (klass); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&src_template)); + + gst_element_class_set_details (element_class, &gst_dshowvideosrc_details); +} + +static void +gst_dshowvideosrc_class_init (GstDshowVideoSrcClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSrcClass *gstbasesrc_class; + GstPushSrcClass *gstpushsrc_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesrc_class = (GstBaseSrcClass *) klass; + gstpushsrc_class = (GstPushSrcClass *) klass; + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_dispose); + gobject_class->set_property = + GST_DEBUG_FUNCPTR (gst_dshowvideosrc_set_property); + gobject_class->get_property = + GST_DEBUG_FUNCPTR (gst_dshowvideosrc_get_property); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_dshowvideosrc_change_state); + + gstbasesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_get_caps); + gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_set_caps); + gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_start); + gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_stop); + + gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_dshowvideosrc_create); + + g_object_class_install_property + (gobject_class, PROP_DEVICE, + g_param_spec_string ("device", "Device", + "Directshow device path (@..classID/name)", NULL, G_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_DEVICE_NAME, + g_param_spec_string ("device_name", "Device name", + "Human-readable name of the sound device", NULL, G_PARAM_READWRITE)); + + GST_DEBUG_CATEGORY_INIT (dshowvideosrc_debug, "dshowvideosrc", 0, + "Directshow video source"); + +} + +static void +gst_dshowvideosrc_init (GstDshowVideoSrc * src, GstDshowVideoSrcClass * klass) +{ + src->device = NULL; + src->device_name = NULL; + src->video_cap_filter = NULL; + src->dshow_fakesink = NULL; + src->media_filter = NULL; + src->filter_graph = NULL; + src->caps = NULL; + src->pins_mediatypes = NULL; + src->is_rgb = FALSE; + + src->async_queue = g_async_queue_new (); + + CoInitializeEx (NULL, COINIT_MULTITHREADED); + + gst_base_src_set_live (GST_BASE_SRC (src), TRUE); +} + +static void +gst_dshowvideosrc_dispose (GObject * gobject) +{ + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (gobject); + + if (src->device) { + g_free (src->device); + src->device = NULL; + } + + if (src->device_name) { + g_free (src->device_name); + src->device_name = NULL; + } + + if (src->caps) { + gst_caps_unref (src->caps); + src->caps = NULL; + } + + if (src->pins_mediatypes) { + gst_dshow_free_pins_mediatypes (src->pins_mediatypes); + src->pins_mediatypes = NULL; + } + + /* clean dshow */ + if (src->video_cap_filter) { + IBaseFilter_Release (src->video_cap_filter); + src->video_cap_filter = NULL; + } + + if (src->async_queue) { + g_async_queue_unref (src->async_queue); + src->async_queue = NULL; + } + + CoUninitialize (); +} + +static gboolean +gst_dshowvideosrc_probe_needs_probe (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + static gboolean init = FALSE; + gboolean ret = FALSE; + + if (!init) { + ret = TRUE; + init = TRUE; + } + + return ret; +} + +static void +gst_dshowvideosrc_probe_probe_property (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + + switch (prop_id) { + case PROP_DEVICE_NAME: + //gst_v4l_class_probe_devices (klass, FALSE); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } +} + +static const GList * +gst_dshowvideosrc_probe_get_properties (GstPropertyProbe * probe) +{ + GObjectClass *klass = G_OBJECT_GET_CLASS (probe); + static GList *props = NULL; + + if (!props) { + GParamSpec *pspec; + + pspec = g_object_class_find_property (klass, "device_name"); + props = g_list_append (props, pspec); + } + + return props; +} + +static GValueArray * +gst_dshowvideosrc_get_device_name_values (GstDshowVideoSrc * src) +{ + GValueArray *array = g_value_array_new (0); + GValue value = { 0 }; + ICreateDevEnum *devices_enum = NULL; + IEnumMoniker *moniker_enum = NULL; + IMoniker *moniker = NULL; + HRESULT hres = S_FALSE; + ULONG fetched; + + g_value_init (&value, G_TYPE_STRING); + + hres = CoCreateInstance (&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, + &IID_ICreateDevEnum, (void **) &devices_enum); + if (hres != S_OK) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't create an instance of the system device enumerator (error=%d)", + hres); + array = NULL; + goto clean; + } + + hres = + ICreateDevEnum_CreateClassEnumerator (devices_enum, + &CLSID_VideoInputDeviceCategory, &moniker_enum, 0); + if (hres != S_OK || !moniker_enum) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't get enumeration of video devices (error=%d)", hres); + array = NULL; + goto clean; + } + + IEnumMoniker_Reset (moniker_enum); + + while (hres = IEnumMoniker_Next (moniker_enum, 1, &moniker, &fetched), + hres == S_OK) { + IPropertyBag *property_bag = NULL; + + hres = + IMoniker_BindToStorage (moniker, NULL, NULL, &IID_IPropertyBag, + (void **) &property_bag); + if (SUCCEEDED (hres) && property_bag) { + VARIANT varFriendlyName; + + VariantInit (&varFriendlyName); + hres = + IPropertyBag_Read (property_bag, L"FriendlyName", &varFriendlyName, + NULL); + if (hres == S_OK && varFriendlyName.bstrVal) { + gchar *friendly_name = + g_utf16_to_utf8 ((const gunichar2 *) varFriendlyName.bstrVal, + wcslen (varFriendlyName.bstrVal), NULL, NULL, NULL); + + g_value_set_string (&value, friendly_name); + g_value_array_append (array, &value); + g_value_unset (&value); + g_free (friendly_name); + SysFreeString (varFriendlyName.bstrVal); + } + IPropertyBag_Release (property_bag); + } + IMoniker_Release (moniker); + } + +clean: + if (moniker_enum) { + IEnumMoniker_Release (moniker_enum); + } + + if (devices_enum) { + ICreateDevEnum_Release (devices_enum); + } + + return array; +} + +static GValueArray * +gst_dshowvideosrc_probe_get_values (GstPropertyProbe * probe, + guint prop_id, const GParamSpec * pspec) +{ + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (probe); + GValueArray *array = NULL; + + switch (prop_id) { + case PROP_DEVICE_NAME: + array = gst_dshowvideosrc_get_device_name_values (src); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (probe, prop_id, pspec); + break; + } + + return array; +} + +static void +gst_dshowvideosrc_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (object); + + switch (prop_id) { + case PROP_DEVICE: + { + if (src->device) { + g_free (src->device); + src->device = NULL; + } + if (g_value_get_string (value)) { + src->device = g_strdup (g_value_get_string (value)); + } + break; + } + case PROP_DEVICE_NAME: + { + if (src->device_name) { + g_free (src->device_name); + src->device_name = NULL; + } + if (g_value_get_string (value)) { + src->device_name = g_strdup (g_value_get_string (value)); + } + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_dshowvideosrc_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + +} + +static GstCaps * +gst_dshowvideosrc_get_caps (GstBaseSrc * basesrc) +{ + HRESULT hres = S_OK; + IBindCtx *lpbc = NULL; + IMoniker *videom; + DWORD dwEaten; + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (basesrc); + gunichar2 *unidevice = NULL; + + if (src->device) { + g_free (src->device); + src->device = NULL; + } + + src->device = + gst_dshow_getdevice_from_devicename (&CLSID_VideoInputDeviceCategory, + &src->device_name); + if (!src->device) { + GST_CAT_ERROR (dshowvideosrc_debug, "No video device found."); + return NULL; + } + unidevice = + g_utf8_to_utf16 (src->device, strlen (src->device), NULL, NULL, NULL); + + if (!src->video_cap_filter) { + hres = CreateBindCtx (0, &lpbc); + if (SUCCEEDED (hres)) { + hres = MkParseDisplayName (lpbc, unidevice, &dwEaten, &videom); + if (SUCCEEDED (hres)) { + hres = + IMoniker_BindToObject (videom, lpbc, NULL, &IID_IBaseFilter, + &src->video_cap_filter); + IMoniker_Release (videom); + } + IBindCtx_Release (lpbc); + } + } + + if (src->video_cap_filter && !src->caps) { + /* get the capture pins supported types */ + IPin *capture_pin = NULL; + IEnumPins *enumpins = NULL; + HRESULT hres; + + hres = IBaseFilter_EnumPins (src->video_cap_filter, &enumpins); + if (SUCCEEDED (hres)) { + while (IEnumPins_Next (enumpins, 1, &capture_pin, NULL) == S_OK) { + IKsPropertySet *pKs = NULL; + + hres = + IPin_QueryInterface (capture_pin, &IID_IKsPropertySet, + (void **) &pKs); + if (SUCCEEDED (hres) && pKs) { + DWORD cbReturned; + GUID pin_category; + RPC_STATUS rpcstatus; + + hres = + IKsPropertySet_Get (pKs, &ROPSETID_Pin, + AMPROPERTY_PIN_CATEGORY, NULL, 0, &pin_category, sizeof (GUID), + &cbReturned); + + /* we only want capture pins */ + if (UuidCompare (&pin_category, &PIN_CATEGORY_CAPTURE, + &rpcstatus) == 0) { + IAMStreamConfig *streamcaps = NULL; + + if (SUCCEEDED (IPin_QueryInterface (capture_pin, + &IID_IAMStreamConfig, (void **) &streamcaps))) { + src->caps = + gst_dshowvideosrc_getcaps_from_streamcaps (src, capture_pin, + streamcaps); + IAMStreamConfig_Release (streamcaps); + + GST_CAT_LOG (dshowvideosrc_debug, + "get_cap returned %" GST_PTR_FORMAT, src->caps); + } + } + + IKsPropertySet_Release (pKs); + } + + IPin_Release (capture_pin); + } + IEnumPins_Release (enumpins); + } + } + + if (unidevice) { + g_free (unidevice); + } + + if (src->caps) { + return gst_caps_ref (src->caps); + } + + return NULL; +} + +static GstStateChangeReturn +gst_dshowvideosrc_change_state (GstElement * element, GstStateChange transition) +{ + HRESULT hres = S_FALSE; + IAMVfwCaptureDialogs *dialog = NULL; + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (element); + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + if (src->media_filter) + hres = IMediaFilter_Run (src->media_filter, 0); + if (hres != S_OK) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't RUN the directshow capture graph (error=%d)", hres); + return GST_STATE_CHANGE_FAILURE; + } + break; + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + if (src->media_filter) + hres = IMediaFilter_Stop (src->media_filter); + if (hres != S_OK) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't STOP the directshow capture graph (error=%d)", hres); + return GST_STATE_CHANGE_FAILURE; + } + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + break; + case GST_STATE_CHANGE_READY_TO_NULL: + break; + } + + return GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); +} + +static gboolean +gst_dshowvideosrc_start (GstBaseSrc * bsrc) +{ + HRESULT hres = S_FALSE; + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (bsrc); + + hres = CoCreateInstance (&CLSID_FilterGraph, NULL, CLSCTX_INPROC, + &IID_IFilterGraph, (LPVOID *) & src->filter_graph); + if (hres != S_OK || !src->filter_graph) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't create an instance of the dshow graph manager (error=%d)", hres); + goto error; + } + + hres = IFilterGraph_QueryInterface (src->filter_graph, &IID_IMediaFilter, + (void **) &src->media_filter); + if (hres != S_OK || !src->media_filter) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't get IMediacontrol interface from the graph manager (error=%d)", + hres); + goto error; + } + + hres = CoCreateInstance (&CLSID_DshowFakeSink, NULL, CLSCTX_INPROC, + &IID_IBaseFilter, (LPVOID *) & src->dshow_fakesink); + if (hres != S_OK || !src->dshow_fakesink) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't create an instance of our dshow fakesink filter (error=%d)", + hres); + goto error; + } + + hres = + IFilterGraph_AddFilter (src->filter_graph, src->video_cap_filter, + L"capture"); + if (hres != S_OK) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't add video capture filter to the graph (error=%d)", hres); + goto error; + } + + hres = + IFilterGraph_AddFilter (src->filter_graph, src->dshow_fakesink, L"sink"); + if (hres != S_OK) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't add our fakesink filter to the graph (error=%d)", hres); + goto error; + } + + return TRUE; + +error: + if (src->dshow_fakesink) { + IBaseFilter_Release (src->dshow_fakesink); + src->dshow_fakesink = NULL; + } + + if (src->media_filter) { + IMediaFilter_Release (src->media_filter); + src->media_filter = NULL; + } + if (src->filter_graph) { + IFilterGraph_Release (src->filter_graph); + src->filter_graph = NULL; + } + + return FALSE; +} + +static gboolean +gst_dshowvideosrc_set_caps (GstBaseSrc * bsrc, GstCaps * caps) +{ + HRESULT hres; + IGstDshowInterface *srcinterface = NULL; + IPin *input_pin = NULL; + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (bsrc); + GstStructure *s = gst_caps_get_structure (caps, 0); + + /* search the negociated caps in our caps list to get its index and the corresponding mediatype */ + if (gst_caps_is_subset (caps, src->caps)) { + guint i = 0; + gint res = -1; + + for (; i < gst_caps_get_size (src->caps) && res == -1; i++) { + GstCaps *capstmp = gst_caps_copy_nth (src->caps, i); + + if (gst_caps_is_subset (caps, capstmp)) { + res = i; + } + gst_caps_unref (capstmp); + } + + if (res != -1 && src->pins_mediatypes) { + /* get the corresponding media type and build the dshow graph */ + GstCapturePinMediaType *pin_mediatype = NULL; + gchar *caps_string = NULL; + GList *type = g_list_nth (src->pins_mediatypes, res); + + if (type) { + pin_mediatype = (GstCapturePinMediaType *) type->data; + + hres = + IBaseFilter_QueryInterface (src->dshow_fakesink, + &IID_IGstDshowInterface, (void **) &srcinterface); + + if (hres != S_OK || !srcinterface) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't get IGstDshowInterface interface from our dshow fakesink filter (error=%d)", + hres); + goto error; + } + + IGstDshowInterface_gst_set_media_type (srcinterface, + pin_mediatype->mediatype); + IGstDshowInterface_gst_set_buffer_callback (srcinterface, + gst_dshowvideosrc_push_buffer, (byte *) src); + + if (srcinterface) { + IGstDshowInterface_Release (srcinterface); + } + + gst_dshow_get_pin_from_filter (src->dshow_fakesink, PINDIR_INPUT, + &input_pin); + if (!input_pin) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't get input pin from our dshow fakesink"); + goto error; + } + + hres = + IFilterGraph_ConnectDirect (src->filter_graph, + pin_mediatype->capture_pin, input_pin, NULL); + IPin_Release (input_pin); + + if (hres != S_OK) { + GST_CAT_ERROR (dshowvideosrc_debug, + "Can't connect capture filter with fakesink filter (error=%d)", + hres); + goto error; + } + + /* save width and height negociated */ + gst_structure_get_int (s, "width", &src->width); + gst_structure_get_int (s, "height", &src->height); + + src->is_rgb = FALSE; + caps_string = gst_caps_to_string (caps); + if (caps_string) { + if (strstr (caps_string, "video/x-raw-rgb")) { + src->is_rgb = TRUE; + } else { + src->is_rgb = FALSE; + } + g_free (caps_string); + } + } + } + } + + return TRUE; + +error: + if (srcinterface) { + IGstDshowInterface_Release (srcinterface); + } + + return FALSE; +} + +static gboolean +gst_dshowvideosrc_stop (GstBaseSrc * bsrc) +{ + IPin *input_pin = NULL, *output_pin = NULL; + HRESULT hres = S_FALSE; + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (bsrc); + + if (!src->filter_graph) + return TRUE; + + /* disconnect filters */ + gst_dshow_get_pin_from_filter (src->video_cap_filter, PINDIR_OUTPUT, + &output_pin); + if (output_pin) { + hres = IFilterGraph_Disconnect (src->filter_graph, output_pin); + IPin_Release (output_pin); + } + + gst_dshow_get_pin_from_filter (src->dshow_fakesink, PINDIR_INPUT, &input_pin); + if (input_pin) { + hres = IFilterGraph_Disconnect (src->filter_graph, input_pin); + IPin_Release (input_pin); + } + + /*remove filters from the graph */ + IFilterGraph_RemoveFilter (src->filter_graph, src->video_cap_filter); + IFilterGraph_RemoveFilter (src->filter_graph, src->dshow_fakesink); + + /*release our gstreamer dshow sink */ + IBaseFilter_Release (src->dshow_fakesink); + src->dshow_fakesink = NULL; + + /*release media filter interface */ + IMediaFilter_Release (src->media_filter); + src->media_filter = NULL; + + /*release the filter graph manager */ + IFilterGraph_Release (src->filter_graph); + src->filter_graph = NULL; + + return TRUE; +} + +static GstFlowReturn +gst_dshowvideosrc_create (GstPushSrc * psrc, GstBuffer ** buf) +{ + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (psrc); + + *buf = g_async_queue_pop (src->async_queue); + + GST_CAT_DEBUG (dshowvideosrc_debug, + "dshowvideosrc_create => pts %" GST_TIME_FORMAT " duration %" + GST_TIME_FORMAT, GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (*buf)), + GST_TIME_ARGS (GST_BUFFER_DURATION (*buf))); + + return GST_FLOW_OK; +} + +static GstCaps * +gst_dshowvideosrc_getcaps_from_streamcaps (GstDshowVideoSrc * src, IPin * pin, + IAMStreamConfig * streamcaps) +{ + GstCaps *caps = NULL; + HRESULT hres = S_OK; + RPC_STATUS rpcstatus; + int icount = 0; + int isize = 0; + VIDEO_STREAM_CONFIG_CAPS vscc; + int i = 0; + + if (!streamcaps) + return NULL; + + IAMStreamConfig_GetNumberOfCapabilities (streamcaps, &icount, &isize); + + if (isize != sizeof (vscc)) + return NULL; + + for (; i < icount; i++) { + GstCapturePinMediaType *pin_mediatype = g_new0 (GstCapturePinMediaType, 1); + + IPin_AddRef (pin); + pin_mediatype->capture_pin = pin; + + hres = + IAMStreamConfig_GetStreamCaps (streamcaps, i, &pin_mediatype->mediatype, + (BYTE *) & vscc); + if (hres == S_OK && pin_mediatype->mediatype) { + VIDEOINFOHEADER *video_info; + GstCaps *mediacaps = NULL; + + if (!caps) + caps = gst_caps_new_empty (); + + /* I420 */ + if ((UuidCompare (&pin_mediatype->mediatype->subtype, &MEDIASUBTYPE_I420, + &rpcstatus) == 0 && rpcstatus == RPC_S_OK) + && (UuidCompare (&pin_mediatype->mediatype->formattype, + &FORMAT_VideoInfo, &rpcstatus) == 0 + && rpcstatus == RPC_S_OK)) { + video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat; + + mediacaps = gst_caps_new_simple ("video/x-raw-yuv", + "width", G_TYPE_INT, video_info->bmiHeader.biWidth, + "height", G_TYPE_INT, video_info->bmiHeader.biHeight, + "framerate", GST_TYPE_FRACTION, + (int) (10000000 / video_info->AvgTimePerFrame), 1, "format", + GST_TYPE_FOURCC, MAKEFOURCC ('I', '4', '2', '0'), NULL); + + if (mediacaps) { + src->pins_mediatypes = + g_list_append (src->pins_mediatypes, pin_mediatype); + gst_caps_append (caps, mediacaps); + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + continue; + } + + /* RGB24 */ + if ((UuidCompare (&pin_mediatype->mediatype->subtype, &MEDIASUBTYPE_RGB24, + &rpcstatus) == 0 && rpcstatus == RPC_S_OK) + && (UuidCompare (&pin_mediatype->mediatype->formattype, + &FORMAT_VideoInfo, &rpcstatus) == 0 + && rpcstatus == RPC_S_OK)) { + video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat; + + /* ffmpegcolorspace handles RGB24 in BIG_ENDIAN */ + mediacaps = gst_caps_new_simple ("video/x-raw-rgb", + "bpp", G_TYPE_INT, 24, + "depth", G_TYPE_INT, 24, + "width", G_TYPE_INT, video_info->bmiHeader.biWidth, + "height", G_TYPE_INT, video_info->bmiHeader.biHeight, + "framerate", GST_TYPE_FRACTION, + (int) (10000000 / video_info->AvgTimePerFrame), 1, "endianness", + G_TYPE_INT, G_BIG_ENDIAN, "red_mask", G_TYPE_INT, 255, "green_mask", + G_TYPE_INT, 65280, "blue_mask", G_TYPE_INT, 16711680, NULL); + + if (mediacaps) { + src->pins_mediatypes = + g_list_append (src->pins_mediatypes, pin_mediatype); + gst_caps_append (caps, mediacaps); + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + continue; + } + + /* DVSD */ + if ((UuidCompare (&pin_mediatype->mediatype->subtype, &MEDIASUBTYPE_dvsd, + &rpcstatus) == 0 && rpcstatus == RPC_S_OK) + && (UuidCompare (&pin_mediatype->mediatype->formattype, + &FORMAT_VideoInfo, &rpcstatus) == 0 + && rpcstatus == RPC_S_OK)) { + video_info = (VIDEOINFOHEADER *) pin_mediatype->mediatype->pbFormat; + + mediacaps = gst_caps_new_simple ("video/x-dv", + "systemstream", G_TYPE_BOOLEAN, FALSE, + "format", GST_TYPE_FOURCC, GST_MAKE_FOURCC ('d', 'v', 's', 'd'), + "framerate", GST_TYPE_FRACTION, + (int) (10000000 / video_info->AvgTimePerFrame), 1, "width", + G_TYPE_INT, video_info->bmiHeader.biWidth, "height", G_TYPE_INT, + video_info->bmiHeader.biHeight, NULL); + + if (mediacaps) { + src->pins_mediatypes = + g_list_append (src->pins_mediatypes, pin_mediatype); + gst_caps_append (caps, mediacaps); + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + continue; + } + + /* DV stream */ + if ((UuidCompare (&pin_mediatype->mediatype->subtype, &MEDIASUBTYPE_dvsd, + &rpcstatus) == 0 && rpcstatus == RPC_S_OK) + && (UuidCompare (&pin_mediatype->mediatype->formattype, + &FORMAT_DvInfo, &rpcstatus) == 0 && rpcstatus == RPC_S_OK)) { + + mediacaps = gst_caps_new_simple ("video/x-dv", + "systemstream", G_TYPE_BOOLEAN, TRUE, NULL); + + if (mediacaps) { + src->pins_mediatypes = + g_list_append (src->pins_mediatypes, pin_mediatype); + gst_caps_append (caps, mediacaps); + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + continue; + } + } else { + gst_dshow_free_pin_mediatype (pin_mediatype); + } + } + + if (caps && gst_caps_is_empty (caps)) { + gst_caps_unref (caps); + caps = NULL; + } + + return caps; +} + +static gboolean +gst_dshowvideosrc_push_buffer (byte * buffer, long size, byte * src_object, + UINT64 start, UINT64 stop) +{ + GstDshowVideoSrc *src = GST_DSHOWVIDEOSRC (src_object); + GstBuffer *buf; + IPin *pPin = NULL; + HRESULT hres = S_FALSE; + AM_MEDIA_TYPE *pMediaType = NULL; + + if (!buffer || size == 0 || !src) { + return FALSE; + } + + /* create a new buffer assign to it the clock time as timestamp */ + buf = gst_buffer_new_and_alloc (size); + + GST_BUFFER_SIZE (buf) = size; + GST_BUFFER_TIMESTAMP (buf) = gst_clock_get_time (GST_ELEMENT (src)->clock); + GST_BUFFER_TIMESTAMP (buf) -= GST_ELEMENT (src)->base_time; + GST_BUFFER_DURATION (buf) = stop - start; + + if (src->is_rgb) { + /* FOR RGB directshow decoder will return bottom-up BITMAP + * There is probably a way to get top-bottom video frames from + * the decoder... + */ + gint line = 0; + gint stride = size / src->height; + + for (; line < src->height; line++) { + memcpy (GST_BUFFER_DATA (buf) + (line * stride), + buffer + (size - ((line + 1) * (stride))), stride); + } + } else { + memcpy (GST_BUFFER_DATA (buf), buffer, size); + } + + GST_CAT_DEBUG (dshowvideosrc_debug, + "push_buffer => pts %" GST_TIME_FORMAT "duration %" GST_TIME_FORMAT, + GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buf)), GST_TIME_ARGS (stop - start)); + + /* the negotiate() method already set caps on the source pad */ + gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src))); + + g_async_queue_push (src->async_queue, buf); + + return TRUE; +} diff --git a/sys/dshowsrcwrapper/gstdshowvideosrc.h b/sys/dshowsrcwrapper/gstdshowvideosrc.h new file mode 100644 index 00000000..994326fd --- /dev/null +++ b/sys/dshowsrcwrapper/gstdshowvideosrc.h @@ -0,0 +1,85 @@ +/* GStreamer + * Copyright (C) 2007 Sebastien Moutte <sebastien@moutte.net> + * + * gstdshowvideosrc.h: + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_DSHOWVIDEOSRC_H__ +#define __GST_DSHOWVIDEOSRC_H__ + +#include <gst/gst.h> +#include <gst/base/gstpushsrc.h> +#include <gst/interfaces/propertyprobe.h> + +#include "gstdshowsrcwrapper.h" + +// 30323449-0000-0010-8000-00AA00389B71 MEDIASUBTYPE_I420 +DEFINE_GUID(MEDIASUBTYPE_I420, 0x30323449, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xAA, 0x00, 0x38, 0x9B, 0x71); + +G_BEGIN_DECLS +#define GST_TYPE_DSHOWVIDEOSRC (gst_dshowvideosrc_get_type()) +#define GST_DSHOWVIDEOSRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_DSHOWVIDEOSRC,GstDshowVideoSrc)) +#define GST_DSHOWVIDEOSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_DSHOWVIDEOSRC,GstDshowVideoSrcClass)) +#define GST_IS_DSHOWVIDEOSRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_DSHOWVIDEOSRC)) +#define GST_IS_DSHOWVIDEOSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_DSHOWVIDEOSRC)) +typedef struct _GstDshowVideoSrc GstDshowVideoSrc; +typedef struct _GstDshowVideoSrcClass GstDshowVideoSrcClass; + +struct _GstDshowVideoSrc +{ + GstPushSrc src; + + /* device dshow reference (generally classid/name) */ + gchar *device; + + /* device friendly name */ + gchar *device_name; + + /* list of caps created from the list of supported media types of the dshow capture filter */ + GstCaps *caps; + + /* list of dshow media types from the filter's capture pins */ + GList *pins_mediatypes; + + /* dshow video capture filter */ + IBaseFilter *video_cap_filter; + + /* dshow sink filter */ + IBaseFilter *dshow_fakesink; + + /* graph manager interfaces */ + IMediaFilter *media_filter; + IFilterGraph *filter_graph; + + /* async queue which will contain incoming buffers from directshow */ + GAsyncQueue *async_queue; + + gboolean is_rgb; + gint width; + gint height; +}; + +struct _GstDshowVideoSrcClass +{ + GstPushSrcClass parent_class; +}; + +GType gst_dshowvideosrc_get_type (void); + +G_END_DECLS +#endif /* __GST_DSHOWVIDEOSRC_H__ */ diff --git a/win32/common/libgstdshow.def b/win32/common/libgstdshow.def new file mode 100644 index 00000000..d5e6d57a --- /dev/null +++ b/win32/common/libgstdshow.def @@ -0,0 +1,15 @@ +EXPORTS + DllMain PRIVATE + DllGetClassObject PRIVATE + DllCanUnloadNow PRIVATE + DllRegisterServer PRIVATE + DllUnregisterServer PRIVATE + + gst_dshow_find_filter + gst_dshow_free_mediatype + gst_dshow_free_pin_mediatype + gst_dshow_free_pins_mediatypes + gst_dshow_get_pin_from_filter + gst_dshow_getdevice_from_devicename + gst_dshow_register_fakefilters + diff --git a/win32/vs6/gst_plugins_bad.dsw b/win32/vs6/gst_plugins_bad.dsw index 3f531578..c3278fed 100644 --- a/win32/vs6/gst_plugins_bad.dsw +++ b/win32/vs6/gst_plugins_bad.dsw @@ -39,6 +39,30 @@ Package=<4> ############################################################################### +Project: "libgstdshow"=".\libgstdshow.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "libgstdshowsrcwrapper"=".\libdshowsrcwrapper.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Project: "libgstmpegvideoparse"=".\libgstmpegvideoparse.dsp" - Package Owner=<4> Package=<5> diff --git a/win32/vs6/libdshowsrcwrapper.dsp b/win32/vs6/libdshowsrcwrapper.dsp new file mode 100644 index 00000000..38e1a45d --- /dev/null +++ b/win32/vs6/libdshowsrcwrapper.dsp @@ -0,0 +1,137 @@ +# Microsoft Developer Studio Project File - Name="libgstdshowsrcwrapper" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=libgstdshowsrcwrapper - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libdshowsrcwrapper.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libdshowsrcwrapper.mak" CFG="libgstdshowsrcwrapper - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libgstdshowsrcwrapper - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libgstdshowsrcwrapper - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libgstdshowsrcwrapper - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDSHOWSRCWRAPPER_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "../../gst-libs" /I "../../../gst-plugins-base/gst-libs" /I "../../../gstreamer/libs" /I "../common" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DSHOWSRCWRAPPER_EXPORTS" /D "HAVE_CONFIG_H" /D "COBJMACROS" /D "_WIN32_DCOM" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 libgstdshow-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib libgstaudio-0.10.lib libgstinterfaces-0.10.lib glib-2.0.lib gobject-2.0.lib ole32.lib oleaut32.lib Rpcrt4.lib Strmiids.lib user32.lib /nologo /dll /machine:I386 /out:"Release/libgstdshowsrcwrapper.dll" /libpath:"../../../dshowfakefilters/release" /libpath:"../gstreamer/win32/vs6/release" /libpath:"../gst-plugins-base/win32/vs6/release" /libpath:"./release" +# Begin Special Build Tool +TargetPath=.\Release\libgstdshowsrcwrapper.dll +SOURCE="$(InputPath)" +PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\lib\gstreamer-0.10 +# End Special Build Tool + +!ELSEIF "$(CFG)" == "libgstdshowsrcwrapper - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDSHOWSRCWRAPPER_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "../../gst-libs" /I "../../../gst-plugins-base/gst-libs" /I "../../../gstreamer/libs" /I "../common" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "DSHOWSRCWRAPPER_EXPORTS" /D "HAVE_CONFIG_H" /D "COBJMACROS" /D "_WIN32_DCOM" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libgstdshow-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib libgstaudio-0.10.lib libgstinterfaces-0.10.lib glib-2.0D.lib gobject-2.0D.lib ole32.lib oleaut32.lib Rpcrt4.lib user32.lib strmiids.lib /nologo /dll /debug /machine:I386 /out:"Debug/libgstdshowsrcwrapper.dll" /pdbtype:sept /libpath:"../gstreamer/win32/vs6/debug" /libpath:"../gst-plugins-base/win32/vs6/debug" /libpath:"./debug" +# Begin Special Build Tool +TargetPath=.\Debug\libgstdshowsrcwrapper.dll +SOURCE="$(InputPath)" +PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\debug\lib\gstreamer-0.10 +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "libgstdshowsrcwrapper - Win32 Release" +# Name "libgstdshowsrcwrapper - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\sys\dshowsrcwrapper\gstdshowaudiosrc.c +# End Source File +# Begin Source File + +SOURCE=..\..\sys\dshowsrcwrapper\gstdshowsrcwrapper.c +# End Source File +# Begin Source File + +SOURCE=..\..\sys\dshowsrcwrapper\gstdshowvideosrc.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=..\..\sys\dshowsrcwrapper\gstdshowaudiosrc.h +# End Source File +# Begin Source File + +SOURCE=..\..\sys\dshowsrcwrapper\gstdshowsrcwrapper.h +# End Source File +# Begin Source File + +SOURCE=..\..\sys\dshowsrcwrapper\gstdshowvideosrc.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/win32/vs6/libgstdirectsound.dsp b/win32/vs6/libgstdirectsound.dsp index e763d481..e6c37370 100644 --- a/win32/vs6/libgstdirectsound.dsp +++ b/win32/vs6/libgstdirectsound.dsp @@ -53,7 +53,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 -# ADD LINK32 glib-2.0.lib gobject-2.0.lib libgstaudio-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib dsound.lib dxerr9.lib user32.lib /nologo /dll /machine:I386 /libpath:"../../../gstreamer/win32/vs6/release" /libpath:"../../../gst-plugins-base/win32/vs6/release" /libpath:"./release" +# ADD LINK32 glib-2.0.lib gobject-2.0.lib libgstaudio-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib dsound.lib dxerr9.lib user32.lib /nologo /dll /machine:I386 /libpath:"../../../gstreamer/win32/vs6/release" /libpath:"../../../gst-plugins-base/win32/vs6/release" /libpath:"./release" # Begin Special Build Tool TargetPath=.\Release\libgstdirectsound.dll SOURCE="$(InputPath)" @@ -84,7 +84,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 glib-2.0D.lib gobject-2.0D.lib libgstaudio-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib dsound.lib dxerr9.lib user32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug" +# ADD LINK32 glib-2.0D.lib gobject-2.0D.lib libgstaudio-0.10.lib libgstreamer-0.10.lib libgstbase-0.10.lib libgstinterfaces-0.10.lib dsound.lib dxerr9.lib user32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept /libpath:"../../../gstreamer/win32/vs6/debug" /libpath:"../../../gst-plugins-base/win32/vs6/debug" /libpath:"./debug" # SUBTRACT LINK32 /incremental:no # Begin Special Build Tool TargetPath=.\Debug\libgstdirectsound.dll diff --git a/win32/vs6/libgstdshow.dsp b/win32/vs6/libgstdshow.dsp new file mode 100644 index 00000000..891e2c66 --- /dev/null +++ b/win32/vs6/libgstdshow.dsp @@ -0,0 +1,155 @@ +# Microsoft Developer Studio Project File - Name="libgstdshow" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=libgstdshow - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "libgstdshow.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "libgstdshow.mak" CFG="libgstdshow - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "libgstdshow - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "libgstdshow - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "libgstdshow - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDSHOW_EXPORTS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBDSHOW_EXPORTS" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "NDEBUG" +# ADD RSC /l 0x40c /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 libgstreamer-0.10.lib glib-2.0.lib strmbase.lib quartz.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib ole32.lib winmm.lib msacm32.lib olepro32.lib uuid.lib strmiids.lib advapi32.lib olepro32.lib /nologo /dll /machine:I386 /out:"Release/libgstdshow-0.10.dll" +# SUBTRACT LINK32 /nodefaultlib +# Begin Special Build Tool +TargetPath=.\Release\libgstdshow-0.10.dll +SOURCE="$(InputPath)" +PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\bin +# End Special Build Tool + +!ELSEIF "$(CFG)" == "libgstdshow - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBGSTDSHOW_EXPORTS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LIBDSHOW_EXPORTS" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x40c /d "_DEBUG" +# ADD RSC /l 0x40c /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 libgstreamer-0.10.lib glib-2.0D.lib strmbasd.lib quartz.lib kernel32.lib user32.lib gdi32.lib comdlg32.lib ole32.lib winmm.lib msacm32.lib olepro32.lib oleaut32.lib advapi32.lib uuid.lib strmiids.lib /nologo /dll /debug /machine:I386 /out:"Debug/libgstdshow-0.10.dll" /pdbtype:sept +# SUBTRACT LINK32 /nodefaultlib +# Begin Special Build Tool +TargetPath=.\Debug\libgstdshow-0.10.dll +SOURCE="$(InputPath)" +PostBuild_Cmds=copy /Y $(TargetPath) c:\gstreamer\debug\bin +# End Special Build Tool + +!ENDIF + +# Begin Target + +# Name "libgstdshow - Win32 Release" +# Name "libgstdshow - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshow.cpp" +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshowfakesink.cpp" +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshowfakesrc.cpp" +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshowinterface.cpp" +# SUBTRACT CPP /YX /Yc /Yu +# End Source File +# Begin Source File + +SOURCE=..\common\libgstdshow.def +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshow.h" +# End Source File +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshowfakesink.h" +# End Source File +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshowfakesrc.h" +# End Source File +# Begin Source File + +SOURCE="..\..\gst-libs\gst\dshow\gstdshowinterface.h" +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project |