- 締切済み
Powershellでtsファイルをmp4に変換
Powershellでtsファイルを無劣化でmp4に変換する事が出来そうなので 下記の記事を参考にスクリプト(test.ps1)を作成してみました。 http://pcsos.blog89.fc2.com/blog-entry-243.html '-------------------------------------------------- # MP4・MPG・WMV・TS ⇒ H.264 MP4 (PowerShell ファイル名スペース対応) $TARGET_DIR="C:\Users\ssd\Desktop\変換前\" $DEST_DIR="C:\Users\ssd\Desktop\変換後\" $FFMPEG="C:\ffmpeg-2022-12-11\bin\ffmpeg.exe" $FFMPEG_OPT_VIDEO="-c:v copy" $FFMPEG_OPT_AUDIO="-c:a copy" function h264enc { if ($args.count -ge 1) { $arg="-i '$args.mpg' -movflags faststart $FFMPEG_OPT_VIDEO $FFMPEG_OPT_AUDIO $DEST_DIR'$args.mp4'" powershell -Command "$FFMPEG $arg" } else { "エンコード対象のファイルを指定してください。" } } cd $TARGET_DIR Get-ChildItem | ForEach-Object { h264enc $_.Basename } pause '-------------------------------------------------- 変換されそうにはなりますが、 mpegを書き出し時に 「No such file or directory」とエラーになります。 エラーの修正をお願いします。
- みんなの回答 (6)
- 専門家の回答
みんなの回答
- superside0
- ベストアンサー率64% (461/711)
> 具体的には、a.txtが存在するとa.tsとして変換対象とするようで ターゲットにディレクトリ内に、*.tsファイルのみだけという条件で 成り立つプログラムになっているからですね。 具体的には Get-ChildItem | ForEach-Object { h264enc $_.Basename } ですべてのファイルをループで回してますが .Basenameを指定しているのでそのファイル名から拡張子と取り除いてからh246encというfunctionに渡しています。 受け取ったh246enc内では、 受け取った拡張子無しの名前に $args.ts として拡張子.tsを 追加しているので a.txtがあるとき a.txt → a → a.ts というファイル名の変換が行われて ffmpeg.exe の引数にしているので 当然、そのファイルが存在しないエラーになりますね。 もともとの話では、 > (そのために変換すべきtsファイルを事前に集合させています。) でしたが、それ以外のファイルもあるのなら それを考慮したプログラムにしないとだめです。 案1) 基本的にはいまのままで function h264enc 内で 引数で指定されたベースファイル名(拡張子無し)したに.tsを保管した ファイルが存在しなければfunctionを終わるようにif分を追加する if ( -not (Test-Path "$args.ts") ) {return} 案2) Get-ChildItem だけだと ディレクトリ内の全ファイルとサブディレクトリを取り出すので Get-ChildItem ↓ Get-ChildItem -File -Recurse -Include *.ts に変更して特定の拡張子のファイルのみに絞り込む 案3) 上記に加えて Get-ChildItem -File -Recurse -Include *.ts -Name にし、その行のfunctionをコールしている { h264enc $_.Basename } を { h264enc $_ } にしてしまえば function内で "$args.ts"のようにして.tsを連結させる必要もなくなる
- superside0
- ベストアンサー率64% (461/711)
Get-ChildItem | ForEach-Object { h264enc $_.Basename } で ファイル名の拡張子を外したものを Functionに渡せれますが それを Function内で "-i '$args.mpg' ~" のように、ダブルクォーテーションのなかでクォーテーション を使うと クォーテーションがそのまま生きて 「-i '元のファイル名の拡張子なし.mpg' ~」に展開されて しまっていませんか? つまり、前後に クォーテーションが付帯してしまった 本来は存在しないファイル名になってしまっていませんか? 実験してみたのですが、たとえば、 a.txt b b.txt ※ファイル名中に空白あり 日本語ファイル名.txt というファイルのみがあるディレクトリで function aaa { $arg="$args.txt"; type $arg } Get-ChildItem |ForEach-Object { aaa $_.Basename } だと各txtをtype表示してくましたが、 この例のように function aaa { $arg="'$args.txt'"; type $arg } Get-ChildItem |ForEach-Object { aaa $_.Basename } だと 'a.txt'ファイルが見つからないというエラーになりました。
お礼
superside0さん、回答感謝いたします。 Powershellのど素人がネット情報を頼りに付け焼き刃で希望の処理をしたいと 「ああでもない、こうでもない、それではここを変更すれば、んー!!、これも違う」と 試行錯誤で進行しているのでおかしな点がたくさん発生していると思います。 現在も改良途中ですが この記載の下の方に試用中のps1コードを添付しました。 '--------------------------------------------- >本来は存在しないファイル名になってしまっていませんか? >だと 'a.txt'ファイルが見つからないというエラーになりました。 ご指摘の点ですが 「a.ts'ファイルが見つからない」というエラーになりました 正確には「No such file or directory」のエラー表示が出ます。 一応、tsファイルはmp4ファイルには変換できますが それ以外にTSファイルが置かれているディレクトリに 動画ファイル(*.ts)以外に他のファイル(*.bat,*ps1)も存在するので このファイルも処理しようとして 「No such file or directory」とエラー表示が出ます。 具体的には、a.txtが存在するとa.tsとして変換対象とするようで 当然そのような拡張子のファイルは存在しないので上記のエラーが吐き出されます。 (ts以外のフィルが10個あるとすれば同じエラーが10個表示されます。) 拡張子がtsのファイルのみを処理対象として それ以外の拡張子は処理対象から外したいのですが どのようにコードを変更すれば良いでしょうか? アドバイスをお願いします。 '----------------------------------------------- 以下現在のps1のコードです。 #tsファイルを無劣化でmp4に変換 #'--------------------------------- # TSファイルが置かれているディレクトリ $TARGET_DIR="C:\Users\TAC_\Desktop\変換前" # ffmpegの実行ファイル $FFMPEG="C:\ffmpeg-2022-12-11\bin\ffmpeg.exe" # エンコードオプション(Video コピー) $FFMPEG_OPT_VIDEO="-c:v copy" # エンコードオプション(Audio コピー) $FFMPEG_OPT_AUDIO="-c:a copy" # スレッド数。CPUのコア数と同じ数 ?。 #Inter(R)Core(TM) i5-10400CPU @2.90HHZ コア数=6 $FFMPEG_OPT_THREADS="6" # ファンクション定義 function h264enc { if ($args.count -ge 1) { $arg="-i '$args.ts' -movflags faststart $FFMPEG_OPT_VIDEO $FFMPEG_OPT_AUDIO -threads $FFMPEG_OPT_THREADS '$args.mp4'" powershell -Command "$FFMPEG $arg" } else { "エンコード対象のファイルを指定してください。" } } cd $TARGET_DIR Get-ChildItem | ForEach-Object { h264enc $_.Basename } #ファイル名を変えずにmp4を移動させる場合 Move-Item *.mp4 C:\Users\TAC_\Desktop\変換後 #PowerShellで一時停止(PowerShellでもPauseは使える) #「続行するには、Enter キーを押してください…:」と表示される。 pause
- 4017B
- ベストアンサー率73% (1336/1814)
>作成依頼の全て丸投げ状態 いつもでしたら華麗にスルー&ブロック登録して終わる所ですが(笑)。今回は前述した通り、自分も現在勉強中の身ですので、自分のスキルアップのためにも何とかやってみようと思いますが…ちょっと時間が掛かりそうです。 なので確約は出来ないのですが、1週間くらいですかね?ちょっと今現在、自分のPCが調子が悪くて、作業中に突然にOS再起動に入ったりする謎現象が発生する様になりまして…この回答を書き込んでいる最中もちょっとビク付きながら行っています。 なのでこのままこのスレは閉じて貰っても構いませんし、気長に待って貰えるのであれば、30日後に自動締め切りされるまで放置でも構いません。ちょっと色々とやってみたいと思います…!
お礼
>いつもでしたら華麗にスルー&ブロック登録して終わる所です そうでしょうね。 総判断されても良いような丸投げ依頼ですから.... >自分のスキルアップのためにも何とかやってみようと思いますが…ちょっと時間が掛かりそうです。 PCが調子の悪い状態で問題解決のため助言頂けそうなので どう言う結果が出ても良いのでこのまま4017Bさんのリターンを待ちたいと思います。 よろしくお願いします。 (私のPCも約2ヶ月前メモリーの接触不良が原因でPCがハング状態になる 症例が出たり出なかったりで原因特定に到るまで約1ヶ月かかりました。 その間、何度もメモリーの指し直しはやっているのですが 症状が出るほどに憂鬱な気分で過ごしていたので4017Bさんの現状は少しは理解できます。) 私の方も理解不足ながらコードの見直しなどを続けています。 現時点で少し改善がありました。 最初の質問でうまく処理できなかったコードですが 参考記事のコードがおかしかったのも原因のようです。 一応、試行錯誤の結果。下記のps1で処理はできましたが問題もあります。 (tsファイル自体は、無劣化でmp4には変換できました。) 問題とは、TSファイルが置かれているディレクトリには 動画ファイル(*.ts)以外に他のファイル(*.bat,*ps1)も存在するので このファイルも処理しようとして 「No such file or directory」とエラー表示が出ます。 例えば、test.ps1が存在するとtest.tsとして変換対象とするのですが 当然そのようなファイルは存在しないので上記のエラーが吐き出されます。 #tsファイルを無劣化でmp4に変換 #'--------------------------------- # TSファイルが置かれているディレクトリ $TARGET_DIR="C:\Users\TAC_\Desktop\変換前" # ffmpegの実行ファイル $FFMPEG="C:\ffmpeg-2022-12-11\bin\ffmpeg.exe" # エンコードオプション(Video コピー) $FFMPEG_OPT_VIDEO="-c:v copy" # エンコードオプション(Audio コピー) $FFMPEG_OPT_AUDIO="-c:a copy" # スレッド数。CPUのコア数と同じ数 ?。 #Inter(R)Core(TM) i5-10400CPU @2.90HHZ コア数=6 $FFMPEG_OPT_THREADS="6" # ファンクション定義 function h264enc { if ($args.count -ge 1) { $arg="-i '$args.ts' -movflags faststart $FFMPEG_OPT_VIDEO $FFMPEG_OPT_AUDIO -threads $FFMPEG_OPT_THREADS '$args.mp4'" powershell -Command "$FFMPEG $arg" } else { "エンコード対象のファイルを指定してください。" } } cd $TARGET_DIR Get-ChildItem | ForEach-Object { h264enc $_.Basename } #ファイル名を変えずにmp4を移動させる場合 Move-Item *.mp4 C:\Users\TAC_\Desktop\変換後 #PowerShellで一時停止(PowerShellでもPauseは使える) #「続行するには、Enter キーを押してください…:」と表示される。 pause
- 4017B
- ベストアンサー率73% (1336/1814)
PowerShellは同じPS1書式に則ったテキストファイルであれば、特段に変換処理などせずにそのままファイルをPATH指定するだけで、内容を丸ごと読み込んで自スクリプト内で自由に扱う事が出来るという、実に素晴らしい仕様特性があります!これを利用して「外部ファイルリストを読み込む」ことで解決できそうな気がします。 具体的には… 1. BAT等でドラッグ&ドロップで複数ファイルのリストを取得し、それをテキストファイルとして別途保存。 2. 同じくBATでリスト保存後にPS1ファイルを呼び出して実行(BAT本体はここで終了)。 3. BATから呼び出されたPS1ファイルが起動実行、外部リストを読み込んで処理… ~みたいな流れですかね?最初にBATを使うのは、Windowsの標準仕様だとPS1ファイルは直に起動させられないので(右クリックメニューからとか、事前にショートカット化して置く必要があるため、なかなか面倒…)。後、正直、web上にはBAT関連の情報は溢れかえっていますが、PowerShellに関してはまだまだ情報が少なく、特に日本語での解説記事は皆無に近いので。PowerShellで行う処理は出来るだけ簡単基本な事柄に限定させて置いた方が良いかなと。 BATで "my_video_list.ps1" というテキストファイルを作成保存。で、その中身を… $my_flist=@('D:\my-videos\_src\testvideo_01.avi','D:\my-videos\_src\testvideo_02.avi'); ~という風にします。余分な空白や改行は機械に読ませる時には必要無いので、処理を速くしてバグを防ぐためにも、一繋がりの1行テキストとして作成保存して置いた方が良いでしょう。 で、処理を実際に実行するPS1ファイルの冒頭に… .'D:\my-videos\my_video_list.ps1'; ~みたいな感じでリストへのPATHを記述して置きます。PowerShellスクリプトの仕様で、 .'ファイルへのPATH'; という構文で外部ファイルの読み込みコマンドとして機能します。PS1ファイル形式では無いテキストファイルを読み込む場合には、また別の Get-Content を使ったりしますが。同じPS1ファイルであればコレが一番簡単で確実な方法です。 こうして読み込まれたPS1ファイルは、その中に記述された変数や関数などは全て、読み込んだ本体のPS1ファイルに記述したのと同じ様に解釈され機能します。よく使う「ffmpeg.exeへのPATH」などを別途にまとめて外部ファイル化して置く様な使い方はよく使います。 とりあえず以上の様な感じですかね?一応、自分もPowerShellでffmpegを動かす方法は勉強し始めたばかりですので、現時点ではズバっと「コレです!」という風に回答出来ないのがもどかしいのですが…。
お礼
ファイルリストを利用する方法(流れ)のアドバイスありがとうございます。 なんとか「具体的には....」の 1.にあるファイルリスト(名称:FileList.txt)を作成できました 形式は、i以下のように1ファイル、1行形式です。 aaa あああ.ts bbb ddd eee.ts ccc いいい.ts ddd.ts ええええ eee.ts 何となく2.、3. の流れも漠然と理解できますが いかんせんPowershellもbatも初心者の領域なので後に続く説明を残念ながら理解できませんでした。 前提条件として 1)ディレクトリー(C:\Users\ssd\Desktop\変換前)に以下のファイルが存在 対象となる複数のtsファイル tsファイルのファイルリスト(FileList.txt) 動画変換用PSファイル(test.ps1) 2)変換後のmp4ファイルは、変換先フォルダー(C:\Users\ssd\Desktop\変換後\)に書き出す 以上の場合でPSファイルを呼び出すbatファイル(main.bat)はどのようなコードになりますか? 当然、動画変換用PSファイルも現在のtest.ps1を変更しないと動作しないので書き換えが必要だと思います。 作成依頼の全て丸投げ状態で恐縮ですがお願いします。 test.ps1の現在のコードは下記です。 # Powershellでtsファイルをmp4に無劣化で変換 #----- $ffmpeg = 'C:\ffmpeg-2022-12-11\bin\ffmpeg.exe'; $Output_Dir = 'C:\Users\ssd\Desktop\変換後\'; $Convert = '.mp4'; $Source_List = @( 'C:\Users\ssd\Desktop\変換前\あああ いいい 123.ts' ); #----- foreach ( $fname_in in $Source_List ) { $fname_out = $Output_Dir + [System.IO.Path]::GetFileNameWithoutExtension($fname_in) + $Convert; $my_args = "-i `"$fname_in`" -c:v copy -c:a copy `"$fname_out`""; Start-Process -FilePath $ffmpeg -ArgumentList $my_args -NoNewWindow -Wait; } #PowerShellで一時停止(Pause) $host.UI.RawUI.ReadKey();
- 4017B
- ベストアンサー率73% (1336/1814)
PowerShellスクリプトとしても重大な構文エラーがあります。 $Source_List の中身を指定する際に、複数の値を代入する時は , で区切りますが…一番最後の値には「何も付けてはいけない」です。カンマ(,)があるとPowerShellは「まだこの先に続きの値が存在するな…」という風に解釈して処理が続けられ、そしてあるべきはずの値が無いのでエラーになります。 $Source_List = @( 'C:\Users\ssd\Desktop\変換前\あああ いいい 123.ts' ); ~以上の様にして置けば文字化けはするかもだけど、式としてはエラーは無く通るはず…? >日本語&空白文字 まああり得ないというか百害あって一利無しなんで、少なくとも今後共に何らかのスクリプト処理やらコマンドライン系のツールを少しでも扱う気があるのでしたら。今すぐ自分のPC環境から徹底的に「日本語ファイル名を排除」して置いた方が良いと思います。そして同じく「ファイル名とフォルダ名には絶対に空白文字を入れない!!」です。いまマジで "百害あって一利無し" ですので…。 >PowerShellで一時停止 $host.UI.RawUI.ReadKey(); ~という構文を最後に追記して置けば、全部の処理が終わった後でもウィンドウが即閉じる事は無く、何かキー入力があるまで待機する様になります。
お礼
4017Bさん、 アドバイスのカンマ(,)を除いて処理できるのを確認しました。 (リストは、カンマ(,)で繋ぐが最後にカンマ(,)が合ってはダメなのですね) >日本語&空白文字 「ファイル名とフォルダ名には絶対に空白文字を入れない!!」 確かに "百害あって一利無し" なのは薄々気がついていましたが 今回のように元のtsファイルにスペースがある場合は例外となってしまします。 (ファイル名は、他の人が考える事が多いので....) そこで、以下のようなbatでスペースをアンダーバー(_)に変換する事があります。 @echo off rem 該当するファイルを書き換える(スペース>アンダーバー) for %%f in ( *.ts ) do call :sub "%%f" exit /b :sub set fname=%1 set fname=%fname: =_% set fname=%fname: =_% ren %1 %fname% goto :EOF '----------------------------------- 後、処理するファイルのリスト( $my_flist )を手書きでなく 自動で処理するになれば解決しそうです。 何かアイデアはありませんか?
- 4017B
- ベストアンサー率73% (1336/1814)
他人の書いたコードはさっぱり解読不能なので、とりあえず自分ならこうするという感じで PowerShellのスクリプを用いた ffmpegを制御して動画形式のみを変換するサンプルコードです(いわゆる無劣化非圧縮というヤツです)。事前に「処理するファイルのリスト( $my_flist )」を作って置き、そのリストに基づいて変換した動画を「出力用に指定されたフォルダ( $mydir_out )」の中へ保存していきます。 #----- $ffmpeg = 'C:\Program Files\ffmpeg\bin\ffmpeg.exe'; $mydir_out = 'D:\my-videos\_output\'; $my_fext = '.mkv'; $my_flist = @( 'D:\my-videos\_src\testvideo_01.avi', 'D:\my-videos\_src\testvideo_02.avi' ); #----- foreach ( $fname_in in $my_flist ) { $fname_out = $mydir_out + [System.IO.Path]::GetFileNameWithoutExtension($fname_in) + $my_fext; $my_args = "-i `"$fname_in`" -c:v copy -c:a copy `"$fname_out`""; Start-Process -FilePath $ffmpeg -ArgumentList $my_args -NoNewWindow -Wait; } ~自分の環境下では特に問題無く動作しましたので、コレをベースに「環境変数=ファイルへの絶対パス」を使用環境に合わせて書き直して貰えればよいかと。後、やっつけ仕事なので、細かいファイルの死活チェック等のエラーが出ない様にする安全処理などは全く行いませんので。テスト無しにいきなり使わずに、オリジナル動画などは別に安全な場所にコピーしてから実験してください。 あ、自分の癖というか習性で「MKV動画」に変換する様に記述していますので。他の動画形式にする場合は、$my_fext の値を適当に書き換えてください。ffmpegは高性能なので、出力ファイルとして指定されたファイル名の拡張子を見て、自動的にそれに合わせたコンテナ化が成されますので。特にファイル形式指定のための引数は必要ありません。 P.S. 結局、foeach関数が使えるスクリプト処理であるならば。四の五の言わずにfoeach関数を使うのが最も簡単です。後はそこに渡す配列($my_flist)をどうやって生成するかだけに注力すれば良いので。 これもスクリプト等で自動生成するのか、或いはその都度に手書き入力するのかは、処理するファイルの数や頻度、使用者のPC環境などによって変わるでしょうから。どうするのが一番良いのかは、また別の話になります。
お礼
4017Bさん、回答ありがとうございます。 「Avidemuxで複数ファイルを一括読み込んで処理」でも参加いただきましたね。 一応、batで何とか満足行く処置ができたので Powershellに挑戦してみる事にしました。 (batでは、最後まで不要な元動画(*.ts)をゴミ箱に移動させたる事ができずに 代替え案で収まりをつけました。 頂いたコード以下のように私の環境に合うように変更して試用しましたが test.ps1をダブルクリックで起動させても一瞬、PS画面が出ますがすぐに閉じてしまいます。 (最後に pause を追加しましたが....) 変換処理は、行われていません。 思うに変換元のファイルにスペース(半角、全角)を含んでいる事が 原因になる事はありますか ? なお、test.ps1 は、変換元の動画フォルダーに配置しています。 #----- $ffmpeg = 'C:\ffmpeg-2022-12-11\bin\ffmpeg.exe'; $Output_Dir = 'C:\Users\ssd\Desktop\変換後\'; $Convert = '.mp4'; $Source_List = @( 'C:\Users\ssd\Desktop\変換前\あああ いいい 123.ts', ); #----- foreach ( $fname_in in $Source_List ) { $fname_out = $Output_Dir + [System.IO.Path]::GetFileNameWithoutExtension($fname_in) + $Convert; $my_args = "-i `"$fname_in`" -c:v copy -c:a copy `"$fname_out`""; Start-Process -FilePath $ffmpeg -ArgumentList $my_args -NoNewWindow -Wait; } pause '------------------------------------- >配列($my_flist)をどうやって生成するか 変換元の動画ファイルが多い場合 処理するファイルのリスト( $my_flist )を手書きで作成するのは大変なので 希望としては$Source_Listフォルダーに有る全てのtsファイルを対象にしたいです。 (そのために変換すべきtsファイルを事前に集合させています。)
お礼
superside0さん、 ts以外の拡張子を持つファイルを処理対象から外すコードを教えていただき感謝いたします。 >それ以外のファイルもあるのなら >それを考慮したプログラムにしないとだめです。 tsファイルを処理するこのPowershell(ps1)ファイルや 同様な処理ができるbatファイルを一箇所のフォルダーに配置したほうが 後々忘れないだろうし管理が簡単だろうと思い今の状態になりました。 (ホントは、tsファイルだけが良いのでしょうが...) Powershellは、Batより融通が利く分 コードが難解でネット情報もbatほど多くないように思えます。 ど素人の私は、案2),案3)は理解が追い付いていません。 直感的に分かりそうな案1)のIF分を先頭に追加する方法を頂きました。 if分の配置ですが以下のようにしましたがどうでしょうか? 試用では、今までのエラー表示無くmp4への変換作業も行われました。 # ファンクション定義 function h264enc { if ( -not (Test-Path "$args.ts") ) {return} if ($args.count -ge 1) {