Skip to content

Commit 3892c2d

Browse files
committed
Windows 10 Anniversary Update - March 2017 Update 2
2 parents c29f596 + afe2b4a commit 3892c2d

File tree

117 files changed

+4820
-596
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+4820
-596
lines changed

Samples/CameraFrames/cpp/FrameRenderer.cpp

+83-34
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ using namespace Microsoft::WRL;
2222
using namespace Windows::Foundation;
2323
using namespace Windows::Graphics::Imaging;
2424
using namespace Windows::Media::Capture::Frames;
25+
using namespace Windows::Media::MediaProperties;
2526
using namespace Windows::UI::Xaml::Controls;
2627
using namespace Windows::UI::Xaml::Media::Imaging;
2728

@@ -236,6 +237,33 @@ void FrameRenderer::ProcessFrame(Windows::Media::Capture::Frames::MediaFrameRefe
236237
}
237238
}
238239

240+
String^ FrameRenderer::GetSubtypeForFrameReader(MediaFrameSourceKind kind, MediaFrameFormat^ format)
241+
{
242+
// Note that media encoding subtypes may differ in case.
243+
// https://docs.microsoft.com/en-us/uwp/api/Windows.Media.MediaProperties.MediaEncodingSubtypes
244+
245+
String^ subtype = format->Subtype;
246+
switch (kind)
247+
{
248+
// For color sources, we accept anything and request that it be converted to Bgra8.
249+
case MediaFrameSourceKind::Color:
250+
return MediaEncodingSubtypes::Bgra8;
251+
252+
// The only depth format we can render is D16.
253+
case MediaFrameSourceKind::Depth:
254+
return CompareStringOrdinal(subtype->Data(), -1, L"D16", -1, TRUE) == CSTR_EQUAL ? subtype : nullptr;
255+
256+
// The only infrared formats we can render are L8 and L16.
257+
case MediaFrameSourceKind::Infrared:
258+
return (CompareStringOrdinal(subtype->Data(), -1, L"L8", -1, TRUE) == CSTR_EQUAL ||
259+
CompareStringOrdinal(subtype->Data(), -1, L"L16", -1, TRUE) == CSTR_EQUAL) ? subtype : nullptr;
260+
261+
// No other source kinds are supported by this class.
262+
default:
263+
return nullptr;
264+
}
265+
}
266+
239267
SoftwareBitmap^ FrameRenderer::ConvertToDisplayableImage(VideoMediaFrame^ inputFrame)
240268
{
241269
if (inputFrame == nullptr)
@@ -244,45 +272,66 @@ SoftwareBitmap^ FrameRenderer::ConvertToDisplayableImage(VideoMediaFrame^ inputF
244272
}
245273

246274
SoftwareBitmap^ inputBitmap = inputFrame->SoftwareBitmap;
247-
if ((inputBitmap->BitmapPixelFormat == BitmapPixelFormat::Bgra8) &&
248-
(inputBitmap->BitmapAlphaMode == BitmapAlphaMode::Premultiplied))
249-
{
250-
// SoftwareBitmap is already in the correct format for an Image control, so just return a copy.
251-
return SoftwareBitmap::Copy(inputBitmap);
252-
}
253-
else if ((inputBitmap->BitmapPixelFormat == BitmapPixelFormat::Gray16) && (inputFrame->FrameReference->SourceKind == MediaFrameSourceKind::Depth))
254-
{
255-
using namespace std::placeholders;
256-
257-
// Use a special pseudo color to render 16 bits depth frame.
258-
// Since we must scale the output appropriately we use std::bind to
259-
// create a function that takes the depth scale as input but also matches
260-
// the required signature.
261-
double depthScale = inputFrame->DepthMediaFrame->DepthFormat->DepthScaleInMeters;
262-
return TransformBitmap(inputBitmap, std::bind(&PseudoColorForDepth, _1, _2, _3, static_cast<float>(depthScale)));
263-
}
264-
else if (inputBitmap->BitmapPixelFormat == BitmapPixelFormat::Gray16)
265-
{
266-
// Use pseudo color to render 16 bits frames.
267-
return TransformBitmap(inputBitmap, PseudoColorFor16BitInfrared);
268-
}
269-
else if (inputBitmap->BitmapPixelFormat == BitmapPixelFormat::Gray8)
270-
{
271-
// Use pseudo color to render 8 bits frames.
272-
return TransformBitmap(inputBitmap, PseudoColorFor8BitInfrared);
273-
}
274-
else
275+
auto mode = inputBitmap->BitmapAlphaMode;
276+
277+
switch (inputFrame->FrameReference->SourceKind)
275278
{
276-
try
279+
case MediaFrameSourceKind::Color:
280+
// XAML requires Bgra8 with premultiplied alpha.
281+
// We requested Bgra8 from the MediaFrameReader, so all that's
282+
// left is fixing the alpha channel if necessary.
283+
if (inputBitmap->BitmapPixelFormat != BitmapPixelFormat::Bgra8)
284+
{
285+
OutputDebugStringW(L"Color format should have been Bgra8.\r\n");
286+
}
287+
else if (inputBitmap->BitmapAlphaMode == BitmapAlphaMode::Premultiplied)
277288
{
278-
// Convert to Bgra8 Premultiplied SoftwareBitmap, so xaml can display in UI.
289+
// Already in the correct format.
290+
return SoftwareBitmap::Copy(inputBitmap);
291+
}
292+
else
293+
{
294+
// Convert to premultiplied alpha.
279295
return SoftwareBitmap::Convert(inputBitmap, BitmapPixelFormat::Bgra8, BitmapAlphaMode::Premultiplied);
280296
}
281-
catch (InvalidArgumentException^ exception)
297+
return nullptr;
298+
299+
case MediaFrameSourceKind::Depth:
300+
// We requested D16 from the MediaFrameReader, so the frame should
301+
// be in Gray16 format.
302+
303+
if (inputBitmap->BitmapPixelFormat == BitmapPixelFormat::Gray16)
304+
{
305+
using namespace std::placeholders;
306+
307+
// Use a special pseudo color to render 16 bits depth frame.
308+
// Since we must scale the output appropriately we use std::bind to
309+
// create a function that takes the depth scale as input but also matches
310+
// the required signature.
311+
double depthScale = inputFrame->DepthMediaFrame->DepthFormat->DepthScaleInMeters;
312+
return TransformBitmap(inputBitmap, std::bind(&PseudoColorForDepth, _1, _2, _3, static_cast<float>(depthScale)));
313+
}
314+
else
282315
{
283-
// Conversion of software bitmap format is not supported. Drop this frame.
284-
OutputDebugStringW(exception->Message->Data());
285-
OutputDebugStringW(L"\r\n");
316+
OutputDebugStringW(L"Depth format in unexpected format.\r\n");
317+
}
318+
return nullptr;
319+
320+
case MediaFrameSourceKind::Infrared:
321+
// We requested L8 or L16 from the MediaFrameReader, so the frame should
322+
// be in Gray8 or Gray16 format.
323+
switch (inputBitmap->BitmapPixelFormat)
324+
{
325+
case BitmapPixelFormat::Gray8:
326+
// Use pseudo color to render 8 bits frames.
327+
return TransformBitmap(inputBitmap, PseudoColorFor8BitInfrared);
328+
329+
case BitmapPixelFormat::Gray16:
330+
// Use pseudo color to render 16 bits frames.
331+
return TransformBitmap(inputBitmap, PseudoColorFor16BitInfrared);
332+
333+
default:
334+
OutputDebugStringW(L"Infrared format should have been Gray8 or Gray16.\r\n");
286335
return nullptr;
287336
}
288337
}

Samples/CameraFrames/cpp/FrameRenderer.h

+10-1
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,23 @@ namespace SDKTemplate
2929
/// </summary>
3030
void ProcessFrame(Windows::Media::Capture::Frames::MediaFrameReference^ frame);
3131

32+
/// <summary>
33+
/// Determines the subtype to request from the MediaFrameReader that will result in
34+
/// a frame that can be rendered by ConvertToDisplayableImage.
35+
/// </summary>
36+
/// <returns>Subtype string to request, or null if subtype is not renderable.</returns>
37+
static Platform::String^ GetSubtypeForFrameReader(
38+
Windows::Media::Capture::Frames::MediaFrameSourceKind kind,
39+
Windows::Media::Capture::Frames::MediaFrameFormat^ format);
40+
3241
private: // Private static methods.
3342
/// <summary>
3443
/// Converts the input frame to BGRA8 premultiplied alpha format and returns the result.
3544
/// Returns nullptr if the input frame cannot be converted BGRA8 premultiplied alpha.
3645
/// </summary>
3746
static Windows::Graphics::Imaging::SoftwareBitmap^ ConvertToDisplayableImage(
3847
Windows::Media::Capture::Frames::VideoMediaFrame^ inputFrame);
39-
48+
4049
/// <summary>
4150
/// Transforms pixels of inputBitmap to an output bitmap using the supplied pixel transformation method.
4251
/// Returns nullptr if translation fails.

Samples/CameraFrames/cpp/Scenario1_DisplayDepthColorIR.xaml.cpp

+76-89
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "pch.h"
1313
#include "Scenario1_DisplayDepthColorIR.xaml.h"
1414
#include "FrameRenderer.h"
15+
#include <unordered_set>
1516

1617
using namespace SDKTemplate;
1718

@@ -25,16 +26,6 @@ using namespace Windows::Media::Capture;
2526
using namespace Windows::Media::Capture::Frames;
2627
using namespace Windows::UI::Xaml::Media::Imaging;
2728

28-
MediaFrameSourceInfo^ Scenario1_DisplayDepthColorIR::GetFirstSourceInfoOfKind(MediaFrameSourceGroup^ group, MediaFrameSourceKind kind)
29-
{
30-
auto matchingInfo = std::find_if(begin(group->SourceInfos), end(group->SourceInfos),
31-
[kind](MediaFrameSourceInfo^ sourceInfo)
32-
{
33-
return sourceInfo->SourceKind == kind;
34-
});
35-
return (matchingInfo != end(group->SourceInfos)) ? *matchingInfo : nullptr;
36-
}
37-
3829
Scenario1_DisplayDepthColorIR::Scenario1_DisplayDepthColorIR()
3930
{
4031
InitializeComponent();
@@ -73,114 +64,110 @@ task<void> Scenario1_DisplayDepthColorIR::PickNextMediaSourceAsync()
7364

7465
task<void> Scenario1_DisplayDepthColorIR::PickNextMediaSourceWorkerAsync()
7566
{
76-
struct EligibleGroup
77-
{
78-
MediaFrameSourceGroup^ Group;
79-
std::array<MediaFrameSourceInfo^, 3> SourceInfos;
80-
};
81-
8267
return CleanupMediaCaptureAsync()
8368
.then([this]()
8469
{
8570
return create_task(MediaFrameSourceGroup::FindAllAsync());
86-
}).then([this](IVectorView<MediaFrameSourceGroup^>^ allGroups)
71+
}, task_continuation_context::get_current_winrt_context())
72+
.then([this](IVectorView<MediaFrameSourceGroup^>^ allGroups)
8773
{
88-
// Identify the color, depth, and infrared sources of each group,
89-
// and keep only the groups that have at least one recognized source.
90-
std::vector<EligibleGroup> eligibleGroups;
91-
for (auto group : allGroups)
92-
{
93-
EligibleGroup eligibleGroup;
94-
eligibleGroup.Group = group;
95-
// For each source kind, find the source which offers that kind of media frame,
96-
// or null if there is no such source.
97-
eligibleGroup.SourceInfos[0] = GetFirstSourceInfoOfKind(group, MediaFrameSourceKind::Color);
98-
eligibleGroup.SourceInfos[1] = GetFirstSourceInfoOfKind(group, MediaFrameSourceKind::Depth);
99-
eligibleGroup.SourceInfos[2] = GetFirstSourceInfoOfKind(group, MediaFrameSourceKind::Infrared);
100-
// If any source was found of any kind we support, keep this group.
101-
if (std::any_of(eligibleGroup.SourceInfos.begin(), eligibleGroup.SourceInfos.end(),
102-
[](MediaFrameSourceInfo^ sourceInfo) { return sourceInfo != nullptr; }))
103-
{
104-
eligibleGroups.push_back(eligibleGroup);
105-
}
106-
}
107-
108-
if (eligibleGroups.size() == 0)
74+
if (allGroups->Size == 0)
10975
{
110-
m_logger->Log("No source group with color, depth or infrared found.");
76+
m_logger->Log("No source groups found.");
11177
return task_from_result();
11278
}
11379

11480
// Pick next group in the array after each time the Next button is clicked.
115-
m_selectedSourceGroupIndex = (m_selectedSourceGroupIndex + 1) % eligibleGroups.size();
81+
m_selectedSourceGroupIndex = (m_selectedSourceGroupIndex + 1) % allGroups->Size;
82+
MediaFrameSourceGroup^ selectedGroup = allGroups->GetAt(m_selectedSourceGroupIndex);
11683

117-
m_logger->Log("Found " + eligibleGroups.size().ToString() + " groups and " +
84+
m_logger->Log("Found " + allGroups->Size.ToString() + " groups and " +
11885
"selecting index [" + m_selectedSourceGroupIndex.ToString() + "] : " +
119-
eligibleGroups[m_selectedSourceGroupIndex].Group->DisplayName);
120-
EligibleGroup selected = eligibleGroups[m_selectedSourceGroupIndex];
86+
selectedGroup->DisplayName);
12187

12288
// Initialize MediaCapture with selected group.
123-
return TryInitializeMediaCaptureAsync(selected.Group)
124-
.then([this, selected](bool initialized)
89+
return TryInitializeMediaCaptureAsync(selectedGroup)
90+
.then([this, selectedGroup](bool initialized)
12591
{
12692
if (!initialized)
12793
{
12894
return CleanupMediaCaptureAsync();
12995
}
13096

13197
// Set up frame readers, register event handlers and start streaming.
98+
auto startedKinds = std::make_shared<std::unordered_set<MediaFrameSourceKind>>();
13299
task<void> createReadersTask = task_from_result();
133-
for (size_t i = 0; i < selected.SourceInfos.size(); i++)
100+
for (IKeyValuePair<String^, MediaFrameSource^>^ kvp : m_mediaCapture->FrameSources)
134101
{
135-
MediaFrameSourceInfo^ info = selected.SourceInfos[i];
136-
if (info != nullptr)
102+
MediaFrameSource^ source = kvp->Value;
103+
createReadersTask = createReadersTask.then([this, startedKinds, source]()
137104
{
138-
createReadersTask = createReadersTask && CreateReaderAsync(selected.Group, info);
139-
}
140-
else
105+
MediaFrameSourceKind kind = source->Info->SourceKind;
106+
107+
// Ignore this source if we already have a source of this kind.
108+
if (startedKinds->find(kind) != startedKinds->end())
109+
{
110+
return task_from_result();
111+
}
112+
113+
// Look for a format which the FrameRenderer can render.
114+
String^ requestedSubtype = nullptr;
115+
auto found = std::find_if(begin(source->SupportedFormats), end(source->SupportedFormats),
116+
[&](MediaFrameFormat^ format)
117+
{
118+
requestedSubtype = FrameRenderer::GetSubtypeForFrameReader(kind, format);
119+
return requestedSubtype != nullptr;
120+
});
121+
if (requestedSubtype == nullptr)
122+
{
123+
// No acceptable format was found. Ignore this source.
124+
return task_from_result();
125+
}
126+
127+
// Tell the source to use the format we can render.
128+
return create_task(source->SetFormatAsync(*found))
129+
.then([this, source, requestedSubtype]()
130+
{
131+
return create_task(m_mediaCapture->CreateFrameReaderAsync(source, requestedSubtype));
132+
}, task_continuation_context::get_current_winrt_context())
133+
.then([this, kind](MediaFrameReader^ frameReader)
134+
{
135+
EventRegistrationToken token = frameReader->FrameArrived +=
136+
ref new TypedEventHandler<MediaFrameReader^, MediaFrameArrivedEventArgs^>(this, &Scenario1_DisplayDepthColorIR::FrameReader_FrameArrived);
137+
138+
// Keep track of created reader and event handler so it can be stopped later.
139+
m_readers.push_back(std::make_pair(frameReader, token));
140+
141+
m_logger->Log(kind.ToString() + " reader created");
142+
143+
return create_task(frameReader->StartAsync());
144+
}, task_continuation_context::get_current_winrt_context())
145+
.then([this, kind, startedKinds](MediaFrameReaderStartStatus status)
146+
{
147+
if (status == MediaFrameReaderStartStatus::Success)
148+
{
149+
m_logger->Log("Started " + kind.ToString() + " reader.");
150+
startedKinds->insert(kind);
151+
}
152+
else
153+
{
154+
m_logger->Log("Unable to start " + kind.ToString() + " reader. Error: " + status.ToString());
155+
}
156+
}, task_continuation_context::get_current_winrt_context());
157+
}, task_continuation_context::get_current_winrt_context());
158+
}
159+
// Run the loop and see if any sources were used.
160+
return createReadersTask.then([this, startedKinds, selectedGroup]()
161+
{
162+
if (startedKinds->size() == 0)
141163
{
142-
String^ frameKind = (i == 0 ? "Color" : i == 1 ? "Depth" : "Infrared");
143-
m_logger->Log("No " + frameKind + " source in group " + selected.Group->DisplayName);
164+
m_logger->Log("No eligible sources in " + selectedGroup->DisplayName + ".");
144165
}
145-
146-
}
147-
return createReadersTask;
148-
});
166+
}, task_continuation_context::get_current_winrt_context());
167+
}, task_continuation_context::get_current_winrt_context());
149168
}, task_continuation_context::get_current_winrt_context());
150169
}
151170

152-
task<void> Scenario1_DisplayDepthColorIR::CreateReaderAsync(MediaFrameSourceGroup^ group, MediaFrameSourceInfo^ info)
153-
{
154-
// Access the initialized frame source by looking up the the Id of the source.
155-
// Verify that the Id is present, because it may have left the group while were were
156-
// busy deciding which group to use.
157-
if (!m_mediaCapture->FrameSources->HasKey(info->Id))
158-
{
159-
m_logger->Log("Unable to start " + info->SourceKind.ToString() + " reader: Frame source not found");
160-
return task_from_result();
161-
}
162-
163-
return create_task(m_mediaCapture->CreateFrameReaderAsync(m_mediaCapture->FrameSources->Lookup(info->Id)))
164-
.then([this, info](MediaFrameReader^ frameReader)
165-
{
166-
EventRegistrationToken token = frameReader->FrameArrived +=
167-
ref new TypedEventHandler<MediaFrameReader^, MediaFrameArrivedEventArgs^>(this, &Scenario1_DisplayDepthColorIR::FrameReader_FrameArrived);
168-
169-
m_logger->Log(info->SourceKind.ToString() + " reader created");
170-
171-
// Keep track of created reader and event handler so it can be stopped later.
172-
m_readers.push_back(std::make_pair(frameReader, token));
173-
174-
return create_task(frameReader->StartAsync());
175-
}).then([this, info](MediaFrameReaderStartStatus status)
176-
{
177-
if (status != MediaFrameReaderStartStatus::Success)
178-
{
179-
m_logger->Log("Unable to start " + info->SourceKind.ToString() + " reader. Error: " + status.ToString());
180-
}
181-
});
182-
}
183-
184171
task<bool> Scenario1_DisplayDepthColorIR::TryInitializeMediaCaptureAsync(MediaFrameSourceGroup^ group)
185172
{
186173
if (m_mediaCapture != nullptr)

0 commit comments

Comments
 (0)