KB5003430:在 Windows 资源管理器中编辑元数据时,FLAC 编码的音乐文件已损坏

应用对象
Windows 10 Enterprise, version 2004 Windows 10 Home and Pro, version 2004 Windows 10 Pro, version 2004 Windows 10 Enterprise and Education, version 2004 Windows 10 Pro Education, version 2004 Windows 10 Pro for Workstations, version 2004 Windows 10 Pro, version 20H2 Windows 10 Enterprise, version 20H2 Windows 10 Enterprise and Education, version 20H2 Windows 10 Home and Pro, version 20H2 Windows 10 Pro Education, version 20H2 Windows 10 Pro for Workstations, version 20H2

摘要

此更新解决了一个元数据编码问题,该问题导致免费无损音频编解码器 (FLAC) 音乐文件在其标题、艺术家或其他元数据发生更改时变得无法播放。

原因

当 FLAC 文件在 FLAC 标头之前包含 ID3 帧时,可能会出现此问题。 ID3 帧包含标题和艺术家等元数据。 FLAC 属性处理程序假定所有 FLAC 文件都以 4 字节起始代码 fLaC 开头,并且未考虑文件开头的 ID3 帧。 因此,ID3 帧将被覆盖,而启动代码 fLaC 使文件无法播放。

解决方案

若要防止将来的 FLAC 音乐文件出现此问题,请安装 2021 年 5 月 25 日 - KB5003214 (操作系统内部版本 19041.1013、19042.1013 和 19043.1013) 预览版。

若要修复受影响的 FLAC 音乐文件,请运行以下 PowerShell 脚本。

重要

此脚本不会还原存储在 ID3 帧中的丢失元数据。 但是,它确实使文件再次可播放。

  1. 打开记事本。

  2. 将以下脚本复制并粘贴到记事本中:

    # 版权所有 2021 Microsoft
    # 此脚本将修复 Media Foundation 根据KB5003430损坏的 FLAC 文件。
    # 有关详细信息,请参阅KB5003430
    param (
    [parameter (Mandatory=$true,
    HelpMessage=“Media Foundation 已损坏的 FLAC 文件的路径”,
    ValueFromRemainingArguments=$true) ]
    [ValidateScript ({ -not [String]::IsNullOrEmpty ($_) -and (Test-Path $_) }) ]
    [String]$File
    )
    # 我们需要备份当前文件,以备出现任何错误
    $FileDirectory = Split-Path -Resolve $File
    $Filename = Split-Path -Leaf -Resolve $File
    $FullPath = Join-Path -Resolve $FileDirectory $Filename
    $Filename = [String]::Format (“Backup_{0:yyyyMMdd_hhmmss}_{1}”, [DateTime]::Now,$Filename)
    $BackupLocation = Join-Path $FileDirectory $Filename
    Write-Output“Microsoft FLAC 修复工具。 此工具将修复在编辑其详细信息时损坏的 FLAC 音频文件。”
    Write-Output“受影响的文件: $FullPath”
    Write-Output“将备份文件:$BackupLocation”
    Write-Output“是否继续?”
    $choice=$host.ui.PromptForChoice (“修复 FLAC 脚本”、“是否要继续”, ('&是', '&No') , 1)
    函数 ParseStreamInfoMetadataBlock ([System.IO.FileStream]$stream)
    {
    $blockType = $stream。ReadByte ()
    $lastBlock = ($blockType -shr 7) -ne 0
    $blockType = $blockType -band 0x7F
    如果 ($blockType -ne 0)
    {
    返回$false
    }
    $blockSize = ( ($stream。ReadByte () -shl 16) -bor ($stream.ReadByte () -shl 8) -bor $stream。ReadByte () )
    如果 ($blockSize -lt 34)
    {
    返回$false
    }
    $minAudioBlockSize = ($stream。ReadByte () -shl 8) -bor $stream。ReadByte ()
    $maxAudioBlockSize = ($stream。ReadByte () -shl 8) -bor $stream。ReadByte ()
    如果 ($minAudioBlockSize -lt 16 或 $maxAudioBlockSize -lt 16)
    {
    返回$false
    }
    $minFrameSize = ( ($stream。ReadByte () -shl 16) -bor ($stream.ReadByte () -shl 8) -bor $stream。ReadByte () )
    $maxFrameSize = ( ($stream。ReadByte () -shl 16) -bor ($stream.ReadByte () -shl 8) -bor $stream。ReadByte () )
    $sampleInfo = ( ($stream。ReadByte () -shl 24) -bor ($stream.ReadByte () -shl 16) -bor ($stream.ReadByte () -shl 8) -bor $stream。ReadByte () )
    $sampleRate = $sampleInfo -shr 12
    $channelCount = ( ($sampleInfo -shr 9) -band 0x7) + 1
    $bitsPerSample = ( ($sampleInfo -shr 4) -band 0x1F) + 1
    [UInt64]$sampleCount = ( ($stream。ReadByte () -shl 24) -bor ($stream.ReadByte () -shl 16) -bor ($stream.ReadByte () -shl 8) -bor $stream。ReadByte () )
    $sampleCount = ( ([UInt64]$sampleInfo -band 0xF) -shl 32) -bor $sampleCount
    $MD 5HashBytes = New-Object byte[] 16
    $stream。读取 ($MD 5HashBytes、0、$MD 5HashBytes.Length)
    $MD 5Hash = [Guid] ($MD 5HashBytes)
    如果 ($sampleRate -eq 0)
    {
    返回$false
    }
    # 通过这些检查意味着我们可能具有流信息标头,并且可以重新生成文件
    Write-Output“文件Stream信息”
    Write-Output“采样率:$sampleRate”
    Write-Output“音频通道:$channelCount”
    Write-Output“示例深度:$bitsPerSample”
    Write-Output“MD5 音频示例哈希:$MD 5Hash”
    返回$true
    }
    如果 ($choice -eq 0)
    {
    Copy-Item $FullPath -Destination $BackupLocation -Force
    $stream = [System.IO.File]::Open ($FullPath,[System.IO.FileMode]::Open)
    $stream。Seek (4,[System.IO.SeekOrigin]::Begin)
    而 ($stream。ReadByte () -eq 0) {}
    # 我们现在需要弄清楚有效的 FLAC 元数据帧从何处开始
    # 我们可能指向大小成员的最后一个字节,因此我们将查找 4 个字节并重试
    $flacDataStartPosition = $stream。位置 - 4
    $stream。Seek ($flacDataStartPosition,[System.IO.SeekOrigin]::Begin)
    而 (-not (ParseStreamInfoMetadataBlock ($stream) ) )
    {
    $flacDataStartPosition = $flacDataStartPosition + 1
    $stream。Seek ($flacDataStartPosition,[System.IO.SeekOrigin]::Begin)
    }
    # 插入开始代码
    $stream。Seek ($flacDataStartPosition,[System.IO.SeekOrigin]::Begin)
    如果 (测试路径“$FullPath.tmp”)
    {
    Remove-Item“$FullPath.tmp”
    }
    $fixedStream = [System.IO.File]::Open (“$FullPath.tmp”, [System.IO.FileMode]::CreateNew)
    [byte[]]$startCode = [char[]] ('f', 'L', 'a', 'C') ;
    $fixedStream.Write ($startCode、0、$startCode.Length)
    $stream。CopyTo ($fixedStream)
    $stream。关闭 ()
    $fixedStream.Close ()
    Move-Item -强制“$FullPath.tmp”$FullPath
    }
  3. 在“文件”菜单上,单击“保存”。

  4. 在“ 另存为 ”对话框中,找到要在其中保存 PowerShell 脚本的文件夹。

  5. 在“ 文件名 ”框中,键入 FixFlacFiles.ps1,将“ 另存为类型 ”框更改为 “文本文档 (*.txt) 然后单击” 保存”。

  6. 在 Windows 资源管理器中,找到保存的 PowerShell 脚本。

  7. 右键单击该脚本,然后单击“ 使用 PowerShell 运行”。

  8. 出现提示时,键入不可播放 FLAC 文件的文件名,然后按 Enter。