Windows 10 Version 1703 - May 2017 Update
This commit is contained in:
Коммит
bb447b0648
11
README.md
11
README.md
|
@ -14,9 +14,9 @@ This repo contains the samples that demonstrate the API usage patterns for the U
|
|||
|
||||
## Universal Windows Platform development
|
||||
|
||||
These samples require Visual Studio 2015 and the Windows Software Development Kit (SDK) for Windows 10 to build, test, and deploy your Universal Windows Platform apps.
|
||||
These samples require Visual Studio 2017 and the Windows Software Development Kit (SDK) for Windows 10 to build, test, and deploy your Universal Windows Platform apps.
|
||||
|
||||
[Get a free copy of Visual Studio 2015 Community Edition with support for building Universal Windows Platform apps](http://go.microsoft.com/fwlink/p/?LinkID=280676)
|
||||
[Get a free copy of Visual Studio 2017 Community Edition with support for building Universal Windows Platform apps](http://go.microsoft.com/fwlink/p/?LinkID=280676)
|
||||
|
||||
Additionally, to stay on top of the latest updates to Windows and the development tools, become a Windows Insider by joining the Windows Insider Program.
|
||||
|
||||
|
@ -24,14 +24,14 @@ Additionally, to stay on top of the latest updates to Windows and the developmen
|
|||
|
||||
## Using the samples
|
||||
|
||||
The easiest way to use these samples without using Git is to download the zip file containing the current version (using the following link or by clicking the "Download ZIP" button on the repo page). You can then unzip the entire archive and use the samples in Visual Studio 2015.
|
||||
The easiest way to use these samples without using Git is to download the zip file containing the current version (using the following link or by clicking the "Download ZIP" button on the repo page). You can then unzip the entire archive and use the samples in Visual Studio 2017.
|
||||
|
||||
[Download the samples ZIP](../../archive/master.zip)
|
||||
|
||||
**Notes:**
|
||||
* Before you unzip the archive, right-click it, select **Properties**, and then select **Unblock**.
|
||||
* Be sure to unzip the entire archive, and not just individual samples. The samples all depend on the SharedContent folder in the archive.
|
||||
* In Visual Studio 2015, the platform target defaults to ARM, so be sure to change that to x64 or x86 if you want to test on a non-ARM device.
|
||||
* In Visual Studio 2017, the platform target defaults to ARM, so be sure to change that to x64 or x86 if you want to test on a non-ARM device.
|
||||
|
||||
The samples use Linked files in Visual Studio to reduce duplication of common files, including sample template files and image assets. These common files are stored in the SharedContent folder at the root of the repository, and are referred to in the project files using links.
|
||||
|
||||
|
@ -412,8 +412,11 @@ For additional Windows samples, see [Windows on GitHub](http://microsoft.github.
|
|||
<td><a href="Samples/D2DGradientMesh">Direct2D gradient mesh</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="Samples/D2DSvgImage">Direct2D SVG image rendering</a></td>
|
||||
<td><a href="Samples/EfficientAnimations">Efficient animations (HTML)</a></td>
|
||||
<td><a href="Samples/XamlTransform3DAnimations">Transform3D animations</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="Samples/XamlTransform3DParallax">Transform3D parallax</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
@ -35,8 +35,8 @@ Build the sample
|
|||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -31,7 +31,7 @@ In addition to Visual Studio and the Windows SDK, you need the following:
|
|||
* The Unity plugin for Visual Studio.
|
||||
This can be installed as part of installing Unity,
|
||||
or you can
|
||||
[download it](https://visualstudiogallery.msdn.microsoft.com/8d26236e-4a64-4d64-8486-7df95156aba9 "Visual Studio 2015 Tools for Unity")
|
||||
[download it](https://visualstudiogallery.msdn.microsoft.com/8d26236e-4a64-4d64-8486-7df95156aba9 "Visual Studio 2017 Tools for Unity")
|
||||
manually.
|
||||
|
||||
* The 3D Builder app.
|
||||
|
|
|
@ -79,8 +79,8 @@ When you choose the **Enable** button for the **Data Events** option, the app be
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -49,8 +49,8 @@ Registers a background task for activity changes. The background task runs whene
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -43,37 +43,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -86,11 +86,10 @@ by imposing a lower DesiredMaxBitrate in order to restrict content on unsecured
|
|||
|
||||
Not shown in this scenario, but related in concept:
|
||||
|
||||
* Passing a Stream to a manifest in the constructor of AdaptiveMediaSource,
|
||||
to replace the first web request for a Uri.
|
||||
* Passing a Stream to a manifest in the constructor of AdaptiveMediaSource, to replace the first web request for a Uri.
|
||||
* Getting a copy of the downloaded bytes after they have been consumed by the platform in DownloadCompleted.
|
||||
|
||||
*Tune the AdaptiveMediaSource download and bitrate switching heuristics**
|
||||
**Tune the AdaptiveMediaSource download and bitrate switching heuristics**
|
||||
|
||||
This scenario shows ways in which the app can tune the adaptive media source.
|
||||
|
||||
|
@ -104,10 +103,14 @@ only after extensive testing under a range of network conditions.
|
|||
|
||||
This scenario shows ways in which the app can consume or create timed metadata.
|
||||
|
||||
The AdaptiveMediaSource publishes ID3 tags within TS content
|
||||
and any M3U8 comment tags it finds in manifests
|
||||
as TimedMetadataTracks.
|
||||
This sample shows how to register to consume this data in the app.
|
||||
The AdaptiveMediaSource creates TimedMetadataTracks, and fires Cues for
|
||||
|
||||
* ID3 tags within TS content
|
||||
* emsg boxes within fragmented MP4 content
|
||||
* Comment tags found in HLS manifests
|
||||
|
||||
This sample shows how to register to consume this data in the app, and demonstrates
|
||||
how SCTE-35 can be parsed from emsg boxes and used to schedule ads.
|
||||
|
||||
The captioning system will also publish TimedMetadataTracks for:
|
||||
WebVTT segments within an HLS presentation,
|
||||
|
@ -115,13 +118,12 @@ additional files (TTML, SRT or WebVTT) added to the source,
|
|||
or 608 captions within SEI NALUs of H.264.
|
||||
Although it is not demonstrated in this sample,
|
||||
the app can opt to render the captions itself
|
||||
by following a process similar to one used in this scenario.
|
||||
by following a process similar to one used for data cues in this scenario.
|
||||
|
||||
The app can also create a Custom TimedMetadataTrack and add it to a MediaSource.
|
||||
This provides a uniform event-based mechanism to consume timed-synchronized information.
|
||||
Here we demonstrate playback progress reporting using a custom class TrackingEventCue.
|
||||
We re-use this concept in the next sample
|
||||
to provide reporting on five ads inserted into a main MediaPlaybackItem.
|
||||
We re-use this concept in the next sample to provide reporting on ads inserted into a main MediaPlaybackItem.
|
||||
|
||||
**Create advertisements within an AdaptiveMediaSource MediaPlaybackItem**
|
||||
|
||||
|
@ -135,11 +137,37 @@ For each of these ads, and the main content,
|
|||
we re-use the Custom TimedMetadataTracks from the Metadata sample
|
||||
to raise playback progress events.
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Live Seekable Range**
|
||||
|
||||
This scenario demonstrates seeking within the MediaTimeRange exposed by
|
||||
`MediaPlayer.MediaPlaybackSession.GetSeekableRanges()`
|
||||
This is often called a DVR Window and is used in over the top television (OTT) broadcasts
|
||||
and live event streaming.
|
||||
|
||||
The sample also demonstrate how to further limit the size of the DVR window
|
||||
using the AdaptiveMediaSource properties:
|
||||
|
||||
* MinLiveOffset: The leading edge of the DRV window, as imposed by the content or platform.
|
||||
|
||||
* DesiredLiveOffset: The application-controlled leading-edge of the DRV window.
|
||||
It allows the app to provide additional back-off from the leading edge of the Content
|
||||
to manage Content Distribution Network conditions.
|
||||
|
||||
* DesiredSeekableWindowSize: The application-controlled DVR window depth.
|
||||
This allows the app to limit how far back into the DVR window the user can seek.
|
||||
|
||||
* MaxSeekableWindowSize: The DRV window depth, as imposed by the content.
|
||||
|
||||
The sample demonstrates the use of AdaptiveMediaSourceCorrelatedTimes,
|
||||
an object which provides the offsets between the platform's media Position,
|
||||
the original PresentationTimeStamp within the media segments, and
|
||||
the content encoding time (EXT-X-PROGRAM-DATE-TIME in HLS and its equivalent in DASH).
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](https://dev.windows.com)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -169,9 +197,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
|
||||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio?2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
@ -185,3 +212,4 @@ The next steps depend on whether you just want to deploy the sample or you want
|
|||
### Deploying and running the sample
|
||||
|
||||
- To debug the sample and then run it, press F5 or select Debug > Start Debugging. To run the sample without debugging, press Ctrl+F5 or selectDebug > Start Without Debugging.
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|ARM'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\ARM\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
|
@ -31,9 +30,8 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|ARM'">
|
||||
<OutputPath>bin\ARM\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>ARM</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
|
@ -44,8 +42,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
|
@ -54,9 +51,8 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
|
@ -67,8 +63,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DefineConstants>DEBUG;TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
|
@ -77,9 +72,8 @@
|
|||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UWP</DefineConstants>
|
||||
<DefineConstants>TRACE;NETFX_CORE;WINDOWS_UAP</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<NoWarn>;2008</NoWarn>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
|
@ -102,13 +96,50 @@
|
|||
<Compile Include="..\..\..\SharedContent\cs\AssemblyInfo.cs">
|
||||
<Link>Properties\AssemblyInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\LogView.xaml.cs">
|
||||
<Link>Shared\Logging\LogView.xaml.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\AdaptiveMediaSourceHttpFilterLogger.cs">
|
||||
<Link>Shared\Logging\AdaptiveMediaSourceHttpFilterLogger.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\AdaptiveMediaSourceLogger.cs">
|
||||
<Link>Shared\Logging\AdaptiveMediaSourceLogger.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\MediaPlaybackItemLogger.cs">
|
||||
<Link>Shared\Logging\MediaPlaybackItemLogger.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\MediaPlaybackListLogger.cs">
|
||||
<Link>Shared\Logging\MediaPlaybackListLogger.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\MediaPlayerLogger.cs">
|
||||
<Link>Shared\Logging\MediaPlayerLogger.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\MediaSourceLogger.cs">
|
||||
<Link>Shared\Logging\MediaSourceLogger.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\Extensions\AdaptiveMediaSourceStringExtensions.cs">
|
||||
<Link>Shared\Logging\Extensions\AdaptiveMediaSourceStringExtensions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\Extensions\HttpProgressStringExtensions.cs">
|
||||
<Link>Shared\Logging\Extensions\HttpProgressStringExtensions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\Extensions\JsonFormatter.cs">
|
||||
<Link>Shared\Logging\Extensions\JsonFormatter.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\Extensions\MediaFoundationGuidStringExtensions.cs">
|
||||
<Link>Shared\Logging\Extensions\MediaFoundationGuidStringExtensions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\Extensions\MediaPlaybackItemStringExtensions.cs">
|
||||
<Link>Shared\Logging\Extensions\MediaPlaybackItemStringExtensions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\..\..\SharedContent\cs\Logging\Extensions\MediaPlaybackListStringExtensions.cs">
|
||||
<Link>Shared\Logging\Extensions\MediaPlaybackListStringExtensions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Helpers\CommonLicenseRequest.cs" />
|
||||
<Compile Include="Helpers\MediaFoundationGuidStringExtensions.cs" />
|
||||
<Compile Include="Helpers\MediaPlaybackItemStringExtensions.cs" />
|
||||
<Compile Include="Helpers\MediaPlayerExtensions.cs" />
|
||||
<Compile Include="Helpers\PlayReadyHelper.cs" />
|
||||
<Compile Include="Logger.xaml.cs">
|
||||
<DependentUpon>Logger.xaml</DependentUpon>
|
||||
<Compile Include="Controls\ContentSelector.xaml.cs">
|
||||
<DependentUpon>ContentSelector.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Models\AdaptiveContentModel.cs" />
|
||||
<Compile Include="SampleConfiguration.cs" />
|
||||
|
@ -130,6 +161,9 @@
|
|||
<Compile Include="Scenario6_AdInsertion.xaml.cs">
|
||||
<DependentUpon>Scenario6_AdInsertion.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Scenario7_LiveSeekableRange.xaml.cs">
|
||||
<DependentUpon>Scenario7_LiveSeekableRange.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Shared\TrackingEventCue.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -148,7 +182,12 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Logger.xaml">
|
||||
<Page Include="..\..\..\SharedContent\cs\Logging\LogView.xaml">
|
||||
<Link>Shared\Logging\LogView.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Controls\ContentSelector.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
|
@ -176,6 +215,10 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Scenario7_LiveSeekableRange.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="..\..\..\SharedContent\xaml\Styles.xaml">
|
||||
<Link>Styles\Styles.xaml</Link>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<UserControl
|
||||
x:Class="SDKTemplate.Controls.ContentSelector"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400">
|
||||
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadId" Content="Load Id:" Click="LoadId_Click" Margin="5,0"/>
|
||||
<ComboBox x:Name="SelectedContent" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel x:Name="LoadUriPanel" Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadUri" Content="Load Uri:" Click="LoadUri_Click" Margin="5,0" />
|
||||
<TextBox x:Name="UriBox" InputScope="Url" HorizontalAlignment="Stretch" Margin="5,0" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="SetSource" IsEnabled="False" Content="Set Source" Click="SetSource_Click" Margin="5,0"/>
|
||||
<CheckBox x:Name="AutoPlay" Checked="AutoPlay_Checked" Unchecked="AutoPlay_Checked" Content="AutoPlay" IsChecked="False" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</UserControl>
|
|
@ -0,0 +1,175 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
using SDKTemplate.Models;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Web.Http;
|
||||
|
||||
namespace SDKTemplate.Controls
|
||||
{
|
||||
public sealed partial class ContentSelector : UserControl
|
||||
{
|
||||
public ContentSelector()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private MediaPlayer mediaPlayer;
|
||||
private IEnumerable<AdaptiveContentModel> adaptiveContentModels;
|
||||
public AdaptiveContentModel SelectedModel;
|
||||
private LogView loggerControl;
|
||||
Func<Uri, HttpClient, Task<MediaPlaybackItem>> CreateMediaPlaybackItem;
|
||||
public MediaPlaybackItem MediaPlaybackItem;
|
||||
public HttpClient optionalHttpClient;
|
||||
|
||||
internal void Initialize(MediaPlayer mediaPlayer,
|
||||
IEnumerable<AdaptiveContentModel> adaptiveContentModels,
|
||||
HttpClient optionalHttpClient,
|
||||
LogView loggerControl,
|
||||
Func<Uri, HttpClient, Task<MediaPlaybackItem>> loadSourceFromUriAsync)
|
||||
{
|
||||
if (mediaPlayer == null)
|
||||
throw new ArgumentNullException("mediaPlayer");
|
||||
this.mediaPlayer = mediaPlayer;
|
||||
|
||||
if (adaptiveContentModels == null)
|
||||
throw new ArgumentNullException("adaptiveContentModels");
|
||||
this.adaptiveContentModels = adaptiveContentModels;
|
||||
|
||||
if (loggerControl == null)
|
||||
throw new ArgumentNullException("loggerControl");
|
||||
this.loggerControl = loggerControl;
|
||||
|
||||
if (loadSourceFromUriAsync == null)
|
||||
throw new ArgumentNullException("loadSourceFromUriAsync");
|
||||
this.CreateMediaPlaybackItem = loadSourceFromUriAsync;
|
||||
|
||||
this.optionalHttpClient = optionalHttpClient;
|
||||
|
||||
// Set data context:
|
||||
SelectedContent.ItemsSource = this.adaptiveContentModels;
|
||||
// Set default item:
|
||||
SetSelectedModel(this.adaptiveContentModels.First());
|
||||
}
|
||||
|
||||
public void SetSelectedModel(AdaptiveContentModel model)
|
||||
{
|
||||
SelectedModel = model;
|
||||
SelectedContent.SelectedItem = SelectedModel;
|
||||
}
|
||||
|
||||
public async void HideLoadUri()
|
||||
{
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
this.LoadUriPanel.Visibility = Visibility.Collapsed;
|
||||
});
|
||||
}
|
||||
public async void SetAutoPlay(bool IsChecked)
|
||||
{
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
AutoPlay.IsChecked = IsChecked;
|
||||
});
|
||||
}
|
||||
|
||||
private async void LoadId_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayer == null || adaptiveContentModels == null || loggerControl == null)
|
||||
return;
|
||||
|
||||
this.SelectedModel = (AdaptiveContentModel)SelectedContent.SelectedItem;
|
||||
|
||||
UriBox.Text = SelectedModel.ManifestUri.ToString();
|
||||
await CreateNewMediaPlaybackItem(SelectedModel.ManifestUri);
|
||||
}
|
||||
|
||||
private async void LoadUri_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayer == null || adaptiveContentModels == null || loggerControl == null)
|
||||
return;
|
||||
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(UriBox.Text, UriKind.Absolute, out uri))
|
||||
{
|
||||
loggerControl.Log("Malformed Uri in Load text box.", SDKTemplate.Logging.LogViewLoggingLevel.Critical);
|
||||
return;
|
||||
}
|
||||
await CreateNewMediaPlaybackItem(uri);
|
||||
}
|
||||
|
||||
private async Task CreateNewMediaPlaybackItem(Uri uri)
|
||||
{
|
||||
SetSourceEnabled(false);
|
||||
this.MediaPlaybackItem = null;
|
||||
this.MediaPlaybackItem = await CreateMediaPlaybackItem(uri, optionalHttpClient);
|
||||
if (this.MediaPlaybackItem != null)
|
||||
{
|
||||
loggerControl.Log($"Loaded Uri: {uri}");
|
||||
SetSourceEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private async void SetSourceEnabled(bool SetEnabled)
|
||||
{
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
SetSource.IsEnabled = SetEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
private void AutoPlay_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayer == null || adaptiveContentModels == null || loggerControl == null)
|
||||
return;
|
||||
|
||||
mediaPlayer.AutoPlay = (bool)(sender as CheckBox).IsChecked;
|
||||
}
|
||||
|
||||
private void ForceEquirectangularSphericalVideoFrameFormat()
|
||||
{
|
||||
if (mediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.None ||
|
||||
mediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Opening)
|
||||
return;
|
||||
|
||||
var mpsvp = mediaPlayer.PlaybackSession.SphericalVideoProjection;
|
||||
if (mpsvp == null)
|
||||
return;
|
||||
|
||||
if (mpsvp.FrameFormat != Windows.Media.MediaProperties.SphericalVideoFrameFormat.Equirectangular)
|
||||
mpsvp.FrameFormat = Windows.Media.MediaProperties.SphericalVideoFrameFormat.Equirectangular;
|
||||
|
||||
if (mpsvp.IsEnabled != true)
|
||||
mpsvp.IsEnabled = true;
|
||||
|
||||
mpsvp.HorizontalFieldOfViewInDegrees = 120;
|
||||
}
|
||||
|
||||
private void SetSource_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayer == null || adaptiveContentModels == null || loggerControl == null)
|
||||
return;
|
||||
|
||||
// It is at this point that the MediaSource (within a MediaPlaybackItem) will be fully resolved.
|
||||
// For an AdaptiveMediaSource, this is the point at which media is first requested and parsed.
|
||||
mediaPlayer.Source = this.MediaPlaybackItem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SDKTemplate.Helpers
|
||||
{
|
||||
public static class MediaFoundationGuidStringExtensions
|
||||
{
|
||||
// Translation of selected GUIDs used in MF to their human-readable attribute strings
|
||||
// These are in defined the Windows SDK and in various regkeys.
|
||||
// Ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317906(v=vs.85).aspx
|
||||
|
||||
public static string ToMFAttributeName(Guid guidToFind)
|
||||
{
|
||||
string retVal = guidToFind.ToString();
|
||||
string mfAttribute;
|
||||
if (MfGuidDictionary.TryGetValue(guidToFind, out mfAttribute))
|
||||
{
|
||||
retVal = mfAttribute;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
public static string ToMFAttributeName(object objectToCheck)
|
||||
{
|
||||
// Return .ToString as default:
|
||||
string retVal = objectToCheck.ToString();
|
||||
|
||||
// Passed object is Guid
|
||||
if (objectToCheck is Guid)
|
||||
{
|
||||
Guid guidToFind = (Guid)objectToCheck;
|
||||
retVal = ToMFAttributeName(guidToFind);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Passed object is Guid.ToString()
|
||||
Guid guidToFind;
|
||||
if (Guid.TryParse(retVal, out guidToFind))
|
||||
{
|
||||
retVal = ToMFAttributeName(guidToFind);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
private static Dictionary<Guid, string> MfGuidDictionary = new Dictionary<Guid, string>()
|
||||
{
|
||||
{new Guid("73646976-0000-0010-8000-00AA00389B71"), "[MEDIATYPE_Video]"},
|
||||
{new Guid("73647561-0000-0010-8000-00AA00389B71"), "[MEDIATYPE_Audio]"},
|
||||
{new Guid("73747874-0000-0010-8000-00AA00389B71"), "[MEDIATYPE_Text]"},
|
||||
|
||||
{new Guid("3F40F4F0-5622-4FF8-B6D8-A17A584BEE5E"), "[MFVideoFormat_H264_ES]"},
|
||||
|
||||
{new Guid("7632f0e6-9538-4d61-acda-ea29c8c14456"), "[MF_MT_AAC_AUDIO_PROFILE_LEVEL_INDICATION]"},
|
||||
{new Guid("bfbabe79-7434-4d1c-94f0-72a3b9e17188"), "[MF_MT_AAC_PAYLOAD_TYPE]"},
|
||||
{new Guid("c9173739-5e56-461c-b713-46fb995cb95f"), "[MF_MT_ALL_SAMPLES_INDEPENDENT]"},
|
||||
{new Guid("73d1072d-1870-4174-a063-29ff4ff6c11e"), "[MF_MT_AM_FORMAT_TYPE]"},
|
||||
{new Guid("1aab75c8-cfef-451c-ab95-ac034b8e1731"), "[MF_MT_AUDIO_AVG_BYTES_PER_SECOND]"},
|
||||
{new Guid("f2deb57f-40fa-4764-aa33-ed4f2d1ff669"), "[MF_MT_AUDIO_BITS_PER_SAMPLE]"},
|
||||
{new Guid("322de230-9eeb-43bd-ab7a-ff412251541d"), "[MF_MT_AUDIO_BLOCK_ALIGNMENT]"},
|
||||
{new Guid("55fb5765-644a-4caf-8479-938983bb1588"), "[MF_MT_AUDIO_CHANNEL_MASK]"},
|
||||
{new Guid("37e48bf5-645e-4c5b-89de-ada9e29b696a"), "[MF_MT_AUDIO_NUM_CHANNELS]"},
|
||||
{new Guid("a901aaba-e037-458a-bdf6-545be2074042"), "[MF_MT_AUDIO_PREFER_WAVEFORMATEX]"},
|
||||
{new Guid("5faeeae7-0290-4c31-9e8a-c534f68d9dba"), "[MF_MT_AUDIO_SAMPLES_PER_SECOND]"},
|
||||
{new Guid("799cabd6-3508-4db4-a3c7-569cd533deb1"), "[MF_MT_AVG_BIT_ERROR_RATE]"},
|
||||
{new Guid("20332624-fb0d-4d9e-bd0d-cbf6786c102e"), "[MF_MT_AVG_BITRATE]"},
|
||||
{new Guid("3afd0cee-18f2-4ba5-a110-8bea502e1f92"), "[MF_MT_COMPRESSED]"},
|
||||
{new Guid("b8ebefaf-b718-4e04-b0a9-116775e3321b"), "[MF_MT_FIXED_SIZE_SAMPLES]"},
|
||||
{new Guid("c459a2e8-3d2c-4e44-b132-fee5156c7bb0"), "[MF_MT_FRAME_RATE]"},
|
||||
{new Guid("1652c33d-d6b2-4012-b834-72030849a37d"), "[MF_MT_FRAME_SIZE]"},
|
||||
{new Guid("e2724bb8-e676-4806-b4b2-a8d6efb44ccd"), "[MF_MT_INTERLACE_MODE]"},
|
||||
{new Guid("48eba18e-f8c9-4687-bf11-0a74c9f96a8f"), "[MF_MT_MAJOR_TYPE]"},
|
||||
{new Guid("3c036de7-3ad0-4c9e-9216-ee6d6ac21cb3"), "[MF_MT_MPEG_SEQUENCE_HEADER]"},
|
||||
{new Guid("9aa7e155-b64a-4c1d-a500-455d600b6560"), "[MF_MT_MPEG4_CURRENT_SAMPLE_ENTRY]"},
|
||||
{new Guid("261e9d83-9529-4b8f-a111-8b9c950a81a9"), "[MF_MT_MPEG4_SAMPLE_DESCRIPTION]"},
|
||||
{new Guid("c6376a1e-8d0a-4027-be45-6d9a0ad39bb6"), "[MF_MT_PIXEL_ASPECT_RATIO]"},
|
||||
{new Guid("dad3ab78-1990-408b-bce2-eba673dacc10"), "[MF_MT_SAMPLE_SIZE]"},
|
||||
{new Guid("f7e34c9a-42e8-4714-b74b-cb29d72c35e5"), "[MF_MT_SUBTYPE]"},
|
||||
{new Guid("b6bc765f-4c3b-40a4-bd51-2535b66fe09d"), "[MF_MT_USER_DATA]"},
|
||||
{new Guid("96f66574-11c5-4015-8666-bff516436da7"), "[MF_MT_VIDEO_LEVEL | MF_MT_MPEG2_LEVEL]"},
|
||||
{new Guid("ad76a80b-2d5c-4e0b-b375-64e520137036"), "[MF_MT_VIDEO_PROFILE]"},
|
||||
{new Guid("c380465d-2271-428c-9b83-ecea3b4a85c1"), "[MF_MT_VIDEO_ROTATION]"},
|
||||
{new Guid("a7911d53-12a4-4965-ae70-6eadd6ff0551"), "[MF_NALU_LENGTH_SET]"},
|
||||
{new Guid("8f020eea-1508-471f-9da6-507d7cfa40db"), "[MF_PROGRESSIVE_CODING_CONTENT]"},
|
||||
};
|
||||
}
|
||||
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Windows.Media.MediaProperties;
|
||||
using Windows.Media.Playback;
|
||||
|
||||
namespace SDKTemplate.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// This class demonstrates the full range of properties available on the MediaPlaybackItem.
|
||||
///
|
||||
/// </summary>
|
||||
public static class MediaPlaybackItemStringExtensions
|
||||
{
|
||||
|
||||
public static string ToFormattedString(this MediaPlaybackItem item)
|
||||
{
|
||||
if (item == null)
|
||||
return String.Empty;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// MediaPlaybackItem.Source.CustomProperties
|
||||
var source = item.Source;
|
||||
if (source != null && source.CustomProperties.Any())
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||
sb.AppendLine("Source.CustomProperties:");
|
||||
foreach (var prop in source.CustomProperties)
|
||||
{
|
||||
sb.AppendLine(prop.Key + ":\t" + prop.Value);
|
||||
}
|
||||
}
|
||||
|
||||
// MediaPlaybackItem.VideoTracks[].*
|
||||
foreach (var track in item.VideoTracks)
|
||||
{
|
||||
// Note that AdaptiveMediaSource only exposes a single Video track. Details on bitrates are directly on the AdaptiveMediaSource.
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||
sb.AppendLine("TrackKind:\t" + track.TrackKind);
|
||||
sb.AppendLine("Id:\t" + track.Id);
|
||||
sb.AppendLine("Label:\t" + track.Label);
|
||||
sb.AppendLine("Language:\t" + track.Language);
|
||||
sb.AppendLine("Name:\t" + track.Name);
|
||||
sb.AppendLine("DecoderStatus:\t" + track.SupportInfo.DecoderStatus);
|
||||
sb.AppendLine("MediaSourceStatus:\t" + track.SupportInfo.MediaSourceStatus);
|
||||
var encodingProps = track.GetEncodingProperties();
|
||||
if (encodingProps != null)
|
||||
{
|
||||
sb.AppendLine("Encoding Properties:");
|
||||
sb.AppendLine("Type:\t" + encodingProps.Type);
|
||||
sb.AppendLine("Subtype:\t" + MediaFoundationGuidStringExtensions.ToMFAttributeName(encodingProps.Subtype));
|
||||
sb.AppendLine("Bitrate:\t" + encodingProps.Bitrate);
|
||||
sb.AppendLine(encodingProps.FrameRate.ToFormattedString("FrameRate"));
|
||||
sb.AppendLine("Height:\t" + encodingProps.Height);
|
||||
sb.AppendLine(encodingProps.PixelAspectRatio.ToFormattedString("PixelAspectRatio"));
|
||||
sb.AppendLine("ProfileId:\t" + encodingProps.ProfileId);
|
||||
sb.AppendLine("StereoscopicVideoPackingMode:\t" + encodingProps.StereoscopicVideoPackingMode);
|
||||
sb.AppendLine("Width:\t" + encodingProps.Width);
|
||||
var additionalProperties = encodingProps.Properties;
|
||||
sb.AppendLine(additionalProperties.ToFormattedString());
|
||||
}
|
||||
}
|
||||
|
||||
// MediaPlaybackItem.AudioTracks[].*
|
||||
foreach (var track in item.AudioTracks)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||
sb.AppendLine("TrackKind:\t" + track.TrackKind);
|
||||
sb.AppendLine("Id:\t" + track.Id);
|
||||
sb.AppendLine("Label:\t" + track.Label);
|
||||
sb.AppendLine("Language:\t" + track.Language);
|
||||
sb.AppendLine("Name:\t" + track.Name);
|
||||
sb.AppendLine("DecoderStatus:\t" + track.SupportInfo.DecoderStatus);
|
||||
sb.AppendLine("MediaSourceStatus:\t" + track.SupportInfo.MediaSourceStatus);
|
||||
var encodingProps = track.GetEncodingProperties();
|
||||
if (encodingProps != null)
|
||||
{
|
||||
sb.AppendLine("Encoding Properties:");
|
||||
sb.AppendLine("Type:\t" + encodingProps.Type);
|
||||
sb.AppendLine("Subtype:\t" + MediaFoundationGuidStringExtensions.ToMFAttributeName(encodingProps.Subtype));
|
||||
sb.AppendLine("Bitrate:\t" + encodingProps.Bitrate);
|
||||
sb.AppendLine("BitsPerSample:\t" + encodingProps.BitsPerSample);
|
||||
sb.AppendLine("ChannelCount:\t" + encodingProps.ChannelCount);
|
||||
sb.AppendLine("SampleRate:\t" + encodingProps.SampleRate);
|
||||
var additionalProperties = encodingProps.Properties;
|
||||
sb.AppendLine(additionalProperties.ToFormattedString());
|
||||
}
|
||||
}
|
||||
|
||||
// MediaPlaybackItem.TimedMetadataTracks[].*
|
||||
foreach (var track in item.TimedMetadataTracks)
|
||||
{
|
||||
sb.AppendLine();
|
||||
sb.AppendLine("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||
sb.AppendLine("TrackKind:\t" + track.TrackKind);
|
||||
sb.AppendLine("Id:\t" + track.Id);
|
||||
sb.AppendLine("Label:\t" + track.Label);
|
||||
sb.AppendLine("Language:\t" + track.Language);
|
||||
sb.AppendLine("Name:\t" + track.Name);
|
||||
if (track.ActiveCues != null)
|
||||
sb.AppendLine("ActiveCues.Count:\t" + track.ActiveCues.Count);
|
||||
if (track.Cues != null)
|
||||
sb.AppendLine("Cues.Count:\t" + track.Cues.Count);
|
||||
sb.AppendLine("DispatchType:\t" + track.DispatchType);
|
||||
sb.AppendLine("TimedMetadataKind:\t" + track.TimedMetadataKind);
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
static string ToFormattedString(this MediaRatio mediaRatio, string key)
|
||||
{
|
||||
string retVal = string.Empty;
|
||||
if (!String.IsNullOrEmpty(key) && mediaRatio != null)
|
||||
{
|
||||
retVal = key + ":\t" + mediaRatio.Numerator + "/" + mediaRatio.Denominator;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
static string ToFormattedString(this MediaPropertySet mediaPropertySet)
|
||||
{
|
||||
var retVal = new StringBuilder();
|
||||
|
||||
if (mediaPropertySet.Count != 0)
|
||||
retVal.AppendLine("Additional Encoding Properties:");
|
||||
foreach (var prop in mediaPropertySet)
|
||||
{
|
||||
// We can also get the various MF_ Guid-based props, some of which are a repeat from above:
|
||||
retVal.AppendLine(MediaFoundationGuidStringExtensions.ToMFAttributeName(prop.Key) + ":\t" + MediaFoundationGuidStringExtensions.ToMFAttributeName(prop.Value));
|
||||
|
||||
// Special case for Byte Arrays:
|
||||
if (prop.Value.GetType() == typeof(System.Byte[]))
|
||||
{
|
||||
var propBytes = prop.Value as System.Byte[];
|
||||
if (propBytes != null && propBytes.Length > 0)
|
||||
{
|
||||
String byteString = "";
|
||||
foreach (var b in propBytes)
|
||||
{
|
||||
byteString += String.Format("{0:X2} ", b);
|
||||
}
|
||||
retVal.AppendLine(MediaFoundationGuidStringExtensions.ToMFAttributeName(prop.Key) + " as Hex:\t" + byteString);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -38,7 +38,33 @@ namespace SDKTemplate.Helpers
|
|||
|
||||
var item = mediaPlayer.Source as MediaPlaybackItem;
|
||||
if (item != null && item.Source != null)
|
||||
{
|
||||
if (item.BreakSchedule.PrerollBreak != null)
|
||||
{
|
||||
foreach (var mpItem in item.BreakSchedule.PrerollBreak.PlaybackList.Items)
|
||||
{
|
||||
mpItem.Source?.Dispose();
|
||||
}
|
||||
}
|
||||
if (item.BreakSchedule.MidrollBreaks.Count != 0)
|
||||
{
|
||||
foreach (var mrBreak in item.BreakSchedule.MidrollBreaks)
|
||||
{
|
||||
foreach (var mpItem in mrBreak.PlaybackList.Items)
|
||||
{
|
||||
mpItem.Source?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item.BreakSchedule.PostrollBreak != null)
|
||||
{
|
||||
foreach (var mpItem in item.BreakSchedule.PostrollBreak.PlaybackList.Items)
|
||||
{
|
||||
mpItem.Source?.Dispose();
|
||||
}
|
||||
}
|
||||
item.Source.Dispose();
|
||||
}
|
||||
};
|
||||
mediaPlayer.Source = null;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//*********************************************************
|
||||
|
||||
using SDKTemplate;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
|
@ -36,11 +37,11 @@ namespace SDKTemplate.Helpers
|
|||
/// </summary>
|
||||
public class PlayReadyHelper
|
||||
{
|
||||
public PlayReadyHelper(Logger logger = null)
|
||||
public PlayReadyHelper(LogView logger = null)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
private Logger logger;
|
||||
private LogView logger;
|
||||
|
||||
|
||||
private const int MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = -2147174251;
|
||||
|
@ -58,7 +59,7 @@ namespace SDKTemplate.Helpers
|
|||
{
|
||||
if (logger != null)
|
||||
{
|
||||
logger.Log(message);
|
||||
logger.Log(message, LogViewLoggingLevel.Information);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
<UserControl
|
||||
x:Class="SDKTemplate.Logger"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="400">
|
||||
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Button Click="{x:Bind CopyLogToClipboard_Click}" Content="Copy log" Margin="0,0,10,0"/>
|
||||
<Button Click="{x:Bind ClearLog_Click}" Content="Clear log"/>
|
||||
</StackPanel>
|
||||
<ScrollViewer Margin="0,10,0,0" Height="100" HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Visible" VerticalScrollMode="Enabled" VerticalScrollBarVisibility="Visible">
|
||||
<ListBox x:Name="LoggingListBox">
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="Padding" Value="0"/>
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
</ListBox>
|
||||
</ScrollViewer>
|
||||
</StackPanel>
|
||||
|
||||
</UserControl>
|
|
@ -1,48 +0,0 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
public sealed partial class Logger : UserControl
|
||||
{
|
||||
public Logger()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
public async void Log(string message)
|
||||
{
|
||||
string logEntry = $"{DateTime.Now:HH:mm:ss.fff} - {message}";
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
LoggingListBox.Items.Insert(0, new TextBlock() { Text = logEntry });
|
||||
});
|
||||
}
|
||||
|
||||
public void CopyLogToClipboard_Click()
|
||||
{
|
||||
var content = new DataPackage();
|
||||
content.SetText(String.Join("\r\n", LoggingListBox.Items.Select(item => (item as TextBlock).Text)));
|
||||
Clipboard.SetContent(content);
|
||||
}
|
||||
|
||||
public void ClearLog_Click()
|
||||
{
|
||||
LoggingListBox.Items.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -93,27 +93,52 @@ namespace SDKTemplate.Models
|
|||
{ Captions = "Indexer,en,http://nimbuspm.origin.mediaservices.windows.net/aed33834-ec2d-4788-88b5-a4505b3d032c/pp4_blog_demo.vtt" },
|
||||
|
||||
// Live HLS content:
|
||||
new AdaptiveContentModel(10, "Azure Media Services 24x7 (HLS, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=m3u8-aapl)")
|
||||
new AdaptiveContentModel(10, "60min Azure Media Services 24x7 (HLS, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=m3u8-aapl)")
|
||||
{ Live = true },
|
||||
new AdaptiveContentModel(15, "30min Azure Media Services 24x7 (HLS, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=m3u8-aapl,filter=30mindvr)")
|
||||
{ Live = true },
|
||||
new AdaptiveContentModel(16, "5min Azure Media Services 24x7 (HLS, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=m3u8-aapl,filter=5mindvr)")
|
||||
{ Live = true },
|
||||
new AdaptiveContentModel(17, "2min Azure Media Services 24x7 (HLS, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=m3u8-aapl,filter=2mindvr)")
|
||||
{ Live = true },
|
||||
|
||||
// Live DASH content (manifest type = dynamic) is not available using the AdaptiveMediaSource:
|
||||
// new AdaptiveContentModel(NA, "Azure Media Services 24x7 (DASH, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=mpd-time-csf)")
|
||||
// { Live = true },
|
||||
new AdaptiveContentModel(110, "60min Azure Media Services 24x7 (DASH, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=mpd-time-csf)")
|
||||
{ Live = true },
|
||||
new AdaptiveContentModel(111, "30min Azure Media Services 24x7 (DASH, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=mpd-time-csf,filter=30mindvr)")
|
||||
{ Live = true },
|
||||
new AdaptiveContentModel(112, "5min Azure Media Services 24x7 (DASH, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=mpd-time-csf,filter=5mindvr)")
|
||||
{ Live = true },
|
||||
new AdaptiveContentModel(113, "2min Azure Media Services 24x7 (DASH, Live) - (CC) blender.org", "http://b028.wpc.azureedge.net/80B028/Samples/a38e6323-95e9-4f1f-9b38-75eba91704e4/5f2ce531-d508-49fb-8152-647eba422aec.ism/manifest(format=mpd-time-csf,filter=2mindvr)")
|
||||
{ Live = true },
|
||||
|
||||
// PlayReady DASH streams need a properly setup MediaProtectionManager:
|
||||
new AdaptiveContentModel(110, "Big Buck Bunny (DASH) with DRM (PlayReady/Widevine CENC) - (CC) peach.blender.org", "http://amssamples.streaming.mediaservices.windows.net/622b189f-ec39-43f2-93a2-201ac4e31ce1/BigBuckBunny.ism/manifest(format=mpd-time-csf)")
|
||||
new AdaptiveContentModel(115, "Big Buck Bunny (DASH) with DRM (PlayReady/Widevine CENC) - (CC) peach.blender.org", "http://amssamples.streaming.mediaservices.windows.net/622b189f-ec39-43f2-93a2-201ac4e31ce1/BigBuckBunny.ism/manifest(format=mpd-time-csf)")
|
||||
{ PlayReady = true },
|
||||
new AdaptiveContentModel(111, "Tears of Steel Trailer (DASH, PlayReady) - (CC) mango.blender.org", "http://amssamples.streaming.mediaservices.windows.net/de1470b3-7b3c-4902-ab53-d19b37ef3bd7/TearsOfSteelTeaser.ism/manifest(format=mpd-time-csf)")
|
||||
new AdaptiveContentModel(116, "Tears of Steel Trailer (DASH, PlayReady) - (CC) mango.blender.org", "http://amssamples.streaming.mediaservices.windows.net/de1470b3-7b3c-4902-ab53-d19b37ef3bd7/TearsOfSteelTeaser.ism/manifest(format=mpd-time-csf)")
|
||||
{ PlayReady = true },
|
||||
new AdaptiveContentModel(112, "Sintel Trailer (DASH, PlayReady) - (CC) durian.blender.org", "http://amssamples.streaming.mediaservices.windows.net/bf657309-71d9-4436-b94b-8ac0d2ca222b/SintelTrailer.ism/manifest(format=mpd-time-csf)")
|
||||
new AdaptiveContentModel(117, "Sintel Trailer (DASH, PlayReady) - (CC) durian.blender.org", "http://amssamples.streaming.mediaservices.windows.net/bf657309-71d9-4436-b94b-8ac0d2ca222b/SintelTrailer.ism/manifest(format=mpd-time-csf)")
|
||||
{ PlayReady = true },
|
||||
|
||||
// Live DASH PlayReady content is not available using the AdaptiveMediaSource:
|
||||
// new AdaptiveContentModel(NA, "Azure Media Services 24x7 Live PlayReady/Widevine CENC - (CC) blender.org (DASH)", "http://b028.wpc.azureedge.net/80B028/SampleStream/3f6088ec-9e1f-4db7-b7d9-3ec07183ce7d/e405bd0a-a34f-40e2-b70b-4322c46f5cb7.ism/manifest(format=mpd-time-csf)")
|
||||
// { PlayReady = true, Live = true },
|
||||
// new AdaptiveContentModel(NA, "Azure Media Services 24x7 Live PlayReady - (CC) blender.org (DASH)", "http://b028.wpc.azureedge.net/80B028/Samples/859b335f-eebc-4ff1-ac03-98e9b614e2c1/0cc164eb-193e-48cb-bc6b-041cc28307e4.ism/manifest(format=mpd-time-csf)")
|
||||
// { PlayReady = true, Live = true, },
|
||||
new AdaptiveContentModel(118, "60min Azure Media Services 24x7 Live PlayReady/Widevine CENC - (CC) blender.org (DASH, Live)", "http://b028.wpc.azureedge.net/80B028/SampleStream/3f6088ec-9e1f-4db7-b7d9-3ec07183ce7d/e405bd0a-a34f-40e2-b70b-4322c46f5cb7.ism/manifest(format=mpd-time-csf)")
|
||||
{ PlayReady = true, Live = true },
|
||||
new AdaptiveContentModel(119, "30min Azure Media Services 24x7 Live PlayReady/Widevine CENC - (CC) blender.org (DASH, Live)", "http://b028.wpc.azureedge.net/80B028/SampleStream/3f6088ec-9e1f-4db7-b7d9-3ec07183ce7d/e405bd0a-a34f-40e2-b70b-4322c46f5cb7.ism/manifest(format=mpd-time-csf,filter=30mindvr)")
|
||||
{ PlayReady = true, Live = true },
|
||||
new AdaptiveContentModel(120, "5min Azure Media Services 24x7 Live PlayReady/Widevine CENC - (CC) blender.org (DASH, Live)", "http://b028.wpc.azureedge.net/80B028/SampleStream/3f6088ec-9e1f-4db7-b7d9-3ec07183ce7d/e405bd0a-a34f-40e2-b70b-4322c46f5cb7.ism/manifest(format=mpd-time-csf,filter=5mindvr)")
|
||||
{ PlayReady = true, Live = true },
|
||||
new AdaptiveContentModel(121, "2min Azure Media Services 24x7 Live PlayReady/Widevine CENC - (CC) blender.org (DASH, Live)", "http://b028.wpc.azureedge.net/80B028/SampleStream/3f6088ec-9e1f-4db7-b7d9-3ec07183ce7d/e405bd0a-a34f-40e2-b70b-4322c46f5cb7.ism/manifest(format=mpd-time-csf,filter=2mindvr)")
|
||||
{ PlayReady = true, Live = true },
|
||||
|
||||
new AdaptiveContentModel(122, "60min Azure Media Services 24x7 Live PlayReady - (CC) blender.org (DASH, Live, 60min)", "http://b028.wpc.azureedge.net/80B028/Samples/859b335f-eebc-4ff1-ac03-98e9b614e2c1/0cc164eb-193e-48cb-bc6b-041cc28307e4.ism/manifest(format=mpd-time-csf)")
|
||||
{ PlayReady = true, Live = true, },
|
||||
new AdaptiveContentModel(123, "30min Azure Media Services 24x7 Live PlayReady - (CC) blender.org (DASH, Live, 30min)", "http://b028.wpc.azureedge.net/80B028/Samples/859b335f-eebc-4ff1-ac03-98e9b614e2c1/0cc164eb-193e-48cb-bc6b-041cc28307e4.ism/manifest(format=mpd-time-csf,filter=30mindvr)")
|
||||
{ PlayReady = true, Live = true, },
|
||||
new AdaptiveContentModel(124, "5min Azure Media Services 24x7 Live PlayReady - (CC) blender.org (DASH, Live, 5min)", "http://b028.wpc.azureedge.net/80B028/Samples/859b335f-eebc-4ff1-ac03-98e9b614e2c1/0cc164eb-193e-48cb-bc6b-041cc28307e4.ism/manifest(format=mpd-time-csf,filter=5mindvr)")
|
||||
{ PlayReady = true, Live = true, },
|
||||
new AdaptiveContentModel(125, "2min Azure Media Services 24x7 Live PlayReady - (CC) blender.org (DASH, Live, 2min)", "http://b028.wpc.azureedge.net/80B028/Samples/859b335f-eebc-4ff1-ac03-98e9b614e2c1/0cc164eb-193e-48cb-bc6b-041cc28307e4.ism/manifest(format=mpd-time-csf,filter=2mindvr)")
|
||||
{ PlayReady = true, Live = true, },
|
||||
|
||||
// HLS streams with AES-128 CBC encryption:
|
||||
new AdaptiveContentModel(11, "Sintel (HLS, AES-128 encryption) - (CC) durian.blender.org", "http://amssamples.streaming.mediaservices.windows.net/49b57c87-f5f3-48b3-ba22-c55cfdffa9cb/Sintel.ism/manifest(format=m3u8-aapl)")
|
||||
{ Aes = true },
|
||||
|
@ -132,6 +157,10 @@ namespace SDKTemplate.Models
|
|||
Aes = true,
|
||||
AesToken = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cm46bWljcm9zb2Z0OmF6dXJlOm1lZGlhc2VydmljZXM6Y29udGVudGtleWlkZW50aWZpZXIiOiI5ZGRhMGJjYy01NmZiLTQxNDMtOWQzMi0zYWI5Y2M2ZWE4MGIiLCJpc3MiOiJodHRwOi8vdGVzdGFjcy5jb20vIiwiYXVkIjoidXJuOnRlc3QiLCJleHAiOjE3MTA4MDczODl9.lJXm5hmkp5ArRIAHqVJGefW2bcTzd91iZphoKDwa6w8"
|
||||
},
|
||||
|
||||
// From: http://se-mashup.fokus.fraunhofer.de:8080/adinsertion-sample/scte.html
|
||||
new AdaptiveContentModel(200, "Fraunhofer Fokus test stream (DASH, Live, SCTE35 emsg) - (Copyright) Fraunhofer Fokus", "http://vm2.dashif.org/livesim/scte35_1/testpic_2s/Manifest.mpd")
|
||||
{ Live = true },
|
||||
};
|
||||
|
||||
public static IReadOnlyList<AdaptiveContentModel> GetKnownAzureMediaServicesModels()
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace SDKTemplate
|
|||
new Scenario() { Title="Adaptive Streaming Tuning", ClassType=typeof(Scenario4_Tuning)},
|
||||
new Scenario() { Title="Metadata", ClassType=typeof(Scenario5_Metadata)},
|
||||
new Scenario() { Title="Ad Insertion", ClassType=typeof(Scenario6_AdInsertion)},
|
||||
new Scenario() { Title="Live Seekable Range", ClassType=typeof(Scenario7_LiveSeekableRange)},
|
||||
};
|
||||
|
||||
public static IReadOnlyList<AdaptiveContentModel> ContentManagementSystemStub = AdaptiveContentModel.GetKnownAzureMediaServicesModels();
|
||||
|
@ -86,4 +87,4 @@ namespace SDKTemplate
|
|||
return Symbol.ZeroBars;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="12,10,12,12">
|
||||
|
@ -31,6 +30,7 @@
|
|||
An AdaptiveMediaSource is created implicitly when a manifest URI is used with MediaSource.CreateFromUri(uri).
|
||||
No properties or callbacks of the AdaptiveMediaSource can be retrieved when it is created implicitly.
|
||||
</TextBlock>
|
||||
<Button x:Name="Load" Content="Load" Click="Load_Click"/>
|
||||
</StackPanel>
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" AreTransportControlsEnabled="True" />
|
||||
<!-- Alternatively, you can set the Source to your content Uri:
|
||||
|
|
|
@ -44,9 +44,9 @@ namespace SDKTemplate
|
|||
}
|
||||
}
|
||||
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
private void Load_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// NOTE: Change this to 110 to see DASH with PlayReady scenario
|
||||
// NOTE: Change this to 115 to see DASH with PlayReady scenario
|
||||
const int contentIdForCMS = 1;
|
||||
|
||||
AdaptiveContentModel adaptiveContentModel = MainPage.FindContentById(contentIdForCMS);
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:local="using:SDKTemplate.Controls"
|
||||
xmlns:logging="using:SDKTemplate.Logging"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
@ -27,19 +28,18 @@
|
|||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Orientation="Vertical">
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,10" Orientation="Vertical">
|
||||
<StackPanel x:Name="DescriptionText">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario demonstrates events which report the state of adaptive streaming.
|
||||
If the URI entered below is not supported for adaptive streaming,
|
||||
the sample falls back to MediaSource.CreateFromUri().
|
||||
This scenario demonstrates the explicit use of an AdaptiveMediaSource and
|
||||
all those events which report the state of adaptive streaming and the rest of the playback pipeline.
|
||||
If the URI entered below is not supported for adaptive streaming,
|
||||
the sample falls back to MediaSource.CreateFromUri().
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="10,10">
|
||||
<Button x:Name="LoadUri" Content="Load Uri" Click="LoadUri_Click" Margin="5,0" />
|
||||
<TextBox x:Name="UriBox" InputScope="Url" HorizontalAlignment="Stretch" Margin="5,0" />
|
||||
</StackPanel>
|
||||
<local:ContentSelector x:Name="ContentSelectorControl"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="10,10">
|
||||
<SymbolIcon Symbol="Download" ToolTipService.ToolTip="Download bitrate"/>
|
||||
<SymbolIcon Name="iconDownloadBitrate" Symbol="ZeroBars"/>
|
||||
|
@ -47,12 +47,11 @@
|
|||
<SymbolIcon Symbol="Play" ToolTipService.ToolTip="Playback bitrate"/>
|
||||
<SymbolIcon Name="iconPlaybackBitrate" Symbol="ZeroBars"/>
|
||||
<TextBlock Name="txtPlaybackBitrate" Margin="5,0"/>
|
||||
<CheckBox x:Name="VerboseLog" Click="VerboseLog_Click" Content="Verbose Log" IsChecked="False" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" AreTransportControlsEnabled="True" MinHeight="50" Margin="0,10,0,0"/>
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
|
||||
|
||||
<local:Logger x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
<logging:LogView x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -10,13 +10,10 @@
|
|||
//*********************************************************
|
||||
|
||||
using SDKTemplate.Helpers;
|
||||
using SDKTemplate.Models;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Globalization;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.Media.Streaming.Adaptive;
|
||||
|
@ -25,14 +22,13 @@ using Windows.UI.Xaml;
|
|||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Web.Http;
|
||||
using Windows.Web.Http.Filters;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
/// See the README.md for discussion of this scenario.
|
||||
public sealed partial class Scenario2_EventHandlers : Page
|
||||
{
|
||||
AdaptiveMediaSource adaptiveMediaSource;
|
||||
Task LoadSourceFromUriTask = Task.CompletedTask;
|
||||
private BitrateHelper bitrateHelper;
|
||||
|
||||
public Scenario2_EventHandlers()
|
||||
|
@ -40,17 +36,18 @@ namespace SDKTemplate
|
|||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override async void OnNavigatedFrom(NavigationEventArgs e)
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
// To insure we don't clean-up half-constructed objects,
|
||||
// wait for any active source loading to complete.
|
||||
await LoadSourceFromUriTask;
|
||||
|
||||
// Release handles on various media objects to ensure a quick clean-up
|
||||
ContentSelectorControl.MediaPlaybackItem = null;
|
||||
var mediaPlayer = mediaPlayerElement.MediaPlayer;
|
||||
if (mediaPlayer != null)
|
||||
{
|
||||
UnregisterForMediaPlayerEvents(mediaPlayer);
|
||||
mediaPlayerLogger?.Dispose();
|
||||
mediaPlayerLogger = null;
|
||||
|
||||
UnregisterHandlers(mediaPlayer);
|
||||
|
||||
mediaPlayer.DisposeSource();
|
||||
mediaPlayerElement.SetMediaPlayer(null);
|
||||
mediaPlayer.Dispose();
|
||||
|
@ -59,61 +56,84 @@ namespace SDKTemplate
|
|||
|
||||
private void UnregisterHandlers(MediaPlayer mediaPlayer)
|
||||
{
|
||||
AdaptiveMediaSource adaptiveMediaSource = null;
|
||||
MediaPlaybackItem mpItem = mediaPlayer.Source as MediaPlaybackItem;
|
||||
if (mpItem != null)
|
||||
{
|
||||
UnregisterForMediaPlaybackItemEvents(mpItem);
|
||||
UnregisterForMediaSourceEvents(mpItem.Source);
|
||||
adaptiveMediaSource = mpItem.Source.AdaptiveMediaSource;
|
||||
}
|
||||
MediaSource source = mediaPlayer.Source as MediaSource;
|
||||
if (source != null)
|
||||
{
|
||||
UnregisterForMediaSourceEvents(source);
|
||||
adaptiveMediaSource = source.AdaptiveMediaSource;
|
||||
}
|
||||
|
||||
mediaPlaybackItemLogger?.Dispose();
|
||||
mediaPlaybackItemLogger = null;
|
||||
|
||||
mediaSourceLogger?.Dispose();
|
||||
mediaSourceLogger = null;
|
||||
|
||||
adaptiveMediaSourceLogger?.Dispose();
|
||||
adaptiveMediaSourceLogger = null;
|
||||
|
||||
UnregisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
}
|
||||
|
||||
private async void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Explicitly create the instance of MediaPlayer if you need to register for its events
|
||||
// (like MediaOpened / MediaFailed) prior to setting an IMediaPlaybackSource.
|
||||
var mediaPlayer = new MediaPlayer();
|
||||
RegisterForMediaPlayerEvents(mediaPlayer);
|
||||
|
||||
// Ensure we have PlayReady support, if the user enters a DASH/PR Uri in the text box:
|
||||
// We use a helper class that logs all the events for the MediaPlayer:
|
||||
mediaPlayerLogger = new MediaPlayerLogger(LoggerControl, mediaPlayer);
|
||||
|
||||
// Ensure we have PlayReady support, in case the user enters a DASH/PR Uri in the text box.
|
||||
var prHelper = new PlayReadyHelper(LoggerControl);
|
||||
prHelper.SetUpProtectionManager(mediaPlayer);
|
||||
mediaPlayerElement.SetMediaPlayer(mediaPlayer);
|
||||
|
||||
AdaptiveContentModel adaptiveContentModel = MainPage.FindContentById(1);
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
LoadSourceFromUriTask = LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
await LoadSourceFromUriTask;
|
||||
// This Scenario focuses on event handling, mostly via the "Logger" helper classes
|
||||
// in the Shared folder.
|
||||
//
|
||||
// In addition, the App can also insert an IHttpFilter into the Windows.Web.Http stack
|
||||
// which is used by the AdaptiveMediaSource. To do so, it must derive a class from
|
||||
// IHttpFilter, provide the HttpBaseProtocolFilter to that class to execute requests,
|
||||
// then use the derived filter as the constructor for the HttpClient.
|
||||
//
|
||||
// The HttpClient is then used in the constructor of the AdaptiveMediaSource.
|
||||
// The App should explicitly set:
|
||||
// CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache
|
||||
// When passing an HttpClient into the constructor of AdpativeMediaSource,
|
||||
// set this on the HttpBaseProtocolFilter.
|
||||
//
|
||||
// More than one IHttpFilter can be nested, for example, an App might
|
||||
// use a filter to modify web requests: see Scenario3 for details.
|
||||
//
|
||||
// In this scenario, we add an AdaptiveMediaSourceHttpFilterLogger to provide additional
|
||||
// verbose logging details for each request.
|
||||
var baseProtocolFilter = new HttpBaseProtocolFilter();
|
||||
baseProtocolFilter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache; // Always set WriteBehavior = NoCache
|
||||
var fistLevelFilter = new AdaptiveMediaSourceHttpFilterLogger(LoggerControl, baseProtocolFilter);
|
||||
var httpClient = new HttpClient(fistLevelFilter);
|
||||
|
||||
|
||||
ContentSelectorControl.Initialize(
|
||||
mediaPlayer,
|
||||
MainPage.ContentManagementSystemStub.Where(m => !m.Aes),
|
||||
httpClient,
|
||||
LoggerControl,
|
||||
LoadSourceFromUriAsync);
|
||||
}
|
||||
|
||||
private async void LoadUri_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
#region Content Loading
|
||||
|
||||
private async Task<MediaPlaybackItem> LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(UriBox.Text, UriKind.Absolute, out uri))
|
||||
{
|
||||
Log("Malformed Uri in Load text box.");
|
||||
return;
|
||||
}
|
||||
|
||||
LoadSourceFromUriTask = LoadSourceFromUriAsync(uri);
|
||||
await LoadSourceFromUriTask;
|
||||
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
private async Task LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
if (mediaPlayerElement.MediaPlayer?.Source != null)
|
||||
{
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer.DisposeSource();
|
||||
}
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
AdaptiveMediaSourceCreationResult result = null;
|
||||
if (httpClient != null)
|
||||
|
@ -125,391 +145,88 @@ namespace SDKTemplate
|
|||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
|
||||
}
|
||||
|
||||
// We don't need to save a reference to the MediaSource,
|
||||
// because we can obtain it from the MediaPlaybackItem.Source in event handlers.
|
||||
MediaSource source;
|
||||
|
||||
if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
|
||||
{
|
||||
adaptiveMediaSource = result.MediaSource;
|
||||
var adaptiveMediaSource = result.MediaSource;
|
||||
|
||||
// We use a helper class that logs all the events for the AdaptiveMediaSource:
|
||||
adaptiveMediaSourceLogger = new AdaptiveMediaSourceLogger(LoggerControl, adaptiveMediaSource);
|
||||
|
||||
// In addition to logging, we use the callbacks to update some UI elements in this scenario:
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
|
||||
// At this point, we have read the manifest of the media source, and all bitrates are known.
|
||||
bitrateHelper = new BitrateHelper(adaptiveMediaSource.AvailableBitrates);
|
||||
|
||||
// The AdaptiveMediaSource chooses initial playback and download bitrates.
|
||||
// See the Tuning scenario for examples of customizing these bitrates.
|
||||
await UpdatePlaybackBitrate(adaptiveMediaSource.CurrentPlaybackBitrate);
|
||||
await UpdatePlaybackBitrateAsync(adaptiveMediaSource.CurrentPlaybackBitrate);
|
||||
await UpdateDownloadBitrateAsync(adaptiveMediaSource.CurrentDownloadBitrate);
|
||||
|
||||
// Register for events before resolving the MediaSource.
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
|
||||
source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Error creating the AdaptiveMediaSource: {result.Status}");
|
||||
Log($"Error creating the AdaptiveMediaSource. Status: {result.Status}, ExtendedError.Message: {result.ExtendedError.Message}, ExtendedError.HResult: {result.ExtendedError.HResult.ToString("X8")}");
|
||||
|
||||
// Try to load the URI as a progressive download URI.
|
||||
// In this scenario, we make a second attempt to load any URI that is
|
||||
// not adaptive streaming as a progressive download URI:
|
||||
Log($"Attempting to create a MediaSource from uri: {uri}");
|
||||
source = MediaSource.CreateFromUri(uri);
|
||||
}
|
||||
|
||||
// We use a helper class that logs all the events for the MediaSource:
|
||||
mediaSourceLogger = new MediaSourceLogger(LoggerControl, source);
|
||||
|
||||
// You can save additional information in the CustomPropertySet for future retrieval.
|
||||
// Note: MediaSource.CustomProperties is a ValueSet and therefore can store
|
||||
// only serializable types.
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties.Add("uri", uri.ToString());
|
||||
source.CustomProperties["uri"] = uri.ToString();
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties.Add("contentId", Guid.NewGuid());
|
||||
source.CustomProperties["contentId"] = Guid.NewGuid().ToString();
|
||||
|
||||
RegisterForMediaSourceEvents(source);
|
||||
|
||||
// Register for events before resolving the MediaSource.
|
||||
var mpItem = new MediaPlaybackItem(source);
|
||||
RegisterForMediaPlaybackItemEvents(mpItem);
|
||||
|
||||
// It is at this point that the MediaSource (within a MediaPlaybackItem) will be fully resolved.
|
||||
// It gets opened, and events start being raised.
|
||||
// We use a helper class that logs all the events for the MediaPlaybackItem:
|
||||
mediaPlaybackItemLogger = new MediaPlaybackItemLogger(LoggerControl, mpItem);
|
||||
|
||||
// Since we are in an async function, the user may have user navigated away, which will null the MediaPlayer.
|
||||
if (mediaPlayerElement.MediaPlayer != null)
|
||||
HideDescriptionOnSmallScreen();
|
||||
|
||||
return mpItem;
|
||||
}
|
||||
|
||||
private async void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
mediaPlayerElement.MediaPlayer.Source = mpItem;
|
||||
}
|
||||
}
|
||||
|
||||
#region MediaPlayer Event Handlers
|
||||
private void RegisterForMediaPlayerEvents(MediaPlayer mediaPlayer)
|
||||
{
|
||||
// Player Events
|
||||
mediaPlayer.SourceChanged += MediaPlayer_SourceChanged;
|
||||
mediaPlayer.MediaOpened += MediaPlayer_MediaOpened;
|
||||
mediaPlayer.MediaEnded += MediaPlayer_MediaEnded;
|
||||
mediaPlayer.MediaFailed += MediaPlayer_MediaFailed;
|
||||
mediaPlayer.VolumeChanged += MediaPlayer_VolumeChanged;
|
||||
mediaPlayer.IsMutedChanged += MediaPlayer_IsMutedChanged;
|
||||
// NOTE: There are a number of deprecated events on MediaPlayer.
|
||||
// Please use the equivalent events on the MediaPlayer.PlaybackSession as shown below.
|
||||
|
||||
// PlaybackSession Events
|
||||
mediaPlayer.PlaybackSession.BufferingEnded += MediaPlayer_PlaybackSession_BufferingEnded;
|
||||
mediaPlayer.PlaybackSession.BufferingProgressChanged += MediaPlayer_PlaybackSession_BufferingProgressChanged;
|
||||
mediaPlayer.PlaybackSession.BufferingStarted += MediaPlayer_PlaybackSession_BufferingStarted;
|
||||
mediaPlayer.PlaybackSession.DownloadProgressChanged += MediaPlayer_PlaybackSession_DownloadProgressChanged;
|
||||
mediaPlayer.PlaybackSession.NaturalDurationChanged += MediaPlayer_PlaybackSession_NaturalDurationChanged;
|
||||
mediaPlayer.PlaybackSession.NaturalVideoSizeChanged += MediaPlayer_PlaybackSession_NaturalVideoSizeChanged;
|
||||
mediaPlayer.PlaybackSession.PlaybackRateChanged += MediaPlayer_PlaybackSession_PlaybackRateChanged;
|
||||
mediaPlayer.PlaybackSession.PlaybackStateChanged += MediaPlayer_PlaybackSession_PlaybackStateChanged;
|
||||
// The .PositionChanged is excessively verbose for the UI logging we are doing in this sample:
|
||||
// mediaPlayer.PlaybackSession.PositionChanged += MediaPlayer_PlaybackSession_PositionChanged;
|
||||
mediaPlayer.PlaybackSession.SeekCompleted += MediaPlayer_PlaybackSession_SeekCompleted;
|
||||
}
|
||||
|
||||
private void UnregisterForMediaPlayerEvents(MediaPlayer mediaPlayer)
|
||||
{
|
||||
if (mediaPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Player Events
|
||||
mediaPlayer.SourceChanged -= MediaPlayer_SourceChanged;
|
||||
mediaPlayer.MediaOpened -= MediaPlayer_MediaOpened;
|
||||
mediaPlayer.MediaEnded -= MediaPlayer_MediaEnded;
|
||||
mediaPlayer.MediaFailed -= MediaPlayer_MediaFailed;
|
||||
mediaPlayer.VolumeChanged -= MediaPlayer_VolumeChanged;
|
||||
mediaPlayer.IsMutedChanged -= MediaPlayer_IsMutedChanged;
|
||||
|
||||
// PlaybackSession Events
|
||||
mediaPlayer.PlaybackSession.BufferingEnded -= MediaPlayer_PlaybackSession_BufferingEnded;
|
||||
mediaPlayer.PlaybackSession.BufferingProgressChanged -= MediaPlayer_PlaybackSession_BufferingProgressChanged;
|
||||
mediaPlayer.PlaybackSession.BufferingStarted -= MediaPlayer_PlaybackSession_BufferingStarted;
|
||||
mediaPlayer.PlaybackSession.DownloadProgressChanged -= MediaPlayer_PlaybackSession_DownloadProgressChanged;
|
||||
mediaPlayer.PlaybackSession.NaturalDurationChanged -= MediaPlayer_PlaybackSession_NaturalDurationChanged;
|
||||
mediaPlayer.PlaybackSession.NaturalVideoSizeChanged -= MediaPlayer_PlaybackSession_NaturalVideoSizeChanged;
|
||||
mediaPlayer.PlaybackSession.PlaybackRateChanged -= MediaPlayer_PlaybackSession_PlaybackRateChanged;
|
||||
mediaPlayer.PlaybackSession.PlaybackStateChanged -= MediaPlayer_PlaybackSession_PlaybackStateChanged;
|
||||
mediaPlayer.PlaybackSession.SeekCompleted -= MediaPlayer_PlaybackSession_SeekCompleted;
|
||||
}
|
||||
|
||||
private void MediaPlayer_SourceChanged(MediaPlayer sender, object args)
|
||||
{
|
||||
Log("mediaPlayer.SourceChanged");
|
||||
}
|
||||
private void MediaPlayer_MediaOpened(MediaPlayer sender, object args)
|
||||
{
|
||||
Log($"MediaPlayer_MediaOpened, Duration: {sender.PlaybackSession.NaturalDuration}");
|
||||
}
|
||||
private void MediaPlayer_MediaEnded(MediaPlayer sender, object args)
|
||||
{
|
||||
Log("MediaPlayer_MediaEnded");
|
||||
}
|
||||
private void MediaPlayer_MediaFailed(MediaPlayer sender, MediaPlayerFailedEventArgs args)
|
||||
{
|
||||
Log($"MediaPlayer_MediaFailed Error: {args.Error}, ErrorMessage: {args.ErrorMessage}, ExtendedErrorCode.Message: {args.ExtendedErrorCode.Message}");
|
||||
}
|
||||
private void MediaPlayer_VolumeChanged(MediaPlayer sender, object args)
|
||||
{
|
||||
Log($"MediaPlayer_VolumeChanged, Volume: {sender.Volume}");
|
||||
}
|
||||
private void MediaPlayer_IsMutedChanged(MediaPlayer sender, object args)
|
||||
{
|
||||
Log($"MediaPlayer_IsMutedChanged, IsMuted={sender.IsMuted}");
|
||||
}
|
||||
// PlaybackSession Events
|
||||
private void MediaPlayer_PlaybackSession_BufferingEnded(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log("PlaybackSession_BufferingEnded");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_BufferingProgressChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_BufferingProgressChanged, BufferingProgress: {sender.BufferingProgress}");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_BufferingStarted(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log("PlaybackSession_BufferingStarted");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_DownloadProgressChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_DownloadProgressChanged, DownloadProgress: {sender.DownloadProgress}");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_NaturalDurationChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_NaturalDurationChanged, NaturalDuration: {sender.NaturalDuration}");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_NaturalVideoSizeChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_NaturalVideoSizeChanged, NaturalVideoWidth: {sender.NaturalVideoWidth}, NaturalVideoHeight: {sender.NaturalVideoHeight}");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_PlaybackRateChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_PlaybackRateChanged, PlaybackRate: {sender.PlaybackRate}");
|
||||
}
|
||||
private void MediaPlayer_PlaybackSession_PlaybackStateChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_PlaybackStateChanged, PlaybackState: {sender.PlaybackState}");
|
||||
}
|
||||
// private void MediaPlayer_PlaybackSession.PositionChanged(MediaPlaybackSession sender, object args)
|
||||
// {
|
||||
// LogOnUI("PlaybackSession_PositionChanged, Position: " + sender.Position);
|
||||
// }
|
||||
|
||||
private void MediaPlayer_PlaybackSession_SeekCompleted(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_SeekCompleted, Position: {sender.Position}");
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MediaSource Event Handlers
|
||||
private void RegisterForMediaSourceEvents(MediaSource source)
|
||||
{
|
||||
source.StateChanged += Source_StateChanged;
|
||||
source.OpenOperationCompleted += Source_OpenOperationCompleted;
|
||||
}
|
||||
|
||||
private void UnregisterForMediaSourceEvents(MediaSource source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
source.StateChanged -= Source_StateChanged;
|
||||
source.OpenOperationCompleted -= Source_OpenOperationCompleted;
|
||||
}
|
||||
|
||||
private void Source_StateChanged(MediaSource sender, MediaSourceStateChangedEventArgs args)
|
||||
{
|
||||
Log($"Source.StateChanged:{args.OldState} to {args.NewState}");
|
||||
}
|
||||
|
||||
private void Source_OpenOperationCompleted(MediaSource sender, MediaSourceOpenOperationCompletedEventArgs args)
|
||||
{
|
||||
// Get the MediaPlaybackItem that corresponds to the MediaSource.
|
||||
MediaPlaybackItem item = MediaPlaybackItem.FindFromMediaSource(sender);
|
||||
if (item != null && item.AudioTracks.Count > 0)
|
||||
{
|
||||
// The MediaPlaybackItem contains additional information about the underlying media.
|
||||
string audioCodec = item.AudioTracks[item.AudioTracks.SelectedIndex].GetEncodingProperties().Subtype;
|
||||
|
||||
// We can read values from the MediaSource.CustomProperties.
|
||||
var uri = (string)sender.CustomProperties["uri"];
|
||||
var contentId = (Guid)sender.CustomProperties["contentId"];
|
||||
Log($"Opened Media Source with Uri: {uri}, ContentId: {contentId}, Codec: {audioCodec}");
|
||||
|
||||
// This extension method in MediaPlaybackItemStringExtensions dumps all the properties from all the tracks.
|
||||
var allProperties = item.ToFormattedString();
|
||||
Log($"MediaPlaybackItem nested properties: {allProperties}");
|
||||
// The AdaptiveMediaSource can manage multiple video tracks internally,
|
||||
// but only a single video track is exposed in the MediaPlaybackItem, not a collection.
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MediaPlaybackItem Event Handlers
|
||||
|
||||
private void RegisterForMediaPlaybackItemEvents(MediaPlaybackItem item)
|
||||
{
|
||||
item.AudioTracks.SelectedIndexChanged += AudioTracks_SelectedIndexChanged;
|
||||
item.AudioTracksChanged += Item_AudioTracksChanged;
|
||||
item.VideoTracksChanged += Item_VideoTracksChanged;
|
||||
item.TimedMetadataTracksChanged += Item_TimedMetadataTracksChanged;
|
||||
}
|
||||
|
||||
private void UnregisterForMediaPlaybackItemEvents(MediaPlaybackItem item)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
item.AudioTracks.SelectedIndexChanged -= AudioTracks_SelectedIndexChanged;
|
||||
item.AudioTracksChanged -= Item_AudioTracksChanged;
|
||||
item.VideoTracksChanged -= Item_VideoTracksChanged;
|
||||
item.TimedMetadataTracksChanged -= Item_TimedMetadataTracksChanged;
|
||||
foreach (AudioTrack audioTrack in item.AudioTracks)
|
||||
{
|
||||
audioTrack.OpenFailed -= AudioTrack_OpenFailed;
|
||||
}
|
||||
foreach (VideoTrack videoTrack in item.VideoTracks)
|
||||
{
|
||||
videoTrack.OpenFailed -= VideoTrack_OpenFailed;
|
||||
}
|
||||
}
|
||||
|
||||
private void AudioTracks_SelectedIndexChanged(ISingleSelectMediaTrackList sender, object args)
|
||||
{
|
||||
MediaPlaybackAudioTrackList list = sender as MediaPlaybackAudioTrackList;
|
||||
AudioTrack audioTrack = list[sender.SelectedIndex];
|
||||
MediaPlaybackItem mpItem = audioTrack.PlaybackItem;
|
||||
var contentId = (Guid)mpItem.Source.CustomProperties["contentId"];
|
||||
string audioCodec = audioTrack.GetEncodingProperties().Subtype;
|
||||
var msg = $"The newly selected audio track of {contentId} has Codec {audioCodec}";
|
||||
var language = audioTrack.Language;
|
||||
if (!String.IsNullOrEmpty(language))
|
||||
{
|
||||
// Transform the language code into a UI-localized language name.
|
||||
msg += ", Language: " + (new Language(language)).DisplayName;
|
||||
}
|
||||
Log(msg);
|
||||
}
|
||||
|
||||
private void Item_AudioTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
|
||||
{
|
||||
Log($"item.AudioTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.AudioTracks.Count}");
|
||||
|
||||
switch (args.CollectionChange)
|
||||
{
|
||||
case CollectionChange.Reset:
|
||||
foreach (AudioTrack track in sender.AudioTracks)
|
||||
{
|
||||
// Tracks are added once as a source discovers them in the source media.
|
||||
// This occurs prior to the track media being opened.
|
||||
// Register here so that we can receive the Track.OpenFailed event.
|
||||
track.OpenFailed += AudioTrack_OpenFailed;
|
||||
}
|
||||
break;
|
||||
case CollectionChange.ItemInserted:
|
||||
// Additional tracks added after loading the main source should be registered here.
|
||||
AudioTrack newTrack = sender.AudioTracks[(int)args.Index];
|
||||
newTrack.OpenFailed += AudioTrack_OpenFailed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Item_VideoTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
|
||||
{
|
||||
Log($"item.VideoTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.VideoTracks.Count}");
|
||||
|
||||
switch (args.CollectionChange)
|
||||
{
|
||||
case CollectionChange.Reset:
|
||||
foreach (VideoTrack track in sender.VideoTracks)
|
||||
{
|
||||
track.OpenFailed += VideoTrack_OpenFailed;
|
||||
}
|
||||
break;
|
||||
case CollectionChange.ItemInserted:
|
||||
VideoTrack newTrack = sender.VideoTracks[(int)args.Index];
|
||||
newTrack.OpenFailed += VideoTrack_OpenFailed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Item_TimedMetadataTracksChanged(MediaPlaybackItem sender, IVectorChangedEventArgs args)
|
||||
{
|
||||
Log($"item.TimedMetadataTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.TimedMetadataTracks.Count}");
|
||||
|
||||
// This is the proper time to register for timed metadata Events the app cares to consume.
|
||||
// See the Metadata scenario for more details.
|
||||
}
|
||||
|
||||
private void AudioTrack_OpenFailed(AudioTrack sender, AudioTrackOpenFailedEventArgs args)
|
||||
{
|
||||
Log($"AudioTrack.OpenFailed: ExtendedError:{args.ExtendedError} DecoderStatus:{sender.SupportInfo.DecoderStatus} MediaSourceStatus:{sender.SupportInfo.MediaSourceStatus}");
|
||||
}
|
||||
|
||||
private void VideoTrack_OpenFailed(VideoTrack sender, VideoTrackOpenFailedEventArgs args)
|
||||
{
|
||||
Log($"VideoTrack.OpenFailed: ExtendedError:{args.ExtendedError} DecoderStatus:{sender.SupportInfo.DecoderStatus} MediaSourceStatus:{sender.SupportInfo.MediaSourceStatus}");
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region AdaptiveMediaSource Event Handlers
|
||||
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
adaptiveMediaSource.DownloadRequested += DownloadRequested;
|
||||
adaptiveMediaSource.DownloadFailed += DownloadFailed;
|
||||
adaptiveMediaSource.DownloadCompleted += DownloadCompleted;
|
||||
adaptiveMediaSource.DownloadBitrateChanged += DownloadBitrateChanged;
|
||||
adaptiveMediaSource.PlaybackBitrateChanged += PlaybackBitrateChanged;
|
||||
}
|
||||
|
||||
private void UnregisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
adaptiveMediaSource.DownloadRequested -= DownloadRequested;
|
||||
adaptiveMediaSource.DownloadFailed -= DownloadFailed;
|
||||
adaptiveMediaSource.DownloadCompleted -= DownloadCompleted;
|
||||
adaptiveMediaSource.DownloadBitrateChanged -= DownloadBitrateChanged;
|
||||
adaptiveMediaSource.PlaybackBitrateChanged -= PlaybackBitrateChanged;
|
||||
}
|
||||
|
||||
private void VerboseLog_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
verbose = (sender as CheckBox).IsChecked.Value;
|
||||
}
|
||||
|
||||
private bool verbose = false;
|
||||
private void DownloadRequested(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadRequestedEventArgs args)
|
||||
{
|
||||
if (verbose)
|
||||
if (adaptiveMediaSource != null)
|
||||
{
|
||||
Log($"DownloadRequested: {args.ResourceType}, {args.ResourceUri}");
|
||||
adaptiveMediaSource.DownloadBitrateChanged -= DownloadBitrateChanged;
|
||||
adaptiveMediaSource.PlaybackBitrateChanged -= PlaybackBitrateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadFailed(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadFailedEventArgs args)
|
||||
{
|
||||
Log($"DownloadFailed: {args.HttpResponseMessage}, {args.ResourceType}, {args.ResourceUri}");
|
||||
}
|
||||
|
||||
private void DownloadCompleted(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadCompletedEventArgs args)
|
||||
{
|
||||
if (verbose)
|
||||
{
|
||||
Log($"DownloadCompleted: {args.ResourceType}, {args.ResourceUri}");
|
||||
}
|
||||
// You can get a copy of the http response bytes for additional processing.
|
||||
// Note that the AdaptiveMediaSource has already consumed these bytes. Modifying them has no effect.
|
||||
// If you need to modify the request or send specific bytes to AdaptiveMediaSource, do so in
|
||||
// DownloadRequested. See the RequestModification scenario for more details.
|
||||
// var buffer = await args.HttpResponseMessage.Content.ReadAsBufferAsync();
|
||||
}
|
||||
|
||||
private async void DownloadBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadBitrateChangedEventArgs args)
|
||||
{
|
||||
uint downloadBitrate = args.NewValue;
|
||||
|
@ -518,37 +235,39 @@ namespace SDKTemplate
|
|||
|
||||
private async Task UpdateDownloadBitrateAsync(uint downloadBitrate)
|
||||
{
|
||||
Log($"DownloadBitrateChanged: {downloadBitrate}");
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
|
||||
{
|
||||
iconDownloadBitrate.Symbol = bitrateHelper.GetBitrateSymbol(downloadBitrate);
|
||||
txtDownloadBitrate.Text = downloadBitrate.ToString();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
private async void PlaybackBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourcePlaybackBitrateChangedEventArgs args)
|
||||
{
|
||||
uint playbackBitrate = args.NewValue;
|
||||
await UpdatePlaybackBitrate(playbackBitrate);
|
||||
await UpdatePlaybackBitrateAsync(playbackBitrate);
|
||||
}
|
||||
|
||||
private async Task UpdatePlaybackBitrate(uint playbackBitrate)
|
||||
private async Task UpdatePlaybackBitrateAsync(uint playbackBitrate)
|
||||
{
|
||||
Log($"PlaybackBitrateChanged: {playbackBitrate}");
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
|
||||
{
|
||||
iconPlaybackBitrate.Symbol = bitrateHelper.GetBitrateSymbol(playbackBitrate);
|
||||
txtPlaybackBitrate.Text = playbackBitrate.ToString();
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Utilities
|
||||
private void Log(string message)
|
||||
{
|
||||
LoggerControl.Log(message);
|
||||
}
|
||||
MediaPlayerLogger mediaPlayerLogger;
|
||||
MediaSourceLogger mediaSourceLogger;
|
||||
MediaPlaybackItemLogger mediaPlaybackItemLogger;
|
||||
AdaptiveMediaSourceLogger adaptiveMediaSourceLogger;
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:local="using:SDKTemplate.Controls"
|
||||
xmlns:logging="using:SDKTemplate.Logging"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
@ -39,10 +40,8 @@
|
|||
This scenario also imposes bandwidth restriction based on the HDCP protection level.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,10,0,0">
|
||||
<Button x:Name="Load" Content="Load Id:" Click="Load_Click" Margin="10,0,0,0"/>
|
||||
<ComboBox x:Name="SelectedContent" />
|
||||
</StackPanel>
|
||||
<local:ContentSelector x:Name="ContentSelectorControl"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel x:Name="AzureAuthorizationMethodPanel" Margin="5,5">
|
||||
<RadioButton x:Name="RadioButtonNone" GroupName="AzureMethod" Content="None" Tag="None" Click="AzureMethodSelected_Click" />
|
||||
|
@ -62,6 +61,6 @@
|
|||
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
|
||||
|
||||
<local:Logger x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
<logging:LogView x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
//*********************************************************
|
||||
|
||||
using SDKTemplate.Helpers;
|
||||
using SDKTemplate.Models;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
@ -18,8 +18,10 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Windows.Foundation;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.Media.Protection;
|
||||
using Windows.Media.Streaming.Adaptive;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
|
@ -35,6 +37,10 @@ namespace SDKTemplate
|
|||
/// scenario for patterns that can be used to clean up.
|
||||
public sealed partial class Scenario3_RequestModification : Page
|
||||
{
|
||||
|
||||
private AzureKeyAcquisitionMethod tokenMethod;
|
||||
private CancellationTokenSource ctsForAppHttpClientForKeys = new CancellationTokenSource();
|
||||
|
||||
public Scenario3_RequestModification()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
@ -42,28 +48,60 @@ namespace SDKTemplate
|
|||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ctsForAppHttpClientForKeys.Cancel(); // Cancel any HTTP requests the app was making.
|
||||
adaptiveMS = null;
|
||||
var mp = mediaPlayerElement.MediaPlayer;
|
||||
if (mp != null)
|
||||
// Cancel any HTTP requests the app was making:
|
||||
ctsForAppHttpClientForKeys.Cancel();
|
||||
|
||||
// Release handles on various media objects to ensure a quick clean-up
|
||||
ContentSelectorControl.MediaPlaybackItem = null;
|
||||
var mediaPlayer = mediaPlayerElement.MediaPlayer;
|
||||
if (mediaPlayer != null)
|
||||
{
|
||||
mp.DisposeSource();
|
||||
mediaPlayerLogger?.Dispose();
|
||||
mediaPlayerLogger = null;
|
||||
|
||||
UnregisterHandlers(mediaPlayer);
|
||||
|
||||
mediaPlayer.DisposeSource();
|
||||
mediaPlayerElement.SetMediaPlayer(null);
|
||||
mp.Dispose();
|
||||
mediaPlayer.Dispose();
|
||||
}
|
||||
|
||||
// We will clean up HDCP explicitly, this ensures the OutputProtectionManager
|
||||
// does not have to continue to impose our policy until the Garbage Collector
|
||||
// cleans the object.
|
||||
// We clean up HDCP explicitly. Otherwise, the OutputProtectionManager
|
||||
// will continue to impose our policy until it is finalized by the
|
||||
// garbage collector.
|
||||
hdcpSession?.Dispose();
|
||||
hdcpSession = null;
|
||||
}
|
||||
|
||||
AdaptiveContentModel adaptiveContentModel;
|
||||
private void UnregisterHandlers(MediaPlayer mediaPlayer)
|
||||
{
|
||||
AdaptiveMediaSource adaptiveMediaSource = null;
|
||||
MediaPlaybackItem mpItem = mediaPlayer.Source as MediaPlaybackItem;
|
||||
if (mpItem != null)
|
||||
{
|
||||
adaptiveMediaSource = mpItem.Source.AdaptiveMediaSource;
|
||||
}
|
||||
MediaSource source = mediaPlayer.Source as MediaSource;
|
||||
if (source != null)
|
||||
{
|
||||
adaptiveMediaSource = source.AdaptiveMediaSource;
|
||||
}
|
||||
|
||||
mediaPlaybackItemLogger?.Dispose();
|
||||
mediaPlaybackItemLogger = null;
|
||||
|
||||
mediaSourceLogger?.Dispose();
|
||||
mediaSourceLogger = null;
|
||||
|
||||
adaptiveMediaSourceLogger?.Dispose();
|
||||
adaptiveMediaSourceLogger = null;
|
||||
|
||||
UnregisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
}
|
||||
|
||||
AddAuthorizationHeaderFilter httpClientFilter;
|
||||
HdcpSession hdcpSession;
|
||||
AdaptiveMediaSource adaptiveMS;
|
||||
|
||||
AdaptiveMediaSource adaptiveMediaSource;
|
||||
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
@ -76,54 +114,62 @@ namespace SDKTemplate
|
|||
{
|
||||
// After a change, impose a maximum bitrate based on the actual protection level.
|
||||
HdcpProtection? protection = session.GetEffectiveProtection();
|
||||
SetMaxBitrateForProtectionLevel(protection, adaptiveMS);
|
||||
SetMaxBitrateForProtectionLevel(protection, adaptiveMediaSource);
|
||||
};
|
||||
|
||||
// Choose a default content, and tell the user that some content IDs
|
||||
// require an authorization mode. Filter out the PlayReady content
|
||||
// because this scenario does not support PlayReady.
|
||||
SelectedContent.ItemsSource = MainPage.ContentManagementSystemStub.Where(model => !model.PlayReady);
|
||||
SelectedContent.SelectedItem = MainPage.FindContentById(13);
|
||||
// Explicitly create the instance of MediaPlayer if you need to register for its events
|
||||
// (like MediaOpened / MediaFailed) prior to setting an IMediaPlaybackSource.
|
||||
var mediaPlayer = new MediaPlayer();
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlayer:
|
||||
mediaPlayerLogger = new MediaPlayerLogger(LoggerControl, mediaPlayer);
|
||||
|
||||
mediaPlayerElement.SetMediaPlayer(mediaPlayer);
|
||||
|
||||
ContentSelectorControl.Initialize(
|
||||
mediaPlayer,
|
||||
MainPage.ContentManagementSystemStub.Where(m =>!m.PlayReady),
|
||||
null,
|
||||
LoggerControl,
|
||||
LoadSourceFromUriAsync);
|
||||
|
||||
ContentSelectorControl.HideLoadUri(); // Avoid free text URIs for this scenario.
|
||||
|
||||
// Initialize tokenMethod based on the default selected radio button.
|
||||
var defaultRadioButton = AzureAuthorizationMethodPanel.Children.OfType<RadioButton>().First(button => button.IsChecked.Value);
|
||||
Enum.TryParse((string)defaultRadioButton.Tag, out tokenMethod);
|
||||
|
||||
Log("Content Id 13 and 14 require that you choose an authorization method.");
|
||||
ContentSelectorControl.SetSelectedModel(MainPage.ContentManagementSystemStub.Where(m => m.Id == 13).FirstOrDefault());
|
||||
}
|
||||
|
||||
private async void Load_Click(object sender, RoutedEventArgs e)
|
||||
|
||||
#region Content Loading
|
||||
|
||||
private async Task<MediaPlaybackItem> LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
adaptiveContentModel = (AdaptiveContentModel)SelectedContent.SelectedItem;
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
if (tokenMethod == AzureKeyAcquisitionMethod.AuthorizationHeader)
|
||||
{
|
||||
if (ContentSelectorControl.SelectedModel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// Use an IHttpFilter to identify key request URIs and insert an Authorization header with the Bearer token.
|
||||
var baseProtocolFilter = new HttpBaseProtocolFilter();
|
||||
baseProtocolFilter.CacheControl.WriteBehavior = HttpCacheWriteBehavior.NoCache; // Always set WriteBehavior = NoCache
|
||||
httpClientFilter = new AddAuthorizationHeaderFilter(baseProtocolFilter);
|
||||
httpClientFilter.AuthorizationHeader = new HttpCredentialsHeaderValue("Bearer", adaptiveContentModel.AesToken);
|
||||
var httpClient = new HttpClient(httpClientFilter);
|
||||
httpClientFilter.AuthorizationHeader = new HttpCredentialsHeaderValue("Bearer", ContentSelectorControl.SelectedModel.AesToken);
|
||||
httpClient = new HttpClient(httpClientFilter);
|
||||
|
||||
// Here is where you can add any required custom CDN headers.
|
||||
httpClient.DefaultRequestHeaders.Append("X-HeaderKey", "HeaderValue");
|
||||
// NOTE: It is not recommended to set Authorization headers needed for key request on the
|
||||
// default headers of the HttpClient, as these will also be used on non-HTTPS calls
|
||||
// for media segments and manifests -- and thus will be easily visible.
|
||||
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri, httpClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
}
|
||||
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
DescriptionText.Visibility = (ActualHeight < 650) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
private async Task LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
AdaptiveMediaSourceCreationResult result = null;
|
||||
if (httpClient != null)
|
||||
|
@ -135,39 +181,76 @@ namespace SDKTemplate
|
|||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
|
||||
}
|
||||
|
||||
MediaSource source;
|
||||
if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
|
||||
{
|
||||
adaptiveMS = result.MediaSource;
|
||||
adaptiveMediaSource = result.MediaSource;
|
||||
|
||||
// Register for events before setting the IMediaPlaybackSource
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMS);
|
||||
// We use a helper class that logs all the events for the AdaptiveMediaSource:
|
||||
adaptiveMediaSourceLogger = new AdaptiveMediaSourceLogger(LoggerControl, adaptiveMediaSource);
|
||||
|
||||
// In addition to logging, we use the callbacks to update some UI elements in this scenario:
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
|
||||
// At this point, we have read the manifest of the media source, and all bitrates are known.
|
||||
// Now that we have bitrates, attempt to cap them based on HdcpProtection.
|
||||
HdcpProtection? protection = hdcpSession.GetEffectiveProtection();
|
||||
SetMaxBitrateForProtectionLevel(protection, adaptiveMS);
|
||||
SetMaxBitrateForProtectionLevel(protection, adaptiveMediaSource);
|
||||
|
||||
MediaSource source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMS);
|
||||
source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource);
|
||||
|
||||
// Note that in this sample with very few event handlers, we are creating neither
|
||||
// a MediaPlayer nor a MediaPlaybackItem. The MediaPlayer will be created implicitly
|
||||
// by the mpElement, which will also manage its lifetime.
|
||||
|
||||
mediaPlayerElement.Source = source;
|
||||
// You can now access mpElement.MediaPlayer, but it is too late to register
|
||||
// to handle its MediaOpened event.
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Error creating the AdaptiveMediaSource: {result.Status}");
|
||||
Log($"Error creating the AdaptiveMediaSource. Status: {result.Status}, ExtendedError.Message: {result.ExtendedError.Message}, ExtendedError.HResult: {result.ExtendedError.HResult.ToString("X8")}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// We use a helper class that logs all the events for the MediaSource:
|
||||
mediaSourceLogger = new MediaSourceLogger(LoggerControl, source);
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties["uri"] = uri.ToString();
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties["contentId"] = Guid.NewGuid().ToString();
|
||||
|
||||
var mpItem = new MediaPlaybackItem(source);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlaybackItem:
|
||||
mediaPlaybackItemLogger = new MediaPlaybackItemLogger(LoggerControl, mpItem);
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
|
||||
return mpItem;
|
||||
}
|
||||
|
||||
private async void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region AdaptiveMediaSource Event Handlers
|
||||
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource aMS)
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
aMS.DownloadRequested += DownloadRequested;
|
||||
aMS.DownloadFailed += DownloadFailed;
|
||||
adaptiveMediaSource.DownloadRequested += DownloadRequested;
|
||||
adaptiveMediaSource.DownloadFailed += DownloadFailed;
|
||||
}
|
||||
|
||||
private void UnregisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
if (adaptiveMediaSource != null)
|
||||
{
|
||||
adaptiveMediaSource.DownloadRequested -= DownloadRequested;
|
||||
adaptiveMediaSource.DownloadFailed -= DownloadFailed;
|
||||
}
|
||||
}
|
||||
|
||||
private async void DownloadRequested(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadRequestedEventArgs args)
|
||||
|
@ -201,7 +284,7 @@ namespace SDKTemplate
|
|||
|
||||
private void ModifyKeyRequestUri(AdaptiveMediaSourceDownloadRequestedEventArgs args)
|
||||
{
|
||||
if (adaptiveContentModel == null)
|
||||
if (ContentSelectorControl.SelectedModel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -211,14 +294,14 @@ namespace SDKTemplate
|
|||
// To change an segment request into a byte-range Uri into another resource
|
||||
|
||||
// Add the Bearer token to the Uri and modify the args.Result.ResourceUri
|
||||
string armoredAuthToken = System.Net.WebUtility.UrlEncode("Bearer=" + adaptiveContentModel.AesToken);
|
||||
string armoredAuthToken = System.Net.WebUtility.UrlEncode("Bearer=" + ContentSelectorControl.SelectedModel.AesToken);
|
||||
string uriWithTokenParameter = $"{args.ResourceUri.AbsoluteUri}&token={armoredAuthToken}";
|
||||
args.Result.ResourceUri = new Uri(uriWithTokenParameter);
|
||||
}
|
||||
|
||||
private async Task AppDownloadedKeyRequest(AdaptiveMediaSourceDownloadRequestedEventArgs args)
|
||||
{
|
||||
if (adaptiveContentModel == null)
|
||||
if (ContentSelectorControl.SelectedModel == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -235,7 +318,7 @@ namespace SDKTemplate
|
|||
try
|
||||
{
|
||||
var appHttpClientForKeys = new HttpClient();
|
||||
appHttpClientForKeys.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Bearer", adaptiveContentModel.AesToken);
|
||||
appHttpClientForKeys.DefaultRequestHeaders.Authorization = new HttpCredentialsHeaderValue("Bearer", ContentSelectorControl.SelectedModel.AesToken);
|
||||
|
||||
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, args.ResourceUri);
|
||||
|
||||
|
@ -293,7 +376,9 @@ namespace SDKTemplate
|
|||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region AzureKeyAcquisitionMethod
|
||||
|
||||
enum AzureKeyAcquisitionMethod
|
||||
{
|
||||
None,
|
||||
|
@ -301,8 +386,6 @@ namespace SDKTemplate
|
|||
UrlQueryParameter,
|
||||
ApplicationDownloaded,
|
||||
}
|
||||
private AzureKeyAcquisitionMethod tokenMethod;
|
||||
private CancellationTokenSource ctsForAppHttpClientForKeys = new CancellationTokenSource();
|
||||
|
||||
private void AzureMethodSelected_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
|
@ -315,6 +398,7 @@ namespace SDKTemplate
|
|||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region HdcpDesiredMinimumProtection
|
||||
|
||||
/// <summary>
|
||||
|
@ -344,51 +428,60 @@ namespace SDKTemplate
|
|||
/// </summary>
|
||||
/// <param name="protection">Protection level to use when imposing bandwidth restriction.</param>
|
||||
/// <param name="ams">AdaptiveMediaSource on which to impose restrictions</param>
|
||||
private void SetMaxBitrateForProtectionLevel(HdcpProtection? protection, AdaptiveMediaSource ams)
|
||||
private async void SetMaxBitrateForProtectionLevel(HdcpProtection? protection, AdaptiveMediaSource ams)
|
||||
{
|
||||
EffectiveHdcpProtectionText.Text = protection.ToString();
|
||||
|
||||
if (ams != null && ams.AvailableBitrates.Count > 1)
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
// Get a sorted list of available bitrates.
|
||||
var bitrates = new List<uint>(ams.AvailableBitrates);
|
||||
bitrates.Sort();
|
||||
EffectiveHdcpProtectionText.Text = protection.ToString();
|
||||
|
||||
// Apply maximum bitrate policy based on a fictitious content publisher's rules.
|
||||
switch (protection)
|
||||
if (ams != null && ams.AvailableBitrates.Count > 1)
|
||||
{
|
||||
case HdcpProtection.OnWithTypeEnforcement:
|
||||
// Allow full bitrate.
|
||||
ams.DesiredMaxBitrate = bitrates[bitrates.Count - 1];
|
||||
DesiredMaxBitrateText.Text = "full bitrate allowed";
|
||||
break;
|
||||
case HdcpProtection.On:
|
||||
// When there is no HDCP Type 1, make the highest bitrate unavailable.
|
||||
ams.DesiredMaxBitrate = bitrates[bitrates.Count - 2];
|
||||
DesiredMaxBitrateText.Text = "highest bitrate is unavailable";
|
||||
break;
|
||||
case HdcpProtection.Off:
|
||||
case null:
|
||||
default:
|
||||
// When there is no HDCP at all (Off), or the system is still trying to determine what
|
||||
// HDCP protection level to apply (null), then make only the lowest bitrate available.
|
||||
ams.DesiredMaxBitrate = bitrates[0];
|
||||
DesiredMaxBitrateText.Text = "lowest bitrate only";
|
||||
break;
|
||||
// Get a sorted list of available bitrates.
|
||||
var bitrates = new List<uint>(ams.AvailableBitrates);
|
||||
bitrates.Sort();
|
||||
|
||||
// Apply maximum bitrate policy based on a fictitious content publisher's rules.
|
||||
switch (protection)
|
||||
{
|
||||
case HdcpProtection.OnWithTypeEnforcement:
|
||||
// Allow full bitrate.
|
||||
ams.DesiredMaxBitrate = bitrates[bitrates.Count - 1];
|
||||
DesiredMaxBitrateText.Text = "full bitrate allowed";
|
||||
break;
|
||||
case HdcpProtection.On:
|
||||
// When there is no HDCP Type 1, make the highest bitrate unavailable.
|
||||
ams.DesiredMaxBitrate = bitrates[bitrates.Count - 2];
|
||||
DesiredMaxBitrateText.Text = "highest bitrate is unavailable";
|
||||
break;
|
||||
case HdcpProtection.Off:
|
||||
case null:
|
||||
default:
|
||||
// When there is no HDCP at all (Off), or the system is still trying to determine what
|
||||
// HDCP protection level to apply (null), then make only the lowest bitrate available.
|
||||
ams.DesiredMaxBitrate = bitrates[0];
|
||||
DesiredMaxBitrateText.Text = "lowest bitrate only";
|
||||
break;
|
||||
}
|
||||
Log($"Imposed DesiredMaxBitrate={ams.DesiredMaxBitrate} for HdcpProtection.{protection}");
|
||||
}
|
||||
Log($"Imposed DesiredMaxBitrate={ams.DesiredMaxBitrate} for HdcpProtection.{protection}");
|
||||
}
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Utilities
|
||||
private void Log(string message)
|
||||
{
|
||||
LoggerControl.Log(message);
|
||||
}
|
||||
MediaPlayerLogger mediaPlayerLogger;
|
||||
MediaSourceLogger mediaSourceLogger;
|
||||
MediaPlaybackItemLogger mediaPlaybackItemLogger;
|
||||
AdaptiveMediaSourceLogger adaptiveMediaSourceLogger;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
#region IHttpFilter to add an authorization header
|
||||
|
||||
public class AddAuthorizationHeaderFilter : IHttpFilter
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:local="using:SDKTemplate.Controls"
|
||||
xmlns:logging="using:SDKTemplate.Logging"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
@ -37,18 +38,9 @@
|
|||
should only be done after extensive testing under a range of network conditions.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5">
|
||||
<Button x:Name="LoadId" Content="Load Id:" Click="LoadId_Click" Margin="0,0,5,0"/>
|
||||
<ComboBox x:Name="SelectedContent"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadUri" Content="Load Uri:" Click="LoadUri_Click" Margin="5,0" />
|
||||
<TextBox x:Name="UriBox" InputScope="Url" HorizontalAlignment="Stretch" Margin="5,0" />
|
||||
</StackPanel>
|
||||
<local:ContentSelector x:Name="ContentSelectorControl"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="SetSource" Content="Set Source" Click="SetSource_Click" Margin="0,0,5,0"/>
|
||||
<SymbolIcon Symbol="Download" ToolTipService.ToolTip="Download bitrate"/>
|
||||
<SymbolIcon Name="iconDownloadBitrate" Symbol="ZeroBars"/>
|
||||
<TextBlock Name="txtDownloadBitrate" Margin="5,0"/>
|
||||
|
@ -87,11 +79,10 @@
|
|||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
|
||||
|
||||
<local:Logger x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
<logging:LogView x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -10,9 +10,8 @@
|
|||
//*********************************************************
|
||||
|
||||
using SDKTemplate.Helpers;
|
||||
using SDKTemplate.Models;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -28,11 +27,13 @@ using Windows.Web.Http;
|
|||
namespace SDKTemplate
|
||||
{
|
||||
/// See the README.md for discussion of this scenario.
|
||||
///
|
||||
/// Note: We register but do not unregister event handlers in this scenario, see the EventHandler
|
||||
/// scenario for patterns that can be used to clean up.
|
||||
|
||||
public sealed partial class Scenario4_Tuning : Page
|
||||
{
|
||||
CancellationTokenSource ctsForInboundBitsPerSecondUiRefresh = new CancellationTokenSource();
|
||||
private AdaptiveMediaSource adaptiveMediaSource;
|
||||
private BitrateHelper bitrateHelper;
|
||||
|
||||
public Scenario4_Tuning()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
|
@ -42,40 +43,68 @@ namespace SDKTemplate
|
|||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
ctsForInboundBitsPerSecondUiRefresh.Cancel(); // Cancel timer
|
||||
adaptiveMS = null; // release app instance of AdaptiveMediaSource
|
||||
mpItem = null; // release app instance of MediaPlaybackItem
|
||||
var mp = mediaPlayerElement.MediaPlayer;
|
||||
if (mp != null)
|
||||
adaptiveMediaSource = null; // release app instance of AdaptiveMediaSource
|
||||
|
||||
// Release handles on various media objects to ensure a quick clean-up
|
||||
ContentSelectorControl.MediaPlaybackItem = null;
|
||||
var mediaPlayer = mediaPlayerElement.MediaPlayer;
|
||||
if (mediaPlayer != null)
|
||||
{
|
||||
mp.DisposeSource();
|
||||
mediaPlayerLogger?.Dispose();
|
||||
mediaPlayerLogger = null;
|
||||
|
||||
UnregisterHandlers(mediaPlayer);
|
||||
|
||||
mediaPlayer.DisposeSource();
|
||||
mediaPlayerElement.SetMediaPlayer(null);
|
||||
mp.Dispose();
|
||||
mediaPlayer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
CancellationTokenSource ctsForInboundBitsPerSecondUiRefresh = new CancellationTokenSource();
|
||||
private AdaptiveContentModel adaptiveContentModel;
|
||||
private AdaptiveMediaSource adaptiveMS;
|
||||
private MediaPlaybackItem mpItem;
|
||||
private BitrateHelper bitrateHelper;
|
||||
private void UnregisterHandlers(MediaPlayer mediaPlayer)
|
||||
{
|
||||
AdaptiveMediaSource adaptiveMediaSource = null;
|
||||
MediaPlaybackItem mpItem = mediaPlayer.Source as MediaPlaybackItem;
|
||||
if (mpItem != null)
|
||||
{
|
||||
adaptiveMediaSource = mpItem.Source.AdaptiveMediaSource;
|
||||
}
|
||||
MediaSource source = mediaPlayer.Source as MediaSource;
|
||||
if (source != null)
|
||||
{
|
||||
adaptiveMediaSource = source.AdaptiveMediaSource;
|
||||
}
|
||||
|
||||
private async void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
mediaPlaybackItemLogger?.Dispose();
|
||||
mediaPlaybackItemLogger = null;
|
||||
|
||||
mediaSourceLogger?.Dispose();
|
||||
mediaSourceLogger = null;
|
||||
|
||||
adaptiveMediaSourceLogger?.Dispose();
|
||||
adaptiveMediaSourceLogger = null;
|
||||
|
||||
UnregisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
}
|
||||
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mediaPlayer = new MediaPlayer();
|
||||
RegisterForMediaPlayerEvents(mediaPlayer);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlayer:
|
||||
mediaPlayerLogger = new MediaPlayerLogger(LoggerControl, mediaPlayer);
|
||||
|
||||
// Ensure we have PlayReady support, if the user enters a DASH/PR Uri in the text box:
|
||||
var prHelper = new PlayReadyHelper(LoggerControl);
|
||||
prHelper.SetUpProtectionManager(mediaPlayer);
|
||||
mediaPlayerElement.SetMediaPlayer(mediaPlayer);
|
||||
|
||||
// Choose a default content.
|
||||
SelectedContent.ItemsSource = MainPage.ContentManagementSystemStub.ToArray();
|
||||
adaptiveContentModel = MainPage.FindContentById(10);
|
||||
SelectedContent.SelectedItem = adaptiveContentModel;
|
||||
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
ContentSelectorControl.Initialize(
|
||||
mediaPlayer,
|
||||
MainPage.ContentManagementSystemStub.Where(m => !m.Aes),
|
||||
null,
|
||||
LoggerControl,
|
||||
LoadSourceFromUriAsync);
|
||||
|
||||
// There is no InboundBitsPerSecondChanged event, so we start a polling thread to update UI.
|
||||
PollForInboundBitsPerSecond(ctsForInboundBitsPerSecondUiRefresh);
|
||||
|
@ -87,11 +116,11 @@ namespace SDKTemplate
|
|||
var refreshRate = TimeSpan.FromSeconds(2);
|
||||
while (!cts.IsCancellationRequested)
|
||||
{
|
||||
if (adaptiveMS != null)
|
||||
if (adaptiveMediaSource != null)
|
||||
{
|
||||
if (InboundBitsPerSecondLast != adaptiveMS.InboundBitsPerSecond)
|
||||
if (InboundBitsPerSecondLast != adaptiveMediaSource.InboundBitsPerSecond)
|
||||
{
|
||||
InboundBitsPerSecondLast = adaptiveMS.InboundBitsPerSecond;
|
||||
InboundBitsPerSecondLast = adaptiveMediaSource.InboundBitsPerSecond;
|
||||
InboundBitsPerSecondText.Text = InboundBitsPerSecondLast.ToString();
|
||||
}
|
||||
}
|
||||
|
@ -102,44 +131,9 @@ namespace SDKTemplate
|
|||
|
||||
#region Content Loading
|
||||
|
||||
private void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
DescriptionText.Visibility = (ActualHeight < 700) ? Visibility.Collapsed : Visibility.Visible;
|
||||
}
|
||||
|
||||
private async void LoadId_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
adaptiveContentModel = (AdaptiveContentModel)SelectedContent.SelectedItem;
|
||||
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
}
|
||||
|
||||
private async void LoadUri_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(UriBox.Text, UriKind.Absolute, out uri))
|
||||
{
|
||||
Log("Malformed Uri in Load text box.");
|
||||
}
|
||||
|
||||
await LoadSourceFromUriAsync(uri);
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
}
|
||||
|
||||
private void SetSource_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// It is at this point that the MediaSource (within a MediaPlaybackItem) will be fully resolved.
|
||||
// For an AdaptiveMediaSource, this is the point at which media is first requested and parsed.
|
||||
mediaPlayerElement.Source = mpItem;
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
}
|
||||
|
||||
private async Task LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
private async Task<MediaPlaybackItem> LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
AdaptiveMediaSourceCreationResult result = null;
|
||||
|
@ -151,50 +145,62 @@ namespace SDKTemplate
|
|||
{
|
||||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
|
||||
}
|
||||
|
||||
MediaSource source;
|
||||
if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
|
||||
{
|
||||
adaptiveMS = result.MediaSource;
|
||||
adaptiveMediaSource = result.MediaSource;
|
||||
|
||||
bitrateHelper = new BitrateHelper(adaptiveMS.AvailableBitrates);
|
||||
InitializeBitrateLists(adaptiveMS);
|
||||
// We use a helper class that logs all the events for the AdaptiveMediaSource:
|
||||
adaptiveMediaSourceLogger = new AdaptiveMediaSourceLogger(LoggerControl, adaptiveMediaSource);
|
||||
|
||||
// In addition to logging, we use the callbacks to update some UI elements in this scenario:
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMediaSource);
|
||||
|
||||
// At this point, we have read the manifest of the media source, and all bitrates are known.
|
||||
await UpdatePlaybackBitrate(adaptiveMS.CurrentPlaybackBitrate);
|
||||
await UpdateDownloadBitrate(adaptiveMS.CurrentDownloadBitrate);
|
||||
bitrateHelper = new BitrateHelper(adaptiveMediaSource.AvailableBitrates);
|
||||
InitializeBitrateLists(adaptiveMediaSource);
|
||||
await UpdatePlaybackBitrateAsync(adaptiveMediaSource.CurrentPlaybackBitrate);
|
||||
await UpdateDownloadBitrateAsync(adaptiveMediaSource.CurrentDownloadBitrate);
|
||||
|
||||
// Register for events before resolving the MediaSource.
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMS);
|
||||
|
||||
MediaSource source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMS);
|
||||
|
||||
// You can save additional information in the CustomPropertySet for future retrieval.
|
||||
// Note: MediaSource.CustomProperties is a ValueSet and therefore can store
|
||||
// only serializable types.
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties.Add("uri", uri.ToString());
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties.Add("contentId", Guid.NewGuid());
|
||||
|
||||
mpItem = new MediaPlaybackItem(source);
|
||||
source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("Error creating the AdaptiveMediaSource: " + result.Status);
|
||||
Log($"Error creating the AdaptiveMediaSource. Status: {result.Status}, ExtendedError.Message: {result.ExtendedError.Message}, ExtendedError.HResult: {result.ExtendedError.HResult.ToString("X8")}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// We use a helper class that logs all the events for the MediaSource:
|
||||
mediaSourceLogger = new MediaSourceLogger(LoggerControl, source);
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties["uri"] = uri.ToString();
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties["contentId"] = Guid.NewGuid().ToString();
|
||||
|
||||
var mpItem = new MediaPlaybackItem(source);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlaybackItem:
|
||||
mediaPlaybackItemLogger = new MediaPlaybackItemLogger(LoggerControl, mpItem);
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
|
||||
return mpItem;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region MediaPlayer Event Handlers
|
||||
private void RegisterForMediaPlayerEvents(MediaPlayer mediaPlayer)
|
||||
private async void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
mediaPlayer.PlaybackSession.NaturalVideoSizeChanged +=
|
||||
(sender, args) => Log("PlaybackSession.NaturalVideoSizeChanged, NaturalVideoWidth: " + sender.NaturalVideoWidth + " NaturalVideoHeight: " + sender.NaturalVideoHeight);
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Adaptive Bitrate control
|
||||
|
||||
private void InitializeBitrateLists(AdaptiveMediaSource aMS)
|
||||
|
@ -228,11 +234,11 @@ namespace SDKTemplate
|
|||
private void InitialBitrateList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var selection = (e.AddedItems.Count > 0) ? (BitrateItem)e.AddedItems[0] : null;
|
||||
if (selection != null && adaptiveMS.InitialBitrate != selection.Bitrate)
|
||||
if (selection != null && adaptiveMediaSource.InitialBitrate != selection.Bitrate)
|
||||
{
|
||||
if (IsValidBitrateCombination(adaptiveMS.DesiredMinBitrate, adaptiveMS.DesiredMaxBitrate, selection.Bitrate.Value))
|
||||
if (IsValidBitrateCombination(adaptiveMediaSource.DesiredMinBitrate, adaptiveMediaSource.DesiredMaxBitrate, selection.Bitrate.Value))
|
||||
{
|
||||
adaptiveMS.InitialBitrate = selection.Bitrate.Value;
|
||||
adaptiveMediaSource.InitialBitrate = selection.Bitrate.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -244,11 +250,11 @@ namespace SDKTemplate
|
|||
private void DesiredMinBitrateList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var selection = (e.AddedItems.Count > 0) ? (BitrateItem)e.AddedItems[0] : null;
|
||||
if (selection != null && adaptiveMS.DesiredMinBitrate != selection.Bitrate)
|
||||
if (selection != null && adaptiveMediaSource.DesiredMinBitrate != selection.Bitrate)
|
||||
{
|
||||
if (IsValidBitrateCombination(selection.Bitrate, adaptiveMS.DesiredMaxBitrate, adaptiveMS.InitialBitrate))
|
||||
if (IsValidBitrateCombination(selection.Bitrate, adaptiveMediaSource.DesiredMaxBitrate, adaptiveMediaSource.InitialBitrate))
|
||||
{
|
||||
adaptiveMS.DesiredMinBitrate = selection.Bitrate;
|
||||
adaptiveMediaSource.DesiredMinBitrate = selection.Bitrate;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -260,11 +266,11 @@ namespace SDKTemplate
|
|||
private void DesiredMaxBitrateList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
var selection = (e.AddedItems.Count > 0) ? (BitrateItem)e.AddedItems[0] : null;
|
||||
if (selection != null && adaptiveMS.DesiredMaxBitrate != selection.Bitrate)
|
||||
if (selection != null && adaptiveMediaSource.DesiredMaxBitrate != selection.Bitrate)
|
||||
{
|
||||
if (IsValidBitrateCombination(adaptiveMS.DesiredMinBitrate, selection.Bitrate, adaptiveMS.InitialBitrate))
|
||||
if (IsValidBitrateCombination(adaptiveMediaSource.DesiredMinBitrate, selection.Bitrate, adaptiveMediaSource.InitialBitrate))
|
||||
{
|
||||
adaptiveMS.DesiredMaxBitrate = selection.Bitrate;
|
||||
adaptiveMediaSource.DesiredMaxBitrate = selection.Bitrate;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -278,7 +284,7 @@ namespace SDKTemplate
|
|||
double ratio;
|
||||
if (double.TryParse(BitrateDowngradeTriggerRatioText.Text, out ratio))
|
||||
{
|
||||
adaptiveMS.AdvancedSettings.BitrateDowngradeTriggerRatio = ratio;
|
||||
adaptiveMediaSource.AdvancedSettings.BitrateDowngradeTriggerRatio = ratio;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -287,34 +293,36 @@ namespace SDKTemplate
|
|||
double ratio;
|
||||
if (double.TryParse(BitrateDowngradeTriggerRatioText.Text, out ratio))
|
||||
{
|
||||
adaptiveMS.AdvancedSettings.DesiredBitrateHeadroomRatio = ratio;
|
||||
adaptiveMediaSource.AdvancedSettings.DesiredBitrateHeadroomRatio = ratio;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region AdaptiveMediaSource Event Handlers
|
||||
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource aMS)
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
aMS.DownloadFailed += DownloadFailed;
|
||||
aMS.DownloadBitrateChanged += DownloadBitrateChanged;
|
||||
aMS.PlaybackBitrateChanged += PlaybackBitrateChanged;
|
||||
adaptiveMediaSource.DownloadBitrateChanged += DownloadBitrateChanged;
|
||||
adaptiveMediaSource.PlaybackBitrateChanged += PlaybackBitrateChanged;
|
||||
}
|
||||
|
||||
private void DownloadFailed(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadFailedEventArgs args)
|
||||
private void UnregisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
Log($"DownloadFailed: {args.HttpResponseMessage}, {args.ResourceType}, {args.ResourceUri}");
|
||||
if (adaptiveMediaSource != null)
|
||||
{
|
||||
adaptiveMediaSource.DownloadBitrateChanged -= DownloadBitrateChanged;
|
||||
adaptiveMediaSource.PlaybackBitrateChanged -= PlaybackBitrateChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private async void DownloadBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadBitrateChangedEventArgs args)
|
||||
{
|
||||
uint downloadBitrate = args.NewValue;
|
||||
await UpdateDownloadBitrate(downloadBitrate);
|
||||
await UpdateDownloadBitrateAsync(downloadBitrate);
|
||||
}
|
||||
|
||||
private async Task UpdateDownloadBitrate(uint downloadBitrate)
|
||||
private async Task UpdateDownloadBitrateAsync(uint downloadBitrate)
|
||||
{
|
||||
Log("DownloadBitrateChanged: " + downloadBitrate);
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
|
||||
{
|
||||
iconDownloadBitrate.Symbol = bitrateHelper.GetBitrateSymbol(downloadBitrate);
|
||||
|
@ -325,12 +333,11 @@ namespace SDKTemplate
|
|||
private async void PlaybackBitrateChanged(AdaptiveMediaSource sender, AdaptiveMediaSourcePlaybackBitrateChangedEventArgs args)
|
||||
{
|
||||
uint playbackBitrate = args.NewValue;
|
||||
await UpdatePlaybackBitrate(playbackBitrate);
|
||||
await UpdatePlaybackBitrateAsync(playbackBitrate);
|
||||
}
|
||||
|
||||
private async Task UpdatePlaybackBitrate(uint playbackBitrate)
|
||||
private async Task UpdatePlaybackBitrateAsync(uint playbackBitrate)
|
||||
{
|
||||
Log("PlaybackBitrateChanged: " + playbackBitrate);
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
|
||||
{
|
||||
iconPlaybackBitrate.Symbol = bitrateHelper.GetBitrateSymbol(playbackBitrate);
|
||||
|
@ -339,14 +346,20 @@ namespace SDKTemplate
|
|||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Utilities
|
||||
private void Log(string message)
|
||||
{
|
||||
LoggerControl.Log(message);
|
||||
}
|
||||
MediaPlayerLogger mediaPlayerLogger;
|
||||
MediaSourceLogger mediaSourceLogger;
|
||||
MediaPlaybackItemLogger mediaPlaybackItemLogger;
|
||||
AdaptiveMediaSourceLogger adaptiveMediaSourceLogger;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Item which provides a nicer display name for "null" bitrate.
|
||||
/// </summary>
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:local="using:SDKTemplate.Controls"
|
||||
xmlns:logging="using:SDKTemplate.Logging"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
@ -28,27 +29,19 @@
|
|||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,10" Orientation="Vertical">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario shows several ways in which the app can consume or create timed metadata.
|
||||
Enter your own HLS manifest URI which contains m3u8 comments or ID3 tags in the TS segments.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadId" Content="Load Id:" Click="LoadId_Click" Margin="5,0"/>
|
||||
<ComboBox x:Name="SelectedContent" Margin="5,0"/>
|
||||
<StackPanel x:Name="DescriptionText">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario shows several ways in which the app can consume or create timed metadata.
|
||||
Enter your own: HLS manifest URI which contains m3u8 comments or ID3 tags in the TS segments;
|
||||
or DASH manifest URI with fMp4 segments that contain emsg boxes (stce35 will be parsed to insert ads).
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadUri" Content="Load Uri:" Click="LoadUri_Click" Margin="5,0" />
|
||||
<TextBox x:Name="UriBox" InputScope="Url" HorizontalAlignment="Stretch" Margin="5,0" />
|
||||
</StackPanel>
|
||||
|
||||
<Button x:Name="SetSource" Content="Set Source" Click="SetSource_Click" Margin="5,5"/>
|
||||
|
||||
<local:ContentSelector x:Name="ContentSelectorControl"/>
|
||||
</StackPanel>
|
||||
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
|
||||
|
||||
<local:Logger x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
<logging:LogView x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//*********************************************************
|
||||
// *********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
|
@ -7,30 +7,29 @@
|
|||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
// *********************************************************
|
||||
|
||||
using SDKTemplate.Helpers;
|
||||
using SDKTemplate.Models;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.Media.Streaming.Adaptive;
|
||||
using Windows.Storage.Streams;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Web.Http;
|
||||
|
||||
using StringBuilder = System.Text.StringBuilder;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
/// See the README.md for discussion of this scenario.
|
||||
///
|
||||
/// Note: We register but do not unregister event handlers in this scenario, see the EventHandler
|
||||
/// scenario for patterns that can be used to clean up.
|
||||
// See the README.md for discussion of this scenario.
|
||||
|
||||
public sealed partial class Scenario5_Metadata : Page
|
||||
{
|
||||
public Scenario5_Metadata()
|
||||
|
@ -40,69 +39,79 @@ namespace SDKTemplate
|
|||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
mpItem = null;
|
||||
var mp = mediaPlayerElement.MediaPlayer;
|
||||
if (mp != null)
|
||||
|
||||
// Release handles on various media objects to ensure a quick clean-up
|
||||
ContentSelectorControl.MediaPlaybackItem = null;
|
||||
var mediaPlayer = mediaPlayerElement.MediaPlayer;
|
||||
if (mediaPlayer != null)
|
||||
{
|
||||
mp.DisposeSource();
|
||||
mediaPlayerLogger?.Dispose();
|
||||
mediaPlayerLogger = null;
|
||||
|
||||
UnregisterHandlers(mediaPlayer);
|
||||
|
||||
mediaPlayer.DisposeSource();
|
||||
mediaPlayerElement.SetMediaPlayer(null);
|
||||
mp.Dispose();
|
||||
mediaPlayer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private AdaptiveContentModel adaptiveContentModel;
|
||||
private MediaPlaybackItem mpItem;
|
||||
private void UnregisterHandlers(MediaPlayer mediaPlayer)
|
||||
{
|
||||
AdaptiveMediaSource adaptiveMediaSource = null;
|
||||
MediaPlaybackItem mpItem = mediaPlayer.Source as MediaPlaybackItem;
|
||||
if (mpItem != null)
|
||||
{
|
||||
adaptiveMediaSource = mpItem.Source.AdaptiveMediaSource;
|
||||
UnregisterForMediaSourceEvents(mpItem.Source);
|
||||
UnregisterForMediaPlaybackItemEvents(mpItem);
|
||||
}
|
||||
MediaSource source = mediaPlayer.Source as MediaSource;
|
||||
if (source != null)
|
||||
{
|
||||
adaptiveMediaSource = source.AdaptiveMediaSource;
|
||||
UnregisterForMediaSourceEvents(source);
|
||||
}
|
||||
|
||||
private async void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
mediaPlaybackItemLogger?.Dispose();
|
||||
mediaPlaybackItemLogger = null;
|
||||
|
||||
mediaSourceLogger?.Dispose();
|
||||
mediaSourceLogger = null;
|
||||
|
||||
adaptiveMediaSourceLogger?.Dispose();
|
||||
adaptiveMediaSourceLogger = null;
|
||||
|
||||
}
|
||||
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mediaPlayer = new MediaPlayer();
|
||||
mediaPlayer.AutoPlay = true;
|
||||
RegisterForMediaPlayerEvents(mediaPlayer);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlayer:
|
||||
mediaPlayerLogger = new MediaPlayerLogger(LoggerControl, mediaPlayer);
|
||||
|
||||
// Ensure we have PlayReady support, in case the user enters a DASH/PR Uri in the text box.
|
||||
var prHelper = new PlayReadyHelper(LoggerControl);
|
||||
prHelper.SetUpProtectionManager(mediaPlayer);
|
||||
|
||||
mediaPlayerElement.SetMediaPlayer(mediaPlayer);
|
||||
|
||||
// Choose a default content.
|
||||
SelectedContent.ItemsSource = MainPage.ContentManagementSystemStub;
|
||||
adaptiveContentModel = MainPage.FindContentById(1);
|
||||
SelectedContent.SelectedItem = adaptiveContentModel;
|
||||
ContentSelectorControl.Initialize(
|
||||
mediaPlayer,
|
||||
MainPage.ContentManagementSystemStub.Where(m => !m.Aes),
|
||||
null,
|
||||
LoggerControl,
|
||||
LoadSourceFromUriAsync);
|
||||
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
ContentSelectorControl.SetAutoPlay(true); // Force AutoPlay in this scenario.
|
||||
}
|
||||
|
||||
|
||||
#region Content Loading
|
||||
|
||||
private async void LoadId_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
adaptiveContentModel = (AdaptiveContentModel)SelectedContent.SelectedItem;
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
}
|
||||
|
||||
private async void LoadUri_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(UriBox.Text, UriKind.Absolute, out uri))
|
||||
{
|
||||
Log("Malformed Uri in Load text box.");
|
||||
}
|
||||
|
||||
await LoadSourceFromUriAsync(uri);
|
||||
}
|
||||
|
||||
private void SetSource_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// It is at this point that the MediaSource (within a MediaPlaybackItem) will be fully resolved.
|
||||
// For an AdaptiveMediaSource, this is the point at which media is first requested and parsed.
|
||||
mediaPlayerElement.Source = mpItem;
|
||||
}
|
||||
|
||||
private async Task LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
private async Task<MediaPlaybackItem> LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
AdaptiveMediaSourceCreationResult result = null;
|
||||
|
@ -114,77 +123,94 @@ namespace SDKTemplate
|
|||
{
|
||||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
|
||||
}
|
||||
|
||||
MediaSource source;
|
||||
if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
|
||||
{
|
||||
var adaptiveMS = result.MediaSource;
|
||||
var adaptiveMediaSource = result.MediaSource;
|
||||
|
||||
// Register for events before resolving the MediaSource.
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMS);
|
||||
// We use a helper class that logs all the events for the AdaptiveMediaSource:
|
||||
adaptiveMediaSourceLogger = new AdaptiveMediaSourceLogger(LoggerControl, adaptiveMediaSource);
|
||||
|
||||
MediaSource source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMS);
|
||||
source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource);
|
||||
|
||||
// You can save additional information in the CustomPropertySet for future retrieval.
|
||||
// Note: MediaSource.CustomProperties is a ValueSet and therefore can store
|
||||
// only serializable types.
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties.Add("uri", uri.ToString());
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties.Add("contentId", Guid.NewGuid());
|
||||
|
||||
RegisterForMediaSourceEvents(source);
|
||||
|
||||
// Register for events before resolving the MediaSource.
|
||||
mpItem = new MediaPlaybackItem(source);
|
||||
RegisterForMediaPlaybackItemEvents(mpItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Error creating the AdaptiveMediaSource: {result.Status}");
|
||||
Log($"Error creating the AdaptiveMediaSource. Status: {result.Status}, ExtendedError.Message: {result.ExtendedError.Message}, ExtendedError.HResult: {result.ExtendedError.HResult.ToString("X8")}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// We use a helper class that logs all the events for the MediaSource:
|
||||
mediaSourceLogger = new MediaSourceLogger(LoggerControl, source);
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties["uri"] = uri.ToString();
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties["contentId"] = Guid.NewGuid().ToString();
|
||||
|
||||
// In addition to logging, this scenario uses MediaSource events:
|
||||
RegisterForMediaSourceEvents(source);
|
||||
|
||||
var mpItem = new MediaPlaybackItem(source);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlaybackItem:
|
||||
mediaPlaybackItemLogger = new MediaPlaybackItemLogger(LoggerControl, mpItem);
|
||||
|
||||
// In addition to logging, this scenario uses MediaPlaybackItem events:
|
||||
RegisterForMediaPlaybackItemEvents(mpItem);
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
|
||||
return mpItem;
|
||||
}
|
||||
|
||||
private async void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MediaPlayer Event Handlers
|
||||
private void RegisterForMediaPlayerEvents(MediaPlayer mediaPlayer)
|
||||
{
|
||||
// Player Events
|
||||
// See the EventHandlers scenario for details on when to unregister the event handlers.
|
||||
mediaPlayer.SourceChanged += (sender, args) => Log("mediaPlayer.SourceChanged");
|
||||
mediaPlayer.MediaOpened += (sender, args) => Log($"MediaPlayer_MediaOpened, Duration: {sender.PlaybackSession.NaturalDuration}");
|
||||
mediaPlayer.MediaEnded += (sender, args) => Log("mediaPlayer.MediaEnded");
|
||||
mediaPlayer.MediaFailed += (sender, args) => Log($"MediaPlayer_MediaFailed Error: {args.Error}, ErrorMessage: {args.ErrorMessage}, ExtendedErrorCode.Message: {args.ExtendedErrorCode.Message}");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MediaSource Event Handlers
|
||||
|
||||
private void RegisterForMediaSourceEvents(MediaSource source)
|
||||
{
|
||||
source.StateChanged += (sender, args) => Log($"Source.StateChanged:{args.OldState} to {args.NewState}");
|
||||
source.OpenOperationCompleted += Source_OpenOperationCompleted;
|
||||
}
|
||||
private void UnregisterForMediaSourceEvents(MediaSource source)
|
||||
{
|
||||
source.OpenOperationCompleted -= Source_OpenOperationCompleted;
|
||||
}
|
||||
|
||||
private void Source_OpenOperationCompleted(MediaSource source, MediaSourceOpenOperationCompletedEventArgs args)
|
||||
{
|
||||
// Here we create our own metadata track.
|
||||
// Our goal is to track progress through the asset and report it back to a server.
|
||||
var contentId = (Guid)source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
var reportingUriFormat = "http://myserver/reporting/{0}?id={1}";
|
||||
//From \Shared\TrackingEventCue.cs :
|
||||
TrackingEventCue.CreateTrackingEventsTrack(source, contentId.ToString(), reportingUriFormat);
|
||||
// From \Shared\TrackingEventCue.cs :
|
||||
TrackingEventCue.CreateTrackingEventsTrack(source, contentId, reportingUriFormat);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region MediaPlaybackItem Event Handlers
|
||||
|
||||
private void RegisterForMediaPlaybackItemEvents(MediaPlaybackItem item)
|
||||
{
|
||||
// If we encountered some unknown tags in an m3u8 manifest,
|
||||
// we might already have metadata tracks in the source,
|
||||
// which is used as the constructor for the MediaPlaybackItem,
|
||||
// therefore, the MediaPlaybackItem may already have metadata tracks.
|
||||
// which is used as the constructor for the MediaPlaybackItem.
|
||||
// Therefore, the MediaPlaybackItem may already have metadata tracks.
|
||||
// Since TracksChanged will not be raised for these it is best to check
|
||||
// if we have tracks, and set up the handlers:
|
||||
if (item.TimedMetadataTracks.Count > 0)
|
||||
|
@ -198,28 +224,41 @@ namespace SDKTemplate
|
|||
}
|
||||
|
||||
// For any tracks found as the content is parsed, we register for the event handler:
|
||||
item.TimedMetadataTracksChanged += (MediaPlaybackItem sender, IVectorChangedEventArgs args) =>
|
||||
{
|
||||
Log($"item.TimedMetadataTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.TimedMetadataTracks.Count}");
|
||||
item.TimedMetadataTracksChanged += Item_TimedMetadataTracksChanged;
|
||||
}
|
||||
|
||||
if (args.CollectionChange == CollectionChange.ItemInserted)
|
||||
private void UnregisterForMediaPlaybackItemEvents(MediaPlaybackItem item)
|
||||
{
|
||||
item.TimedMetadataTracksChanged -= Item_TimedMetadataTracksChanged;
|
||||
foreach (var track in item.TimedMetadataTracks)
|
||||
{
|
||||
UnregisterMetadataHandlers(track);
|
||||
}
|
||||
}
|
||||
|
||||
private void Item_TimedMetadataTracksChanged(MediaPlaybackItem item, IVectorChangedEventArgs args)
|
||||
{
|
||||
Log($"item.TimedMetadataTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{item.TimedMetadataTracks.Count}");
|
||||
|
||||
if (args.CollectionChange == CollectionChange.ItemInserted)
|
||||
{
|
||||
RegisterMetadataHandlers(item, (int)args.Index);
|
||||
}
|
||||
if (args.CollectionChange == CollectionChange.Reset)
|
||||
{
|
||||
for (int index = 0; index < item.TimedMetadataTracks.Count; index++)
|
||||
{
|
||||
RegisterMetadataHandlers(sender, (int)args.Index);
|
||||
RegisterMetadataHandlers(item, index);
|
||||
}
|
||||
if (args.CollectionChange == CollectionChange.Reset)
|
||||
{
|
||||
for (int index = 0; index < item.TimedMetadataTracks.Count; index++)
|
||||
{
|
||||
RegisterMetadataHandlers(item, index);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterMetadataHandlers(MediaPlaybackItem mediaPlaybackItem, int index)
|
||||
{
|
||||
var timedTrack = mediaPlaybackItem.TimedMetadataTracks[index];
|
||||
var contentId = (Guid)mediaPlaybackItem.Source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
mediaPlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
|
||||
StringBuilder logMsg = new StringBuilder($"{contentId} ");
|
||||
|
||||
|
@ -243,6 +282,12 @@ namespace SDKTemplate
|
|||
timedTrack.Label = "ID3 Tags";
|
||||
mediaPlaybackItem.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
|
||||
}
|
||||
else if (string.Equals(dispatchType, "emsg:mp4", StringComparison.OrdinalIgnoreCase)) // For 'emsg' box embedded in mp4 container
|
||||
{
|
||||
timedTrack.CueEntered += metadata_emsg_mp4_CueEntered;
|
||||
timedTrack.Label = "emsg payload";
|
||||
mediaPlaybackItem.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
|
||||
}
|
||||
|
||||
// Check for our Custom TimedMetadataTrack
|
||||
if (mediaPlaybackItem.TimedMetadataTracks[index].Id == "TrackingEvents")
|
||||
|
@ -264,11 +309,35 @@ namespace SDKTemplate
|
|||
Log(logMsg.ToString());
|
||||
}
|
||||
|
||||
private void UnregisterMetadataHandlers(TimedMetadataTrack timedTrack)
|
||||
{
|
||||
if (timedTrack.Label == "HLS Manifest comments")
|
||||
{
|
||||
timedTrack.CueEntered -= metadata_extm3u_CueEntered;
|
||||
}
|
||||
if(timedTrack.Label == "ID3 Tags")
|
||||
{
|
||||
timedTrack.CueEntered -= metadata_id3_CueEntered;
|
||||
}
|
||||
if(timedTrack.Label == "emsg payload")
|
||||
{
|
||||
timedTrack.CueEntered -= metadata_emsg_mp4_CueEntered;
|
||||
}
|
||||
if (timedTrack.Label == "Tracking Events")
|
||||
{
|
||||
timedTrack.CueEntered -= metadata_TrackingEvents_CueEntered;
|
||||
timedTrack.CueExited -= metadata_TrackingEvents_CueExited;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void metadata_extm3u_CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
{
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
|
||||
var contentId = (Guid)timedMetadataTrack.PlaybackItem.Source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
timedMetadataTrack.PlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
logMsg.AppendLine($"{contentId} M3U8 DataCue CueEntered raised.");
|
||||
var dataCue = args.Cue as DataCue;
|
||||
if (dataCue != null && dataCue.Data != null)
|
||||
|
@ -276,11 +345,11 @@ namespace SDKTemplate
|
|||
// The payload is a UTF-16 Little Endian null-terminated string.
|
||||
// It is any comment line in a manifest that is not part of the HLS spec.
|
||||
var dr = DataReader.FromBuffer(dataCue.Data);
|
||||
dr.UnicodeEncoding = UnicodeEncoding.Utf16LE;
|
||||
dr.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
|
||||
var m3u8Comment = dr.ReadString(dataCue.Data.Length / 2 - 1);
|
||||
logMsg.AppendLine($"Label: {timedMetadataTrack.Label}, Id: {dataCue.Id}, StartTime: {dataCue.StartTime}, Duration: {dataCue.Duration}");
|
||||
logMsg.Append(m3u8Comment);
|
||||
// TODO: Use the m3u8Comment string.
|
||||
// TODO: Use the m3u8Comment string for something useful.
|
||||
}
|
||||
Log(logMsg.ToString());
|
||||
}
|
||||
|
@ -288,7 +357,9 @@ namespace SDKTemplate
|
|||
private void metadata_id3_CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
{
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
var contentId = (Guid)timedMetadataTrack.PlaybackItem.Source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
timedMetadataTrack.PlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
logMsg.AppendLine($"{contentId} ID3 DataCue CueEntered raised.");
|
||||
var dataCue = args.Cue as DataCue;
|
||||
if (dataCue != null && dataCue.Data != null && dataCue.Data.Length >= 10)
|
||||
|
@ -301,7 +372,7 @@ namespace SDKTemplate
|
|||
var header_version_minor = dr.ReadByte();
|
||||
var header_flags = dr.ReadByte();
|
||||
var header_tagSize = dr.ReadUInt32();
|
||||
// TODO: Use the ID3 bytes.
|
||||
// TODO: Use the ID3 bytes for something useful.
|
||||
|
||||
logMsg.AppendLine($"Label: {timedMetadataTrack.Label}, Id: {dataCue.Id}, StartTime: {dataCue.StartTime}, Duration: {dataCue.Duration}");
|
||||
logMsg.Append($"{header_ID3}, {header_version_major}.{header_version_minor}, {header_flags}, {header_tagSize}");
|
||||
|
@ -309,17 +380,227 @@ namespace SDKTemplate
|
|||
Log(logMsg.ToString());
|
||||
}
|
||||
|
||||
private UInt32 lastProcessedAdId = 0;
|
||||
private void metadata_emsg_mp4_CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
{
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
object customValue = null;
|
||||
timedMetadataTrack.PlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
logMsg.AppendLine($"{contentId} mp4 emsg DataCue CueEntered raised.");
|
||||
var dataCue = args.Cue as DataCue;
|
||||
if (dataCue != null)
|
||||
{
|
||||
// Ref: ISO/IEC 20009-1, Section 5.10.3.3.2 Definition of Box Type: 'emsg'
|
||||
string scheme_id_uri = string.Empty;
|
||||
string value = string.Empty;
|
||||
UInt32 timescale = (UInt32) TimeSpan.TicksPerSecond;
|
||||
UInt32 presentation_time_delta = (UInt32)dataCue.StartTime.Ticks;
|
||||
UInt32 event_duration = (UInt32)dataCue.Duration.Ticks;
|
||||
UInt32 id = 0;
|
||||
Byte[] message_data = null;
|
||||
|
||||
const string scheme_id_uri_key = "emsg:scheme_id_uri";
|
||||
object propValue = null;
|
||||
dataCue.Properties.TryGetValue(scheme_id_uri_key, out propValue);
|
||||
scheme_id_uri = propValue!=null ? (string)propValue : "";
|
||||
|
||||
const string value_key = "emsg:value";
|
||||
propValue = null;
|
||||
dataCue.Properties.TryGetValue(value_key, out propValue);
|
||||
value = propValue != null ? (string)propValue : "";
|
||||
|
||||
const string timescale_key = "emsg:timescale";
|
||||
propValue = null;
|
||||
dataCue.Properties.TryGetValue(timescale_key, out propValue);
|
||||
timescale = propValue != null ? (UInt32)propValue : timescale;
|
||||
|
||||
const string presentation_time_delta_key = "emsg:presentation_time_delta";
|
||||
propValue = null;
|
||||
dataCue.Properties.TryGetValue(presentation_time_delta_key, out propValue);
|
||||
presentation_time_delta = propValue != null ? (UInt32)propValue : presentation_time_delta;
|
||||
|
||||
const string event_duration_key = "emsg:event_duration";
|
||||
propValue = null;
|
||||
dataCue.Properties.TryGetValue(event_duration_key, out propValue);
|
||||
event_duration = propValue != null ? (UInt32)propValue : event_duration;
|
||||
|
||||
const string id_key = "emsg:id";
|
||||
propValue = null;
|
||||
dataCue.Properties.TryGetValue(id_key, out propValue);
|
||||
id = propValue != null ? (UInt32)propValue : 0;
|
||||
|
||||
logMsg.AppendLine($"Label: {timedMetadataTrack.Label}, Id: {dataCue.Id}, StartTime: {dataCue.StartTime}, Duration: {dataCue.Duration}");
|
||||
logMsg.Append($"scheme_id_uri: {scheme_id_uri}, value: {value}, timescale: {timescale}, presentation_time_delta: {presentation_time_delta}, event_duration: {event_duration}, id: {id}");
|
||||
|
||||
if (dataCue.Data != null)
|
||||
{
|
||||
var dr = DataReader.FromBuffer(dataCue.Data);
|
||||
|
||||
// Check if this is a SCTE ad message:
|
||||
// Ref: http://dashif.org/identifiers/event-schemes/
|
||||
if (scheme_id_uri.ToLower() == "urn:scte:scte35:2013:xml")
|
||||
{
|
||||
// SCTE recommends publishing emsg more than once, so we avoid reprocessing the same message id:
|
||||
if (lastProcessedAdId != id)
|
||||
{
|
||||
lastProcessedAdId = id; // TODO: Requires robustness. Messages may be out of order, which would break this sample's logic.
|
||||
|
||||
dr.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
|
||||
var scte35payload = dr.ReadString(dataCue.Data.Length);
|
||||
logMsg.Append($", message_data: {scte35payload}");
|
||||
ScheduleAdFromScte35Payload(timedMetadataTrack, presentation_time_delta, timescale, event_duration, scte35payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
logMsg.AppendLine($"This emsg.Id, {id}, has already been processed.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message_data = new byte[dataCue.Data.Length];
|
||||
dr.ReadBytes(message_data);
|
||||
// TODO: Use the 'emsg' bytes for something useful.
|
||||
logMsg.Append($", message_data.Length: {message_data.Length}");
|
||||
}
|
||||
}
|
||||
}
|
||||
Log(logMsg.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This function attempts to parse the SCTE-35 payload, then schedule an appropriately offset Ad using the MediaBreak APIs
|
||||
/// </summary>
|
||||
/// <param name="timedMetadataTrack">Track which fired the cue</param>
|
||||
/// <param name="presentation_time_delta"></param>
|
||||
/// <param name="timescale"></param>
|
||||
/// <param name="event_duration"></param>
|
||||
/// <param name="scte35payload"></param>
|
||||
private async void ScheduleAdFromScte35Payload(TimedMetadataTrack timedMetadataTrack, uint presentation_time_delta, uint timescale, uint event_duration, string scte35payload)
|
||||
{
|
||||
// TODO: Parse SCTE-35
|
||||
//
|
||||
// Ref:
|
||||
// http://www.scte.org/SCTEDocs/Standards/ANSI_SCTE%20214-3%202015.pdf
|
||||
//
|
||||
// Eg:
|
||||
//
|
||||
// <SpliceInfoSection ptsAdjustment="0" scte35:tier="4095">
|
||||
// <SpliceInsert spliceEventId="147467497"
|
||||
// spliceEventCancelIndicator="false"
|
||||
// outOfNetworkIndicator="false"
|
||||
// uniqueProgramId="0"
|
||||
// availNum="0"
|
||||
// availsExpected="0"
|
||||
// spliceImmediateFlag="false" >
|
||||
// <Program>
|
||||
// <SpliceTime ptsTime="6257853600"/>
|
||||
// </Program>
|
||||
// <BreakDuration autoReturn="true" duration="900000"/>
|
||||
// </SpliceInsert>
|
||||
// </SpliceInfoSection>
|
||||
//
|
||||
//
|
||||
|
||||
// We use the metadata track object which fired the Cue to walk our way back up the
|
||||
// media object stack to find our original AdaptiveMediaSource.
|
||||
//
|
||||
// The AdaptiveMediaSource is required because the SCTE-35 payload includes
|
||||
// timing offsets which are relative to the original content PTS -- see below.
|
||||
var ams = timedMetadataTrack.PlaybackItem.Source.AdaptiveMediaSource;
|
||||
|
||||
if (ams != null && timescale != 0)
|
||||
{
|
||||
// ++++
|
||||
// NOTE: DO NOT PARSE SCTE35 LIKE THIS IN PRODUCTION CODE!
|
||||
//
|
||||
// Reminder:
|
||||
//
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
// We will not demonstrate proper SCTE35 parsing in this sample,
|
||||
// but instead we search through the xml find the ptsTime if present,
|
||||
// and use it to schedule an ad; keeping in place the various time offsets.
|
||||
//
|
||||
// e.g.: var sampleScte35Payload = "<SpliceInfoSection ptsAdjustment=\"0\" scte35:tier=\"4095\">< SpliceInsert spliceEventId = \"147467497\" spliceEventCancelIndicator = \"false\" outOfNetworkIndicator = \"false\" uniqueProgramId = \"0\" availNum = \"0\" availsExpected = \"0\" spliceImmediateFlag = \"false\" > < Program >< SpliceTime ptsTime = \"6257853600\" /></ Program > < BreakDuration autoReturn = \"true\" duration = \"900000\" /> </ SpliceInsert > </ SpliceInfoSection > ";
|
||||
//
|
||||
var xmlStrings = scte35payload.Split(new string[] { "<", "/", ">", " ", "=", "\"" }, StringSplitOptions.RemoveEmptyEntries);
|
||||
string ptsTime = string.Empty;
|
||||
for (int i = 0; i < xmlStrings.Length; i++)
|
||||
{
|
||||
if (xmlStrings[i] == "ptsTime")
|
||||
{
|
||||
if (i + 1 < xmlStrings.Length)
|
||||
{
|
||||
ptsTime = xmlStrings[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
|
||||
// The AdaptiveMediaSource keeps track of the original PTS in an AdaptiveMediaSourceCorrelatedTimes
|
||||
// object that can be retrieved via ams.GetCorrelatedTimes(). All the while, it provids the
|
||||
// media pipeline with a consistent timeline that re-aligns zero at the begining of the SeekableRange
|
||||
// when first joining a Live stream.
|
||||
long pts = 0;
|
||||
long.TryParse(ptsTime, out pts);
|
||||
var timeCorrelation = ams.GetCorrelatedTimes();
|
||||
if (timeCorrelation.Position.HasValue && timeCorrelation.PresentationTimeStamp.HasValue)
|
||||
{
|
||||
TimeSpan currentPosition;
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
currentPosition = mediaPlayerElement.MediaPlayer.PlaybackSession.Position;
|
||||
});
|
||||
TimeSpan emsgPresentationTimeDelta = TimeSpan.FromSeconds(presentation_time_delta/timescale);
|
||||
long delayInTicks = timeCorrelation.PresentationTimeStamp.Value.Ticks - pts;
|
||||
TimeSpan correctionForAsyncCalls = currentPosition - timeCorrelation.Position.Value;
|
||||
TimeSpan targetAdPosition = emsgPresentationTimeDelta + TimeSpan.FromTicks(delayInTicks) + correctionForAsyncCalls;
|
||||
|
||||
Log($"Timing Info: PlaybackSession.Position:{currentPosition} targetAdPosition:{targetAdPosition} Delta:{targetAdPosition-currentPosition} Ams.Position:{timeCorrelation.Position.GetValueOrDefault().Ticks} SCTE ptsTime:{pts} emsgPresentationTimeDelta:{emsgPresentationTimeDelta} Ams.PresentationTimeStamp:{timeCorrelation.PresentationTimeStamp.GetValueOrDefault().Ticks} Ams.ProgramDateTime:{timeCorrelation.ProgramDateTime.GetValueOrDefault()}");
|
||||
|
||||
MediaBreakInsertionMethod insertionMethod = ams.IsLive ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt;
|
||||
var redSkyUri = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4");
|
||||
if (targetAdPosition != TimeSpan.Zero && targetAdPosition >= currentPosition)
|
||||
{
|
||||
// Schedule ad in the future:
|
||||
Log($"Ad insertion triggerd by 'emsg'. Scheduled: {targetAdPosition.ToString()} Current:{currentPosition.ToString()}");
|
||||
var midRollBreak = new MediaBreak(insertionMethod, targetAdPosition);
|
||||
midRollBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)));
|
||||
timedMetadataTrack.PlaybackItem.BreakSchedule.InsertMidrollBreak(midRollBreak);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Play now!
|
||||
Log($"Ad inserted immediately. Scheduled: {targetAdPosition.ToString()} Current:{currentPosition.ToString()}");
|
||||
var midRollBreak = new MediaBreak(insertionMethod);
|
||||
midRollBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)));
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
mediaPlayerElement.MediaPlayer.BreakManager.PlayBreak(midRollBreak);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void metadata_TrackingEvents_CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
{
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
var contentId = (Guid)timedMetadataTrack.PlaybackItem.Source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
timedMetadataTrack.PlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
logMsg.AppendLine($"{contentId} TrackingEventCue CueEntered raised.");
|
||||
var trackingEventCue = args.Cue as TrackingEventCue;
|
||||
if (trackingEventCue != null)
|
||||
{
|
||||
logMsg.AppendLine($"Label: {timedMetadataTrack.Label}, Id: {trackingEventCue.Id}, StartTime: {trackingEventCue.StartTime}, Duration: {trackingEventCue.Duration}");
|
||||
logMsg.Append($"{trackingEventCue.TrackingEventUri}");
|
||||
// TODO: Use the reporing Uri.
|
||||
// TODO: Use the reporing Uri for something useful.
|
||||
}
|
||||
Log(logMsg.ToString());
|
||||
}
|
||||
|
@ -327,7 +608,9 @@ namespace SDKTemplate
|
|||
private void metadata_TrackingEvents_CueExited(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
{
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
var contentId = (Guid)timedMetadataTrack.PlaybackItem.Source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
timedMetadataTrack.PlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
logMsg.AppendLine($"{contentId} TrackingEventCue CueExited raised.");
|
||||
var trackingEventCue = args.Cue as TrackingEventCue;
|
||||
if (trackingEventCue != null)
|
||||
|
@ -339,25 +622,16 @@ namespace SDKTemplate
|
|||
}
|
||||
#endregion
|
||||
|
||||
#region AdaptiveMediaSource Event Handlers
|
||||
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource aMS)
|
||||
{
|
||||
aMS.DownloadFailed += DownloadFailed;
|
||||
}
|
||||
|
||||
private void DownloadFailed(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadFailedEventArgs args)
|
||||
{
|
||||
Log($"DownloadFailed: {args.HttpResponseMessage}, {args.ResourceType}, {args.ResourceUri}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Utilities
|
||||
private void Log(string message)
|
||||
{
|
||||
LoggerControl.Log(message);
|
||||
}
|
||||
MediaPlayerLogger mediaPlayerLogger;
|
||||
MediaSourceLogger mediaSourceLogger;
|
||||
MediaPlaybackItemLogger mediaPlaybackItemLogger;
|
||||
AdaptiveMediaSourceLogger adaptiveMediaSourceLogger;
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:SDKTemplate"
|
||||
xmlns:local="using:SDKTemplate.Controls"
|
||||
xmlns:logging="using:SDKTemplate.Logging"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
|
@ -28,31 +29,20 @@
|
|||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,10" Orientation="Vertical">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
<StackPanel x:Name="DescriptionText">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario demonstrates simple Ad insertion with playback progress reporting.
|
||||
We add two pre-roll ads, two mid-roll ads at 10% into the main content, and a
|
||||
post-roll ad. For each of these ads, and the main content, we re-use the Custom
|
||||
TimedMetadataTracks from the Metadata sample to raise playback progress events.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadId" Content="Load Id:" Click="LoadId_Click" Margin="5,0"/>
|
||||
<ComboBox x:Name="SelectedContent" Margin="5,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="LoadUri" Content="Load Uri:" Click="LoadUri_Click" Margin="5,0" />
|
||||
<TextBox x:Name="UriBox" InputScope="Url" HorizontalAlignment="Stretch" Margin="5,0" />
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="5,5">
|
||||
<Button x:Name="SetSource" Content="Set Source" Click="SetSource_Click" Margin="5,0"/>
|
||||
<CheckBox x:Name="AutoPlay" Checked="AutoPlay_Checked" Unchecked="AutoPlay_Checked" Content="AutoPlay" IsChecked="False" />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<local:ContentSelector x:Name="ContentSelectorControl"/>
|
||||
</StackPanel>
|
||||
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
|
||||
|
||||
<local:Logger x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
<logging:LogView x:Name="LoggerControl" Grid.Row="2" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Page>
|
||||
|
|
|
@ -10,26 +10,25 @@
|
|||
//*********************************************************
|
||||
|
||||
using SDKTemplate.Helpers;
|
||||
using SDKTemplate.Models;
|
||||
using SDKTemplate.Logging;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Foundation.Collections;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.Media.Streaming.Adaptive;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Web.Http;
|
||||
|
||||
using StringBuilder = System.Text.StringBuilder;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
/// See the README.md for discussion of this scenario.
|
||||
///
|
||||
/// Note: We register but do not unregister event handlers in this scenario.
|
||||
/// See the EventHandler scenario for patterns that can be used to clean up.
|
||||
|
||||
public sealed partial class Scenario6_AdInsertion : Page
|
||||
{
|
||||
public Scenario6_AdInsertion()
|
||||
|
@ -39,76 +38,76 @@ namespace SDKTemplate
|
|||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
mpItem = null;
|
||||
var mp = mediaPlayerElement.MediaPlayer;
|
||||
if (mp != null)
|
||||
// Release handles on various media objects to ensure a quick clean-up
|
||||
ContentSelectorControl.MediaPlaybackItem = null;
|
||||
var mediaPlayer = mediaPlayerElement.MediaPlayer;
|
||||
if (mediaPlayer != null)
|
||||
{
|
||||
mp.DisposeSource();
|
||||
mediaPlayerLogger?.Dispose();
|
||||
mediaPlayerLogger = null;
|
||||
|
||||
UnregisterHandlers(mediaPlayer);
|
||||
|
||||
mediaPlayer.DisposeSource();
|
||||
mediaPlayerElement.SetMediaPlayer(null);
|
||||
mp.Dispose();
|
||||
mediaPlayer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private AdaptiveContentModel adaptiveContentModel;
|
||||
private MediaPlaybackItem mpItem;
|
||||
private bool isLiveMediaSource = false;
|
||||
private void UnregisterHandlers(MediaPlayer mediaPlayer)
|
||||
{
|
||||
AdaptiveMediaSource adaptiveMediaSource = null;
|
||||
MediaPlaybackItem mpItem = mediaPlayer.Source as MediaPlaybackItem;
|
||||
if (mpItem != null)
|
||||
{
|
||||
adaptiveMediaSource = mpItem.Source.AdaptiveMediaSource;
|
||||
UnregisterForMediaSourceEvents(mpItem.Source);
|
||||
UnregisterForMediaPlaybackItemEvents(mpItem);
|
||||
}
|
||||
MediaSource source = mediaPlayer.Source as MediaSource;
|
||||
if (source != null)
|
||||
{
|
||||
adaptiveMediaSource = source.AdaptiveMediaSource;
|
||||
UnregisterForMediaSourceEvents(source);
|
||||
}
|
||||
|
||||
private async void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
mediaPlaybackItemLogger?.Dispose();
|
||||
mediaPlaybackItemLogger = null;
|
||||
|
||||
mediaSourceLogger?.Dispose();
|
||||
mediaSourceLogger = null;
|
||||
|
||||
adaptiveMediaSourceLogger?.Dispose();
|
||||
adaptiveMediaSourceLogger = null;
|
||||
|
||||
}
|
||||
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mediaPlayer = new MediaPlayer();
|
||||
RegisterForMediaPlayerEvents(mediaPlayer);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlayer:
|
||||
mediaPlayerLogger = new MediaPlayerLogger(LoggerControl, mediaPlayer);
|
||||
|
||||
// Ensure we have PlayReady support, in case the user enters a DASH/PR Uri in the text box.
|
||||
var prHelper = new PlayReadyHelper(LoggerControl);
|
||||
prHelper.SetUpProtectionManager(mediaPlayer);
|
||||
|
||||
mediaPlayerElement.SetMediaPlayer(mediaPlayer);
|
||||
|
||||
// Choose a default content.
|
||||
SelectedContent.ItemsSource = MainPage.ContentManagementSystemStub;
|
||||
adaptiveContentModel = MainPage.FindContentById(1);
|
||||
SelectedContent.SelectedItem = adaptiveContentModel;
|
||||
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
ContentSelectorControl.Initialize(
|
||||
mediaPlayer,
|
||||
MainPage.ContentManagementSystemStub.Where(m => !m.Aes),
|
||||
null,
|
||||
LoggerControl,
|
||||
LoadSourceFromUriAsync);
|
||||
}
|
||||
|
||||
|
||||
#region Content Loading
|
||||
|
||||
private async void LoadId_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
adaptiveContentModel = (AdaptiveContentModel)SelectedContent.SelectedItem;
|
||||
|
||||
UriBox.Text = adaptiveContentModel.ManifestUri.ToString();
|
||||
await LoadSourceFromUriAsync(adaptiveContentModel.ManifestUri);
|
||||
}
|
||||
|
||||
private async void LoadUri_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Uri uri;
|
||||
if (!Uri.TryCreate(UriBox.Text, UriKind.Absolute, out uri))
|
||||
{
|
||||
Log("Malformed Uri in Load text box.");
|
||||
}
|
||||
|
||||
mpItem = null;
|
||||
await LoadSourceFromUriAsync(uri);
|
||||
}
|
||||
|
||||
private void AutoPlay_Checked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
mediaPlayerElement.AutoPlay = (bool)(sender as CheckBox).IsChecked;
|
||||
}
|
||||
|
||||
private void SetSource_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// It is at this point that the MediaSource (within a MediaPlaybackItem) will be fully resolved.
|
||||
// For an AdaptiveMediaSource, this is the point at which media is first requested and parsed.
|
||||
mediaPlayerElement.Source = mpItem;
|
||||
}
|
||||
|
||||
private async Task LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
private async Task<MediaPlaybackItem> LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
AdaptiveMediaSourceCreationResult result = null;
|
||||
|
@ -120,31 +119,60 @@ namespace SDKTemplate
|
|||
{
|
||||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
|
||||
}
|
||||
|
||||
MediaSource source;
|
||||
if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
|
||||
{
|
||||
var adaptiveMS = result.MediaSource;
|
||||
isLiveMediaSource = adaptiveMS.IsLive;
|
||||
RegisterForAdaptiveMediaSourceEvents(adaptiveMS);
|
||||
var adaptiveMediaSource = result.MediaSource;
|
||||
|
||||
MediaSource source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMS);
|
||||
source.CustomProperties.Add("uri", uri.ToString());
|
||||
source.CustomProperties.Add("contentId", "MainContent_ID");
|
||||
RegisterForMediaSourceEvents(source);
|
||||
// We use a helper class that logs all the events for the AdaptiveMediaSource:
|
||||
adaptiveMediaSourceLogger = new AdaptiveMediaSourceLogger(LoggerControl, adaptiveMediaSource);
|
||||
|
||||
source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource);
|
||||
|
||||
mpItem = new MediaPlaybackItem(source);
|
||||
RegisterForMediaPlaybackItemEvents(mpItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Error creating the AdaptiveMediaSource: {result.Status}");
|
||||
Log($"Error creating the AdaptiveMediaSource. Status: {result.Status}, ExtendedError.Message: {result.ExtendedError.Message}, ExtendedError.HResult: {result.ExtendedError.HResult.ToString("X8")}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// We use a helper class that logs all the events for the MediaSource:
|
||||
mediaSourceLogger = new MediaSourceLogger(LoggerControl, source);
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties["uri"] = uri.ToString();
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties["contentId"] = "MainContent_ID";
|
||||
|
||||
// In addition to logging, this scenario uses MediaSource events:
|
||||
RegisterForMediaSourceEvents(source);
|
||||
|
||||
var mpItem = new MediaPlaybackItem(source);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlaybackItem:
|
||||
mediaPlaybackItemLogger = new MediaPlaybackItemLogger(LoggerControl, mpItem);
|
||||
|
||||
// In addition to logging, this scenario uses MediaPlaybackItem events:
|
||||
RegisterForMediaPlaybackItemEvents(mpItem);
|
||||
|
||||
// Now that we should have a MediaPlaybackItem, we will insert pre- mid- and post-roll ads
|
||||
// with the MediaBreak API.
|
||||
if (mpItem != null)
|
||||
CreateMediaBreaksForItem(mpItem);
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
|
||||
return mpItem;
|
||||
}
|
||||
|
||||
private async void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
CreateMediaBreaksForItem(mpItem);
|
||||
}
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
});
|
||||
}
|
||||
|
||||
private void CreateMediaBreaksForItem(MediaPlaybackItem item)
|
||||
|
@ -200,6 +228,7 @@ namespace SDKTemplate
|
|||
{
|
||||
// For live streaming, the duration will be TimeSpan.MaxValue, which won't work for this scenario,
|
||||
// so we'll assume the total duration is 2 minutes for the purpose of ad insertion.
|
||||
bool isLiveMediaSource = item.Source.AdaptiveMediaSource != null ? item.Source.AdaptiveMediaSource.IsLive : false;
|
||||
long sourceDurationTicks = isLiveMediaSource ? TimeSpan.FromMinutes(2).Ticks : sender.Duration.Value.Ticks;
|
||||
var positionAt10PercentOfMainContent = TimeSpan.FromTicks(sourceDurationTicks / 10);
|
||||
|
||||
|
@ -227,42 +256,33 @@ namespace SDKTemplate
|
|||
}
|
||||
#endregion
|
||||
|
||||
#region MediaPlayer Event Handlers
|
||||
private void RegisterForMediaPlayerEvents(MediaPlayer mediaPlayer)
|
||||
{
|
||||
// Player Events
|
||||
mediaPlayer.SourceChanged += (sender, args) => Log("mediaPlayer.SourceChanged");
|
||||
mediaPlayer.MediaOpened += (sender, args) => Log($"MediaPlayer_MediaOpened, Duration: {sender.PlaybackSession.NaturalDuration}");
|
||||
mediaPlayer.MediaEnded += (sender, args) => Log("mediaPlayer.MediaEnded");
|
||||
mediaPlayer.MediaFailed += (sender, args) => Log($"MediaPlayer_MediaFailed Error: {args.Error}, ErrorMessage: {args.ErrorMessage}, ExtendedErrorCode.Message: {args.ExtendedErrorCode.Message}");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region MediaSource Event Handlers
|
||||
|
||||
private void RegisterForMediaSourceEvents(MediaSource source)
|
||||
{
|
||||
if (source != null)
|
||||
{
|
||||
source.StateChanged += (sender, args) => Log($"Source.StateChanged:{args.OldState} to {args.NewState}");
|
||||
source.OpenOperationCompleted += Source_OpenOperationCompleted;
|
||||
}
|
||||
else
|
||||
{
|
||||
Log("ERROR: Tried RegisterForMediaSourceEvents with a null source");
|
||||
}
|
||||
source.OpenOperationCompleted += Source_OpenOperationCompleted;
|
||||
}
|
||||
private void UnregisterForMediaSourceEvents(MediaSource source)
|
||||
{
|
||||
source.OpenOperationCompleted -= Source_OpenOperationCompleted;
|
||||
}
|
||||
|
||||
private void Source_OpenOperationCompleted(MediaSource source, MediaSourceOpenOperationCompletedEventArgs args)
|
||||
{
|
||||
// Here we create our own metadata track.
|
||||
// Our goal is to track progress through the asset and report it back to a server.
|
||||
var contentId = (string)source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
var reportingUriFormat = "http://myserver/reporting/{0}?id={1}";
|
||||
//From \Shared\TrackingEventCue.cs :
|
||||
// From \Shared\TrackingEventCue.cs:
|
||||
TrackingEventCue.CreateTrackingEventsTrack(source, contentId, reportingUriFormat);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region MediaPlaybackItem Event Handlers
|
||||
|
||||
private void RegisterForMediaPlaybackItemEvents(MediaPlaybackItem item)
|
||||
|
@ -284,29 +304,41 @@ namespace SDKTemplate
|
|||
}
|
||||
|
||||
// For any tracks found as the content is parsed, we register for the event handler:
|
||||
item.TimedMetadataTracksChanged += (MediaPlaybackItem sender, IVectorChangedEventArgs args) =>
|
||||
{
|
||||
Log($"item.TimedMetadataTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{sender.TimedMetadataTracks.Count}");
|
||||
|
||||
if (args.CollectionChange == CollectionChange.ItemInserted)
|
||||
{
|
||||
RegisterMetadataHandlers(sender, (int)args.Index);
|
||||
}
|
||||
if (args.CollectionChange == CollectionChange.Reset)
|
||||
{
|
||||
for (int index = 0; index < item.TimedMetadataTracks.Count; index++)
|
||||
{
|
||||
RegisterMetadataHandlers(item, index);
|
||||
}
|
||||
}
|
||||
};
|
||||
item.TimedMetadataTracksChanged += Item_TimedMetadataTracksChanged;
|
||||
}
|
||||
|
||||
private void UnregisterForMediaPlaybackItemEvents(MediaPlaybackItem item)
|
||||
{
|
||||
item.TimedMetadataTracksChanged -= Item_TimedMetadataTracksChanged;
|
||||
foreach (var track in item.TimedMetadataTracks)
|
||||
{
|
||||
UnregisterMetadataHandlers(track);
|
||||
}
|
||||
}
|
||||
|
||||
private void Item_TimedMetadataTracksChanged(MediaPlaybackItem item, IVectorChangedEventArgs args)
|
||||
{
|
||||
Log($"item.TimedMetadataTracksChanged: CollectionChange:{args.CollectionChange} Index:{args.Index} Total:{item.TimedMetadataTracks.Count}");
|
||||
|
||||
if (args.CollectionChange == CollectionChange.ItemInserted)
|
||||
{
|
||||
RegisterMetadataHandlers(item, (int)args.Index);
|
||||
}
|
||||
if (args.CollectionChange == CollectionChange.Reset)
|
||||
{
|
||||
for (int index = 0; index < item.TimedMetadataTracks.Count; index++)
|
||||
{
|
||||
RegisterMetadataHandlers(item, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterMetadataHandlers(MediaPlaybackItem mediaPlaybackItem, int index)
|
||||
{
|
||||
var timedTrack = mediaPlaybackItem.TimedMetadataTracks[index];
|
||||
var contentId = (string)mediaPlaybackItem.Source.CustomProperties["contentId"];
|
||||
object customValue = null;
|
||||
mediaPlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
|
||||
StringBuilder logMsg = new StringBuilder($"{contentId} ");
|
||||
|
||||
|
@ -320,51 +352,55 @@ namespace SDKTemplate
|
|||
timedTrack.Label = "Tracking Events";
|
||||
mediaPlaybackItem.TimedMetadataTracks.SetPresentationMode((uint)index, TimedMetadataTrackPresentationMode.ApplicationPresented);
|
||||
}
|
||||
|
||||
logMsg.AppendLine($"Registered CueEntered for {timedTrack.Label}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
logMsg.AppendLine($"Did not register CueEntered for TimedMetadataTrack.");
|
||||
logMsg.AppendLine("Did not register CueEntered for TimedMetadataTrack.");
|
||||
}
|
||||
logMsg.AppendLine($"TimedMetadataKind: {timedTrack.TimedMetadataKind}, Id: {timedTrack.Id}, Label: {timedTrack.Label}, DispatchType: {timedTrack.DispatchType}, Language: {timedTrack.Language}");
|
||||
|
||||
Log(logMsg.ToString());
|
||||
}
|
||||
|
||||
private void metadata_TrackingEvents_CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
private void UnregisterMetadataHandlers(TimedMetadataTrack timedTrack)
|
||||
{
|
||||
if (timedTrack.Label == "Tracking Events")
|
||||
{
|
||||
timedTrack.CueEntered -= metadata_TrackingEvents_CueEntered;
|
||||
}
|
||||
}
|
||||
|
||||
private void metadata_TrackingEvents_CueEntered(TimedMetadataTrack timedMetadataTrack, MediaCueEventArgs args)
|
||||
{
|
||||
StringBuilder logMsg = new StringBuilder();
|
||||
|
||||
var contentId = (string)timedMetadataTrack.PlaybackItem.Source.CustomProperties["contentId"];
|
||||
logMsg.AppendLine("{contentId} TrackingEventCue CueEntered raised.");
|
||||
object customValue = null;
|
||||
timedMetadataTrack.PlaybackItem.Source.CustomProperties.TryGetValue("contentId", out customValue);
|
||||
string contentId = (string)customValue;
|
||||
logMsg.AppendLine($"{contentId} TrackingEventCue CueEntered raised.");
|
||||
var trackingEventCue = args.Cue as TrackingEventCue;
|
||||
if (trackingEventCue != null)
|
||||
{
|
||||
logMsg.AppendLine($"Label: {timedMetadataTrack.Label}, Id: {trackingEventCue.Id}, StartTime: {trackingEventCue.StartTime}, Duration: {trackingEventCue.Duration}");
|
||||
logMsg.Append($"{trackingEventCue.TrackingEventUri}");
|
||||
// TODO: Use the reporting Uri.
|
||||
// TODO: Use the reporing Uri.
|
||||
}
|
||||
Log(logMsg.ToString());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region AdaptiveMediaSource Event Handlers
|
||||
private void RegisterForAdaptiveMediaSourceEvents(AdaptiveMediaSource aMS)
|
||||
{
|
||||
aMS.DownloadFailed += DownloadFailed;
|
||||
}
|
||||
|
||||
private void DownloadFailed(AdaptiveMediaSource sender, AdaptiveMediaSourceDownloadFailedEventArgs args)
|
||||
{
|
||||
Log($"DownloadFailed: {args.HttpResponseMessage}, {args.ResourceType}, {args.ResourceUri}");
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Utilities
|
||||
private void Log(string message)
|
||||
{
|
||||
LoggerControl.Log(message);
|
||||
}
|
||||
MediaPlayerLogger mediaPlayerLogger;
|
||||
MediaSourceLogger mediaSourceLogger;
|
||||
MediaPlaybackItemLogger mediaPlaybackItemLogger;
|
||||
AdaptiveMediaSourceLogger adaptiveMediaSourceLogger;
|
||||
#endregion
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
<!--
|
||||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
-->
|
||||
<Page
|
||||
x:Class="SDKTemplate.Scenario7_LiveSeekableRange"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="using:SDKTemplate.Controls"
|
||||
xmlns:logging="using:SDKTemplate.Logging"
|
||||
Loaded="Page_OnLoaded"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Padding="12,10,12,12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Grid.Row="0" Margin="0,0,0,10" Orientation="Vertical">
|
||||
<StackPanel x:Name="DescriptionText">
|
||||
<TextBlock Text="Description:" Style="{StaticResource SampleHeaderTextStyle}"/>
|
||||
<TextBlock Style="{StaticResource ScenarioDescriptionTextStyle}" TextWrapping="Wrap">
|
||||
This scenario demonstrates a seekable range in Live content, also known as a Live DVR window.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<local:ContentSelector x:Name="ContentSelectorControl"/>
|
||||
</StackPanel>
|
||||
|
||||
<MediaPlayerElement x:Name="mediaPlayerElement" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" AreTransportControlsEnabled="True" />
|
||||
|
||||
<StackPanel x:Name="CustomMediaControl" Grid.Row="2" Margin="0,10,0,0" Orientation="Vertical">
|
||||
|
||||
<Grid x:Name="SeekableWindowControls" Margin="0,10,0,0" HorizontalAlignment="Center" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="MaxSeekableWindowSize" Margin="10,0" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="MaxSeekableWindowSize" Text="MaxSeekableWindowSize" Margin="10,0" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" />
|
||||
|
||||
<TextBlock Text="DesiredSeekableWindowSize" Margin="10,0" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" >
|
||||
<TextBox x:Name="DesiredSeekableWindowSize" Text="DesiredSeekableWindowSize" Margin="10,0" HorizontalAlignment="Center" />
|
||||
<Button x:Name="DesiredSeekableWindowSizeButton" Content="Set" Margin="0,0,10,0" Click="DesiredSeekableWindowSizeButton_Click" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="DesiredLiveOffset" Margin="10,0" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" />
|
||||
<StackPanel Orientation="Horizontal" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center" >
|
||||
<TextBox x:Name="DesiredLiveOffset" Text="DesiredLiveOffset" Margin="10,0" HorizontalAlignment="Center" />
|
||||
<Button x:Name="DesiredLiveOffsetButton" Content="Set" Margin="0,0,10,0" Click="DesiredLiveOffsetButton_Click" HorizontalAlignment="Center" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Text="MinLiveOffset" Margin="10,0" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="MinLiveOffset" Text="MinLiveOffset" Margin="10,0" Grid.Row="1" Grid.Column="3" HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="PositionUpdateControls" Margin="0,10,0,0" HorizontalAlignment="Center" >
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Text="StartPosition" Margin="10,0" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="StartPosition" Text="Start" Margin="10,0" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Center" />
|
||||
|
||||
<TextBlock Text="CurrentPosition" Margin="10,0" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="CurrentPosition" Text="Current" Margin="10,0" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" />
|
||||
|
||||
<TextBlock Text="EndPosition" Margin="10,0" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" />
|
||||
<TextBlock x:Name="EndPosition" Text="End" Margin="10,0" Grid.Row="1" Grid.Column="2" HorizontalAlignment="Center" />
|
||||
|
||||
<Slider x:Name="PositionSlider" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="3" Width="500" Orientation="Horizontal" Height="auto"/>
|
||||
</Grid>
|
||||
|
||||
|
||||
<StackPanel x:Name="DiscreteControls" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Top">
|
||||
<Button x:Name="LogCurrentTimeCorrelation" Content="Log Times" Click="LogCurrentTimeCorrelation_Click" />
|
||||
<Button x:Name ="GoToStart" Content="GoToStart" Click="GoToStart_Click" />
|
||||
<Button Tag="-00:15:00" Content="<<15m" Click="SeekFixedAmount_Click"/>
|
||||
<Button Tag="-00:05:00" Content="<<5m" Click="SeekFixedAmount_Click"/>
|
||||
<Button Tag="-00:00:30" Content="<<30s" Click="SeekFixedAmount_Click"/>
|
||||
<Button Tag="-00:00:02" Content="<<2s" Click="SeekFixedAmount_Click"/>
|
||||
<Button x:Name="PlayButton" IsEnabled="False" Click="Play_Click">
|
||||
<SymbolIcon x:Name="PlayIcon" Symbol="Play"/>
|
||||
</Button>
|
||||
<Button x:Name="PauseButton" IsEnabled="False" Click="Pause_Click">
|
||||
<SymbolIcon x:Name="PauseIcon" Symbol="Pause"/>
|
||||
</Button>
|
||||
<Button Tag="00:00:02" Content="2s>>" Click="SeekFixedAmount_Click"/>
|
||||
<Button Tag="00:00:30" Content="30s>>" Click="SeekFixedAmount_Click"/>
|
||||
<Button Tag="00:05:00" Content="5m>>" Click="SeekFixedAmount_Click"/>
|
||||
<Button Tag="00:15:00" Content="15m>>" Click="SeekFixedAmount_Click"/>
|
||||
<Button x:Name ="GoToLive" Content="GoToLive" Click="GoToLive_Click" />
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<logging:LogView x:Name="LoggerControl" Grid.Row="3" Margin="0,10,0,0"/>
|
||||
</Grid>
|
||||
</Page>
|
|
@ -0,0 +1,515 @@
|
|||
//*********************************************************
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
|
||||
// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
|
||||
// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
|
||||
//
|
||||
//*********************************************************
|
||||
|
||||
using SDKTemplate.Helpers;
|
||||
using SDKTemplate.Logging;
|
||||
using SDKTemplate.Logging.Extensions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Media;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.Playback;
|
||||
using Windows.Media.Streaming.Adaptive;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Navigation;
|
||||
using Windows.Web.Http;
|
||||
|
||||
namespace SDKTemplate
|
||||
{
|
||||
/// See the README.md for discussion of this scenario.
|
||||
|
||||
public sealed partial class Scenario7_LiveSeekableRange : Page
|
||||
{
|
||||
public Scenario7_LiveSeekableRange()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnNavigatedFrom(NavigationEventArgs e)
|
||||
{
|
||||
// Release handles on various media objects to ensure a quick clean-up
|
||||
ContentSelectorControl.MediaPlaybackItem = null;
|
||||
var mediaPlayer = mediaPlayerElement.MediaPlayer;
|
||||
if (mediaPlayer != null)
|
||||
{
|
||||
mediaPlayerLogger?.Dispose();
|
||||
mediaPlayerLogger = null;
|
||||
|
||||
UnregisterForDiscreteControls(mediaPlayer);
|
||||
UnregisterForPositionUpdateControl(mediaPlayer);
|
||||
|
||||
UnregisterHandlers(mediaPlayer);
|
||||
|
||||
mediaPlayer.DisposeSource();
|
||||
mediaPlayerElement.SetMediaPlayer(null);
|
||||
mediaPlayer.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void UnregisterHandlers(MediaPlayer mediaPlayer)
|
||||
{
|
||||
mediaPlaybackItemLogger?.Dispose();
|
||||
mediaPlaybackItemLogger = null;
|
||||
|
||||
mediaSourceLogger?.Dispose();
|
||||
mediaSourceLogger = null;
|
||||
|
||||
adaptiveMediaSourceLogger?.Dispose();
|
||||
adaptiveMediaSourceLogger = null;
|
||||
}
|
||||
|
||||
private void Page_OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var mediaPlayer = new MediaPlayer();
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlayer:
|
||||
mediaPlayerLogger = new MediaPlayerLogger(LoggerControl, mediaPlayer);
|
||||
|
||||
// In addition to logging, we use the callbacks to update some UI elements in this scenario:
|
||||
RegisterForDiscreteControls(mediaPlayer);
|
||||
RegisterForPositionUpdateControls(mediaPlayer);
|
||||
|
||||
// Ensure we have PlayReady support, in case the user enters a DASH/PR Uri in the text box.
|
||||
var prHelper = new PlayReadyHelper(LoggerControl);
|
||||
prHelper.SetUpProtectionManager(mediaPlayer);
|
||||
mediaPlayerElement.SetMediaPlayer(mediaPlayer);
|
||||
|
||||
ContentSelectorControl.Initialize(
|
||||
mediaPlayer,
|
||||
MainPage.ContentManagementSystemStub.Where(m => !m.Aes && m.Live),
|
||||
null,
|
||||
LoggerControl,
|
||||
LoadSourceFromUriAsync);
|
||||
|
||||
// Initialize scenario specific layout:
|
||||
ContentSelectorControl.SetAutoPlay(true);
|
||||
mediaPlayerElement.AreTransportControlsEnabled = false;
|
||||
LoggerControl.Height = 200;
|
||||
}
|
||||
|
||||
#region Content Loading
|
||||
|
||||
private async Task<MediaPlaybackItem> LoadSourceFromUriAsync(Uri uri, HttpClient httpClient = null)
|
||||
{
|
||||
UnregisterHandlers(mediaPlayerElement.MediaPlayer);
|
||||
mediaPlayerElement.MediaPlayer?.DisposeSource();
|
||||
|
||||
AdaptiveMediaSourceCreationResult result = null;
|
||||
if (httpClient != null)
|
||||
{
|
||||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri, httpClient);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
|
||||
}
|
||||
|
||||
MediaSource source;
|
||||
if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
|
||||
{
|
||||
var adaptiveMediaSource = result.MediaSource;
|
||||
|
||||
// We use a helper class that logs all the events for the AdaptiveMediaSource:
|
||||
adaptiveMediaSourceLogger = new AdaptiveMediaSourceLogger(LoggerControl, adaptiveMediaSource);
|
||||
|
||||
source = MediaSource.CreateFromAdaptiveMediaSource(adaptiveMediaSource);
|
||||
|
||||
if (adaptiveMediaSource.MaxSeekableWindowSize.HasValue)
|
||||
{
|
||||
UpdateSeekableWindowControls(adaptiveMediaSource);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Log($"Error creating the AdaptiveMediaSource. Status: {result.Status}, ExtendedError.Message: {result.ExtendedError.Message}, ExtendedError.HResult: {result.ExtendedError.HResult.ToString("X8")}");
|
||||
return null;
|
||||
}
|
||||
|
||||
// We use a helper class that logs all the events for the MediaSource:
|
||||
mediaSourceLogger = new MediaSourceLogger(LoggerControl, source);
|
||||
|
||||
// Save the original Uri.
|
||||
source.CustomProperties["uri"] = uri.ToString();
|
||||
|
||||
// You're likely to put a content tracking id into the CustomProperties.
|
||||
source.CustomProperties["contentId"] = Guid.NewGuid().ToString();
|
||||
|
||||
var mpItem = new MediaPlaybackItem(source);
|
||||
|
||||
// We use a helper class that logs all the events for the MediaPlaybackItem:
|
||||
mediaPlaybackItemLogger = new MediaPlaybackItemLogger(LoggerControl, mpItem);
|
||||
|
||||
HideDescriptionOnSmallScreen();
|
||||
|
||||
return mpItem;
|
||||
}
|
||||
|
||||
private async void HideDescriptionOnSmallScreen()
|
||||
{
|
||||
// On small screens, hide the description text to make room for the video.
|
||||
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
DescriptionText.Visibility = (ActualHeight < 500) ? Visibility.Collapsed : Visibility.Visible;
|
||||
});
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region CustomMediaControl
|
||||
|
||||
#region SeekableWindowControls
|
||||
|
||||
private void DesiredSeekableWindowSizeButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var adaptiveMediaSource = (mediaPlayerElement.MediaPlayer.Source as MediaPlaybackItem)?.Source?.AdaptiveMediaSource;
|
||||
if (adaptiveMediaSource == null)
|
||||
return;
|
||||
TimeSpan result = adaptiveMediaSource.DesiredSeekableWindowSize.GetValueOrDefault();
|
||||
if (TimeSpan.TryParse(DesiredSeekableWindowSize.Text, out result))
|
||||
{
|
||||
adaptiveMediaSource.DesiredSeekableWindowSize = result;
|
||||
}
|
||||
UpdateSeekableWindowControls();
|
||||
}
|
||||
|
||||
private void DesiredLiveOffsetButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var adaptiveMediaSource = (mediaPlayerElement.MediaPlayer.Source as MediaPlaybackItem)?.Source?.AdaptiveMediaSource;
|
||||
if (adaptiveMediaSource == null)
|
||||
return;
|
||||
TimeSpan result = adaptiveMediaSource.DesiredLiveOffset;
|
||||
if (TimeSpan.TryParse(DesiredLiveOffset.Text, out result))
|
||||
{
|
||||
adaptiveMediaSource.DesiredLiveOffset = result;
|
||||
}
|
||||
UpdateSeekableWindowControls();
|
||||
}
|
||||
|
||||
private void UpdateSeekableWindowControls()
|
||||
{
|
||||
var adaptiveMediaSource = (mediaPlayerElement.MediaPlayer.Source as MediaPlaybackItem)?.Source?.AdaptiveMediaSource;
|
||||
UpdateSeekableWindowControls(adaptiveMediaSource);
|
||||
}
|
||||
|
||||
private void UpdateSeekableWindowControls(AdaptiveMediaSource adaptiveMediaSource)
|
||||
{
|
||||
if (adaptiveMediaSource == null)
|
||||
return;
|
||||
|
||||
var task = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
MaxSeekableWindowSize.Text = adaptiveMediaSource.MaxSeekableWindowSize.HasValue ? $"{adaptiveMediaSource.MaxSeekableWindowSize.Value.ToString("c")}" : "";
|
||||
DesiredSeekableWindowSize.Text = adaptiveMediaSource.DesiredSeekableWindowSize.HasValue ? $"{adaptiveMediaSource.DesiredSeekableWindowSize.Value.ToString("c")}" : "";
|
||||
DesiredLiveOffset.Text = $"{adaptiveMediaSource.DesiredLiveOffset.ToString("c")}";
|
||||
MinLiveOffset.Text = adaptiveMediaSource.MinLiveOffset.HasValue ? $"{adaptiveMediaSource.MinLiveOffset.Value.ToString("c")}" : "";
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PositionUpdateControl
|
||||
|
||||
double m_SliderFullScale = 100000.0; // Sets granularity of slider
|
||||
|
||||
TimeSpan m_PlaybackPositionMaxTime = TimeSpan.FromHours(1);
|
||||
TimeSpan m_PlaybackPositionMinTime= TimeSpan.Zero;
|
||||
|
||||
private void RegisterForPositionUpdateControls(MediaPlayer mp)
|
||||
{
|
||||
// Setup slider
|
||||
PositionSlider.Minimum = 0.0;
|
||||
PositionSlider.Maximum = m_SliderFullScale;
|
||||
PositionSlider.Value = 0.0;
|
||||
|
||||
// Register for events
|
||||
mp.SourceChanged += PositionUpdateControl_SourceChanged;
|
||||
mp.PlaybackSession.PositionChanged += PositionUpdateControl_PositionChanged;
|
||||
mp.PlaybackSession.SeekableRangesChanged += PositionUpdateControl_SeekableRangesChanged;
|
||||
}
|
||||
|
||||
private void PositionUpdateControl_SourceChanged(MediaPlayer sender, object args)
|
||||
{
|
||||
m_PlaybackPositionMaxTime = TimeSpan.FromHours(1);
|
||||
m_PlaybackPositionMinTime = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
private void UnregisterForPositionUpdateControl(MediaPlayer mp)
|
||||
{
|
||||
mp.SourceChanged -= PositionUpdateControl_SourceChanged;
|
||||
mp.PlaybackSession.PositionChanged -= PositionUpdateControl_PositionChanged;
|
||||
mp.PlaybackSession.SeekableRangesChanged -= PositionUpdateControl_SeekableRangesChanged;
|
||||
}
|
||||
|
||||
private void PositionUpdateControl_SeekableRangesChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
var seekableRanges = sender.GetSeekableRanges();
|
||||
UpdateSeekableRangesControl(seekableRanges);
|
||||
}
|
||||
|
||||
private void UpdateSeekableRangesControl(IReadOnlyList<MediaTimeRange> SeekableRanges)
|
||||
{
|
||||
if (SeekableRanges.Count > 0)
|
||||
{
|
||||
var SeekableRangeMin = SeekableRanges.First();
|
||||
m_PlaybackPositionMinTime = SeekableRangeMin.Start;
|
||||
|
||||
var SeekableRangeMax = SeekableRanges.Last();
|
||||
m_PlaybackPositionMaxTime = SeekableRangeMax.End;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_PlaybackPositionMaxTime = TimeSpan.FromHours(1);
|
||||
m_PlaybackPositionMinTime = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
var task = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
StartPosition.Text = m_PlaybackPositionMinTime.ToString("c");
|
||||
EndPosition.Text = m_PlaybackPositionMaxTime.ToString("c");
|
||||
});
|
||||
|
||||
string ranges = "";
|
||||
foreach (var range in SeekableRanges)
|
||||
{
|
||||
ranges += $"[{range.Start},{range.End}],";
|
||||
}
|
||||
ranges = ranges.TrimEnd(',');
|
||||
Log($"MediaPlayer_PlaybackSession_SeekableRangesChanged: {ranges}");
|
||||
}
|
||||
|
||||
private async void PositionUpdateControl_PositionChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
var postion = sender.Position;
|
||||
var newSliderValue = GetSliderPositionAtPlaybackPosition(postion, m_SliderFullScale, m_PlaybackPositionMinTime, m_PlaybackPositionMaxTime);
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
CurrentPosition.Text = postion.ToString("c");
|
||||
PositionSlider.Value = newSliderValue;
|
||||
});
|
||||
}
|
||||
|
||||
#region PositionSlider events
|
||||
|
||||
private void SeekToRequestedPosition(TimeSpan requestedPosition)
|
||||
{
|
||||
Log($"Seeking to:{requestedPosition.ToString("c")}");
|
||||
mediaPlayerElement.MediaPlayer.PlaybackSession.Position = requestedPosition;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// We will use slider ticks to drive a playback Position.
|
||||
///
|
||||
/// This is a linear interpolation, so:
|
||||
/// y = m*x + b
|
||||
/// Where:
|
||||
/// Position = m*sliderPosition + b
|
||||
///
|
||||
/// Where we have some data points:
|
||||
///
|
||||
/// At MinPosition, we are at slider position=0
|
||||
/// MinPosition = m * 0 + b
|
||||
/// Thus:
|
||||
/// b = MinPosition
|
||||
///
|
||||
/// We choose a 100000 tick granularity for the slider,
|
||||
/// at which point it will be at MaxPosition:
|
||||
/// MaxPosition = m * 100000 + b
|
||||
/// MaxPosition = m * 100000 + MinPosition
|
||||
///
|
||||
/// Thus:
|
||||
/// m = (MaxPosition - MinPosition) / 100000
|
||||
/// m = (MaxPosition - MinPosition) / sliderFullScale
|
||||
///
|
||||
/// And more generally, we have:
|
||||
///
|
||||
/// PlaybackPosition = [(MaxPosition - MinPosition) / sliderFullScale] * SliderPosition + MinPosition
|
||||
/// or:
|
||||
/// PlaybackPosition = ((MaxPosition - MinPosition) * SliderPosition / sliderFullScale) + MinPosition
|
||||
///
|
||||
/// </summary>
|
||||
public TimeSpan GetPlaybackPosition(double sliderPosition, double sliderFullScale, TimeSpan MinPosition, TimeSpan MaxPosition)
|
||||
{
|
||||
if (sliderFullScale == 0)
|
||||
return TimeSpan.Zero;
|
||||
return TimeSpan.FromTicks((long)((MaxPosition - MinPosition).Ticks * sliderPosition / sliderFullScale) + MinPosition.Ticks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given:
|
||||
/// y = m * x + b
|
||||
/// x = (y - b) /m
|
||||
///
|
||||
/// Where from above:
|
||||
/// b = MinPosition
|
||||
/// m = (MaxPosition - MinPosition) / sliderFullScale
|
||||
///
|
||||
/// We have:
|
||||
/// Position = (PlaybackPosition - MinPosition) * sliderFullScale / (MaxPosition - MinPosition)
|
||||
///
|
||||
/// </summary>
|
||||
public double GetSliderPositionAtPlaybackPosition(TimeSpan playbackPosition, double sliderFullScale, TimeSpan MinPosition, TimeSpan MaxPosition)
|
||||
{
|
||||
if ((MaxPosition - MinPosition).Ticks == 0)
|
||||
return 0;
|
||||
|
||||
if (playbackPosition == TimeSpan.Zero)
|
||||
{
|
||||
LoggerControl.Log("Transient playbackPosition == TimeSpan.Zero", LogViewLoggingLevel.Error);
|
||||
}
|
||||
|
||||
var interpolatedPosition = (playbackPosition - MinPosition).Ticks * sliderFullScale / (MaxPosition - MinPosition).Ticks;
|
||||
|
||||
if (interpolatedPosition < 0)
|
||||
{
|
||||
interpolatedPosition = 0;
|
||||
LoggerControl.Log("Transient calculatedPosition < 0", LogViewLoggingLevel.Error);
|
||||
}
|
||||
|
||||
return interpolatedPosition;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region DiscreteControls
|
||||
|
||||
private void SeekFixedAmount_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
TimeSpan amount = TimeSpan.Zero;
|
||||
string selected = (sender as Button).Tag.ToString();
|
||||
TimeSpan.TryParse(selected, out amount);
|
||||
if (amount != TimeSpan.Zero)
|
||||
{
|
||||
var requestedPosition = mediaPlayerElement.MediaPlayer.PlaybackSession.Position + amount;
|
||||
SeekToRequestedPosition(requestedPosition);
|
||||
}
|
||||
}
|
||||
|
||||
private void Play_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if(mediaPlayerElement.MediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Paused)
|
||||
{
|
||||
mediaPlayerElement.MediaPlayer.Play();
|
||||
}
|
||||
}
|
||||
|
||||
private void Pause_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayerElement.MediaPlayer.PlaybackSession.PlaybackState == MediaPlaybackState.Playing)
|
||||
{
|
||||
mediaPlayerElement.MediaPlayer.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
private void GoToStart_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayerElement.MediaPlayer != null)
|
||||
{
|
||||
var seekableRanges = mediaPlayerElement.MediaPlayer.PlaybackSession.GetSeekableRanges();
|
||||
if (seekableRanges.Count > 0)
|
||||
{
|
||||
UpdateSeekableRangesControl(seekableRanges);
|
||||
var requestedPosition = seekableRanges[0].Start;
|
||||
SeekToRequestedPosition(requestedPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GoToLive_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (mediaPlayerElement.MediaPlayer != null)
|
||||
{
|
||||
var seekableRanges = mediaPlayerElement.MediaPlayer.PlaybackSession.GetSeekableRanges();
|
||||
if (seekableRanges.Count > 0)
|
||||
{
|
||||
UpdateSeekableRangesControl(seekableRanges);
|
||||
var requestedPosition = seekableRanges[seekableRanges.Count-1].End;
|
||||
SeekToRequestedPosition(requestedPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RegisterForDiscreteControls(MediaPlayer mediaPlayer)
|
||||
{
|
||||
// PlaybackSession Events
|
||||
mediaPlayer.PlaybackSession.PlaybackStateChanged += MediaPlayer_PlaybackSession_PlaybackStateChanged;
|
||||
}
|
||||
|
||||
private void UnregisterForDiscreteControls(MediaPlayer mediaPlayer)
|
||||
{
|
||||
if (mediaPlayer == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// PlaybackSession Events
|
||||
mediaPlayer.PlaybackSession.PlaybackStateChanged -= MediaPlayer_PlaybackSession_PlaybackStateChanged;
|
||||
}
|
||||
|
||||
private async void MediaPlayer_PlaybackSession_PlaybackStateChanged(MediaPlaybackSession sender, object args)
|
||||
{
|
||||
Log($"PlaybackSession_PlaybackStateChanged, PlaybackState: {sender.PlaybackState}");
|
||||
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
switch (sender.PlaybackState)
|
||||
{
|
||||
case MediaPlaybackState.None:
|
||||
case MediaPlaybackState.Opening:
|
||||
case MediaPlaybackState.Buffering:
|
||||
PlayButton.IsEnabled = false;
|
||||
PauseButton.IsEnabled = false;
|
||||
break;
|
||||
case MediaPlaybackState.Playing:
|
||||
PlayButton.IsEnabled = false;
|
||||
PauseButton.IsEnabled = true;
|
||||
break;
|
||||
case MediaPlaybackState.Paused:
|
||||
PlayButton.IsEnabled = true;
|
||||
PauseButton.IsEnabled = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void LogCurrentTimeCorrelation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var adaptiveMediaSource = (mediaPlayerElement.MediaPlayer.Source as MediaPlaybackItem)?.Source?.AdaptiveMediaSource;
|
||||
if (adaptiveMediaSource == null)
|
||||
return;
|
||||
var times = adaptiveMediaSource.GetCorrelatedTimes();
|
||||
Log(times.ToJsonObject().ToString());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#endregion // CustomMediaControl
|
||||
|
||||
#region Utilities
|
||||
private void Log(string message)
|
||||
{
|
||||
LoggerControl.Log(message);
|
||||
}
|
||||
MediaPlayerLogger mediaPlayerLogger;
|
||||
MediaSourceLogger mediaSourceLogger;
|
||||
MediaPlaybackItemLogger mediaPlaybackItemLogger;
|
||||
AdaptiveMediaSourceLogger adaptiveMediaSourceLogger;
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -61,8 +61,8 @@ Build the sample
|
|||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -56,8 +56,8 @@ for more details.
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio<EFBFBD>2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -41,35 +41,35 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
|
|
@ -44,37 +44,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -44,37 +44,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -24,26 +24,26 @@ Specifically, this sample covers:
|
|||
- Discovering and connecting to an Onboardee's SoftAP.
|
||||
- Implementing method calls to get an Onboardee's network scan, configuring an Onboardee with WiFi credentials etc.
|
||||
|
||||
**Note** The Universal Windows samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Universal Windows samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
### Samples
|
||||
|
||||
[AllJoyn Producer Experiences](http://go.microsoft.com/fwlink/p/?LinkId=534025)
|
||||
[AllJoyn Consumer Experiences](http://go.microsoft.com/fwlink/p/?LinkID=534021)
|
||||
[AllJoyn Producer Experiences](http://go.microsoft.com/fwlink/p/?LinkId=534025)
|
||||
[AllJoyn Consumer Experiences](http://go.microsoft.com/fwlink/p/?LinkID=534021)
|
||||
|
||||
The AllSeen Alliance has samples in [Windows SDK](https://allseenalliance.org/developers/download)
|
||||
|
||||
### Reference
|
||||
|
||||
[MSDN Reference](https://msdn.microsoft.com/library/windows/apps/windows.devices.alljoyn.aspx)
|
||||
[AllJoyn Reference] (https://allseenalliance.org/developers/develop/api-reference)
|
||||
[Troubleshooting AllJoyn blog](http://channel9.msdn.com/Blogs/Internet-of-Things-Blog/Troubleshooting-AllJoyn-with-Windows-10-Insider-Preview-Builds)
|
||||
[MSDN Reference](https://msdn.microsoft.com/library/windows/apps/windows.devices.alljoyn.aspx)
|
||||
[AllJoyn Reference](https://allseenalliance.org/developers/develop/api-reference)
|
||||
[Troubleshooting AllJoyn blog](http://channel9.msdn.com/Blogs/Internet-of-Things-Blog/Troubleshooting-AllJoyn-with-Windows-10-Insider-Preview-Builds)
|
||||
|
||||
## System requirements
|
||||
|
||||
|
@ -57,8 +57,8 @@ ARM, ARM64, x86, or amd64 system
|
|||
|
||||
## Build the sample
|
||||
|
||||
1. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the C# language. Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
1. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the C# language. Double-click the Visual Studio Solution (.sln) file.
|
||||
3. Set the active solution configuration and platform to the desired values under **Build** \> **Configuration Manager**.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
|
|
|
@ -24,26 +24,26 @@ Specifically, this sample covers:
|
|||
- Creating and launching an Onboarding Producer.
|
||||
- Handling the Onboarding interface's Method calls, Property get/set requests and Signals.
|
||||
|
||||
**Note** The Universal Windows samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Universal Windows samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
### Samples
|
||||
|
||||
[AllJoyn Producer Experiences](http://go.microsoft.com/fwlink/p/?LinkId=534025)
|
||||
[AllJoyn Consumer Experiences](http://go.microsoft.com/fwlink/p/?LinkID=534021)
|
||||
[AllJoyn Producer Experiences](http://go.microsoft.com/fwlink/p/?LinkId=534025)
|
||||
[AllJoyn Consumer Experiences](http://go.microsoft.com/fwlink/p/?LinkID=534021)
|
||||
|
||||
The AllSeen Alliance has samples in [Windows SDK](https://allseenalliance.org/developers/download)
|
||||
|
||||
### Reference
|
||||
|
||||
[MSDN Reference](https://msdn.microsoft.com/library/windows/apps/windows.devices.alljoyn.aspx)
|
||||
[AllJoyn Reference] (https://allseenalliance.org/developers/develop/api-reference)
|
||||
[Troubleshooting AllJoyn blog](http://channel9.msdn.com/Blogs/Internet-of-Things-Blog/Troubleshooting-AllJoyn-with-Windows-10-Insider-Preview-Builds)
|
||||
[MSDN Reference](https://msdn.microsoft.com/library/windows/apps/windows.devices.alljoyn.aspx)
|
||||
[AllJoyn Reference](https://allseenalliance.org/developers/develop/api-reference)
|
||||
[Troubleshooting AllJoyn blog](http://channel9.msdn.com/Blogs/Internet-of-Things-Blog/Troubleshooting-AllJoyn-with-Windows-10-Insider-Preview-Builds)
|
||||
|
||||
## System requirements
|
||||
|
||||
|
@ -57,8 +57,8 @@ ARM, ARM64, x86, or amd64 system
|
|||
|
||||
## Build the sample
|
||||
|
||||
1. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the C# language. Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
1. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the C# language. Double-click the Visual Studio Solution (.sln) file.
|
||||
3. Set the active solution configuration and platform to the desired values under **Build** \> **Configuration Manager**.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
|
|
|
@ -38,8 +38,8 @@ When you choose the **Get Data** button for the **Polling** option, the app will
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -42,11 +42,11 @@ The sample demonstrates the following animation scenarios:
|
|||
|
||||
This sample is written in HTML, CSS, and JavaScript. For the XAML version, see the [XAML personality animations sample](http://go.microsoft.com/fwlink/p/?linkid=242401) and the [XAML animations sample](http://go.microsoft.com/fwlink/p/?linkid=242404).
|
||||
|
||||
**Note** The Universal Windows app samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Universal Windows app samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -104,8 +104,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -22,11 +22,11 @@ The sample shows the metrics involved in the following scenarios:
|
|||
- Adding an item to a list
|
||||
- Bringing a new page on the screen
|
||||
|
||||
**Note** The Universal Windows app samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Universal Windows app samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -49,8 +49,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -55,8 +55,8 @@ which an app service uses to receive and respond to messages.
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -59,8 +59,8 @@ The sample covers these key tasks:
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -19,11 +19,11 @@ The sample uses the [Windows.ApplicationModel.Resources.Core](http://msdn.micros
|
|||
|
||||
We encourage you to separate your resources, such as strings and files, from your app code, so you can maintain and alter your resources independently. You can use [Application Resources](http://msdn.microsoft.com/library/windows/apps/br225039) APIs to tailor your apps to a variety of device, system, and user configurations. Resources enable apps to be localized into multiple languages, customized for various device DPIs and form factors, and tailored for specific types of users.
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -46,8 +46,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -47,8 +47,8 @@ For more info about the concepts and APIs demonstrated in this sample, see these
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -65,8 +65,8 @@ To obtain an insider copy of Windows 10, go to [Windows 10](http://insider.windo
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -25,8 +25,8 @@ Build the sample
|
|||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -72,7 +72,7 @@ The custom effect has a property set that can be modified by calling the **SetPr
|
|||
Related topics
|
||||
--------------
|
||||
|
||||
[Windows.Media.Audio namespace] (https://msdn.microsoft.com/library/windows/apps/windows.media.audio.aspx)
|
||||
[Windows.Media.Audio namespace](https://msdn.microsoft.com/library/windows/apps/windows.media.audio.aspx)
|
||||
|
||||
|
||||
System requirements
|
||||
|
@ -86,8 +86,8 @@ Build the sample
|
|||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -60,6 +60,9 @@ namespace AudioCreation
|
|||
|
||||
private async void File_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Clear any old messages.
|
||||
rootPage.NotifyUser("", NotifyType.StatusMessage);
|
||||
|
||||
// If another file is already loaded into the FileInput node
|
||||
if (fileInput != null)
|
||||
{
|
||||
|
@ -96,6 +99,16 @@ namespace AudioCreation
|
|||
}
|
||||
|
||||
fileInput = fileInputResult.FileInputNode;
|
||||
|
||||
if (fileInput.Duration <= TimeSpan.FromSeconds(3))
|
||||
{
|
||||
// Imported file is too short
|
||||
rootPage.NotifyUser("Please pick an audio file which is longer than 3 seconds", NotifyType.ErrorMessage);
|
||||
fileInput.Dispose();
|
||||
fileInput = null;
|
||||
return;
|
||||
}
|
||||
|
||||
fileInput.AddOutgoingConnection(deviceOutput);
|
||||
fileButton.Background = new SolidColorBrush(Colors.Green);
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ To obtain an insider copy of Windows 10, go to [Windows 10](http://insider.windo
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -41,37 +41,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -14,7 +14,7 @@ Shows how to create and register background tasks that will run in the main proc
|
|||
> the samples collection, and GitHub, see [Get the UWP samples from GitHub](https://aka.ms/ovu2uq).
|
||||
> For more samples, see the [Samples portal](https://aka.ms/winsamples) on the Windows Dev Center.
|
||||
|
||||
**Note** This Universal Windows app sample requires Visual Studio 2015 to build and Windows 10 Anniversay Update to execute.
|
||||
**Note** This Universal Windows app sample requires Visual Studio 2017 to build and Windows 10 Anniversay Update to execute.
|
||||
|
||||
A background task is triggered by a system or time event and can be constrained by one or more conditions. When a background task is triggered, OnBackgroundActivated is invoked and performs the work of the background task. A background task can run even when the app that registered the background task is suspended or not running.
|
||||
|
||||
|
@ -72,8 +72,8 @@ Windows Phone 10 Anniversary Update
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -43,37 +43,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -334,8 +334,8 @@ Build the sample
|
|||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -42,8 +42,8 @@ Related topics
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -44,37 +44,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -76,8 +76,8 @@ Windows Phone 10
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -44,37 +44,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -67,8 +67,8 @@ For more information on network capabilities, see [How to set network capabiliti
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
### Deploying and running the Windows version of the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -44,37 +44,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -18,7 +18,7 @@ This sample shows how to:
|
|||
|
||||
1. **Obtain the barcode scanner**
|
||||
|
||||
Uses a [**DeviceWatcher**](https://docs.microsoft.com/en-us/uwp/api/Windows.Devices.Enumeration.DeviceWatcher)
|
||||
Uses a [**DeviceWatcher**](https://docs.microsoft.com/uwp/api/Windows.Devices.Enumeration.DeviceWatcher)
|
||||
to enumerate and select the first barcode scanner.
|
||||
|
||||
2. **Claim the barcode scanner for exclusive use**
|
||||
|
@ -47,20 +47,20 @@ This sample shows how to:
|
|||
|
||||
The app package manifest shows how to specify the device capability name for the Point of Service (POS) devices. All POS apps are required declare [DeviceCapability](http://msdn.microsoft.com/library/windows/apps/br211430) in the app package manifest, either by using "PointofService" as shown in this sample or by using a device specific GUID, such as "C243FFBD-3AFC-45E9-B3D3-2BA18BC7EBC5" for a barcode scanner.
|
||||
|
||||
For a list of compatible barcode scanners, see [Barcode Scanner Compatible Hardware](https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/barcode-scanner#compatible-hardware).
|
||||
For a list of compatible barcode scanners, see [Barcode Scanner Compatible Hardware](https://docs.microsoft.com/windows/uwp/devices-sensors/barcode-scanner#compatible-hardware).
|
||||
|
||||
**Note** The Universal Windows app samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Universal Windows app samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
### Reference
|
||||
|
||||
[Windows.Devices.PointOfService namespace](http://msdn.microsoft.com/library/windows/apps/dn298071)
|
||||
[Barcode Scanner Compatible Hardware](https://docs.microsoft.com/en-us/windows/uwp/devices-sensors/barcode-scanner#compatible-hardware)
|
||||
[Barcode Scanner Compatible Hardware](https://docs.microsoft.com/windows/uwp/devices-sensors/barcode-scanner#compatible-hardware)
|
||||
[USB HID POS Scanner specification](http://go.microsoft.com/fwlink/p/?linkid=309230)
|
||||
[Windows app samples](http://go.microsoft.com/fwlink/p/?LinkID=227694)
|
||||
|
||||
|
@ -75,8 +75,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -38,8 +38,8 @@ When you choose the **Get Data** button for the **Polling** option, the app will
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -23,11 +23,11 @@ Specifically, this sample shows how to:
|
|||
- **Acquire a video frame** from a video capture stream and convert it to a format supported by FaceDetector
|
||||
- **Retrieve results** from FaceDetector and visualize them
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -74,8 +74,8 @@ The FaceDetector is intended to operate on a static image or a single frame of v
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++ or C#). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++ or C#). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -41,35 +41,35 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
|
|
@ -23,11 +23,11 @@ Specifically, this sample shows how to:
|
|||
- **Acquire video frames** from the video capture stream and convert it to a format supported by FaceTracker
|
||||
- **Retrieve results** from FaceTracker and visualize them
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -64,8 +64,8 @@ The FaceTracker is intended to operate on a running video stream and is optimize
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -41,35 +41,35 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
|
|
@ -22,11 +22,11 @@ Specifically, this sample shows how to:
|
|||
- **Manipulate a XAML element:** Use the ManipulationMode property to register for specific manipulation events on XAML elements and react to them in order to move and rotate the element.
|
||||
- **Manipulate an object using a GestureRecognizer:** Use an instance of a GestureRecognizer to move and rotate an object. This is useful if your app uses its own framework and, thus, cannot use the manipulation events on XAML elements.
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -55,8 +55,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -41,35 +41,35 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
|
|
@ -48,8 +48,8 @@ Build the sample
|
|||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -21,7 +21,7 @@ Specifically, this sample covers:
|
|||
|
||||
From the Visual Studio debugging toolbar, use the Lifecycle Events menu to trigger suspend and resume events.
|
||||
|
||||
**Note** The Universal Windows app samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Universal Windows app samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain an insider copy of Windows 10, go to [Windows 10](http://insider.windows.com).
|
||||
|
||||
|
@ -45,8 +45,8 @@ To obtain an insider copy of Windows 10, go to [Windows 10](http://insider.windo
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -34,8 +34,8 @@ This sample allows the user to publish and watch for Bluetooth Low Energy advert
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -28,11 +28,11 @@ Search for "BT_Code" to find the portions of the sample that are particularly
|
|||
relevant to Bluetooth.
|
||||
Note in particular the "bluetooth" capability declaration in the manifest.
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -67,8 +67,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio?2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -38,11 +38,11 @@ Same as the Foreground Chat Server,
|
|||
except that it initializes a Background task that runs only when a client device is connected.
|
||||
The host device will advertise support for the custom service in the SDP record until the background task is unregistered.
|
||||
|
||||
**Note:** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note:** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
## Related topics
|
||||
|
||||
|
@ -66,8 +66,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
|
||||
## Build the sample
|
||||
|
||||
1. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the language you desire - either C++, C#, or JavaScript. Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
1. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Go to the directory to which you unzipped the sample. Then go to the subdirectory containing the sample in the language you desire - either C++, C#, or JavaScript. Double-click the Visual Studio Solution (.sln) file.
|
||||
3. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -75,8 +75,8 @@ This scenario also demonstrates converting from a language-specific date type to
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -21,11 +21,11 @@ Specifically, this sample shows how to:
|
|||
|
||||
See the Package.appxmanifest file for the extensions and capabilities a Caller ID app must declare.
|
||||
|
||||
**Note** The Windows universal samples require Visual Studio 2015 to build and Windows 10 to execute.
|
||||
**Note** The Windows universal samples require Visual Studio 2017 to build and Windows 10 to execute.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](http://go.microsoft.com/fwlink/?LinkID=532421)
|
||||
|
||||
To obtain information about Microsoft Visual Studio 2015 and the tools for developing Windows apps, go to [Visual Studio 2015](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
To obtain information about Microsoft Visual Studio and the tools for developing Windows apps, go to [Visual Studio](http://go.microsoft.com/fwlink/?LinkID=532422)
|
||||
|
||||
### Reference
|
||||
|
||||
|
@ -46,8 +46,8 @@ To obtain information about Microsoft Visual Studio 2015 and the tools for devel
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio?2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -84,8 +84,8 @@ This sample also implements a custom UI to better simulate the experience that a
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -68,8 +68,8 @@ This sample also implements a custom UI to better simulate the experience that a
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -41,7 +41,7 @@ Use the FrameReader class to read frames from a frame source as they arrive.
|
|||
|
||||
### Additional remarks
|
||||
|
||||
**Note** The Windows universal samples for Windows 10 require Visual Studio 2015 Update 2
|
||||
**Note** The Windows universal samples for Windows 10 require Visual Studio 2017 Update 2
|
||||
and Windows SDK version 14332 or above to build.
|
||||
|
||||
To obtain information about Windows 10 development, go to the [Windows Dev Center](https://dev.windows.com).
|
||||
|
@ -64,10 +64,10 @@ To obtain information about Windows 10 development, go to the [Windows Dev Cente
|
|||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with
|
||||
the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the
|
||||
subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or
|
||||
JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -41,35 +41,35 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
|
|
|
@ -59,8 +59,8 @@ Due to the custom UI that this sample implements, any messages intended for the
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!---
|
||||
<!---
|
||||
category: AudioVideoAndCamera
|
||||
samplefwlink: http://go.microsoft.com/fwlink/p/?LinkId=620517
|
||||
--->
|
||||
|
|
|
@ -77,8 +77,8 @@ To keep code complexity low, but offer easier navigation between the different c
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
|
@ -19,31 +19,31 @@ addition, the developer can query the driver to see if it supports additional fe
|
|||
|
||||
This sample covers:
|
||||
|
||||
Scenario 1: Locate a Record Specific Profile: You can use profiles to verify if a camera supports a specific resolution or
|
||||
Scenario 1: Locate a Record Specific Profile: You can use profiles to verify if a camera supports a specific resolution or
|
||||
custom setting via querying for video profile. We demonstrate two methods:
|
||||
1) When you choose "Find 640x480 30 FPS Recording Profile" button, we determine if the back video capture device supports
|
||||
a camera profile with a 640x480(WVGA) 30 FPS resolution. We first check if the back video capture device supports a Video
|
||||
Profile. We iterate through all the profiles the device supports to demonstrate available Video Profiles on the device. Then
|
||||
we search for the 640x480(WVGA) 30 FPS profile. If located, we initialize Media Capture Settings with this profile.
|
||||
2) When you choose the "Find Custom Recording Profile" button, we are looking to see if a device supports a specific Custom
|
||||
Profile. The custom profile would allow the camera driver to optimize for additional features. For this demonstration we use
|
||||
a static profile for 640x480 30 FPS that is avaliable in the phone emulators.
|
||||
1. When you choose "Find 640x480 30 FPS Recording Profile" button, we determine if the back video capture device supports
|
||||
a camera profile with a 640x480(WVGA) 30 FPS resolution. We first check if the back video capture device supports a Video
|
||||
Profile. We iterate through all the profiles the device supports to demonstrate available Video Profiles on the device. Then
|
||||
we search for the 640x480(WVGA) 30 FPS profile. If located, we initialize Media Capture Settings with this profile.
|
||||
2. When you choose the "Find Custom Recording Profile" button, we are looking to see if a device supports a specific Custom
|
||||
Profile. The custom profile would allow the camera driver to optimize for additional features. For this demonstration we use
|
||||
a static profile for 640x480 30 FPS that is avaliable in the phone emulators.
|
||||
|
||||
Scenario 2: Query Profile for Concurrency: This scenarios demonstrates using profiles to determine if a device is capable of streaming
|
||||
from both the front and rear video capture devices at the same time.
|
||||
1) When you choose "Query for Concurrent Profile button, the app queries for a front and back device that supports a video profile. If a profile
|
||||
is supported on both devices we then check the devices for profiles that support concurrency. From the available profiles we look for a concurrent profile match on both
|
||||
devices. If a concurrent profile match is found, we initialize both front and back Media Capture settings of the devices to the concurrency profile.
|
||||
from both the front and rear video capture devices at the same time.
|
||||
1. When you choose "Query for Concurrent Profile button, the app queries for a front and back device that supports a video profile. If a profile
|
||||
is supported on both devices we then check the devices for profiles that support concurrency. From the available profiles we look for a concurrent profile match on both
|
||||
devices. If a concurrent profile match is found, we initialize both front and back Media Capture settings of the devices to the concurrency profile.
|
||||
|
||||
Scenario 3: Query Profile for Hdr Support: This scenarios demonstrates using Camera Profile to determine if a device is capable of supporting
|
||||
Scenario 3: Query Profile for Hdr Support: This scenarios demonstrates using Camera Profile to determine if a device is capable of supporting
|
||||
Hdr Video.
|
||||
1) When you choose "Query Profile for HDR Support" button, the app will query the if the back video capture device supports a Video Profile. Then we query the available profiles
|
||||
to see if Hdr Video is supported calling the IsHdrVideoSupported() method. If so, we set Media Capture settings to the Hdr supported video profile and set Hdr Video mode to auto.
|
||||
1. When you choose "Query Profile for HDR Support" button, the app will query the if the back video capture device supports a Video Profile. Then we query the available profiles
|
||||
to see if Hdr Video is supported calling the IsHdrVideoSupported() method. If so, we set Media Capture settings to the Hdr supported video profile and set Hdr Video mode to auto.
|
||||
|
||||
Related topics
|
||||
--------------
|
||||
[Windows.Media.Capture.MediaCapture namespace] (https://msdn.microsoft.com/library/windows/apps/windows.media.devices.aspx)
|
||||
[Windows.Devices.Enumeration namespace] (https://msdn.microsoft.com/library/windows/apps/windows.devices.enumeration.aspx)
|
||||
[Windows.Media.Capture.MediaCapture namespace](https://msdn.microsoft.com/library/windows/apps/windows.media.devices.aspx)
|
||||
[Windows.Devices.Enumeration namespace](https://msdn.microsoft.com/library/windows/apps/windows.devices.enumeration.aspx)
|
||||
|
||||
**Conceptual**
|
||||
|
||||
|
@ -58,16 +58,17 @@ Related topics
|
|||
System requirements
|
||||
-----------------------------
|
||||
Camera that supports Video Profiles
|
||||
Client
|
||||
Windows 10
|
||||
Windows Phone 10
|
||||
|
||||
**Client:** Windows 10
|
||||
|
||||
**Phone:** Windows 10
|
||||
|
||||
Build the sample
|
||||
----------------
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
Run the sample
|
||||
|
|
|
@ -42,37 +42,37 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<PlatformToolset>v141</PlatformToolset>
|
||||
<UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
|
|
|
@ -81,8 +81,8 @@ the changes will be reflected in any videos taken with the video button.
|
|||
## Build the sample
|
||||
|
||||
1. If you download the samples ZIP, be sure to unzip the entire archive, not just the folder with the sample you want to build.
|
||||
2. Start Microsoft Visual Studio 2015 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio 2015 Solution (.sln) file.
|
||||
2. Start Microsoft Visual Studio 2017 and select **File** \> **Open** \> **Project/Solution**.
|
||||
3. Starting in the folder where you unzipped the samples, go to the Samples subfolder, then the subfolder for this specific sample, then the subfolder for your preferred language (C++, C#, or JavaScript). Double-click the Visual Studio Solution (.sln) file.
|
||||
4. Press Ctrl+Shift+B, or select **Build** \> **Build Solution**.
|
||||
|
||||
## Run the sample
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче