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