반토막 인코더

최?신 nvidia 그래픽 가속 옵션 사용

파워쉘 (실행 준비)

  1. 튜링 아키텍쳐 이후 글카에서만 쓰는 것을 추천합니다. 및 추가 설명
  2. 윈도우용 FFmpeg 윈도우 버전 다운로드 방법 - 7r 채널
  3. 궁금한 점은 [파워쉘][FFmpeg][인코더] st.ps1 - 반토막인코더(리팩토링버전) - 7r 채널 여기서 질문
  4. 파워쉘 관리자권한실행 >> 아래 명령어 입력 (파워쉘 스크립트 사용권한 설명서)

    Set-ExecutionPolicy RemoteSigned

박스

일단 안되면 이코드를 복사해서 메모장에 다른이름 저장 st.ps1으로 텍스트 인코딩은 ANSI로 설정해서 저장하세요.
param (
  [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1)]
  [string]$SearchString = "*",
  [string]$SearchPath = $PWD,
  [string]$Extension = 'mkv',
  [switch]$Recurse
)

function Get-EncodeOption($inputProcessNumber) {
  # 옵션_번호 { [HalfEncoder]$인코딩_옵션 = [HalfEncoder]::New(확장자, root_path, 인코딩파일뒤_프로세스명 입력, ffmpeg 인풋파일에 관한 인자, ffmpeg 아웃풋파일에 관한 인자) } 로 클래스 활용 새로운 인스턴스 만들면서 옵션 적용
  switch ($inputProcessNumber) {
    1 { [HalfEncoder]$encodingOption = [HalfEncoder]::New( $Extension, $SearchPath, '-#streamCopy', '', '-c copy' ) } 
    2 { [HalfEncoder]$encodingOption = [HalfEncoder]::New( '', $SearchPath, '-#audioOnly', '', '-vn -c:a copy' ) } 
    3 { [HalfEncoder]$encodingOption = [HalfEncoder]::New( $Extension, $SearchPath, '-#hevc', '-c:v h264_cuvid', '' ) } 
    4 { [HalfEncoder]$encodingOption = [HalfEncoder]::New( $Extension, $SearchPath, '-#vp9toHEVC', '-c:v vp9_cuvid', '' ) } 
    5 { [HalfEncoder]$encodingOption = [HalfEncoder]::New( $Extension, $SearchPath, '-#hevc_720p', '-c:v h264_cuvid -resize 1280x720', '' ) } 
    6 { [HalfEncoder]$encodingOption = [HalfEncoder]::New( $Extension, $SearchPath, '-#re_hevc_720p', '-c:v hevc_cuvid -resize 1280x720', '' ) } 
    default { Clear-Host; $inputProcessNumber = $null } 
  }
  return $encodingOption
}


# ========== 하단 수정 금지 =========
class HalfEncoder {
  [string]$newGPU = "-bf:v 5 -b_ref_mode:v middle -rc-lookahead 32 -spatial-aq 1 -temporal-aq 1 -aq-strength 12"
  [string]$nvidiaEnc = "-map 0:v:0 -c:v:0 hevc_nvenc -tag:v hvc1 -preset:v p7 -cq:v 26 -tune:v hq $newGPU -map 0:a:0 -c:a:0 copy"
  [string]$nvidia_memory = '-hwaccel cuda -hwaccel_output_format cuda'
  [string]$audio_ext = 'm4a'
  [string]$metadata = '-sn -dn -map_metadata -1 -map_chapters -1 -metadata creation_time=now -metadata encoded_by=7r -movflags faststart'
  [string]$preproperty = "-y -v 32 -hide_banner -ignore_unknown -protocol_whitelist `"file,http,https,tcp,tls,crypto`" -fflags discardcorrupt -correct_ts_overflow 0"

  [string]$HEext
  [string]$process_name
  [string]$full_dir
  [string]$ffmpeg_input_command
  [string]$ffmpeg_output_command

  HalfEncoder(
    [string]$gen_ext,
    [string]$gen_dir,
    [string]$gen_processName,
    [string]$gen_inputCommand,
    [string]$gen_outputCommand
  ) {
    $this.HEext = if ($gen_ext) { $gen_ext } else { $this.audio_ext }
    $this.process_name = $gen_processName
    $this.full_dir = Join-Path $gen_dir ($gen_processName.replace('-#', ''))

    $this.ffmpeg_input_command = if ($gen_outputCommand) {
      "{0} {1}" -f $this.preproperty, $gen_inputCommand
    } else {
      "{0} {1} {2}" -f $this.preproperty, $this.nvidia_memory, $gen_inputCommand
    }

    $this.ffmpeg_output_command = if ($gen_outputCommand) {
      "{0} {1}" -f $this.metadata, $gen_outputCommand
    } else {
      "{0} {1}" -f $this.metadata, $this.nvidiaEnc
    }
  }
}

function Remove-ListItem {
  param ( [array]$toRemoveList )
  Write-Host "삭제될 파일 목록입니다.
    `r======= LIST ======="
  $toRemoveList.name
  $select_remove = Read-Host "
    `r====================
    `r삭제하시겠습니까? [default: 아니오]
    `r====================
    `r[1] 예
    `r[2] 아니오
    `rInput " 
  if (!($select_remove -match '^[2]?$')) {
    Write-Host ">> 삭제합니다.`n"
    Remove-Item $toRemoveList
  } else {
    Write-Host ">> 삭제하지 않습니다.`n"
  }
}  

function Invoke-VideoEncoding {
  $list = Get-ChildItem -Path $SearchPath -Recurse:$Recurse -File -Filter "*$($SearchString -replace '.\\', '')*" | Sort-Object -Property Length
  if (!$list) { 
    Write-Host "`n파일이 존재하지 않습니다.`n"
  } else {
    while ($true) {
      Clear-Host
      Write-Host "반토막 인코더를 실행합니다.
        `rFile Search Keyword: $SearchString
        `r======= LIST ======="
      $list.name 
      $select_process = Read-Host "
        `r====================
        `rFFmpeg 인코더를 선택하시오. [default: 종료]
        `r====================
        `r[q] 종료
        `r[1] COPY
        `r[2] None-Video
        `r[3] HEVC
        `r[4] vp9 -> HEVC
        `r[5] h264/1080p -> HEVC/720p
        `r[6] HEVC/1080p -> 재인코딩/720p
        `rInput " 
      if ($select_process -match '^[Qq]?$') {
        return
      } elseif ($select_process -match '^[1-6]$') {
        $half_enc_opt = Get-EncodeOption $select_process
        Write-Host
        break
      }
    }

    if (!(Test-Path $half_enc_opt.full_dir)) { New-Item $half_enc_opt.full_dir -Type Directory | Out-Null }
    $list | ForEach-Object {
      $start_time = get-date -Format "yyyy-MM-dd HH:mm:ss"
      [string]$cleanedFileName = $_.BaseName + $half_enc_opt.process_name + '.' + $half_enc_opt.HEext
      [string]$ffmpeg_args = @(
        $half_enc_opt.ffmpeg_input_command
        "-i `"${_}`""
        $half_enc_opt.ffmpeg_output_command
        "`"$(Join-Path $half_enc_opt.full_dir $cleanedFileName)`""
      )
        
      Start-Process -FilePath ffmpeg.exe -ArgumentList $ffmpeg_args -NoNewWindow -Wait -Verbose 
        
      Write-Host ">> 시작 시각: ${start_time}
        `r>> 종료 시각: $(get-date -Format "yyyy-MM-dd HH:mm:ss")`r`n"
    }
    Remove-ListItem $list
  }
  Write-Host "반토막 인코더가 종료됩니다...`n" 
}

Invoke-VideoEncoding


박스 까서 내용물을 환경변수 설정한 폴더에 저장


각 옵션 번호별 활용법

  1. 스트림복사
  2. h264 비디오코덱으로 인코딩된 모든 동영상 > hevc 비디오코덱, 해상도 유지로 인코딩 옵션
  3. 모든 비디오 파일 음원 추출
  4. h264 비디오코덱으로 인코딩된 1080p 해상도 동영상 > hevc 비디오코덱, 720p 해상도로 인코딩
  5. hevc 비디오코덱으로 인코딩된 1008p 해상도 동영상 > hevc 비디오코덱, 720p 해상도로 인코딩

기본 설정 변경법

  1. 아래 처럼 써있는 라인 찾기
    param (
      [Parameter(Mandatory = $true, ValueFromPipeline = $true, Position = 1)]
      [string]$SearchString = "*",
      [string]$SearchPath = $PWD,
      [string]$Extension = 'mkv',
      [switch]$Recurse
    )
  2. [string]$SearchString = 뒤에 "*"대신 ts나, 다른 확장자 입력 시 해당 확장자만 선택 가능
    • "*"은 기본적으로 모든 파일명을 검색하는 정규식임
    • st.ps1 실행시 뒤에 입력하지 않는 다면, 아래와 같이 따로 입력하는 명령어가 실행이 되니 참고 하시오.
      (SearchString: 뒤에 원하는 검색어 입력하면됨)
  3. [string]$SearchPath = 뒤에 $PWD(현재 파워쉘이 실행되는 폴더경로를 말함) 대신에 "C:\1videos"같이 폴더 경로 설정 가능 
    (주의: "\"(역슬래쉬)로 각 폴더를 나누어야 함.)
    • 실녹기의 기본 폴더 설정임.
    • 입력한 폴더에 [hevc인코딩, 스트림 복사, 오디오추출] 이렇게 세 개의 폴더가 생성됨
  4. [string]$Extension = 뒤에 'mkv'대신 원하는 비디오/오디오 컨테이너 확장자 입력,(mkv,mp4 추천)
  5. [switch]$Recurse는 st.ps1 [중간에_입력한_여러_명령어들] 뒤에 -Recurse 라고 입력해서 실행하면 하위 폴더 내  모든 파일들일  검색해서 실행함.
    • 개인적으로는 따로 입력하지 않고 그냥 그대로 쓰는 것을 추천
    • [switch] 변수는 기본적으로 입력하지 않으면 $false로 작동함.
    • -Recurse 옵션이 하위 폴더 내 파일 모두 검색 옵션이기 때문에 꼭 필요하지 않는 이상 쓰지 않는 것을 추천합니다.
  6. param () 안에 $로 시작하는 각 변수는 파워쉘 명령에서 따로 설정하지 않으면 생기는 default 값임.
    • 파워쉘에서 입력할 때, 해당 인자가 입력되면, 입력한 대로 사용됨.
    • st -dir 이렇식으로 변수명을 입력하면, 순서 상관 없이 알아서 지정됨.
    • 관련 내용은 아래 활용법에서 정리해드림.
  7. 그래픽 가속 인코딩이고, nvdia 그래픽 카드만 가능합니다.
    • 그 중에서 1000번대 이전 구형 그래픽 카드는 [string]$newGPU = "블라블라" 써진 코드 앞에 '#' 을 붙여주면 알아서 오류가 해결됩니다.

파워쉘에서 사용방법

순서 상관 없이 인자 뒤에 값으로 설정

st -SearchString [파일명에서_공통부분입력] -SearchPath [인코딩_후_저장할_폴더지정] -Extension [인코딩_후_파일_확장자_설정] -Recurse(입력할지말지선택)

인자 없이, 순서로 인자값 설정

st [파일명에서_공통부분입력] [인코딩_후_저장할_폴더지정]  [인코딩_후_파일_확장자_설정] -Recurse(입력할지말지선택)

각 인자 입력 방식으로 활용법 정리

아래의 예시는 구버전의 목록이지만 응용할 수 있는 힌트로 보시면 됩니다.

 각 예시 사진을 보면서 확인해보세요.
1. 아무것도 입력 없이 명령어만 입력 
st


2. 각 파일명에서 공통되는 텍스트 입력

(주로 스트 아이디 입력으로 해당 파일 긁어모음)

st [공통되는_파일명]


3. 모든파일들을 "원하는폴더"에 저장(공백으로 구분)
st * [원하는폴더]


4. '공통되는파일명' '원하는폴더' 모두 지정(공백으로 구분)
st [공통되는파일명] [원하는폴더]