mirror of
https://github.com/microsoft/PowerToys
synced 2025-08-22 01:58:04 +00:00
Add missing codec detection and warning message in video preview (#39726)
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR adds support for detecting missing video codecs during video file preview, and displays a warning message to inform the user when the required codec is not installed. ### Changes - Added `GetMissingCodecAsync` to detect unsupported video formats using `MediaEncodingProfile` and `CodecQuery`. - If a required codec is missing, display a warning in the preview UI. - Added localized string `MissingVideoCodec_WarningMessage`: > "This video uses the {0} format, which isn't supported. Please install the required codec to play it." - Add Store Search   <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] **Closes:** https://github.com/microsoft/PowerToys/issues/39235, https://github.com/microsoft/PowerToys/issues/38201 - [ ] **Communication:** I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [x] **Localization:** All end user facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [WXS for installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs) for new binaries and localization folder - [ ] [YML for CI pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml) for new test projects - [ ] [YML for signed pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml) - [ ] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #xxx <!-- Provide a more detailed description of the PR, other things fixed or any additional comments/features here --> ## Detailed Description of the Pull Request / Additional comments <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed To simulate a missing codec (e.g., AV1): 1. Check if the AV1 extension is installed: ```powershell Get-AppxPackage -Name *AV1* 2. If installed, remove it: ```powershell Get-AppxPackage -Name *AV1* | Remove-AppxPackage 3. Use Peek to preview a video encoded in AV1 format. 4. Confirm that a warning message is shown indicating the missing codec.
This commit is contained in:
parent
a1cf836c6d
commit
96c5cf1897
@ -60,6 +60,21 @@
|
||||
</MediaPlayerElement.TransportControls>
|
||||
</MediaPlayerElement>
|
||||
|
||||
<RichTextBlock
|
||||
x:Name="VideoWarningMessage"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
Foreground="{StaticResource TextFillColorSecondaryBrush}"
|
||||
Visibility="{x:Bind IsWarningMessageVisible(VideoPreviewer.MissingCodecName), Mode=OneWay}">
|
||||
<Paragraph>
|
||||
<Run Text="{x:Bind GetWarningMessage(VideoPreviewer.MissingCodecName), Mode=OneWay}" />
|
||||
<Hyperlink Click="CodecSearchHyperlink_Click">
|
||||
<Run x:Uid="VideoCodecStoreLink" />
|
||||
</Hyperlink>
|
||||
</Paragraph>
|
||||
</RichTextBlock>
|
||||
|
||||
|
||||
<controls:AudioControl
|
||||
x:Name="AudioPreview"
|
||||
Source="{x:Bind AudioPreviewer.Preview, Mode=OneWay}"
|
||||
|
@ -14,6 +14,7 @@ using Microsoft.PowerToys.Telemetry;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Controls.Primitives;
|
||||
using Microsoft.UI.Xaml.Documents;
|
||||
using Microsoft.UI.Xaml.Input;
|
||||
using Microsoft.Web.WebView2.Core;
|
||||
using Peek.Common.Extensions;
|
||||
@ -149,6 +150,28 @@ namespace Peek.FilePreviewer
|
||||
return isValidPreview ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public Visibility IsWarningMessageVisible(string? missingCodecName)
|
||||
{
|
||||
var shouldShow = !string.IsNullOrEmpty(missingCodecName);
|
||||
|
||||
return shouldShow ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public string GetWarningMessage(string missingCodecName)
|
||||
{
|
||||
return ReadableStringHelper.FormatResourceString("VideoMissingCodec_WarningMessage", missingCodecName);
|
||||
}
|
||||
|
||||
private async void CodecSearchHyperlink_Click(Hyperlink sender, HyperlinkClickEventArgs args)
|
||||
{
|
||||
string codecName = VideoPreviewer?.MissingCodecName ?? string.Empty;
|
||||
|
||||
string searchQuery = Uri.EscapeDataString(codecName);
|
||||
Uri storeSearchUri = new Uri($"ms-windows-store://search/?query=codec {codecName}");
|
||||
|
||||
await Windows.System.Launcher.LaunchUriAsync(storeSearchUri);
|
||||
}
|
||||
|
||||
public Visibility IsUnsupportedPreviewVisible(IUnsupportedFilePreviewer? previewer, PreviewState state)
|
||||
{
|
||||
var isValidPreview = previewer != null && (MatchPreviewState(state, PreviewState.Loaded) || MatchPreviewState(state, PreviewState.Error));
|
||||
|
@ -9,5 +9,7 @@ namespace Peek.FilePreviewer.Previewers.Interfaces
|
||||
public interface IVideoPreviewer : IPreviewer, IPreviewTarget
|
||||
{
|
||||
public MediaSource? Preview { get; }
|
||||
|
||||
public string? MissingCodecName { get; }
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Peek.Common.Extensions;
|
||||
using Peek.Common.Helpers;
|
||||
@ -16,6 +17,8 @@ using Peek.FilePreviewer.Models;
|
||||
using Peek.FilePreviewer.Previewers.Interfaces;
|
||||
using Windows.Foundation;
|
||||
using Windows.Media.Core;
|
||||
using Windows.Media.MediaProperties;
|
||||
using Windows.Media.Transcoding;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace Peek.FilePreviewer.Previewers
|
||||
@ -31,6 +34,9 @@ namespace Peek.FilePreviewer.Previewers
|
||||
[ObservableProperty]
|
||||
private Size videoSize;
|
||||
|
||||
[ObservableProperty]
|
||||
private string? missingCodecName;
|
||||
|
||||
public VideoPreviewer(IFileSystemItem file)
|
||||
{
|
||||
Item = file;
|
||||
@ -56,6 +62,7 @@ namespace Peek.FilePreviewer.Previewers
|
||||
public async Task LoadPreviewAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
State = PreviewState.Loading;
|
||||
MissingCodecName = null;
|
||||
VideoTask = LoadVideoAsync(cancellationToken);
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
await VideoTask;
|
||||
@ -90,6 +97,35 @@ namespace Peek.FilePreviewer.Previewers
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<string> GetMissingCodecAsync(StorageFile? file)
|
||||
{
|
||||
try
|
||||
{
|
||||
var profile = await MediaEncodingProfile.CreateFromFileAsync(file);
|
||||
|
||||
if (profile.Video != null)
|
||||
{
|
||||
var codecQuery = new CodecQuery();
|
||||
var decoders = await codecQuery.FindAllAsync(
|
||||
CodecKind.Video,
|
||||
CodecCategory.Decoder,
|
||||
profile.Video.Subtype);
|
||||
|
||||
return decoders.Count > 0 ? string.Empty : profile.Video.Subtype;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogWarning($"No video profile found for file {file?.Path}. Cannot determine codec support.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError($"Error checking codec support for file {file?.Path}: {ex.Message}");
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private Task<bool> LoadVideoAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
return TaskExtension.RunSafe(async () =>
|
||||
@ -98,10 +134,17 @@ namespace Peek.FilePreviewer.Previewers
|
||||
|
||||
var storageFile = await Item.GetStorageItemAsync() as StorageFile;
|
||||
|
||||
var missingCodecName = await GetMissingCodecAsync(storageFile);
|
||||
|
||||
await Dispatcher.RunOnUiThread(() =>
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
if (!string.IsNullOrEmpty(missingCodecName))
|
||||
{
|
||||
MissingCodecName = missingCodecName;
|
||||
}
|
||||
|
||||
Preview = MediaSource.CreateFromStorageFile(storageFile);
|
||||
});
|
||||
});
|
||||
|
@ -372,4 +372,10 @@
|
||||
<data name="DeleteConfirmationDialog_DontWarnCheckbox.Content" xml:space="preserve">
|
||||
<value>Don't show this warning again</value>
|
||||
</data>
|
||||
<data name="VideoMissingCodec_WarningMessage" xml:space="preserve">
|
||||
<value>Your device doesn't support the {0} format. To play this file, install a codec that supports this format.</value>
|
||||
</data>
|
||||
<data name="VideoCodecStoreLink.Text" xml:space="preserve">
|
||||
<value>Search in Microsoft Store</value>
|
||||
</data>
|
||||
</root>
|
Loading…
x
Reference in New Issue
Block a user