R
Richard.Haggard
Guest
I have a WPF C# framework application which calls a .NET Standard library assembly in which a MediaCapture class is being instantiated. The code that does the initialization is the same as is in many of Microsoft's samples. The problem is, the InitializeAsync is immediately returning and the code runs on to do things with the MediaCapture object before the init has actually completed so, of course, there are problems.
The problem is not the code itself but how I want to use it. MediaCapture.InitializeAsync() is, as its name implies, an async. Due to the manner in which the camera code is going to be used it is possible that the MediaCapture object will need to be destroyed and recreated multiple times. Rather than duplicate that code all over the place it would be better to have a single method that disposes of the MediaCapture object, recreates and initializes it as required. How can I structure things so that the kind of problem demonstrated in the following code does not happen, ie., attempt to make use of the MediaCapture object before the initialization has completed?
In this very simple example, the MediaCapture object is wrapped in a class property. The property is instantiated in the parent class's constructor. The constructor goes on to collect information about the video system. As previously stated, the information collection can execute before the InitializeAsync() has completed and then bad things happen.
private MediaCapture MediaCaptureMgr { get { return _MediaCaptureMgr; } set { _MediaCaptureMgr = value; } }
private MediaCapture _MediaCaptureMgr = null;
public ObservableCollection<string> VideoResolutions
{
get { return _VideoResolutions; }
private set { _VideoResolutions = value; }
}
private ObservableCollection<string> _VideoResolutions = new ObservableCollection<string>();
// Class constructor.
// InitAsync() returns immediately, allowing a call to
// GetStreamProperties() to happen too soon and
// it will try to access things that are not in a fit state to be accessed.
public CameraModel()
{
InitAsync();
foreach (string s in GetStreamProperties(MediaStreamType.VideoPreview))
VideoResolutions.Add(s);
}
// Because of the await, control returns to the caller
// while the InitializeAsync itself executes.
private async void InitAsync()
{
if (MediaCaptureMgr == null)
{
MediaCaptureMgr = new MediaCapture();
await MediaCaptureMgr.InitializeAsync();
}
}
// Method in which an exception may be thrown because the MediaCapture object has not completed its init.
private List<string> GetStreamProperties(MediaStreamType streamType)
{
List<string> properties = new List<string>();
// Exception here because MediaCaptureMgr may not be ready to be used yet.
// Query all properties of the specified stream type
IEnumerable<StreamPropertiesHelper> allStreamProperties =
MediaCaptureMgr.VideoDeviceController.GetAvailableMediaStreamProperties(streamType).Select(x => new StreamPropertiesHelper(x));
allStreamProperties = allStreamProperties.OrderByDescending(x => x.Height * x.Width).ThenByDescending(x => x.FrameRate);
foreach (var property in allStreamProperties)
properties.Add($"AspectRation={property.AspectRatio}, {property.Width}x{property.Height}" );
return properties;
}
Richard Lewis Haggard
Continue reading...
The problem is not the code itself but how I want to use it. MediaCapture.InitializeAsync() is, as its name implies, an async. Due to the manner in which the camera code is going to be used it is possible that the MediaCapture object will need to be destroyed and recreated multiple times. Rather than duplicate that code all over the place it would be better to have a single method that disposes of the MediaCapture object, recreates and initializes it as required. How can I structure things so that the kind of problem demonstrated in the following code does not happen, ie., attempt to make use of the MediaCapture object before the initialization has completed?
In this very simple example, the MediaCapture object is wrapped in a class property. The property is instantiated in the parent class's constructor. The constructor goes on to collect information about the video system. As previously stated, the information collection can execute before the InitializeAsync() has completed and then bad things happen.
private MediaCapture MediaCaptureMgr { get { return _MediaCaptureMgr; } set { _MediaCaptureMgr = value; } }
private MediaCapture _MediaCaptureMgr = null;
public ObservableCollection<string> VideoResolutions
{
get { return _VideoResolutions; }
private set { _VideoResolutions = value; }
}
private ObservableCollection<string> _VideoResolutions = new ObservableCollection<string>();
// Class constructor.
// InitAsync() returns immediately, allowing a call to
// GetStreamProperties() to happen too soon and
// it will try to access things that are not in a fit state to be accessed.
public CameraModel()
{
InitAsync();
foreach (string s in GetStreamProperties(MediaStreamType.VideoPreview))
VideoResolutions.Add(s);
}
// Because of the await, control returns to the caller
// while the InitializeAsync itself executes.
private async void InitAsync()
{
if (MediaCaptureMgr == null)
{
MediaCaptureMgr = new MediaCapture();
await MediaCaptureMgr.InitializeAsync();
}
}
// Method in which an exception may be thrown because the MediaCapture object has not completed its init.
private List<string> GetStreamProperties(MediaStreamType streamType)
{
List<string> properties = new List<string>();
// Exception here because MediaCaptureMgr may not be ready to be used yet.
// Query all properties of the specified stream type
IEnumerable<StreamPropertiesHelper> allStreamProperties =
MediaCaptureMgr.VideoDeviceController.GetAvailableMediaStreamProperties(streamType).Select(x => new StreamPropertiesHelper(x));
allStreamProperties = allStreamProperties.OrderByDescending(x => x.Height * x.Width).ThenByDescending(x => x.FrameRate);
foreach (var property in allStreamProperties)
properties.Add($"AspectRation={property.AspectRatio}, {property.Width}x{property.Height}" );
return properties;
}
Richard Lewis Haggard
Continue reading...