Commit 76241c91 authored by Michael Niedermayer's avatar Michael Niedermayer

Merge remote-tracking branch 'rdp/dshow_crossbar'

* rdp/dshow_crossbar:
  dshow: fix docu escapes
  dshow: some devices only list themselves under "Video sources" but actually have both video and audio output pins, so make the audio pins accessible by video source name.
  dshow: add options for allowing filter popup configuration dialogs to be presented to the user
  dshow: introduce support for crossbar [multiple input selectable] devices
  dshow: drop initial audio packets with weird timestamps
  dshow: use non deprecated api
  dshow: miscellaneous tweaks
  dshow: allow selecting devices by an alternative name (workaround for devices with symbols in them), allow specifying capture pins by name and alternative (unique) name
Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents a915b1da b587ec00
......@@ -2487,7 +2487,7 @@ decklink_outdev_extralibs="-lstdc++"
decklink_indev_deps="decklink pthreads"
decklink_indev_extralibs="-lstdc++"
dshow_indev_deps="IBaseFilter"
dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid"
dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32"
dv1394_indev_deps="dv1394"
dv1394_indev_select="dv_demuxer"
fbdev_indev_deps="linux_fb_h"
......
......@@ -167,7 +167,7 @@ The input name should be in the format:
@end example
where @var{TYPE} can be either @var{audio} or @var{video},
and @var{NAME} is the device's name.
and @var{NAME} is the device's name or alternative name..
@subsection Options
......@@ -220,6 +220,39 @@ Setting this value too low can degrade performance.
See also
@url{http://msdn.microsoft.com/en-us/library/windows/desktop/dd377582(v=vs.85).aspx}
@item video_pin_name
Select video capture pin to use by name or alternative name.
@item audio_pin_name
Select audio capture pin to use by name or alternative name.
@item crossbar_video_input_pin_number
Select video input pin number for crossbar device. This will be
routed to the crossbar device's Video Decoder output pin.
@item crossbar_audio_input_pin_number
Select audio input pin number for crossbar device. This will be
routed to the crossbar device's Audio Decoder output pin.
@item show_video_device_dialog
If set to @option{true}, before capture starts, popup a display dialog
to the end user, allowing them to change video filter properties
and configurations manually.
Note that for crossbar devices, this may be needed at times to toggle
between PAL and NTSC input frame rates and sizes, etc. Possibly
enabling different scan rates/frame rates and avoiding green bars at
the bottom, etc.
@item show_audio_device_dialog
If set to @option{true}, before capture starts, popup a display dialog
to the end user, allowing them to change audio filter properties
and configurations manually.
@item show_crossbar_connection_dialog
If set to @option{true}, before capture starts, popup a display
dialog to the end user, allowing them to manually
modify crossbar pin routings.
@end table
@subsection Examples
......@@ -256,6 +289,19 @@ Print the list of supported options in selected device and exit:
$ ffmpeg -list_options true -f dshow -i video="Camera"
@end example
@item
Specify pin names to capture by name or alternative name, specify alternative device name:
@example
$ ffmpeg -f dshow -audio_pin_name "Audio Out" -video_pin_name 2 -i video=video="@@device_pnp_\\?\pci#ven_1a0a&dev_6200&subsys_62021461&rev_01#4&e2c7dd6&0&00e1#@{65e8773d-8f56-11d0-a3b9-00a0c9223196@}\@{ca465100-deb0-4d59-818f-8c477184adf6@}":audio="Microphone"
@end example
@item
Configure a crossbar device, specifying crossbar pins, allow user to adjust video capture properties at startup:
@example
$ ffmpeg -f dshow -show_video_device_dialog true -crossbar_video_input_pin_number 0
-crossbar_audio_input_pin_number 3 -i video="AVerMedia BDA Analog Capture":audio="AVerMedia BDA Analog Capture"
@end example
@end itemize
@section dv1394
......
......@@ -19,7 +19,7 @@ OBJS-$(CONFIG_BKTR_INDEV) += bktr.o
OBJS-$(CONFIG_CACA_OUTDEV) += caca.o
OBJS-$(CONFIG_DECKLINK_OUTDEV) += decklink_enc.o decklink_enc_c.o decklink_common.o
OBJS-$(CONFIG_DECKLINK_INDEV) += decklink_dec.o decklink_dec_c.o decklink_common.o
OBJS-$(CONFIG_DSHOW_INDEV) += dshow.o dshow_enummediatypes.o \
OBJS-$(CONFIG_DSHOW_INDEV) += dshow_crossbar.o dshow.o dshow_enummediatypes.o \
dshow_enumpins.o dshow_filter.o \
dshow_pin.o dshow_common.o
OBJS-$(CONFIG_DV1394_INDEV) += dv1394.o
......
This diff is collapsed.
......@@ -65,6 +65,11 @@ enum dshowDeviceType {
AudioDevice = 1,
};
enum dshowSourceFilterType {
VideoSourceDevice = 0,
AudioSourceDevice = 1,
};
#define DECLARE_QUERYINTERFACE(class, ...) \
long WINAPI \
class##_QueryInterface(class *this, const GUID *riid, void **ppvObject) \
......@@ -223,7 +228,7 @@ libAVEnumPins *libAVEnumPins_Create (libAVPin *pin, libAVFilter *filter);
* libAVEnumMediaTypes
****************************************************************************/
struct libAVEnumMediaTypes {
IEnumPinsVtbl *vtbl;
IEnumMediaTypesVtbl *vtbl;
long ref;
int pos;
AM_MEDIA_TYPE type;
......@@ -277,4 +282,66 @@ long WINAPI libAVFilter_QueryVendorInfo(libAVFilter *, wchar_t **);
void libAVFilter_Destroy(libAVFilter *);
libAVFilter *libAVFilter_Create (void *, void *, enum dshowDeviceType);
/*****************************************************************************
* dshow_ctx
****************************************************************************/
struct dshow_ctx {
const AVClass *class;
IGraphBuilder *graph;
char *device_name[2];
int video_device_number;
int audio_device_number;
int list_options;
int list_devices;
int audio_buffer_size;
int crossbar_video_input_pin_number;
int crossbar_audio_input_pin_number;
char *video_pin_name;
char *audio_pin_name;
int show_video_device_dialog;
int show_audio_device_dialog;
int show_crossbar_connection_dialog;
IBaseFilter *device_filter[2];
IPin *device_pin[2];
libAVFilter *capture_filter[2];
libAVPin *capture_pin[2];
HANDLE mutex;
HANDLE event[2]; /* event[0] is set by DirectShow
* event[1] is set by callback() */
AVPacketList *pktl;
int eof;
int64_t curbufsize[2];
unsigned int video_frame_num;
IMediaControl *control;
IMediaEvent *media_event;
enum AVPixelFormat pixel_format;
enum AVCodecID video_codec_id;
char *framerate;
int requested_width;
int requested_height;
AVRational requested_framerate;
int sample_rate;
int sample_size;
int channels;
};
/*****************************************************************************
* CrossBar
****************************************************************************/
HRESULT dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx);
void dshow_show_filter_properties(IBaseFilter *pFilter, AVFormatContext *avctx);
#endif /* AVDEVICE_DSHOW_H */
/*
* DirectShow capture interface
* Copyright (c) 2015 Roger Pack
*
* 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_capture.h"
static const char *
GetPhysicalPinName(long pin_type)
{
switch (pin_type)
{
case PhysConn_Video_Tuner: return "Video Tuner";
case PhysConn_Video_Composite: return "Video Composite";
case PhysConn_Video_SVideo: return "S-Video";
case PhysConn_Video_RGB: return "Video RGB";
case PhysConn_Video_YRYBY: return "Video YRYBY";
case PhysConn_Video_SerialDigital: return "Video Serial Digital";
case PhysConn_Video_ParallelDigital: return "Video Parallel Digital";
case PhysConn_Video_SCSI: return "Video SCSI";
case PhysConn_Video_AUX: return "Video AUX";
case PhysConn_Video_1394: return "Video 1394";
case PhysConn_Video_USB: return "Video USB";
case PhysConn_Video_VideoDecoder: return "Video Decoder";
case PhysConn_Video_VideoEncoder: return "Video Encoder";
case PhysConn_Audio_Tuner: return "Audio Tuner";
case PhysConn_Audio_Line: return "Audio Line";
case PhysConn_Audio_Mic: return "Audio Microphone";
case PhysConn_Audio_AESDigital: return "Audio AES/EBU Digital";
case PhysConn_Audio_SPDIFDigital: return "Audio S/PDIF";
case PhysConn_Audio_SCSI: return "Audio SCSI";
case PhysConn_Audio_AUX: return "Audio AUX";
case PhysConn_Audio_1394: return "Audio 1394";
case PhysConn_Audio_USB: return "Audio USB";
case PhysConn_Audio_AudioDecoder: return "Audio Decoder";
default: return "Unknown Crossbar Pin Type—Please report!";
}
}
static HRESULT
setup_crossbar_options(IAMCrossbar *cross_bar, enum dshowDeviceType devtype, AVFormatContext *avctx)
{
struct dshow_ctx *ctx = avctx->priv_data;
long count_output_pins, count_input_pins;
int i;
int log_level = ctx->list_options ? AV_LOG_INFO : AV_LOG_DEBUG;
int video_input_pin = ctx->crossbar_video_input_pin_number;
int audio_input_pin = ctx->crossbar_audio_input_pin_number;
const char *device_name = ctx->device_name[devtype];
HRESULT hr;
av_log(avctx, log_level, "Crossbar Switching Information for %s:\n", device_name);
hr = IAMCrossbar_get_PinCounts(cross_bar, &count_output_pins, &count_input_pins);
if (hr != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar pin counts\n");
return hr;
}
for (i = 0; i < count_output_pins; i++)
{
long related_pin, pin_type, route_to_pin;
hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, FALSE, i, &related_pin, &pin_type);
if (pin_type == PhysConn_Video_VideoDecoder) {
/* assume there is only one "Video (and one Audio) Decoder" output pin, and it's all we care about routing to...for now */
if (video_input_pin != -1) {
av_log(avctx, log_level, "Routing video input from pin %d\n", video_input_pin);
hr = IAMCrossbar_Route(cross_bar, i, video_input_pin);
if (hr != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Unable to route video input from pin %d\n", video_input_pin);
return AVERROR(EIO);
}
}
} else if (pin_type == PhysConn_Audio_AudioDecoder) {
if (audio_input_pin != -1) {
av_log(avctx, log_level, "Routing audio input from pin %d\n", audio_input_pin);
hr = IAMCrossbar_Route(cross_bar, i, audio_input_pin);
if (hr != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Unable to route audio input from pin %d\n", audio_input_pin);
return hr;
}
}
} else {
av_log(avctx, AV_LOG_WARNING, "Unexpected output pin type, please report the type if you want to use this (%s)", GetPhysicalPinName(pin_type));
}
hr = IAMCrossbar_get_IsRoutedTo(cross_bar, i, &route_to_pin);
if (hr != S_OK) {
av_log(avctx, AV_LOG_ERROR, "Unable to get crossbar is routed to from pin %d\n", i);
return hr;
}
av_log(avctx, log_level, " Crossbar Output pin %d: \"%s\" related output pin: %ld ", i, GetPhysicalPinName(pin_type), related_pin);
av_log(avctx, log_level, "current input pin: %ld ", route_to_pin);
av_log(avctx, log_level, "compatible input pins: ");
for (int j = 0; j < count_input_pins; j++)
{
hr = IAMCrossbar_CanRoute(cross_bar, i, j);
if (hr == S_OK)
av_log(avctx, log_level ,"%d ", j);
}
av_log(avctx, log_level, "\n");
}
for (i = 0; i < count_input_pins; i++)
{
long related_pin, pin_type;
hr = IAMCrossbar_get_CrossbarPinInfo(cross_bar, TRUE, i, &related_pin, &pin_type);
if (hr != S_OK) {
av_log(avctx, AV_LOG_ERROR, "unable to get crossbar info audio input from pin %d\n", i);
return hr;
}
av_log(avctx, log_level, " Crossbar Input pin %d - \"%s\" ", i, GetPhysicalPinName(pin_type));
av_log(avctx, log_level, "related input pin: %ld\n", related_pin);
}
return S_OK;
}
/**
* Given a fully constructed graph, check if there is a cross bar filter, and configure its pins if so.
*/
HRESULT
dshow_try_setup_crossbar_options(ICaptureGraphBuilder2 *graph_builder2,
IBaseFilter *device_filter, enum dshowDeviceType devtype, AVFormatContext *avctx)
{
struct dshow_ctx *ctx = avctx->priv_data;
IAMCrossbar *cross_bar = NULL;
IBaseFilter *cross_bar_filter = NULL;
HRESULT hr;
hr = ICaptureGraphBuilder2_FindInterface(graph_builder2, &LOOK_UPSTREAM_ONLY, (const GUID *) NULL,
(IBaseFilter *) device_filter, &IID_IAMCrossbar, (void**) &cross_bar);
if (hr != S_OK) {
/* no crossbar found */
hr = S_OK;
goto end;
}
if (ctx->show_crossbar_connection_dialog) {
hr = IAMCrossbar_QueryInterface(cross_bar, &IID_IBaseFilter, (void **) &cross_bar_filter);
if (hr != S_OK)
goto end;
dshow_show_filter_properties(cross_bar_filter, avctx);
}
hr = setup_crossbar_options(cross_bar, devtype, avctx);
if (hr != S_OK)
goto end;
end:
if (cross_bar)
IAMCrossbar_Release(cross_bar);
if (cross_bar_filter)
IBaseFilter_Release(cross_bar_filter);
return hr;
}
......@@ -320,6 +320,14 @@ libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample)
} else {
int64_t dummy;
IMediaSample_GetTime(sample, &curtime, &dummy);
if(curtime > 400000000000000000LL) {
/* initial frames sometimes start < 0 (shown as a very large number here,
like 437650244077016960 which FFmpeg doesn't like.
TODO figure out math. For now just drop them. */
av_log(NULL, AV_LOG_DEBUG,
"dshow dropping initial (or ending) audio frame with odd PTS too high %"PRId64"\n", curtime);
return S_OK;
}
curtime += pin->filter->start_time;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment