From 124bf327709706e5fda91f0d44f804f5b6844dd2 Mon Sep 17 00:00:00 2001 From: Matt Goldman Date: Fri, 3 Apr 2026 13:02:50 +1100 Subject: [PATCH 1/4] Add StreamMediaSource documentation --- docs/maui/views/MediaElement.md | 40 +++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/docs/maui/views/MediaElement.md b/docs/maui/views/MediaElement.md index 3da67118..9fcf9828 100644 --- a/docs/maui/views/MediaElement.md +++ b/docs/maui/views/MediaElement.md @@ -13,6 +13,7 @@ ms.date: 02/15/2024 - The web, using a URI (HTTP or HTTPS). - A resource embedded in the platform application, using the `embed://` URI scheme. - Files that come from the app's local filesystem, using the `filesystem://` URI scheme. +- Any valid source via a `Stream`. `MediaElement` can use the platform playback controls, which are referred to as transport controls. However, they are disabled by default and can be replaced with your own transport controls. The following screenshots show `MediaElement` playing a video with the platform transport controls: @@ -239,6 +240,39 @@ An example of how to use this syntax in XAML can be seen below. ShouldShowPlaybackControls="True" /> ``` +### Play media from a Stream + +You can play media from a `Stream`, which enables scenarios where end-to-end capture and playback remains in memory. + +Consider for example capturing a video using [`MediaPicker`](https://learn.microsoft.com/dotnet/maui/platform-integration/device-media/picker): + +```csharp +var videoResult = await MediaPicker.Default.CaptureVideoAsync(new MediaPickerOptions +{ + Title = "Capture Video" +}); +``` + +`videoResult` is a `FileResult` and the stream can be read directly by a `MediaElement`. + + +```xaml + +``` + +Copying it to a new stream allows you to set the position to 0 (so it can be read and controlled by the `MediaElement`) and disposed properly. + +```csharp +await using var stream = await videoResult.OpenReadAsync(); +var memoryStream = new MemoryStream(); +await stream.CopyToAsync(memoryStream); +memoryStream.Position = 0; + +MyMediaElement.Source = MediaSource.FromStream(memoryStream); +``` + +This may be particularly useful for scenarios with security requirements that don't allow saving data outside the app's sandboxed environment. + ## Understand MediaSource types A `MediaElement` can play media by setting its `Source` property to a remote or local media file. The `Source` property is of type `MediaSource`, and this class defines three static methods: @@ -246,6 +280,7 @@ A `MediaElement` can play media by setting its `Source` property to a remote or - `FromFile`, returns a `FileMediaSource` instance from a `string` argument. - `FromUri`, returns a `UriMediaSource` instance from a `Uri` argument. - `FromResource`, returns a `ResourceMediaSource` instance from a `string` argument. +- `FromStream`, returns a `StreamMediaSource` instance from a `Stream` argument. In addition, the `MediaSource` class also has implicit operators that return `MediaSource` instances from `string` and `Uri` arguments. @@ -257,6 +292,7 @@ The `MediaSource` class also has these derived classes: - `FileMediaSource`, which is used to specify a local media file from a `string`. This class has a `Path` property that can be set to a `string`. In addition, this class has implicit operators to convert a `string` to a `FileMediaSource` object, and a `FileMediaSource` object to a `string`. - `UriMediaSource`, which is used to specify a remote media file from a URI. This class has a `Uri` property that can be set to a `Uri`. - `ResourceMediaSource`, which is used to specify an embedded file that is provided through the app's resource files. This class has a `Path` property that can be set to a `string`. +- `StreamMediaSource`, which is ised to specify a stream that is read from incrementally from a memory, file, or remote source. > [!NOTE] > When a `FileMediaSource` object is created in XAML, a type converter is invoked to return a `FileMediaSource` instance from a `string`. @@ -374,7 +410,7 @@ Media playback controls implemented by each platform include a volume bar. This A custom volume bar can be implemented using a [`Slider`](xref:Microsoft.Maui.Controls.Slider), as shown in the following example: ```xaml - + - + ``` In this example, the [`Slider`](xref:Microsoft.Maui.Controls.Slider) data binds its `Value` property to the `Volume` property of the `MediaElement`. This is possible because the `Volume` property uses a `TwoWay` binding. Therefore, changing the `Value` property will result in the `Volume` property changing. From 8d0613c0520c568b9a0f6d7617968b6b83741a76 Mon Sep 17 00:00:00 2001 From: Matt Goldman Date: Fri, 3 Apr 2026 13:09:42 +1100 Subject: [PATCH 2/4] Spelling/typos --- docs/maui/views/MediaElement.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/maui/views/MediaElement.md b/docs/maui/views/MediaElement.md index 9fcf9828..4e229044 100644 --- a/docs/maui/views/MediaElement.md +++ b/docs/maui/views/MediaElement.md @@ -223,7 +223,7 @@ Local media can be played from the following sources: - Files that come from the app's local filesystem, using the `filesystem://` URI scheme. > [!NOTE] -> The shorthand `embed://` and `filesystem://` only work from XAML. In code, please use `MediaSource.FromResource()` and `MediaSource.FromFile()` respectively. Using these methods, you can omit the the `embed://` and `filesystem://` prefixes. The rest of the path should be the same. +> The shorthand `embed://` and `filesystem://` only work from XAML. In code, please use `MediaSource.FromResource()` and `MediaSource.FromFile()` respectively. Using these methods, you can omit the `embed://` and `filesystem://` prefixes. The rest of the path should be the same. ### Play media embedded in the app package @@ -251,16 +251,21 @@ var videoResult = await MediaPicker.Default.CaptureVideoAsync(new MediaPickerOpt { Title = "Capture Video" }); + +if (videoResult is null) +{ + return; +} ``` -`videoResult` is a `FileResult` and the stream can be read directly by a `MediaElement`. +`videoResult` is a `FileResult`, and its stream can be read by a `MediaElement`. ```xaml ``` -Copying it to a new stream allows you to set the position to 0 (so it can be read and controlled by the `MediaElement`) and disposed properly. +Copying it to a new stream lets you reset the position to 0 so the `MediaElement` can read it correctly. Keep that stream alive for the duration of playback, and dispose it when it's no longer needed. ```csharp await using var stream = await videoResult.OpenReadAsync(); @@ -275,7 +280,7 @@ This may be particularly useful for scenarios with security requirements that do ## Understand MediaSource types -A `MediaElement` can play media by setting its `Source` property to a remote or local media file. The `Source` property is of type `MediaSource`, and this class defines three static methods: +A `MediaElement` can play media by setting its `Source` property to a remote or local media file. The `Source` property is of type `MediaSource`, and this class defines four static methods: - `FromFile`, returns a `FileMediaSource` instance from a `string` argument. - `FromUri`, returns a `UriMediaSource` instance from a `Uri` argument. @@ -292,7 +297,7 @@ The `MediaSource` class also has these derived classes: - `FileMediaSource`, which is used to specify a local media file from a `string`. This class has a `Path` property that can be set to a `string`. In addition, this class has implicit operators to convert a `string` to a `FileMediaSource` object, and a `FileMediaSource` object to a `string`. - `UriMediaSource`, which is used to specify a remote media file from a URI. This class has a `Uri` property that can be set to a `Uri`. - `ResourceMediaSource`, which is used to specify an embedded file that is provided through the app's resource files. This class has a `Path` property that can be set to a `string`. -- `StreamMediaSource`, which is ised to specify a stream that is read from incrementally from a memory, file, or remote source. +- `StreamMediaSource`, which is used to specify a stream that is read incrementally from memory, a file, or a remote source. > [!NOTE] > When a `FileMediaSource` object is created in XAML, a type converter is invoked to return a `FileMediaSource` instance from a `string`. From f59064f8a402dee2e542710cc16cc6ca823c620e Mon Sep 17 00:00:00 2001 From: Matt Goldman Date: Fri, 3 Apr 2026 13:10:30 +1100 Subject: [PATCH 3/4] Update note to suggest bindable properties for non-string converted sources --- docs/maui/views/MediaElement.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/maui/views/MediaElement.md b/docs/maui/views/MediaElement.md index 4e229044..a5a481ae 100644 --- a/docs/maui/views/MediaElement.md +++ b/docs/maui/views/MediaElement.md @@ -223,7 +223,7 @@ Local media can be played from the following sources: - Files that come from the app's local filesystem, using the `filesystem://` URI scheme. > [!NOTE] -> The shorthand `embed://` and `filesystem://` only work from XAML. In code, please use `MediaSource.FromResource()` and `MediaSource.FromFile()` respectively. Using these methods, you can omit the `embed://` and `filesystem://` prefixes. The rest of the path should be the same. +> The shorthand `embed://` and `filesystem://` only work when `Source` is set from a string in XAML. In code, please use `MediaSource.FromResource()` and `MediaSource.FromFile()` respectively. Using these methods, you can omit the `embed://` and `filesystem://` prefixes. The rest of the path should be the same. Stream-backed sources don't have an equivalent URI-style XAML shorthand. To use a stream source with XAML, bind `Source` to a `MediaSource` instance created in code. ### Play media embedded in the app package From 6d64fe6e27eb425da1d677c82460f18d6463ac3b Mon Sep 17 00:00:00 2001 From: Matt Goldman Date: Fri, 10 Apr 2026 17:45:38 +1000 Subject: [PATCH 4/4] Update docs/maui/views/MediaElement.md Co-authored-by: Shaun Lawrence --- docs/maui/views/MediaElement.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/maui/views/MediaElement.md b/docs/maui/views/MediaElement.md index a5a481ae..f603317e 100644 --- a/docs/maui/views/MediaElement.md +++ b/docs/maui/views/MediaElement.md @@ -244,7 +244,7 @@ An example of how to use this syntax in XAML can be seen below. You can play media from a `Stream`, which enables scenarios where end-to-end capture and playback remains in memory. -Consider for example capturing a video using [`MediaPicker`](https://learn.microsoft.com/dotnet/maui/platform-integration/device-media/picker): +Consider for example capturing a video using [`MediaPicker`](/dotnet/maui/platform-integration/device-media/picker): ```csharp var videoResult = await MediaPicker.Default.CaptureVideoAsync(new MediaPickerOptions