1 /*
2 * Directshow capture interface
3 * Copyright (c) 2010 Ramiro Polla
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 #include "libavutil/parseutils.h"
24 #include "libavutil/pixdesc.h"
25 #include "libavutil/opt.h"
26 #include "libavutil/mem.h"
27 #include "libavformat/internal.h"
28 #include "libavformat/riff.h"
29 #include "avdevice.h"
30 #include "libavcodec/raw.h"
31 #include "objidl.h"
32 #include "shlwapi.h"
33 // NB: technically, we should include dxva.h and use
34 // DXVA_ExtendedFormat, but that type is not defined in
35 // the MinGW headers. The DXVA2_ExtendedFormat and the
36 // contents of its fields is identical to
37 // DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
38 // and is provided by MinGW as well, so we use that
39 // instead. NB also that per the Microsoft docs, the
40 // lowest 8 bits of the structure, i.e. the SampleFormat
41 // field, contain AMCONTROL_xxx flags instead of sample
42 // format information, and should thus not be used.
43 // NB further that various values in the structure's
44 // fields (e.g. BT.2020 color space) are not provided
45 // for either of the DXVA structs, but are provided in
46 // the flags of the corresponding fields of Media Foundation.
47 // These may be provided by DirectShow devices (e.g. LAVFilters
48 // does so). So we use those values here too (the equivalence is
49 // indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
50 #include "d3d9types.h"
51 #include "dxva2api.h"
52
53 #ifndef AMCONTROL_COLORINFO_PRESENT
54 // not defined in some versions of MinGW's dvdmedia.h
55 # define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
56 #endif
57
58
dshow_pixfmt(DWORD biCompression,WORD biBitCount)59 static enum AVPixelFormat dshow_pixfmt(DWORD biCompression, WORD biBitCount)
60 {
61 switch(biCompression) {
62 case BI_BITFIELDS:
63 case BI_RGB:
64 switch(biBitCount) { /* 1-8 are untested */
65 case 1:
66 return AV_PIX_FMT_MONOWHITE;
67 case 4:
68 return AV_PIX_FMT_RGB4;
69 case 8:
70 return AV_PIX_FMT_RGB8;
71 case 16:
72 return AV_PIX_FMT_RGB555;
73 case 24:
74 return AV_PIX_FMT_BGR24;
75 case 32:
76 return AV_PIX_FMT_0RGB32;
77 }
78 }
79 return avpriv_pix_fmt_find(PIX_FMT_LIST_RAW, biCompression); // all others
80 }
81
dshow_color_range(DXVA2_ExtendedFormat * fmt_info)82 static enum AVColorRange dshow_color_range(DXVA2_ExtendedFormat *fmt_info)
83 {
84 switch (fmt_info->NominalRange)
85 {
86 case DXVA2_NominalRange_Unknown:
87 return AVCOL_RANGE_UNSPECIFIED;
88 case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
89 return AVCOL_RANGE_JPEG;
90 case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
91 return AVCOL_RANGE_MPEG;
92 case DXVA2_NominalRange_48_208:
93 // not an ffmpeg color range
94 return AVCOL_RANGE_UNSPECIFIED;
95
96 // values from MediaFoundation SDK (mfobjects.h)
97 case 4: // MFNominalRange_64_127
98 // not an ffmpeg color range
99 return AVCOL_RANGE_UNSPECIFIED;
100
101 default:
102 return AVCOL_RANGE_UNSPECIFIED;
103 }
104 }
105
dshow_color_space(DXVA2_ExtendedFormat * fmt_info)106 static enum AVColorSpace dshow_color_space(DXVA2_ExtendedFormat *fmt_info)
107 {
108 switch (fmt_info->VideoTransferMatrix)
109 {
110 case DXVA2_VideoTransferMatrix_BT709:
111 return AVCOL_SPC_BT709;
112 case DXVA2_VideoTransferMatrix_BT601:
113 return AVCOL_SPC_BT470BG;
114 case DXVA2_VideoTransferMatrix_SMPTE240M:
115 return AVCOL_SPC_SMPTE240M;
116
117 // values from MediaFoundation SDK (mfobjects.h)
118 case 4: // MFVideoTransferMatrix_BT2020_10
119 case 5: // MFVideoTransferMatrix_BT2020_12
120 if (fmt_info->VideoTransferFunction == 12) // MFVideoTransFunc_2020_const
121 return AVCOL_SPC_BT2020_CL;
122 else
123 return AVCOL_SPC_BT2020_NCL;
124
125 default:
126 return AVCOL_SPC_UNSPECIFIED;
127 }
128 }
129
dshow_color_primaries(DXVA2_ExtendedFormat * fmt_info)130 static enum AVColorPrimaries dshow_color_primaries(DXVA2_ExtendedFormat *fmt_info)
131 {
132 switch (fmt_info->VideoPrimaries)
133 {
134 case DXVA2_VideoPrimaries_Unknown:
135 return AVCOL_PRI_UNSPECIFIED;
136 case DXVA2_VideoPrimaries_reserved:
137 return AVCOL_PRI_RESERVED;
138 case DXVA2_VideoPrimaries_BT709:
139 return AVCOL_PRI_BT709;
140 case DXVA2_VideoPrimaries_BT470_2_SysM:
141 return AVCOL_PRI_BT470M;
142 case DXVA2_VideoPrimaries_BT470_2_SysBG:
143 case DXVA2_VideoPrimaries_EBU3213: // this is PAL
144 return AVCOL_PRI_BT470BG;
145 case DXVA2_VideoPrimaries_SMPTE170M:
146 case DXVA2_VideoPrimaries_SMPTE_C:
147 return AVCOL_PRI_SMPTE170M;
148 case DXVA2_VideoPrimaries_SMPTE240M:
149 return AVCOL_PRI_SMPTE240M;
150
151 // values from MediaFoundation SDK (mfobjects.h)
152 case 9: // MFVideoPrimaries_BT2020
153 return AVCOL_PRI_BT2020;
154 case 10: // MFVideoPrimaries_XYZ
155 return AVCOL_PRI_SMPTE428;
156 case 11: // MFVideoPrimaries_DCI_P3
157 return AVCOL_PRI_SMPTE431;
158 case 12: // MFVideoPrimaries_ACES (Academy Color Encoding System)
159 // not an FFmpeg color primary
160 return AVCOL_PRI_UNSPECIFIED;
161
162 default:
163 return AVCOL_PRI_UNSPECIFIED;
164 }
165 }
166
dshow_color_trc(DXVA2_ExtendedFormat * fmt_info)167 static enum AVColorTransferCharacteristic dshow_color_trc(DXVA2_ExtendedFormat *fmt_info)
168 {
169 switch (fmt_info->VideoTransferFunction)
170 {
171 case DXVA2_VideoTransFunc_Unknown:
172 return AVCOL_TRC_UNSPECIFIED;
173 case DXVA2_VideoTransFunc_10:
174 return AVCOL_TRC_LINEAR;
175 case DXVA2_VideoTransFunc_18:
176 // not an FFmpeg transfer characteristic
177 return AVCOL_TRC_UNSPECIFIED;
178 case DXVA2_VideoTransFunc_20:
179 // not an FFmpeg transfer characteristic
180 return AVCOL_TRC_UNSPECIFIED;
181 case DXVA2_VideoTransFunc_22:
182 return AVCOL_TRC_GAMMA22;
183 case DXVA2_VideoTransFunc_709:
184 return AVCOL_TRC_BT709;
185 case DXVA2_VideoTransFunc_240M:
186 return AVCOL_TRC_SMPTE240M;
187 case DXVA2_VideoTransFunc_sRGB:
188 return AVCOL_TRC_IEC61966_2_1;
189 case DXVA2_VideoTransFunc_28:
190 return AVCOL_TRC_GAMMA28;
191
192 // values from MediaFoundation SDK (mfobjects.h)
193 case 9: // MFVideoTransFunc_Log_100
194 return AVCOL_TRC_LOG;
195 case 10: // MFVideoTransFunc_Log_316
196 return AVCOL_TRC_LOG_SQRT;
197 case 11: // MFVideoTransFunc_709_sym
198 // not an FFmpeg transfer characteristic
199 return AVCOL_TRC_UNSPECIFIED;
200 case 12: // MFVideoTransFunc_2020_const
201 case 13: // MFVideoTransFunc_2020
202 if (fmt_info->VideoTransferMatrix == 5) // MFVideoTransferMatrix_BT2020_12
203 return AVCOL_TRC_BT2020_12;
204 else
205 return AVCOL_TRC_BT2020_10;
206 case 14: // MFVideoTransFunc_26
207 // not an FFmpeg transfer characteristic
208 return AVCOL_TRC_UNSPECIFIED;
209 case 15: // MFVideoTransFunc_2084
210 return AVCOL_TRC_SMPTEST2084;
211 case 16: // MFVideoTransFunc_HLG
212 return AVCOL_TRC_ARIB_STD_B67;
213 case 17: // MFVideoTransFunc_10_rel
214 // not an FFmpeg transfer characteristic? Undocumented also by MS
215 return AVCOL_TRC_UNSPECIFIED;
216
217 default:
218 return AVCOL_TRC_UNSPECIFIED;
219 }
220 }
221
dshow_chroma_loc(DXVA2_ExtendedFormat * fmt_info)222 static enum AVChromaLocation dshow_chroma_loc(DXVA2_ExtendedFormat *fmt_info)
223 {
224 if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_Cosited) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
225 return AVCHROMA_LOC_TOPLEFT;
226 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG1) // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
227 return AVCHROMA_LOC_CENTER;
228 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG2) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
229 return AVCHROMA_LOC_LEFT;
230 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_DV_PAL) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
231 return AVCHROMA_LOC_TOPLEFT;
232 else
233 // unknown
234 return AVCHROMA_LOC_UNSPECIFIED;
235 }
236
237 static int
dshow_read_close(AVFormatContext * s)238 dshow_read_close(AVFormatContext *s)
239 {
240 struct dshow_ctx *ctx = s->priv_data;
241 PacketListEntry *pktl;
242
243 if (ctx->control) {
244 IMediaControl_Stop(ctx->control);
245 IMediaControl_Release(ctx->control);
246 }
247
248 if (ctx->media_event)
249 IMediaEvent_Release(ctx->media_event);
250
251 if (ctx->graph) {
252 IEnumFilters *fenum;
253 int r;
254 r = IGraphBuilder_EnumFilters(ctx->graph, &fenum);
255 if (r == S_OK) {
256 IBaseFilter *f;
257 IEnumFilters_Reset(fenum);
258 while (IEnumFilters_Next(fenum, 1, &f, NULL) == S_OK) {
259 if (IGraphBuilder_RemoveFilter(ctx->graph, f) == S_OK)
260 IEnumFilters_Reset(fenum); /* When a filter is removed,
261 * the list must be reset. */
262 IBaseFilter_Release(f);
263 }
264 IEnumFilters_Release(fenum);
265 }
266 IGraphBuilder_Release(ctx->graph);
267 }
268
269 if (ctx->capture_pin[VideoDevice])
270 ff_dshow_pin_Release(ctx->capture_pin[VideoDevice]);
271 if (ctx->capture_pin[AudioDevice])
272 ff_dshow_pin_Release(ctx->capture_pin[AudioDevice]);
273 if (ctx->capture_filter[VideoDevice])
274 ff_dshow_filter_Release(ctx->capture_filter[VideoDevice]);
275 if (ctx->capture_filter[AudioDevice])
276 ff_dshow_filter_Release(ctx->capture_filter[AudioDevice]);
277
278 if (ctx->device_pin[VideoDevice])
279 IPin_Release(ctx->device_pin[VideoDevice]);
280 if (ctx->device_pin[AudioDevice])
281 IPin_Release(ctx->device_pin[AudioDevice]);
282 if (ctx->device_filter[VideoDevice])
283 IBaseFilter_Release(ctx->device_filter[VideoDevice]);
284 if (ctx->device_filter[AudioDevice])
285 IBaseFilter_Release(ctx->device_filter[AudioDevice]);
286
287 av_freep(&ctx->device_name[0]);
288 av_freep(&ctx->device_name[1]);
289 av_freep(&ctx->device_unique_name[0]);
290 av_freep(&ctx->device_unique_name[1]);
291
292 if(ctx->mutex)
293 CloseHandle(ctx->mutex);
294 if(ctx->event[0])
295 CloseHandle(ctx->event[0]);
296 if(ctx->event[1])
297 CloseHandle(ctx->event[1]);
298
299 pktl = ctx->pktl;
300 while (pktl) {
301 PacketListEntry *next = pktl->next;
302 av_packet_unref(&pktl->pkt);
303 av_free(pktl);
304 pktl = next;
305 }
306
307 CoUninitialize();
308
309 return 0;
310 }
311
dup_wchar_to_utf8(wchar_t * w)312 static char *dup_wchar_to_utf8(wchar_t *w)
313 {
314 char *s = NULL;
315 int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
316 s = av_malloc(l);
317 if (s)
318 WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
319 return s;
320 }
321
shall_we_drop(AVFormatContext * s,int index,enum dshowDeviceType devtype)322 static int shall_we_drop(AVFormatContext *s, int index, enum dshowDeviceType devtype)
323 {
324 struct dshow_ctx *ctx = s->priv_data;
325 static const uint8_t dropscore[] = {62, 75, 87, 100};
326 const int ndropscores = FF_ARRAY_ELEMS(dropscore);
327 unsigned int buffer_fullness = (ctx->curbufsize[index]*100)/s->max_picture_buffer;
328 const char *devtypename = (devtype == VideoDevice) ? "video" : "audio";
329
330 if(dropscore[++ctx->video_frame_num%ndropscores] <= buffer_fullness) {
331 av_log(s, AV_LOG_ERROR,
332 "real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped!\n",
333 ctx->device_name[devtype], devtypename, buffer_fullness, s->max_picture_buffer);
334 return 1;
335 }
336
337 return 0;
338 }
339
340 static void
callback(void * priv_data,int index,uint8_t * buf,int buf_size,int64_t time,enum dshowDeviceType devtype)341 callback(void *priv_data, int index, uint8_t *buf, int buf_size, int64_t time, enum dshowDeviceType devtype)
342 {
343 AVFormatContext *s = priv_data;
344 struct dshow_ctx *ctx = s->priv_data;
345 PacketListEntry **ppktl, *pktl_next;
346
347 // dump_videohdr(s, vdhdr);
348
349 WaitForSingleObject(ctx->mutex, INFINITE);
350
351 if(shall_we_drop(s, index, devtype))
352 goto fail;
353
354 pktl_next = av_mallocz(sizeof(*pktl_next));
355 if(!pktl_next)
356 goto fail;
357
358 if(av_new_packet(&pktl_next->pkt, buf_size) < 0) {
359 av_free(pktl_next);
360 goto fail;
361 }
362
363 pktl_next->pkt.stream_index = index;
364 pktl_next->pkt.pts = time;
365 memcpy(pktl_next->pkt.data, buf, buf_size);
366
367 for(ppktl = &ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->next);
368 *ppktl = pktl_next;
369 ctx->curbufsize[index] += buf_size;
370
371 SetEvent(ctx->event[1]);
372 ReleaseMutex(ctx->mutex);
373
374 return;
375 fail:
376 ReleaseMutex(ctx->mutex);
377 return;
378 }
379
380 static void
dshow_get_device_media_types(AVFormatContext * avctx,enum dshowDeviceType devtype,enum dshowSourceFilterType sourcetype,IBaseFilter * device_filter,enum AVMediaType ** media_types,int * nb_media_types)381 dshow_get_device_media_types(AVFormatContext *avctx, enum dshowDeviceType devtype,
382 enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter,
383 enum AVMediaType **media_types, int *nb_media_types)
384 {
385 IEnumPins *pins = 0;
386 IPin *pin;
387 int has_audio = 0, has_video = 0;
388
389 if (IBaseFilter_EnumPins(device_filter, &pins) != S_OK)
390 return;
391
392 while (IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
393 IKsPropertySet *p = NULL;
394 PIN_INFO info = { 0 };
395 GUID category;
396 DWORD r2;
397 IEnumMediaTypes *types = NULL;
398 AM_MEDIA_TYPE *type;
399
400 if (IPin_QueryPinInfo(pin, &info) != S_OK)
401 goto next;
402 IBaseFilter_Release(info.pFilter);
403
404 if (info.dir != PINDIR_OUTPUT)
405 goto next;
406 if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
407 goto next;
408 if (IKsPropertySet_Get(p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
409 NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
410 goto next;
411 if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
412 goto next;
413
414 if (IPin_EnumMediaTypes(pin, &types) != S_OK)
415 goto next;
416
417 // enumerate media types exposed by pin
418 // NB: don't know if a pin can expose both audio and video, check 'm all to be safe
419 IEnumMediaTypes_Reset(types);
420 while (IEnumMediaTypes_Next(types, 1, &type, NULL) == S_OK) {
421 if (IsEqualGUID(&type->majortype, &MEDIATYPE_Video)) {
422 has_video = 1;
423 } else if (IsEqualGUID(&type->majortype, &MEDIATYPE_Audio)) {
424 has_audio = 1;
425 }
426 CoTaskMemFree(type);
427 }
428
429 next:
430 if (types)
431 IEnumMediaTypes_Release(types);
432 if (p)
433 IKsPropertySet_Release(p);
434 if (pin)
435 IPin_Release(pin);
436 }
437
438 IEnumPins_Release(pins);
439
440 if (has_audio || has_video) {
441 int nb_types = has_audio + has_video;
442 *media_types = av_malloc_array(nb_types, sizeof(enum AVMediaType));
443 if (*media_types) {
444 if (has_audio)
445 (*media_types)[0] = AVMEDIA_TYPE_AUDIO;
446 if (has_video)
447 (*media_types)[0 + has_audio] = AVMEDIA_TYPE_VIDEO;
448 *nb_media_types = nb_types;
449 }
450 }
451 }
452
453 /**
454 * Cycle through available devices using the device enumerator devenum,
455 * retrieve the device with type specified by devtype and return the
456 * pointer to the object found in *pfilter.
457 * If pfilter is NULL, list all device names.
458 * If device_list is not NULL, populate it with found devices instead of
459 * outputting device names to log
460 */
461 static int
dshow_cycle_devices(AVFormatContext * avctx,ICreateDevEnum * devenum,enum dshowDeviceType devtype,enum dshowSourceFilterType sourcetype,IBaseFilter ** pfilter,char ** device_unique_name,AVDeviceInfoList ** device_list)462 dshow_cycle_devices(AVFormatContext *avctx, ICreateDevEnum *devenum,
463 enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype,
464 IBaseFilter **pfilter, char **device_unique_name,
465 AVDeviceInfoList **device_list)
466 {
467 struct dshow_ctx *ctx = avctx->priv_data;
468 IBaseFilter *device_filter = NULL;
469 IEnumMoniker *classenum = NULL;
470 IMoniker *m = NULL;
471 const char *device_name = ctx->device_name[devtype];
472 int skip = (devtype == VideoDevice) ? ctx->video_device_number
473 : ctx->audio_device_number;
474 int r;
475
476 const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
477 &CLSID_AudioInputDeviceCategory };
478 const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
479 const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
480
481 r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype],
482 (IEnumMoniker **) &classenum, 0);
483 if (r != S_OK) {
484 av_log(avctx, AV_LOG_ERROR, "Could not enumerate %s devices (or none found).\n",
485 devtypename);
486 return AVERROR(EIO);
487 }
488
489 while (!device_filter && IEnumMoniker_Next(classenum, 1, &m, NULL) == S_OK) {
490 IPropertyBag *bag = NULL;
491 char *friendly_name = NULL;
492 char *unique_name = NULL;
493 VARIANT var;
494 IBindCtx *bind_ctx = NULL;
495 LPOLESTR olestr = NULL;
496 LPMALLOC co_malloc = NULL;
497 AVDeviceInfo *device = NULL;
498 enum AVMediaType *media_types = NULL;
499 int nb_media_types = 0;
500 int i;
501
502 r = CoGetMalloc(1, &co_malloc);
503 if (r != S_OK)
504 goto fail;
505 r = CreateBindCtx(0, &bind_ctx);
506 if (r != S_OK)
507 goto fail;
508 /* GetDisplayname works for both video and audio, DevicePath doesn't */
509 r = IMoniker_GetDisplayName(m, bind_ctx, NULL, &olestr);
510 if (r != S_OK)
511 goto fail;
512 unique_name = dup_wchar_to_utf8(olestr);
513 /* replace ':' with '_' since we use : to delineate between sources */
514 for (i = 0; i < strlen(unique_name); i++) {
515 if (unique_name[i] == ':')
516 unique_name[i] = '_';
517 }
518
519 r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (void *) &bag);
520 if (r != S_OK)
521 goto fail;
522
523 var.vt = VT_BSTR;
524 r = IPropertyBag_Read(bag, L"FriendlyName", &var, NULL);
525 if (r != S_OK)
526 goto fail;
527 friendly_name = dup_wchar_to_utf8(var.bstrVal);
528
529 if (pfilter) {
530 if (strcmp(device_name, friendly_name) && strcmp(device_name, unique_name))
531 goto fail;
532
533 if (!skip--) {
534 r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void *) &device_filter);
535 if (r != S_OK) {
536 av_log(avctx, AV_LOG_ERROR, "Unable to BindToObject for %s\n", device_name);
537 goto fail;
538 }
539 *device_unique_name = unique_name;
540 unique_name = NULL;
541 // success, loop will end now
542 }
543 } else {
544 // get media types exposed by pins of device
545 if (IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (void* ) &device_filter) == S_OK) {
546 dshow_get_device_media_types(avctx, devtype, sourcetype, device_filter, &media_types, &nb_media_types);
547 IBaseFilter_Release(device_filter);
548 device_filter = NULL;
549 }
550 if (device_list) {
551 device = av_mallocz(sizeof(AVDeviceInfo));
552 if (!device)
553 goto fail;
554
555 device->device_name = av_strdup(unique_name);
556 device->device_description = av_strdup(friendly_name);
557 if (!device->device_name || !device->device_description)
558 goto fail;
559
560 // make space in device_list for this new device
561 if (av_reallocp_array(&(*device_list)->devices,
562 (*device_list)->nb_devices + 1,
563 sizeof(*(*device_list)->devices)) < 0)
564 goto fail;
565
566 // attach media_types to device
567 device->nb_media_types = nb_media_types;
568 device->media_types = media_types;
569 nb_media_types = 0;
570 media_types = NULL;
571
572 // store device in list
573 (*device_list)->devices[(*device_list)->nb_devices] = device;
574 (*device_list)->nb_devices++;
575 device = NULL; // copied into array, make sure not freed below
576 }
577 else {
578 av_log(avctx, AV_LOG_INFO, "\"%s\"", friendly_name);
579 if (nb_media_types > 0) {
580 const char* media_type = av_get_media_type_string(media_types[0]);
581 av_log(avctx, AV_LOG_INFO, " (%s", media_type ? media_type : "unknown");
582 for (int i = 1; i < nb_media_types; ++i) {
583 media_type = av_get_media_type_string(media_types[i]);
584 av_log(avctx, AV_LOG_INFO, ", %s", media_type ? media_type : "unknown");
585 }
586 av_log(avctx, AV_LOG_INFO, ")");
587 } else {
588 av_log(avctx, AV_LOG_INFO, " (none)");
589 }
590 av_log(avctx, AV_LOG_INFO, "\n");
591 av_log(avctx, AV_LOG_INFO, " Alternative name \"%s\"\n", unique_name);
592 }
593 }
594
595 fail:
596 av_freep(&media_types);
597 if (device) {
598 av_freep(&device->device_name);
599 av_freep(&device->device_description);
600 // NB: no need to av_freep(&device->media_types), its only moved to device once nothing can fail anymore
601 av_free(device);
602 }
603 if (olestr && co_malloc)
604 IMalloc_Free(co_malloc, olestr);
605 if (bind_ctx)
606 IBindCtx_Release(bind_ctx);
607 av_freep(&friendly_name);
608 av_freep(&unique_name);
609 if (bag)
610 IPropertyBag_Release(bag);
611 IMoniker_Release(m);
612 }
613
614 IEnumMoniker_Release(classenum);
615
616 if (pfilter) {
617 if (!device_filter) {
618 av_log(avctx, AV_LOG_ERROR, "Could not find %s device with name [%s] among source devices of type %s.\n",
619 devtypename, device_name, sourcetypename);
620 return AVERROR(EIO);
621 }
622 *pfilter = device_filter;
623 }
624
625 return 0;
626 }
627
dshow_get_device_list(AVFormatContext * avctx,AVDeviceInfoList * device_list)628 static int dshow_get_device_list(AVFormatContext *avctx, AVDeviceInfoList *device_list)
629 {
630 ICreateDevEnum *devenum = NULL;
631 int r;
632 int ret = AVERROR(EIO);
633
634 if (!device_list)
635 return AVERROR(EINVAL);
636
637 CoInitialize(0);
638
639 r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
640 &IID_ICreateDevEnum, (void**)&devenum);
641 if (r != S_OK) {
642 av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
643 goto error;
644 }
645
646 ret = dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, &device_list);
647 if (ret < S_OK)
648 goto error;
649 ret = dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, &device_list);
650
651 error:
652 if (devenum)
653 ICreateDevEnum_Release(devenum);
654
655 CoUninitialize();
656
657 return ret;
658 }
659
dshow_should_set_format(AVFormatContext * avctx,enum dshowDeviceType devtype)660 static int dshow_should_set_format(AVFormatContext *avctx, enum dshowDeviceType devtype)
661 {
662 struct dshow_ctx *ctx = avctx->priv_data;
663
664 return (devtype == VideoDevice && (ctx->framerate ||
665 (ctx->requested_width && ctx->requested_height) ||
666 ctx->pixel_format != AV_PIX_FMT_NONE ||
667 ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO))
668 || (devtype == AudioDevice && (ctx->channels || ctx->sample_size || ctx->sample_rate));
669 }
670
671
672 struct dshow_format_info {
673 enum dshowDeviceType devtype;
674 // video
675 int64_t framerate;
676 enum AVPixelFormat pix_fmt;
677 enum AVCodecID codec_id;
678 enum AVColorRange col_range;
679 enum AVColorSpace col_space;
680 enum AVColorPrimaries col_prim;
681 enum AVColorTransferCharacteristic col_trc;
682 enum AVChromaLocation chroma_loc;
683 int width;
684 int height;
685 // audio
686 int sample_rate;
687 int sample_size;
688 int channels;
689 };
690
691 // user must av_free the returned pointer
dshow_get_format_info(AM_MEDIA_TYPE * type)692 static struct dshow_format_info *dshow_get_format_info(AM_MEDIA_TYPE *type)
693 {
694 struct dshow_format_info *fmt_info = NULL;
695 BITMAPINFOHEADER *bih;
696 DXVA2_ExtendedFormat *extended_format_info = NULL;
697 WAVEFORMATEX *fx;
698 enum dshowDeviceType devtype;
699 int64_t framerate;
700
701 if (!type)
702 return NULL;
703
704 if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
705 VIDEOINFOHEADER *v = (void *) type->pbFormat;
706 framerate = v->AvgTimePerFrame;
707 bih = &v->bmiHeader;
708 devtype = VideoDevice;
709 } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
710 VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
711 devtype = VideoDevice;
712 framerate = v->AvgTimePerFrame;
713 bih = &v->bmiHeader;
714 if (v->dwControlFlags & AMCONTROL_COLORINFO_PRESENT)
715 extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
716 } else if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
717 fx = (void *) type->pbFormat;
718 devtype = AudioDevice;
719 } else {
720 return NULL;
721 }
722
723 fmt_info = av_mallocz(sizeof(struct dshow_format_info));
724 if (!fmt_info)
725 return NULL;
726 // initialize fields where unset is not zero
727 fmt_info->pix_fmt = AV_PIX_FMT_NONE;
728 fmt_info->col_space = AVCOL_SPC_UNSPECIFIED;
729 fmt_info->col_prim = AVCOL_PRI_UNSPECIFIED;
730 fmt_info->col_trc = AVCOL_TRC_UNSPECIFIED;
731 // now get info about format
732 fmt_info->devtype = devtype;
733 if (devtype == VideoDevice) {
734 fmt_info->width = bih->biWidth;
735 fmt_info->height = bih->biHeight;
736 fmt_info->framerate = framerate;
737 fmt_info->pix_fmt = dshow_pixfmt(bih->biCompression, bih->biBitCount);
738 if (fmt_info->pix_fmt == AV_PIX_FMT_NONE) {
739 const AVCodecTag *const tags[] = { avformat_get_riff_video_tags(), NULL };
740 fmt_info->codec_id = av_codec_get_id(tags, bih->biCompression);
741 }
742 else
743 fmt_info->codec_id = AV_CODEC_ID_RAWVIDEO;
744
745 if (extended_format_info) {
746 fmt_info->col_range = dshow_color_range(extended_format_info);
747 fmt_info->col_space = dshow_color_space(extended_format_info);
748 fmt_info->col_prim = dshow_color_primaries(extended_format_info);
749 fmt_info->col_trc = dshow_color_trc(extended_format_info);
750 fmt_info->chroma_loc = dshow_chroma_loc(extended_format_info);
751 }
752 } else {
753 fmt_info->sample_rate = fx->nSamplesPerSec;
754 fmt_info->sample_size = fx->wBitsPerSample;
755 fmt_info->channels = fx->nChannels;
756 }
757
758 return fmt_info;
759 }
760
dshow_get_default_format(IPin * pin,IAMStreamConfig * config,enum dshowDeviceType devtype,AM_MEDIA_TYPE ** type)761 static void dshow_get_default_format(IPin *pin, IAMStreamConfig *config, enum dshowDeviceType devtype, AM_MEDIA_TYPE **type)
762 {
763 HRESULT hr;
764
765 if ((hr = IAMStreamConfig_GetFormat(config, type)) != S_OK) {
766 if (hr == E_NOTIMPL || !IsEqualGUID(&(*type)->majortype, devtype == VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
767 // default not available or of wrong type,
768 // fall back to iterating exposed formats
769 // until one of the right type is found
770 IEnumMediaTypes* types = NULL;
771 if (IPin_EnumMediaTypes(pin, &types) != S_OK)
772 return;
773 IEnumMediaTypes_Reset(types);
774 while (IEnumMediaTypes_Next(types, 1, type, NULL) == S_OK) {
775 if (IsEqualGUID(&(*type)->majortype, devtype == VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
776 break;
777 }
778 CoTaskMemFree(*type);
779 *type = NULL;
780 }
781 IEnumMediaTypes_Release(types);
782 }
783 }
784 }
785
786 /**
787 * Cycle through available formats available from the specified pin,
788 * try to set parameters specified through AVOptions, or the pin's
789 * default format if no such parameters were set. If successful,
790 * return 1 in *pformat_set.
791 * If pformat_set is NULL, list all pin capabilities.
792 */
793 static void
dshow_cycle_formats(AVFormatContext * avctx,enum dshowDeviceType devtype,IPin * pin,int * pformat_set)794 dshow_cycle_formats(AVFormatContext *avctx, enum dshowDeviceType devtype,
795 IPin *pin, int *pformat_set)
796 {
797 struct dshow_ctx *ctx = avctx->priv_data;
798 IAMStreamConfig *config = NULL;
799 AM_MEDIA_TYPE *type = NULL;
800 AM_MEDIA_TYPE *previous_match_type = NULL;
801 int format_set = 0;
802 void *caps = NULL;
803 int i, n, size, r;
804 int wait_for_better = 0;
805 int use_default;
806
807 // format parameters requested by user
808 // if none are requested by user, the values will below be set to
809 // those of the default format
810 // video
811 enum AVCodecID requested_video_codec_id = ctx->video_codec_id;
812 enum AVPixelFormat requested_pixel_format = ctx->pixel_format;
813 int64_t requested_framerate = ctx->framerate ? ((int64_t)ctx->requested_framerate.den * 10000000)
814 / ctx->requested_framerate.num : 0;
815 int requested_width = ctx->requested_width;
816 int requested_height = ctx->requested_height;
817 // audio
818 int requested_sample_rate = ctx->sample_rate;
819 int requested_sample_size = ctx->sample_size;
820 int requested_channels = ctx->channels;
821
822 if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
823 return;
824 if (IAMStreamConfig_GetNumberOfCapabilities(config, &n, &size) != S_OK)
825 goto end;
826
827 caps = av_malloc(size);
828 if (!caps)
829 goto end;
830
831 /**
832 * If we should open the device with the default format,
833 * then:
834 * 1. check what the format of the default device is, and
835 * 2. below we iterate all formats till we find a matching
836 * one, with most info exposed (see comment below).
837 */
838 use_default = !dshow_should_set_format(avctx, devtype);
839 if (use_default && pformat_set)
840 {
841 // get default
842 dshow_get_default_format(pin, config, devtype, &type);
843 if (!type)
844 // this pin does not expose any formats of the expected type
845 goto end;
846
847 if (type) {
848 // interrogate default format, so we know what to search for below
849 struct dshow_format_info *fmt_info = dshow_get_format_info(type);
850 if (fmt_info) {
851 if (fmt_info->devtype == VideoDevice) {
852 requested_video_codec_id = fmt_info->codec_id;
853 requested_pixel_format = fmt_info->pix_fmt;
854 requested_framerate = fmt_info->framerate;
855 requested_width = fmt_info->width;
856 requested_height = fmt_info->height;
857 } else {
858 requested_sample_rate = fmt_info->sample_rate;
859 requested_sample_size = fmt_info->sample_size;
860 requested_channels = fmt_info->channels;
861 }
862 av_free(fmt_info); // free but don't set to NULL to enable below check
863 }
864
865 if (type && type->pbFormat)
866 CoTaskMemFree(type->pbFormat);
867 CoTaskMemFree(type);
868 type = NULL;
869 if (!fmt_info)
870 // default format somehow invalid, can't continue with this pin
871 goto end;
872 fmt_info = NULL;
873 }
874 }
875
876 // NB: some devices (e.g. Logitech C920) expose each video format twice:
877 // both a format containing a VIDEOINFOHEADER and a format containing
878 // a VIDEOINFOHEADER2. We want, if possible, to select a format with a
879 // VIDEOINFOHEADER2, as this potentially provides more info about the
880 // format. So, if in the iteration below we have found a matching format,
881 // but it is a VIDEOINFOHEADER, keep looking for a matching format that
882 // exposes contains a VIDEOINFOHEADER2. Fall back to the VIDEOINFOHEADER
883 // format if no corresponding VIDEOINFOHEADER2 is found when we finish
884 // iterating.
885 for (i = 0; i < n && !format_set; i++) {
886 struct dshow_format_info *fmt_info = NULL;
887 r = IAMStreamConfig_GetStreamCaps(config, i, &type, (void *) caps);
888 if (r != S_OK)
889 goto next;
890 #if DSHOWDEBUG
891 ff_print_AM_MEDIA_TYPE(type);
892 #endif
893
894 fmt_info = dshow_get_format_info(type);
895 if (!fmt_info)
896 goto next;
897
898 if (devtype == VideoDevice) {
899 VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
900 BITMAPINFOHEADER *bih;
901 int64_t *fr;
902 #if DSHOWDEBUG
903 ff_print_VIDEO_STREAM_CONFIG_CAPS(vcaps);
904 #endif
905
906 if (fmt_info->devtype != VideoDevice)
907 goto next;
908
909 if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo)) {
910 VIDEOINFOHEADER *v = (void *) type->pbFormat;
911 fr = &v->AvgTimePerFrame;
912 bih = &v->bmiHeader;
913 wait_for_better = 1;
914 } else if (IsEqualGUID(&type->formattype, &FORMAT_VideoInfo2)) {
915 VIDEOINFOHEADER2 *v = (void *) type->pbFormat;
916 fr = &v->AvgTimePerFrame;
917 bih = &v->bmiHeader;
918 wait_for_better = 0;
919 }
920
921 if (!pformat_set) {
922 const char *chroma = av_chroma_location_name(fmt_info->chroma_loc);
923 if (fmt_info->pix_fmt == AV_PIX_FMT_NONE) {
924 const AVCodec *codec = avcodec_find_decoder(fmt_info->codec_id);
925 if (fmt_info->codec_id == AV_CODEC_ID_NONE || !codec) {
926 av_log(avctx, AV_LOG_INFO, " unknown compression type 0x%X", (int) bih->biCompression);
927 } else {
928 av_log(avctx, AV_LOG_INFO, " vcodec=%s", codec->name);
929 }
930 } else {
931 av_log(avctx, AV_LOG_INFO, " pixel_format=%s", av_get_pix_fmt_name(fmt_info->pix_fmt));
932 }
933 av_log(avctx, AV_LOG_INFO, " min s=%ldx%ld fps=%g max s=%ldx%ld fps=%g",
934 vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
935 1e7 / vcaps->MaxFrameInterval,
936 vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
937 1e7 / vcaps->MinFrameInterval);
938
939 if (fmt_info->col_range != AVCOL_RANGE_UNSPECIFIED ||
940 fmt_info->col_space != AVCOL_SPC_UNSPECIFIED ||
941 fmt_info->col_prim != AVCOL_PRI_UNSPECIFIED ||
942 fmt_info->col_trc != AVCOL_TRC_UNSPECIFIED) {
943 const char *range = av_color_range_name(fmt_info->col_range);
944 const char *space = av_color_space_name(fmt_info->col_space);
945 const char *prim = av_color_primaries_name(fmt_info->col_prim);
946 const char *trc = av_color_transfer_name(fmt_info->col_trc);
947 av_log(avctx, AV_LOG_INFO, " (%s, %s/%s/%s",
948 range ? range : "unknown",
949 space ? space : "unknown",
950 prim ? prim : "unknown",
951 trc ? trc : "unknown");
952 if (fmt_info->chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
953 av_log(avctx, AV_LOG_INFO, ", %s", chroma ? chroma : "unknown");
954 av_log(avctx, AV_LOG_INFO, ")");
955 }
956 else if (fmt_info->chroma_loc != AVCHROMA_LOC_UNSPECIFIED)
957 av_log(avctx, AV_LOG_INFO, "(%s)", chroma ? chroma : "unknown");
958
959 av_log(avctx, AV_LOG_INFO, "\n");
960 goto next;
961 }
962 if (requested_video_codec_id != AV_CODEC_ID_RAWVIDEO) {
963 if (requested_video_codec_id != fmt_info->codec_id)
964 goto next;
965 }
966 if (requested_pixel_format != AV_PIX_FMT_NONE &&
967 requested_pixel_format != fmt_info->pix_fmt) {
968 goto next;
969 }
970 if (requested_framerate) {
971 if (requested_framerate > vcaps->MaxFrameInterval ||
972 requested_framerate < vcaps->MinFrameInterval)
973 goto next;
974 *fr = requested_framerate;
975 }
976 if (requested_width && requested_height) {
977 if (requested_width > vcaps->MaxOutputSize.cx ||
978 requested_width < vcaps->MinOutputSize.cx ||
979 requested_height > vcaps->MaxOutputSize.cy ||
980 requested_height < vcaps->MinOutputSize.cy)
981 goto next;
982 bih->biWidth = requested_width;
983 bih->biHeight = requested_height;
984 }
985 } else {
986 WAVEFORMATEX *fx;
987 AUDIO_STREAM_CONFIG_CAPS *acaps = caps;
988 #if DSHOWDEBUG
989 ff_print_AUDIO_STREAM_CONFIG_CAPS(acaps);
990 #endif
991 if (IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx)) {
992 fx = (void *) type->pbFormat;
993 } else {
994 goto next;
995 }
996 if (!pformat_set) {
997 av_log(
998 avctx,
999 AV_LOG_INFO,
1000 " ch=%2u, bits=%2u, rate=%6lu\n",
1001 fx->nChannels, fx->wBitsPerSample, fx->nSamplesPerSec
1002 );
1003 continue;
1004 }
1005 if (
1006 (requested_sample_rate && requested_sample_rate != fx->nSamplesPerSec) ||
1007 (requested_sample_size && requested_sample_size != fx->wBitsPerSample) ||
1008 (requested_channels && requested_channels != fx->nChannels )
1009 ) {
1010 goto next;
1011 }
1012 }
1013
1014 // found a matching format. Either apply or store
1015 // for safekeeping if we might maybe find a better
1016 // format with more info attached to it (see comment
1017 // above loop)
1018 if (!wait_for_better) {
1019 if (IAMStreamConfig_SetFormat(config, type) != S_OK)
1020 goto next;
1021 format_set = 1;
1022 }
1023 else if (!previous_match_type) {
1024 // store this matching format for possible later use.
1025 // If we have already found a matching format, ignore it
1026 previous_match_type = type;
1027 type = NULL;
1028 }
1029 next:
1030 av_freep(&fmt_info);
1031 if (type && type->pbFormat)
1032 CoTaskMemFree(type->pbFormat);
1033 CoTaskMemFree(type);
1034 type = NULL;
1035 }
1036
1037 // set the pin's format, if wanted
1038 if (pformat_set && !format_set) {
1039 if (previous_match_type) {
1040 // previously found a matching VIDEOINFOHEADER format and stored
1041 // it for safe keeping. Searching further for a matching
1042 // VIDEOINFOHEADER2 format yielded nothing. So set the pin's
1043 // format based on the VIDEOINFOHEADER format.
1044 // NB: this never applies to an audio format because
1045 // previous_match_type always NULL in that case
1046 if (IAMStreamConfig_SetFormat(config, previous_match_type) == S_OK)
1047 format_set = 1;
1048 }
1049 else if (use_default) {
1050 // default format returned by device apparently was not contained
1051 // in the capabilities of any of the formats returned by the device
1052 // (sic?). Fall back to directly setting the default format
1053 dshow_get_default_format(pin, config, devtype, &type);
1054 if (IAMStreamConfig_SetFormat(config, type) == S_OK)
1055 format_set = 1;
1056 if (type && type->pbFormat)
1057 CoTaskMemFree(type->pbFormat);
1058 CoTaskMemFree(type);
1059 type = NULL;
1060 }
1061 }
1062
1063 end:
1064 if (previous_match_type && previous_match_type->pbFormat)
1065 CoTaskMemFree(previous_match_type->pbFormat);
1066 CoTaskMemFree(previous_match_type);
1067 IAMStreamConfig_Release(config);
1068 av_free(caps);
1069 if (pformat_set)
1070 *pformat_set = format_set;
1071 }
1072
1073 /**
1074 * Set audio device buffer size in milliseconds (which can directly impact
1075 * latency, depending on the device).
1076 */
1077 static int
dshow_set_audio_buffer_size(AVFormatContext * avctx,IPin * pin)1078 dshow_set_audio_buffer_size(AVFormatContext *avctx, IPin *pin)
1079 {
1080 struct dshow_ctx *ctx = avctx->priv_data;
1081 IAMBufferNegotiation *buffer_negotiation = NULL;
1082 ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
1083 IAMStreamConfig *config = NULL;
1084 AM_MEDIA_TYPE *type = NULL;
1085 int ret = AVERROR(EIO);
1086
1087 if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (void **) &config) != S_OK)
1088 goto end;
1089 if (IAMStreamConfig_GetFormat(config, &type) != S_OK)
1090 goto end;
1091 if (!IsEqualGUID(&type->formattype, &FORMAT_WaveFormatEx))
1092 goto end;
1093
1094 props.cbBuffer = (((WAVEFORMATEX *) type->pbFormat)->nAvgBytesPerSec)
1095 * ctx->audio_buffer_size / 1000;
1096
1097 if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (void **) &buffer_negotiation) != S_OK)
1098 goto end;
1099 if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK)
1100 goto end;
1101
1102 ret = 0;
1103
1104 end:
1105 if (buffer_negotiation)
1106 IAMBufferNegotiation_Release(buffer_negotiation);
1107 if (type) {
1108 if (type->pbFormat)
1109 CoTaskMemFree(type->pbFormat);
1110 CoTaskMemFree(type);
1111 }
1112 if (config)
1113 IAMStreamConfig_Release(config);
1114
1115 return ret;
1116 }
1117
1118 /**
1119 * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
1120 */
1121 void
ff_dshow_show_filter_properties(IBaseFilter * device_filter,AVFormatContext * avctx)1122 ff_dshow_show_filter_properties(IBaseFilter *device_filter, AVFormatContext *avctx) {
1123 ISpecifyPropertyPages *property_pages = NULL;
1124 IUnknown *device_filter_iunknown = NULL;
1125 HRESULT hr;
1126 FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
1127 CAUUID ca_guid = {0};
1128
1129 hr = IBaseFilter_QueryInterface(device_filter, &IID_ISpecifyPropertyPages, (void **)&property_pages);
1130 if (hr != S_OK) {
1131 av_log(avctx, AV_LOG_WARNING, "requested filter does not have a property page to show");
1132 goto end;
1133 }
1134 hr = IBaseFilter_QueryFilterInfo(device_filter, &filter_info);
1135 if (hr != S_OK) {
1136 goto fail;
1137 }
1138 hr = IBaseFilter_QueryInterface(device_filter, &IID_IUnknown, (void **)&device_filter_iunknown);
1139 if (hr != S_OK) {
1140 goto fail;
1141 }
1142 hr = ISpecifyPropertyPages_GetPages(property_pages, &ca_guid);
1143 if (hr != S_OK) {
1144 goto fail;
1145 }
1146 hr = OleCreatePropertyFrame(NULL, 0, 0, filter_info.achName, 1, &device_filter_iunknown, ca_guid.cElems,
1147 ca_guid.pElems, 0, 0, NULL);
1148 if (hr != S_OK) {
1149 goto fail;
1150 }
1151 goto end;
1152 fail:
1153 av_log(avctx, AV_LOG_ERROR, "Failure showing property pages for filter");
1154 end:
1155 if (property_pages)
1156 ISpecifyPropertyPages_Release(property_pages);
1157 if (device_filter_iunknown)
1158 IUnknown_Release(device_filter_iunknown);
1159 if (filter_info.pGraph)
1160 IFilterGraph_Release(filter_info.pGraph);
1161 if (ca_guid.pElems)
1162 CoTaskMemFree(ca_guid.pElems);
1163 }
1164
1165 /**
1166 * Cycle through available pins using the device_filter device, of type
1167 * devtype, retrieve the first output pin and return the pointer to the
1168 * object found in *ppin.
1169 * If ppin is NULL, cycle through all pins listing audio/video capabilities.
1170 */
1171 static int
dshow_cycle_pins(AVFormatContext * avctx,enum dshowDeviceType devtype,enum dshowSourceFilterType sourcetype,IBaseFilter * device_filter,IPin ** ppin)1172 dshow_cycle_pins(AVFormatContext *avctx, enum dshowDeviceType devtype,
1173 enum dshowSourceFilterType sourcetype, IBaseFilter *device_filter, IPin **ppin)
1174 {
1175 struct dshow_ctx *ctx = avctx->priv_data;
1176 IEnumPins *pins = 0;
1177 IPin *device_pin = NULL;
1178 IPin *pin;
1179 int r;
1180
1181 const char *devtypename = (devtype == VideoDevice) ? "video" : "audio only";
1182 const char *sourcetypename = (sourcetype == VideoSourceDevice) ? "video" : "audio";
1183
1184 int set_format = dshow_should_set_format(avctx, devtype);
1185 int format_set = 0;
1186 int should_show_properties = (devtype == VideoDevice) ? ctx->show_video_device_dialog : ctx->show_audio_device_dialog;
1187
1188 if (should_show_properties)
1189 ff_dshow_show_filter_properties(device_filter, avctx);
1190
1191 r = IBaseFilter_EnumPins(device_filter, &pins);
1192 if (r != S_OK) {
1193 av_log(avctx, AV_LOG_ERROR, "Could not enumerate pins.\n");
1194 return AVERROR(EIO);
1195 }
1196
1197 if (!ppin) {
1198 av_log(avctx, AV_LOG_INFO, "DirectShow %s device options (from %s devices)\n",
1199 devtypename, sourcetypename);
1200 }
1201
1202 while (!device_pin && IEnumPins_Next(pins, 1, &pin, NULL) == S_OK) {
1203 IKsPropertySet *p = NULL;
1204 PIN_INFO info = {0};
1205 GUID category;
1206 DWORD r2;
1207 char *name_buf = NULL;
1208 wchar_t *pin_id = NULL;
1209 char *pin_buf = NULL;
1210 char *desired_pin_name = devtype == VideoDevice ? ctx->video_pin_name : ctx->audio_pin_name;
1211
1212 IPin_QueryPinInfo(pin, &info);
1213 IBaseFilter_Release(info.pFilter);
1214
1215 if (info.dir != PINDIR_OUTPUT)
1216 goto next;
1217 if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (void **) &p) != S_OK)
1218 goto next;
1219 if (IKsPropertySet_Get(p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
1220 NULL, 0, &category, sizeof(GUID), &r2) != S_OK)
1221 goto next;
1222 if (!IsEqualGUID(&category, &PIN_CATEGORY_CAPTURE))
1223 goto next;
1224 name_buf = dup_wchar_to_utf8(info.achName);
1225
1226 r = IPin_QueryId(pin, &pin_id);
1227 if (r != S_OK) {
1228 av_log(avctx, AV_LOG_ERROR, "Could not query pin id\n");
1229 return AVERROR(EIO);
1230 }
1231 pin_buf = dup_wchar_to_utf8(pin_id);
1232
1233 if (!ppin) {
1234 av_log(avctx, AV_LOG_INFO, " Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
1235 dshow_cycle_formats(avctx, devtype, pin, NULL);
1236 goto next;
1237 }
1238
1239 if (desired_pin_name) {
1240 if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
1241 av_log(avctx, AV_LOG_DEBUG, "skipping pin \"%s\" (\"%s\") != requested \"%s\"\n",
1242 name_buf, pin_buf, desired_pin_name);
1243 goto next;
1244 }
1245 }
1246
1247 // will either try to find format matching options supplied by user
1248 // or try to open default format. Successful if returns with format_set==1
1249 dshow_cycle_formats(avctx, devtype, pin, &format_set);
1250 if (!format_set) {
1251 goto next;
1252 }
1253
1254 if (devtype == AudioDevice && ctx->audio_buffer_size) {
1255 if (dshow_set_audio_buffer_size(avctx, pin) < 0) {
1256 av_log(avctx, AV_LOG_ERROR, "unable to set audio buffer size %d to pin, using pin anyway...", ctx->audio_buffer_size);
1257 }
1258 }
1259
1260 if (format_set) {
1261 device_pin = pin;
1262 av_log(avctx, AV_LOG_DEBUG, "Selecting pin %s on %s\n", name_buf, devtypename);
1263 }
1264 next:
1265 if (p)
1266 IKsPropertySet_Release(p);
1267 if (device_pin != pin)
1268 IPin_Release(pin);
1269 av_free(name_buf);
1270 av_free(pin_buf);
1271 if (pin_id)
1272 CoTaskMemFree(pin_id);
1273 }
1274
1275 IEnumPins_Release(pins);
1276
1277 if (ppin) {
1278 if (set_format && !format_set) {
1279 av_log(avctx, AV_LOG_ERROR, "Could not set %s options\n", devtypename);
1280 return AVERROR(EIO);
1281 }
1282 if (!device_pin) {
1283 av_log(avctx, AV_LOG_ERROR,
1284 "Could not find output pin from %s capture device.\n", devtypename);
1285 return AVERROR(EIO);
1286 }
1287 *ppin = device_pin;
1288 }
1289
1290 return 0;
1291 }
1292
1293 /**
1294 * List options for device with type devtype, source filter type sourcetype
1295 *
1296 * @param devenum device enumerator used for accessing the device
1297 */
1298 static int
dshow_list_device_options(AVFormatContext * avctx,ICreateDevEnum * devenum,enum dshowDeviceType devtype,enum dshowSourceFilterType sourcetype)1299 dshow_list_device_options(AVFormatContext *avctx, ICreateDevEnum *devenum,
1300 enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
1301 {
1302 struct dshow_ctx *ctx = avctx->priv_data;
1303 IBaseFilter *device_filter = NULL;
1304 char *device_unique_name = NULL;
1305 int r;
1306
1307 if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_unique_name, NULL)) < 0)
1308 return r;
1309 ctx->device_filter[devtype] = device_filter;
1310 ctx->device_unique_name[devtype] = device_unique_name;
1311 if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, NULL)) < 0)
1312 return r;
1313 return 0;
1314 }
1315
1316 static int
dshow_open_device(AVFormatContext * avctx,ICreateDevEnum * devenum,enum dshowDeviceType devtype,enum dshowSourceFilterType sourcetype)1317 dshow_open_device(AVFormatContext *avctx, ICreateDevEnum *devenum,
1318 enum dshowDeviceType devtype, enum dshowSourceFilterType sourcetype)
1319 {
1320 struct dshow_ctx *ctx = avctx->priv_data;
1321 IBaseFilter *device_filter = NULL;
1322 char *device_filter_unique_name = NULL;
1323 IGraphBuilder *graph = ctx->graph;
1324 IPin *device_pin = NULL;
1325 DShowPin *capture_pin = NULL;
1326 DShowFilter *capture_filter = NULL;
1327 ICaptureGraphBuilder2 *graph_builder2 = NULL;
1328 int ret = AVERROR(EIO);
1329 int r;
1330 IStream *ifile_stream = NULL;
1331 IStream *ofile_stream = NULL;
1332 IPersistStream *pers_stream = NULL;
1333 enum dshowDeviceType otherDevType = (devtype == VideoDevice) ? AudioDevice : VideoDevice;
1334
1335 const wchar_t *filter_name[2] = { L"Audio capture filter", L"Video capture filter" };
1336
1337
1338 if ( ((ctx->audio_filter_load_file) && (strlen(ctx->audio_filter_load_file)>0) && (sourcetype == AudioSourceDevice)) ||
1339 ((ctx->video_filter_load_file) && (strlen(ctx->video_filter_load_file)>0) && (sourcetype == VideoSourceDevice)) ) {
1340 HRESULT hr;
1341 char *filename = NULL;
1342
1343 if (sourcetype == AudioSourceDevice)
1344 filename = ctx->audio_filter_load_file;
1345 else
1346 filename = ctx->video_filter_load_file;
1347
1348 hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_READ, &ifile_stream);
1349 if (S_OK != hr) {
1350 av_log(avctx, AV_LOG_ERROR, "Could not open capture filter description file.\n");
1351 goto error;
1352 }
1353
1354 hr = OleLoadFromStream(ifile_stream, &IID_IBaseFilter, (void **) &device_filter);
1355 if (hr != S_OK) {
1356 av_log(avctx, AV_LOG_ERROR, "Could not load capture filter from file.\n");
1357 goto error;
1358 }
1359
1360 if (sourcetype == AudioSourceDevice)
1361 av_log(avctx, AV_LOG_INFO, "Audio-");
1362 else
1363 av_log(avctx, AV_LOG_INFO, "Video-");
1364 av_log(avctx, AV_LOG_INFO, "Capture filter loaded successfully from file \"%s\".\n", filename);
1365 } else {
1366
1367 if ((r = dshow_cycle_devices(avctx, devenum, devtype, sourcetype, &device_filter, &device_filter_unique_name, NULL)) < 0) {
1368 ret = r;
1369 goto error;
1370 }
1371 }
1372 if (ctx->device_filter[otherDevType]) {
1373 // avoid adding add two instances of the same device to the graph, one for video, one for audio
1374 // a few devices don't support this (could also do this check earlier to avoid double crossbars, etc. but they seem OK)
1375 if (strcmp(device_filter_unique_name, ctx->device_unique_name[otherDevType]) == 0) {
1376 av_log(avctx, AV_LOG_DEBUG, "reusing previous graph capture filter... %s\n", device_filter_unique_name);
1377 IBaseFilter_Release(device_filter);
1378 device_filter = ctx->device_filter[otherDevType];
1379 IBaseFilter_AddRef(ctx->device_filter[otherDevType]);
1380 } else {
1381 av_log(avctx, AV_LOG_DEBUG, "not reusing previous graph capture filter %s != %s\n", device_filter_unique_name, ctx->device_unique_name[otherDevType]);
1382 }
1383 }
1384
1385 ctx->device_filter [devtype] = device_filter;
1386 ctx->device_unique_name [devtype] = device_filter_unique_name;
1387
1388 r = IGraphBuilder_AddFilter(graph, device_filter, NULL);
1389 if (r != S_OK) {
1390 av_log(avctx, AV_LOG_ERROR, "Could not add device filter to graph.\n");
1391 goto error;
1392 }
1393
1394 if ((r = dshow_cycle_pins(avctx, devtype, sourcetype, device_filter, &device_pin)) < 0) {
1395 ret = r;
1396 goto error;
1397 }
1398
1399 ctx->device_pin[devtype] = device_pin;
1400
1401 capture_filter = ff_dshow_filter_Create(avctx, callback, devtype);
1402 if (!capture_filter) {
1403 av_log(avctx, AV_LOG_ERROR, "Could not create grabber filter.\n");
1404 goto error;
1405 }
1406 ctx->capture_filter[devtype] = capture_filter;
1407
1408 if ( ((ctx->audio_filter_save_file) && (strlen(ctx->audio_filter_save_file)>0) && (sourcetype == AudioSourceDevice)) ||
1409 ((ctx->video_filter_save_file) && (strlen(ctx->video_filter_save_file)>0) && (sourcetype == VideoSourceDevice)) ) {
1410
1411 HRESULT hr;
1412 char *filename = NULL;
1413
1414 if (sourcetype == AudioSourceDevice)
1415 filename = ctx->audio_filter_save_file;
1416 else
1417 filename = ctx->video_filter_save_file;
1418
1419 hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_CREATE | STGM_READWRITE, &ofile_stream);
1420 if (S_OK != hr) {
1421 av_log(avctx, AV_LOG_ERROR, "Could not create capture filter description file.\n");
1422 goto error;
1423 }
1424
1425 hr = IBaseFilter_QueryInterface(device_filter, &IID_IPersistStream, (void **) &pers_stream);
1426 if (hr != S_OK) {
1427 av_log(avctx, AV_LOG_ERROR, "Query for IPersistStream failed.\n");
1428 goto error;
1429 }
1430
1431 hr = OleSaveToStream(pers_stream, ofile_stream);
1432 if (hr != S_OK) {
1433 av_log(avctx, AV_LOG_ERROR, "Could not save capture filter \n");
1434 goto error;
1435 }
1436
1437 hr = IStream_Commit(ofile_stream, STGC_DEFAULT);
1438 if (S_OK != hr) {
1439 av_log(avctx, AV_LOG_ERROR, "Could not commit capture filter data to file.\n");
1440 goto error;
1441 }
1442
1443 if (sourcetype == AudioSourceDevice)
1444 av_log(avctx, AV_LOG_INFO, "Audio-");
1445 else
1446 av_log(avctx, AV_LOG_INFO, "Video-");
1447 av_log(avctx, AV_LOG_INFO, "Capture filter saved successfully to file \"%s\".\n", filename);
1448 }
1449
1450 r = IGraphBuilder_AddFilter(graph, (IBaseFilter *) capture_filter,
1451 filter_name[devtype]);
1452 if (r != S_OK) {
1453 av_log(avctx, AV_LOG_ERROR, "Could not add capture filter to graph\n");
1454 goto error;
1455 }
1456
1457 ff_dshow_pin_AddRef(capture_filter->pin);
1458 capture_pin = capture_filter->pin;
1459 ctx->capture_pin[devtype] = capture_pin;
1460
1461 r = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC_SERVER,
1462 &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
1463 if (r != S_OK) {
1464 av_log(avctx, AV_LOG_ERROR, "Could not create CaptureGraphBuilder2\n");
1465 goto error;
1466 }
1467 ICaptureGraphBuilder2_SetFiltergraph(graph_builder2, graph);
1468 if (r != S_OK) {
1469 av_log(avctx, AV_LOG_ERROR, "Could not set graph for CaptureGraphBuilder2\n");
1470 goto error;
1471 }
1472
1473 r = ICaptureGraphBuilder2_RenderStream(graph_builder2, NULL, NULL, (IUnknown *) device_pin, NULL /* no intermediate filter */,
1474 (IBaseFilter *) capture_filter); /* connect pins, optionally insert intermediate filters like crossbar if necessary */
1475
1476 if (r != S_OK) {
1477 av_log(avctx, AV_LOG_ERROR, "Could not RenderStream to connect pins\n");
1478 goto error;
1479 }
1480
1481 r = ff_dshow_try_setup_crossbar_options(graph_builder2, device_filter, devtype, avctx);
1482
1483 if (r != S_OK) {
1484 av_log(avctx, AV_LOG_ERROR, "Could not setup CrossBar\n");
1485 goto error;
1486 }
1487
1488 ret = 0;
1489
1490 error:
1491 if (graph_builder2 != NULL)
1492 ICaptureGraphBuilder2_Release(graph_builder2);
1493
1494 if (pers_stream)
1495 IPersistStream_Release(pers_stream);
1496
1497 if (ifile_stream)
1498 IStream_Release(ifile_stream);
1499
1500 if (ofile_stream)
1501 IStream_Release(ofile_stream);
1502
1503 return ret;
1504 }
1505
waveform_codec_id(enum AVSampleFormat sample_fmt)1506 static enum AVCodecID waveform_codec_id(enum AVSampleFormat sample_fmt)
1507 {
1508 switch (sample_fmt) {
1509 case AV_SAMPLE_FMT_U8: return AV_CODEC_ID_PCM_U8;
1510 case AV_SAMPLE_FMT_S16: return AV_CODEC_ID_PCM_S16LE;
1511 case AV_SAMPLE_FMT_S32: return AV_CODEC_ID_PCM_S32LE;
1512 default: return AV_CODEC_ID_NONE; /* Should never happen. */
1513 }
1514 }
1515
sample_fmt_bits_per_sample(int bits)1516 static enum AVSampleFormat sample_fmt_bits_per_sample(int bits)
1517 {
1518 switch (bits) {
1519 case 8: return AV_SAMPLE_FMT_U8;
1520 case 16: return AV_SAMPLE_FMT_S16;
1521 case 32: return AV_SAMPLE_FMT_S32;
1522 default: return AV_SAMPLE_FMT_NONE; /* Should never happen. */
1523 }
1524 }
1525
1526 static int
dshow_add_device(AVFormatContext * avctx,enum dshowDeviceType devtype)1527 dshow_add_device(AVFormatContext *avctx,
1528 enum dshowDeviceType devtype)
1529 {
1530 struct dshow_ctx *ctx = avctx->priv_data;
1531 AM_MEDIA_TYPE type;
1532 AVCodecParameters *par;
1533 AVStream *st;
1534 struct dshow_format_info *fmt_info = NULL;
1535 int ret = AVERROR(EIO);
1536
1537 type.pbFormat = NULL;
1538
1539 st = avformat_new_stream(avctx, NULL);
1540 if (!st) {
1541 ret = AVERROR(ENOMEM);
1542 goto error;
1543 }
1544 st->id = devtype;
1545
1546 ctx->capture_filter[devtype]->stream_index = st->index;
1547
1548 ff_dshow_pin_ConnectionMediaType(ctx->capture_pin[devtype], &type);
1549 fmt_info = dshow_get_format_info(&type);
1550 if (!fmt_info) {
1551 ret = AVERROR(EIO);
1552 goto error;
1553 }
1554
1555 par = st->codecpar;
1556 if (devtype == VideoDevice) {
1557 BITMAPINFOHEADER *bih = NULL;
1558 AVRational time_base;
1559
1560 if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo)) {
1561 VIDEOINFOHEADER *v = (void *) type.pbFormat;
1562 time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
1563 bih = &v->bmiHeader;
1564 } else if (IsEqualGUID(&type.formattype, &FORMAT_VideoInfo2)) {
1565 VIDEOINFOHEADER2 *v = (void *) type.pbFormat;
1566 time_base = (AVRational) { v->AvgTimePerFrame, 10000000 };
1567 bih = &v->bmiHeader;
1568 }
1569 if (!bih) {
1570 av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
1571 goto error;
1572 }
1573
1574 st->avg_frame_rate = av_inv_q(time_base);
1575 st->r_frame_rate = av_inv_q(time_base);
1576
1577 par->codec_type = AVMEDIA_TYPE_VIDEO;
1578 par->width = fmt_info->width;
1579 par->height = fmt_info->height;
1580 par->codec_tag = bih->biCompression;
1581 par->format = fmt_info->pix_fmt;
1582 if (bih->biCompression == MKTAG('H', 'D', 'Y', 'C')) {
1583 av_log(avctx, AV_LOG_DEBUG, "attempt to use full range for HDYC...\n");
1584 par->color_range = AVCOL_RANGE_MPEG; // just in case it needs this...
1585 }
1586 par->color_range = fmt_info->col_range;
1587 par->color_space = fmt_info->col_space;
1588 par->color_primaries = fmt_info->col_prim;
1589 par->color_trc = fmt_info->col_trc;
1590 par->chroma_location = fmt_info->chroma_loc;
1591 par->codec_id = fmt_info->codec_id;
1592 if (par->codec_id == AV_CODEC_ID_RAWVIDEO) {
1593 if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
1594 par->bits_per_coded_sample = bih->biBitCount;
1595 if (par->height < 0) {
1596 par->height *= -1;
1597 } else {
1598 par->extradata = av_malloc(9 + AV_INPUT_BUFFER_PADDING_SIZE);
1599 if (par->extradata) {
1600 par->extradata_size = 9;
1601 memcpy(par->extradata, "BottomUp", 9);
1602 }
1603 }
1604 }
1605 } else {
1606 if (par->codec_id == AV_CODEC_ID_NONE) {
1607 av_log(avctx, AV_LOG_ERROR, "Unknown compression type. "
1608 "Please report type 0x%X.\n", (int) bih->biCompression);
1609 ret = AVERROR_PATCHWELCOME;
1610 goto error;
1611 }
1612 par->bits_per_coded_sample = bih->biBitCount;
1613 }
1614 } else {
1615 if (!IsEqualGUID(&type.formattype, &FORMAT_WaveFormatEx)) {
1616 av_log(avctx, AV_LOG_ERROR, "Could not get media type.\n");
1617 goto error;
1618 }
1619
1620 par->codec_type = AVMEDIA_TYPE_AUDIO;
1621 par->format = sample_fmt_bits_per_sample(fmt_info->sample_size);
1622 par->codec_id = waveform_codec_id(par->format);
1623 par->sample_rate = fmt_info->sample_rate;
1624 par->ch_layout.nb_channels = fmt_info->channels;
1625 }
1626
1627 avpriv_set_pts_info(st, 64, 1, 10000000);
1628
1629 ret = 0;
1630
1631 error:
1632 av_freep(&fmt_info);
1633 if (type.pbFormat)
1634 CoTaskMemFree(type.pbFormat);
1635 return ret;
1636 }
1637
parse_device_name(AVFormatContext * avctx)1638 static int parse_device_name(AVFormatContext *avctx)
1639 {
1640 struct dshow_ctx *ctx = avctx->priv_data;
1641 char **device_name = ctx->device_name;
1642 char *name = av_strdup(avctx->url);
1643 char *tmp = name;
1644 int ret = 1;
1645 char *type;
1646
1647 while ((type = strtok(tmp, "="))) {
1648 char *token = strtok(NULL, ":");
1649 tmp = NULL;
1650
1651 if (!strcmp(type, "video")) {
1652 device_name[0] = token;
1653 } else if (!strcmp(type, "audio")) {
1654 device_name[1] = token;
1655 } else {
1656 device_name[0] = NULL;
1657 device_name[1] = NULL;
1658 break;
1659 }
1660 }
1661
1662 if (!device_name[0] && !device_name[1]) {
1663 ret = 0;
1664 } else {
1665 if (device_name[0])
1666 device_name[0] = av_strdup(device_name[0]);
1667 if (device_name[1])
1668 device_name[1] = av_strdup(device_name[1]);
1669 }
1670
1671 av_free(name);
1672 return ret;
1673 }
1674
dshow_read_header(AVFormatContext * avctx)1675 static int dshow_read_header(AVFormatContext *avctx)
1676 {
1677 struct dshow_ctx *ctx = avctx->priv_data;
1678 IGraphBuilder *graph = NULL;
1679 ICreateDevEnum *devenum = NULL;
1680 IMediaControl *control = NULL;
1681 IMediaEvent *media_event = NULL;
1682 HANDLE media_event_handle;
1683 HANDLE proc;
1684 int ret = AVERROR(EIO);
1685 int r;
1686
1687 CoInitialize(0);
1688
1689 if (!ctx->list_devices && !parse_device_name(avctx)) {
1690 av_log(avctx, AV_LOG_ERROR, "Malformed dshow input string.\n");
1691 goto error;
1692 }
1693
1694 ctx->video_codec_id = avctx->video_codec_id ? avctx->video_codec_id
1695 : AV_CODEC_ID_RAWVIDEO;
1696 if (ctx->pixel_format != AV_PIX_FMT_NONE) {
1697 if (ctx->video_codec_id != AV_CODEC_ID_RAWVIDEO) {
1698 av_log(avctx, AV_LOG_ERROR, "Pixel format may only be set when "
1699 "video codec is not set or set to rawvideo\n");
1700 ret = AVERROR(EINVAL);
1701 goto error;
1702 }
1703 }
1704 if (ctx->framerate) {
1705 r = av_parse_video_rate(&ctx->requested_framerate, ctx->framerate);
1706 if (r < 0) {
1707 av_log(avctx, AV_LOG_ERROR, "Could not parse framerate '%s'.\n", ctx->framerate);
1708 goto error;
1709 }
1710 }
1711
1712 r = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
1713 &IID_IGraphBuilder, (void **) &graph);
1714 if (r != S_OK) {
1715 av_log(avctx, AV_LOG_ERROR, "Could not create capture graph.\n");
1716 goto error;
1717 }
1718 ctx->graph = graph;
1719
1720 r = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER,
1721 &IID_ICreateDevEnum, (void **) &devenum);
1722 if (r != S_OK) {
1723 av_log(avctx, AV_LOG_ERROR, "Could not enumerate system devices.\n");
1724 goto error;
1725 }
1726
1727 if (ctx->list_devices) {
1728 dshow_cycle_devices(avctx, devenum, VideoDevice, VideoSourceDevice, NULL, NULL, NULL);
1729 dshow_cycle_devices(avctx, devenum, AudioDevice, AudioSourceDevice, NULL, NULL, NULL);
1730 ret = AVERROR_EXIT;
1731 goto error;
1732 }
1733 if (ctx->list_options) {
1734 if (ctx->device_name[VideoDevice])
1735 if ((r = dshow_list_device_options(avctx, devenum, VideoDevice, VideoSourceDevice))) {
1736 ret = r;
1737 goto error;
1738 }
1739 if (ctx->device_name[AudioDevice]) {
1740 if (dshow_list_device_options(avctx, devenum, AudioDevice, AudioSourceDevice)) {
1741 /* show audio options from combined video+audio sources as fallback */
1742 if ((r = dshow_list_device_options(avctx, devenum, AudioDevice, VideoSourceDevice))) {
1743 ret = r;
1744 goto error;
1745 }
1746 }
1747 }
1748 // don't exit yet, allow it to list crossbar options in dshow_open_device
1749 }
1750 if (ctx->device_name[VideoDevice]) {
1751 if ((r = dshow_open_device(avctx, devenum, VideoDevice, VideoSourceDevice)) < 0 ||
1752 (r = dshow_add_device(avctx, VideoDevice)) < 0) {
1753 ret = r;
1754 goto error;
1755 }
1756 }
1757 if (ctx->device_name[AudioDevice]) {
1758 if ((r = dshow_open_device(avctx, devenum, AudioDevice, AudioSourceDevice)) < 0 ||
1759 (r = dshow_add_device(avctx, AudioDevice)) < 0) {
1760 av_log(avctx, AV_LOG_INFO, "Searching for audio device within video devices for %s\n", ctx->device_name[AudioDevice]);
1761 /* see if there's a video source with an audio pin with the given audio name */
1762 if ((r = dshow_open_device(avctx, devenum, AudioDevice, VideoSourceDevice)) < 0 ||
1763 (r = dshow_add_device(avctx, AudioDevice)) < 0) {
1764 ret = r;
1765 goto error;
1766 }
1767 }
1768 }
1769 if (ctx->list_options) {
1770 /* allow it to list crossbar options in dshow_open_device */
1771 ret = AVERROR_EXIT;
1772 goto error;
1773 }
1774 ctx->curbufsize[0] = 0;
1775 ctx->curbufsize[1] = 0;
1776 ctx->mutex = CreateMutex(NULL, 0, NULL);
1777 if (!ctx->mutex) {
1778 av_log(avctx, AV_LOG_ERROR, "Could not create Mutex\n");
1779 goto error;
1780 }
1781 ctx->event[1] = CreateEvent(NULL, 1, 0, NULL);
1782 if (!ctx->event[1]) {
1783 av_log(avctx, AV_LOG_ERROR, "Could not create Event\n");
1784 goto error;
1785 }
1786
1787 r = IGraphBuilder_QueryInterface(graph, &IID_IMediaControl, (void **) &control);
1788 if (r != S_OK) {
1789 av_log(avctx, AV_LOG_ERROR, "Could not get media control.\n");
1790 goto error;
1791 }
1792 ctx->control = control;
1793
1794 r = IGraphBuilder_QueryInterface(graph, &IID_IMediaEvent, (void **) &media_event);
1795 if (r != S_OK) {
1796 av_log(avctx, AV_LOG_ERROR, "Could not get media event.\n");
1797 goto error;
1798 }
1799 ctx->media_event = media_event;
1800
1801 r = IMediaEvent_GetEventHandle(media_event, (void *) &media_event_handle);
1802 if (r != S_OK) {
1803 av_log(avctx, AV_LOG_ERROR, "Could not get media event handle.\n");
1804 goto error;
1805 }
1806 proc = GetCurrentProcess();
1807 r = DuplicateHandle(proc, media_event_handle, proc, &ctx->event[0],
1808 0, 0, DUPLICATE_SAME_ACCESS);
1809 if (!r) {
1810 av_log(avctx, AV_LOG_ERROR, "Could not duplicate media event handle.\n");
1811 goto error;
1812 }
1813
1814 r = IMediaControl_Run(control);
1815 if (r == S_FALSE) {
1816 OAFilterState pfs;
1817 r = IMediaControl_GetState(control, 0, &pfs);
1818 }
1819 if (r != S_OK) {
1820 av_log(avctx, AV_LOG_ERROR, "Could not run graph (sometimes caused by a device already in use by other application)\n");
1821 goto error;
1822 }
1823
1824 ret = 0;
1825
1826 error:
1827
1828 if (devenum)
1829 ICreateDevEnum_Release(devenum);
1830
1831 if (ret < 0)
1832 dshow_read_close(avctx);
1833
1834 return ret;
1835 }
1836
1837 /**
1838 * Checks media events from DirectShow and returns -1 on error or EOF. Also
1839 * purges all events that might be in the event queue to stop the trigger
1840 * of event notification.
1841 */
dshow_check_event_queue(IMediaEvent * media_event)1842 static int dshow_check_event_queue(IMediaEvent *media_event)
1843 {
1844 LONG_PTR p1, p2;
1845 long code;
1846 int ret = 0;
1847
1848 while (IMediaEvent_GetEvent(media_event, &code, &p1, &p2, 0) != E_ABORT) {
1849 if (code == EC_COMPLETE || code == EC_DEVICE_LOST || code == EC_ERRORABORT)
1850 ret = -1;
1851 IMediaEvent_FreeEventParams(media_event, code, p1, p2);
1852 }
1853
1854 return ret;
1855 }
1856
dshow_read_packet(AVFormatContext * s,AVPacket * pkt)1857 static int dshow_read_packet(AVFormatContext *s, AVPacket *pkt)
1858 {
1859 struct dshow_ctx *ctx = s->priv_data;
1860 PacketListEntry *pktl = NULL;
1861
1862 while (!ctx->eof && !pktl) {
1863 WaitForSingleObject(ctx->mutex, INFINITE);
1864 pktl = ctx->pktl;
1865 if (pktl) {
1866 *pkt = pktl->pkt;
1867 ctx->pktl = ctx->pktl->next;
1868 av_free(pktl);
1869 ctx->curbufsize[pkt->stream_index] -= pkt->size;
1870 }
1871 ResetEvent(ctx->event[1]);
1872 ReleaseMutex(ctx->mutex);
1873 if (!pktl) {
1874 if (dshow_check_event_queue(ctx->media_event) < 0) {
1875 ctx->eof = 1;
1876 } else if (s->flags & AVFMT_FLAG_NONBLOCK) {
1877 return AVERROR(EAGAIN);
1878 } else {
1879 WaitForMultipleObjects(2, ctx->event, 0, INFINITE);
1880 }
1881 }
1882 }
1883
1884 return ctx->eof ? AVERROR(EIO) : pkt->size;
1885 }
1886
1887 #define OFFSET(x) offsetof(struct dshow_ctx, x)
1888 #define DEC AV_OPT_FLAG_DECODING_PARAM
1889 static const AVOption options[] = {
1890 { "video_size", "set video size given a string such as 640x480 or hd720.", OFFSET(requested_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC },
1891 { "pixel_format", "set video pixel format", OFFSET(pixel_format), AV_OPT_TYPE_PIXEL_FMT, {.i64 = AV_PIX_FMT_NONE}, -1, INT_MAX, DEC },
1892 { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1893 { "sample_rate", "set audio sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1894 { "sample_size", "set audio sample size", OFFSET(sample_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 16, DEC },
1895 { "channels", "set number of audio channels, such as 1 or 2", OFFSET(channels), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1896 { "audio_buffer_size", "set audio device buffer latency size in milliseconds (default is the device's default)", OFFSET(audio_buffer_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1897 { "list_devices", "list available devices", OFFSET(list_devices), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, DEC },
1898 { "list_options", "list available options for specified device", OFFSET(list_options), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, DEC },
1899 { "video_device_number", "set video device number for devices with same name (starts at 0)", OFFSET(video_device_number), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC },
1900 { "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 },
1901 { "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 },
1902 { "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 },
1903 { "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 },
1904 { "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 },
1905 { "show_video_device_dialog", "display property dialog for video capture device", OFFSET(show_video_device_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1906 { "show_audio_device_dialog", "display property dialog for audio capture device", OFFSET(show_audio_device_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1907 { "show_video_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on video device", OFFSET(show_video_crossbar_connection_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1908 { "show_audio_crossbar_connection_dialog", "display property dialog for crossbar connecting pins filter on audio device", OFFSET(show_audio_crossbar_connection_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1909 { "show_analog_tv_tuner_dialog", "display property dialog for analog tuner filter", OFFSET(show_analog_tv_tuner_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1910 { "show_analog_tv_tuner_audio_dialog", "display property dialog for analog tuner audio filter", OFFSET(show_analog_tv_tuner_audio_dialog), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, DEC },
1911 { "audio_device_load", "load audio capture filter device (and properties) from file", OFFSET(audio_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1912 { "audio_device_save", "save audio capture filter device (and properties) to file", OFFSET(audio_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1913 { "video_device_load", "load video capture filter device (and properties) from file", OFFSET(video_filter_load_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1914 { "video_device_save", "save video capture filter device (and properties) to file", OFFSET(video_filter_save_file), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, DEC },
1915 { "use_video_device_timestamps", "use device instead of wallclock timestamps for video frames", OFFSET(use_video_device_timestamps), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, DEC },
1916 { NULL },
1917 };
1918
1919 static const AVClass dshow_class = {
1920 .class_name = "dshow indev",
1921 .item_name = av_default_item_name,
1922 .option = options,
1923 .version = LIBAVUTIL_VERSION_INT,
1924 .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT,
1925 };
1926
1927 const AVInputFormat ff_dshow_demuxer = {
1928 .name = "dshow",
1929 .long_name = NULL_IF_CONFIG_SMALL("DirectShow capture"),
1930 .priv_data_size = sizeof(struct dshow_ctx),
1931 .read_header = dshow_read_header,
1932 .read_packet = dshow_read_packet,
1933 .read_close = dshow_read_close,
1934 .get_device_list= dshow_get_device_list,
1935 .flags = AVFMT_NOFILE | AVFMT_NOBINSEARCH | AVFMT_NOGENSEARCH | AVFMT_NO_BYTE_SEEK,
1936 .priv_class = &dshow_class,
1937 };
1938