FFmpeg
dshow_crossbar.c
Go to the documentation of this file.
1 /*
2  * DirectShow capture interface
3  * Copyright (c) 2015 Roger Pack
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with FFmpeg; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 #include "dshow_capture.h"
23 
24 static const char *
25 GetPhysicalPinName(long pin_type)
26 {
27  switch (pin_type)
28  {
29  case PhysConn_Video_Tuner: return "Video Tuner";
30  case PhysConn_Video_Composite: return "Video Composite";
31  case PhysConn_Video_SVideo: return "S-Video";
32  case PhysConn_Video_RGB: return "Video RGB";
33  case PhysConn_Video_YRYBY: return "Video YRYBY";
34  case PhysConn_Video_SerialDigital: return "Video Serial Digital";
35  case PhysConn_Video_ParallelDigital: return "Video Parallel Digital";
36  case PhysConn_Video_SCSI: return "Video SCSI";
37  case PhysConn_Video_AUX: return "Video AUX";
38  case PhysConn_Video_1394: return "Video 1394";
39  case PhysConn_Video_USB: return "Video USB";
40  case PhysConn_Video_VideoDecoder: return "Video Decoder";
41  case PhysConn_Video_VideoEncoder: return "Video Encoder";
42 
43  case PhysConn_Audio_Tuner: return "Audio Tuner";
44  case PhysConn_Audio_Line: return "Audio Line";
45  case PhysConn_Audio_Mic: return "Audio Microphone";
46  case PhysConn_Audio_AESDigital: return "Audio AES/EBU Digital";
47  case PhysConn_Audio_SPDIFDigital: return "Audio S/PDIF";
48  case PhysConn_Audio_SCSI: return "Audio SCSI";
49  case PhysConn_Audio_AUX: return "Audio AUX";
50  case PhysConn_Audio_1394: return "Audio 1394";
51  case PhysConn_Audio_USB: return "Audio USB";
52  case PhysConn_Audio_AudioDecoder: return "Audio Decoder";
53  default: return "Unknown Crossbar Pin Type—Please report!";
54  }
55 }
56 
57 static HRESULT
58 setup_crossbar_options(IAMCrossbar *cross_bar, enum dshowDeviceType devtype, AVFormatContext *avctx)
59 {
60  struct dshow_ctx *ctx = avctx->priv_data;
61  long count_output_pins, count_input_pins;
62  int i;
63  int log_level = ctx->list_options ? AV_LOG_INFO : AV_LOG_DEBUG;
64  int video_input_pin = ctx->crossbar_video_input_pin_number;
65  int audio_input_pin = ctx->crossbar_audio_input_pin_number;
66  const char *device_name = ctx->device_name[devtype];
67  HRESULT hr;
68 
69  av_log(avctx, log_level, "Crossbar Switching Information for %s:\n", device_name);
70  hr = IAMCrossbar_get_PinCounts(cross_bar, &count_output_pins, &count_input_pins);
71  if (hr != S_OK) {
72  av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar pin counts\n");
73  return hr;
74  }
75 
76  for (i = 0; i < count_output_pins; i++)
77  {
78  int j;
79  long related_pin, pin_type, route_to_pin;
80  hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, FALSE, i, &related_pin, &pin_type);
81  if (pin_type == PhysConn_Video_VideoDecoder) {
82  /* assume there is only one "Video (and one Audio) Decoder" output pin, and it's all we care about routing to...for now */
83  if (video_input_pin != -1) {
84  av_log(avctx, log_level, "Routing video input from pin %d\n", video_input_pin);
85  hr = IAMCrossbar_Route(cross_bar, i, video_input_pin);
86  if (hr != S_OK) {
87  av_log(avctx, AV_LOG_ERROR, "Unable to route video input from pin %d\n", video_input_pin);
88  return AVERROR(EIO);
89  }
90  }
91  } else if (pin_type == PhysConn_Audio_AudioDecoder) {
92  if (audio_input_pin != -1) {
93  av_log(avctx, log_level, "Routing audio input from pin %d\n", audio_input_pin);
94  hr = IAMCrossbar_Route(cross_bar, i, audio_input_pin);
95  if (hr != S_OK) {
96  av_log(avctx, AV_LOG_ERROR, "Unable to route audio input from pin %d\n", audio_input_pin);
97  return hr;
98  }
99  }
100  } else {
101  av_log(avctx, AV_LOG_WARNING, "Unexpected output pin type, please report the type if you want to use this (%s)", GetPhysicalPinName(pin_type));
102  }
103 
104  hr = IAMCrossbar_get_IsRoutedTo(cross_bar, i, &route_to_pin);
105  if (hr != S_OK) {
106  av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar is routed to from pin %d\n", i);
107  return hr;
108  }
109  av_log(avctx, log_level, " Crossbar Output pin %d: \"%s\" related output pin: %ld ", i, GetPhysicalPinName(pin_type), related_pin);
110  av_log(avctx, log_level, "current input pin: %ld ", route_to_pin);
111  av_log(avctx, log_level, "compatible input pins: ");
112 
113  for (j = 0; j < count_input_pins; j++)
114  {
115  hr = IAMCrossbar_CanRoute(cross_bar, i, j);
116  if (hr == S_OK)
117  av_log(avctx, log_level ,"%d ", j);
118  }
119  av_log(avctx, log_level, "\n");
120  }
121 
122  for (i = 0; i < count_input_pins; i++)
123  {
124  long related_pin, pin_type;
125  hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, TRUE, i, &related_pin, &pin_type);
126  if (hr != S_OK) {
127  av_log(avctx, AV_LOG_ERROR, "unable to get crossbar info audio input from pin %d\n", i);
128  return hr;
129  }
130  av_log(avctx, log_level, " Crossbar Input pin %d - \"%s\" ", i, GetPhysicalPinName(pin_type));
131  av_log(avctx, log_level, "related input pin: %ld\n", related_pin);
132  }
133  return S_OK;
134 }
135 
136 /**
137  * Given a fully constructed graph, check if there is a cross bar filter, and configure its pins if so.
138  */
139 HRESULT
140 ff_dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
141  IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx)
142 {
143  struct dshow_ctx *ctx = avctx->priv_data;
144  IAMCrossbar *cross_bar = NULL;
145  IBaseFilter *cross_bar_base_filter = NULL;
146  IAMTVTuner *tv_tuner_filter = NULL;
147  IBaseFilter *tv_tuner_base_filter = NULL;
148  IAMAudioInputMixer *tv_audio_filter = NULL;
149  IBaseFilter *tv_audio_base_filter = NULL;
150  HRESULT hr;
151 
152  hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, (const GUID *) NULL,
153  device_filter, &IID_IAMCrossbar, (void**) &cross_bar);
154  if (hr != S_OK) {
155  /* no crossbar found */
156  hr = S_OK;
157  goto end;
158  }
159  /* TODO some TV tuners apparently have multiple crossbars? */
160 
161  if (devtype == VideoDevice && ctx->show_video_crossbar_connection_dialog ||
162  devtype == AudioDevice && ctx->show_audio_crossbar_connection_dialog) {
163  hr = IAMCrossbar_QueryInterface(cross_bar, &IID_IBaseFilter, (void **) &cross_bar_base_filter);
164  if (hr != S_OK)
165  goto end;
166  ff_dshow_show_filter_properties(cross_bar_base_filter, avctx);
167  }
168 
169  if (devtype == VideoDevice && ctx->show_analog_tv_tuner_dialog) {
170  hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, NULL,
171  device_filter, &IID_IAMTVTuner, (void**) &tv_tuner_filter);
172  if (hr == S_OK) {
173  hr = IAMCrossbar_QueryInterface(tv_tuner_filter, &IID_IBaseFilter, (void **) &tv_tuner_base_filter);
174  if (hr != S_OK)
175  goto end;
176  ff_dshow_show_filter_properties(tv_tuner_base_filter, avctx);
177  } else {
178  av_log(avctx, AV_LOG_WARNING, "unable to find a tv tuner to display dialog for!");
179  }
180  }
181  if (devtype == AudioDevice && ctx->show_analog_tv_tuner_audio_dialog) {
182  hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, NULL,
183  device_filter, &IID_IAMTVAudio, (void**) &tv_audio_filter);
184  if (hr == S_OK) {
185  hr = IAMCrossbar_QueryInterface(tv_audio_filter, &IID_IBaseFilter, (void **) &tv_audio_base_filter);
186  if (hr != S_OK)
187  goto end;
188  ff_dshow_show_filter_properties(tv_audio_base_filter, avctx);
189  } else {
190  av_log(avctx, AV_LOG_WARNING, "unable to find a tv audio tuner to display dialog for!");
191  }
192  }
193 
194  hr = setup_crossbar_options(cross_bar, devtype, avctx);
195  if (hr != S_OK)
196  goto end;
197 
198 end:
199  if (cross_bar)
200  IAMCrossbar_Release(cross_bar);
201  if (cross_bar_base_filter)
202  IBaseFilter_Release(cross_bar_base_filter);
203  if (tv_tuner_filter)
204  IAMTVTuner_Release(tv_tuner_filter);
205  if (tv_tuner_base_filter)
206  IBaseFilter_Release(tv_tuner_base_filter);
207  if (tv_audio_filter)
208  IAMAudioInputMixer_Release(tv_audio_filter);
209  if (tv_audio_base_filter)
210  IBaseFilter_Release(tv_audio_base_filter);
211  return hr;
212 }
AV_LOG_WARNING
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:186
AVERROR
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFrame structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later. That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another. Frame references ownership and permissions
VideoDevice
@ VideoDevice
Definition: dshow_capture.h:63
dshow_capture.h
dshow_ctx::device_filter
IBaseFilter * device_filter[2]
Definition: dshow_capture.h:319
GetPhysicalPinName
static const char * GetPhysicalPinName(long pin_type)
Definition: dshow_crossbar.c:25
dshow_ctx
Definition: dshow_capture.h:287
AV_LOG_ERROR
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:180
AV_LOG_DEBUG
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:201
ctx
AVFormatContext * ctx
Definition: movenc.c:48
AVFormatContext
Format I/O context.
Definition: avformat.h:1104
NULL
#define NULL
Definition: coverity.c:32
setup_crossbar_options
static HRESULT setup_crossbar_options(IAMCrossbar *cross_bar, enum dshowDeviceType devtype, AVFormatContext *avctx)
Definition: dshow_crossbar.c:58
AudioDevice
@ AudioDevice
Definition: dshow_capture.h:64
ff_dshow_show_filter_properties
void ff_dshow_show_filter_properties(IBaseFilter *device_filter, AVFormatContext *avctx)
Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
Definition: dshow.c:1122
dshow_ctx::device_name
char * device_name[2]
Definition: dshow_capture.h:294
AV_LOG_INFO
#define AV_LOG_INFO
Standard information.
Definition: log.h:191
i
#define i(width, name, range_min, range_max)
Definition: cbs_h2645.c:269
ff_dshow_try_setup_crossbar_options
HRESULT ff_dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2, IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx)
Given a fully constructed graph, check if there is a cross bar filter, and configure its pins if so.
Definition: dshow_crossbar.c:140
av_log
#define av_log(a,...)
Definition: tableprint_vlc.h:27
dshowDeviceType
dshowDeviceType
Definition: dshow_capture.h:62
AVFormatContext::priv_data
void * priv_data
Format private data.
Definition: avformat.h:1132