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
22#ifndef AVDEVICE_DSHOW_H
23#define AVDEVICE_DSHOW_H
24
25#define DSHOWDEBUG 0
26
27#include "avdevice.h"
28
29#define COBJMACROS
30#include <windows.h>
31#define NO_DSHOW_STRSAFE
32#include <dshow.h>
33#include <dvdmedia.h>
34
35/* EC_DEVICE_LOST is not defined in MinGW dshow headers. */
36#ifndef EC_DEVICE_LOST
37#define EC_DEVICE_LOST 0x1f
38#endif
39
40long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
41void ff_print_VIDEO_STREAM_CONFIG_CAPS(const VIDEO_STREAM_CONFIG_CAPS *caps);
42void ff_print_AUDIO_STREAM_CONFIG_CAPS(const AUDIO_STREAM_CONFIG_CAPS *caps);
43void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type);
44void ff_printGUID(const GUID *g);
45
46#if DSHOWDEBUG
47extern const AVClass *ff_dshow_context_class_ptr;
48#define dshowdebug(...) av_log(&ff_dshow_context_class_ptr, AV_LOG_DEBUG, __VA_ARGS__)
49#else
50#define dshowdebug(...)
51#endif
52
53static inline void nothing(void *foo)
54{
55}
56
57struct GUIDoffset {
58    const GUID *iid;
59    int offset;
60};
61
62enum dshowDeviceType {
63    VideoDevice = 0,
64    AudioDevice = 1,
65};
66
67#define DECLARE_QUERYINTERFACE(class, ...)                                   \
68long WINAPI                                                                  \
69class##_QueryInterface(class *this, const GUID *riid, void **ppvObject)      \
70{                                                                            \
71    struct GUIDoffset ifaces[] = __VA_ARGS__;                                \
72    int i;                                                                   \
73    dshowdebug(AV_STRINGIFY(class)"_QueryInterface(%p, %p, %p)\n", this, riid, ppvObject); \
74    ff_printGUID(riid);                                                      \
75    if (!ppvObject)                                                          \
76        return E_POINTER;                                                    \
77    for (i = 0; i < sizeof(ifaces)/sizeof(ifaces[0]); i++) {                 \
78        if (IsEqualGUID(riid, ifaces[i].iid)) {                              \
79            void *obj = (void *) ((uint8_t *) this + ifaces[i].offset);      \
80            class##_AddRef(this);                                            \
81            dshowdebug("\tfound %d with offset %d\n", i, ifaces[i].offset);  \
82            *ppvObject = (void *) obj;                                       \
83            return S_OK;                                                     \
84        }                                                                    \
85    }                                                                        \
86    dshowdebug("\tE_NOINTERFACE\n");                                         \
87    *ppvObject = NULL;                                                       \
88    return E_NOINTERFACE;                                                    \
89}
90#define DECLARE_ADDREF(class)                                                \
91unsigned long WINAPI                                                         \
92class##_AddRef(class *this)                                                  \
93{                                                                            \
94    dshowdebug(AV_STRINGIFY(class)"_AddRef(%p)\t%ld\n", this, this->ref+1);  \
95    return InterlockedIncrement(&this->ref);                                 \
96}
97#define DECLARE_RELEASE(class)                                               \
98unsigned long WINAPI                                                         \
99class##_Release(class *this)                                                 \
100{                                                                            \
101    long ref = InterlockedDecrement(&this->ref);                             \
102    dshowdebug(AV_STRINGIFY(class)"_Release(%p)\t%ld\n", this, ref);         \
103    if (!ref)                                                                \
104        class##_Destroy(this);                                               \
105    return ref;                                                              \
106}
107
108#define DECLARE_DESTROY(class, func)                                         \
109void class##_Destroy(class *this)                                            \
110{                                                                            \
111    dshowdebug(AV_STRINGIFY(class)"_Destroy(%p)\n", this);                   \
112    func(this);                                                              \
113    if (this) {                                                              \
114        if (this->vtbl)                                                      \
115            CoTaskMemFree(this->vtbl);                                       \
116        CoTaskMemFree(this);                                                 \
117    }                                                                        \
118}
119#define DECLARE_CREATE(class, setup, ...)                                    \
120class *class##_Create(__VA_ARGS__)                                           \
121{                                                                            \
122    class *this = CoTaskMemAlloc(sizeof(class));                             \
123    void  *vtbl = CoTaskMemAlloc(sizeof(*this->vtbl));                       \
124    dshowdebug(AV_STRINGIFY(class)"_Create(%p)\n", this);                    \
125    if (!this || !vtbl)                                                      \
126        goto fail;                                                           \
127    ZeroMemory(this, sizeof(class));                                         \
128    ZeroMemory(vtbl, sizeof(*this->vtbl));                                   \
129    this->ref  = 1;                                                          \
130    this->vtbl = vtbl;                                                       \
131    if (!setup)                                                              \
132        goto fail;                                                           \
133    dshowdebug("created "AV_STRINGIFY(class)" %p\n", this);                  \
134    return this;                                                             \
135fail:                                                                        \
136    class##_Destroy(this);                                                   \
137    dshowdebug("could not create "AV_STRINGIFY(class)"\n");                  \
138    return NULL;                                                             \
139}
140
141#define SETVTBL(vtbl, class, fn) \
142    do { (vtbl)->fn = (void *) class##_##fn; } while(0)
143
144/*****************************************************************************
145 * Forward Declarations
146 ****************************************************************************/
147typedef struct libAVPin libAVPin;
148typedef struct libAVMemInputPin libAVMemInputPin;
149typedef struct libAVEnumPins libAVEnumPins;
150typedef struct libAVEnumMediaTypes libAVEnumMediaTypes;
151typedef struct libAVFilter libAVFilter;
152
153/*****************************************************************************
154 * libAVPin
155 ****************************************************************************/
156struct libAVPin {
157    IPinVtbl *vtbl;
158    long ref;
159    libAVFilter *filter;
160    IPin *connectedto;
161    AM_MEDIA_TYPE type;
162    IMemInputPinVtbl *imemvtbl;
163};
164
165long          WINAPI libAVPin_QueryInterface          (libAVPin *, const GUID *, void **);
166unsigned long WINAPI libAVPin_AddRef                  (libAVPin *);
167unsigned long WINAPI libAVPin_Release                 (libAVPin *);
168long          WINAPI libAVPin_Connect                 (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
169long          WINAPI libAVPin_ReceiveConnection       (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
170long          WINAPI libAVPin_Disconnect              (libAVPin *);
171long          WINAPI libAVPin_ConnectedTo             (libAVPin *, IPin **);
172long          WINAPI libAVPin_ConnectionMediaType     (libAVPin *, AM_MEDIA_TYPE *);
173long          WINAPI libAVPin_QueryPinInfo            (libAVPin *, PIN_INFO *);
174long          WINAPI libAVPin_QueryDirection          (libAVPin *, PIN_DIRECTION *);
175long          WINAPI libAVPin_QueryId                 (libAVPin *, wchar_t **);
176long          WINAPI libAVPin_QueryAccept             (libAVPin *, const AM_MEDIA_TYPE *);
177long          WINAPI libAVPin_EnumMediaTypes          (libAVPin *, IEnumMediaTypes **);
178long          WINAPI libAVPin_QueryInternalConnections(libAVPin *, IPin **, unsigned long *);
179long          WINAPI libAVPin_EndOfStream             (libAVPin *);
180long          WINAPI libAVPin_BeginFlush              (libAVPin *);
181long          WINAPI libAVPin_EndFlush                (libAVPin *);
182long          WINAPI libAVPin_NewSegment              (libAVPin *, REFERENCE_TIME, REFERENCE_TIME, double);
183
184long          WINAPI libAVMemInputPin_QueryInterface          (libAVMemInputPin *, const GUID *, void **);
185unsigned long WINAPI libAVMemInputPin_AddRef                  (libAVMemInputPin *);
186unsigned long WINAPI libAVMemInputPin_Release                 (libAVMemInputPin *);
187long          WINAPI libAVMemInputPin_GetAllocator            (libAVMemInputPin *, IMemAllocator **);
188long          WINAPI libAVMemInputPin_NotifyAllocator         (libAVMemInputPin *, IMemAllocator *, BOOL);
189long          WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *, ALLOCATOR_PROPERTIES *);
190long          WINAPI libAVMemInputPin_Receive                 (libAVMemInputPin *, IMediaSample *);
191long          WINAPI libAVMemInputPin_ReceiveMultiple         (libAVMemInputPin *, IMediaSample **, long, long *);
192long          WINAPI libAVMemInputPin_ReceiveCanBlock         (libAVMemInputPin *);
193
194void                 libAVPin_Destroy(libAVPin *);
195libAVPin            *libAVPin_Create (libAVFilter *filter);
196
197void                 libAVMemInputPin_Destroy(libAVMemInputPin *);
198
199/*****************************************************************************
200 * libAVEnumPins
201 ****************************************************************************/
202struct libAVEnumPins {
203    IEnumPinsVtbl *vtbl;
204    long ref;
205    int pos;
206    libAVPin *pin;
207    libAVFilter *filter;
208};
209
210long          WINAPI libAVEnumPins_QueryInterface(libAVEnumPins *, const GUID *, void **);
211unsigned long WINAPI libAVEnumPins_AddRef        (libAVEnumPins *);
212unsigned long WINAPI libAVEnumPins_Release       (libAVEnumPins *);
213long          WINAPI libAVEnumPins_Next          (libAVEnumPins *, unsigned long, IPin **, unsigned long *);
214long          WINAPI libAVEnumPins_Skip          (libAVEnumPins *, unsigned long);
215long          WINAPI libAVEnumPins_Reset         (libAVEnumPins *);
216long          WINAPI libAVEnumPins_Clone         (libAVEnumPins *, libAVEnumPins **);
217
218void                 libAVEnumPins_Destroy(libAVEnumPins *);
219libAVEnumPins       *libAVEnumPins_Create (libAVPin *pin, libAVFilter *filter);
220
221/*****************************************************************************
222 * libAVEnumMediaTypes
223 ****************************************************************************/
224struct libAVEnumMediaTypes {
225    IEnumPinsVtbl *vtbl;
226    long ref;
227    int pos;
228    AM_MEDIA_TYPE type;
229};
230
231long          WINAPI libAVEnumMediaTypes_QueryInterface(libAVEnumMediaTypes *, const GUID *, void **);
232unsigned long WINAPI libAVEnumMediaTypes_AddRef        (libAVEnumMediaTypes *);
233unsigned long WINAPI libAVEnumMediaTypes_Release       (libAVEnumMediaTypes *);
234long          WINAPI libAVEnumMediaTypes_Next          (libAVEnumMediaTypes *, unsigned long, AM_MEDIA_TYPE **, unsigned long *);
235long          WINAPI libAVEnumMediaTypes_Skip          (libAVEnumMediaTypes *, unsigned long);
236long          WINAPI libAVEnumMediaTypes_Reset         (libAVEnumMediaTypes *);
237long          WINAPI libAVEnumMediaTypes_Clone         (libAVEnumMediaTypes *, libAVEnumMediaTypes **);
238
239void                 libAVEnumMediaTypes_Destroy(libAVEnumMediaTypes *);
240libAVEnumMediaTypes *libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type);
241
242/*****************************************************************************
243 * libAVFilter
244 ****************************************************************************/
245struct libAVFilter {
246    IBaseFilterVtbl *vtbl;
247    long ref;
248    const wchar_t *name;
249    libAVPin *pin;
250    FILTER_INFO info;
251    FILTER_STATE state;
252    IReferenceClock *clock;
253    enum dshowDeviceType type;
254    void *priv_data;
255    int stream_index;
256    int64_t start_time;
257    void (*callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType type);
258};
259
260long          WINAPI libAVFilter_QueryInterface (libAVFilter *, const GUID *, void **);
261unsigned long WINAPI libAVFilter_AddRef         (libAVFilter *);
262unsigned long WINAPI libAVFilter_Release        (libAVFilter *);
263long          WINAPI libAVFilter_GetClassID     (libAVFilter *, CLSID *);
264long          WINAPI libAVFilter_Stop           (libAVFilter *);
265long          WINAPI libAVFilter_Pause          (libAVFilter *);
266long          WINAPI libAVFilter_Run            (libAVFilter *, REFERENCE_TIME);
267long          WINAPI libAVFilter_GetState       (libAVFilter *, DWORD, FILTER_STATE *);
268long          WINAPI libAVFilter_SetSyncSource  (libAVFilter *, IReferenceClock *);
269long          WINAPI libAVFilter_GetSyncSource  (libAVFilter *, IReferenceClock **);
270long          WINAPI libAVFilter_EnumPins       (libAVFilter *, IEnumPins **);
271long          WINAPI libAVFilter_FindPin        (libAVFilter *, const wchar_t *, IPin **);
272long          WINAPI libAVFilter_QueryFilterInfo(libAVFilter *, FILTER_INFO *);
273long          WINAPI libAVFilter_JoinFilterGraph(libAVFilter *, IFilterGraph *, const wchar_t *);
274long          WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
275
276void                 libAVFilter_Destroy(libAVFilter *);
277libAVFilter         *libAVFilter_Create (void *, void *, enum dshowDeviceType);
278
279#endif /* AVDEVICE_DSHOW_H */
280