标题: [技术讨论] PowerShell看RAR分割檔裡的mp4(缺檔) [打印本页]
作者: nwm310 时间: 2016-11-4 21:35 标题: PowerShell看RAR分割檔裡的mp4(缺檔)
以下方法使用條件:
壓縮方式:僅儲存
至少要有:第一檔
最後一檔(mp4的重要資訊在檔尾。如果最後一檔太小,可能需要倒數第二檔)
方法1:個別解出來、再合併
7-Zip可以個別解出每個分割檔的內容
計算「缺檔大小」 = mp4大小 - 已解出的總合
產生符合「缺檔大小」的檔案,再依順序合併檔案
也許可以用到 fsutil file
fsutil sparse
(沒測試)
方法2:自己補檔
缺少的是中間檔(第一檔、最後一檔以外的檔案)
並且有其他中間檔存在
例如:目前有 part1 part2 part4 part5
缺少 part3
把其中一個中間檔複製並改名成「缺檔的檔名」
例如:
把part2 複製並改名成part3
然後,就可以用MPC-HC、VLC player、Potplayer來看
方法3:掛載(mount)RAR分割檔
需要 PowerShell 5.0
分割檔限制:
壓縮方式:僅儲存
壓縮檔格式:RAR (不是新的RAR5)
壓縮時所設定的分割檔大小:每一個分割檔都一樣大 (除了最後一檔)
下載後的分割檔大小:可以下載到一半、沒有下載完成
不能處理檔名加密的RAR檔(一般加密可以處理)
至少要有:第一檔
最後一檔(mp4的重要資訊在檔尾。如果最後一檔太小,可能需要倒數第二檔)
下載:
到http://pismotec.com/download/
下載並安裝 Pismo File Mount Audit Package
下載Pismo File Mount Developer Kit
取得pfmclr_183.dll、pfmshim16_183.dll
分別在這兩個dll 按右鍵 → 內容 → 解除封鎖
執行方式:
pfmclr_183.dll
pfmshim16_183.dll
RAR分割檔
ps1
把這些東西放在一起,執行 ps1 (不要用「管理員權限」開啟)
執行之後:
要自己去找新掛載的磁碟機(它不會自己彈出來)
如果沒加密,磁碟機裡的是mp4,可以直接打開
如果有加密,磁碟機裡的是rar,要用WinRAR開啟 (會出現錯誤訊息)
解壓縮 (保留毀損的檔案)
卸載:
關掉PS視窗就卸載了。
卸載方面有問題。
卸載之後,打開Powershell視窗,會出現
嘗試在 'FileSystem' 提供者上執行 InitializeDefaultDrives 作業失敗。
如果要完全卸載,請重新開機- #Requires -version 5.0
- if ($host.Version.Major -lt 5){write-host '需要 PowerShell 5.0';pause;exit}
-
-
- $dllfiles = @(gi pfmclr_183.dll , pfmshim16_183.dll )
- if ( $dllfiles.length -lt 2 ){
- write-host '需要dll';pause;exit
- }else{
- Add-Type -literal $dllfiles[0]
- }
-
-
-
- #分析RAR================================================================================
- $rarGroup = dir *.part*.rar | sort |?{$_.name -match '(.*)\.part(\d+)\.rar$' } |
- group -prop {$matches[1] + '/' + $matches[2].length}
-
- for ($i = 0 ; $i -lt $rarGroup.length; $i++){
- if ($rarGroup[$i].group[0] -match 't0*1\.rar$'){
- $rar = $rarGroup[$i].group ; $nFiles = $rarGroup[$i].Count ; break}
- }
- if ($i -eq $rarGroup.lenth) {write-host '找不到第一檔';pause;exit}
- if ($nFiles -eq 1) {write-host '只有一檔,不用處理了';pause;exit}
-
-
- $fs = $rar[0].OpenRead()
- $buffer = new-object byte[](2kb)
-
-
- $n = $fs.read($buffer , 0 , 20)
- if ( $n -ne 20 ) {$fs.close();write-host '第一檔太小了';pause;exit}
- if ($buffer[10] -band 0x80){
- $fs.close();write-host '不能處理檔名加密的RAR檔';pause;exit
- }
-
- $findOK = $false
- while ($fs.Position -lt $fs.length ){
- $n = $fs.read($buffer , 20 , 7)
- if ( $n -ne 7 ) {$fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID}
-
- $n = [BitConverter]::ToUInt16($buffer , 25) -7
- if ( ($fs.Position + $n ) -gt $fs.length ){
- $fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID
- }
- [void]$fs.read($buffer , 27 , $n)
-
- #如果是檔案區塊
- if ( $buffer[22] -eq 0x74 ) {
- #如果是mp4 --> file continued in next volume
- if ( $buffer[23] -band 2 ) {
- #有沒有加密
- if ( $buffer[23] -band 4 ) { $encryption = $true} else { $encryption = $false}
- if ( $buffer[45] -ne 0x30) {
- $fs.close();write-host '壓縮方式不是僅儲存';pause
- stop-process -Id $PID
- }
- $HeaderSize = $n + 7
- $FirstSize = [BitConverter]::ToUInt32($buffer, 27 )
- $Mp4Size = [BitConverter]::ToUInt32($buffer, 31 )
-
- #如果檔案很大
- if ($buffer[24] -band 1 ){
- $HighSize = [BitConverter]::ToUInt32($buffer, 52 )
- $FirstSize = ([long]$HighSize -shl 32 ) + $FirstSize
-
- $HighSize = [BitConverter]::ToUInt32($buffer, 56 )
- $Mp4Size = ([long]$HighSize -shl 32 ) + $Mp4Size
- }
-
- #取得檔名
- $nameSize = [BitConverter]::ToUInt16($buffer , 46 )
- if ($buffer[24] -band 1 ){$namePos = 60 }else { $namePos = 52 }
- $mp4Name=[System.Text.Encoding]::Default.GetString($buffer,$namePos,$nameSize)
- $mp4Name = $mp4Name -replace '\x00.*','' -replace '\?','_'
- $FirstOffset = $fs.Position
- $findOK = $true
- break
-
- }else{ #第一檔裡面的其他檔案
- $n = [BitConverter]::ToUInt32($buffer, 27)
- if ($buffer[24] -band 1 ) {
- $HighSize = [BitConverter]::ToUInt32($buffer, 52 )
- $n += ([long]$HighSize -shl 32 )
- }
- if ( ($fs.Position + $n ) -gt $fs.length ){
- $fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID
- }
- $fs.Position += $n
- }
- }else{#非檔案區塊
- if ($buffer[24] -band 0x80){
- $n = [BitConverter]::ToUInt32($buffer, 27)
- if ( ($fs.Position + $n ) -gt $fs.length ){
- $fs.close();write-host '第一檔太小了';pause;stop-process -Id $PID
- }
- $fs.Position += $n
- }
- }
- }
- $fs.close()
- if ( !$findOK) {write-host '沒找到mp4';pause;exit}
- #計算RAR資訊================================================================================
- $MidOffset = $LastOffset = $HeaderSize + 20
- $MidSize = $FirstSize + ( $FirstOffset - $MidOffset )
- $FullPack = $Mp4Size
- if ($encryption){
- if ( $Mp4Size % 16 ) { $FullPack += 16 - ($Mp4Size % 16) }
- }
-
- $LastSize = ($FullPack - $FirstSize) % $MidSize
- $nLastPart = ($FullPack - $FirstSize - $LastSize) / $MidSize +2
-
- $Mp4offset = $nEmpty = 0
- $mp4Info = & {
- if ($encryption){
- $buffer[10] = $buffer[10] -band 238
- $buffer[11] = $buffer[11] -band 254
- $buffer[23] = $buffer[23] -band 253
-
- $fpbyte = [BitConverter]::GetBytes([uint64]$FullPack)
- [array]::copy($fpbyte,0,$buffer,27,4)
- if ($buffer[24] -band 1 ){
- [array]::copy($fpbyte,4,$buffer,52,4)
- }
-
- @{fs = new-object IO.MemoryStream($buffer,0, (20 + $HeaderSize))
- Mp4offset = $Mp4offset ;offset = 0 ; length = 20 + $HeaderSize
- }
- $Mp4offset += 20 + $HeaderSize
- }
- if ( ($FirstOffset + $FirstSize) -gt $rar[0].length ) {
- $nEmpty = $FirstOffset + $FirstSize - $rar[0].length
- }
- @{fs = $rar[0].OpenRead() ; Mp4offset = $Mp4offset
- offset = $FirstOffset ; length = $FirstSize - $nEmpty
- }
-
- $Mp4offset += $FirstSize - $nEmpty
- $nextN = 2
-
- #$rar[index]
- 1.. ($nFiles - 1) | %{
- [int]$nPart = $rar[$_].basename -replace '.*part',''
- if ( $nPart -gt $nLastPart ) {
- @{fs = $null ; Mp4offset = $Mp4offset ; length = $FullPack - $Mp4offset}
- $nPart = $nLastPart ; return
- }
-
- if ( $nPart -gt $nextN -or $nEmpty -gt 0 ){
- @{fs = $null ; Mp4offset = $Mp4offset
- length = $MidSize * ( $nPart - $nextN ) + $nEmpty
- }
- $Mp4offset += $MidSize * ( $nPart - $nextN ) + $nEmpty
- $nEmpty = 0
- }
-
- #如果是最後一檔
- if ( $nPart -eq $nLastPart ){
- if ( ($LastOffset + $LastSize) -gt $rar[$_].length ) {
- $nEmpty = $LastOffset + $LastSize - $rar[$_].length
- }
- @{fs = $rar[$_].OpenRead() ; Mp4offset = $Mp4offset
- offset = $LastOffset ; length = $LastSize - $nEmpty
- }
-
- if ( $nEmpty -gt 0 ){
- $Mp4offset += $LastSize - $nEmpty
- @{fs = $null ; Mp4offset = $Mp4offset ; length = $nEmpty}
- }
- return
-
- }else{#中間檔
- if ( ($MidOffset + $MidSize) -gt $rar[$_].length ) {
- $nEmpty = $MidOffset + $MidSize - $rar[$_].length
- }
- @{fs = $rar[$_].OpenRead() ; Mp4offset = $Mp4offset
- offset = $MidOffset ; length = $MidSize - $nEmpty
- }
- $Mp4offset += $MidSize - $nEmpty
- $nextN = $nPart + 1
- }
- }
-
- if ( $nPart -lt $nLastPart ){
- @{fs = $null ; Mp4offset = $Mp4offset ; length = $FullPack - $Mp4offset}
- }
- }
- #====================================================================================
- $RarVolumeType=@'
- #Learn from Pismo File Mount Development Kit samples\hellofs_cs\hellofs.cs
- class RarVolume: Pfm+FormatterDispatch{
- $openRoot
- $openFile1
- $File1_name
- $File1_info
- RarVolume(){
- $this.openRoot = new-object Pfm+OpenAttribs -prop @{
- openSequence = 1 ; accessLevel = [Pfm]::accessLevelReadData;
- attribs = new-object Pfm+Attribs -prop @{fileType = [Pfm]::fileTypeFolder ; fileId = 2 }}
-
- $this.openFile1 = new-object Pfm+OpenAttribs -prop @{
- openSequence = 1 ; accessLevel = [Pfm]::accessLevelReadData;
- attribs = new-object Pfm+Attribs -prop @{fileType = [Pfm]::fileTypeFile ; fileId = 3 }}
- }
-
- [void] Dispose(){}
-
- [void] Open( [Pfm+MarshallerOpenOp]$op){
- $perr = 0
- $existed = $false
- $parentFileId = 0
- $endName = $null
- $openAttribs = new-object Pfm+OpenAttribs
- if ($op.NameParts().Length -eq 0){
- if ($this.openRoot.openId -eq 0) {$this.openRoot.openId = $op.NewExistingOpenId() }
- $existed = $true
- $openAttribs = $this.openRoot
-
- }elseif($op.NameParts().Length -eq 1){
- if($op.NameParts()[0].ToLowerInvariant() -ne $this.File1_name.ToLowerInvariant()){
- $perr = [Pfm]::errorNotFound
- }else{
- if ($this.openFile1.openId -eq 0) {$this.openFile1.openId = $op.NewExistingOpenId() }
- $existed = $true
- $endName = $this.File1_name
- $openAttribs = $this.openFile1
- }
-
- }else{ $perr = [Pfm]::errorParentNotFound }
-
- if($perr -eq [Pfm]::errorNotFound -and $op.CreateFileType() -ne 0)
- { $perr = [Pfm]::errorAccessDenied }
-
- $op.Complete( $perr, $existed, $openAttribs, $parentFileId, $endName, 0, $null, 0, $null)
- }
-
- [void] Replace( [Pfm+MarshallerReplaceOp]$op){
- $op.Complete( [Pfm]::errorAccessDenied, $null, $null)
- }
-
- [void] Move( [Pfm+MarshallerMoveOp] $op){
- $op.Complete( [Pfm]::errorAccessDenied, $false, $null, 0, $null, 0, $null, 0, $null)
- }
-
- [void] MoveReplace( [Pfm+MarshallerMoveReplaceOp] $op){
- $op.Complete( [Pfm]::errorAccessDenied)
- }
-
- [void] Delete( [Pfm+MarshallerDeleteOp] $op){
- $op.Complete( [Pfm]::errorAccessDenied)
- }
-
- [void] Close( [Pfm+MarshallerCloseOp] $op){
- $op.Complete( [Pfm]::errorSuccess)
- }
-
- [void] FlushFile( [Pfm+MarshallerFlushFileOp] $op){
- $perr = 0
- $openAttribs = new-object Pfm+OpenAttribs
-
- if ( $op.FileFlags() -ne [Pfm]::fileFlagsInvalid -or
- $op.Color() -ne [Pfm]::colorInvalid -or
- $op.CreateTime() -ne [Pfm]::timeInvalid -or
- $op.WriteTime() -ne [Pfm]::timeInvalid){
-
- $perr = [Pfm]::errorAccessDenied
-
- }elseif ($op.OpenId() -eq $this.openRoot.openId){
-
- $openAttribs = $this.openRoot
-
- }elseif ($op.OpenId() -eq $this.openFile1.openId){
-
- $openAttribs = $this.openFile1
- }else{
- $perr = [Pfm]::errorNotFound
- }
-
- $op.Complete( $perr, $openAttribs, $null)
- }
-
- [void] List( [Pfm+MarshallerListOp] $op){
- $perr = 0
- if ($op.OpenId() -ne $this.openRoot.openId){
- $perr = [Pfm]::errorAccessDenied
- }else{
- $op.Add( $this.openFile1.attribs, $this.File1_name)
- }
-
- $op.Complete( $perr, $true)
- }
-
- [void] ListEnd( [Pfm+MarshallerListEndOp] $op){
- $op.Complete( [Pfm]::errorSuccess)
- }
-
- [void] Read( [Pfm+MarshallerReadOp] $op){
- $data = $op.Data()
- $perr = 0
- $actualSize = 0
-
- if ($op.OpenId() -ne $this.openFile1.openId){
- $perr = [Pfm]::errorAccessDenied
- }else{
- $actualSize = $op.RequestedSize()
- if ($op.FileOffset() -ge $this.openFile1.attribs.fileSize){
- $actualSize = 0
- }elseif ( ( $op.FileOffset() + $op.RequestedSize()) -gt $this.openFile1.attribs.fileSize){
- $actualSize = $this.openFile1.attribs.fileSize - $op.FileOffset()
- }
-
- if ($actualSize -ne 0){
- for ( $i = 1 ; $i -lt $this.File1_info.length ; $i++ ){
- if ($op.FileOffset() -lt $this.File1_info[$i].Mp4offset ){break}
- }
- $i--
-
- if ($this.File1_info[$i].fs -ne $null ){
- $this.File1_info[$i].fs.Position =
- $op.FileOffset() - $this.File1_info[$i].Mp4offset + $this.File1_info[$i].offset
- }
-
- $aaa = $this.File1_info[$i].length - ( $op.FileOffset() - $this.File1_info[$i].Mp4offset)
-
- $offset = 0
- $actualSize1 = $actualSize
- while ($actualSize1 -gt 0){
- if ($actualSize1 -gt $aaa ){
- if ($this.File1_info[$i].fs -ne $null ){
- $this.File1_info[$i].fs.read($data , $offset , $aaa)
- }else{
- [array]::Clear( $data , $offset , $aaa)
- }
- $actualSize1 -= $aaa
- $offset += $aaa
-
- $i++
- if ($this.File1_info[$i].fs -ne $null ){
- $this.File1_info[$i].fs.Position = $this.File1_info[$i].offset
- }
- $aaa = $this.File1_info[$i].length
- }else{
- if ($this.File1_info[$i].fs -ne $null ){
- $this.File1_info[$i].fs.read($data , $offset , $actualSize1)
- }else{
- [array]::Clear( $data , $offset , $actualSize1)
- }
- $actualSize1 = 0
- }
- }
-
- }
- }
-
- $op.Complete( $perr, $actualSize)
- }
-
- [void] Write( [Pfm+MarshallerWriteOp] $op){
- $op.Complete( [Pfm]::errorAccessDenied, 0)
- }
-
- [void] SetSize( [Pfm+MarshallerSetSizeOp] $op){
- $op.Complete( [Pfm]::errorAccessDenied)
- }
-
- [void] Capacity( [Pfm+MarshallerCapacityOp] $op){
- $op.Complete( [Pfm]::errorSuccess, 10TB, 9TB)
- }
-
- [void] FlushMedia( [Pfm+MarshallerFlushMediaOp] $op){
- $op.Complete( [Pfm]::errorSuccess, -1)
- }
-
- [void] Control( [Pfm+MarshallerControlOp] $op){
- $op.Complete( [Pfm]::errorInvalid, 0)
- }
-
- [void] MediaInfo( [Pfm+MarshallerMediaInfoOp] $op){
- $mediaInfo = new-object Pfm+MediaInfo
- $op.Complete( [Pfm]::errorSuccess, $mediaInfo, "RarMp4")
- }
-
- [void] Access( [Pfm+MarshallerAccessOp] $op){
- $perr = 0
- $openAttribs = new-object Pfm+OpenAttribs
-
- if ($op.OpenId() -eq $this.openRoot.openId){
- $openAttribs = $this.openRoot
-
- }elseif($op.OpenId() -eq $this.openFile1.openId){
- $openAttribs = $this.openFile1
-
- }else{
- $perr = [Pfm]::errorNotFound
- }
-
- $op.Complete( $perr, $openAttribs, $null)
- }
-
- [void] ReadXattr( [Pfm+MarshallerReadXattrOp] $op){
- $op.Complete( [Pfm]::errorNotFound, 0, 0)
- }
-
- [void] WriteXattr( [Pfm+MarshallerWriteXattrOp] $op){
- $op.Complete( [Pfm]::errorAccessDenied, 0)
- }
-
-
- }
-
- '@
-
- Invoke-Expression $RarVolumeType
- #開始掛載==================================================================================
- $mcp = new-object Pfm+MountCreateParams -prop @{
- mountFlags = 1
- driveLetter = "Z"
- mountSourceName = "感謝大大無私分享" }
-
- $msp = new-object Pfm+MarshallerServeParams -prop @{
- volumeFlags = 1
- dispatch = new-object RarVolume
- formatterName = "RarMp4Fs" }
-
-
- $msp.dispatch.File1_name = split-path $mp4Name -leaf
- $msp.dispatch.openFile1.attribs.fileSize = $Mp4Size
- $msp.dispatch.File1_info = $mp4Info
-
- if ($encryption){
- $msp.dispatch.File1_name = $msp.dispatch.File1_name +".rar"
- $msp.dispatch.openFile1.attribs.fileSize = $FullPack + 20 + $HeaderSize
-
- }
-
- $n1 = $n2 = -1
- $err = [Pfm]::SystemCreatePipe( [ref] $n1, [ref]$n2 )
- $msp.toFormatterRead = $n1
- $mcp.toFormatterWrite = $n2
-
-
- $n1 = $n2 = -1
- $err = [Pfm]::SystemCreatePipe( [ref] $n1, [ref]$n2 )
- $mcp.fromFormatterRead = $n1
- $msp.fromFormatterWrite = $n2
-
-
-
- $pfmApi = $null
- $err = [Pfm]::ApiFactory( [ref] $pfmApi)
- if($err -ne 0){ Write-Host "ERROR: $err Unable to open PFM API.`n" ; pause ; exit }
-
- $mount = $null
- $err = $pfmApi.MountCreate( $mcp, [ref] $mount)
- if ($err -ne 0){ Write-Host "ERROR: $err Unable to create mount.`n" }
-
-
- [Pfm]::SystemCloseFd( $mcp.toFormatterWrite)
- [Pfm]::SystemCloseFd( $mcp.fromFormatterRead)
-
-
- Write-Host "Press CTRL+C to exit.`n"
- $marshaller = $null
- $err = [Pfm]::MarshallerFactory( [ref]$marshaller )
- if($err -ne 0){ Write-Host "ERROR: $err Unable to create marshaller.`n" ; pause ; exit }
- $marshaller.ServeDispatch( $msp)
-
-
- [Pfm]::SystemCloseFd( $msp.toFormatterRead)
- [Pfm]::SystemCloseFd( $msp.fromFormatterWrite)
-
-
- $pfmApi.Dispose()
- $mount.Dispose()
- $marshaller.Dispose()
复制代码
欢迎光临 批处理之家 (http://www.bathome.net/) |
Powered by Discuz! 7.2 |