diff --git a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor
index 8cf435af1fc..73c72d0bf9b 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor
+++ b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor
@@ -18,6 +18,7 @@ private IVideoDevice? VideoDeviceService { get; set; }
+
diff --git a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs
index 0635c200592..46d1b06ae95 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/VideoDevices.razor.cs
@@ -13,6 +13,9 @@ public partial class VideoDevices : IAsyncDisposable
[Inject, NotNull]
private IVideoDevice? VideoDeviceService { get; set; }
+ [Inject, NotNull]
+ private DownloadService? DownloadService { get; set; }
+
private readonly List _devices = [];
private List _items = [];
@@ -61,6 +64,15 @@ private async Task OnCapture()
_previewUrl = await VideoDeviceService.GetPreviewUrl();
}
+ private async Task OnDownload()
+ {
+ var stream = await VideoDeviceService.GetPreviewData();
+ if (stream != null)
+ {
+ await DownloadService.DownloadFromStreamAsync("preview.png", stream);
+ }
+ }
+
private async Task OnApply(int width, int height) => await VideoDeviceService.Apply(new MediaTrackConstraints() { Width = width, Height = height });
private async Task DisposeAsync(bool disposing)
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index 22785ecd4e6..d9d406a223e 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -7128,7 +7128,7 @@
"VideoDeviceOpenText": "Open",
"VideoDeviceCloseText": "Close",
"VideoDeviceCaptureText": "Capture",
- "VideoDeviceFlipText": "Flip"
+ "VideoDeviceDownloadText": "Download"
},
"BootstrapBlazor.Server.Components.Samples.AudioDevices": {
"AudioDeviceTitle": "IAudioDevice",
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index 5e3cc128f15..f35f000f138 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -7128,7 +7128,7 @@
"VideoDeviceOpenText": "打开设备",
"VideoDeviceCloseText": "关闭设备",
"VideoDeviceCaptureText": "截图",
- "VideoDeviceFlipText": "翻转镜头"
+ "VideoDeviceDownloadText": "下载"
},
"BootstrapBlazor.Server.Components.Samples.AudioDevices": {
"AudioDeviceTitle": "IAudioDevice 音频设备服务",
diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj
index 1a7f7ef8660..d7b84e4d7b4 100644
--- a/src/BootstrapBlazor/BootstrapBlazor.csproj
+++ b/src/BootstrapBlazor/BootstrapBlazor.csproj
@@ -1,7 +1,7 @@
- 9.6.1-beta02
+ 9.6.1-beta03
diff --git a/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs b/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
index 37e124abed0..2e4914bb1ea 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/DefaultMediaDevices.cs
@@ -45,6 +45,18 @@ public async Task Capture()
return await module.InvokeAsync("getPreviewUrl");
}
+ public async Task GetPreviewData()
+ {
+ Stream? ret = null;
+ var module = await LoadModule();
+ var stream = await module.InvokeAsync("getPreviewData");
+ if (stream != null)
+ {
+ ret = await stream.OpenReadStreamAsync(stream.Length);
+ }
+ return ret;
+ }
+
public async Task Apply(MediaTrackConstraints constraints)
{
var module = await LoadModule();
diff --git a/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs b/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs
index b4af4b6de4a..e68dbae597d 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/DefaultVideoDevice.cs
@@ -37,6 +37,11 @@ public Task Capture()
return deviceService.Capture();
}
+ public Task GetPreviewData()
+ {
+ return deviceService.GetPreviewData();
+ }
+
public Task GetPreviewUrl()
{
return deviceService.GetPreviewUrl();
diff --git a/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs b/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
index 8cd7345d6c4..67466fabca4 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/IMediaDevices.cs
@@ -43,6 +43,12 @@ public interface IMediaDevices
///
Task GetPreviewUrl();
+ ///
+ /// Gets the stream of the captured image.
+ ///
+ ///
+ Task GetPreviewData();
+
///
/// Apply the media track constraints.
///
diff --git a/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs b/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
index c197c87bf37..b72bcf73221 100644
--- a/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
+++ b/src/BootstrapBlazor/Services/MediaDevices/IVideoDevice.cs
@@ -36,24 +36,18 @@ public interface IVideoDevice
///
Task Capture();
- /////
- ///// Preview a still image from the video stream.
- /////
- /////
- //Task Preview();
-
- /////
- ///// Gets the stream of the captured image.
- /////
- /////
- //Task GetPreviewImage();
-
///
/// Gets the preview URL of the captured image.
///
///
Task GetPreviewUrl();
+ ///
+ /// Gets the stream of the captured image.
+ ///
+ ///
+ Task GetPreviewData();
+
///
/// Apply the media track constraints.
///
diff --git a/src/BootstrapBlazor/wwwroot/modules/media.js b/src/BootstrapBlazor/wwwroot/modules/media.js
index 53944134c3d..cef7f694731 100644
--- a/src/BootstrapBlazor/wwwroot/modules/media.js
+++ b/src/BootstrapBlazor/wwwroot/modules/media.js
@@ -6,8 +6,13 @@ export async function enumerateDevices() {
console.log("enumerateDevices() not supported.");
}
else {
- await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
- ret = await navigator.mediaDevices.enumerateDevices();
+ try {
+ await navigator.mediaDevices.getUserMedia({ video: true, audio: true });
+ ret = await navigator.mediaDevices.enumerateDevices();
+ }
+ catch (e) {
+ console.warn(e);
+ }
}
return ret;
}
@@ -25,12 +30,12 @@ export async function open(type, options) {
export async function close(selector) {
const media = registerBootstrapBlazorModule("MediaDevices");
- let ret = false;
+ let ret;
if (media.stream) {
ret = await closeVideoDevice(selector);
}
else {
- ret = await stop(selector);
+ ret = stop(selector);
}
return ret;
}
@@ -143,11 +148,17 @@ export async function getPreviewUrl() {
const capture = new ImageCapture(track);
const blob = await capture.takePhoto();
url = URL.createObjectURL(blob);
+ media.previewBlob = blob;
}
}
return url;
}
+export function getPreviewData() {
+ const media = registerBootstrapBlazorModule("MediaDevices");
+ return media.previewBlob;
+}
+
const closeStream = stream => {
if (stream) {
const tracks = stream.getTracks();
@@ -205,7 +216,7 @@ export async function record(options) {
return ret;
}
-export async function stop(selector) {
+export function stop(selector) {
let ret = false;
const media = registerBootstrapBlazorModule("MediaDevices");
if (selector) {
diff --git a/test/UnitTest/Services/VideoDeviceTest.cs b/test/UnitTest/Services/VideoDeviceTest.cs
index 500100ea64f..64e4b616273 100644
--- a/test/UnitTest/Services/VideoDeviceTest.cs
+++ b/test/UnitTest/Services/VideoDeviceTest.cs
@@ -3,6 +3,9 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
+using Microsoft.JSInterop;
+using UnitTest.Mock;
+
namespace UnitTest.Services;
public class VideoDeviceTest : BootstrapBlazorTestBase
@@ -27,6 +30,7 @@ public async Task GetDevices_Ok()
public async Task Open_Ok()
{
Context.JSInterop.Setup("getPreviewUrl").SetResult("blob:https://test-preview");
+ Context.JSInterop.Setup("getPreviewData").SetResult(new MockJSStreamReference());
Context.JSInterop.Setup("open", _ => true).SetResult(true);
Context.JSInterop.Setup("close", _ => true).SetResult(true);
Context.JSInterop.Setup("apply", _ => true).SetResult(true);
@@ -58,5 +62,9 @@ public async Task Open_Ok()
await service.Capture();
var url = await service.GetPreviewUrl();
Assert.Equal("blob:https://test-preview", url);
+
+ var data = await service.GetPreviewData();
+ Assert.NotNull(data);
+ Assert.Equal(4, data.Length);
}
}