Add missing codec detection and warning message in video preview (#39726)
Some checks failed
Spell checking / Check Spelling (push) Has been cancelled
Spell checking / Report (Push) (push) Has been cancelled
Spell checking / Report (PR) (push) Has been cancelled
Spell checking / Update PR (push) Has been cancelled

<!-- 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


![image](https://github.com/user-attachments/assets/7325c3fb-b6ea-4d22-b226-f56e617ac5e2)


![search](https://github.com/user-attachments/assets/e30c1aca-beaf-4d31-a704-abd89279f5c1)

<!-- 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:
leileizhang 2025-06-06 14:08:04 +08:00 committed by GitHub
parent a1cf836c6d
commit 96c5cf1897
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 89 additions and 0 deletions

View File

@ -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}"

View File

@ -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));

View File

@ -9,5 +9,7 @@ namespace Peek.FilePreviewer.Previewers.Interfaces
public interface IVideoPreviewer : IPreviewer, IPreviewTarget
{
public MediaSource? Preview { get; }
public string? MissingCodecName { get; }
}
}

View File

@ -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);
});
});

View File

@ -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>