-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add Camera settings #42
Changes from 7 commits
109cf15
272bb85
510850b
e3d8f0b
49bc98c
84794d1
a0ee273
ffd3341
effa8cd
4bd01b3
85c8830
0c4fa11
2fdc18b
323758b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
using System.Collections.Generic; | ||
|
||
namespace FlashCap | ||
{ | ||
public enum VideoProcessingAmplifierProperty | ||
{ | ||
Brightness, | ||
Contrast, | ||
Hue, | ||
Saturation, | ||
Sharpness, | ||
Gamma, | ||
ColorEnable, | ||
WhiteBalance, | ||
BacklightCompensation, | ||
Gain | ||
} | ||
|
||
public sealed class CaptureDeviceProperties : Dictionary<VideoProcessingAmplifierProperty, CaptureDeviceProperty> | ||
{ | ||
} | ||
|
||
public abstract class CaptureDeviceProperty | ||
{ | ||
public VideoProcessingAmplifierProperty Property { get; private set; } | ||
public int Min { get; private set; } | ||
public int Max { get; private set; } | ||
public int Step { get; private set; } | ||
|
||
protected CaptureDeviceProperty(VideoProcessingAmplifierProperty property, int min, int max, int step) | ||
{ | ||
Property = property; | ||
Min = min; | ||
Max = max; | ||
Step = step; | ||
} | ||
|
||
internal bool IsPropertyValueValid(object? obj) | ||
{ | ||
var value = obj as int?; | ||
|
||
return value != null && value <= Max && value >= Min && value % Step == 0; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -73,6 +73,7 @@ [PreserveSig] public int BufferCB( | |
private bool transcodeIfYUV; | ||
private FrameProcessor frameProcessor; | ||
private NativeMethods_DirectShow.IGraphBuilder? graphBuilder; | ||
private NativeMethods_DirectShow.ICaptureGraphBuilder2? captureGraphBuilder; | ||
private SampleGrabberSink? sampleGrabberSink; | ||
private IntPtr pBih; | ||
|
||
|
@@ -174,7 +175,7 @@ protected override Task OnInitializeAsync( | |
|
||
/////////////////////////////// | ||
|
||
var captureGraphBuilder = NativeMethods_DirectShow.CreateCaptureGraphBuilder(); | ||
captureGraphBuilder = NativeMethods_DirectShow.CreateCaptureGraphBuilder(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I needed a way to access the captureGraph, is there a better way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ldlac No problem. |
||
if (captureGraphBuilder.SetFiltergraph(this.graphBuilder) < 0) | ||
{ | ||
throw new ArgumentException( | ||
|
@@ -312,6 +313,106 @@ protected override Task OnStopAsync(CancellationToken ct) | |
} | ||
} | ||
|
||
public override int GetPropertyValue(VideoProcessingAmplifierProperty property) | ||
{ | ||
if (Properties.TryGetValue(property, out CaptureDeviceProperty _) | ||
&& graphBuilder != null | ||
&& captureGraphBuilder != null) | ||
{ | ||
graphBuilder.FindFilterByName("Capture source", out NativeMethods_DirectShow.IBaseFilter? captureSourceFilter); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in my application (wpf), it's working fine, but in the the sample I've created based on OneShot, I'm getting this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @kekyo I was currently stuck here, any idea why I'm experiencing this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I will check it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ldlac In this source file, there are 3 places that use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @ldlac I debugged the code and found a problem with the added property page display and the property getter/setter accesses ignoring the COM apartments, so I fixed it. 472f25d (I think the FlashCap has been modified to initialize another thread as a single-threaded apartment and access DS objects only on it, as past implementation experience has shown that accessing the calling COM apartment as it is causes many frame drops The following is a list of the DS objects that can be accessed beyond the apartment. When accessing the DS object beyond the apartment, the standard COM way is to marshal the interface, but it is tedious to do this in .NET, so we use In the environment at hand, this modification allows the capture filter property page to be displayed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
if (captureSourceFilter != null) | ||
{ | ||
captureGraphBuilder.FindInterface(Guid.Empty, Guid.Empty, captureSourceFilter, NativeMethods_DirectShow.IAMVideoProcAmpHelper.GUID, out object? videoProcAmpObject); | ||
if (videoProcAmpObject != null) | ||
{ | ||
var videoProcAmp = (NativeMethods_DirectShow.IAMVideoProcAmp)videoProcAmpObject; | ||
videoProcAmp.Get(DirectShowProperty.FromVideoProcessingAmplifierProperty(property), out int value, out NativeMethods_DirectShow.VideoProcAmpFlags _); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really know the use of this one yet, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even in the environment at hand, I was able to obtain a range of values that we believe to be brightness. Nice work! |
||
Marshal.ReleaseComObject(videoProcAmpObject); | ||
return value; | ||
} | ||
Marshal.ReleaseComObject(captureGraphBuilder); | ||
} | ||
} | ||
|
||
throw new ArgumentException( | ||
$"FlashCap: Property is not supported by device: Property={property}"); | ||
} | ||
|
||
public override void SetPropertyValue(VideoProcessingAmplifierProperty property, object? obj) | ||
{ | ||
if (Properties.TryGetValue(property, out CaptureDeviceProperty? captureDeviceProperty) | ||
&& obj != null | ||
&& captureDeviceProperty != null | ||
&& captureDeviceProperty.IsPropertyValueValid(obj) | ||
&& graphBuilder != null | ||
&& captureGraphBuilder != null) | ||
{ | ||
graphBuilder.FindFilterByName("Capture source", out NativeMethods_DirectShow.IBaseFilter? captureSourceFilter); | ||
if (captureSourceFilter != null) | ||
{ | ||
captureGraphBuilder.FindInterface(Guid.Empty, Guid.Empty, captureSourceFilter, NativeMethods_DirectShow.IAMVideoProcAmpHelper.GUID, out object? videoProcAmpObject); | ||
if (videoProcAmpObject != null) | ||
{ | ||
var videoProcAmp = (NativeMethods_DirectShow.IAMVideoProcAmp)videoProcAmpObject; | ||
videoProcAmp.Get(DirectShowProperty.FromVideoProcessingAmplifierProperty(property), out int _, out NativeMethods_DirectShow.VideoProcAmpFlags videoProcAmpFlags); | ||
videoProcAmp.Set(DirectShowProperty.FromVideoProcessingAmplifierProperty(property), (int)obj, videoProcAmpFlags); | ||
Marshal.ReleaseComObject(videoProcAmpObject); | ||
} | ||
Marshal.ReleaseComObject(captureGraphBuilder); | ||
} | ||
} | ||
|
||
throw new ArgumentException( | ||
$"FlashCap: Property is not supported by device: Property={property}"); | ||
} | ||
|
||
public override void DisplayPropertyPage_CaptureFilter(IntPtr hwndOwner) | ||
{ | ||
if (graphBuilder != null | ||
&& graphBuilder.FindFilterByName("Capture source", out NativeMethods_DirectShow.IBaseFilter? captureSourceFilter) >= 0) | ||
{ | ||
DisplayPropertyPage_Filter(captureSourceFilter, hwndOwner); | ||
} | ||
} | ||
|
||
private void DisplayPropertyPage_Filter(object? obj, IntPtr hwndOwner) | ||
{ | ||
if (obj == null) | ||
return; | ||
|
||
if (obj is not NativeMethods_DirectShow.ISpecifyPropertyPages pProp) | ||
return; | ||
|
||
if (obj is not NativeMethods_DirectShow.IBaseFilter filter) | ||
return; | ||
|
||
if (filter.QueryFilterInfo(out NativeMethods_DirectShow.FILTER_INFO filterInfo) < 0) | ||
{ | ||
throw new Exception( | ||
$"FlashCap: Couldn't query filter info"); | ||
} | ||
|
||
if (pProp.GetPages(out NativeMethods_DirectShow.DsCAUUID caGUID) < 0) | ||
{ | ||
throw new Exception( | ||
$"FlashCap: Couldn't get pages"); | ||
} | ||
|
||
object oDevice = obj; | ||
if (NativeMethods_DirectShow.OleCreatePropertyFrame(hwndOwner, 0, 0, filterInfo.chName, 1, ref oDevice, caGUID.cElems, caGUID.pElems, 0, 0, IntPtr.Zero) < 0) | ||
{ | ||
throw new Exception( | ||
$"FlashCap: Couldn't create property frame"); | ||
} | ||
|
||
Marshal.FreeCoTaskMem(caGUID.pElems); | ||
Marshal.ReleaseComObject(pProp); | ||
if (filterInfo.graph != null) | ||
{ | ||
Marshal.ReleaseComObject(filterInfo.graph); | ||
} | ||
} | ||
|
||
#if NET45_OR_GREATER || NETSTANDARD || NETCOREAPP | ||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||
#endif | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
using FlashCap.Internal; | ||
|
||
namespace FlashCap.Devices | ||
{ | ||
public sealed class DirectShowProperty : CaptureDeviceProperty | ||
{ | ||
public DirectShowProperty(VideoProcessingAmplifierProperty property, int min, int max, int step) : base(property, min, max, step) { } | ||
|
||
internal static NativeMethods_DirectShow.VideoProcAmpProperty FromVideoProcessingAmplifierProperty(VideoProcessingAmplifierProperty property) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. each device property should be able to map from There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps there is a more desirable interface, but this is fine for now 👍 |
||
{ | ||
return (NativeMethods_DirectShow.VideoProcAmpProperty)(int)property; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eventually
SetPropertyValue
if more properties are supported, it should receive a widerType/Enum
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I agree. Perhaps the key that is considered standard is Enum, and we need to consider a separate specifiable interface if the device provides an extended key, but we have not yet figured out how far to abstract it. So we can reserve this issue here.