DirectShow capture support
authorRamiro Polla <ramiro.polla@gmail.com>
Sat, 21 May 2011 12:24:50 +0000 (14:24 +0200)
committerMichael Niedermayer <michaelni@gmx.at>
Sat, 21 May 2011 15:23:14 +0000 (17:23 +0200)
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
configure
libavdevice/Makefile
libavdevice/alldevices.c
libavdevice/dshow.c [new file with mode: 0644]
libavdevice/dshow.h [new file with mode: 0644]
libavdevice/dshow_common.c [new file with mode: 0644]
libavdevice/dshow_enummediatypes.c [new file with mode: 0644]
libavdevice/dshow_enumpins.c [new file with mode: 0644]
libavdevice/dshow_filter.c [new file with mode: 0644]
libavdevice/dshow_pin.c [new file with mode: 0644]
libavdevice/vfwcap.c

index c41a949..701d7e9 100755 (executable)
--- a/configure
+++ b/configure
@@ -1463,6 +1463,8 @@ w64_demuxer_deps="wav_demuxer"
 alsa_indev_deps="alsa_asoundlib_h snd_pcm_htimestamp"
 alsa_outdev_deps="alsa_asoundlib_h"
 bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h"
+dshow_indev_deps="IBaseFilter"
+dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid"
 dv1394_indev_deps="dv1394 dv_demuxer"
 fbdev_indev_deps="linux_fb_h"
 jack_indev_deps="jack_jack_h sem_timedwait"
@@ -2979,6 +2981,8 @@ check_func_headers "windows.h vfw.h" capCreateCaptureWindow "$vfwcap_indev_extra
 # w32api 3.12 had it defined wrong
 check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_defines
 
+check_type "dshow.h" IBaseFilter
+
 # check for ioctl_meteor.h, ioctl_bt848.h and alternatives
 { check_header dev/bktr/ioctl_meteor.h &&
   check_header dev/bktr/ioctl_bt848.h; } ||
index 5cfc5e8..4bcb5a3 100644 (file)
@@ -13,6 +13,9 @@ OBJS-$(CONFIG_ALSA_INDEV)                += alsa-audio-common.o \
 OBJS-$(CONFIG_ALSA_OUTDEV)               += alsa-audio-common.o \
                                             alsa-audio-enc.o
 OBJS-$(CONFIG_BKTR_INDEV)                += bktr.o
+OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \
+                                            dshow_enumpins.o dshow_filter.o \
+                                            dshow_pin.o dshow_common.o
 OBJS-$(CONFIG_DV1394_INDEV)              += dv1394.o
 OBJS-$(CONFIG_FBDEV_INDEV)               += fbdev.o
 OBJS-$(CONFIG_JACK_INDEV)                += jack_audio.o
index a0c9b08..3997c73 100644 (file)
@@ -41,6 +41,7 @@ void avdevice_register_all(void)
     /* devices */
     REGISTER_INOUTDEV (ALSA, alsa);
     REGISTER_INDEV    (BKTR, bktr);
+    REGISTER_INDEV    (DSHOW, dshow);
     REGISTER_INDEV    (DV1394, dv1394);
     REGISTER_INDEV    (FBDEV, fbdev);
     REGISTER_INDEV    (JACK, jack);
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c
new file mode 100644 (file)
index 0000000..ef21af7
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ * Directshow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "libavformat/avformat.h"
+#include "libavformat/timefilter.h"
+
+#include "dshow.h"
+
+struct dshow_ctx {
+    IGraphBuilder *graph;
+
+    char *device_name[2];
+
+    IBaseFilter *device_filter[2];
+    IPin        *device_pin[2];
+    libAVFilter *capture_filter[2];
+    libAVPin    *capture_pin[2];
+
+    HANDLE mutex;
+    HANDLE event;
+    AVPacketList *pktl;
+
+    unsigned int curbufsize;
+    unsigned int video_frame_num;
+
+    IMediaControl *control;
+
+    TimeFilter *timefilter;
+};
+
+static enum PixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
+{
+    switch(biCompression) {
+    case MKTAG('U', 'Y', 'V', 'Y'):
+        return PIX_FMT_UYVY422;
+    case MKTAG('Y', 'U', 'Y', '2'):
+        return PIX_FMT_YUYV422;
+    case MKTAG('I', '4', '2', '0'):
+        return PIX_FMT_YUV420P;
+    case BI_RGB:
+        switch(biBitCount) { /* 1-8 are untested */
+            case 1:
+                return PIX_FMT_MONOWHITE;
+            case 4:
+                return PIX_FMT_RGB4;
+            case 8:
+                return PIX_FMT_RGB8;
+            case 16:
+                return PIX_FMT_RGB555;
+            case 24:
+                return PIX_FMT_BGR24;
+            case 32:
+                return PIX_FMT_RGB32;
+        }
+    }
+    return PIX_FMT_NONE;
+}
+
+static enum CodecID dshow_codecid(DWORD biCompression)
+{
+    switch(biCompression) {
+    case MKTAG('d', 'v', 's', 'd'):
+        return CODEC_ID_DVVIDEO;
+    case MKTAG('M', 'J', 'P', 'G'):
+    case MKTAG('m', 'j', 'p', 'g'):
+        return CODEC_ID_MJPEG;
+    }
+    return CODEC_ID_NONE;
+}
+
+static int
+dshow_read_close(AVFormatContext *s)
+{
+    struct dshow_ctx *ctx = s->priv_data;
+    AVPacketList *pktl;
+
+    if (ctx->control) {
+        IMediaControl_Stop(ctx->control);
+        IMediaControl_Release(ctx->control);
+    }
+    if (ctx->graph)
+        IGraphBuilder_Release(ctx->graph);
+
+    /* FIXME remove filters from graph */
+    /* FIXME disconnect pins */
+    if (ctx->capture_pin[VideoDevice])
+        libAVPin_Release(ctx->capture_pin[VideoDevice]);
+    if (ctx->capture_pin[AudioDevice])
+        libAVPin_Release(ctx->capture_pin[AudioDevice]);
+    if (ctx->capture_filter[VideoDevice])
+        libAVFilter_Release(ctx->capture_filter[VideoDevice]);
+    if (ctx->capture_filter[AudioDevice])
+        libAVFilter_Release(ctx->capture_filter[AudioDevice]);
+
+    if (ctx->device_pin[VideoDevice])
+        IPin_Release(ctx->device_pin[VideoDevice]);
+    if (ctx->device_pin[AudioDevice])
+        IPin_Release(ctx->device_pin[AudioDevice]);
+    if (ctx->device_filter[VideoDevice])
+        IBaseFilter_Release(ctx->device_filter[VideoDevice]);
+    if (ctx->device_filter[AudioDevice])
+        IBaseFilter_Release(ctx->device_filter[AudioDevice]);
+
+    if (ctx->device_name[0])
+        av_free(ctx->device_name[0]);
+    if (ctx->device_name[1])
+        av_free(ctx->device_name[1]);
+
+    if(ctx->mutex)
+        CloseHandle(ctx->mutex);
+    if(ctx->event)
+        CloseHandle(ctx->event);
+
+    pktl = ctx->pktl;
+    while (pktl) {
+        AVPacketList *next = pktl->next;
+        av_destruct_packet(&pktl->pkt);
+        av_free(pktl);
+        pktl = next;
+    }
+
+    return 0;
+}
+
+static char *dup_wchar_to_utf8(wchar_t *w)
+{
+    char *s = NULL;
+    int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
+    s = av_malloc(l);
+    if (s)
+        WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
+    return s;
+}
+
+static int shall_we_drop(AVFormatContext *s)
+{
+    struct dshow_ctx *ctx = s->priv_data;
+    const uint8_t dropscore[] = {62, 75, 87, 100};
+    const int ndropscores = FF_ARRAY_ELEMS(dropscore);
+    unsigned int buffer_fullness = (ctx->curbufsize*100)/s->max_picture_buffer;
+
+    if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
+        av_log(s, AV_LOG_ERROR,
+              "real-time buffer %d%% full! frame dropped!\n", buffer_fullness);
+        return 1;
+    }
+
+    return 0;
+}
+
+static void
+callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time)
+{
+    AVFormatContext *s = priv_data;
+    struct dshow_ctx *ctx = s->priv_data;
+    AVPacketList **ppktl, *pktl_next;
+
+//    dump_videohdr(s, vdhdr);
+
+    if(shall_we_drop(s))
+        return;
+
+    WaitForSingleObject(ctx->mutex, INFINITE);
+
+    pktl_next = av_mallocz(sizeof(AVPacketList));
+    if(!pktl_next)
+        goto fail;
+
+    if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
+        av_free(pktl_next);
+        goto fail;
+    }
+
+    pktl_next->pkt.stream_index = index;
+    pktl_next->pkt.pts = time;
+    memcpy(pktl_next->pkt.data, buf, buf_size);
+
+    for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
+    *ppktl = pktl_next;
+
+    ctx->curbufsize += buf_size;
+
+    SetEvent(ctx->event);
+    ReleaseMutex(ctx->mutex);
+
+    return;
+fail:
+    ReleaseMutex(ctx->mutex);
+    return;
+}
+
+static int
+dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
+                  enum dshowDeviceType devtype)
+{
+    struct dshow_ctx *ctx = avctx->priv_data;
+    IBaseFilter *device_filter = NULL;
+    IEnumMoniker *classenum = NULL;
+    IGraphBuilder *graph = ctx->graph;
+    IEnumPins *pins = 0;
+    IMoniker *m = NULL;
+    IPin *device_pin = NULL;
+    libAVPin *capture_pin = NULL;
+    libAVFilter *capture_filter = NULL;
+    const char *device_name = ctx->device_name[devtype];
+    int ret = AVERROR(EIO);
+    IPin *pin;
+    int r, i;
+
+    const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
+                                   &CLSID_AudioInputDeviceCategory };
+    const GUID *mediatype[2] = { &MEDIATYPE_Video, &MEDIATYPE_Audio };
+    const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
+    const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
+
+    r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[devtype],
+                                             (IEnumMoniker **) &classenum, 0);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices.\n",
+               devtypename);
+        goto error;
+    }
+
+    while (IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK && !device_filter) {
+        IPropertyBag *bag = NULL;
+        char *buf = NULL;
+        VARIANT var;
+
+        r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
+        if (r != S_OK)
+            goto fail1;
+
+        var.vt = VT_BSTR;
+        r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
+        if (r != S_OK)
+            goto fail1;
+
+        buf = dup_wchar_to_utf8(var.bstrVal);
+
+        if (strcmp(device_name, buf))
+            goto fail1;
+
+        IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
+
+fail1:
+        if (buf)
+            av_free(buf);
+        if (bag)
+            IPropertyBag_Release(bag);
+        IMoniker_Release(m);
+    }
+
+    if (!device_filter) {
+        av_log(avctx, AV_LOG_ERROR, "Could not find %s device.\n",
+               devtypename);
+        goto error;
+    }
+    ctx->device_filter [devtype] = device_filter;
+
+    r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
+        goto error;
+    }
+
+    r = IBaseFilter_EnumPins(device_filter, &pins);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
+        goto error;
+    }
+
+    i = 0;
+    while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK && !device_pin) {
+        IKsPropertySet *p = NULL;
+        IEnumMediaTypes *types;
+        PIN_INFO info = {0};
+        AM_MEDIA_TYPE *type;
+        GUID category;
+        DWORD r2;
+
+        IPin_QueryPinInfo(pin, &info);
+        IBaseFilter_Release(info.pFilter);
+
+        if (info.dir != PINDIR_OUTPUT)
+            goto next;
+        if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
+            goto next;
+        if (IKsPropertySet_Get(p, &AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
+                               NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
+            goto next;
+        if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
+            goto next;
+
+        if (IPin_EnumMediaTypes(pin, &types) != S_OK)
+            goto next;
+
+        IEnumMediaTypes_Reset(types);
+        while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK && !device_pin) {
+            if (IsEqualGUID(&type->majortype, mediatype[devtype])) {
+                device_pin = pin;
+                goto next;
+            }
+            CoTaskMemFree(type);
+        }
+
+next:
+        if (types)
+            IEnumMediaTypes_Release(types);
+        if (p)
+            IKsPropertySet_Release(p);
+        if (device_pin != pin)
+            IPin_Release(pin);
+    }
+
+    if (!device_pin) {
+        av_log(avctx, AV_LOG_ERROR,
+               "Could not find output pin from %s capture device.\n", devtypename);
+        goto error;
+    }
+    ctx->device_pin[devtype] = device_pin;
+
+    capture_filter = libAVFilter_Create(avctx, callback, devtype);
+    if (!capture_filter) {
+        av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
+        goto error;
+    }
+    ctx->capture_filter[devtype] = capture_filter;
+
+    r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
+                                filter_name[devtype]);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
+        goto error;
+    }
+
+    libAVPin_AddRef(capture_filter->pin);
+    capture_pin = capture_filter->pin;
+    ctx->capture_pin[devtype] = capture_pin;
+
+    r = IGraphBuilder_ConnectDirect(graph, device_pin, (IPin *) capture_pin, NULL);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not connect pins\n");
+        goto error;
+    }
+
+    ret = 0;
+
+error:
+    if (pins)
+        IEnumPins_Release(pins);
+    if (classenum)
+        IEnumMoniker_Release(classenum);
+
+    return ret;
+}
+
+static enum CodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
+{
+    switch (sample_fmt) {
+    case AV_SAMPLE_FMT_U8:  return CODEC_ID_PCM_U8;
+    case AV_SAMPLE_FMT_S16: return CODEC_ID_PCM_S16LE;
+    case AV_SAMPLE_FMT_S32: return CODEC_ID_PCM_S32LE;
+    default:                return CODEC_ID_NONE; /* Should never happen. */
+    }
+}
+
+static enum SampleFormat sample_fmt_bits_per_sample(int bits)
+{
+    switch (bits) {
+    case 8:  return AV_SAMPLE_FMT_U8;
+    case 16: return AV_SAMPLE_FMT_S16;
+    case 32: return AV_SAMPLE_FMT_S32;
+    default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
+    }
+}
+
+static int
+dshow_add_device(AVFormatContext *avctx, AVFormatParameters *ap,
+                 enum dshowDeviceType devtype)
+{
+    struct dshow_ctx *ctx = avctx->priv_data;
+    AM_MEDIA_TYPE type;
+    AVCodecContext *codec;
+    AVStream *st;
+    int ret = AVERROR(EIO);
+
+    st = av_new_stream(avctx, devtype);
+    if (!st) {
+        ret = AVERROR(ENOMEM);
+        goto error;
+    }
+
+    ctx->capture_filter[devtype]->stream_index = st->index;
+
+    libAVPin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
+
+    codec = st->codec;
+    if (devtype == VideoDevice) {
+        BITMAPINFOHEADER *bih = NULL;
+
+        if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
+            VIDEOINFOHEADER *v = (void *) type.pbFormat;
+            bih = &v->bmiHeader;
+        } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
+            VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
+            bih = &v->bmiHeader;
+        }
+        if (!bih) {
+            av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
+            goto error;
+        }
+
+        codec->time_base  = ap->time_base;
+        codec->codec_type = AVMEDIA_TYPE_VIDEO;
+        codec->width      = bih->biWidth;
+        codec->height     = bih->biHeight;
+        codec->pix_fmt    = dshow_pixfmt(bih->biCompression, bih->biBitCount);
+        if (codec->pix_fmt == PIX_FMT_NONE) {
+            codec->codec_id = dshow_codecid(bih->biCompression);
+            if (codec->codec_id == CODEC_ID_NONE) {
+                av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
+                                 "Please report verbose (-v 9) debug information.\n");
+                dshow_read_close(avctx);
+                return AVERROR_PATCHWELCOME;
+            }
+            codec->bits_per_coded_sample = bih->biBitCount;
+        } else {
+            codec->codec_id = CODEC_ID_RAWVIDEO;
+            if (bih->biCompression == BI_RGB) {
+                codec->bits_per_coded_sample = bih->biBitCount;
+                codec->extradata = av_malloc(9 + FF_INPUT_BUFFER_PADDING_SIZE);
+                if (codec->extradata) {
+                    codec->extradata_size = 9;
+                    memcpy(codec->extradata, "BottomUp", 9);
+                }
+            }
+        }
+    } else {
+        WAVEFORMATEX *fx = NULL;
+
+        if (IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
+            fx = (void *) type.pbFormat;
+        }
+        if (!fx) {
+            av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
+            goto error;
+        }
+
+        codec->codec_type  = CODEC_TYPE_AUDIO;
+        codec->sample_fmt  = sample_fmt_bits_per_sample(fx->wBitsPerSample);
+        codec->codec_id    = waveform_codec_id(codec->sample_fmt);
+        codec->sample_rate = fx->nSamplesPerSec;
+        codec->channels    = fx->nChannels;
+    }
+
+    av_set_pts_info(st, 64, 1, 10000000);
+
+    ret = 0;
+
+error:
+    return ret;
+}
+
+static int parse_device_name(AVFormatContext *avctx)
+{
+    struct dshow_ctx *ctx = avctx->priv_data;
+    char **device_name = ctx->device_name;
+    char *name = av_strdup(avctx->filename);
+    char *tmp = name;
+    int ret = 1;
+    char *type;
+
+    while ((type = strtok(tmp, "="))) {
+        char *token = strtok(NULL, ":");
+        tmp = NULL;
+
+        if        (!strcmp(type, "video")) {
+            device_name[0] = token;
+        } else if (!strcmp(type, "audio")) {
+            device_name[1] = token;
+        } else {
+            device_name[0] = NULL;
+            device_name[1] = NULL;
+            break;
+        }
+    }
+
+    if (!device_name[0] && !device_name[1]) {
+        ret = 0;
+    } else {
+        if (device_name[0])
+            device_name[0] = av_strdup(device_name[0]);
+        if (device_name[1])
+            device_name[1] = av_strdup(device_name[1]);
+    }
+
+    av_free(name);
+    return ret;
+}
+
+static int dshow_read_header(AVFormatContext *avctx, AVFormatParameters *ap)
+{
+    struct dshow_ctx *ctx = avctx->priv_data;
+    IGraphBuilder *graph = NULL;
+    ICreateDevEnum *devenum = NULL;
+    IMediaControl *control = NULL;
+    int ret = AVERROR(EIO);
+    int r;
+
+    if (!parse_device_name(avctx)) {
+        av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
+        goto error;
+    }
+
+    CoInitialize(0);
+
+    r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
+                         &IID_IGraphBuilder, (void **) &graph);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
+        goto error;
+    }
+    ctx->graph = graph;
+
+    r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
+                         &IID_ICreateDevEnum, (void **) &devenum);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
+        goto error;
+    }
+
+    if (ctx->device_name[VideoDevice]) {
+        ret = dshow_open_device(avctx, devenum, VideoDevice);
+        if (ret < 0)
+            goto error;
+        ret = dshow_add_device(avctx, ap, VideoDevice);
+        if (ret < 0)
+            goto error;
+    }
+    if (ctx->device_name[AudioDevice]) {
+        ret = dshow_open_device(avctx, devenum, AudioDevice);
+        if (ret < 0)
+            goto error;
+        ret = dshow_add_device(avctx, ap, AudioDevice);
+        if (ret < 0)
+            goto error;
+    }
+
+    ctx->mutex = CreateMutex(NULL, 0, NULL);
+    if (!ctx->mutex) {
+        av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
+        goto error;
+    }
+    ctx->event = CreateEvent(NULL, 1, 0, NULL);
+    if (!ctx->event) {
+        av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
+        goto error;
+    }
+
+    r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
+        goto error;
+    }
+    ctx->control = control;
+
+    r = IMediaControl_Run(control);
+    if (r == S_FALSE) {
+        OAFilterState pfs;
+        r = IMediaControl_GetState(control, 0, &pfs);
+    }
+    if (r != S_OK) {
+        av_log(avctx, AV_LOG_ERROR, "Could not run filter\n");
+        goto error;
+    }
+
+    ret = 0;
+
+error:
+
+    if (ret < 0)
+        dshow_read_close(avctx);
+
+    if (devenum)
+        ICreateDevEnum_Release(devenum);
+
+    return ret;
+}
+
+static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    struct dshow_ctx *ctx = s->priv_data;
+    AVPacketList *pktl = NULL;
+
+    while (!pktl) {
+        WaitForSingleObject(ctx->mutex, INFINITE);
+        pktl = ctx->pktl;
+        if (ctx->pktl) {
+            *pkt = ctx->pktl->pkt;
+            ctx->pktl = ctx->pktl->next;
+            av_free(pktl);
+        }
+        ResetEvent(ctx->event);
+        ReleaseMutex(ctx->mutex);
+        if (!pktl) {
+            if (s->flags & AVFMT_FLAG_NONBLOCK) {
+                return AVERROR(EAGAIN);
+            } else {
+                WaitForSingleObject(ctx->event, INFINITE);
+            }
+        }
+    }
+
+    ctx->curbufsize -= pkt->size;
+
+    return pkt->size;
+}
+
+AVInputFormat dshow_demuxer = {
+    "dshow",
+    NULL_IF_CONFIG_SMALL("DirectShow capture"),
+    sizeof(struct dshow_ctx),
+    NULL,
+    dshow_read_header,
+    dshow_read_packet,
+    dshow_read_close,
+    .flags = AVFMT_NOFILE,
+};
diff --git a/libavdevice/dshow.h b/libavdevice/dshow.h
new file mode 100644 (file)
index 0000000..c991c02
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#define DSHOWDEBUG 0
+
+#include "libavformat/avformat.h"
+
+#define COBJMACROS
+#include <windows.h>
+#include <dshow.h>
+#include <dvdmedia.h>
+
+long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src);
+void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type);
+void ff_printGUID(const GUID *g);
+
+#if DSHOWDEBUG
+extern const AVClass *ff_dshow_context_class_ptr;
+#define dshowdebug(...) av_log(&ff_dshow_context_class_ptr, AV_LOG_DEBUG, __VA_ARGS__)
+#else
+#define dshowdebug(...)
+#endif
+
+static inline void nothing(void *foo)
+{
+}
+
+struct GUIDoffset {
+    const GUID *iid;
+    int offset;
+};
+
+enum dshowDeviceType {
+    VideoDevice = 0,
+    AudioDevice = 1,
+};
+
+#define DECLARE_QUERYINTERFACE(class, ...)                                   \
+long WINAPI                                                                  \
+class##_QueryInterface(class *this, const GUID *riid, void **ppvObject)      \
+{                                                                            \
+    struct GUIDoffset ifaces[] = __VA_ARGS__;                                \
+    int i;                                                                   \
+    dshowdebug(AV_STRINGIFY(class)"_QueryInterface(%p, %p, %p)\n", this, riid, ppvObject); \
+    ff_printGUID(riid);                                                      \
+    if (!ppvObject)                                                          \
+        return E_POINTER;                                                    \
+    for (i = 0; i < sizeof(ifaces)/sizeof(ifaces[0]); i++) {                 \
+        if (IsEqualGUID(riid, ifaces[i].iid)) {                              \
+            void *obj = (void *) ((uint8_t *) this + ifaces[i].offset);      \
+            class##_AddRef(this);                                            \
+            dshowdebug("\tfound %d with offset %d\n", i, ifaces[i].offset);  \
+            *ppvObject = (void *) obj;                                       \
+            return S_OK;                                                     \
+        }                                                                    \
+    }                                                                        \
+    dshowdebug("\tE_NOINTERFACE\n");                                         \
+    *ppvObject = NULL;                                                       \
+    return E_NOINTERFACE;                                                    \
+}
+#define DECLARE_ADDREF(class)                                                \
+unsigned long WINAPI                                                         \
+class##_AddRef(class *this)                                                  \
+{                                                                            \
+    dshowdebug(AV_STRINGIFY(class)"_AddRef(%p)\t%ld\n", this, this->ref+1);  \
+    return InterlockedIncrement(&this->ref);                                 \
+}
+#define DECLARE_RELEASE(class)                                               \
+unsigned long WINAPI                                                         \
+class##_Release(class *this)                                                 \
+{                                                                            \
+    long ref = InterlockedDecrement(&this->ref);                             \
+    dshowdebug(AV_STRINGIFY(class)"_Release(%p)\t%ld\n", this, ref);         \
+    if (!ref)                                                                \
+        class##_Destroy(this);                                               \
+    return ref;                                                              \
+}
+
+#define DECLARE_DESTROY(class, func)                                         \
+void class##_Destroy(class *this)                                            \
+{                                                                            \
+    dshowdebug(AV_STRINGIFY(class)"_Destroy(%p)\n", this);                   \
+    func(this);                                                              \
+    if (this) {                                                              \
+        if (this->vtbl)                                                      \
+            CoTaskMemFree(this->vtbl);                                       \
+        CoTaskMemFree(this);                                                 \
+    }                                                                        \
+}
+#define DECLARE_CREATE(class, setup, ...)                                    \
+class *class##_Create(__VA_ARGS__)                                           \
+{                                                                            \
+    class *this = CoTaskMemAlloc(sizeof(class));                             \
+    void  *vtbl = CoTaskMemAlloc(sizeof(*this->vtbl));                       \
+    dshowdebug(AV_STRINGIFY(class)"_Create(%p)\n", this);                    \
+    if (!this || !vtbl)                                                      \
+        goto fail;                                                           \
+    ZeroMemory(this, sizeof(class));                                         \
+    ZeroMemory(vtbl, sizeof(*this->vtbl));                                   \
+    this->ref  = 1;                                                          \
+    this->vtbl = vtbl;                                                       \
+    if (!setup)                                                              \
+        goto fail;                                                           \
+    dshowdebug("created "AV_STRINGIFY(class)" %p\n", this);                  \
+    return this;                                                             \
+fail:                                                                        \
+    class##_Destroy(this);                                                   \
+    dshowdebug("could not create "AV_STRINGIFY(class)"\n");                  \
+    return NULL;                                                             \
+}
+
+#define SETVTBL(vtbl, class, fn) \
+    do { (vtbl)->fn = (void *) class##_##fn; } while(0)
+
+/*****************************************************************************
+ * Forward Declarations
+ ****************************************************************************/
+typedef struct libAVPin libAVPin;
+typedef struct libAVMemInputPin libAVMemInputPin;
+typedef struct libAVEnumPins libAVEnumPins;
+typedef struct libAVEnumMediaTypes libAVEnumMediaTypes;
+typedef struct libAVFilter libAVFilter;
+
+/*****************************************************************************
+ * libAVPin
+ ****************************************************************************/
+struct libAVPin {
+    IPinVtbl *vtbl;
+    long ref;
+    libAVFilter *filter;
+    IPin *connectedto;
+    AM_MEDIA_TYPE type;
+    IMemInputPinVtbl *imemvtbl;
+};
+
+long          WINAPI libAVPin_QueryInterface          (libAVPin *, const GUID *, void **);
+unsigned long WINAPI libAVPin_AddRef                  (libAVPin *);
+unsigned long WINAPI libAVPin_Release                 (libAVPin *);
+long          WINAPI libAVPin_Connect                 (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
+long          WINAPI libAVPin_ReceiveConnection       (libAVPin *, IPin *, const AM_MEDIA_TYPE *);
+long          WINAPI libAVPin_Disconnect              (libAVPin *);
+long          WINAPI libAVPin_ConnectedTo             (libAVPin *, IPin **);
+long          WINAPI libAVPin_ConnectionMediaType     (libAVPin *, AM_MEDIA_TYPE *);
+long          WINAPI libAVPin_QueryPinInfo            (libAVPin *, PIN_INFO *);
+long          WINAPI libAVPin_QueryDirection          (libAVPin *, PIN_DIRECTION *);
+long          WINAPI libAVPin_QueryId                 (libAVPin *, wchar_t **);
+long          WINAPI libAVPin_QueryAccept             (libAVPin *, const AM_MEDIA_TYPE *);
+long          WINAPI libAVPin_EnumMediaTypes          (libAVPin *, IEnumMediaTypes **);
+long          WINAPI libAVPin_QueryInternalConnections(libAVPin *, IPin **, unsigned long *);
+long          WINAPI libAVPin_EndOfStream             (libAVPin *);
+long          WINAPI libAVPin_BeginFlush              (libAVPin *);
+long          WINAPI libAVPin_EndFlush                (libAVPin *);
+long          WINAPI libAVPin_NewSegment              (libAVPin *, REFERENCE_TIME, REFERENCE_TIME, double);
+
+long          WINAPI libAVMemInputPin_QueryInterface          (libAVMemInputPin *, const GUID *, void **);
+unsigned long WINAPI libAVMemInputPin_AddRef                  (libAVMemInputPin *);
+unsigned long WINAPI libAVMemInputPin_Release                 (libAVMemInputPin *);
+long          WINAPI libAVMemInputPin_GetAllocator            (libAVMemInputPin *, IMemAllocator **);
+long          WINAPI libAVMemInputPin_NotifyAllocator         (libAVMemInputPin *, IMemAllocator *, WINBOOL);
+long          WINAPI libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *, ALLOCATOR_PROPERTIES *);
+long          WINAPI libAVMemInputPin_Receive                 (libAVMemInputPin *, IMediaSample *);
+long          WINAPI libAVMemInputPin_ReceiveMultiple         (libAVMemInputPin *, IMediaSample **, long, long *);
+long          WINAPI libAVMemInputPin_ReceiveCanBlock         (libAVMemInputPin *);
+
+void                 libAVPin_Destroy(libAVPin *);
+libAVPin            *libAVPin_Create (libAVFilter *filter);
+
+void                 libAVMemInputPin_Destroy(libAVMemInputPin *);
+
+/*****************************************************************************
+ * libAVEnumPins
+ ****************************************************************************/
+struct libAVEnumPins {
+    IEnumPinsVtbl *vtbl;
+    long ref;
+    int pos;
+    libAVPin *pin;
+    libAVFilter *filter;
+};
+
+long          WINAPI libAVEnumPins_QueryInterface(libAVEnumPins *, const GUID *, void **);
+unsigned long WINAPI libAVEnumPins_AddRef        (libAVEnumPins *);
+unsigned long WINAPI libAVEnumPins_Release       (libAVEnumPins *);
+long          WINAPI libAVEnumPins_Next          (libAVEnumPins *, unsigned long, IPin **, unsigned long *);
+long          WINAPI libAVEnumPins_Skip          (libAVEnumPins *, unsigned long);
+long          WINAPI libAVEnumPins_Reset         (libAVEnumPins *);
+long          WINAPI libAVEnumPins_Clone         (libAVEnumPins *, libAVEnumPins **);
+
+void                 libAVEnumPins_Destroy(libAVEnumPins *);
+libAVEnumPins       *libAVEnumPins_Create (libAVPin *pin, libAVFilter *filter);
+
+/*****************************************************************************
+ * libAVEnumMediaTypes
+ ****************************************************************************/
+struct libAVEnumMediaTypes {
+    IEnumPinsVtbl *vtbl;
+    long ref;
+    int pos;
+    AM_MEDIA_TYPE type;
+};
+
+long          WINAPI libAVEnumMediaTypes_QueryInterface(libAVEnumMediaTypes *, const GUID *, void **);
+unsigned long WINAPI libAVEnumMediaTypes_AddRef        (libAVEnumMediaTypes *);
+unsigned long WINAPI libAVEnumMediaTypes_Release       (libAVEnumMediaTypes *);
+long          WINAPI libAVEnumMediaTypes_Next          (libAVEnumMediaTypes *, unsigned long, AM_MEDIA_TYPE **, unsigned long *);
+long          WINAPI libAVEnumMediaTypes_Skip          (libAVEnumMediaTypes *, unsigned long);
+long          WINAPI libAVEnumMediaTypes_Reset         (libAVEnumMediaTypes *);
+long          WINAPI libAVEnumMediaTypes_Clone         (libAVEnumMediaTypes *, libAVEnumMediaTypes **);
+
+void                 libAVEnumMediaTypes_Destroy(libAVEnumMediaTypes *);
+libAVEnumMediaTypes *libAVEnumMediaTypes_Create(const AM_MEDIA_TYPE *type);
+
+/*****************************************************************************
+ * libAVFilter
+ ****************************************************************************/
+struct libAVFilter {
+    IBaseFilterVtbl *vtbl;
+    long ref;
+    const wchar_t *name;
+    libAVPin *pin;
+    FILTER_INFO info;
+    FILTER_STATE state;
+    IReferenceClock *clock;
+    enum dshowDeviceType type;
+    void *priv_data;
+    int stream_index;
+    int64_t start_time;
+    void (*callback)(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time);
+};
+
+long          WINAPI libAVFilter_QueryInterface (libAVFilter *, const GUID *, void **);
+unsigned long WINAPI libAVFilter_AddRef         (libAVFilter *);
+unsigned long WINAPI libAVFilter_Release        (libAVFilter *);
+long          WINAPI libAVFilter_GetClassID     (libAVFilter *, CLSID *);
+long          WINAPI libAVFilter_Stop           (libAVFilter *);
+long          WINAPI libAVFilter_Pause          (libAVFilter *);
+long          WINAPI libAVFilter_Run            (libAVFilter *, REFERENCE_TIME);
+long          WINAPI libAVFilter_GetState       (libAVFilter *, DWORD, FILTER_STATE *);
+long          WINAPI libAVFilter_SetSyncSource  (libAVFilter *, IReferenceClock *);
+long          WINAPI libAVFilter_GetSyncSource  (libAVFilter *, IReferenceClock **);
+long          WINAPI libAVFilter_EnumPins       (libAVFilter *, IEnumPins **);
+long          WINAPI libAVFilter_FindPin        (libAVFilter *, const wchar_t *, IPin **);
+long          WINAPI libAVFilter_QueryFilterInfo(libAVFilter *, FILTER_INFO *);
+long          WINAPI libAVFilter_JoinFilterGraph(libAVFilter *, IFilterGraph *, const wchar_t *);
+long          WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
+
+void                 libAVFilter_Destroy(libAVFilter *);
+libAVFilter         *libAVFilter_Create (void *, void *, enum dshowDeviceType);
diff --git a/libavdevice/dshow_common.c b/libavdevice/dshow_common.c
new file mode 100644 (file)
index 0000000..c813dc1
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Directshow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow.h"
+
+long ff_copy_dshow_media_type(AM_MEDIA_TYPE *dst, const AM_MEDIA_TYPE *src)
+{
+    uint8_t *pbFormat = NULL;
+
+    if (src->cbFormat) {
+        pbFormat = CoTaskMemAlloc(src->cbFormat);
+        if (!pbFormat)
+            return E_OUTOFMEMORY;
+        memcpy(pbFormat, src->pbFormat, src->cbFormat);
+    }
+
+    *dst = *src;
+    dst->pUnk = NULL;
+    dst->pbFormat = pbFormat;
+
+    return S_OK;
+}
+
+void ff_printGUID(const GUID *g)
+{
+#if DSHOWDEBUG
+    const uint32_t *d = (const uint32_t *) &g->Data1;
+    const uint16_t *w = (const uint16_t *) &g->Data2;
+    const uint8_t  *c = (const uint8_t  *) &g->Data4;
+
+    dshowdebug("0x%08x 0x%04x 0x%04x %02x%02x%02x%02x%02x%02x%02x%02x",
+               d[0], w[0], w[1],
+               c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
+#endif
+}
+
+static const char *dshow_context_to_name(void *ptr)
+{
+    return "dshow";
+}
+static const AVClass ff_dshow_context_class = { "DirectShow", dshow_context_to_name };
+const AVClass *ff_dshow_context_class_ptr = &ff_dshow_context_class;
+
+#define dstruct(pctx, sname, var, type) \
+    dshowdebug("      "#var":\t%"type"\n", sname->var)
+
+#if DSHOWDEBUG
+static void dump_bih(void *s, BITMAPINFOHEADER *bih)
+{
+    dshowdebug("      BITMAPINFOHEADER\n");
+    dstruct(s, bih, biSize, "lu");
+    dstruct(s, bih, biWidth, "ld");
+    dstruct(s, bih, biHeight, "ld");
+    dstruct(s, bih, biPlanes, "d");
+    dstruct(s, bih, biBitCount, "d");
+    dstruct(s, bih, biCompression, "lu");
+    dshowdebug("      biCompression:\t\"%.4s\"\n",
+                   (char*) &bih->biCompression);
+    dstruct(s, bih, biSizeImage, "lu");
+    dstruct(s, bih, biXPelsPerMeter, "lu");
+    dstruct(s, bih, biYPelsPerMeter, "lu");
+    dstruct(s, bih, biClrUsed, "lu");
+    dstruct(s, bih, biClrImportant, "lu");
+}
+#endif
+
+void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type)
+{
+#if DSHOWDEBUG
+    dshowdebug("    majortype\t");
+    ff_printGUID(&type->majortype);
+    dshowdebug("\n");
+    dshowdebug("    subtype\t");
+    ff_printGUID(&type->subtype);
+    dshowdebug("\n");
+    dshowdebug("    bFixedSizeSamples\t%d\n", type->bFixedSizeSamples);
+    dshowdebug("    bTemporalCompression\t%d\n", type->bTemporalCompression);
+    dshowdebug("    lSampleSize\t%lu\n", type->lSampleSize);
+    dshowdebug("    formattype\t");
+    ff_printGUID(&type->formattype);
+    dshowdebug("\n");
+    dshowdebug("    pUnk\t%p\n", type->pUnk);
+    dshowdebug("    cbFormat\t%lu\n", type->cbFormat);
+    dshowdebug("    pbFormat\t%p\n", type->pbFormat);
+
+    if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
+        VIDEOINFOHEADER *v = (void *) type->pbFormat;
+        dshowdebug("      rcSource: left %ld top %ld right %ld bottom %ld\n",
+                   v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
+        dshowdebug("      rcTarget: left %ld top %ld right %ld bottom %ld\n",
+                   v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
+        dshowdebug("      dwBitRate: %lu\n", v->dwBitRate);
+        dshowdebug("      dwBitErrorRate: %lu\n", v->dwBitErrorRate);
+        dshowdebug("      AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
+        dump_bih(NULL, &v->bmiHeader);
+    } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
+        VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
+        dshowdebug("      rcSource: left %ld top %ld right %ld bottom %ld\n",
+                   v->rcSource.left, v->rcSource.top, v->rcSource.right, v->rcSource.bottom);
+        dshowdebug("      rcTarget: left %ld top %ld right %ld bottom %ld\n",
+                   v->rcTarget.left, v->rcTarget.top, v->rcTarget.right, v->rcTarget.bottom);
+        dshowdebug("      dwBitRate: %lu\n", v->dwBitRate);
+        dshowdebug("      dwBitErrorRate: %lu\n", v->dwBitErrorRate);
+        dshowdebug("      AvgTimePerFrame: %"PRId64"\n", v->AvgTimePerFrame);
+        dshowdebug("      dwInterlaceFlags: %lu\n", v->dwInterlaceFlags);
+        dshowdebug("      dwCopyProtectFlags: %lu\n", v->dwCopyProtectFlags);
+        dshowdebug("      dwPictAspectRatioX: %lu\n", v->dwPictAspectRatioX);
+        dshowdebug("      dwPictAspectRatioY: %lu\n", v->dwPictAspectRatioY);
+//        dshowdebug("      dwReserved1: %lu\n", v->u.dwReserved1); /* mingw-w64 is buggy and doesn't name unnamed unions */
+        dshowdebug("      dwReserved2: %lu\n", v->dwReserved2);
+        dump_bih(NULL, &v->bmiHeader);
+    } else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
+        WAVEFORMATEX *fx = (void *) type->pbFormat;
+        dshowdebug("      wFormatTag: %u\n", fx->wFormatTag);
+        dshowdebug("      nChannels: %u\n", fx->nChannels);
+        dshowdebug("      nSamplesPerSec: %lu\n", fx->nSamplesPerSec);
+        dshowdebug("      nAvgBytesPerSec: %lu\n", fx->nAvgBytesPerSec);
+        dshowdebug("      nBlockAlign: %u\n", fx->nBlockAlign);
+        dshowdebug("      wBitsPerSample: %u\n", fx->wBitsPerSample);
+        dshowdebug("      cbSize: %u\n", fx->cbSize);
+    }
+#endif
+}
diff --git a/libavdevice/dshow_enummediatypes.c b/libavdevice/dshow_enummediatypes.c
new file mode 100644 (file)
index 0000000..a700133
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow.h"
+
+DECLARE_QUERYINTERFACE(libAVEnumMediaTypes,
+    { {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
+DECLARE_ADDREF(libAVEnumMediaTypes)
+DECLARE_RELEASE(libAVEnumMediaTypes)
+
+long WINAPI
+libAVEnumMediaTypes_Next(libAVEnumMediaTypes *this, unsigned long n,
+                         AM_MEDIA_TYPE **types, unsigned long *fetched)
+{
+    int count = 0;
+    dshowdebug("libAVEnumMediaTypes_Next(%p)\n", this);
+    if (!types)
+        return E_POINTER;
+    if (!this->pos && n == 1) {
+        if (!IsEqualGUID(&this->type.majortype, &GUID_NULL)) {
+            AM_MEDIA_TYPE *type = av_malloc(sizeof(AM_MEDIA_TYPE));
+            ff_copy_dshow_media_type(type, &this->type);
+            *types = type;
+            count = 1;
+        }
+        this->pos = 1;
+    }
+    if (fetched)
+        *fetched = count;
+    if (!count)
+        return S_FALSE;
+    return S_OK;
+}
+long WINAPI
+libAVEnumMediaTypes_Skip(libAVEnumMediaTypes *this, unsigned long n)
+{
+    dshowdebug("libAVEnumMediaTypes_Skip(%p)\n", this);
+    if (n) /* Any skip will always fall outside of the only valid type. */
+        return S_FALSE;
+    return S_OK;
+}
+long WINAPI
+libAVEnumMediaTypes_Reset(libAVEnumMediaTypes *this)
+{
+    dshowdebug("libAVEnumMediaTypes_Reset(%p)\n", this);
+    this->pos = 0;
+    return S_OK;
+}
+long WINAPI
+libAVEnumMediaTypes_Clone(libAVEnumMediaTypes *this, libAVEnumMediaTypes **enums)
+{
+    libAVEnumMediaTypes *new;
+    dshowdebug("libAVEnumMediaTypes_Clone(%p)\n", this);
+    if (!enums)
+        return E_POINTER;
+    new = libAVEnumMediaTypes_Create(&this->type);
+    if (!new)
+        return E_OUTOFMEMORY;
+    new->pos = this->pos;
+    *enums = new;
+    return S_OK;
+}
+
+static int
+libAVEnumMediaTypes_Setup(libAVEnumMediaTypes *this, const AM_MEDIA_TYPE *type)
+{
+    IEnumPinsVtbl *vtbl = this->vtbl;
+    SETVTBL(vtbl, libAVEnumMediaTypes, QueryInterface);
+    SETVTBL(vtbl, libAVEnumMediaTypes, AddRef);
+    SETVTBL(vtbl, libAVEnumMediaTypes, Release);
+    SETVTBL(vtbl, libAVEnumMediaTypes, Next);
+    SETVTBL(vtbl, libAVEnumMediaTypes, Skip);
+    SETVTBL(vtbl, libAVEnumMediaTypes, Reset);
+    SETVTBL(vtbl, libAVEnumMediaTypes, Clone);
+
+    if (!type) {
+        this->type.majortype = GUID_NULL;
+    } else {
+        ff_copy_dshow_media_type(&this->type, type);
+    }
+
+    return 1;
+}
+DECLARE_CREATE(libAVEnumMediaTypes, libAVEnumMediaTypes_Setup(this, type), const AM_MEDIA_TYPE *type)
+DECLARE_DESTROY(libAVEnumMediaTypes, nothing)
diff --git a/libavdevice/dshow_enumpins.c b/libavdevice/dshow_enumpins.c
new file mode 100644 (file)
index 0000000..97890fb
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow.h"
+
+DECLARE_QUERYINTERFACE(libAVEnumPins,
+    { {&IID_IUnknown,0}, {&IID_IEnumPins,0} })
+DECLARE_ADDREF(libAVEnumPins)
+DECLARE_RELEASE(libAVEnumPins)
+
+long WINAPI
+libAVEnumPins_Next(libAVEnumPins *this, unsigned long n, IPin **pins,
+                   unsigned long *fetched)
+{
+    int count = 0;
+    dshowdebug("libAVEnumPins_Next(%p)\n", this);
+    if (!pins)
+        return E_POINTER;
+    if (!this->pos && n == 1) {
+        libAVPin_AddRef(this->pin);
+        *pins = (IPin *) this->pin;
+        count = 1;
+        this->pos = 1;
+    }
+    if (fetched)
+        *fetched = count;
+    if (!count)
+        return S_FALSE;
+    return S_OK;
+}
+long WINAPI
+libAVEnumPins_Skip(libAVEnumPins *this, unsigned long n)
+{
+    dshowdebug("libAVEnumPins_Skip(%p)\n", this);
+    if (n) /* Any skip will always fall outside of the only valid pin. */
+        return S_FALSE;
+    return S_OK;
+}
+long WINAPI
+libAVEnumPins_Reset(libAVEnumPins *this)
+{
+    dshowdebug("libAVEnumPins_Reset(%p)\n", this);
+    this->pos = 0;
+    return S_OK;
+}
+long WINAPI
+libAVEnumPins_Clone(libAVEnumPins *this, libAVEnumPins **pins)
+{
+    libAVEnumPins *new;
+    dshowdebug("libAVEnumPins_Clone(%p)\n", this);
+    if (!pins)
+        return E_POINTER;
+    new = libAVEnumPins_Create(this->pin, this->filter);
+    if (!new)
+        return E_OUTOFMEMORY;
+    new->pos = this->pos;
+    *pins = new;
+    return S_OK;
+}
+
+static int
+libAVEnumPins_Setup(libAVEnumPins *this, libAVPin *pin, libAVFilter *filter)
+{
+    IEnumPinsVtbl *vtbl = this->vtbl;
+    SETVTBL(vtbl, libAVEnumPins, QueryInterface);
+    SETVTBL(vtbl, libAVEnumPins, AddRef);
+    SETVTBL(vtbl, libAVEnumPins, Release);
+    SETVTBL(vtbl, libAVEnumPins, Next);
+    SETVTBL(vtbl, libAVEnumPins, Skip);
+    SETVTBL(vtbl, libAVEnumPins, Reset);
+    SETVTBL(vtbl, libAVEnumPins, Clone);
+
+    this->pin = pin;
+    this->filter = filter;
+    libAVFilter_AddRef(this->filter);
+
+    return 1;
+}
+DECLARE_CREATE(libAVEnumPins, libAVEnumPins_Setup(this, pin, filter),
+               libAVPin *pin, libAVFilter *filter)
+DECLARE_DESTROY(libAVEnumPins, nothing)
diff --git a/libavdevice/dshow_filter.c b/libavdevice/dshow_filter.c
new file mode 100644 (file)
index 0000000..e5a3be8
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow.h"
+
+DECLARE_QUERYINTERFACE(libAVFilter,
+    { {&IID_IUnknown,0}, {&IID_IBaseFilter,0} })
+DECLARE_ADDREF(libAVFilter)
+DECLARE_RELEASE(libAVFilter)
+
+long WINAPI
+libAVFilter_GetClassID(libAVFilter *this, CLSID *id)
+{
+    dshowdebug("libAVFilter_GetClassID(%p)\n", this);
+    /* I'm not creating a ClassID just for this. */
+    return E_FAIL;
+}
+long WINAPI
+libAVFilter_Stop(libAVFilter *this)
+{
+    dshowdebug("libAVFilter_Stop(%p)\n", this);
+    this->state = State_Stopped;
+    return S_OK;
+}
+long WINAPI
+libAVFilter_Pause(libAVFilter *this)
+{
+    dshowdebug("libAVFilter_Pause(%p)\n", this);
+    this->state = State_Paused;
+    return S_OK;
+}
+long WINAPI
+libAVFilter_Run(libAVFilter *this, REFERENCE_TIME start)
+{
+    dshowdebug("libAVFilter_Run(%p) %"PRId64"\n", this, start);
+    this->state = State_Running;
+    this->start_time = start;
+    return S_OK;
+}
+long WINAPI
+libAVFilter_GetState(libAVFilter *this, DWORD ms, FILTER_STATE *state)
+{
+    dshowdebug("libAVFilter_GetState(%p)\n", this);
+    if (!state)
+        return E_POINTER;
+    *state = this->state;
+    return S_OK;
+}
+long WINAPI
+libAVFilter_SetSyncSource(libAVFilter *this, IReferenceClock *clock)
+{
+    dshowdebug("libAVFilter_SetSyncSource(%p)\n", this);
+
+    if (this->clock != clock) {
+        if (this->clock)
+            IReferenceClock_Release(this->clock);
+        this->clock = clock;
+        if (clock)
+            IReferenceClock_AddRef(clock);
+    }
+
+    return S_OK;
+}
+long WINAPI
+libAVFilter_GetSyncSource(libAVFilter *this, IReferenceClock **clock)
+{
+    dshowdebug("libAVFilter_GetSyncSource(%p)\n", this);
+
+    if (!clock)
+        return E_POINTER;
+    if (this->clock)
+        IReferenceClock_AddRef(this->clock);
+    *clock = this->clock;
+
+    return S_OK;
+}
+long WINAPI
+libAVFilter_EnumPins(libAVFilter *this, IEnumPins **enumpin)
+{
+    libAVEnumPins *new;
+    dshowdebug("libAVFilter_EnumPins(%p)\n", this);
+
+    if (!enumpin)
+        return E_POINTER;
+    new = libAVEnumPins_Create(this->pin, this);
+    if (!new)
+        return E_OUTOFMEMORY;
+
+    *enumpin = (IEnumPins *) new;
+    return S_OK;
+}
+long WINAPI
+libAVFilter_FindPin(libAVFilter *this, const wchar_t *id, IPin **pin)
+{
+    libAVPin *found = NULL;
+    dshowdebug("libAVFilter_FindPin(%p)\n", this);
+
+    if (!id || !pin)
+        return E_POINTER;
+    if (!wcscmp(id, L"In")) {
+        found = this->pin;
+        libAVPin_AddRef(found);
+    }
+    *pin = (IPin *) found;
+    if (!found)
+        return VFW_E_NOT_FOUND;
+
+    return S_OK;
+}
+long WINAPI
+libAVFilter_QueryFilterInfo(libAVFilter *this, FILTER_INFO *info)
+{
+    dshowdebug("libAVFilter_QueryFilterInfo(%p)\n", this);
+
+    if (!info)
+        return E_POINTER;
+    if (this->info.pGraph)
+        IFilterGraph_AddRef(this->info.pGraph);
+    *info = this->info;
+
+    return S_OK;
+}
+long WINAPI
+libAVFilter_JoinFilterGraph(libAVFilter *this, IFilterGraph *graph,
+                            const wchar_t *name)
+{
+    dshowdebug("libAVFilter_JoinFilterGraph(%p)\n", this);
+
+    this->info.pGraph = graph;
+    if (name)
+        wcscpy(this->info.achName, name);
+
+    return S_OK;
+}
+long WINAPI
+libAVFilter_QueryVendorInfo(libAVFilter *this, wchar_t **info)
+{
+    dshowdebug("libAVFilter_QueryVendorInfo(%p)\n", this);
+
+    if (!info)
+        return E_POINTER;
+    *info = wcsdup(L"libAV");
+
+    return S_OK;
+}
+
+static int
+libAVFilter_Setup(libAVFilter *this, void *priv_data, void *callback,
+                  enum dshowDeviceType type)
+{
+    IBaseFilterVtbl *vtbl = this->vtbl;
+    SETVTBL(vtbl, libAVFilter, QueryInterface);
+    SETVTBL(vtbl, libAVFilter, AddRef);
+    SETVTBL(vtbl, libAVFilter, Release);
+    SETVTBL(vtbl, libAVFilter, GetClassID);
+    SETVTBL(vtbl, libAVFilter, Stop);
+    SETVTBL(vtbl, libAVFilter, Pause);
+    SETVTBL(vtbl, libAVFilter, Run);
+    SETVTBL(vtbl, libAVFilter, GetState);
+    SETVTBL(vtbl, libAVFilter, SetSyncSource);
+    SETVTBL(vtbl, libAVFilter, GetSyncSource);
+    SETVTBL(vtbl, libAVFilter, EnumPins);
+    SETVTBL(vtbl, libAVFilter, FindPin);
+    SETVTBL(vtbl, libAVFilter, QueryFilterInfo);
+    SETVTBL(vtbl, libAVFilter, JoinFilterGraph);
+    SETVTBL(vtbl, libAVFilter, QueryVendorInfo);
+
+    this->pin = libAVPin_Create(this);
+
+    this->priv_data = priv_data;
+    this->callback  = callback;
+    this->type      = type;
+
+    return 1;
+}
+DECLARE_CREATE(libAVFilter, libAVFilter_Setup(this, priv_data, callback, type),
+               void *priv_data, void *callback, enum dshowDeviceType type)
+DECLARE_DESTROY(libAVFilter, nothing)
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c
new file mode 100644 (file)
index 0000000..f31ecc6
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * DirectShow capture interface
+ * Copyright (c) 2010 Ramiro Polla
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "dshow.h"
+
+#include <stddef.h>
+#define imemoffset offsetof(libAVPin, imemvtbl)
+
+DECLARE_QUERYINTERFACE(libAVPin,
+    { {&IID_IUnknown,0}, {&IID_IPin,0}, {&IID_IMemInputPin,imemoffset} })
+DECLARE_ADDREF(libAVPin)
+DECLARE_RELEASE(libAVPin)
+
+long WINAPI
+libAVPin_Connect(libAVPin *this, IPin *pin, const AM_MEDIA_TYPE *type)
+{
+    dshowdebug("libAVPin_Connect(%p, %p, %p)\n", this, pin, type);
+    /* Input pins receive connections. */
+    return S_FALSE;
+}
+long WINAPI
+libAVPin_ReceiveConnection(libAVPin *this, IPin *pin,
+                           const AM_MEDIA_TYPE *type)
+{
+    enum dshowDeviceType devtype = this->filter->type;
+    dshowdebug("libAVPin_ReceiveConnection(%p)\n", this);
+
+    if (!pin)
+        return E_POINTER;
+    if (this->connectedto)
+        return VFW_E_ALREADY_CONNECTED;
+
+    ff_print_AM_MEDIA_TYPE(type);
+    if (devtype == VideoDevice) {
+        if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Video))
+            return VFW_E_TYPE_NOT_ACCEPTED;
+    } else {
+        if (!IsEqualGUID(&type->majortype, &MEDIATYPE_Audio))
+            return VFW_E_TYPE_NOT_ACCEPTED;
+    }
+
+    IPin_AddRef(pin);
+    this->connectedto = pin;
+
+    ff_copy_dshow_media_type(&this->type, type);
+
+    return S_OK;
+}
+long WINAPI
+libAVPin_Disconnect(libAVPin *this)
+{
+    dshowdebug("libAVPin_Disconnect(%p)\n", this);
+
+    if (this->filter->state != State_Stopped)
+        return VFW_E_NOT_STOPPED;
+    if (!this->connectedto)
+        return S_FALSE;
+    this->connectedto = NULL;
+
+    return S_OK;
+}
+long WINAPI
+libAVPin_ConnectedTo(libAVPin *this, IPin **pin)
+{
+    dshowdebug("libAVPin_ConnectedTo(%p)\n", this);
+
+    if (!pin)
+        return E_POINTER;
+    if (!this->connectedto)
+        return VFW_E_NOT_CONNECTED;
+    IPin_AddRef(this->connectedto);
+    *pin = this->connectedto;
+
+    return S_OK;
+}
+long WINAPI
+libAVPin_ConnectionMediaType(libAVPin *this, AM_MEDIA_TYPE *type)
+{
+    dshowdebug("libAVPin_ConnectionMediaType(%p)\n", this);
+
+    if (!type)
+        return E_POINTER;
+    if (!this->connectedto)
+        return VFW_E_NOT_CONNECTED;
+
+    return ff_copy_dshow_media_type(type, &this->type);
+}
+long WINAPI
+libAVPin_QueryPinInfo(libAVPin *this, PIN_INFO *info)
+{
+    dshowdebug("libAVPin_QueryPinInfo(%p)\n", this);
+
+    if (!info)
+        return E_POINTER;
+
+    if (this->filter)
+        libAVFilter_AddRef(this->filter);
+
+    info->pFilter = (IBaseFilter *) this->filter;
+    info->dir     = PINDIR_INPUT;
+    wcscpy(info->achName, L"Capture");
+
+    return S_OK;
+}
+long WINAPI
+libAVPin_QueryDirection(libAVPin *this, PIN_DIRECTION *dir)
+{
+    dshowdebug("libAVPin_QueryDirection(%p)\n", this);
+    if (!dir)
+        return E_POINTER;
+    *dir = PINDIR_INPUT;
+    return S_OK;
+}
+long WINAPI
+libAVPin_QueryId(libAVPin *this, wchar_t **id)
+{
+    dshowdebug("libAVPin_QueryId(%p)\n", this);
+
+    if (!id)
+        return E_POINTER;
+
+    *id = wcsdup(L"libAV Pin");
+
+    return S_OK;
+}
+long WINAPI
+libAVPin_QueryAccept(libAVPin *this, const AM_MEDIA_TYPE *type)
+{
+    dshowdebug("libAVPin_QueryAccept(%p)\n", this);
+    return S_FALSE;
+}
+long WINAPI
+libAVPin_EnumMediaTypes(libAVPin *this, IEnumMediaTypes **enumtypes)
+{
+    const AM_MEDIA_TYPE *type = NULL;
+    libAVEnumMediaTypes *new;
+    dshowdebug("libAVPin_EnumMediaTypes(%p)\n", this);
+
+    if (!enumtypes)
+        return E_POINTER;
+    new = libAVEnumMediaTypes_Create(type);
+    if (!new)
+        return E_OUTOFMEMORY;
+
+    *enumtypes = (IEnumMediaTypes *) new;
+    return S_OK;
+}
+long WINAPI
+libAVPin_QueryInternalConnections(libAVPin *this, IPin **pin,
+                                  unsigned long *npin)
+{
+    dshowdebug("libAVPin_QueryInternalConnections(%p)\n", this);
+    return E_NOTIMPL;
+}
+long WINAPI
+libAVPin_EndOfStream(libAVPin *this)
+{
+    dshowdebug("libAVPin_EndOfStream(%p)\n", this);
+    /* I don't care. */
+    return S_OK;
+}
+long WINAPI
+libAVPin_BeginFlush(libAVPin *this)
+{
+    dshowdebug("libAVPin_BeginFlush(%p)\n", this);
+    /* I don't care. */
+    return S_OK;
+}
+long WINAPI
+libAVPin_EndFlush(libAVPin *this)
+{
+    dshowdebug("libAVPin_EndFlush(%p)\n", this);
+    /* I don't care. */
+    return S_OK;
+}
+long WINAPI
+libAVPin_NewSegment(libAVPin *this, REFERENCE_TIME start, REFERENCE_TIME stop,
+                    double rate)
+{
+    dshowdebug("libAVPin_NewSegment(%p)\n", this);
+    /* I don't care. */
+    return S_OK;
+}
+
+static int
+libAVPin_Setup(libAVPin *this, libAVFilter *filter)
+{
+    IPinVtbl *vtbl = this->vtbl;
+    IMemInputPinVtbl *imemvtbl;
+
+    if (!filter)
+        return 0;
+
+    imemvtbl = av_malloc(sizeof(IMemInputPinVtbl));
+    if (!imemvtbl)
+        return 0;
+
+    SETVTBL(imemvtbl, libAVMemInputPin, QueryInterface);
+    SETVTBL(imemvtbl, libAVMemInputPin, AddRef);
+    SETVTBL(imemvtbl, libAVMemInputPin, Release);
+    SETVTBL(imemvtbl, libAVMemInputPin, GetAllocator);
+    SETVTBL(imemvtbl, libAVMemInputPin, NotifyAllocator);
+    SETVTBL(imemvtbl, libAVMemInputPin, GetAllocatorRequirements);
+    SETVTBL(imemvtbl, libAVMemInputPin, Receive);
+    SETVTBL(imemvtbl, libAVMemInputPin, ReceiveMultiple);
+    SETVTBL(imemvtbl, libAVMemInputPin, ReceiveCanBlock);
+
+    this->imemvtbl = imemvtbl;
+
+    SETVTBL(vtbl, libAVPin, QueryInterface);
+    SETVTBL(vtbl, libAVPin, AddRef);
+    SETVTBL(vtbl, libAVPin, Release);
+    SETVTBL(vtbl, libAVPin, Connect);
+    SETVTBL(vtbl, libAVPin, ReceiveConnection);
+    SETVTBL(vtbl, libAVPin, Disconnect);
+    SETVTBL(vtbl, libAVPin, ConnectedTo);
+    SETVTBL(vtbl, libAVPin, ConnectionMediaType);
+    SETVTBL(vtbl, libAVPin, QueryPinInfo);
+    SETVTBL(vtbl, libAVPin, QueryDirection);
+    SETVTBL(vtbl, libAVPin, QueryId);
+    SETVTBL(vtbl, libAVPin, QueryAccept);
+    SETVTBL(vtbl, libAVPin, EnumMediaTypes);
+    SETVTBL(vtbl, libAVPin, QueryInternalConnections);
+    SETVTBL(vtbl, libAVPin, EndOfStream);
+    SETVTBL(vtbl, libAVPin, BeginFlush);
+    SETVTBL(vtbl, libAVPin, EndFlush);
+    SETVTBL(vtbl, libAVPin, NewSegment);
+
+    this->filter = filter;
+
+    return 1;
+}
+DECLARE_CREATE(libAVPin, libAVPin_Setup(this, filter), libAVFilter *filter)
+DECLARE_DESTROY(libAVPin, nothing)
+
+/*****************************************************************************
+ * libAVMemInputPin
+ ****************************************************************************/
+long WINAPI
+libAVMemInputPin_QueryInterface(libAVMemInputPin *this, const GUID *riid,
+                                void **ppvObject)
+{
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+    dshowdebug("libAVMemInputPin_QueryInterface(%p)\n", this);
+    return libAVPin_QueryInterface(pin, riid, ppvObject);
+}
+unsigned long WINAPI
+libAVMemInputPin_AddRef(libAVMemInputPin *this)
+{
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+    dshowdebug("libAVMemInputPin_AddRef(%p)\n", this);
+    return libAVPin_AddRef(pin);
+}
+unsigned long WINAPI
+libAVMemInputPin_Release(libAVMemInputPin *this)
+{
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+    dshowdebug("libAVMemInputPin_Release(%p)\n", this);
+    return libAVPin_Release(pin);
+}
+long WINAPI
+libAVMemInputPin_GetAllocator(libAVMemInputPin *this, IMemAllocator **alloc)
+{
+    dshowdebug("libAVMemInputPin_GetAllocator(%p)\n", this);
+    return VFW_E_NO_ALLOCATOR;
+}
+long WINAPI
+libAVMemInputPin_NotifyAllocator(libAVMemInputPin *this, IMemAllocator *alloc,
+                                 WINBOOL rdwr)
+{
+    dshowdebug("libAVMemInputPin_NotifyAllocator(%p)\n", this);
+    return S_OK;
+}
+long WINAPI
+libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this,
+                                          ALLOCATOR_PROPERTIES *props)
+{
+    dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this);
+    return E_NOTIMPL;
+}
+long WINAPI
+libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
+{
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+    enum dshowDeviceType devtype = pin->filter->type;
+    void *priv_data;
+    uint8_t *buf;
+    int buf_size;
+    int index;
+    int64_t curtime;
+
+    dshowdebug("libAVMemInputPin_Receive(%p)\n", this);
+
+    if (!sample)
+        return E_POINTER;
+
+    if (devtype == VideoDevice) {
+        /* PTS from video devices is unreliable. */
+        IReferenceClock *clock = pin->filter->clock;
+        IReferenceClock_GetTime(clock, &curtime);
+    } else {
+        int64_t dummy;
+        IMediaSample_GetTime(sample, &curtime, &dummy);
+        curtime += pin->filter->start_time;
+    }
+
+    buf_size = IMediaSample_GetActualDataLength(sample);
+    IMediaSample_GetPointer(sample, &buf);
+    priv_data = pin->filter->priv_data;
+    index = pin->filter->stream_index;
+
+    pin->filter->callback(priv_data, index, buf, buf_size, curtime);
+
+    return S_OK;
+}
+long WINAPI
+libAVMemInputPin_ReceiveMultiple(libAVMemInputPin *this,
+                                 IMediaSample **samples, long n, long *nproc)
+{
+    int i;
+    dshowdebug("libAVMemInputPin_ReceiveMultiple(%p)\n", this);
+
+    for (i = 0; i < n; i++)
+        libAVMemInputPin_Receive(this, samples[i]);
+
+    *nproc = n;
+    return S_OK;
+}
+long WINAPI
+libAVMemInputPin_ReceiveCanBlock(libAVMemInputPin *this)
+{
+    dshowdebug("libAVMemInputPin_ReceiveCanBlock(%p)\n", this);
+    /* I swear I will not block. */
+    return S_FALSE;
+}
+
+void
+libAVMemInputPin_Destroy(libAVMemInputPin *this)
+{
+    libAVPin *pin = (libAVPin *) ((uint8_t *) this - imemoffset);
+    dshowdebug("libAVMemInputPin_Destroy(%p)\n", this);
+    return libAVPin_Destroy(pin);
+}
index 2155db6..b8ca419 100644 (file)
@@ -29,8 +29,6 @@
  * Remove this when MinGW incorporates them. */
 #define HWND_MESSAGE                ((HWND)-3)
 
-#define BI_RGB                      0
-
 /* End of missing MinGW defines */
 
 struct vfw_ctx {