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
32 #include "objidl.h"
33 #include "shlwapi.h"
34 // NB: technically, we should include dxva.h and use
35 // DXVA_ExtendedFormat, but that type is not defined in
36 // the MinGW headers. The DXVA2_ExtendedFormat and the
37 // contents of its fields is identical to
38 // DXVA_ExtendedFormat (see https://docs.microsoft.com/en-us/windows/win32/medfound/extended-color-information#color-space-in-media-types)
39 // and is provided by MinGW as well, so we use that
40 // instead. NB also that per the Microsoft docs, the
41 // lowest 8 bits of the structure, i.e. the SampleFormat
42 // field, contain AMCONTROL_xxx flags instead of sample
43 // format information, and should thus not be used.
44 // NB further that various values in the structure's
45 // fields (e.g. BT.2020 color space) are not provided
46 // for either of the DXVA structs, but are provided in
47 // the flags of the corresponding fields of Media Foundation.
48 // These may be provided by DirectShow devices (e.g. LAVFilters
49 // does so). So we use those values here too (the equivalence is
50 // indicated by Microsoft example code: https://docs.microsoft.com/en-us/windows/win32/api/dxva2api/ns-dxva2api-dxva2_videodesc)
51 #include "d3d9types.h"
52 #include "dxva2api.h"
53
54 #ifndef AMCONTROL_COLORINFO_PRESENT
55 // not defined in some versions of MinGW's dvdmedia.h
56 # define AMCONTROL_COLORINFO_PRESENT 0x00000080 // if set, indicates DXVA color info is present in the upper (24) bits of the dwControlFlags
57 #endif
58
59
61 {
62 switch(biCompression) {
63 case BI_BITFIELDS:
64 case BI_RGB:
65 switch(biBitCount) { /* 1-8 are untested */
66 case 1:
68 case 4:
70 case 8:
72 case 16:
74 case 24:
76 case 32:
78 }
79 }
81 }
82
84 {
85 switch (fmt_info->NominalRange)
86 {
87 case DXVA2_NominalRange_Unknown:
89 case DXVA2_NominalRange_Normal: // equal to DXVA2_NominalRange_0_255
91 case DXVA2_NominalRange_Wide: // equal to DXVA2_NominalRange_16_235
93 case DXVA2_NominalRange_48_208:
94 // not an ffmpeg color range
96
97 // values from MediaFoundation SDK (mfobjects.h)
98 case 4: // MFNominalRange_64_127
99 // not an ffmpeg color range
101
102 default:
104 }
105 }
106
108 {
109 switch (fmt_info->VideoTransferMatrix)
110 {
111 case DXVA2_VideoTransferMatrix_BT709:
113 case DXVA2_VideoTransferMatrix_BT601:
115 case DXVA2_VideoTransferMatrix_SMPTE240M:
117
118 // values from MediaFoundation SDK (mfobjects.h)
119 case 4: // MFVideoTransferMatrix_BT2020_10
120 case 5: // MFVideoTransferMatrix_BT2020_12
121 if (fmt_info->VideoTransferFunction == 12) // MFVideoTransFunc_2020_const
123 else
125
126 default:
128 }
129 }
130
132 {
133 switch (fmt_info->VideoPrimaries)
134 {
135 case DXVA2_VideoPrimaries_Unknown:
137 case DXVA2_VideoPrimaries_reserved:
139 case DXVA2_VideoPrimaries_BT709:
141 case DXVA2_VideoPrimaries_BT470_2_SysM:
143 case DXVA2_VideoPrimaries_BT470_2_SysBG:
144 case DXVA2_VideoPrimaries_EBU3213: // this is PAL
146 case DXVA2_VideoPrimaries_SMPTE170M:
147 case DXVA2_VideoPrimaries_SMPTE_C:
149 case DXVA2_VideoPrimaries_SMPTE240M:
151
152 // values from MediaFoundation SDK (mfobjects.h)
153 case 9: // MFVideoPrimaries_BT2020
155 case 10: // MFVideoPrimaries_XYZ
157 case 11: // MFVideoPrimaries_DCI_P3
159 case 12: // MFVideoPrimaries_ACES (Academy Color Encoding System)
160 // not an FFmpeg color primary
162
163 default:
165 }
166 }
167
169 {
170 switch (fmt_info->VideoTransferFunction)
171 {
172 case DXVA2_VideoTransFunc_Unknown:
174 case DXVA2_VideoTransFunc_10:
176 case DXVA2_VideoTransFunc_18:
177 // not an FFmpeg transfer characteristic
179 case DXVA2_VideoTransFunc_20:
180 // not an FFmpeg transfer characteristic
182 case DXVA2_VideoTransFunc_22:
184 case DXVA2_VideoTransFunc_709:
186 case DXVA2_VideoTransFunc_240M:
188 case DXVA2_VideoTransFunc_sRGB:
190 case DXVA2_VideoTransFunc_28:
192
193 // values from MediaFoundation SDK (mfobjects.h)
194 case 9: // MFVideoTransFunc_Log_100
196 case 10: // MFVideoTransFunc_Log_316
198 case 11: // MFVideoTransFunc_709_sym
199 // not an FFmpeg transfer characteristic
201 case 12: // MFVideoTransFunc_2020_const
202 case 13: // MFVideoTransFunc_2020
203 if (fmt_info->VideoTransferMatrix == 5) // MFVideoTransferMatrix_BT2020_12
205 else
207 case 14: // MFVideoTransFunc_26
208 // not an FFmpeg transfer characteristic
210 case 15: // MFVideoTransFunc_2084
212 case 16: // MFVideoTransFunc_HLG
214 case 17: // MFVideoTransFunc_10_rel
215 // not an FFmpeg transfer characteristic? Undocumented also by MS
217
218 default:
220 }
221 }
222
224 {
225 if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_Cosited) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
227 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG1) // that is: DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes
229 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_MPEG2) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_AlignedChromaPlanes)
231 else if (fmt_info->VideoChromaSubsampling == DXVA2_VideoChromaSubsampling_DV_PAL) // that is: (DXVA2_VideoChromaSubsampling_Horizontally_Cosited | DXVA2_VideoChromaSubsampling_Vertically_Cosited)
233 else
234 // unknown
236 }
237
238 static int
240 {
243
245 IMediaControl_Stop(
ctx->control);
246 IMediaControl_Release(
ctx->control);
247 }
248
249 if (
ctx->media_event)
250 IMediaEvent_Release(
ctx->media_event);
251
253 IEnumFilters *fenum;
255 r = IGraphBuilder_EnumFilters(
ctx->graph, &fenum);
258 IEnumFilters_Reset(fenum);
259 while (IEnumFilters_Next(fenum, 1, &
f,
NULL) == S_OK) {
260 if (IGraphBuilder_RemoveFilter(
ctx->graph,
f) == S_OK)
261 IEnumFilters_Reset(fenum); /* When a filter is removed,
262 * the list must be reset. */
263 IBaseFilter_Release(
f);
264 }
265 IEnumFilters_Release(fenum);
266 }
267 IGraphBuilder_Release(
ctx->graph);
268 }
269
278
287
292
294 CloseHandle(
ctx->mutex);
296 CloseHandle(
ctx->event[0]);
298 CloseHandle(
ctx->event[1]);
299
306 }
307
308 CoUninitialize();
309
310 return 0;
311 }
312
314 {
316 int l = WideCharToMultiByte(CP_UTF8, 0,
w, -1, 0, 0, 0, 0);
319 WideCharToMultiByte(CP_UTF8, 0,
w, -1,
s, l, 0, 0);
321 }
322
324 {
326 static const uint8_t dropscore[] = {62, 75, 87, 100};
328 unsigned int buffer_fullness = (
ctx->curbufsize[
index]*100)/
s->max_picture_buffer;
329 const char *devtypename = (devtype ==
VideoDevice) ?
"video" :
"audio";
330
331 if(dropscore[++
ctx->video_frame_num%ndropscores] <= buffer_fullness) {
333 "real-time buffer [%s] [%s input] too full or near too full (%d%% of size: %d [rtbufsize parameter])! frame dropped!\n",
334 ctx->device_name[devtype], devtypename, buffer_fullness,
s->max_picture_buffer);
335 return 1;
336 }
337
338 return 0;
339 }
340
341 static void
343 {
347
348 // dump_videohdr(s, vdhdr);
349
351
354
356 if(!pktl_next)
358
362 }
363
365 pktl_next->
pkt.
pts = time;
366 memcpy(pktl_next->
pkt.
data, buf, buf_size);
367
368 for(ppktl = &
ctx->pktl ; *ppktl ; ppktl = &(*ppktl)->
next);
369 *ppktl = pktl_next;
371
372 SetEvent(
ctx->event[1]);
373 ReleaseMutex(
ctx->mutex);
374
375 return;
377 ReleaseMutex(
ctx->mutex);
378 return;
379 }
380
381 static void
384 enum AVMediaType **media_types,
int *nb_media_types)
385 {
386 IEnumPins *pins = 0;
387 IPin *pin;
388 int has_audio = 0, has_video = 0;
389
391 return;
392
393 while (IEnumPins_Next(pins, 1, &pin,
NULL) == S_OK) {
394 IKsPropertySet *
p =
NULL;
395 PIN_INFO
info = { 0 };
397 DWORD r2;
398 IEnumMediaTypes *types =
NULL;
400
401 if (IPin_QueryPinInfo(pin, &
info) != S_OK)
402 goto next;
403 IBaseFilter_Release(
info.pFilter);
404
405 if (
info.dir != PINDIR_OUTPUT)
406 goto next;
407 if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (
void **) &
p) != S_OK)
408 goto next;
409 if (IKsPropertySet_Get(
p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
411 goto next;
412 if (!IsEqualGUID(&
category, &PIN_CATEGORY_CAPTURE))
413 goto next;
414
415 if (IPin_EnumMediaTypes(pin, &types) != S_OK)
416 goto next;
417
418 // enumerate media types exposed by pin
419 // NB: don't know if a pin can expose both audio and video, check 'm all to be safe
420 IEnumMediaTypes_Reset(types);
421 while (IEnumMediaTypes_Next(types, 1, &
type,
NULL) == S_OK) {
422 if (IsEqualGUID(&
type->majortype, &MEDIATYPE_Video)) {
423 has_video = 1;
424 }
else if (IsEqualGUID(&
type->majortype, &MEDIATYPE_Audio)) {
425 has_audio = 1;
426 }
428 }
429
430 next:
431 if (types)
432 IEnumMediaTypes_Release(types);
434 IKsPropertySet_Release(
p);
435
436 IPin_Release(pin);
437 }
438
439 IEnumPins_Release(pins);
440
441 if (has_audio || has_video) {
442 int nb_types = has_audio + has_video;
444 if (*media_types) {
445 if (has_audio)
447 if (has_video)
449 *nb_media_types = nb_types;
450 }
451 }
452 }
453
454 /**
455 * Cycle through available devices using the device enumerator devenum,
456 * retrieve the device with type specified by devtype and return the
457 * pointer to the object found in *pfilter.
458 * If pfilter is NULL, list all device names.
459 * If device_list is not NULL, populate it with found devices instead of
460 * outputting device names to log
461 */
462 static int
467 {
470 IEnumMoniker *classenum =
NULL;
474 :
ctx->audio_device_number;
476
477 const GUID *device_guid[2] = { &CLSID_VideoInputDeviceCategory,
478 &CLSID_AudioInputDeviceCategory };
479 const char *devtypename = (devtype ==
VideoDevice) ?
"video" :
"audio only";
480 const char *sourcetypename = (sourcetype ==
VideoSourceDevice) ?
"video" :
"audio";
481
482 r = ICreateDevEnum_CreateClassEnumerator(devenum, device_guid[sourcetype],
483 (IEnumMoniker **) &classenum, 0);
486 devtypename);
488 }
489
491 IPropertyBag *bag =
NULL;
493 char *unique_name =
NULL;
494 VARIANT var;
495 IBindCtx *bind_ctx =
NULL;
496 LPOLESTR olestr =
NULL;
497 LPMALLOC co_malloc =
NULL;
500 int nb_media_types = 0;
502
503 r = CoGetMalloc(1, &co_malloc);
506 r = CreateBindCtx(0, &bind_ctx);
509 /* GetDisplayname works for both video and audio, DevicePath doesn't */
510 r = IMoniker_GetDisplayName(m, bind_ctx,
NULL, &olestr);
514 /* replace ':' with '_' since we use : to delineate between sources */
515 for (
i = 0;
i < strlen(unique_name);
i++) {
516 if (unique_name[
i] ==
':')
517 unique_name[
i] =
'_';
518 }
519
520 r = IMoniker_BindToStorage(m, 0, 0, &IID_IPropertyBag, (
void *) &bag);
523
524 var.vt = VT_BSTR;
525 r = IPropertyBag_Read(bag,
L "FriendlyName", &var,
NULL);
529
530 if (pfilter) {
533
535 r = IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (
void *) &
device_filter);
539 }
542 // success, loop will end now
543 }
544 } else {
545 // get media types exposed by pins of device
546 if (IMoniker_BindToObject(m, 0, 0, &IID_IBaseFilter, (
void* ) &
device_filter) == S_OK) {
550 }
551 if (device_list) {
553 if (!device)
555
560
561 // make space in device_list for this new device
563 (*device_list)->nb_devices + 1,
564 sizeof(*(*device_list)->devices)) < 0)
566
567 // attach media_types to device
570 nb_media_types = 0;
572
573 // store device in list
574 (*device_list)->devices[(*device_list)->nb_devices] = device;
575 (*device_list)->nb_devices++;
576 device =
NULL;
// copied into array, make sure not freed below
577 }
578 else {
580 if (nb_media_types > 0) {
583 for (
int i = 1;
i < nb_media_types; ++
i) {
586 }
588 } else {
590 }
593 }
594 }
595
598 if (device) {
601 // NB: no need to av_freep(&device->media_types), its only moved to device once nothing can fail anymore
603 }
604 if (olestr && co_malloc)
605 IMalloc_Free(co_malloc, olestr);
606 if (bind_ctx)
607 IBindCtx_Release(bind_ctx);
610 if (bag)
611 IPropertyBag_Release(bag);
612 IMoniker_Release(m);
613 }
614
615 IEnumMoniker_Release(classenum);
616
617 if (pfilter) {
619 av_log(avctx,
AV_LOG_ERROR,
"Could not find %s device with name [%s] among source devices of type %s.\n",
622 }
624 }
625
626 return 0;
627 }
628
630 {
631 ICreateDevEnum *devenum =
NULL;
634
635 if (!device_list)
637
638 CoInitialize(0);
639
640 r = CoCreateInstance(&CLSID_SystemDeviceEnum,
NULL, CLSCTX_INPROC_SERVER,
641 &IID_ICreateDevEnum, (void**)&devenum);
645 }
646
651
653 if (devenum)
654 ICreateDevEnum_Release(devenum);
655
656 CoUninitialize();
657
659 }
660
662 {
664
666 (
ctx->requested_width &&
ctx->requested_height) ||
670 }
671
672
675 // video
686 // audio
690 };
691
692 // user must av_free the returned pointer
694 {
696 BITMAPINFOHEADER *bih;
697 DXVA2_ExtendedFormat *extended_format_info =
NULL;
698 WAVEFORMATEX *fx;
701
704
705 if (IsEqualGUID(&
type->formattype, &FORMAT_VideoInfo)) {
706 VIDEOINFOHEADER *v = (
void *)
type->pbFormat;
708 bih = &v->bmiHeader;
710 }
else if (IsEqualGUID(&
type->formattype, &FORMAT_VideoInfo2)) {
711 VIDEOINFOHEADER2 *v = (
void *)
type->pbFormat;
714 bih = &v->bmiHeader;
716 extended_format_info = (DXVA2_ExtendedFormat *) &v->dwControlFlags;
717 }
else if (IsEqualGUID(&
type->formattype, &FORMAT_WaveFormatEx)) {
718 fx = (
void *)
type->pbFormat;
720 } else {
722 }
723
725 if (!fmt_info)
727 // initialize fields where unset is not zero
732 // now get info about format
735 fmt_info->
width = bih->biWidth;
736 fmt_info->
height = bih->biHeight;
742 }
743 else
745
746 if (extended_format_info) {
752 }
753 } else {
757 }
758
759 return fmt_info;
760 }
761
763 {
764 HRESULT hr;
765
766 if ((hr = IAMStreamConfig_GetFormat(
config,
type)) != S_OK) {
767 if (hr == E_NOTIMPL || !IsEqualGUID(&(*type)->majortype,
devtype ==
VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
768 // default not available or of wrong type,
769 // fall back to iterating exposed formats
770 // until one of the right type is found
771 IEnumMediaTypes* types =
NULL;
772 if (IPin_EnumMediaTypes(pin, &types) != S_OK)
773 return;
774 IEnumMediaTypes_Reset(types);
775 while (IEnumMediaTypes_Next(types, 1,
type,
NULL) == S_OK) {
776 if (IsEqualGUID(&(*type)->majortype,
devtype ==
VideoDevice ? &MEDIATYPE_Video : &MEDIATYPE_Audio)) {
777 break;
778 }
779 CoTaskMemFree(*
type);
781 }
782 IEnumMediaTypes_Release(types);
783 }
784 }
785 }
786
787 /**
788 * Cycle through available formats available from the specified pin,
789 * try to set parameters specified through AVOptions, or the pin's
790 * default format if no such parameters were set. If successful,
791 * return 1 in *pformat_set.
792 * If pformat_set is NULL, list all pin capabilities.
793 */
794 static void
796 IPin *pin, int *pformat_set)
797 {
801 AM_MEDIA_TYPE *previous_match_type =
NULL;
802 int format_set = 0;
805 int wait_for_better = 0;
806 int use_default;
807
808 // format parameters requested by user
809 // if none are requested by user, the values will below be set to
810 // those of the default format
811 // video
815 /
ctx->requested_framerate.num : 0;
818 // audio
819 int requested_sample_rate =
ctx->sample_rate;
820 int requested_sample_size =
ctx->sample_size;
821 int requested_channels =
ctx->channels;
822
823 if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (
void **) &
config) != S_OK)
824 return;
825 if (IAMStreamConfig_GetNumberOfCapabilities(
config, &n, &
size) != S_OK)
826 goto end;
827
829 if (!caps)
830 goto end;
831
832 /**
833 * If we should open the device with the default format,
834 * then:
835 * 1. check what the format of the default device is, and
836 * 2. below we iterate all formats till we find a matching
837 * one, with most info exposed (see comment below).
838 */
840 if (use_default && pformat_set)
841 {
842 // get default
845 // this pin does not expose any formats of the expected type
846 goto end;
847
849 // interrogate default format, so we know what to search for below
851 if (fmt_info) {
853 requested_video_codec_id = fmt_info->
codec_id;
854 requested_pixel_format = fmt_info->
pix_fmt;
855 requested_framerate = fmt_info->
framerate;
856 requested_width = fmt_info->
width;
857 requested_height = fmt_info->
height;
858 } else {
861 requested_channels = fmt_info->
channels;
862 }
863 av_free(fmt_info);
// free but don't set to NULL to enable below check
864 }
865
867 CoTaskMemFree(
type->pbFormat);
870 if (!fmt_info)
871 // default format somehow invalid, can't continue with this pin
872 goto end;
874 }
875 }
876
877 // NB: some devices (e.g. Logitech C920) expose each video format twice:
878 // both a format containing a VIDEOINFOHEADER and a format containing
879 // a VIDEOINFOHEADER2. We want, if possible, to select a format with a
880 // VIDEOINFOHEADER2, as this potentially provides more info about the
881 // format. So, if in the iteration below we have found a matching format,
882 // but it is a VIDEOINFOHEADER, keep looking for a matching format that
883 // exposes contains a VIDEOINFOHEADER2. Fall back to the VIDEOINFOHEADER
884 // format if no corresponding VIDEOINFOHEADER2 is found when we finish
885 // iterating.
886 for (
i = 0;
i < n && !format_set;
i++) {
888 r = IAMStreamConfig_GetStreamCaps(
config,
i, &
type, (
void *) caps);
890 goto next;
891 #if DSHOWDEBUG
893 #endif
894
896 if (!fmt_info)
897 goto next;
898
900 VIDEO_STREAM_CONFIG_CAPS *vcaps = caps;
901 BITMAPINFOHEADER *bih =
NULL;
903 #if DSHOWDEBUG
905 #endif
906
908 goto next;
909
910 if (IsEqualGUID(&
type->formattype, &FORMAT_VideoInfo)) {
911 VIDEOINFOHEADER *v = (
void *)
type->pbFormat;
912 fr = &v->AvgTimePerFrame;
913 bih = &v->bmiHeader;
914 wait_for_better = 1;
915 }
else if (IsEqualGUID(&
type->formattype, &FORMAT_VideoInfo2)) {
916 VIDEOINFOHEADER2 *v = (
void *)
type->pbFormat;
917 fr = &v->AvgTimePerFrame;
918 bih = &v->bmiHeader;
919 wait_for_better = 0;
920 }
921
922 if (!pformat_set) {
927 av_log(avctx,
AV_LOG_INFO,
" unknown compression type 0x%X", (
int) bih->biCompression);
928 } else {
930 }
931 } else {
933 }
935 vcaps->MinOutputSize.cx, vcaps->MinOutputSize.cy,
936 1e7 / vcaps->MaxFrameInterval,
937 vcaps->MaxOutputSize.cx, vcaps->MaxOutputSize.cy,
938 1e7 / vcaps->MinFrameInterval);
939
951 prim ? prim : "unknown",
952 trc ? trc : "unknown");
956 }
959
961 goto next;
962 }
964 if (requested_video_codec_id != fmt_info->
codec_id)
965 goto next;
966 }
968 requested_pixel_format != fmt_info->
pix_fmt) {
969 goto next;
970 }
971 if (requested_framerate) {
972 if (requested_framerate > vcaps->MaxFrameInterval ||
973 requested_framerate < vcaps->MinFrameInterval)
974 goto next;
975 *fr = requested_framerate;
976 }
977 if (requested_width && requested_height) {
978 if (requested_width > vcaps->MaxOutputSize.cx ||
979 requested_width < vcaps->MinOutputSize.cx ||
980 requested_height > vcaps->MaxOutputSize.cy ||
981 requested_height < vcaps->MinOutputSize.cy)
982 goto next;
983 bih->biWidth = requested_width;
984 bih->biHeight = requested_height;
985 }
986 } else {
987 WAVEFORMATEX *fx;
988 #if DSHOWDEBUG
989 AUDIO_STREAM_CONFIG_CAPS *acaps = caps;
991 #endif
992 if (IsEqualGUID(&
type->formattype, &FORMAT_WaveFormatEx)) {
993 fx = (
void *)
type->pbFormat;
994 } else {
995 goto next;
996 }
997 if (!pformat_set) {
999 avctx,
1001 " ch=%2u, bits=%2u, rate=%6lu\n",
1002 fx->nChannels, fx->wBitsPerSample, fx->nSamplesPerSec
1003 );
1004 goto next;
1005 }
1006 if (
1007 (requested_sample_rate && requested_sample_rate != fx->nSamplesPerSec) ||
1008 (requested_sample_size && requested_sample_size != fx->wBitsPerSample) ||
1009 (requested_channels && requested_channels != fx->nChannels )
1010 ) {
1011 goto next;
1012 }
1013 }
1014
1015 // found a matching format. Either apply or store
1016 // for safekeeping if we might maybe find a better
1017 // format with more info attached to it (see comment
1018 // above loop)
1019 if (!wait_for_better) {
1020 if (IAMStreamConfig_SetFormat(
config,
type) != S_OK)
1021 goto next;
1022 format_set = 1;
1023 }
1024 else if (!previous_match_type) {
1025 // store this matching format for possible later use.
1026 // If we have already found a matching format, ignore it
1027 previous_match_type =
type;
1029 }
1030 next:
1033 CoTaskMemFree(
type->pbFormat);
1034 CoTaskMemFree(
type);
1036 }
1037
1038 // set the pin's format, if wanted
1039 if (pformat_set && !format_set) {
1040 if (previous_match_type) {
1041 // previously found a matching VIDEOINFOHEADER format and stored
1042 // it for safe keeping. Searching further for a matching
1043 // VIDEOINFOHEADER2 format yielded nothing. So set the pin's
1044 // format based on the VIDEOINFOHEADER format.
1045 // NB: this never applies to an audio format because
1046 // previous_match_type always NULL in that case
1047 if (IAMStreamConfig_SetFormat(
config, previous_match_type) == S_OK)
1048 format_set = 1;
1049 }
1050 else if (use_default) {
1051 // default format returned by device apparently was not contained
1052 // in the capabilities of any of the formats returned by the device
1053 // (sic?). Fall back to directly setting the default format
1055 if (IAMStreamConfig_SetFormat(
config,
type) == S_OK)
1056 format_set = 1;
1058 CoTaskMemFree(
type->pbFormat);
1059 CoTaskMemFree(
type);
1061 }
1062 }
1063
1064 end:
1065 if (previous_match_type && previous_match_type->pbFormat)
1066 CoTaskMemFree(previous_match_type->pbFormat);
1067 CoTaskMemFree(previous_match_type);
1068 IAMStreamConfig_Release(
config);
1070 if (pformat_set)
1071 *pformat_set = format_set;
1072 }
1073
1074 /**
1075 * Set audio device buffer size in milliseconds (which can directly impact
1076 * latency, depending on the device).
1077 */
1078 static int
1080 {
1082 IAMBufferNegotiation *buffer_negotiation =
NULL;
1083 ALLOCATOR_PROPERTIES props = { -1, -1, -1, -1 };
1087
1088 if (IPin_QueryInterface(pin, &IID_IAMStreamConfig, (
void **) &
config) != S_OK)
1089 goto end;
1090 if (IAMStreamConfig_GetFormat(
config, &
type) != S_OK)
1091 goto end;
1092 if (!IsEqualGUID(&
type->formattype, &FORMAT_WaveFormatEx))
1093 goto end;
1094
1095 props.cbBuffer = (((WAVEFORMATEX *)
type->pbFormat)->nAvgBytesPerSec)
1096 *
ctx->audio_buffer_size / 1000;
1097
1098 if (IPin_QueryInterface(pin, &IID_IAMBufferNegotiation, (
void **) &buffer_negotiation) != S_OK)
1099 goto end;
1100 if (IAMBufferNegotiation_SuggestAllocatorProperties(buffer_negotiation, &props) != S_OK)
1101 goto end;
1102
1104
1105 end:
1106 if (buffer_negotiation)
1107 IAMBufferNegotiation_Release(buffer_negotiation);
1110 CoTaskMemFree(
type->pbFormat);
1111 CoTaskMemFree(
type);
1112 }
1114 IAMStreamConfig_Release(
config);
1115
1117 }
1118
1119 /**
1120 * Pops up a user dialog allowing them to adjust properties for the given filter, if possible.
1121 */
1122 void
1124 ISpecifyPropertyPages *property_pages =
NULL;
1125 IUnknown *device_filter_iunknown =
NULL;
1126 HRESULT hr;
1127 FILTER_INFO filter_info = {0}; /* a warning on this line is false positive GCC bug 53119 AFAICT */
1128 CAUUID ca_guid = {0};
1129
1130 hr = IBaseFilter_QueryInterface(
device_filter, &IID_ISpecifyPropertyPages, (
void **)&property_pages);
1131 if (hr != S_OK) {
1133 goto end;
1134 }
1135 hr = IBaseFilter_QueryFilterInfo(
device_filter, &filter_info);
1136 if (hr != S_OK) {
1138 }
1139 hr = IBaseFilter_QueryInterface(
device_filter, &IID_IUnknown, (
void **)&device_filter_iunknown);
1140 if (hr != S_OK) {
1142 }
1143 hr = ISpecifyPropertyPages_GetPages(property_pages, &ca_guid);
1144 if (hr != S_OK) {
1146 }
1147 hr = OleCreatePropertyFrame(
NULL, 0, 0, filter_info.achName, 1, &device_filter_iunknown, ca_guid.cElems,
1148 ca_guid.pElems, 0, 0,
NULL);
1149 if (hr != S_OK) {
1151 }
1152 goto end;
1155 end:
1156 if (property_pages)
1157 ISpecifyPropertyPages_Release(property_pages);
1158 if (device_filter_iunknown)
1159 IUnknown_Release(device_filter_iunknown);
1160 if (filter_info.pGraph)
1161 IFilterGraph_Release(filter_info.pGraph);
1162 if (ca_guid.pElems)
1163 CoTaskMemFree(ca_guid.pElems);
1164 }
1165
1166 /**
1167 * Cycle through available pins using the device_filter device, of type
1168 * devtype, retrieve the first output pin and return the pointer to the
1169 * object found in *ppin.
1170 * If ppin is NULL, cycle through all pins listing audio/video capabilities.
1171 */
1172 static int
1175 {
1177 IEnumPins *pins = 0;
1179 IPin *pin;
1181
1182 const char *devtypename = (devtype ==
VideoDevice) ?
"video" :
"audio only";
1183 const char *sourcetypename = (sourcetype ==
VideoSourceDevice) ?
"video" :
"audio";
1184
1186 int format_set = 0;
1187 int should_show_properties = (devtype ==
VideoDevice) ?
ctx->show_video_device_dialog :
ctx->show_audio_device_dialog;
1188
1189 if (should_show_properties)
1191
1196 }
1197
1198 if (!ppin) {
1200 devtypename, sourcetypename);
1201 }
1202
1203 while (!
device_pin && IEnumPins_Next(pins, 1, &pin,
NULL) == S_OK) {
1204 IKsPropertySet *
p =
NULL;
1205 PIN_INFO
info = {0};
1207 DWORD r2;
1208 char *name_buf =
NULL;
1209 wchar_t *pin_id =
NULL;
1210 char *pin_buf =
NULL;
1211 char *desired_pin_name = devtype ==
VideoDevice ?
ctx->video_pin_name :
ctx->audio_pin_name;
1212
1213 IPin_QueryPinInfo(pin, &
info);
1214 IBaseFilter_Release(
info.pFilter);
1215
1216 if (
info.dir != PINDIR_OUTPUT)
1217 goto next;
1218 if (IPin_QueryInterface(pin, &IID_IKsPropertySet, (
void **) &
p) != S_OK)
1219 goto next;
1220 if (IKsPropertySet_Get(
p, &ROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
1222 goto next;
1223 if (!IsEqualGUID(&
category, &PIN_CATEGORY_CAPTURE))
1224 goto next;
1226
1227 r = IPin_QueryId(pin, &pin_id);
1231 }
1233
1234 if (!ppin) {
1235 av_log(avctx,
AV_LOG_INFO,
" Pin \"%s\" (alternative pin name \"%s\")\n", name_buf, pin_buf);
1237 goto next;
1238 }
1239
1240 if (desired_pin_name) {
1241 if(strcmp(name_buf, desired_pin_name) && strcmp(pin_buf, desired_pin_name)) {
1243 name_buf, pin_buf, desired_pin_name);
1244 goto next;
1245 }
1246 }
1247
1248 // will either try to find format matching options supplied by user
1249 // or try to open default format. Successful if returns with format_set==1
1251 if (!format_set) {
1252 goto next;
1253 }
1254
1257 av_log(avctx,
AV_LOG_ERROR,
"unable to set audio buffer size %d to pin, using pin anyway...",
ctx->audio_buffer_size);
1258 }
1259 }
1260
1261 if (format_set) {
1264 }
1265 next:
1267 IKsPropertySet_Release(
p);
1269 IPin_Release(pin);
1272 if (pin_id)
1273 CoTaskMemFree(pin_id);
1274 }
1275
1276 IEnumPins_Release(pins);
1277
1278 if (ppin) {
1282 }
1285 "Could not find output pin from %s capture device.\n", devtypename);
1287 }
1289 }
1290
1291 return 0;
1292 }
1293
1294 /**
1295 * List options for device with type devtype, source filter type sourcetype
1296 *
1297 * @param devenum device enumerator used for accessing the device
1298 */
1299 static int
1302 {
1307
1314 return 0;
1315 }
1316
1317 static int
1320 {
1323 char *device_filter_unique_name =
NULL;
1328 ICaptureGraphBuilder2 *graph_builder2 =
NULL;
1331 IStream *ifile_stream =
NULL;
1332 IStream *ofile_stream =
NULL;
1333 IPersistStream *pers_stream =
NULL;
1335
1336 const wchar_t *filter_name[2] = {
L "Audio capture filter",
L "Video capture filter" };
1337
1338
1339 if ( ((
ctx->audio_filter_load_file) && (strlen(
ctx->audio_filter_load_file)>0) && (sourcetype ==
AudioSourceDevice)) ||
1340 ((
ctx->video_filter_load_file) && (strlen(
ctx->video_filter_load_file)>0) && (sourcetype ==
VideoSourceDevice)) ) {
1341 HRESULT hr;
1342 char *filename =
NULL;
1343
1345 filename =
ctx->audio_filter_load_file;
1346 else
1347 filename =
ctx->video_filter_load_file;
1348
1349 hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_READ, &ifile_stream);
1350 if (S_OK != hr) {
1353 }
1354
1355 hr = OleLoadFromStream(ifile_stream, &IID_IBaseFilter, (
void **) &
device_filter);
1356 if (hr != S_OK) {
1359 }
1360
1363 else
1365 av_log(avctx,
AV_LOG_INFO,
"Capture filter loaded successfully from file \"%s\".\n", filename);
1366 } else {
1367
1371 }
1372 }
1373 if (
ctx->device_filter[otherDevType]) {
1374 // avoid adding add two instances of the same device to the graph, one for video, one for audio
1375 // a few devices don't support this (could also do this check earlier to avoid double crossbars, etc. but they seem OK)
1376 if (!device_filter_unique_name || strcmp(device_filter_unique_name,
ctx->device_unique_name[otherDevType]) == 0) {
1377 av_log(avctx,
AV_LOG_DEBUG,
"reusing previous graph capture filter... %s\n", device_filter_unique_name);
1380 IBaseFilter_AddRef(
ctx->device_filter[otherDevType]);
1381 } else {
1382 av_log(avctx,
AV_LOG_DEBUG,
"not reusing previous graph capture filter %s != %s\n", device_filter_unique_name,
ctx->device_unique_name[otherDevType]);
1383 }
1384 }
1385
1387 ctx->device_unique_name [devtype] = device_filter_unique_name;
1388
1393 }
1394
1398 }
1399
1401
1406 }
1408
1409 if ( ((
ctx->audio_filter_save_file) && (strlen(
ctx->audio_filter_save_file)>0) && (sourcetype ==
AudioSourceDevice)) ||
1410 ((
ctx->video_filter_save_file) && (strlen(
ctx->video_filter_save_file)>0) && (sourcetype ==
VideoSourceDevice)) ) {
1411
1412 HRESULT hr;
1413 char *filename =
NULL;
1414
1416 filename =
ctx->audio_filter_save_file;
1417 else
1418 filename =
ctx->video_filter_save_file;
1419
1420 hr = SHCreateStreamOnFile ((LPCSTR) filename, STGM_CREATE | STGM_READWRITE, &ofile_stream);
1421 if (S_OK != hr) {
1424 }
1425
1426 hr = IBaseFilter_QueryInterface(
device_filter, &IID_IPersistStream, (
void **) &pers_stream);
1427 if (hr != S_OK) {
1430 }
1431
1432 hr = OleSaveToStream(pers_stream, ofile_stream);
1433 if (hr != S_OK) {
1436 }
1437
1438 hr = IStream_Commit(ofile_stream, STGC_DEFAULT);
1439 if (S_OK != hr) {
1442 }
1443
1446 else
1448 av_log(avctx,
AV_LOG_INFO,
"Capture filter saved successfully to file \"%s\".\n", filename);
1449 }
1450
1452 filter_name[devtype]);
1456 }
1457
1461
1462 r = CoCreateInstance(&CLSID_CaptureGraphBuilder2,
NULL, CLSCTX_INPROC_SERVER,
1463 &IID_ICaptureGraphBuilder2, (void **) &graph_builder2);
1467 }
1468 r = ICaptureGraphBuilder2_SetFiltergraph(graph_builder2,
graph);
1472 }
1473
1474 r = ICaptureGraphBuilder2_RenderStream(graph_builder2,
NULL,
NULL, (IUnknown *)
device_pin,
NULL /* no intermediate filter */,
1475 (IBaseFilter *)
capture_filter);
/* connect pins, optionally insert intermediate filters like crossbar if necessary */
1476
1480 }
1481
1483
1487 }
1488
1490
1492 if (graph_builder2 !=
NULL)
1493 ICaptureGraphBuilder2_Release(graph_builder2);
1494
1495 if (pers_stream)
1496 IPersistStream_Release(pers_stream);
1497
1498 if (ifile_stream)
1499 IStream_Release(ifile_stream);
1500
1501 if (ofile_stream)
1502 IStream_Release(ofile_stream);
1503
1505 }
1506
1508 {
1509 switch (sample_fmt) {
1514 }
1515 }
1516
1518 {
1524 }
1525 }
1526
1527 static int
1530 {
1537
1539
1541 if (!st) {
1544 }
1546
1548
1552 }
1554 if (!fmt_info) {
1557 }
1558
1561 BITMAPINFOHEADER *bih =
NULL;
1563
1564 if (IsEqualGUID(&
type.formattype, &FORMAT_VideoInfo)) {
1565 VIDEOINFOHEADER *v = (
void *)
type.pbFormat;
1566 time_base = (
AVRational) { v->AvgTimePerFrame, 10000000 };
1567 bih = &v->bmiHeader;
1568 }
else if (IsEqualGUID(&
type.formattype, &FORMAT_VideoInfo2)) {
1569 VIDEOINFOHEADER2 *v = (
void *)
type.pbFormat;
1570 time_base = (
AVRational) { v->AvgTimePerFrame, 10000000 };
1571 bih = &v->bmiHeader;
1572 }
1573 if (!bih) {
1576 }
1577
1580
1586 if (bih->biCompression ==
MKTAG(
'H',
'D',
'Y',
'C')) {
1589 }
1597 if (bih->biCompression == BI_RGB || bih->biCompression == BI_BITFIELDS) {
1601 } else {
1606 }
1607 }
1608 }
1609 } else {
1612 "Please report type 0x%X.\n", (int) bih->biCompression);
1615 }
1617 }
1618 } else {
1619 if (!IsEqualGUID(&
type.formattype, &FORMAT_WaveFormatEx)) {
1622 }
1623
1629 }
1630
1632
1634
1638 CoTaskMemFree(
type.pbFormat);
1640 }
1641
1643 {
1650
1651 while ((
type = strtok(
tmp,
"="))) {
1652 char *token = strtok(
NULL,
":");
1654
1655 if (!strcmp(
type,
"video")) {
1657 }
else if (!strcmp(
type,
"audio")) {
1659 } else {
1662 break;
1663 }
1664 }
1665
1668 } else {
1673 }
1674
1677 }
1678
1680 {
1683 ICreateDevEnum *devenum =
NULL;
1686 HANDLE media_event_handle;
1687 HANDLE proc;
1690
1691 CoInitialize(0);
1692
1696 }
1697
1703 "video codec is not set or set to rawvideo\n");
1706 }
1707 }
1708 if (
ctx->framerate) {
1713 }
1714 }
1715
1716 r = CoCreateInstance(&CLSID_FilterGraph,
NULL, CLSCTX_INPROC_SERVER,
1717 &IID_IGraphBuilder, (
void **) &
graph);
1721 }
1723
1724 r = CoCreateInstance(&CLSID_SystemDeviceEnum,
NULL, CLSCTX_INPROC_SERVER,
1725 &IID_ICreateDevEnum, (void **) &devenum);
1729 }
1730
1731 if (
ctx->list_devices) {
1736 }
1737 if (
ctx->list_options) {
1742 }
1745 /* show audio options from combined video+audio sources as fallback */
1749 }
1750 }
1751 }
1752 // don't exit yet, allow it to list crossbar options in dshow_open_device
1753 }
1759 }
1760 }
1765 /* see if there's a video source with an audio pin with the given audio name */
1770 }
1771 }
1772 }
1773 if (
ctx->list_options) {
1774 /* allow it to list crossbar options in dshow_open_device */
1777 }
1778 ctx->curbufsize[0] = 0;
1779 ctx->curbufsize[1] = 0;
1784 }
1786 if (!
ctx->event[1]) {
1789 }
1790
1791 r = IGraphBuilder_QueryInterface(
graph, &IID_IMediaControl, (
void **) &
control);
1795 }
1797
1798 r = IGraphBuilder_QueryInterface(
graph, &IID_IMediaEvent, (
void **) &
media_event);
1802 }
1804
1805 r = IMediaEvent_GetEventHandle(
media_event, (
void *) &media_event_handle);
1809 }
1810 proc = GetCurrentProcess();
1811 r = DuplicateHandle(proc, media_event_handle, proc, &
ctx->event[0],
1812 0, 0, DUPLICATE_SAME_ACCESS);
1816 }
1817
1820 OAFilterState pfs;
1821 r = IMediaControl_GetState(
control, 0, &pfs);
1822 }
1824 av_log(avctx,
AV_LOG_ERROR,
"Could not run graph (sometimes caused by a device already in use by other application)\n");
1826 }
1827
1829
1831
1832 if (devenum)
1833 ICreateDevEnum_Release(devenum);
1834
1837
1839 }
1840
1841 /**
1842 * Checks media events from DirectShow and returns -1 on error or EOF. Also
1843 * purges all events that might be in the event queue to stop the trigger
1844 * of event notification.
1845 */
1847 {
1848 LONG_PTR p1, p2;
1851
1852 while (IMediaEvent_GetEvent(
media_event, &
code, &p1, &p2, 0) != E_ABORT) {
1856 }
1857
1859 }
1860
1862 {
1865
1871 ctx->pktl =
ctx->pktl->next;
1874 }
1875 ResetEvent(
ctx->event[1]);
1876 ReleaseMutex(
ctx->mutex);
1882 } else {
1883 WaitForMultipleObjects(2,
ctx->event, 0, INFINITE);
1884 }
1885 }
1886 }
1887
1889 }
1890
1891 #define OFFSET(x) offsetof(struct dshow_ctx, x)
1892 #define DEC AV_OPT_FLAG_DECODING_PARAM
1921 };
1922
1929 };
1930
1937 .priv_data_size =
sizeof(
struct dshow_ctx),
1942 };