@@ -49,7 +49,7 @@ pub mod wmf {
49
49
use nokhwa_core:: control:: { CameraControl , ControlValueDescription , ControlValue , KnownCameraControl } ;
50
50
use windows:: Win32 :: Media :: DirectShow :: { CameraControl_Flags_Auto , CameraControl_Flags_Manual } ;
51
51
use windows:: Win32 :: Media :: MediaFoundation :: {
52
- IMFMediaType , MFCreateSample , MF_SOURCE_READER_FIRST_VIDEO_STREAM ,
52
+ MFCreateSample , MF_SOURCE_READER_FIRST_VIDEO_STREAM ,
53
53
} ;
54
54
use windows:: {
55
55
core:: { Interface , GUID , PWSTR } ,
@@ -66,14 +66,14 @@ pub mod wmf {
66
66
KernelStreaming :: GUID_NULL ,
67
67
MediaFoundation :: {
68
68
IMFActivate , IMFAttributes , IMFMediaSource , IMFSample , IMFSourceReader ,
69
- MFCreateAttributes , MFCreateMediaType , MFCreateSourceReaderFromMediaSource ,
70
- MFEnumDeviceSources , MFMediaType_Video , MFShutdown , MFStartup ,
69
+ MFCreateAttributes , MFCreateSourceReaderFromMediaSource ,
70
+ MFEnumDeviceSources , MFShutdown , MFStartup ,
71
71
MFSTARTUP_NOSOCKET , MF_API_VERSION , MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME ,
72
72
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE ,
73
73
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID ,
74
74
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK , MF_MT_FRAME_RATE ,
75
75
MF_MT_FRAME_RATE_RANGE_MAX , MF_MT_FRAME_RATE_RANGE_MIN , MF_MT_FRAME_SIZE ,
76
- MF_MT_MAJOR_TYPE , MF_MT_SUBTYPE , MF_READWRITE_DISABLE_CONVERTERS ,
76
+ MF_MT_SUBTYPE , MF_READWRITE_DISABLE_CONVERTERS ,
77
77
} ,
78
78
} ,
79
79
System :: Com :: { CoInitializeEx , CoUninitialize , COINIT } ,
@@ -166,24 +166,14 @@ pub mod wmf {
166
166
fn guid_to_frameformat ( guid : GUID ) -> Option < FrameFormat > {
167
167
match guid {
168
168
MF_VIDEO_FORMAT_NV12 => Some ( FrameFormat :: NV12 ) ,
169
- MF_VIDEO_FORMAT_RGB24 => Some ( FrameFormat :: RAWRGB ) ,
169
+ MF_VIDEO_FORMAT_RGB24 => Some ( FrameFormat :: RAWBGR ) ,
170
170
MF_VIDEO_FORMAT_GRAY => Some ( FrameFormat :: GRAY ) ,
171
171
MF_VIDEO_FORMAT_YUY2 => Some ( FrameFormat :: YUYV ) ,
172
172
MF_VIDEO_FORMAT_MJPEG => Some ( FrameFormat :: MJPEG ) ,
173
173
_ => None ,
174
174
}
175
175
}
176
176
177
- fn frameformat_to_guid ( frameformat : FrameFormat ) -> GUID {
178
- match frameformat {
179
- FrameFormat :: MJPEG => MF_VIDEO_FORMAT_MJPEG ,
180
- FrameFormat :: YUYV => MF_VIDEO_FORMAT_YUY2 ,
181
- FrameFormat :: NV12 => MF_VIDEO_FORMAT_NV12 ,
182
- FrameFormat :: GRAY => MF_VIDEO_FORMAT_GRAY ,
183
- FrameFormat :: RAWRGB => MF_VIDEO_FORMAT_RGB24 ,
184
- }
185
- }
186
-
187
177
pub fn initialize_mf ( ) -> Result < ( ) , NokhwaError > {
188
178
if !( INITIALIZED . load ( Ordering :: SeqCst ) ) {
189
179
if let Err ( why) = unsafe {
@@ -575,6 +565,7 @@ pub mod wmf {
575
565
self . source_reader
576
566
. GetNativeMediaType ( MEDIA_FOUNDATION_FIRST_VIDEO_STREAM , index)
577
567
} {
568
+ index += 1 ;
578
569
let fourcc = match unsafe { media_type. GetGUID ( & MF_MT_SUBTYPE ) } {
579
570
Ok ( fcc) => fcc,
580
571
Err ( why) => {
@@ -599,7 +590,7 @@ pub mod wmf {
599
590
}
600
591
} ;
601
592
602
- // MFRatio is represented as 2 u32s in memory. This means we cann convert it to 2
593
+ // MFRatio is represented as 2 u32s in memory. This means we can convert it to 2
603
594
let framerate_list = {
604
595
let mut framerates = vec ! [ 0_u32 ; 3 ] ;
605
596
if let Ok ( fraction_u64) =
@@ -612,16 +603,6 @@ pub mod wmf {
612
603
}
613
604
framerates. push ( numerator) ;
614
605
} ;
615
- if let Ok ( fraction_u64) =
616
- unsafe { media_type. GetUINT64 ( & MF_MT_FRAME_RATE_RANGE_MAX ) }
617
- {
618
- let mut numerator = ( fraction_u64 >> 32 ) as u32 ;
619
- let denominator = fraction_u64 as u32 ;
620
- if denominator != 1 {
621
- numerator = 0 ;
622
- }
623
- framerates. push ( numerator) ;
624
- } ;
625
606
if let Ok ( fraction_u64) = unsafe { media_type. GetUINT64 ( & MF_MT_FRAME_RATE ) } {
626
607
let mut numerator = ( fraction_u64 >> 32 ) as u32 ;
627
608
let denominator = fraction_u64 as u32 ;
@@ -660,8 +641,6 @@ pub mod wmf {
660
641
) ) ;
661
642
}
662
643
}
663
-
664
- index += 1 ;
665
644
}
666
645
Ok ( camera_format_list)
667
646
}
@@ -1016,88 +995,125 @@ pub mod wmf {
1016
995
}
1017
996
1018
997
pub fn set_format ( & mut self , format : CameraFormat ) -> Result < ( ) , NokhwaError > {
1019
- // convert to media_type
1020
- let media_type: IMFMediaType = match unsafe { MFCreateMediaType ( ) } {
1021
- Ok ( mt) => mt,
1022
- Err ( why) => {
1023
- return Err ( NokhwaError :: StructureError {
1024
- structure : "IMFMediaType" . to_string ( ) ,
1025
- error : why. to_string ( ) ,
1026
- } )
998
+ // We need to make sure to use all the original attributes of the IMFMediaType to avoid problems.
999
+ // Otherwise, constructing IMFMediaType from scratch can sometimes fail due to not exactly matching.
1000
+ // Therefore, we search for the first media_type that matches and also works correctly.
1001
+
1002
+ let mut last_error : Option < NokhwaError > = None ;
1003
+
1004
+ let mut index = 0 ;
1005
+ while let Ok ( media_type) = unsafe {
1006
+ self . source_reader
1007
+ . GetNativeMediaType ( MEDIA_FOUNDATION_FIRST_VIDEO_STREAM , index)
1008
+ } {
1009
+ index += 1 ;
1010
+ let fourcc = match unsafe { media_type. GetGUID ( & MF_MT_SUBTYPE ) } {
1011
+ Ok ( fcc) => fcc,
1012
+ Err ( why) => {
1013
+ return Err ( NokhwaError :: GetPropertyError {
1014
+ property : "MF_MT_SUBTYPE" . to_string ( ) ,
1015
+ error : why. to_string ( ) ,
1016
+ } )
1017
+ }
1018
+ } ;
1019
+
1020
+ let frame_fmt = match guid_to_frameformat ( fourcc) {
1021
+ Some ( fcc) => fcc,
1022
+ None => continue ,
1023
+ } ;
1024
+
1025
+ if frame_fmt != format. format ( ) {
1026
+ continue ;
1027
1027
}
1028
- } ;
1029
1028
1030
- // set relevant things
1031
- let resolution = ( u64:: from ( format. resolution ( ) . width_x ) << 32_u64 )
1032
- + u64:: from ( format. resolution ( ) . height_y ) ;
1033
- let fps = {
1034
- let frame_rate_u64 = 0_u64 ;
1035
- let mut bytes: [ u8 ; 8 ] = frame_rate_u64. to_le_bytes ( ) ;
1036
- bytes[ 7 ] = format. frame_rate ( ) as u8 ;
1037
- bytes[ 3 ] = 0x01 ;
1038
- u64:: from_le_bytes ( bytes)
1039
- } ;
1040
- let fourcc = frameformat_to_guid ( format. format ( ) ) ;
1041
- // setting to the new media_type
1042
- if let Err ( why) = unsafe { media_type. SetGUID ( & MF_MT_MAJOR_TYPE , & MFMediaType_Video ) } {
1043
- return Err ( NokhwaError :: SetPropertyError {
1044
- property : "MF_MT_MAJOR_TYPE" . to_string ( ) ,
1045
- value : "MFMediaType_Video" . to_string ( ) ,
1046
- error : why. to_string ( ) ,
1047
- } ) ;
1048
- }
1049
- if let Err ( why) = unsafe { media_type. SetGUID ( & MF_MT_SUBTYPE , & fourcc) } {
1050
- return Err ( NokhwaError :: SetPropertyError {
1051
- property : "MF_MT_SUBTYPE" . to_string ( ) ,
1052
- value : format ! ( "{:?}" , fourcc) ,
1053
- error : why. to_string ( ) ,
1054
- } ) ;
1055
- }
1056
- if let Err ( why) = unsafe { media_type. SetUINT64 ( & MF_MT_FRAME_SIZE , resolution) } {
1057
- return Err ( NokhwaError :: SetPropertyError {
1058
- property : "MF_MT_FRAME_SIZE" . to_string ( ) ,
1059
- value : resolution. to_string ( ) ,
1060
- error : why. to_string ( ) ,
1061
- } ) ;
1062
- }
1063
- if let Err ( why) = unsafe { media_type. SetUINT64 ( & MF_MT_FRAME_RATE , fps) } {
1064
- return Err ( NokhwaError :: SetPropertyError {
1065
- property : "MF_MT_FRAME_RATE" . to_string ( ) ,
1066
- value : fps. to_string ( ) ,
1067
- error : why. to_string ( ) ,
1068
- } ) ;
1069
- }
1070
- if let Err ( why) = unsafe { media_type. SetUINT64 ( & MF_MT_FRAME_RATE_RANGE_MIN , fps) } {
1071
- return Err ( NokhwaError :: SetPropertyError {
1072
- property : "MF_MT_FRAME_RATE_RANGE_MIN" . to_string ( ) ,
1073
- value : fps. to_string ( ) ,
1074
- error : why. to_string ( ) ,
1075
- } ) ;
1076
- }
1077
- if let Err ( why) = unsafe { media_type. SetUINT64 ( & MF_MT_FRAME_RATE_RANGE_MAX , fps) } {
1078
- return Err ( NokhwaError :: SetPropertyError {
1079
- property : "MF_MT_FRAME_RATE_RANGE_MAX" . to_string ( ) ,
1080
- value : fps. to_string ( ) ,
1081
- error : why. to_string ( ) ,
1082
- } ) ;
1029
+ let ( width, height) = match unsafe { media_type. GetUINT64 ( & MF_MT_FRAME_SIZE ) } {
1030
+ Ok ( res_u64) => {
1031
+ let width = ( res_u64 >> 32 ) as u32 ;
1032
+ let height = res_u64 as u32 ; // the cast will truncate the upper bits
1033
+ ( width, height)
1034
+ }
1035
+ Err ( why) => {
1036
+ return Err ( NokhwaError :: GetPropertyError {
1037
+ property : "MF_MT_FRAME_SIZE" . to_string ( ) ,
1038
+ error : why. to_string ( ) ,
1039
+ } )
1040
+ }
1041
+ } ;
1042
+
1043
+ if ( Resolution { width_x : width, height_y : height } ) != format. resolution ( ) {
1044
+ continue ;
1045
+ }
1046
+
1047
+ // MFRatio is represented as 2 u32s in memory. This means we can convert it to 2
1048
+ let framerate_list = {
1049
+ let mut framerates = vec ! [ 0_u32 ; 3 ] ;
1050
+ if let Ok ( fraction_u64) =
1051
+ unsafe { media_type. GetUINT64 ( & MF_MT_FRAME_RATE_RANGE_MAX ) }
1052
+ {
1053
+ let mut numerator = ( fraction_u64 >> 32 ) as u32 ;
1054
+ let denominator = fraction_u64 as u32 ;
1055
+ if denominator != 1 {
1056
+ numerator = 0 ;
1057
+ }
1058
+ framerates. push ( numerator) ;
1059
+ } ;
1060
+ if let Ok ( fraction_u64) = unsafe { media_type. GetUINT64 ( & MF_MT_FRAME_RATE ) } {
1061
+ let mut numerator = ( fraction_u64 >> 32 ) as u32 ;
1062
+ let denominator = fraction_u64 as u32 ;
1063
+ if denominator != 1 {
1064
+ numerator = 0 ;
1065
+ }
1066
+ framerates. push ( numerator) ;
1067
+ } ;
1068
+ if let Ok ( fraction_u64) =
1069
+ unsafe { media_type. GetUINT64 ( & MF_MT_FRAME_RATE_RANGE_MIN ) }
1070
+ {
1071
+ let mut numerator = ( fraction_u64 >> 32 ) as u32 ;
1072
+ let denominator = fraction_u64 as u32 ;
1073
+ if denominator != 1 {
1074
+ numerator = 0 ;
1075
+ }
1076
+ framerates. push ( numerator) ;
1077
+ } ;
1078
+ framerates
1079
+ } ;
1080
+
1081
+ for frame_rate in framerate_list {
1082
+ if frame_rate == format. frame_rate ( ) {
1083
+ let result = unsafe {
1084
+ self . source_reader . SetCurrentMediaType (
1085
+ MEDIA_FOUNDATION_FIRST_VIDEO_STREAM ,
1086
+ None ,
1087
+ & media_type,
1088
+ )
1089
+ } ;
1090
+
1091
+ match result {
1092
+ Ok ( _) => {
1093
+ self . device_format = format;
1094
+ self . format_refreshed ( ) ?;
1095
+ return Ok ( ( ) ) ;
1096
+ } ,
1097
+ Err ( why) => {
1098
+ last_error = Some ( NokhwaError :: SetPropertyError {
1099
+ property : "MEDIA_FOUNDATION_FIRST_VIDEO_STREAM" . to_string ( ) ,
1100
+ value : format ! ( "{media_type:?}" ) ,
1101
+ error : why. to_string ( ) ,
1102
+ } ) ;
1103
+ }
1104
+ }
1105
+ }
1106
+ }
1083
1107
}
1084
1108
1085
- if let Err ( why) = unsafe {
1086
- self . source_reader . SetCurrentMediaType (
1087
- MEDIA_FOUNDATION_FIRST_VIDEO_STREAM ,
1088
- None ,
1089
- & media_type,
1090
- )
1091
- } {
1092
- return Err ( NokhwaError :: SetPropertyError {
1093
- property : "MEDIA_FOUNDATION_FIRST_VIDEO_STREAM" . to_string ( ) ,
1094
- value : format ! ( "{media_type:?}" ) ,
1095
- error : why. to_string ( ) ,
1096
- } ) ;
1109
+ if let Some ( err) = last_error {
1110
+ return Err ( err) ;
1097
1111
}
1098
- self . device_format = format;
1099
- self . format_refreshed ( ) ?;
1100
- Ok ( ( ) )
1112
+
1113
+ Err ( NokhwaError :: InitializeError {
1114
+ backend : ApiBackend :: MediaFoundation ,
1115
+ error : "Failed to fulfill requested format" . to_string ( ) ,
1116
+ } )
1101
1117
}
1102
1118
1103
1119
pub fn is_stream_open ( & self ) -> bool {
0 commit comments