2020-12-15

Win10 mp4 : 剪輯、取出音樂、設定屬性

把這個ps1 放在 mp4 旁邊
按右鍵 → 用 PowerShell 執行

如果 mp4 不能移動、改名,把 PS 窗口關掉
Add-Type -AssemblyName System.Runtime.WindowsRuntime

[Windows.Storage.StorageFile , Windows.Storage , ContentType=WindowsRuntime] > $null
[Windows.Media.Transcoding.MediaTranscoder, Windows.Media.Transcoding , ContentType=WindowsRuntime] > $null

#learn from https://fleexlab.blogspot.com/2018/02/using-winrts-iasyncoperation-in.html
Function await($WinRtTask, $ResultType = $null) {
switch($ResultType.count){
0{ $TaskType = 'IAsyncAction' }
1{
if ($ResultType -eq [double]){
$TaskType = 'IAsyncActionWithProgress`1'
}else{
$TaskType = 'IAsyncOperation`1'
}
}
2{ $TaskType = 'IAsyncOperationWithProgress`2'}
default {throw '$ResultType error'}
}

$asTask = [System.WindowsRuntimeSystemExtensions].GetMethods() | ?{
$_.Name -eq 'AsTask' -and
$TaskType -eq $_.GetParameters().ParameterType.name}

if ($ResultType.count -gt 0){
$asTask = $asTask.MakeGenericMethod($ResultType)
}

$netTask = $asTask.Invoke($null, @($WinRtTask))
$netTask.Wait(-1) | Out-Null
if ($TaskType -like 'IAsyncOperation*'){
$netTask.Result
}
}

Function mp4Trim($mp4Path, $startTime = 0, $stopTime = 0, $musicOnly = $false){
$transcoder = [Windows.Media.Transcoding.MediaTranscoder]::new()
$startTime, $stopTime = $startTime, $stopTime -replace '^\d+$','0:0:$&' -replace '^\d+:\d+$','0:$&'
$transcoder.TrimStartTime = $startTime
$transcoder.TrimStopTime = $stopTime

$a = [Windows.Storage.StorageFile]
$mp4 = await ($a::GetFileFromPathAsync($mp4Path)) ($a)
$a = [Windows.Media.MediaProperties.MediaEncodingProfile]
$encProfile = await $a::CreateFromFileAsync($mp4) ($a)
$mp4SaveName = $mp4.name

if ($encProfile.video -ne $null -and $musicOnly){
$q = [Windows.Media.MediaProperties.AudioEncodingQuality]::High
$a = [Windows.Media.MediaProperties.MediaEncodingProfile]
$ext = ''
switch($encProfile.Audio.Subtype){
'AAC'{$ext = 'm4a'}
'MP3'{
$ext = 'mp3'
# if set to $flase, something error when listening to mp3
$transcoder.AlwaysReencode = $true
}
'WMA9'{$ext = 'wma'}
}

if ($ext -ne ''){
$musicProfile = $a::"Create$ext"($q)
$musicProfile.Audio = $encProfile.Audio
$encProfile = $musicProfile
$mp4SaveName = $mp4.DisplayName + ".$ext"
}
}
if ($encProfile.Audio.Subtype -eq 'WMA8'){$transcoder.AlwaysReencode = $true}

$a = [Windows.Storage.StorageFolder]
$mp4Folder = await ($mp4.GetParentAsync()) ($a)

$a = [Windows.Storage.StorageFile]
# GenerateUniqueName=0; ReplaceExisting=1; FailIfExists=2; OpenIfExists=3
$mp4Save = await ($mp4Folder.CreateFileAsync($mp4SaveName, 0)) ($a)

$a = [Windows.Media.Transcoding.PrepareTranscodeResult]
$prepare = await ($transcoder.PrepareFileTranscodeAsync($mp4, $mp4Save, $encProfile)) ($a)

if($prepare.CanTranscode){
write-host "transcoding"
await ($prepare.TranscodeAsync()) ([double])
Write-Host "transcode complete"
Write-Host 'wait 2 seconds for transcoder unlock'
sleep 2
}else{
Write-Host "can't transcode"
}

}
function mp4Property($mp4Path, $title = '', [uint32]$rating = 60, $comment = ''){

$a = [Windows.Storage.StorageFile]
$mp4 = await ($a::GetFileFromPathAsync($mp4Path)) ($a)

$a = [Windows.Storage.FileProperties.VideoProperties]
$videoP = await ($mp4.Properties.GetVideoPropertiesAsync()) ($a)
# star 1..12 13..37 38..62 63..87 88..99
$videoP.Rating = $rating
await $videoP.SavePropertiesAsync()

$a = [Windows.Storage.FileProperties.DocumentProperties]
$docP = await ($mp4.Properties.GetDocumentPropertiesAsync()) ($a)
$docP.title = $title
$docP.Comment = $comment
await $docP.SavePropertiesAsync()

<#

$a = [Windows.Storage.FileProperties.ImageProperties]
$imgP = await ($mp4.Properties.GetImagePropertiesAsync()) ($a)

$a = [Windows.Storage.FileProperties.MusicProperties]
$musicP = await ($mp4.Properties.GetMusicPropertiesAsync()) ($a)

#all properties
$videoP, $docP, $imgP, $musicP

#properties (can set)
$videoP, $docP, $imgP, $musicP | gm 'put_*' -Force
#>

<#
# https://docs.microsoft.com/en-us/windows/win32/properties/props
$a = [System.Collections.Generic.IDictionary[string, Object]]
[string[]]$propNames = 'System.Title', 'System.Rating', 'System.Comment'
await $mp4.Properties.RetrievePropertiesAsync($propNames) ($a) |%{
"{0} : {1}" -f $_.Key, $_.Value
}

$s = 'System.Collections.Generic.KeyValuePair[string,System.Object]'
$a = [type]$s
$arr = @(
$a::new('System.Title', $title),
$a::new('System.Rating', $rating),
$a::new('System.Comment', $comment)
) -as [type]"$s[]"

await $mp4.Properties.SavePropertiesAsync($arr)
#>
}

cd -literal $PSScriptRoot
[Environment]::CurrentDirectory = pwd

$files = @(dir *.mp4, *.mp3, *.m4a, *.wmv, *.wma -file)
if ($files.count -ne 0){
# mp4Trim filePath startTime stopTime musicOnly
mp4Trim $files[0] 0:20 1:50

# music only
# mp4Trim $files[0] 0:20 1:50 $true
# music only & after 0:20
# mp4Trim $files[0] 0:20 0 $true
# mp4Property filePath title rating comment
# (1 ~ 5 star) rating 1..12 13..37 38..62 63..87 88..99
mp4Property $files[0] 'a title' 90 'a comment'
}
# When mp4 can't move or Rename , close PowerShell console

沒有留言:

張貼留言