Last active
August 16, 2016 04:13
-
-
Save rdp/4949907c1cafffd0b05470bc05167c1a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c | |
index f2453e6..00e1c5e 100644 | |
--- a/libavdevice/dshow.c | |
+++ b/libavdevice/dshow.c | |
@@ -30,6 +30,11 @@ | |
#include "objidl.h" | |
#include "shlwapi.h" | |
+static int | |
+dshow_cycle_dtv_devices(AVFormatContext *avctx, const GUID *device_guid, const char *sourcetypename, const char *device_name, ICreateDevEnum *devenum, IBaseFilter **pfilter); | |
+static int | |
+dshow_connect_bda_pins(AVFormatContext *avctx, IBaseFilter *source, const char *src_pin_name, IPin *pin_out, IBaseFilter *destination, const char *dest_pin_name, | |
+IPin **lookup_pin, const char *lookup_pin_name ); | |
static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount) | |
{ | |
@@ -197,6 +202,8 @@ fail: | |
return; | |
} | |
+ | |
+ | |
/** | |
* Cycle through available devices using the device enumerator devenum, | |
* retrieve the device with type specified by devtype and return the | |
@@ -721,6 +728,100 @@ dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum, | |
return 0; | |
} | |
+ | |
+/* dshow_find_pin given a filter, direction and optional pin name, return a ref to that pin | |
+ * note this does add a reference to the pin returned... | |
+*/ | |
+static int | |
+dshow_lookup_pin(AVFormatContext *avctx, IBaseFilter *filter, PIN_DIRECTION pin_direction, IPin **discovered_pin, const char *lookup_pin_name, const char *filter_descriptive_text) { | |
+ IEnumPins *pins = 0; | |
+ IPin *pin = NULL; | |
+ IPin *local_discovered_pin = NULL; // for easier release checking | |
+ int r; | |
+ | |
+ r = IBaseFilter_EnumPins(filter, &pins); | |
+ if (r != S_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate filter %s pins.\n", filter_descriptive_text); | |
+ return AVERROR(EIO); | |
+ } | |
+ while (!local_discovered_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) { | |
+ char *name_buf; | |
+ PIN_INFO info = {0}; | |
+ | |
+ IPin_QueryPinInfo(pin, &info); | |
+ IBaseFilter_Release(info.pFilter); | |
+ name_buf = dup_wchar_to_utf8(info.achName); | |
+ av_log(avctx, AV_LOG_DEBUG, "Filter %s pin [%s] has direction %d wanted direction %d\n", filter_descriptive_text, name_buf, info.dir, pin_direction); | |
+ | |
+ if (info.dir == pin_direction) | |
+ if ( (lookup_pin_name == NULL) || //if input name empty | |
+ ((lookup_pin_name) && !(strcmp(name_buf,lookup_pin_name))) ) //or input name not empty and equal to the current pin | |
+ local_discovered_pin = pin; | |
+ if (!local_discovered_pin) | |
+ IPin_Release(pin); | |
+ } | |
+ IEnumPins_Release(pins); | |
+ | |
+ if (!local_discovered_pin) { | |
+ if (lookup_pin_name) | |
+ av_log(avctx, AV_LOG_ERROR, "Filter %s doesn't have pin with direction %d named \"%s\"\n", filter_descriptive_text, pin_direction, lookup_pin_name); | |
+ else | |
+ av_log(avctx, AV_LOG_ERROR, "Filter %s doesn't have pin with direction %d\n", filter_descriptive_text, pin_direction); | |
+ return AVERROR(EIO); | |
+ } | |
+ *discovered_pin = local_discovered_pin; | |
+ return 0; // success | |
+} | |
+ | |
+/* dshow_connect_bda_pins connects [source] filter's output pin named [src_pin_name] to [destination] filter's input pin named [dest_pin_name] | |
+ * and provides the [destination] filter's output pin named [lookup_pin_name] (or pin_out) to a pin ptr [lookup_pin] | |
+ * pin names and lookup_pin can be NULL if not needed/doesn't care | |
+*/ | |
+static int | |
+dshow_connect_bda_pins(AVFormatContext *avctx, IBaseFilter *source, const char *src_pin_name, IPin *pin_out, IBaseFilter *destination, const char *dest_pin_name, | |
+IPin **lookup_pin, const char *lookup_pin_name ) | |
+{ | |
+ struct dshow_ctx *ctx = avctx->priv_data; | |
+ IGraphBuilder *graph = NULL; | |
+ IPin *pin_in = NULL; | |
+ int r; | |
+ | |
+ graph = ctx->graph; | |
+ | |
+ if (!graph || (!source && !pin_out) || !destination) | |
+ { | |
+ av_log(avctx, AV_LOG_ERROR, "Missing graph component.\n"); | |
+ return AVERROR(EIO); | |
+ } | |
+ if (pin_out == NULL) { | |
+ r = dshow_lookup_pin(avctx, source, PINDIR_OUTPUT, &pin_out, src_pin_name, "source filter"); | |
+ if (r != S_OK) { | |
+ return r; | |
+ } | |
+ } | |
+ r = dshow_lookup_pin(avctx, destination, PINDIR_INPUT, &pin_in, dest_pin_name, "dest filter"); | |
+ if (r != S_OK) { | |
+ return r; | |
+ } | |
+ | |
+ ///connect pins | |
+ | |
+ r = IGraphBuilder_Connect(graph, pin_out, pin_in); | |
+ if (r != S_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Could not connect pins.\n"); | |
+ return AVERROR(EIO); | |
+ } | |
+ | |
+ if (lookup_pin != NULL) { | |
+ r = dshow_lookup_pin(avctx, destination, PINDIR_OUTPUT, lookup_pin, lookup_pin_name, "outgoing pin on destination"); | |
+ if (r != S_OK) { | |
+ return r; | |
+ } | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
static int | |
dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, | |
enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype) | |
@@ -798,12 +899,35 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, | |
av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n"); | |
goto error; | |
} | |
+ | |
if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) { | |
ret = r; | |
goto error; | |
} | |
+ if (sourcetype == VideoSourceDevice) { | |
+ IBaseFilter *smart_tee = NULL; | |
+ | |
+ if ((r = dshow_cycle_dtv_devices(avctx, &CLSID_LegacyAmFilterCategory, "BDA Network Tuner", "Smart Tee", devenum, &smart_tee)) < 0) { | |
+ goto error; | |
+ } | |
+ av_log(avctx, AV_LOG_DEBUG, "got smart tee\n"); | |
+ r = IGraphBuilder_AddFilter(graph, smart_tee, NULL); | |
+ if (r != S_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Could not add smart tee to graph.\n"); | |
+ goto error; | |
+ } | |
+ /* connect device_pin to smart_tee's "Input" | |
+ and assign smart_tee's "Preview" to device_pin */ | |
+ r = dshow_connect_bda_pins(avctx, NULL, NULL, device_pin, smart_tee, NULL, &device_pin, "Capture"); | |
+ if (r != S_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Could not connect smart_tee or somefin\n"); | |
+ goto error; | |
+ } | |
+ } | |
+ | |
+ | |
ctx->device_pin[devtype] = device_pin; | |
capture_filter = libAVFilter_Create(avctx, callback, devtype); | |
@@ -862,8 +986,9 @@ dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum, | |
goto error; | |
} | |
+ | |
libAVPin_AddRef(capture_filter->pin); | |
- capture_pin = capture_filter->pin; | |
+ capture_pin = capture_filter->pin; // our local pin | |
ctx->capture_pin[devtype] = capture_pin; | |
r = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER, | |
@@ -1215,7 +1340,6 @@ static int dshow_read_header(AVFormatContext *avctx) | |
av_log(avctx, AV_LOG_ERROR, "Could not run graph (sometimes caused by a device already in use by other application)\n"); | |
goto error; | |
} | |
- | |
ret = 0; | |
error: | |
@@ -1279,6 +1403,114 @@ static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt) | |
return ctx->eof ? AVERROR(EIO) : pkt->size; | |
} | |
+ | |
+/** | |
+ * Cycle through available devices using the device enumerator devenum, | |
+ * retrieve the device with type specified by devtype and return the | |
+ * pointer to the object found in *pfilter. | |
+ * If pfilter is NULL, list all device names. | |
+ */ | |
+static int | |
+dshow_cycle_dtv_devices(AVFormatContext *avctx, const GUID *device_guid, const char *sourcetypename, const char *device_name, ICreateDevEnum *devenum, IBaseFilter **pfilter) | |
+{ | |
+ struct dshow_ctx *ctx = avctx->priv_data; | |
+ IBaseFilter *device_filter = NULL; | |
+ IEnumMoniker *classenum = NULL; | |
+ IMoniker *m = NULL; | |
+ int skip = ctx->video_device_number; | |
+ int r; | |
+ | |
+ const char *devtypename = "dtv"; | |
+ | |
+ r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid, | |
+ (IEnumMoniker **) &classenum, 0); | |
+ if (r != S_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n", | |
+ devtypename); | |
+ return AVERROR(EIO); | |
+ } | |
+ | |
+ while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) { | |
+ IPropertyBag *bag = NULL; | |
+ char *friendly_name = NULL; | |
+ char *unique_name = NULL; | |
+ VARIANT var; | |
+ IBindCtx *bind_ctx = NULL; | |
+ LPOLESTR olestr = NULL; | |
+ LPMALLOC co_malloc = NULL; | |
+ int i; | |
+ | |
+ r = CoGetMalloc(1, &co_malloc); | |
+ if (r = S_OK) | |
+ goto fail1; | |
+ r = CreateBindCtx(0, &bind_ctx); | |
+ if (r != S_OK) | |
+ goto fail1; | |
+ /* GetDisplayname works for both video and audio, DevicePath doesn't */ | |
+ r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr); | |
+ if (r != S_OK) | |
+ goto fail1; | |
+ unique_name = dup_wchar_to_utf8(olestr); | |
+ /* replace ':' with '_' since we use : to delineate between sources */ | |
+ for (i = 0; i < strlen(unique_name); i++) { | |
+ if (unique_name[i] == ':') | |
+ unique_name[i] = '_'; | |
+ } | |
+ | |
+ 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; | |
+ friendly_name = dup_wchar_to_utf8(var.bstrVal); | |
+ | |
+ if (pfilter) { | |
+ av_log(avctx, AV_LOG_DEBUG, "comparing requested %s to device name %s\n", device_name, friendly_name); | |
+ if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name)) | |
+ goto fail1; | |
+ | |
+ if (!skip--) { | |
+ r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter); | |
+ if (r != S_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name); | |
+ goto fail1; | |
+ } | |
+ } | |
+ } else { | |
+ av_log(avctx, AV_LOG_INFO, " \"%s\"\n", friendly_name); | |
+ av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name); | |
+ } | |
+ | |
+fail1: | |
+ if (olestr && co_malloc) | |
+ IMalloc_Free(co_malloc, olestr); | |
+ if (bind_ctx) | |
+ IBindCtx_Release(bind_ctx); | |
+ av_free(friendly_name); | |
+ av_free(unique_name); | |
+ if (bag) | |
+ IPropertyBag_Release(bag); | |
+ IMoniker_Release(m); | |
+ } | |
+ | |
+ IEnumMoniker_Release(classenum); | |
+ | |
+ if (pfilter) { | |
+ if (!device_filter) { | |
+ av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n", | |
+ devtypename, device_name, sourcetypename); | |
+ return AVERROR(EIO); | |
+ } | |
+ *pfilter = device_filter; | |
+ } | |
+ | |
+ return 0; | |
+} | |
+ | |
+ | |
#define OFFSET(x) offsetof(struct dshow_ctx, x) | |
#define DEC AV_OPT_FLAG_DECODING_PARAM | |
static const AVOption options[] = { | |
diff --git a/libavdevice/dshow_capture.h b/libavdevice/dshow_capture.h | |
index 475d62b..8baea77 100644 | |
--- a/libavdevice/dshow_capture.h | |
+++ b/libavdevice/dshow_capture.h | |
@@ -22,7 +22,7 @@ | |
#ifndef AVDEVICE_DSHOW_CAPTURE_H | |
#define AVDEVICE_DSHOW_CAPTURE_H | |
-#define DSHOWDEBUG 0 | |
+#define DSHOWDEBUG 1 | |
#include "avdevice.h" | |
@@ -47,7 +47,7 @@ void ff_print_AM_MEDIA_TYPE(const AM_MEDIA_TYPE *type); | |
void ff_printGUID(const GUID *g); | |
extern const AVClass *ff_dshow_context_class_ptr; | |
-#define dshowdebug(...) ff_dlog(&ff_dshow_context_class_ptr, __VA_ARGS__) | |
+#define dshowdebug(...) av_log(&ff_dshow_context_class_ptr, AV_LOG_DEBUG, __VA_ARGS__) | |
static inline void nothing(void *foo) | |
{ | |
diff --git a/libavdevice/dshow_filter.c b/libavdevice/dshow_filter.c | |
index 7360adc..4039378 100644 | |
--- a/libavdevice/dshow_filter.c | |
+++ b/libavdevice/dshow_filter.c | |
@@ -146,18 +146,19 @@ libAVFilter_JoinFilterGraph(libAVFilter *this, IFilterGraph *graph, | |
this->info.pGraph = graph; | |
if (name) | |
- wcscpy(this->info.achName, name); | |
+ wcscpy(this->info.achName, name); // name is "your name" | |
return S_OK; | |
} | |
long WINAPI | |
libAVFilter_QueryVendorInfo(libAVFilter *this, wchar_t **info) | |
{ | |
- dshowdebug("libAVFilter_QueryVendorInfo(%p)\n", this); | |
+ dshowdebug("libAVFilter_QueryVendorInfo(%p) not impl\n", this); | |
+ return E_NOTIMPL; | |
if (!info) | |
return E_POINTER; | |
- *info = wcsdup(L"libAV"); | |
+ *info = NULL;//wcsdup(L"libAV"); | |
return S_OK; | |
} | |
diff --git a/libavdevice/dshow_pin.c b/libavdevice/dshow_pin.c | |
index 664246d..6e290a4 100644 | |
--- a/libavdevice/dshow_pin.c | |
+++ b/libavdevice/dshow_pin.c | |
@@ -297,6 +297,7 @@ libAVMemInputPin_GetAllocatorRequirements(libAVMemInputPin *this, | |
dshowdebug("libAVMemInputPin_GetAllocatorRequirements(%p)\n", this); | |
return E_NOTIMPL; | |
} | |
+ | |
long WINAPI | |
libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample) | |
{ | |
@@ -314,6 +315,7 @@ libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample) | |
IReferenceClock *clock = pin->filter->clock; | |
int64_t dummy; | |
struct dshow_ctx *ctx; | |
+ int hr; | |
dshowdebug("libAVMemInputPin_Receive(%p)\n", this); | |
@@ -341,7 +343,11 @@ libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample) | |
} | |
buf_size = IMediaSample_GetActualDataLength(sample); | |
- IMediaSample_GetPointer(sample, &buf); | |
+ hr = IMediaSample_GetPointer(sample, &buf); | |
+ if (hr != S_OK) { | |
+ av_log(NULL, AV_LOG_ERROR, "cannot getPointer"); | |
+ return hr; | |
+ } | |
priv_data = pin->filter->priv_data; | |
s = priv_data; | |
ctx = s->priv_data; | |
@@ -350,8 +356,8 @@ libAVMemInputPin_Receive(libAVMemInputPin *this, IMediaSample *sample) | |
av_log(NULL, AV_LOG_VERBOSE, "dshow passing through packet of type %s size %8d " | |
"timestamp %"PRId64" orig timestamp %"PRId64" graph timestamp %"PRId64" diff %"PRId64" %s\n", | |
devtypename, buf_size, curtime, orig_curtime, graphtime, graphtime - orig_curtime, ctx->device_name[devtype]); | |
- pin->filter->callback(priv_data, index, buf, buf_size, curtime, devtype); | |
- | |
+ pin->filter->callback(priv_data, index, buf, buf_size, curtime, devtype); | |
+ | |
return S_OK; | |
} | |
long WINAPI |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment