| function ReadBox( $fs , $start , $end ,$search = $null ){ |
| $h = @{} |
| $fs.position = $start |
| |
| if ( $search -eq $null ){ |
| $searchBox = $null |
| }else{ |
| $searchBox = @($search)[0] |
| $L = @($search).length |
| if( $L -gt 1 ){ |
| $rest = $search[ 1..$L ] |
| } |
| } |
| |
| while($fs.position -lt $end){ |
| $boxSizePos = $fs.position ; $boxSizeLength = 4 |
| |
| if (($fs.position + 8) -gt $end){ break } |
| |
| [void]$fs.read($buffer , 0 , 8) |
| |
| $boxSize = [System.BitConverter]::ToUInt32( $buffer[3..0] , 0) |
| $boxType = ( $buffer[4..7] | %{[char]$_} ) -join '' |
| $boxEnd = $fs.position + $boxSize - 8 |
| |
| if ( $boxSize -eq 1 ){ |
| if (($fs.position + 8) -gt $end){ break } |
| |
| [void]$fs.read($buffer , 0 , 8) |
| $boxSize = [System.BitConverter]::ToUInt64( $buffer[7..0] , 0) |
| $boxEnd = $fs.position + $boxSize - 16 |
| $boxSizePos += 8 |
| $boxSizeLength = 8 |
| }elseif ($boxSize -eq 0 ) { |
| $boxEnd = $fs.length |
| } |
| |
| if ($boxend -gt $end ){ break } |
| |
| if ($boxType -eq $searchBox){ |
| $h1 = @{boxSizePos = $boxSizePos ; boxSizeLength = $boxSizeLength |
| boxSize = $boxSize ; boxEnd = $boxEnd } |
| |
| if ($L -eq 1 ){ |
| return $h1 |
| }else{ |
| $boxHeadSize = 8 |
| if ($boxType -eq 'meta') {$boxHeadSize +=4} |
| return @($h1) + (ReadBox $fs ($boxSizePos + $boxHeadSize ) $boxEnd $rest ) |
| } |
| } |
| |
| $h[$boxType] = @{boxSizePos = $boxSizePos ; boxSizeLength = $boxSizeLength |
| boxSize = $boxSize ; boxEnd = $boxEnd } |
| |
| $fs.position = $boxEnd |
| } |
| if ($search -eq $null){ return $h }else{ return $null } |
| } |
| |
| function addSomeThing([io.fileinfo]$mp4 , [io.fileinfo]$jpg , [io.fileinfo]$txt = $null){ |
| trap{ $_ ;read-host;$fs.close() ; return } |
| |
| $fs = $mp4.Open('open' , 'readWrite' , 'read') |
| |
| $h = ReadBox $fs 0 $fs.length |
| |
| if ( $h.ftyp -eq $null -or $h.ftyp.boxSizePos -ne 0 -or |
| $h.moov -eq $null -or $h.mdat -eq $null){ |
| throw "$mp4 :This is not a MP4 file." |
| } |
| |
| if ($h.moov.boxSizePos -lt $h.mdat.boxSizePos){ |
| throw "$mp4 : only meta info in the end of file will be processed" |
| } |
| $box = @() |
| $box += $h.moov |
| |
| |
| $fileEmpty = $false |
| if ($jpg -ne $null){ |
| if ($jpg.length -gt $bufferSize){echo 'jpg size is too big';read-host; $fs.close();return } |
| |
| if ($jpg.length -eq 0 ) { $fileEmpty = $true} |
| |
| $arrSearch = 'udta\meta\ilst\covr' -split '\\' |
| |
| }elseif ($txt -ne $null){ |
| if ($txt.length -eq 0 ){ $fileEmpty = $true } |
| |
| $arrSearch = 'udta\chpl' -split '\\' |
| |
| }else{ $fs.close() ;return } |
| |
| |
| $box += ReadBox $fs ($box[-1].boxSizePos + 8) $box[-1].boxEnd $arrSearch |
| |
| if ( $box[-1] -eq $null ) { |
| if ( $fileEmpty ) { $fs.close() ;return } |
| $insertPos = $backupPos = $box[-2].boxEnd |
| |
| }else{ |
| $insertPos = $box[-1].boxSizePos |
| $backupPos = $box[-1].boxEnd |
| } |
| |
| if ( ! $fileEmpty ){ |
| if ($jpg -ne $null ){ |
| |
| $TotalSize = 8 + (12 + 33) + |
| |
| 8 + ( 8 + 16 + $jpg.length ) |
| |
| [uint32[]]$arrBoxsize = 0 , 8 , (12 + 33) , 8 |%{ |
| $TotalSize -= $_ ; $TotalSize } |
| $dataSize = $jpg.length |
| }else{ |
| $chapterInfo = @{} |
| if ( $insertPos -ne $backupPos ){ |
| if ( ($backupPos - $insertPos) -gt 17 ) { |
| $fs.Position = $insertPos + 17 |
| |
| while($fs.Position -lt $backupPos){ |
| if ( ($fs.Position + 8) -gt $backupPos ){ break } |
| [void]$fs.read($buffer , 0 , 8) |
| $ticks = [System.BitConverter]::ToInt64( $buffer[7..0] , 0) |
| |
| if ( ($fs.Position + 1) -gt $backupPos ){ break } |
| [byte]$n = $fs.ReadByte() |
| |
| if ( ($fs.Position + $n) -gt $backupPos ){ break } |
| [void]$fs.read($buffer , 0 , $n) |
| if ($n -gt 0){ |
| $chapterInfo[$ticks] = @([byte]$n) + $buffer[0..($n-1)] |
| }else{ |
| $chapterInfo[$ticks] = @([byte]$n) |
| } |
| |
| } |
| } |
| } |
| |
| gc -literal $txt |%{ |
| $a , $b = $_.split('',2,1) |
| |
| if ($t = $a -as [timespan] ){ |
| if ( $t.ticks -lt 0 ){ |
| $chapterInfo.Remove( -($t.ticks) ) |
| }else{ |
| $n = [System.Text.Encoding]::UTF8.GetByteCount(@($b)) |
| if ( $n -lt 256 ){ |
| $chapterInfo[$t.ticks] = @([byte]$n) + [System.Text.Encoding]::UTF8.GetBytes(@($b)) |
| } |
| } |
| } |
| } |
| |
| $n = 0 |
| $chapter = $chapterInfo.Keys | sort | %{ |
| $n++ |
| $arrByte = [System.BitConverter]::GetBytes( $_ ) |
| $arrByte[7..0] |
| $chapterInfo[$_] |
| } |
| if ( $n -gt 255 ) { $n = 255} |
| $chapter = @([byte]$n) + $chapter |
| |
| $dataSize = $chapter.length |
| |
| |
| $TotalSize = 8 + 16 + $chapter.length |
| [uint32[]]$arrBoxsize = 0 , 8 |%{ $TotalSize -= $_ ; $TotalSize} |
| } |
| |
| [byte[]]$addBox = |
| for ($i = ($box.length -1) -1 ; $i -lt $arrSearch.length ; $i++){ |
| $arrByte = [System.BitConverter]::GetBytes( $arrBoxsize[$i] ) |
| $arrByte[3..0] |
| $arrSearch[$i][0..3] |
| |
| switch ( $arrSearch[$i] ){ |
| 'meta'{ |
| ,0 * 4 |
| (,0 * 3 ) + 33 ; 'hdlr'[0..3] |
| ,0 * 8 ; 'mdirappl'[0..7] ; ,0 * 9 |
| break |
| } |
| 'covr'{ |
| $arrByte = [System.BitConverter]::GetBytes( $arrBoxsize[$i] - 8 ) |
| $arrByte[3..0] ; 'data'[0..3] |
| (,0 * 3 ) + 13 ; ,0 * 4 |
| break |
| } |
| 'chpl'{ |
| 1 ; ,0 * 7 |
| break |
| } |
| } |
| } |
| } |
| |
| if ($fileEmpty){ |
| $addSize = 0 |
| }else{ |
| $addSize = $addBox.length + $dataSize |
| } |
| $editSize = $addSize - ($backupPos - $insertPos) |
| |
| |
| |
| if ( ($insertPos + $addSize) -ne $backupPos){ |
| |
| $backupSize = $fs.length - $backupPos |
| |
| if ( $backupSize -gt $bufferSize ){ |
| throw "bufferSize $($bufferSize/1mb)mb is too small" |
| } |
| |
| $fs.position = $backupPos |
| [void]$fs.read($buffer , 0 , $backupSize ) |
| |
| |
| $fs.position = $insertPos + $addSize |
| $fs.write($buffer , 0 , $backupSize ) |
| } |
| |
| |
| if ( ! $fileEmpty){ |
| $fs.position = $insertPos |
| $fs.write($addBox , 0 , $addBox.length) |
| |
| if ($jpg -ne $null){ |
| $fs1 = $jpg.OpenRead() |
| [void]$fs1.read($buffer , 0 , $jpg.length) |
| $fs1.close() |
| $fs.write($buffer , 0 , $jpg.length) |
| }else{ |
| $fs.write($chapter , 0 , $chapter.length) |
| } |
| } |
| |
| |
| for ($i = 0 ; $i -lt ($box.length - 1) ; $i++) { |
| |
| if ( $box[$i].boxSizeLength -eq 4 ){ |
| [uint32]$boxSize = $box[$i].boxSize + $editSize |
| $arrByte = [System.BitConverter]::GetBytes($boxSize) |
| $arrByte = $arrByte[3..0] |
| }else{ |
| [uint64]$boxSize = $box[$i].boxSize + $editSize |
| $arrByte = [System.BitConverter]::GetBytes($boxSize) |
| $arrByte = $arrByte[7..0] |
| } |
| |
| $fs.position = $box[$i].boxSizePos |
| $fs.write($arrByte , 0 , $box[$i].boxSizeLength) |
| } |
| |
| if ($editSize -lt 0){ |
| $fs.SetLength($fs.length + $editSize) |
| } |
| $fs.close() |
| |
| } |
| |
| |
| $bufferSize = 20mb |
| $buffer = new-object byte[]($bufferSize) |
| |
| cd -Literal (Split-Path $MyInvocation.MyCommand.Path) |
| |
| |
| [Environment]::CurrentDirectory = pwd |
| |
| dir *.mp4 |?{! $_.PSIsContainer}|%{ |
| if (Test-Path -literal "$($_.BaseName).jpg" -PathType Leaf){ |
| addSomeThing $_ "$($_.BaseName).jpg" |
| } |
| |
| if (Test-Path -literal "$($_.BaseName).txt" -PathType Leaf){ |
| addSomeThing $_ $null "$($_.BaseName).txt" |
| } |
| |
| }COPY |