dshow_pin.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /*
  2. * DirectShow capture interface
  3. * Copyright (c) 2010 Ramiro Polla
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #define NO_DSHOW_STRSAFE
  22. #include "dshow_capture.h"
  23. #include <stddef.h>
  24. #define imemoffset offsetof(libAVPin, imemvtbl)
  25. DECLARE_QUERYINTERFACE(libAVPin,
  26. { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
  27. DECLARE_ADDREF(libAVPin)
  28. DECLARE_RELEASE(libAVPin)
  29. long WINAPI
  30. libAVPin_Connect(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
  31. {
  32. dshowdebug("libAVPin_Connect(%p, %p, %p)\n", this, pin, type);
  33. /* Input pins receive connections. */
  34. return S_FALSE;
  35. }
  36. long WINAPI
  37. libAVPin_ReceiveConnection(libAVPin *this, IPin *pin,
  38. const AM_MEDIA_TYPE *type)
  39. {
  40. enum dshowDeviceType devtype = this->filter->type;
  41. dshowdebug("libAVPin_ReceiveConnection(%p)\n", this);
  42. if (!pin)
  43. return E_POINTER;
  44. if (this->connectedto)
  45. return VFW_E_ALREADY_CONNECTED;
  46. ff_print_AM_MEDIA_TYPE(type);
  47. if (devtype == VideoDevice) {
  48. if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
  49. return VFW_E_TYPE_NOT_ACCEPTED;
  50. } else {
  51. if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
  52. return VFW_E_TYPE_NOT_ACCEPTED;
  53. }
  54. IPin_AddRef(pin);
  55. this->connectedto = pin;
  56. ff_copy_dshow_media_type(&this->type, type);
  57. return S_OK;
  58. }
  59. long WINAPI
  60. libAVPin_Disconnect(libAVPin *this)
  61. {
  62. dshowdebug("libAVPin_Disconnect(%p)\n", this);
  63. if (this->filter->state != State_Stopped)
  64. return VFW_E_NOT_STOPPED;
  65. if (!this->connectedto)
  66. return S_FALSE;
  67. IPin_Release(this->connectedto);
  68. this->connectedto = NULL;
  69. return S_OK;
  70. }
  71. long WINAPI
  72. libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
  73. {
  74. dshowdebug("libAVPin_ConnectedTo(%p)\n", this);
  75. if (!pin)
  76. return E_POINTER;
  77. if (!this->connectedto)
  78. return VFW_E_NOT_CONNECTED;
  79. IPin_AddRef(this->connectedto);
  80. *pin = this->connectedto;
  81. return S_OK;
  82. }
  83. long WINAPI
  84. libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
  85. {
  86. dshowdebug("libAVPin_ConnectionMediaType(%p)\n", this);
  87. if (!type)
  88. return E_POINTER;
  89. if (!this->connectedto)
  90. return VFW_E_NOT_CONNECTED;
  91. return ff_copy_dshow_media_type(type, &this->type);
  92. }
  93. long WINAPI
  94. libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
  95. {
  96. dshowdebug("libAVPin_QueryPinInfo(%p)\n", this);
  97. if (!info)
  98. return E_POINTER;
  99. if (this->filter)
  100. libAVFilter_AddRef(this->filter);
  101. info->pFilter = (IBaseFilter *) this->filter;
  102. info->dir = PINDIR_INPUT;
  103. wcscpy(info->achName, L"Capture");
  104. return S_OK;
  105. }
  106. long WINAPI
  107. libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
  108. {
  109. dshowdebug("libAVPin_QueryDirection(%p)\n", this);
  110. if (!dir)
  111. return E_POINTER;
  112. *dir = PINDIR_INPUT;
  113. return S_OK;
  114. }
  115. long WINAPI
  116. libAVPin_QueryId(libAVPin *this, wchar_t **id)
  117. {
  118. dshowdebug("libAVPin_QueryId(%p)\n", this);
  119. if (!id)
  120. return E_POINTER;
  121. *id = wcsdup(L"libAV Pin");
  122. return S_OK;
  123. }
  124. long WINAPI
  125. libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
  126. {
  127. dshowdebug("libAVPin_QueryAccept(%p)\n", this);
  128. return S_FALSE;
  129. }
  130. long WINAPI
  131. libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
  132. {
  133. const AM_MEDIA_TYPE *type = NULL;
  134. libAVEnumMediaTypes *new;
  135. dshowdebug("libAVPin_EnumMediaTypes(%p)\n", this);
  136. if (!enumtypes)
  137. return E_POINTER;
  138. new = libAVEnumMediaTypes_Create(type);
  139. if (!new)
  140. return E_OUTOFMEMORY;
  141. *enumtypes = (IEnumMediaTypes *) new;
  142. return S_OK;
  143. }
  144. long WINAPI
  145. libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin,
  146. unsigned long *npin)
  147. {
  148. dshowdebug("libAVPin_QueryInternalConnections(%p)\n", this);
  149. return E_NOTIMPL;
  150. }
  151. long WINAPI
  152. libAVPin_EndOfStream(libAVPin *this)
  153. {
  154. dshowdebug("libAVPin_EndOfStream(%p)\n", this);
  155. /* I don't care. */
  156. return S_OK;
  157. }
  158. long WINAPI
  159. libAVPin_BeginFlush(libAVPin *this)
  160. {
  161. dshowdebug("libAVPin_BeginFlush(%p)\n", this);
  162. /* I don't care. */
  163. return S_OK;
  164. }
  165. long WINAPI
  166. libAVPin_EndFlush(libAVPin *this)
  167. {
  168. dshowdebug("libAVPin_EndFlush(%p)\n", this);
  169. /* I don't care. */
  170. return S_OK;
  171. }
  172. long WINAPI
  173. libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
  174. double rate)
  175. {
  176. dshowdebug("libAVPin_NewSegment(%p)\n", this);
  177. /* I don't care. */
  178. return S_OK;
  179. }
  180. static int
  181. libAVPin_Setup(libAVPin *this, libAVFilter *filter)
  182. {
  183. IPinVtbl *vtbl = this->vtbl;
  184. IMemInputPinVtbl *imemvtbl;
  185. if (!filter)
  186. return 0;
  187. imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
  188. if (!imemvtbl)
  189. return 0;
  190. SETVTBL(imemvtbl, libAVMemInputPin, QueryInterface);
  191. SETVTBL(imemvtbl, libAVMemInputPin, AddRef);
  192. SETVTBL(imemvtbl, libAVMemInputPin, Release);
  193. SETVTBL(imemvtbl, libAVMemInputPin, GetAllocator);
  194. SETVTBL(imemvtbl, libAVMemInputPin, NotifyAllocator);
  195. SETVTBL(imemvtbl, libAVMemInputPin, GetAllocatorRequirements);
  196. SETVTBL(imemvtbl, libAVMemInputPin, Receive);
  197. SETVTBL(imemvtbl, libAVMemInputPin, ReceiveMultiple);
  198. SETVTBL(imemvtbl, libAVMemInputPin, ReceiveCanBlock);
  199. this->imemvtbl = imemvtbl;
  200. SETVTBL(vtbl, libAVPin, QueryInterface);
  201. SETVTBL(vtbl, libAVPin, AddRef);
  202. SETVTBL(vtbl, libAVPin, Release);
  203. SETVTBL(vtbl, libAVPin, Connect);
  204. SETVTBL(vtbl, libAVPin, ReceiveConnection);
  205. SETVTBL(vtbl, libAVPin, Disconnect);
  206. SETVTBL(vtbl, libAVPin, ConnectedTo);
  207. SETVTBL(vtbl, libAVPin, ConnectionMediaType);
  208. SETVTBL(vtbl, libAVPin, QueryPinInfo);
  209. SETVTBL(vtbl, libAVPin, QueryDirection);
  210. SETVTBL(vtbl, libAVPin, QueryId);
  211. SETVTBL(vtbl, libAVPin, QueryAccept);
  212. SETVTBL(vtbl, libAVPin, EnumMediaTypes);
  213. SETVTBL(vtbl, libAVPin, QueryInternalConnections);
  214. SETVTBL(vtbl, libAVPin, EndOfStream);
  215. SETVTBL(vtbl, libAVPin, BeginFlush);
  216. SETVTBL(vtbl, libAVPin, EndFlush);
  217. SETVTBL(vtbl, libAVPin, NewSegment);
  218. this->filter = filter;
  219. return 1;
  220. }
  221. DECLARE_CREATE(libAVPin, libAVPin_Setup(this, filter), libAVFilter *filter)
  222. DECLARE_DESTROY(libAVPin, nothing)
  223. /*****************************************************************************
  224. * libAVMemInputPin
  225. ****************************************************************************/
  226. long WINAPI
  227. libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid,
  228. void **ppvObject)
  229. {
  230. libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
  231. dshowdebug("libAVMemInputPin_QueryInterface(%p)\n", this);
  232. return libAVPin_QueryInterface(pin, riid, ppvObject);
  233. }
  234. unsigned long WINAPI
  235. libAVMemInputPin_AddRef(libAVMemInputPin *this)
  236. {
  237. libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
  238. dshowdebug("libAVMemInputPin_AddRef(%p)\n", this);
  239. return libAVPin_AddRef(pin);
  240. }
  241. unsigned long WINAPI
  242. libAVMemInputPin_Release(libAVMemInputPin *this)
  243. {
  244. libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
  245. dshowdebug("libAVMemInputPin_Release(%p)\n", this);
  246. return libAVPin_Release(pin);
  247. }
  248. long WINAPI
  249. libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
  250. {
  251. dshowdebug("libAVMemInputPin_GetAllocator(%p)\n", this);
  252. return VFW_E_NO_ALLOCATOR;
  253. }
  254. long WINAPI
  255. libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc,
  256. WINBOOL rdwr)
  257. {
  258. dshowdebug("libAVMemInputPin_NotifyAllocator(%p)\n", this);
  259. return S_OK;
  260. }
  261. long WINAPI
  262. libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this,
  263. ALLOCATOR_PROPERTIES *props)
  264. {
  265. dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this);
  266. return E_NOTIMPL;
  267. }
  268. long WINAPI
  269. libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
  270. {
  271. libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
  272. enum dshowDeviceType devtype = pin->filter->type;
  273. void *priv_data;
  274. uint8_t *buf;
  275. int buf_size;
  276. int index;
  277. int64_t curtime;
  278. dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
  279. if (!sample)
  280. return E_POINTER;
  281. if (devtype == VideoDevice) {
  282. /* PTS from video devices is unreliable. */
  283. IReferenceClock *clock = pin->filter->clock;
  284. IReferenceClock_GetTime(clock, &curtime);
  285. } else {
  286. int64_t dummy;
  287. IMediaSample_GetTime(sample, &curtime, &dummy);
  288. curtime += pin->filter->start_time;
  289. }
  290. buf_size = IMediaSample_GetActualDataLength(sample);
  291. IMediaSample_GetPointer(sample, &buf);
  292. priv_data = pin->filter->priv_data;
  293. index = pin->filter->stream_index;
  294. pin->filter->callback(priv_data, index, buf, buf_size, curtime);
  295. return S_OK;
  296. }
  297. long WINAPI
  298. libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this,
  299. IMediaSample **samples, long n, long *nproc)
  300. {
  301. int i;
  302. dshowdebug("libAVMemInputPin_ReceiveMultiple(%p)\n", this);
  303. for (i = 0; i < n; i++)
  304. libAVMemInputPin_Receive(this, samples[i]);
  305. *nproc = n;
  306. return S_OK;
  307. }
  308. long WINAPI
  309. libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
  310. {
  311. dshowdebug("libAVMemInputPin_ReceiveCanBlock(%p)\n", this);
  312. /* I swear I will not block. */
  313. return S_FALSE;
  314. }
  315. void
  316. libAVMemInputPin_Destroy(libAVMemInputPin *this)
  317. {
  318. libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
  319. dshowdebug("libAVMemInputPin_Destroy(%p)\n", this);
  320. return libAVPin_Destroy(pin);
  321. }