Browse code

DirectShow capture support Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Ramiro Polla authored on 2011/05/21 21:24:50
Showing 11 changed files
... ...
@@ -1463,6 +1463,8 @@ w64_demuxer_deps="wav_demuxer"
1463 1463
 alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
1464 1464
 alsa_outdev_deps="alsa_asoundlib_h"
1465 1465
 bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h"
1466
+dshow_indev_deps="IBaseFilter"
1467
+dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid"
1466 1468
 dv1394_indev_deps="dv1394 dv_demuxer"
1467 1469
 fbdev_indev_deps="linux_fb_h"
1468 1470
 jack_indev_deps="jack_jack_h sem_timedwait"
... ...
@@ -2979,6 +2981,8 @@ check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extra
2979 2979
 # w32api 3.12 had it defined wrong
2980 2980
 check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_defines
2981 2981
 
2982
+check_type "dshow.h" IBaseFilter
2983
+
2982 2984
 # check for ioctl_meteor.h, ioctl_bt848.h and alternatives
2983 2985
 { check_header dev/bktr/ioctl_meteor.h &&
2984 2986
   check_header dev/bktr/ioctl_bt848.h; } ||
... ...
@@ -13,6 +13,9 @@ OBJS-$(CONFIG_ALSA_INDEV)                += alsa-audio-common.o \
13 13
 OBJS-$(CONFIG_ALSA_OUTDEV)               += alsa-audio-common.o \
14 14
                                             alsa-audio-enc.o
15 15
 OBJS-$(CONFIG_BKTR_INDEV)                += bktr.o
16
+OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \
17
+                                            dshow_enumpins.o dshow_filter.o \
18
+                                            dshow_pin.o dshow_common.o
16 19
 OBJS-$(CONFIG_DV1394_INDEV)              += dv1394.o
17 20
 OBJS-$(CONFIG_FBDEV_INDEV)               += fbdev.o
18 21
 OBJS-$(CONFIG_JACK_INDEV)                += jack_audio.o
... ...
@@ -41,6 +41,7 @@ void avdevice_register_all(void)
41 41
     /* devices */
42 42
     REGISTER_INOUTDEV (ALSA, alsa);
43 43
     REGISTER_INDEV    (BKTR, bktr);
44
+    REGISTER_INDEV    (DSHOW, dshow);
44 45
     REGISTER_INDEV    (DV1394, dv1394);
45 46
     REGISTER_INDEV    (FBDEV, fbdev);
46 47
     REGISTER_INDEV    (JACK, jack);
47 48
new file mode 100644
... ...
@@ -0,0 +1,646 @@
0
+/*
1
+ * Directshow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "libavformat/avformat.h"
22
+#include "libavformat/timefilter.h"
23
+
24
+#include "dshow.h"
25
+
26
+struct dshow_ctx {
27
+    IGraphBuilder *graph;
28
+
29
+    char *device_name[2];
30
+
31
+    IBaseFilter *device_filter[2];
32
+    IPin        *device_pin[2];
33
+    libAVFilter *capture_filter[2];
34
+    libAVPin    *capture_pin[2];
35
+
36
+    HANDLE mutex;
37
+    HANDLE event;
38
+    AVPacketList *pktl;
39
+
40
+    unsigned int curbufsize;
41
+    unsigned int video_frame_num;
42
+
43
+    IMediaControl *control;
44
+
45
+    TimeFilter *timefilter;
46
+};
47
+
48
+static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
49
+{
50
+    switch(biCompression) {
51
+    case MKTAG('U', 'Y', 'V', 'Y'):
52
+        return PIX_FMT_UYVY422;
53
+    case MKTAG('Y', 'U', 'Y', '2'):
54
+        return PIX_FMT_YUYV422;
55
+    case MKTAG('I', '4', '2', '0'):
56
+        return PIX_FMT_YUV420P;
57
+    case BI_RGB:
58
+        switch(biBitCount) { /* 1-8 are untested */
59
+            case 1:
60
+                return PIX_FMT_MONOWHITE;
61
+            case 4:
62
+                return PIX_FMT_RGB4;
63
+            case 8:
64
+                return PIX_FMT_RGB8;
65
+            case 16:
66
+                return PIX_FMT_RGB555;
67
+            case 24:
68
+                return PIX_FMT_BGR24;
69
+            case 32:
70
+                return PIX_FMT_RGB32;
71
+        }
72
+    }
73
+    return PIX_FMT_NONE;
74
+}
75
+
76
+static enum CodecID dshow_codecid(DWORD biCompression)
77
+{
78
+    switch(biCompression) {
79
+    case MKTAG('d', 'v', 's', 'd'):
80
+        return CODEC_ID_DVVIDEO;
81
+    case MKTAG('M', 'J', 'P', 'G'):
82
+    case MKTAG('m', 'j', 'p', 'g'):
83
+        return CODEC_ID_MJPEG;
84
+    }
85
+    return CODEC_ID_NONE;
86
+}
87
+
88
+static int
89
+dshow_read_close(AVFormatContext *s)
90
+{
91
+    struct dshow_ctx *ctx = s->priv_data;
92
+    AVPacketList *pktl;
93
+
94
+    if (ctx->control) {
95
+        IMediaControl_Stop(ctx->control);
96
+        IMediaControl_Release(ctx->control);
97
+    }
98
+    if (ctx->graph)
99
+        IGraphBuilder_Release(ctx->graph);
100
+
101
+    /* FIXME remove filters from graph */
102
+    /* FIXME disconnect pins */
103
+    if (ctx->capture_pin[VideoDevice])
104
+        libAVPin_Release(ctx->capture_pin[VideoDevice]);
105
+    if (ctx->capture_pin[AudioDevice])
106
+        libAVPin_Release(ctx->capture_pin[AudioDevice]);
107
+    if (ctx->capture_filter[VideoDevice])
108
+        libAVFilter_Release(ctx->capture_filter[VideoDevice]);
109
+    if (ctx->capture_filter[AudioDevice])
110
+        libAVFilter_Release(ctx->capture_filter[AudioDevice]);
111
+
112
+    if (ctx->device_pin[VideoDevice])
113
+        IPin_Release(ctx->device_pin[VideoDevice]);
114
+    if (ctx->device_pin[AudioDevice])
115
+        IPin_Release(ctx->device_pin[AudioDevice]);
116
+    if (ctx->device_filter[VideoDevice])
117
+        IBaseFilter_Release(ctx->device_filter[VideoDevice]);
118
+    if (ctx->device_filter[AudioDevice])
119
+        IBaseFilter_Release(ctx->device_filter[AudioDevice]);
120
+
121
+    if (ctx->device_name[0])
122
+        av_free(ctx->device_name[0]);
123
+    if (ctx->device_name[1])
124
+        av_free(ctx->device_name[1]);
125
+
126
+    if(ctx->mutex)
127
+        CloseHandle(ctx->mutex);
128
+    if(ctx->event)
129
+        CloseHandle(ctx->event);
130
+
131
+    pktl = ctx->pktl;
132
+    while (pktl) {
133
+        AVPacketList *next = pktl->next;
134
+        av_destruct_packet(&pktl->pkt);
135
+        av_free(pktl);
136
+        pktl = next;
137
+    }
138
+
139
+    return 0;
140
+}
141
+
142
+static char *dup_wchar_to_utf8(wchar_t *w)
143
+{
144
+    char *s = NULL;
145
+    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
146
+    s = av_malloc(l);
147
+    if (s)
148
+        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
149
+    return s;
150
+}
151
+
152
+static int shall_we_drop(AVFormatContext *s)
153
+{
154
+    struct dshow_ctx *ctx = s->priv_data;
155
+    const uint8_t dropscore[] = {62, 75, 87, 100};
156
+    const int ndropscores = FF_ARRAY_ELEMS(dropscore);
157
+    unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer;
158
+
159
+    if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
160
+        av_log(s, AV_LOG_ERROR,
161
+              "real-time buffer %d%% full! frame dropped!\n", buffer_fullness);
162
+        return 1;
163
+    }
164
+
165
+    return 0;
166
+}
167
+
168
+static void
169
+callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
170
+{
171
+    AVFormatContext *s = priv_data;
172
+    struct dshow_ctx *ctx = s->priv_data;
173
+    AVPacketList **ppktl, *pktl_next;
174
+
175
+//    dump_videohdr(s, vdhdr);
176
+
177
+    if(shall_we_drop(s))
178
+        return;
179
+
180
+    WaitForSingleObject(ctx->mutex, INFINITE);
181
+
182
+    pktl_next = av_mallocz(sizeof(AVPacketList));
183
+    if(!pktl_next)
184
+        goto fail;
185
+
186
+    if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
187
+        av_free(pktl_next);
188
+        goto fail;
189
+    }
190
+
191
+    pktl_next->pkt.stream_index = index;
192
+    pktl_next->pkt.pts = time;
193
+    memcpy(pktl_next->pkt.data, buf, buf_size);
194
+
195
+    for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
196
+    *ppktl = pktl_next;
197
+
198
+    ctx->curbufsize += buf_size;
199
+
200
+    SetEvent(ctx->event);
201
+    ReleaseMutex(ctx->mutex);
202
+
203
+    return;
204
+fail:
205
+    ReleaseMutex(ctx->mutex);
206
+    return;
207
+}
208
+
209
+static int
210
+dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
211
+                  enum dshowDeviceType devtype)
212
+{
213
+    struct dshow_ctx *ctx = avctx->priv_data;
214
+    IBaseFilter *device_filter = NULL;
215
+    IEnumMoniker *classenum = NULL;
216
+    IGraphBuilder *graph = ctx->graph;
217
+    IEnumPins *pins = 0;
218
+    IMoniker *m = NULL;
219
+    IPin *device_pin = NULL;
220
+    libAVPin *capture_pin = NULL;
221
+    libAVFilter *capture_filter = NULL;
222
+    const char *device_name = ctx->device_name[devtype];
223
+    int ret = AVERROR(EIO);
224
+    IPin *pin;
225
+    int r, i;
226
+
227
+    const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
228
+                                   &CLSID_AudioInputDeviceCategory };
229
+    const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
230
+    const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
231
+    const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
232
+
233
+    r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype],
234
+                                             (IEnumMoniker **) &classenum, 0);
235
+    if (r != S_OK) {
236
+        av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n",
237
+               devtypename);
238
+        goto error;
239
+    }
240
+
241
+    while (IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK && !device_filter) {
242
+        IPropertyBag *bag = NULL;
243
+        char *buf = NULL;
244
+        VARIANT var;
245
+
246
+        r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
247
+        if (r != S_OK)
248
+            goto fail1;
249
+
250
+        var.vt = VT_BSTR;
251
+        r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
252
+        if (r != S_OK)
253
+            goto fail1;
254
+
255
+        buf = dup_wchar_to_utf8(var.bstrVal);
256
+
257
+        if (strcmp(device_name, buf))
258
+            goto fail1;
259
+
260
+        IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
261
+
262
+fail1:
263
+        if (buf)
264
+            av_free(buf);
265
+        if (bag)
266
+            IPropertyBag_Release(bag);
267
+        IMoniker_Release(m);
268
+    }
269
+
270
+    if (!device_filter) {
271
+        av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n",
272
+               devtypename);
273
+        goto error;
274
+    }
275
+    ctx->device_filter [devtype] = device_filter;
276
+
277
+    r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
278
+    if (r != S_OK) {
279
+        av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
280
+        goto error;
281
+    }
282
+
283
+    r = IBaseFilter_EnumPins(device_filter, &pins);
284
+    if (r != S_OK) {
285
+        av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
286
+        goto error;
287
+    }
288
+
289
+    i = 0;
290
+    while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !device_pin) {
291
+        IKsPropertySet *p = NULL;
292
+        IEnumMediaTypes *types;
293
+        PIN_INFO info = {0};
294
+        AM_MEDIA_TYPE *type;
295
+        GUID category;
296
+        DWORD r2;
297
+
298
+        IPin_QueryPinInfo(pin, &info);
299
+        IBaseFilter_Release(info.pFilter);
300
+
301
+        if (info.dir != PINDIR_OUTPUT)
302
+            goto next;
303
+        if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
304
+            goto next;
305
+        if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
306
+                               NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
307
+            goto next;
308
+        if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
309
+            goto next;
310
+
311
+        if (IPin_EnumMediaTypes(pin, &types) != S_OK)
312
+            goto next;
313
+
314
+        IEnumMediaTypes_Reset(types);
315
+        while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK && !device_pin) {
316
+            if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
317
+                device_pin = pin;
318
+                goto next;
319
+            }
320
+            CoTaskMemFree(type);
321
+        }
322
+
323
+next:
324
+        if (types)
325
+            IEnumMediaTypes_Release(types);
326
+        if (p)
327
+            IKsPropertySet_Release(p);
328
+        if (device_pin != pin)
329
+            IPin_Release(pin);
330
+    }
331
+
332
+    if (!device_pin) {
333
+        av_log(avctx, AV_LOG_ERROR,
334
+               "Could not find output pin from %s capture device.\n", devtypename);
335
+        goto error;
336
+    }
337
+    ctx->device_pin[devtype] = device_pin;
338
+
339
+    capture_filter = libAVFilter_Create(avctx, callback, devtype);
340
+    if (!capture_filter) {
341
+        av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
342
+        goto error;
343
+    }
344
+    ctx->capture_filter[devtype] = capture_filter;
345
+
346
+    r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
347
+                                filter_name[devtype]);
348
+    if (r != S_OK) {
349
+        av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
350
+        goto error;
351
+    }
352
+
353
+    libAVPin_AddRef(capture_filter->pin);
354
+    capture_pin = capture_filter->pin;
355
+    ctx->capture_pin[devtype] = capture_pin;
356
+
357
+    r = IGraphBuilder_ConnectDirect(graph, device_pin, (IPin *) capture_pin, NULL);
358
+    if (r != S_OK) {
359
+        av_log(avctx, AV_LOG_ERROR, "Could not connect pins\n");
360
+        goto error;
361
+    }
362
+
363
+    ret = 0;
364
+
365
+error:
366
+    if (pins)
367
+        IEnumPins_Release(pins);
368
+    if (classenum)
369
+        IEnumMoniker_Release(classenum);
370
+
371
+    return ret;
372
+}
373
+
374
+static enum CodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
375
+{
376
+    switch (sample_fmt) {
377
+    case AV_SAMPLE_FMT_U8:  return CODEC_ID_PCM_U8;
378
+    case AV_SAMPLE_FMT_S16: return CODEC_ID_PCM_S16LE;
379
+    case AV_SAMPLE_FMT_S32: return CODEC_ID_PCM_S32LE;
380
+    default:                return CODEC_ID_NONE; /* Should never happen. */
381
+    }
382
+}
383
+
384
+static enum SampleFormat sample_fmt_bits_per_sample(int bits)
385
+{
386
+    switch (bits) {
387
+    case 8:  return AV_SAMPLE_FMT_U8;
388
+    case 16: return AV_SAMPLE_FMT_S16;
389
+    case 32: return AV_SAMPLE_FMT_S32;
390
+    default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
391
+    }
392
+}
393
+
394
+static int
395
+dshow_add_device(AVFormatContext *avctx, AVFormatParameters *ap,
396
+                 enum dshowDeviceType devtype)
397
+{
398
+    struct dshow_ctx *ctx = avctx->priv_data;
399
+    AM_MEDIA_TYPE type;
400
+    AVCodecContext *codec;
401
+    AVStream *st;
402
+    int ret = AVERROR(EIO);
403
+
404
+    st = av_new_stream(avctx, devtype);
405
+    if (!st) {
406
+        ret = AVERROR(ENOMEM);
407
+        goto error;
408
+    }
409
+
410
+    ctx->capture_filter[devtype]->stream_index = st->index;
411
+
412
+    libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
413
+
414
+    codec = st->codec;
415
+    if (devtype == VideoDevice) {
416
+        BITMAPINFOHEADER *bih = NULL;
417
+
418
+        if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
419
+            VIDEOINFOHEADER *v = (void *) type.pbFormat;
420
+            bih = &v->bmiHeader;
421
+        } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
422
+            VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
423
+            bih = &v->bmiHeader;
424
+        }
425
+        if (!bih) {
426
+            av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
427
+            goto error;
428
+        }
429
+
430
+        codec->time_base  = ap->time_base;
431
+        codec->codec_type = AVMEDIA_TYPE_VIDEO;
432
+        codec->width      = bih->biWidth;
433
+        codec->height     = bih->biHeight;
434
+        codec->pix_fmt    = dshow_pixfmt(bih->biCompression, bih->biBitCount);
435
+        if (codec->pix_fmt == PIX_FMT_NONE) {
436
+            codec->codec_id = dshow_codecid(bih->biCompression);
437
+            if (codec->codec_id == CODEC_ID_NONE) {
438
+                av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
439
+                                 "Please report verbose (-v 9) debug information.\n");
440
+                dshow_read_close(avctx);
441
+                return AVERROR_PATCHWELCOME;
442
+            }
443
+            codec->bits_per_coded_sample = bih->biBitCount;
444
+        } else {
445
+            codec->codec_id = CODEC_ID_RAWVIDEO;
446
+            if (bih->biCompression == BI_RGB) {
447
+                codec->bits_per_coded_sample = bih->biBitCount;
448
+                codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE);
449
+                if (codec->extradata) {
450
+                    codec->extradata_size = 9;
451
+                    memcpy(codec->extradata, "BottomUp", 9);
452
+                }
453
+            }
454
+        }
455
+    } else {
456
+        WAVEFORMATEX *fx = NULL;
457
+
458
+        if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
459
+            fx = (void *) type.pbFormat;
460
+        }
461
+        if (!fx) {
462
+            av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
463
+            goto error;
464
+        }
465
+
466
+        codec->codec_type  = CODEC_TYPE_AUDIO;
467
+        codec->sample_fmt  = sample_fmt_bits_per_sample(fx->wBitsPerSample);
468
+        codec->codec_id    = waveform_codec_id(codec->sample_fmt);
469
+        codec->sample_rate = fx->nSamplesPerSec;
470
+        codec->channels    = fx->nChannels;
471
+    }
472
+
473
+    av_set_pts_info(st, 64, 1, 10000000);
474
+
475
+    ret = 0;
476
+
477
+error:
478
+    return ret;
479
+}
480
+
481
+static int parse_device_name(AVFormatContext *avctx)
482
+{
483
+    struct dshow_ctx *ctx = avctx->priv_data;
484
+    char **device_name = ctx->device_name;
485
+    char *name = av_strdup(avctx->filename);
486
+    char *tmp = name;
487
+    int ret = 1;
488
+    char *type;
489
+
490
+    while ((type = strtok(tmp, "="))) {
491
+        char *token = strtok(NULL, ":");
492
+        tmp = NULL;
493
+
494
+        if        (!strcmp(type, "video")) {
495
+            device_name[0] = token;
496
+        } else if (!strcmp(type, "audio")) {
497
+            device_name[1] = token;
498
+        } else {
499
+            device_name[0] = NULL;
500
+            device_name[1] = NULL;
501
+            break;
502
+        }
503
+    }
504
+
505
+    if (!device_name[0] && !device_name[1]) {
506
+        ret = 0;
507
+    } else {
508
+        if (device_name[0])
509
+            device_name[0] = av_strdup(device_name[0]);
510
+        if (device_name[1])
511
+            device_name[1] = av_strdup(device_name[1]);
512
+    }
513
+
514
+    av_free(name);
515
+    return ret;
516
+}
517
+
518
+static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
519
+{
520
+    struct dshow_ctx *ctx = avctx->priv_data;
521
+    IGraphBuilder *graph = NULL;
522
+    ICreateDevEnum *devenum = NULL;
523
+    IMediaControl *control = NULL;
524
+    int ret = AVERROR(EIO);
525
+    int r;
526
+
527
+    if (!parse_device_name(avctx)) {
528
+        av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
529
+        goto error;
530
+    }
531
+
532
+    CoInitialize(0);
533
+
534
+    r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
535
+                         &IID_IGraphBuilder, (void **) &graph);
536
+    if (r != S_OK) {
537
+        av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
538
+        goto error;
539
+    }
540
+    ctx->graph = graph;
541
+
542
+    r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
543
+                         &IID_ICreateDevEnum, (void **) &devenum);
544
+    if (r != S_OK) {
545
+        av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
546
+        goto error;
547
+    }
548
+
549
+    if (ctx->device_name[VideoDevice]) {
550
+        ret = dshow_open_device(avctx, devenum, VideoDevice);
551
+        if (ret < 0)
552
+            goto error;
553
+        ret = dshow_add_device(avctx, ap, VideoDevice);
554
+        if (ret < 0)
555
+            goto error;
556
+    }
557
+    if (ctx->device_name[AudioDevice]) {
558
+        ret = dshow_open_device(avctx, devenum, AudioDevice);
559
+        if (ret < 0)
560
+            goto error;
561
+        ret = dshow_add_device(avctx, ap, AudioDevice);
562
+        if (ret < 0)
563
+            goto error;
564
+    }
565
+
566
+    ctx->mutex = CreateMutex(NULL, 0, NULL);
567
+    if (!ctx->mutex) {
568
+        av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
569
+        goto error;
570
+    }
571
+    ctx->event = CreateEvent(NULL, 1, 0, NULL);
572
+    if (!ctx->event) {
573
+        av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
574
+        goto error;
575
+    }
576
+
577
+    r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
578
+    if (r != S_OK) {
579
+        av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
580
+        goto error;
581
+    }
582
+    ctx->control = control;
583
+
584
+    r = IMediaControl_Run(control);
585
+    if (r == S_FALSE) {
586
+        OAFilterState pfs;
587
+        r = IMediaControl_GetState(control, 0, &pfs);
588
+    }
589
+    if (r != S_OK) {
590
+        av_log(avctx, AV_LOG_ERROR, "Could not run filter\n");
591
+        goto error;
592
+    }
593
+
594
+    ret = 0;
595
+
596
+error:
597
+
598
+    if (ret < 0)
599
+        dshow_read_close(avctx);
600
+
601
+    if (devenum)
602
+        ICreateDevEnum_Release(devenum);
603
+
604
+    return ret;
605
+}
606
+
607
+static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
608
+{
609
+    struct dshow_ctx *ctx = s->priv_data;
610
+    AVPacketList *pktl = NULL;
611
+
612
+    while (!pktl) {
613
+        WaitForSingleObject(ctx->mutex, INFINITE);
614
+        pktl = ctx->pktl;
615
+        if (ctx->pktl) {
616
+            *pkt = ctx->pktl->pkt;
617
+            ctx->pktl = ctx->pktl->next;
618
+            av_free(pktl);
619
+        }
620
+        ResetEvent(ctx->event);
621
+        ReleaseMutex(ctx->mutex);
622
+        if (!pktl) {
623
+            if (s->flags & AVFMT_FLAG_NONBLOCK) {
624
+                return AVERROR(EAGAIN);
625
+            } else {
626
+                WaitForSingleObject(ctx->event, INFINITE);
627
+            }
628
+        }
629
+    }
630
+
631
+    ctx->curbufsize -= pkt->size;
632
+
633
+    return pkt->size;
634
+}
635
+
636
+AVInputFormat dshow_demuxer = {
637
+    "dshow",
638
+    NULL_IF_CONFIG_SMALL("DirectShow capture"),
639
+    sizeof(struct dshow_ctx),
640
+    NULL,
641
+    dshow_read_header,
642
+    dshow_read_packet,
643
+    dshow_read_close,
644
+    .flags = AVFMT_NOFILE,
645
+};
0 646
new file mode 100644
... ...
@@ -0,0 +1,266 @@
0
+/*
1
+ * DirectShow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#define DSHOWDEBUG 0
22
+
23
+#include "libavformat/avformat.h"
24
+
25
+#define COBJMACROS
26
+#include <windows.h>
27
+#include <dshow.h>
28
+#include <dvdmedia.h>
29
+
30
+long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
31
+void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type);
32
+void ff_printGUID(const GUID *g);
33
+
34
+#if DSHOWDEBUG
35
+extern const AVClass *ff_dshow_context_class_ptr;
36
+#define dshowdebug(...) av_log(&ff_dshow_context_class_ptr, AV_LOG_DEBUG, __VA_ARGS__)
37
+#else
38
+#define dshowdebug(...)
39
+#endif
40
+
41
+static inline void nothing(void *foo)
42
+{
43
+}
44
+
45
+struct GUIDoffset {
46
+    const GUID *iid;
47
+    int offset;
48
+};
49
+
50
+enum dshowDeviceType {
51
+    VideoDevice = 0,
52
+    AudioDevice = 1,
53
+};
54
+
55
+#define DECLARE_QUERYINTERFACE(class, ...)                                   \
56
+long WINAPI                                                                  \
57
+class##_QueryInterface(class *this, const GUID *riid, void **ppvObject)      \
58
+{                                                                            \
59
+    struct GUIDoffset ifaces[] = __VA_ARGS__;                                \
60
+    int i;                                                                   \
61
+    dshowdebug(AV_STRINGIFY(class)"_QueryInterface(%p, %p, %p)\n", this, riid, ppvObject); \
62
+    ff_printGUID(riid);                                                      \
63
+    if (!ppvObject)                                                          \
64
+        return E_POINTER;                                                    \
65
+    for (i = 0; i < sizeof(ifaces)/sizeof(ifaces[0]); i++) {                 \
66
+        if (IsEqualGUID(riid, ifaces[i].iid)) {                              \
67
+            void *obj = (void *) ((uint8_t *) this + ifaces[i].offset);      \
68
+            class##_AddRef(this);                                            \
69
+            dshowdebug("\tfound %d with offset %d\n", i, ifaces[i].offset);  \
70
+            *ppvObject = (void *) obj;                                       \
71
+            return S_OK;                                                     \
72
+        }                                                                    \
73
+    }                                                                        \
74
+    dshowdebug("\tE_NOINTERFACE\n");                                         \
75
+    *ppvObject = NULL;                                                       \
76
+    return E_NOINTERFACE;                                                    \
77
+}
78
+#define DECLARE_ADDREF(class)                                                \
79
+unsigned long WINAPI                                                         \
80
+class##_AddRef(class *this)                                                  \
81
+{                                                                            \
82
+    dshowdebug(AV_STRINGIFY(class)"_AddRef(%p)\t%ld\n", this, this->ref+1);  \
83
+    return InterlockedIncrement(&this->ref);                                 \
84
+}
85
+#define DECLARE_RELEASE(class)                                               \
86
+unsigned long WINAPI                                                         \
87
+class##_Release(class *this)                                                 \
88
+{                                                                            \
89
+    long ref = InterlockedDecrement(&this->ref);                             \
90
+    dshowdebug(AV_STRINGIFY(class)"_Release(%p)\t%ld\n", this, ref);         \
91
+    if (!ref)                                                                \
92
+        class##_Destroy(this);                                               \
93
+    return ref;                                                              \
94
+}
95
+
96
+#define DECLARE_DESTROY(class, func)                                         \
97
+void class##_Destroy(class *this)                                            \
98
+{                                                                            \
99
+    dshowdebug(AV_STRINGIFY(class)"_Destroy(%p)\n", this);                   \
100
+    func(this);                                                              \
101
+    if (this) {                                                              \
102
+        if (this->vtbl)                                                      \
103
+            CoTaskMemFree(this->vtbl);                                       \
104
+        CoTaskMemFree(this);                                                 \
105
+    }                                                                        \
106
+}
107
+#define DECLARE_CREATE(class, setup, ...)                                    \
108
+class *class##_Create(__VA_ARGS__)                                           \
109
+{                                                                            \
110
+    class *this = CoTaskMemAlloc(sizeof(class));                             \
111
+    void  *vtbl = CoTaskMemAlloc(sizeof(*this->vtbl));                       \
112
+    dshowdebug(AV_STRINGIFY(class)"_Create(%p)\n", this);                    \
113
+    if (!this || !vtbl)                                                      \
114
+        goto fail;                                                           \
115
+    ZeroMemory(this, sizeof(class));                                         \
116
+    ZeroMemory(vtbl, sizeof(*this->vtbl));                                   \
117
+    this->ref  = 1;                                                          \
118
+    this->vtbl = vtbl;                                                       \
119
+    if (!setup)                                                              \
120
+        goto fail;                                                           \
121
+    dshowdebug("created "AV_STRINGIFY(class)" %p\n", this);                  \
122
+    return this;                                                             \
123
+fail:                                                                        \
124
+    class##_Destroy(this);                                                   \
125
+    dshowdebug("could not create "AV_STRINGIFY(class)"\n");                  \
126
+    return NULL;                                                             \
127
+}
128
+
129
+#define SETVTBL(vtbl, class, fn) \
130
+    do { (vtbl)->fn = (void *) class##_##fn; } while(0)
131
+
132
+/*****************************************************************************
133
+ * Forward Declarations
134
+ ****************************************************************************/
135
+typedef struct libAVPin libAVPin;
136
+typedef struct libAVMemInputPin libAVMemInputPin;
137
+typedef struct libAVEnumPins libAVEnumPins;
138
+typedef struct libAVEnumMediaTypes libAVEnumMediaTypes;
139
+typedef struct libAVFilter libAVFilter;
140
+
141
+/*****************************************************************************
142
+ * libAVPin
143
+ ****************************************************************************/
144
+struct libAVPin {
145
+    IPinVtbl *vtbl;
146
+    long ref;
147
+    libAVFilter *filter;
148
+    IPin *connectedto;
149
+    AM_MEDIA_TYPE type;
150
+    IMemInputPinVtbl *imemvtbl;
151
+};
152
+
153
+long          WINAPI libAVPin_QueryInterface          (libAVPin *, const GUID *, void **);
154
+unsigned long WINAPI libAVPin_AddRef                  (libAVPin *);
155
+unsigned long WINAPI libAVPin_Release                 (libAVPin *);
156
+long          WINAPI libAVPin_Connect                 (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
157
+long          WINAPI libAVPin_ReceiveConnection       (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
158
+long          WINAPI libAVPin_Disconnect              (libAVPin *);
159
+long          WINAPI libAVPin_ConnectedTo             (libAVPin *, IPin **);
160
+long          WINAPI libAVPin_ConnectionMediaType     (libAVPin *, AM_MEDIA_TYPE *);
161
+long          WINAPI libAVPin_QueryPinInfo            (libAVPin *, PIN_INFO *);
162
+long          WINAPI libAVPin_QueryDirection          (libAVPin *, PIN_DIRECTION *);
163
+long          WINAPI libAVPin_QueryId                 (libAVPin *, wchar_t **);
164
+long          WINAPI libAVPin_QueryAccept             (libAVPin *, const AM_MEDIA_TYPE *);
165
+long          WINAPI libAVPin_EnumMediaTypes          (libAVPin *, IEnumMediaTypes **);
166
+long          WINAPI libAVPin_QueryInternalConnections(libAVPin *, IPin **, unsigned long *);
167
+long          WINAPI libAVPin_EndOfStream             (libAVPin *);
168
+long          WINAPI libAVPin_BeginFlush              (libAVPin *);
169
+long          WINAPI libAVPin_EndFlush                (libAVPin *);
170
+long          WINAPI libAVPin_NewSegment              (libAVPin *, REFERENCE_TIME, REFERENCE_TIME, double);
171
+
172
+long          WINAPI libAVMemInputPin_QueryInterface          (libAVMemInputPin *, const GUID *, void **);
173
+unsigned long WINAPI libAVMemInputPin_AddRef                  (libAVMemInputPin *);
174
+unsigned long WINAPI libAVMemInputPin_Release                 (libAVMemInputPin *);
175
+long          WINAPI libAVMemInputPin_GetAllocator            (libAVMemInputPin *, IMemAllocator **);
176
+long          WINAPI libAVMemInputPin_NotifyAllocator         (libAVMemInputPin *, IMemAllocator *, WINBOOL);
177
+long          WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *, ALLOCATOR_PROPERTIES *);
178
+long          WINAPI libAVMemInputPin_Receive                 (libAVMemInputPin *, IMediaSample *);
179
+long          WINAPI libAVMemInputPin_ReceiveMultiple         (libAVMemInputPin *, IMediaSample **, long, long *);
180
+long          WINAPI libAVMemInputPin_ReceiveCanBlock         (libAVMemInputPin *);
181
+
182
+void                 libAVPin_Destroy(libAVPin *);
183
+libAVPin            *libAVPin_Create (libAVFilter *filter);
184
+
185
+void                 libAVMemInputPin_Destroy(libAVMemInputPin *);
186
+
187
+/*****************************************************************************
188
+ * libAVEnumPins
189
+ ****************************************************************************/
190
+struct libAVEnumPins {
191
+    IEnumPinsVtbl *vtbl;
192
+    long ref;
193
+    int pos;
194
+    libAVPin *pin;
195
+    libAVFilter *filter;
196
+};
197
+
198
+long          WINAPI libAVEnumPins_QueryInterface(libAVEnumPins *, const GUID *, void **);
199
+unsigned long WINAPI libAVEnumPins_AddRef        (libAVEnumPins *);
200
+unsigned long WINAPI libAVEnumPins_Release       (libAVEnumPins *);
201
+long          WINAPI libAVEnumPins_Next          (libAVEnumPins *, unsigned long, IPin **, unsigned long *);
202
+long          WINAPI libAVEnumPins_Skip          (libAVEnumPins *, unsigned long);
203
+long          WINAPI libAVEnumPins_Reset         (libAVEnumPins *);
204
+long          WINAPI libAVEnumPins_Clone         (libAVEnumPins *, libAVEnumPins **);
205
+
206
+void                 libAVEnumPins_Destroy(libAVEnumPins *);
207
+libAVEnumPins       *libAVEnumPins_Create (libAVPin *pin, libAVFilter *filter);
208
+
209
+/*****************************************************************************
210
+ * libAVEnumMediaTypes
211
+ ****************************************************************************/
212
+struct libAVEnumMediaTypes {
213
+    IEnumPinsVtbl *vtbl;
214
+    long ref;
215
+    int pos;
216
+    AM_MEDIA_TYPE type;
217
+};
218
+
219
+long          WINAPI libAVEnumMediaTypes_QueryInterface(libAVEnumMediaTypes *, const GUID *, void **);
220
+unsigned long WINAPI libAVEnumMediaTypes_AddRef        (libAVEnumMediaTypes *);
221
+unsigned long WINAPI libAVEnumMediaTypes_Release       (libAVEnumMediaTypes *);
222
+long          WINAPI libAVEnumMediaTypes_Next          (libAVEnumMediaTypes *, unsigned long, AM_MEDIA_TYPE **, unsigned long *);
223
+long          WINAPI libAVEnumMediaTypes_Skip          (libAVEnumMediaTypes *, unsigned long);
224
+long          WINAPI libAVEnumMediaTypes_Reset         (libAVEnumMediaTypes *);
225
+long          WINAPI libAVEnumMediaTypes_Clone         (libAVEnumMediaTypes *, libAVEnumMediaTypes **);
226
+
227
+void                 libAVEnumMediaTypes_Destroy(libAVEnumMediaTypes *);
228
+libAVEnumMediaTypes *libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type);
229
+
230
+/*****************************************************************************
231
+ * libAVFilter
232
+ ****************************************************************************/
233
+struct libAVFilter {
234
+    IBaseFilterVtbl *vtbl;
235
+    long ref;
236
+    const wchar_t *name;
237
+    libAVPin *pin;
238
+    FILTER_INFO info;
239
+    FILTER_STATE state;
240
+    IReferenceClock *clock;
241
+    enum dshowDeviceType type;
242
+    void *priv_data;
243
+    int stream_index;
244
+    int64_t start_time;
245
+    void (*callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time);
246
+};
247
+
248
+long          WINAPI libAVFilter_QueryInterface (libAVFilter *, const GUID *, void **);
249
+unsigned long WINAPI libAVFilter_AddRef         (libAVFilter *);
250
+unsigned long WINAPI libAVFilter_Release        (libAVFilter *);
251
+long          WINAPI libAVFilter_GetClassID     (libAVFilter *, CLSID *);
252
+long          WINAPI libAVFilter_Stop           (libAVFilter *);
253
+long          WINAPI libAVFilter_Pause          (libAVFilter *);
254
+long          WINAPI libAVFilter_Run            (libAVFilter *, REFERENCE_TIME);
255
+long          WINAPI libAVFilter_GetState       (libAVFilter *, DWORD, FILTER_STATE *);
256
+long          WINAPI libAVFilter_SetSyncSource  (libAVFilter *, IReferenceClock *);
257
+long          WINAPI libAVFilter_GetSyncSource  (libAVFilter *, IReferenceClock **);
258
+long          WINAPI libAVFilter_EnumPins       (libAVFilter *, IEnumPins **);
259
+long          WINAPI libAVFilter_FindPin        (libAVFilter *, const wchar_t *, IPin **);
260
+long          WINAPI libAVFilter_QueryFilterInfo(libAVFilter *, FILTER_INFO *);
261
+long          WINAPI libAVFilter_JoinFilterGraph(libAVFilter *, IFilterGraph *, const wchar_t *);
262
+long          WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
263
+
264
+void                 libAVFilter_Destroy(libAVFilter *);
265
+libAVFilter         *libAVFilter_Create (void *, void *, enum dshowDeviceType);
0 266
new file mode 100644
... ...
@@ -0,0 +1,141 @@
0
+/*
1
+ * Directshow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "dshow.h"
22
+
23
+long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src)
24
+{
25
+    uint8_t *pbFormat = NULL;
26
+
27
+    if (src->cbFormat) {
28
+        pbFormat = CoTaskMemAlloc(src->cbFormat);
29
+        if (!pbFormat)
30
+            return E_OUTOFMEMORY;
31
+        memcpy(pbFormat, src->pbFormat, src->cbFormat);
32
+    }
33
+
34
+    *dst = *src;
35
+    dst->pUnk = NULL;
36
+    dst->pbFormat = pbFormat;
37
+
38
+    return S_OK;
39
+}
40
+
41
+void ff_printGUID(const GUID *g)
42
+{
43
+#if DSHOWDEBUG
44
+    const uint32_t *d = (const uint32_t *) &g->Data1;
45
+    const uint16_t *w = (const uint16_t *) &g->Data2;
46
+    const uint8_t  *c = (const uint8_t  *) &g->Data4;
47
+
48
+    dshowdebug("0x%08x 0x%04x 0x%04x %02x%02x%02x%02x%02x%02x%02x%02x",
49
+               d[0], w[0], w[1],
50
+               c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
51
+#endif
52
+}
53
+
54
+static const char *dshow_context_to_name(void *ptr)
55
+{
56
+    return "dshow";
57
+}
58
+static const AVClass ff_dshow_context_class = { "DirectShow", dshow_context_to_name };
59
+const AVClass *ff_dshow_context_class_ptr = &ff_dshow_context_class;
60
+
61
+#define dstruct(pctx, sname, var, type) \
62
+    dshowdebug("      "#var":\t%"type"\n", sname->var)
63
+
64
+#if DSHOWDEBUG
65
+static void dump_bih(void *s, BITMAPINFOHEADER *bih)
66
+{
67
+    dshowdebug("      BITMAPINFOHEADER\n");
68
+    dstruct(s, bih, biSize, "lu");
69
+    dstruct(s, bih, biWidth, "ld");
70
+    dstruct(s, bih, biHeight, "ld");
71
+    dstruct(s, bih, biPlanes, "d");
72
+    dstruct(s, bih, biBitCount, "d");
73
+    dstruct(s, bih, biCompression, "lu");
74
+    dshowdebug("      biCompression:\t\"%.4s\"\n",
75
+                   (char*) &bih->biCompression);
76
+    dstruct(s, bih, biSizeImage, "lu");
77
+    dstruct(s, bih, biXPelsPerMeter, "lu");
78
+    dstruct(s, bih, biYPelsPerMeter, "lu");
79
+    dstruct(s, bih, biClrUsed, "lu");
80
+    dstruct(s, bih, biClrImportant, "lu");
81
+}
82
+#endif
83
+
84
+void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
85
+{
86
+#if DSHOWDEBUG
87
+    dshowdebug("    majortype\t");
88
+    ff_printGUID(&type->majortype);
89
+    dshowdebug("\n");
90
+    dshowdebug("    subtype\t");
91
+    ff_printGUID(&type->subtype);
92
+    dshowdebug("\n");
93
+    dshowdebug("    bFixedSizeSamples\t%d\n", type->bFixedSizeSamples);
94
+    dshowdebug("    bTemporalCompression\t%d\n", type->bTemporalCompression);
95
+    dshowdebug("    lSampleSize\t%lu\n", type->lSampleSize);
96
+    dshowdebug("    formattype\t");
97
+    ff_printGUID(&type->formattype);
98
+    dshowdebug("\n");
99
+    dshowdebug("    pUnk\t%p\n", type->pUnk);
100
+    dshowdebug("    cbFormat\t%lu\n", type->cbFormat);
101
+    dshowdebug("    pbFormat\t%p\n", type->pbFormat);
102
+
103
+    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
104
+        VIDEOINFOHEADER *v = (void *) type->pbFormat;
105
+        dshowdebug("      rcSource: left %ld top %ld right %ld bottom %ld\n",
106
+                   v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
107
+        dshowdebug("      rcTarget: left %ld top %ld right %ld bottom %ld\n",
108
+                   v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
109
+        dshowdebug("      dwBitRate: %lu\n", v->dwBitRate);
110
+        dshowdebug("      dwBitErrorRate: %lu\n", v->dwBitErrorRate);
111
+        dshowdebug("      AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
112
+        dump_bih(NULL, &v->bmiHeader);
113
+    } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
114
+        VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
115
+        dshowdebug("      rcSource: left %ld top %ld right %ld bottom %ld\n",
116
+                   v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
117
+        dshowdebug("      rcTarget: left %ld top %ld right %ld bottom %ld\n",
118
+                   v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
119
+        dshowdebug("      dwBitRate: %lu\n", v->dwBitRate);
120
+        dshowdebug("      dwBitErrorRate: %lu\n", v->dwBitErrorRate);
121
+        dshowdebug("      AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
122
+        dshowdebug("      dwInterlaceFlags: %lu\n", v->dwInterlaceFlags);
123
+        dshowdebug("      dwCopyProtectFlags: %lu\n", v->dwCopyProtectFlags);
124
+        dshowdebug("      dwPictAspectRatioX: %lu\n", v->dwPictAspectRatioX);
125
+        dshowdebug("      dwPictAspectRatioY: %lu\n", v->dwPictAspectRatioY);
126
+//        dshowdebug("      dwReserved1: %lu\n", v->u.dwReserved1); /* mingw-w64 is buggy and doesn't name unnamed unions */
127
+        dshowdebug("      dwReserved2: %lu\n", v->dwReserved2);
128
+        dump_bih(NULL, &v->bmiHeader);
129
+    } else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
130
+        WAVEFORMATEX *fx = (void *) type->pbFormat;
131
+        dshowdebug("      wFormatTag: %u\n", fx->wFormatTag);
132
+        dshowdebug("      nChannels: %u\n", fx->nChannels);
133
+        dshowdebug("      nSamplesPerSec: %lu\n", fx->nSamplesPerSec);
134
+        dshowdebug("      nAvgBytesPerSec: %lu\n", fx->nAvgBytesPerSec);
135
+        dshowdebug("      nBlockAlign: %u\n", fx->nBlockAlign);
136
+        dshowdebug("      wBitsPerSample: %u\n", fx->wBitsPerSample);
137
+        dshowdebug("      cbSize: %u\n", fx->cbSize);
138
+    }
139
+#endif
140
+}
0 141
new file mode 100644
... ...
@@ -0,0 +1,103 @@
0
+/*
1
+ * DirectShow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "dshow.h"
22
+
23
+DECLARE_QUERYINTERFACE(libAVEnumMediaTypes,
24
+    { {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
25
+DECLARE_ADDREF(libAVEnumMediaTypes)
26
+DECLARE_RELEASE(libAVEnumMediaTypes)
27
+
28
+long WINAPI
29
+libAVEnumMediaTypes_Next(libAVEnumMediaTypes *this, unsigned long n,
30
+                         AM_MEDIA_TYPE **types, unsigned long *fetched)
31
+{
32
+    int count = 0;
33
+    dshowdebug("libAVEnumMediaTypes_Next(%p)\n", this);
34
+    if (!types)
35
+        return E_POINTER;
36
+    if (!this->pos && n == 1) {
37
+        if (!IsEqualGUID(&this->type.majortype, &GUID_NULL)) {
38
+            AM_MEDIA_TYPE *type = av_malloc(sizeof(AM_MEDIA_TYPE));
39
+            ff_copy_dshow_media_type(type, &this->type);
40
+            *types = type;
41
+            count = 1;
42
+        }
43
+        this->pos = 1;
44
+    }
45
+    if (fetched)
46
+        *fetched = count;
47
+    if (!count)
48
+        return S_FALSE;
49
+    return S_OK;
50
+}
51
+long WINAPI
52
+libAVEnumMediaTypes_Skip(libAVEnumMediaTypes *this, unsigned long n)
53
+{
54
+    dshowdebug("libAVEnumMediaTypes_Skip(%p)\n", this);
55
+    if (n) /* Any skip will always fall outside of the only valid type. */
56
+        return S_FALSE;
57
+    return S_OK;
58
+}
59
+long WINAPI
60
+libAVEnumMediaTypes_Reset(libAVEnumMediaTypes *this)
61
+{
62
+    dshowdebug("libAVEnumMediaTypes_Reset(%p)\n", this);
63
+    this->pos = 0;
64
+    return S_OK;
65
+}
66
+long WINAPI
67
+libAVEnumMediaTypes_Clone(libAVEnumMediaTypes *this, libAVEnumMediaTypes **enums)
68
+{
69
+    libAVEnumMediaTypes *new;
70
+    dshowdebug("libAVEnumMediaTypes_Clone(%p)\n", this);
71
+    if (!enums)
72
+        return E_POINTER;
73
+    new = libAVEnumMediaTypes_Create(&this->type);
74
+    if (!new)
75
+        return E_OUTOFMEMORY;
76
+    new->pos = this->pos;
77
+    *enums = new;
78
+    return S_OK;
79
+}
80
+
81
+static int
82
+libAVEnumMediaTypes_Setup(libAVEnumMediaTypes *this, const AM_MEDIA_TYPE *type)
83
+{
84
+    IEnumPinsVtbl *vtbl = this->vtbl;
85
+    SETVTBL(vtbl, libAVEnumMediaTypes, QueryInterface);
86
+    SETVTBL(vtbl, libAVEnumMediaTypes, AddRef);
87
+    SETVTBL(vtbl, libAVEnumMediaTypes, Release);
88
+    SETVTBL(vtbl, libAVEnumMediaTypes, Next);
89
+    SETVTBL(vtbl, libAVEnumMediaTypes, Skip);
90
+    SETVTBL(vtbl, libAVEnumMediaTypes, Reset);
91
+    SETVTBL(vtbl, libAVEnumMediaTypes, Clone);
92
+
93
+    if (!type) {
94
+        this->type.majortype = GUID_NULL;
95
+    } else {
96
+        ff_copy_dshow_media_type(&this->type, type);
97
+    }
98
+
99
+    return 1;
100
+}
101
+DECLARE_CREATE(libAVEnumMediaTypes, libAVEnumMediaTypes_Setup(this, type), const AM_MEDIA_TYPE *type)
102
+DECLARE_DESTROY(libAVEnumMediaTypes, nothing)
0 103
new file mode 100644
... ...
@@ -0,0 +1,99 @@
0
+/*
1
+ * DirectShow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "dshow.h"
22
+
23
+DECLARE_QUERYINTERFACE(libAVEnumPins,
24
+    { {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
25
+DECLARE_ADDREF(libAVEnumPins)
26
+DECLARE_RELEASE(libAVEnumPins)
27
+
28
+long WINAPI
29
+libAVEnumPins_Next(libAVEnumPins *this, unsigned long n, IPin **pins,
30
+                   unsigned long *fetched)
31
+{
32
+    int count = 0;
33
+    dshowdebug("libAVEnumPins_Next(%p)\n", this);
34
+    if (!pins)
35
+        return E_POINTER;
36
+    if (!this->pos && n == 1) {
37
+        libAVPin_AddRef(this->pin);
38
+        *pins = (IPin *) this->pin;
39
+        count = 1;
40
+        this->pos = 1;
41
+    }
42
+    if (fetched)
43
+        *fetched = count;
44
+    if (!count)
45
+        return S_FALSE;
46
+    return S_OK;
47
+}
48
+long WINAPI
49
+libAVEnumPins_Skip(libAVEnumPins *this, unsigned long n)
50
+{
51
+    dshowdebug("libAVEnumPins_Skip(%p)\n", this);
52
+    if (n) /* Any skip will always fall outside of the only valid pin. */
53
+        return S_FALSE;
54
+    return S_OK;
55
+}
56
+long WINAPI
57
+libAVEnumPins_Reset(libAVEnumPins *this)
58
+{
59
+    dshowdebug("libAVEnumPins_Reset(%p)\n", this);
60
+    this->pos = 0;
61
+    return S_OK;
62
+}
63
+long WINAPI
64
+libAVEnumPins_Clone(libAVEnumPins *this, libAVEnumPins **pins)
65
+{
66
+    libAVEnumPins *new;
67
+    dshowdebug("libAVEnumPins_Clone(%p)\n", this);
68
+    if (!pins)
69
+        return E_POINTER;
70
+    new = libAVEnumPins_Create(this->pin, this->filter);
71
+    if (!new)
72
+        return E_OUTOFMEMORY;
73
+    new->pos = this->pos;
74
+    *pins = new;
75
+    return S_OK;
76
+}
77
+
78
+static int
79
+libAVEnumPins_Setup(libAVEnumPins *this, libAVPin *pin, libAVFilter *filter)
80
+{
81
+    IEnumPinsVtbl *vtbl = this->vtbl;
82
+    SETVTBL(vtbl, libAVEnumPins, QueryInterface);
83
+    SETVTBL(vtbl, libAVEnumPins, AddRef);
84
+    SETVTBL(vtbl, libAVEnumPins, Release);
85
+    SETVTBL(vtbl, libAVEnumPins, Next);
86
+    SETVTBL(vtbl, libAVEnumPins, Skip);
87
+    SETVTBL(vtbl, libAVEnumPins, Reset);
88
+    SETVTBL(vtbl, libAVEnumPins, Clone);
89
+
90
+    this->pin = pin;
91
+    this->filter = filter;
92
+    libAVFilter_AddRef(this->filter);
93
+
94
+    return 1;
95
+}
96
+DECLARE_CREATE(libAVEnumPins, libAVEnumPins_Setup(this, pin, filter),
97
+               libAVPin *pin, libAVFilter *filter)
98
+DECLARE_DESTROY(libAVEnumPins, nothing)
0 99
new file mode 100644
... ...
@@ -0,0 +1,196 @@
0
+/*
1
+ * DirectShow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "dshow.h"
22
+
23
+DECLARE_QUERYINTERFACE(libAVFilter,
24
+    { {&IID_IUnknown,0}, {&IID_IBaseFilter,0} })
25
+DECLARE_ADDREF(libAVFilter)
26
+DECLARE_RELEASE(libAVFilter)
27
+
28
+long WINAPI
29
+libAVFilter_GetClassID(libAVFilter *this, CLSID *id)
30
+{
31
+    dshowdebug("libAVFilter_GetClassID(%p)\n", this);
32
+    /* I'm not creating a ClassID just for this. */
33
+    return E_FAIL;
34
+}
35
+long WINAPI
36
+libAVFilter_Stop(libAVFilter *this)
37
+{
38
+    dshowdebug("libAVFilter_Stop(%p)\n", this);
39
+    this->state = State_Stopped;
40
+    return S_OK;
41
+}
42
+long WINAPI
43
+libAVFilter_Pause(libAVFilter *this)
44
+{
45
+    dshowdebug("libAVFilter_Pause(%p)\n", this);
46
+    this->state = State_Paused;
47
+    return S_OK;
48
+}
49
+long WINAPI
50
+libAVFilter_Run(libAVFilter *this, REFERENCE_TIME start)
51
+{
52
+    dshowdebug("libAVFilter_Run(%p) %"PRId64"\n", this, start);
53
+    this->state = State_Running;
54
+    this->start_time = start;
55
+    return S_OK;
56
+}
57
+long WINAPI
58
+libAVFilter_GetState(libAVFilter *this, DWORD ms, FILTER_STATE *state)
59
+{
60
+    dshowdebug("libAVFilter_GetState(%p)\n", this);
61
+    if (!state)
62
+        return E_POINTER;
63
+    *state = this->state;
64
+    return S_OK;
65
+}
66
+long WINAPI
67
+libAVFilter_SetSyncSource(libAVFilter *this, IReferenceClock *clock)
68
+{
69
+    dshowdebug("libAVFilter_SetSyncSource(%p)\n", this);
70
+
71
+    if (this->clock != clock) {
72
+        if (this->clock)
73
+            IReferenceClock_Release(this->clock);
74
+        this->clock = clock;
75
+        if (clock)
76
+            IReferenceClock_AddRef(clock);
77
+    }
78
+
79
+    return S_OK;
80
+}
81
+long WINAPI
82
+libAVFilter_GetSyncSource(libAVFilter *this, IReferenceClock **clock)
83
+{
84
+    dshowdebug("libAVFilter_GetSyncSource(%p)\n", this);
85
+
86
+    if (!clock)
87
+        return E_POINTER;
88
+    if (this->clock)
89
+        IReferenceClock_AddRef(this->clock);
90
+    *clock = this->clock;
91
+
92
+    return S_OK;
93
+}
94
+long WINAPI
95
+libAVFilter_EnumPins(libAVFilter *this, IEnumPins **enumpin)
96
+{
97
+    libAVEnumPins *new;
98
+    dshowdebug("libAVFilter_EnumPins(%p)\n", this);
99
+
100
+    if (!enumpin)
101
+        return E_POINTER;
102
+    new = libAVEnumPins_Create(this->pin, this);
103
+    if (!new)
104
+        return E_OUTOFMEMORY;
105
+
106
+    *enumpin = (IEnumPins *) new;
107
+    return S_OK;
108
+}
109
+long WINAPI
110
+libAVFilter_FindPin(libAVFilter *this, const wchar_t *id, IPin **pin)
111
+{
112
+    libAVPin *found = NULL;
113
+    dshowdebug("libAVFilter_FindPin(%p)\n", this);
114
+
115
+    if (!id || !pin)
116
+        return E_POINTER;
117
+    if (!wcscmp(id, L"In")) {
118
+        found = this->pin;
119
+        libAVPin_AddRef(found);
120
+    }
121
+    *pin = (IPin *) found;
122
+    if (!found)
123
+        return VFW_E_NOT_FOUND;
124
+
125
+    return S_OK;
126
+}
127
+long WINAPI
128
+libAVFilter_QueryFilterInfo(libAVFilter *this, FILTER_INFO *info)
129
+{
130
+    dshowdebug("libAVFilter_QueryFilterInfo(%p)\n", this);
131
+
132
+    if (!info)
133
+        return E_POINTER;
134
+    if (this->info.pGraph)
135
+        IFilterGraph_AddRef(this->info.pGraph);
136
+    *info = this->info;
137
+
138
+    return S_OK;
139
+}
140
+long WINAPI
141
+libAVFilter_JoinFilterGraph(libAVFilter *this, IFilterGraph *graph,
142
+                            const wchar_t *name)
143
+{
144
+    dshowdebug("libAVFilter_JoinFilterGraph(%p)\n", this);
145
+
146
+    this->info.pGraph = graph;
147
+    if (name)
148
+        wcscpy(this->info.achName, name);
149
+
150
+    return S_OK;
151
+}
152
+long WINAPI
153
+libAVFilter_QueryVendorInfo(libAVFilter *this, wchar_t **info)
154
+{
155
+    dshowdebug("libAVFilter_QueryVendorInfo(%p)\n", this);
156
+
157
+    if (!info)
158
+        return E_POINTER;
159
+    *info = wcsdup(L"libAV");
160
+
161
+    return S_OK;
162
+}
163
+
164
+static int
165
+libAVFilter_Setup(libAVFilter *this, void *priv_data, void *callback,
166
+                  enum dshowDeviceType type)
167
+{
168
+    IBaseFilterVtbl *vtbl = this->vtbl;
169
+    SETVTBL(vtbl, libAVFilter, QueryInterface);
170
+    SETVTBL(vtbl, libAVFilter, AddRef);
171
+    SETVTBL(vtbl, libAVFilter, Release);
172
+    SETVTBL(vtbl, libAVFilter, GetClassID);
173
+    SETVTBL(vtbl, libAVFilter, Stop);
174
+    SETVTBL(vtbl, libAVFilter, Pause);
175
+    SETVTBL(vtbl, libAVFilter, Run);
176
+    SETVTBL(vtbl, libAVFilter, GetState);
177
+    SETVTBL(vtbl, libAVFilter, SetSyncSource);
178
+    SETVTBL(vtbl, libAVFilter, GetSyncSource);
179
+    SETVTBL(vtbl, libAVFilter, EnumPins);
180
+    SETVTBL(vtbl, libAVFilter, FindPin);
181
+    SETVTBL(vtbl, libAVFilter, QueryFilterInfo);
182
+    SETVTBL(vtbl, libAVFilter, JoinFilterGraph);
183
+    SETVTBL(vtbl, libAVFilter, QueryVendorInfo);
184
+
185
+    this->pin = libAVPin_Create(this);
186
+
187
+    this->priv_data = priv_data;
188
+    this->callback  = callback;
189
+    this->type      = type;
190
+
191
+    return 1;
192
+}
193
+DECLARE_CREATE(libAVFilter, libAVFilter_Setup(this, priv_data, callback, type),
194
+               void *priv_data, void *callback, enum dshowDeviceType type)
195
+DECLARE_DESTROY(libAVFilter, nothing)
0 196
new file mode 100644
... ...
@@ -0,0 +1,361 @@
0
+/*
1
+ * DirectShow capture interface
2
+ * Copyright (c) 2010 Ramiro Polla
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+#include "dshow.h"
22
+
23
+#include <stddef.h>
24
+#define imemoffset offsetof(libAVPin, imemvtbl)
25
+
26
+DECLARE_QUERYINTERFACE(libAVPin,
27
+    { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
28
+DECLARE_ADDREF(libAVPin)
29
+DECLARE_RELEASE(libAVPin)
30
+
31
+long WINAPI
32
+libAVPin_Connect(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
33
+{
34
+    dshowdebug("libAVPin_Connect(%p, %p, %p)\n", this, pin, type);
35
+    /* Input pins receive connections. */
36
+    return S_FALSE;
37
+}
38
+long WINAPI
39
+libAVPin_ReceiveConnection(libAVPin *this, IPin *pin,
40
+                           const AM_MEDIA_TYPE *type)
41
+{
42
+    enum dshowDeviceType devtype = this->filter->type;
43
+    dshowdebug("libAVPin_ReceiveConnection(%p)\n", this);
44
+
45
+    if (!pin)
46
+        return E_POINTER;
47
+    if (this->connectedto)
48
+        return VFW_E_ALREADY_CONNECTED;
49
+
50
+    ff_print_AM_MEDIA_TYPE(type);
51
+    if (devtype == VideoDevice) {
52
+        if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
53
+            return VFW_E_TYPE_NOT_ACCEPTED;
54
+    } else {
55
+        if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
56
+            return VFW_E_TYPE_NOT_ACCEPTED;
57
+    }
58
+
59
+    IPin_AddRef(pin);
60
+    this->connectedto = pin;
61
+
62
+    ff_copy_dshow_media_type(&this->type, type);
63
+
64
+    return S_OK;
65
+}
66
+long WINAPI
67
+libAVPin_Disconnect(libAVPin *this)
68
+{
69
+    dshowdebug("libAVPin_Disconnect(%p)\n", this);
70
+
71
+    if (this->filter->state != State_Stopped)
72
+        return VFW_E_NOT_STOPPED;
73
+    if (!this->connectedto)
74
+        return S_FALSE;
75
+    this->connectedto = NULL;
76
+
77
+    return S_OK;
78
+}
79
+long WINAPI
80
+libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
81
+{
82
+    dshowdebug("libAVPin_ConnectedTo(%p)\n", this);
83
+
84
+    if (!pin)
85
+        return E_POINTER;
86
+    if (!this->connectedto)
87
+        return VFW_E_NOT_CONNECTED;
88
+    IPin_AddRef(this->connectedto);
89
+    *pin = this->connectedto;
90
+
91
+    return S_OK;
92
+}
93
+long WINAPI
94
+libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
95
+{
96
+    dshowdebug("libAVPin_ConnectionMediaType(%p)\n", this);
97
+
98
+    if (!type)
99
+        return E_POINTER;
100
+    if (!this->connectedto)
101
+        return VFW_E_NOT_CONNECTED;
102
+
103
+    return ff_copy_dshow_media_type(type, &this->type);
104
+}
105
+long WINAPI
106
+libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
107
+{
108
+    dshowdebug("libAVPin_QueryPinInfo(%p)\n", this);
109
+
110
+    if (!info)
111
+        return E_POINTER;
112
+
113
+    if (this->filter)
114
+        libAVFilter_AddRef(this->filter);
115
+
116
+    info->pFilter = (IBaseFilter *) this->filter;
117
+    info->dir     = PINDIR_INPUT;
118
+    wcscpy(info->achName, L"Capture");
119
+
120
+    return S_OK;
121
+}
122
+long WINAPI
123
+libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
124
+{
125
+    dshowdebug("libAVPin_QueryDirection(%p)\n", this);
126
+    if (!dir)
127
+        return E_POINTER;
128
+    *dir = PINDIR_INPUT;
129
+    return S_OK;
130
+}
131
+long WINAPI
132
+libAVPin_QueryId(libAVPin *this, wchar_t **id)
133
+{
134
+    dshowdebug("libAVPin_QueryId(%p)\n", this);
135
+
136
+    if (!id)
137
+        return E_POINTER;
138
+
139
+    *id = wcsdup(L"libAV Pin");
140
+
141
+    return S_OK;
142
+}
143
+long WINAPI
144
+libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
145
+{
146
+    dshowdebug("libAVPin_QueryAccept(%p)\n", this);
147
+    return S_FALSE;
148
+}
149
+long WINAPI
150
+libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
151
+{
152
+    const AM_MEDIA_TYPE *type = NULL;
153
+    libAVEnumMediaTypes *new;
154
+    dshowdebug("libAVPin_EnumMediaTypes(%p)\n", this);
155
+
156
+    if (!enumtypes)
157
+        return E_POINTER;
158
+    new = libAVEnumMediaTypes_Create(type);
159
+    if (!new)
160
+        return E_OUTOFMEMORY;
161
+
162
+    *enumtypes = (IEnumMediaTypes *) new;
163
+    return S_OK;
164
+}
165
+long WINAPI
166
+libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin,
167
+                                  unsigned long *npin)
168
+{
169
+    dshowdebug("libAVPin_QueryInternalConnections(%p)\n", this);
170
+    return E_NOTIMPL;
171
+}
172
+long WINAPI
173
+libAVPin_EndOfStream(libAVPin *this)
174
+{
175
+    dshowdebug("libAVPin_EndOfStream(%p)\n", this);
176
+    /* I don't care. */
177
+    return S_OK;
178
+}
179
+long WINAPI
180
+libAVPin_BeginFlush(libAVPin *this)
181
+{
182
+    dshowdebug("libAVPin_BeginFlush(%p)\n", this);
183
+    /* I don't care. */
184
+    return S_OK;
185
+}
186
+long WINAPI
187
+libAVPin_EndFlush(libAVPin *this)
188
+{
189
+    dshowdebug("libAVPin_EndFlush(%p)\n", this);
190
+    /* I don't care. */
191
+    return S_OK;
192
+}
193
+long WINAPI
194
+libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
195
+                    double rate)
196
+{
197
+    dshowdebug("libAVPin_NewSegment(%p)\n", this);
198
+    /* I don't care. */
199
+    return S_OK;
200
+}
201
+
202
+static int
203
+libAVPin_Setup(libAVPin *this, libAVFilter *filter)
204
+{
205
+    IPinVtbl *vtbl = this->vtbl;
206
+    IMemInputPinVtbl *imemvtbl;
207
+
208
+    if (!filter)
209
+        return 0;
210
+
211
+    imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
212
+    if (!imemvtbl)
213
+        return 0;
214
+
215
+    SETVTBL(imemvtbl, libAVMemInputPin, QueryInterface);
216
+    SETVTBL(imemvtbl, libAVMemInputPin, AddRef);
217
+    SETVTBL(imemvtbl, libAVMemInputPin, Release);
218
+    SETVTBL(imemvtbl, libAVMemInputPin, GetAllocator);
219
+    SETVTBL(imemvtbl, libAVMemInputPin, NotifyAllocator);
220
+    SETVTBL(imemvtbl, libAVMemInputPin, GetAllocatorRequirements);
221
+    SETVTBL(imemvtbl, libAVMemInputPin, Receive);
222
+    SETVTBL(imemvtbl, libAVMemInputPin, ReceiveMultiple);
223
+    SETVTBL(imemvtbl, libAVMemInputPin, ReceiveCanBlock);
224
+
225
+    this->imemvtbl = imemvtbl;
226
+
227
+    SETVTBL(vtbl, libAVPin, QueryInterface);
228
+    SETVTBL(vtbl, libAVPin, AddRef);
229
+    SETVTBL(vtbl, libAVPin, Release);
230
+    SETVTBL(vtbl, libAVPin, Connect);
231
+    SETVTBL(vtbl, libAVPin, ReceiveConnection);
232
+    SETVTBL(vtbl, libAVPin, Disconnect);
233
+    SETVTBL(vtbl, libAVPin, ConnectedTo);
234
+    SETVTBL(vtbl, libAVPin, ConnectionMediaType);
235
+    SETVTBL(vtbl, libAVPin, QueryPinInfo);
236
+    SETVTBL(vtbl, libAVPin, QueryDirection);
237
+    SETVTBL(vtbl, libAVPin, QueryId);
238
+    SETVTBL(vtbl, libAVPin, QueryAccept);
239
+    SETVTBL(vtbl, libAVPin, EnumMediaTypes);
240
+    SETVTBL(vtbl, libAVPin, QueryInternalConnections);
241
+    SETVTBL(vtbl, libAVPin, EndOfStream);
242
+    SETVTBL(vtbl, libAVPin, BeginFlush);
243
+    SETVTBL(vtbl, libAVPin, EndFlush);
244
+    SETVTBL(vtbl, libAVPin, NewSegment);
245
+
246
+    this->filter = filter;
247
+
248
+    return 1;
249
+}
250
+DECLARE_CREATE(libAVPin, libAVPin_Setup(this, filter), libAVFilter *filter)
251
+DECLARE_DESTROY(libAVPin, nothing)
252
+
253
+/*****************************************************************************
254
+ * libAVMemInputPin
255
+ ****************************************************************************/
256
+long WINAPI
257
+libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid,
258
+                                void **ppvObject)
259
+{
260
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
261
+    dshowdebug("libAVMemInputPin_QueryInterface(%p)\n", this);
262
+    return libAVPin_QueryInterface(pin, riid, ppvObject);
263
+}
264
+unsigned long WINAPI
265
+libAVMemInputPin_AddRef(libAVMemInputPin *this)
266
+{
267
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
268
+    dshowdebug("libAVMemInputPin_AddRef(%p)\n", this);
269
+    return libAVPin_AddRef(pin);
270
+}
271
+unsigned long WINAPI
272
+libAVMemInputPin_Release(libAVMemInputPin *this)
273
+{
274
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
275
+    dshowdebug("libAVMemInputPin_Release(%p)\n", this);
276
+    return libAVPin_Release(pin);
277
+}
278
+long WINAPI
279
+libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
280
+{
281
+    dshowdebug("libAVMemInputPin_GetAllocator(%p)\n", this);
282
+    return VFW_E_NO_ALLOCATOR;
283
+}
284
+long WINAPI
285
+libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc,
286
+                                 WINBOOL rdwr)
287
+{
288
+    dshowdebug("libAVMemInputPin_NotifyAllocator(%p)\n", this);
289
+    return S_OK;
290
+}
291
+long WINAPI
292
+libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this,
293
+                                          ALLOCATOR_PROPERTIES *props)
294
+{
295
+    dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this);
296
+    return E_NOTIMPL;
297
+}
298
+long WINAPI
299
+libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
300
+{
301
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
302
+    enum dshowDeviceType devtype = pin->filter->type;
303
+    void *priv_data;
304
+    uint8_t *buf;
305
+    int buf_size;
306
+    int index;
307
+    int64_t curtime;
308
+
309
+    dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
310
+
311
+    if (!sample)
312
+        return E_POINTER;
313
+
314
+    if (devtype == VideoDevice) {
315
+        /* PTS from video devices is unreliable. */
316
+        IReferenceClock *clock = pin->filter->clock;
317
+        IReferenceClock_GetTime(clock, &curtime);
318
+    } else {
319
+        int64_t dummy;
320
+        IMediaSample_GetTime(sample, &curtime, &dummy);
321
+        curtime += pin->filter->start_time;
322
+    }
323
+
324
+    buf_size = IMediaSample_GetActualDataLength(sample);
325
+    IMediaSample_GetPointer(sample, &buf);
326
+    priv_data = pin->filter->priv_data;
327
+    index = pin->filter->stream_index;
328
+
329
+    pin->filter->callback(priv_data, index, buf, buf_size, curtime);
330
+
331
+    return S_OK;
332
+}
333
+long WINAPI
334
+libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this,
335
+                                 IMediaSample **samples, long n, long *nproc)
336
+{
337
+    int i;
338
+    dshowdebug("libAVMemInputPin_ReceiveMultiple(%p)\n", this);
339
+
340
+    for (i = 0; i < n; i++)
341
+        libAVMemInputPin_Receive(this, samples[i]);
342
+
343
+    *nproc = n;
344
+    return S_OK;
345
+}
346
+long WINAPI
347
+libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
348
+{
349
+    dshowdebug("libAVMemInputPin_ReceiveCanBlock(%p)\n", this);
350
+    /* I swear I will not block. */
351
+    return S_FALSE;
352
+}
353
+
354
+void
355
+libAVMemInputPin_Destroy(libAVMemInputPin *this)
356
+{
357
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
358
+    dshowdebug("libAVMemInputPin_Destroy(%p)\n", this);
359
+    return libAVPin_Destroy(pin);
360
+}
... ...
@@ -29,8 +29,6 @@
29 29
  * Remove this when MinGW incorporates them. */
30 30
 #define HWND_MESSAGE                ((HWND)-3)
31 31
 
32
-#define BI_RGB                      0
33
-
34 32
 /* End of missing MinGW defines */
35 33
 
36 34
 struct vfw_ctx {