Browse code

dshow: introduce support for crossbar [multiple input selectable] devices

Signed-off-by: rogerdpack <rogerpack2005@gmail.com>

rogerdpack authored on 2015/01/23 22:35:16
Showing 5 changed files
... ...
@@ -226,6 +226,14 @@ Select video capture pin to use by name or alternative name.
226 226
 @item audio_pin_name
227 227
 Select audio capture pin to use by name or alternative name.
228 228
 
229
+@item crossbar_video_input_pin_number
230
+Select video input pin number for crossbar device. This will be
231
+routed to the crossbar device's Video Decoder output pin.
232
+
233
+@item crossbar_audio_input_pin_number
234
+Select audio input pin number for crossbar device. This will be
235
+routed to the crossbar device's Audio Decoder output pin.
236
+
229 237
 @end table
230 238
 
231 239
 @subsection Examples
... ...
@@ -19,7 +19,7 @@ OBJS-$(CONFIG_BKTR_INDEV)                += bktr.o
19 19
 OBJS-$(CONFIG_CACA_OUTDEV)               += caca.o
20 20
 OBJS-$(CONFIG_DECKLINK_OUTDEV)           += decklink_enc.o decklink_enc_c.o decklink_common.o
21 21
 OBJS-$(CONFIG_DECKLINK_INDEV)            += decklink_dec.o decklink_dec_c.o decklink_common.o
22
-OBJS-$(CONFIG_DSHOW_INDEV)               += dshow.o dshow_enummediatypes.o \
22
+OBJS-$(CONFIG_DSHOW_INDEV)               += dshow_crossbar.o dshow.o dshow_enummediatypes.o \
23 23
                                             dshow_enumpins.o dshow_filter.o \
24 24
                                             dshow_pin.o dshow_common.o
25 25
 OBJS-$(CONFIG_DV1394_INDEV)              += dv1394.o
... ...
@@ -28,51 +28,6 @@
28 28
 #include "avdevice.h"
29 29
 #include "libavcodec/raw.h"
30 30
 
31
-struct dshow_ctx {
32
-    const AVClass *class;
33
-
34
-    IGraphBuilder *graph;
35
-
36
-    char *device_name[2];
37
-    int video_device_number;
38
-    int audio_device_number;
39
-
40
-    int   list_options;
41
-    int   list_devices;
42
-    int   audio_buffer_size;
43
-    char *video_pin_name;
44
-    char *audio_pin_name;
45
-
46
-    IBaseFilter *device_filter[2];
47
-    IPin        *device_pin[2];
48
-    libAVFilter *capture_filter[2];
49
-    libAVPin    *capture_pin[2];
50
-
51
-    HANDLE mutex;
52
-    HANDLE event[2]; /* event[0] is set by DirectShow
53
-                      * event[1] is set by callback() */
54
-    AVPacketList *pktl;
55
-
56
-    int eof;
57
-
58
-    int64_t curbufsize[2];
59
-    unsigned int video_frame_num;
60
-
61
-    IMediaControl *control;
62
-    IMediaEvent *media_event;
63
-
64
-    enum AVPixelFormat pixel_format;
65
-    enum AVCodecID video_codec_id;
66
-    char *framerate;
67
-
68
-    int requested_width;
69
-    int requested_height;
70
-    AVRational requested_framerate;
71
-
72
-    int sample_rate;
73
-    int sample_size;
74
-    int channels;
75
-};
76 31
 
77 32
 static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
78 33
 {
... ...
@@ -710,8 +665,7 @@ dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
710 710
 }
711 711
 
712 712
 static int
713
-dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
714
-                  enum dshowDeviceType devtype)
713
+dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, enum dshowDeviceType devtype)
715 714
 {
716 715
     struct dshow_ctx *ctx = avctx->priv_data;
717 716
     IBaseFilter *device_filter = NULL;
... ...
@@ -719,6 +673,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
719 719
     IPin *device_pin = NULL;
720 720
     libAVPin *capture_pin = NULL;
721 721
     libAVFilter *capture_filter = NULL;
722
+    ICaptureGraphBuilder2 *graph_builder2 = NULL;
722 723
     int ret = AVERROR(EIO);
723 724
     int r;
724 725
 
... ...
@@ -741,6 +696,7 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
741 741
         ret = r;
742 742
         goto error;
743 743
     }
744
+
744 745
     ctx->device_pin[devtype] = device_pin;
745 746
 
746 747
     capture_filter = libAVFilter_Create(avctx, callback, devtype);
... ...
@@ -761,15 +717,39 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
761 761
     capture_pin = capture_filter->pin;
762 762
     ctx->capture_pin[devtype] = capture_pin;
763 763
 
764
-    r = IGraphBuilder_ConnectDirect(graph, device_pin, (IPin *) capture_pin, NULL);
764
+    r = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
765
+                         &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
766
+    if (r != S_OK) {
767
+        av_log(avctx, AV_LOG_ERROR, "Could not create CaptureGraphBuilder2\n");
768
+        goto error;
769
+    }
770
+    ICaptureGraphBuilder2_SetFiltergraph(graph_builder2, graph);
771
+    if (r != S_OK) {
772
+        av_log(avctx, AV_LOG_ERROR, "Could not set graph for CaptureGraphBuilder2\n");
773
+        goto error;
774
+    }
775
+
776
+    r = ICaptureGraphBuilder2_RenderStream(graph_builder2, NULL, NULL, (IUnknown *) device_pin, NULL /* no intermediate filter */,
777
+        (IBaseFilter *) capture_filter); /* connect pins, optionally insert intermediate filters like crossbar if necessary */
778
+
779
+    if (r != S_OK) {
780
+        av_log(avctx, AV_LOG_ERROR, "Could not RenderStream to connect pins\n");
781
+        goto error;
782
+    }
783
+
784
+    r = dshow_try_setup_crossbar_options(graph_builder2, device_filter, devtype, avctx);
785
+
765 786
     if (r != S_OK) {
766
-        av_log(avctx, AV_LOG_ERROR, "Could not connect pins\n");
787
+        av_log(avctx, AV_LOG_ERROR, "Could not setup CrossBar\n");
767 788
         goto error;
768 789
     }
769 790
 
770 791
     ret = 0;
771 792
 
772 793
 error:
794
+    if (graph_builder2 != NULL)
795
+        ICaptureGraphBuilder2_Release(graph_builder2);
796
+
773 797
     return ret;
774 798
 }
775 799
 
... ...
@@ -988,11 +968,15 @@ static int dshow_read_header(AVFormatContext *avctx)
988 988
     }
989 989
     if (ctx->list_options) {
990 990
         if (ctx->device_name[VideoDevice])
991
-            dshow_list_device_options(avctx, devenum, VideoDevice);
991
+            if ((r = dshow_list_device_options(avctx, devenum, VideoDevice))) {
992
+                ret = r;
993
+                goto error;
994
+            }
992 995
         if (ctx->device_name[AudioDevice])
993
-            dshow_list_device_options(avctx, devenum, AudioDevice);
994
-        ret = AVERROR_EXIT;
995
-        goto error;
996
+            if ((r = dshow_list_device_options(avctx, devenum, AudioDevice))) {
997
+                ret = r;
998
+                goto error;
999
+            }
996 1000
     }
997 1001
 
998 1002
     if (ctx->device_name[VideoDevice]) {
... ...
@@ -1009,6 +993,11 @@ static int dshow_read_header(AVFormatContext *avctx)
1009 1009
             goto error;
1010 1010
         }
1011 1011
     }
1012
+    if (ctx->list_options) {
1013
+        /* allow it to list crossbar options in dshow_open_device */
1014
+        ret = AVERROR_EXIT;
1015
+        goto error;
1016
+    }
1012 1017
     ctx->curbufsize[0] = 0;
1013 1018
     ctx->curbufsize[1] = 0;
1014 1019
     ctx->mutex = CreateMutex(NULL, 0, NULL);
... ...
@@ -1142,6 +1131,8 @@ static const AVOption options[] = {
1142 1142
     { "audio_device_number", "set audio device number for devices with same name (starts at 0)", OFFSET(audio_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1143 1143
     { "video_pin_name", "select video capture pin by name", OFFSET(video_pin_name),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1144 1144
     { "audio_pin_name", "select audio capture pin by name", OFFSET(audio_pin_name),AV_OPT_TYPE_STRING, {.str = NULL},  0, 0, AV_OPT_FLAG_ENCODING_PARAM },
1145
+    { "crossbar_video_input_pin_number", "set video input pin number for crossbar device", OFFSET(crossbar_video_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
1146
+    { "crossbar_audio_input_pin_number", "set audio input pin number for crossbar device", OFFSET(crossbar_audio_input_pin_number), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, DEC },
1145 1147
     { NULL },
1146 1148
 };
1147 1149
 
... ...
@@ -277,4 +277,65 @@ long          WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
277 277
 void                 libAVFilter_Destroy(libAVFilter *);
278 278
 libAVFilter         *libAVFilter_Create (void *, void *, enum dshowDeviceType);
279 279
 
280
+/*****************************************************************************
281
+ * dshow_ctx
282
+ ****************************************************************************/
283
+struct dshow_ctx {
284
+    const AVClass *class;
285
+
286
+    IGraphBuilder *graph;
287
+
288
+    char *device_name[2];
289
+    int video_device_number;
290
+    int audio_device_number;
291
+
292
+    int   list_options;
293
+    int   list_devices;
294
+    int   audio_buffer_size;
295
+    int   crossbar_video_input_pin_number;
296
+    int   crossbar_audio_input_pin_number;
297
+    char *video_pin_name;
298
+    char *audio_pin_name;
299
+    int   show_video_device_dialog;
300
+    int   show_audio_device_dialog;
301
+
302
+    IBaseFilter *device_filter[2];
303
+    IPin        *device_pin[2];
304
+    libAVFilter *capture_filter[2];
305
+    libAVPin    *capture_pin[2];
306
+
307
+    HANDLE mutex;
308
+    HANDLE event[2]; /* event[0] is set by DirectShow
309
+                      * event[1] is set by callback() */
310
+    AVPacketList *pktl;
311
+
312
+    int eof;
313
+
314
+    int64_t curbufsize[2];
315
+    unsigned int video_frame_num;
316
+
317
+    IMediaControl *control;
318
+    IMediaEvent *media_event;
319
+
320
+    enum AVPixelFormat pixel_format;
321
+    enum AVCodecID video_codec_id;
322
+    char *framerate;
323
+
324
+    int requested_width;
325
+    int requested_height;
326
+    AVRational requested_framerate;
327
+
328
+    int sample_rate;
329
+    int sample_size;
330
+    int channels;
331
+};
332
+
333
+/*****************************************************************************
334
+ * CrossBar
335
+ ****************************************************************************/
336
+HRESULT dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
337
+    IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx);
338
+
339
+void dshow_show_filter_properties(IBaseFilter *pFilter, AVFormatContext *avctx);
340
+
280 341
 #endif /* AVDEVICE_DSHOW_H */
281 342
new file mode 100644
... ...
@@ -0,0 +1,164 @@
0
+/*
1
+ * DirectShow capture interface
2
+ * Copyright (c) 2015 Roger Pack
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_capture.h"
22
+
23
+static const char *
24
+GetPhysicalPinName(long pin_type)
25
+{
26
+    switch (pin_type)
27
+    {
28
+    case PhysConn_Video_Tuner:            return "Video Tuner";
29
+    case PhysConn_Video_Composite:        return "Video Composite";
30
+    case PhysConn_Video_SVideo:           return "S-Video";
31
+    case PhysConn_Video_RGB:              return "Video RGB";
32
+    case PhysConn_Video_YRYBY:            return "Video YRYBY";
33
+    case PhysConn_Video_SerialDigital:    return "Video Serial Digital";
34
+    case PhysConn_Video_ParallelDigital:  return "Video Parallel Digital";
35
+    case PhysConn_Video_SCSI:             return "Video SCSI";
36
+    case PhysConn_Video_AUX:              return "Video AUX";
37
+    case PhysConn_Video_1394:             return "Video 1394";
38
+    case PhysConn_Video_USB:              return "Video USB";
39
+    case PhysConn_Video_VideoDecoder:     return "Video Decoder";
40
+    case PhysConn_Video_VideoEncoder:     return "Video Encoder";
41
+
42
+    case PhysConn_Audio_Tuner:            return "Audio Tuner";
43
+    case PhysConn_Audio_Line:             return "Audio Line";
44
+    case PhysConn_Audio_Mic:              return "Audio Microphone";
45
+    case PhysConn_Audio_AESDigital:       return "Audio AES/EBU Digital";
46
+    case PhysConn_Audio_SPDIFDigital:     return "Audio S/PDIF";
47
+    case PhysConn_Audio_SCSI:             return "Audio SCSI";
48
+    case PhysConn_Audio_AUX:              return "Audio AUX";
49
+    case PhysConn_Audio_1394:             return "Audio 1394";
50
+    case PhysConn_Audio_USB:              return "Audio USB";
51
+    case PhysConn_Audio_AudioDecoder:     return "Audio Decoder";
52
+    default:                              return "Unknown Crossbar Pin Type—Please report!";
53
+    }
54
+}
55
+
56
+static HRESULT
57
+setup_crossbar_options(IAMCrossbar *cross_bar, enum dshowDeviceType devtype, AVFormatContext *avctx)
58
+{
59
+    struct dshow_ctx *ctx = avctx->priv_data;
60
+    long count_output_pins, count_input_pins;
61
+    int i;
62
+    int log_level = ctx->list_options ? AV_LOG_INFO : AV_LOG_DEBUG;
63
+    int video_input_pin = ctx->crossbar_video_input_pin_number;
64
+    int audio_input_pin = ctx->crossbar_audio_input_pin_number;
65
+    const char *device_name = ctx->device_name[devtype];
66
+    HRESULT hr;
67
+
68
+    av_log(avctx, log_level, "Crossbar Switching Information for %s:\n", device_name);
69
+    hr = IAMCrossbar_get_PinCounts(cross_bar, &count_output_pins, &count_input_pins);
70
+    if (hr != S_OK) {
71
+        av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar pin counts\n");
72
+        return hr;
73
+    }
74
+
75
+    for (i = 0; i < count_output_pins; i++)
76
+    {
77
+        long related_pin, pin_type, route_to_pin;
78
+        hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, FALSE, i, &related_pin, &pin_type);
79
+        if (pin_type == PhysConn_Video_VideoDecoder) {
80
+            /* assume there is only one "Video (and one Audio) Decoder" output pin, and it's all we care about routing to...for now */
81
+            if (video_input_pin != -1) {
82
+                av_log(avctx, log_level, "Routing video input from pin %d\n", video_input_pin);
83
+                hr = IAMCrossbar_Route(cross_bar, i, video_input_pin);
84
+                if (hr != S_OK) {
85
+                    av_log(avctx, AV_LOG_ERROR, "Unable to route video input from pin %d\n", video_input_pin);
86
+                    return AVERROR(EIO);
87
+                }
88
+            }
89
+        } else if (pin_type == PhysConn_Audio_AudioDecoder) {
90
+            if (audio_input_pin != -1) {
91
+                av_log(avctx, log_level, "Routing audio input from pin %d\n", audio_input_pin);
92
+                hr = IAMCrossbar_Route(cross_bar, i, audio_input_pin);
93
+                if (hr != S_OK) {
94
+                    av_log(avctx, AV_LOG_ERROR, "Unable to route audio input from pin %d\n", audio_input_pin);
95
+                    return hr;
96
+                }
97
+            }
98
+        } else {
99
+            av_log(avctx, AV_LOG_WARNING, "Unexpected output pin type, please report the type if you want to use this (%s)", GetPhysicalPinName(pin_type));
100
+        }
101
+
102
+        hr = IAMCrossbar_get_IsRoutedTo(cross_bar, i, &route_to_pin);
103
+        if (hr != S_OK) {
104
+            av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar is routed to from pin %d\n", i);
105
+            return hr;
106
+        }
107
+        av_log(avctx, log_level, "  Crossbar Output pin %d: \"%s\" related output pin: %ld ", i, GetPhysicalPinName(pin_type), related_pin);
108
+        av_log(avctx, log_level, "current input pin: %ld ", route_to_pin);
109
+        av_log(avctx, log_level, "compatible input pins: ");
110
+
111
+        for (int j = 0; j < count_input_pins; j++)
112
+        {
113
+            hr = IAMCrossbar_CanRoute(cross_bar, i, j);
114
+            if (hr == S_OK)
115
+                av_log(avctx, log_level ,"%d ", j);
116
+        }
117
+        av_log(avctx, log_level, "\n");
118
+    }
119
+
120
+    for (i = 0; i < count_input_pins; i++)
121
+    {
122
+        long related_pin, pin_type;
123
+        hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, TRUE, i, &related_pin, &pin_type);
124
+        if (hr != S_OK) {
125
+            av_log(avctx, AV_LOG_ERROR, "unable to get crossbar info audio input from pin %d\n", i);
126
+            return hr;
127
+        }
128
+        av_log(avctx, log_level, "  Crossbar Input pin %d - \"%s\" ", i, GetPhysicalPinName(pin_type));
129
+        av_log(avctx, log_level, "related input pin: %ld\n", related_pin);
130
+    }
131
+    return S_OK;
132
+}
133
+
134
+/**
135
+ * Given a fully constructed graph, check if there is a cross bar filter, and configure its pins if so.
136
+ */
137
+HRESULT
138
+dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
139
+    IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx)
140
+{
141
+    IAMCrossbar *cross_bar = NULL;
142
+    IBaseFilter *cross_bar_filter = NULL;
143
+    HRESULT hr;
144
+
145
+    hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, (const GUID *) NULL,
146
+            (IBaseFilter *) device_filter, &IID_IAMCrossbar, (void**) &cross_bar);
147
+    if (hr != S_OK) {
148
+        /* no crossbar found */
149
+        hr = S_OK;
150
+        goto end;
151
+    }
152
+
153
+    hr = setup_crossbar_options(cross_bar, devtype, avctx);
154
+    if (hr != S_OK)
155
+        goto end;
156
+
157
+end:
158
+    if (cross_bar)
159
+        IAMCrossbar_Release(cross_bar);
160
+    if (cross_bar_filter)
161
+        IBaseFilter_Release(cross_bar_filter);
162
+    return hr;
163
+}