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
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
60 {
61 switch(biCompression) {
62 case BI_BITFIELDS:
63 case BI_RGB:
64 switch(biBitCount) { /* 1-8 are untested */
65 case 1:
67 case 4:
69 case 8:
71 case 16:
73 case 24:
75 case 32:
77 }
78 }
80 }
81
83 {
84 switch (fmt_info->NominalRange)
85 {
86 case DXVA2_NominalRange_Unknown:
88 case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
90 case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
92 case DXVA2_NominalRange_48_208:
93 // not an ffmpeg color range
95
96 // values from MediaFoundation SDK (mfobjects.h)
97 case 4: // MFNominalRange_64_127
98 // not an ffmpeg color range
100
101 default:
103 }
104 }
105
107 {
108 switch (fmt_info->VideoTransferMatrix)
109 {
110 case DXVA2_VideoTransferMatrix_BT709:
112 case DXVA2_VideoTransferMatrix_BT601:
114 case DXVA2_VideoTransferMatrix_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
122 else
124
125 default:
127 }
128 }
129
131 {
132 switch (fmt_info->VideoPrimaries)
133 {
134 case DXVA2_VideoPrimaries_Unknown:
136 case DXVA2_VideoPrimaries_reserved:
138 case DXVA2_VideoPrimaries_BT709:
140 case DXVA2_VideoPrimaries_BT470_2_SysM:
142 case DXVA2_VideoPrimaries_BT470_2_SysBG:
143 case DXVA2_VideoPrimaries_EBU3213: // this is PAL
145 case DXVA2_VideoPrimaries_SMPTE170M:
146 case DXVA2_VideoPrimaries_SMPTE_C:
148 case DXVA2_VideoPrimaries_SMPTE240M:
150
151 // values from MediaFoundation SDK (mfobjects.h)
152 case 9: // MFVideoPrimaries_BT2020
154 case 10: // MFVideoPrimaries_XYZ
156 case 11: // MFVideoPrimaries_DCI_P3
158 case 12: // MFVideoPrimaries_ACES (Academy Color Encoding System)
159 // not an FFmpeg color primary
161
162 default:
164 }
165 }
166
168 {
169 switch (fmt_info->VideoTransferFunction)
170 {
171 case DXVA2_VideoTransFunc_Unknown:
173 case DXVA2_VideoTransFunc_10:
175 case DXVA2_VideoTransFunc_18:
176 // not an FFmpeg transfer characteristic
178 case DXVA2_VideoTransFunc_20:
179 // not an FFmpeg transfer characteristic
181 case DXVA2_VideoTransFunc_22:
183 case DXVA2_VideoTransFunc_709:
185 case DXVA2_VideoTransFunc_240M:
187 case DXVA2_VideoTransFunc_sRGB:
189 case DXVA2_VideoTransFunc_28:
191
192 // values from MediaFoundation SDK (mfobjects.h)
193 case 9: // MFVideoTransFunc_Log_100
195 case 10: // MFVideoTransFunc_Log_316
197 case 11: // MFVideoTransFunc_709_sym
198 // not an FFmpeg transfer characteristic
200 case 12: // MFVideoTransFunc_2020_const
201 case 13: // MFVideoTransFunc_2020
202 if (fmt_info->VideoTransferMatrix == 5) // MFVideoTransferMatrix_BT2020_12
204 else
206 case 14: // MFVideoTransFunc_26
207 // not an FFmpeg transfer characteristic
209 case 15: // MFVideoTransFunc_2084
211 case 16: // MFVideoTransFunc_HLG
213 case 17: // MFVideoTransFunc_10_rel
214 // not an FFmpeg transfer characteristic? Undocumented also by MS
216
217 default:
219 }
220 }
221
223 {
224 if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_Cosited) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
226 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG1) // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
228 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG2) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
230 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_DV_PAL) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
232 else
233 // unknown
235 }
236
237 static int
239 {
242
244 IMediaControl_Stop(
ctx->control);
245 IMediaControl_Release(
ctx->control);
246 }
247
248 if (
ctx->media_event)
249 IMediaEvent_Release(
ctx->media_event);
250
252 IEnumFilters *fenum;
254 r = IGraphBuilder_EnumFilters(
ctx->graph, &fenum);
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
277
286
291
293 CloseHandle(
ctx->mutex);
295 CloseHandle(
ctx->event[0]);
297 CloseHandle(
ctx->event[1]);
298
305 }
306
307 CoUninitialize();
308
309 return 0;
310 }
311
313 {
315 int l = WideCharToMultiByte(CP_UTF8, 0,
w, -1, 0, 0, 0, 0);
318 WideCharToMultiByte(CP_UTF8, 0,
w, -1,
s, l, 0, 0);
320 }
321
323 {
325 static const uint8_t dropscore[] = {62, 75, 87, 100};
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) {
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
342 {
346
347 // dump_videohdr(s, vdhdr);
348
350
353
355 if(!pktl_next)
357
361 }
362
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;
370
371 SetEvent(
ctx->event[1]);
372 ReleaseMutex(
ctx->mutex);
373
374 return;
376 ReleaseMutex(
ctx->mutex);
377 return;
378 }
379
380 static void
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
390 return;
391
392 while (IEnumPins_Next(pins, 1, &pin,
NULL) == S_OK) {
393 IKsPropertySet *p =
NULL;
394 PIN_INFO
info = { 0 };
396 DWORD r2;
397 IEnumMediaTypes *types =
NULL;
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,
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 }
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;
443 if (*media_types) {
444 if (has_audio)
446 if (has_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
466 {
469 IEnumMoniker *classenum =
NULL;
473 :
ctx->audio_device_number;
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);
485 devtypename);
487 }
488
490 IPropertyBag *bag =
NULL;
492 char *unique_name =
NULL;
493 VARIANT var;
494 IBindCtx *bind_ctx =
NULL;
495 LPOLESTR olestr =
NULL;
496 LPMALLOC co_malloc =
NULL;
499 int nb_media_types = 0;
501
502 r = CoGetMalloc(1, &co_malloc);
505 r = CreateBindCtx(0, &bind_ctx);
508 /* GetDisplayname works for both video and audio, DevicePath doesn't */
509 r = IMoniker_GetDisplayName(m, bind_ctx,
NULL, &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);
522
523 var.vt = VT_BSTR;
524 r = IPropertyBag_Read(bag,
L "FriendlyName", &var,
NULL);
528
529 if (pfilter) {
532
533 if (!skip--) {
534 r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (
void *) &
device_filter);
538 }
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) {
549 }
550 if (device_list) {
552 if (!device)
554
559
560 // make space in device_list for this new device
562 (*device_list)->nb_devices + 1,
563 sizeof(*(*device_list)->devices)) < 0)
565
566 // attach media_types to device
569 nb_media_types = 0;
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 {
579 if (nb_media_types > 0) {
582 for (
int i = 1;
i < nb_media_types; ++
i) {
585 }
587 } else {
589 }
592 }
593 }
594
597 if (device) {
600 // NB: no need to av_freep(&device->media_types), its only moved to device once nothing can fail anymore
602 }
603 if (olestr && co_malloc)
604 IMalloc_Free(co_malloc, olestr);
605 if (bind_ctx)
606 IBindCtx_Release(bind_ctx);
609 if (bag)
610 IPropertyBag_Release(bag);
611 IMoniker_Release(m);
612 }
613
614 IEnumMoniker_Release(classenum);
615
616 if (pfilter) {
618 av_log(avctx,
AV_LOG_ERROR,
"Could not find %s device with name [%s] among source devices of type %s.\n",
621 }
623 }
624
625 return 0;
626 }
627
629 {
630 ICreateDevEnum *devenum =
NULL;
633
634 if (!device_list)
636
637 CoInitialize(0);
638
639 r = CoCreateInstance(&CLSID_SystemDeviceEnum,
NULL, CLSCTX_INPROC_SERVER,
640 &IID_ICreateDevEnum, (void**)&devenum);
644 }
645
650
652 if (devenum)
653 ICreateDevEnum_Release(devenum);
654
655 CoUninitialize();
656
658 }
659
661 {
663
665 (
ctx->requested_width &&
ctx->requested_height) ||
669 }
670
671
674 // video
685 // audio
689 };
690
691 // user must av_free the returned pointer
693 {
695 BITMAPINFOHEADER *bih;
696 DXVA2_ExtendedFormat *extended_format_info =
NULL;
697 WAVEFORMATEX *fx;
700
703
704 if (IsEqualGUID(&
type->formattype, &FORMAT_VideoInfo)) {
705 VIDEOINFOHEADER *v = (
void *)
type->pbFormat;
707 bih = &v->bmiHeader;
709 }
else if (IsEqualGUID(&
type->formattype, &FORMAT_VideoInfo2)) {
710 VIDEOINFOHEADER2 *v = (
void *)
type->pbFormat;
713 bih = &v->bmiHeader;
715 extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
716 }
else if (IsEqualGUID(&
type->formattype, &FORMAT_WaveFormatEx)) {
717 fx = (
void *)
type->pbFormat;
719 } else {
721 }
722
724 if (!fmt_info)
726 // initialize fields where unset is not zero
731 // now get info about format
734 fmt_info->
width = bih->biWidth;
735 fmt_info->
height = bih->biHeight;
741 }
742 else
744
745 if (extended_format_info) {
751 }
752 } else {
756 }
757
758 return fmt_info;
759 }
760
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);
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
795 IPin *pin, int *pformat_set)
796 {
800 AM_MEDIA_TYPE *previous_match_type =
NULL;
801 int format_set = 0;
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
814 /
ctx->requested_framerate.num : 0;
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
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 */
839 if (use_default && pformat_set)
840 {
841 // get default
844 // this pin does not expose any formats of the expected type
845 goto end;
846
848 // interrogate default format, so we know what to search for below
850 if (fmt_info) {
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 {
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
866 CoTaskMemFree(
type->pbFormat);
869 if (!fmt_info)
870 // default format somehow invalid, can't continue with this pin
871 goto end;
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++) {
887 r = IAMStreamConfig_GetStreamCaps(
config,
i, &
type, (
void *) caps);
889 goto next;
890 #if DSHOWDEBUG
892 #endif
893
895 if (!fmt_info)
896 goto next;
897
899 VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
900 BITMAPINFOHEADER *bih;
901 int64_t *fr;
902 #if DSHOWDEBUG
904 #endif
905
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) {
926 av_log(avctx,
AV_LOG_INFO,
" unknown compression type 0x%X", (
int) bih->biCompression);
927 } else {
929 }
930 } else {
932 }
934 vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
935 1e7 / vcaps->MaxFrameInterval,
936 vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
937 1e7 / vcaps->MinFrameInterval);
938
948 range ? range : "unknown",
950 prim ? prim : "unknown",
951 trc ? trc : "unknown");
955 }
958
960 goto next;
961 }
963 if (requested_video_codec_id != fmt_info->
codec_id)
964 goto next;
965 }
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
990 #endif
991 if (IsEqualGUID(&
type->formattype, &FORMAT_WaveFormatEx)) {
992 fx = (
void *)
type->pbFormat;
993 } else {
994 goto next;
995 }
996 if (!pformat_set) {
998 avctx,
1000 " ch=%2u, bits=%2u, rate=%6lu\n",
1001 fx->nChannels, fx->wBitsPerSample, fx->nSamplesPerSec
1002 );
1003 continue;
1004 }
1005 if (
1006 (
ctx->sample_rate &&
ctx->sample_rate != fx->nSamplesPerSec) ||
1007 (
ctx->sample_size &&
ctx->sample_size != fx->wBitsPerSample) ||
1008 (
ctx->channels &&
ctx->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;
1028 }
1029 next:
1032 CoTaskMemFree(
type->pbFormat);
1033 CoTaskMemFree(
type);
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
1054 if (IAMStreamConfig_SetFormat(
config,
type) == S_OK)
1055 format_set = 1;
1057 CoTaskMemFree(
type->pbFormat);
1058 CoTaskMemFree(
type);
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);
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
1079 {
1081 IAMBufferNegotiation *buffer_negotiation =
NULL;
1082 ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
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
1103
1104 end:
1105 if (buffer_negotiation)
1106 IAMBufferNegotiation_Release(buffer_negotiation);
1109 CoTaskMemFree(
type->pbFormat);
1110 CoTaskMemFree(
type);
1111 }
1113 IAMStreamConfig_Release(
config);
1114
1116 }
1117
1118 /**
1119 * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
1120 */
1121 void
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) {
1132 goto end;
1133 }
1134 hr = IBaseFilter_QueryFilterInfo(
device_filter, &filter_info);
1135 if (hr != S_OK) {
1137 }
1138 hr = IBaseFilter_QueryInterface(
device_filter, &IID_IUnknown, (
void **)&device_filter_iunknown);
1139 if (hr != S_OK) {
1141 }
1142 hr = ISpecifyPropertyPages_GetPages(property_pages, &ca_guid);
1143 if (hr != S_OK) {
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) {
1150 }
1151 goto end;
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
1174 {
1176 IEnumPins *pins = 0;
1178 IPin *pin;
1180
1181 const char *devtypename = (devtype ==
VideoDevice) ?
"video" :
"audio only";
1182 const char *sourcetypename = (sourcetype ==
VideoSourceDevice) ?
"video" :
"audio";
1183
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)
1190
1195 }
1196
1197 if (!ppin) {
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};
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,
1221 goto next;
1222 if (!IsEqualGUID(&
category, &PIN_CATEGORY_CAPTURE))
1223 goto next;
1225
1226 r = IPin_QueryId(pin, &pin_id);
1230 }
1232
1233 if (!ppin) {
1234 av_log(avctx,
AV_LOG_INFO,
" Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
1236 goto next;
1237 }
1238
1239 if (desired_pin_name) {
1240 if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
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
1250 if (!format_set) {
1251 goto next;
1252 }
1253
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) {
1263 }
1264 next:
1265 if (p)
1266 IKsPropertySet_Release(p);
1268 IPin_Release(pin);
1271 if (pin_id)
1272 CoTaskMemFree(pin_id);
1273 }
1274
1275 IEnumPins_Release(pins);
1276
1277 if (ppin) {
1281 }
1284 "Could not find output pin from %s capture device.\n", devtypename);
1286 }
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
1301 {
1306
1313 return 0;
1314 }
1315
1316 static int
1319 {
1322 char *device_filter_unique_name =
NULL;
1327 ICaptureGraphBuilder2 *graph_builder2 =
NULL;
1330 IStream *ifile_stream =
NULL;
1331 IStream *ofile_stream =
NULL;
1332 IPersistStream *pers_stream =
NULL;
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
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) {
1352 }
1353
1354 hr = OleLoadFromStream(ifile_stream, &IID_IBaseFilter, (
void **) &
device_filter);
1355 if (hr != S_OK) {
1358 }
1359
1362 else
1364 av_log(avctx,
AV_LOG_INFO,
"Capture filter loaded successfully from file \"%s\".\n", filename);
1365 } else {
1366
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);
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
1386 ctx->device_unique_name [devtype] = device_filter_unique_name;
1387
1392 }
1393
1397 }
1398
1400
1405 }
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
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) {
1423 }
1424
1425 hr = IBaseFilter_QueryInterface(
device_filter, &IID_IPersistStream, (
void **) &pers_stream);
1426 if (hr != S_OK) {
1429 }
1430
1431 hr = OleSaveToStream(pers_stream, ofile_stream);
1432 if (hr != S_OK) {
1435 }
1436
1437 hr = IStream_Commit(ofile_stream, STGC_DEFAULT);
1438 if (S_OK != hr) {
1441 }
1442
1445 else
1447 av_log(avctx,
AV_LOG_INFO,
"Capture filter saved successfully to file \"%s\".\n", filename);
1448 }
1449
1451 filter_name[devtype]);
1455 }
1456
1460
1461 r = CoCreateInstance(&CLSID_CaptureGraphBuilder2,
NULL, CLSCTX_INPROC_SERVER,
1462 &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
1466 }
1467 ICaptureGraphBuilder2_SetFiltergraph(graph_builder2,
graph);
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
1479 }
1480
1482
1486 }
1487
1489
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
1504 }
1505
1507 {
1508 switch (sample_fmt) {
1513 }
1514 }
1515
1517 {
1523 }
1524 }
1525
1526 static int
1529 {
1536
1538
1540 if (!st) {
1543 }
1545
1547
1550 if (!fmt_info) {
1553 }
1554
1557 BITMAPINFOHEADER *bih =
NULL;
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) {
1572 }
1573
1576
1582 if (bih->biCompression ==
MKTAG(
'H',
'D',
'Y',
'C')) {
1585 }
1593 if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
1597 } else {
1602 }
1603 }
1604 }
1605 } else {
1608 "Please report type 0x%X.\n", (int) bih->biCompression);
1611 }
1613 }
1614 } else {
1615 if (!IsEqualGUID(&
type.formattype, &FORMAT_WaveFormatEx)) {
1618 }
1619
1625 }
1626
1628
1630
1634 CoTaskMemFree(
type.pbFormat);
1636 }
1637
1639 {
1646
1647 while ((
type = strtok(
tmp,
"="))) {
1648 char *token = strtok(
NULL,
":");
1650
1651 if (!strcmp(
type,
"video")) {
1653 }
else if (!strcmp(
type,
"audio")) {
1655 } else {
1658 break;
1659 }
1660 }
1661
1664 } else {
1669 }
1670
1673 }
1674
1676 {
1679 ICreateDevEnum *devenum =
NULL;
1682 HANDLE media_event_handle;
1683 HANDLE proc;
1686
1687 CoInitialize(0);
1688
1692 }
1693
1699 "video codec is not set or set to rawvideo\n");
1702 }
1703 }
1704 if (
ctx->framerate) {
1709 }
1710 }
1711
1712 r = CoCreateInstance(&CLSID_FilterGraph,
NULL, CLSCTX_INPROC_SERVER,
1713 &IID_IGraphBuilder, (
void **) &
graph);
1717 }
1719
1720 r = CoCreateInstance(&CLSID_SystemDeviceEnum,
NULL, CLSCTX_INPROC_SERVER,
1721 &IID_ICreateDevEnum, (void **) &devenum);
1725 }
1726
1727 if (
ctx->list_devices) {
1732 }
1733 if (
ctx->list_options) {
1738 }
1741 /* show audio options from combined video+audio sources as fallback */
1745 }
1746 }
1747 }
1748 // don't exit yet, allow it to list crossbar options in dshow_open_device
1749 }
1755 }
1756 }
1761 /* see if there's a video source with an audio pin with the given audio name */
1766 }
1767 }
1768 }
1769 if (
ctx->list_options) {
1770 /* allow it to list crossbar options in dshow_open_device */
1773 }
1774 ctx->curbufsize[0] = 0;
1775 ctx->curbufsize[1] = 0;
1780 }
1782 if (!
ctx->event[1]) {
1785 }
1786
1787 r = IGraphBuilder_QueryInterface(
graph, &IID_IMediaControl, (
void **) &
control);
1791 }
1793
1794 r = IGraphBuilder_QueryInterface(
graph, &IID_IMediaEvent, (
void **) &
media_event);
1798 }
1800
1801 r = IMediaEvent_GetEventHandle(
media_event, (
void *) &media_event_handle);
1805 }
1806 proc = GetCurrentProcess();
1807 r = DuplicateHandle(proc, media_event_handle, proc, &
ctx->event[0],
1808 0, 0, DUPLICATE_SAME_ACCESS);
1812 }
1813
1816 OAFilterState pfs;
1817 r = IMediaControl_GetState(
control, 0, &pfs);
1818 }
1820 av_log(avctx,
AV_LOG_ERROR,
"Could not run graph (sometimes caused by a device already in use by other application)\n");
1822 }
1823
1825
1827
1828 if (devenum)
1829 ICreateDevEnum_Release(devenum);
1830
1833
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 */
1843 {
1844 LONG_PTR p1, p2;
1847
1848 while (IMediaEvent_GetEvent(
media_event, &
code, &p1, &p2, 0) != E_ABORT) {
1852 }
1853
1855 }
1856
1858 {
1861
1867 ctx->pktl =
ctx->pktl->next;
1870 }
1871 ResetEvent(
ctx->event[1]);
1872 ReleaseMutex(
ctx->mutex);
1878 } else {
1879 WaitForMultipleObjects(2,
ctx->event, 0, INFINITE);
1880 }
1881 }
1882 }
1883
1885 }
1886
1887 #define OFFSET(x) offsetof(struct dshow_ctx, x)
1888 #define DEC AV_OPT_FLAG_DECODING_PARAM
1917 };
1918
1925 };
1926
1930 .priv_data_size =
sizeof(
struct dshow_ctx),
1937 };