環境・やりたいこと
- Windows10
- Anaconda
- python3.10
mp4ファイルの容量を小さくしたい
試したこと
opencv-pythonを使って以下のようにリサイズしました。
画素数を下げることと、fpsを下げることをしています。
fourccなどについてはよく理解できてません。
python
1import cv2 2#リサイズしたいファイル:input_filepath 3 4resize = 2 #ファイルサイズを2分の1にしたい 5resize = resize**0.5 #ルート2 6cap = cv2.VideoCapture(input_filepath) 7 8#生成する無音動画ファイルのパス 9temp_videopath = f".\\temp_video.mp4" 10 11#動画のプロパティを取得 12width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) 13height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) 14fps = cap.get(cv2.CAP_PROP_FPS) 15 16#動画をリサイズ 17fourcc = cv2.VideoWriter_fourcc('m','p','4','v') 18min_fps = 30 19if fps <= min_fps: 20 writer = cv2.VideoWriter(temp_videopath,fourcc, fps, (int(width/resize), int(height/resize))) 21else: 22 writer = cv2.VideoWriter(temp_videopath,fourcc, min_fps, (int(width/resize), int(height/resize))) 23while True: 24 ret, frame = cap.read() 25 if not ret: 26 break 27 cv2.imshow("Frame", frame) 28 frame = cv2.resize(frame,(int(width/resize), int(height/resize))) 29 writer.write(frame) 30writer.release() 31cap.release() 32print("リサイズ完了") 33 34#この後音声を抽出したり結合したりするが割愛
発生している問題
期待していた通りに容量が減ることもあるが、リサイズ前よりも後の方がサイズが大きくなってしまうことがある
245MB→432MBに増加するなど。
これをどうにかしたいのですが、方法が分かりません。
resizeやfps変更をしないで、単に別ファイル名に書き込むだけの場合は、ファイルサイズはだいたい同じになるのでしょうか?
元動画のコーデックを調べて、それに合わせてみたら、どうなりますでしょうか?
https://qiita.com/Gyutan/items/e279e8680b90ca891250
resizeやfps変更をしないで~についてですが、この場合もファイルサイズは大きくなってしまいます。
コーデックについては、mp4がどのようなコーデックを持つのかを知らないので分かりません...コンテナとかいろいろあるみたいですが、調べてみてもよく分かりませんでした。
私が紹介したWebページの
「OpenCVにおけるコーデックの確認方法」
に、コーデックの調べ方が解説されてます
その方法で元動画のコーデックを調べて、それがもし「'm','p','4','v'」とは違ったら、元動画と同じコーデックを指定して、resizeやfps変更をしないで保存したら、ファイルのサイズはどうなりますでしょうか?
動画のコーデックは['a', 'v', 'c', '1']になってました。
resize=1,fpsそのままでavc1でリサイズするように↓のようにしてみましが、246MBのファイルが292MBになりました。
fourcc_int = int(cap.get(cv2.CAP_PROP_FOURCC))
original_fourcc = list((fourcc_int.to_bytes(4, 'little').decode('utf-8')))
print(original_fourcc)
fourcc = fourcc_int
writer = cv2.VideoWriter(temp_videopath,fourcc, fps, (int(width/resize), int(height/resize)))
実行してみると、下記のようなメッセージが出てきました。
Failed to load OpenH264 library: openh264-1.8.0-win64.dll
Please check environment and/or download library: https://github.com/cisco/openh264/releases
> Failed to load OpenH264 library: openh264-1.8.0-win64.dll
が出てる場合は、「'a', 'v', 'c', '1'」(H.264)で保存できてません
「'a', 'v', 'c', '1'」(H.264)で保存するための方法は、
https://blog.shikoan.com/opencv-h264/#OpenH264%E3%81%8C%E5%BF%85%E8%A6%81
の「OpenH264が必要」を見てください
「'a', 'v', 'c', '1'」(H.264)でresizeやfps変更をしないで保存したら、「'a', 'v', 'c', '1'」(H.264)の元動画と同じくらいのファイルサイズになるのではないですかね
元動画とだいたい同じファイルサイズで保存できれば、resizeで画素数を減らせばファイルサイズが小さくなることが期待できます
ありがとうございます。
ダウンロードして実行してみました。OpenH264 Video Codec provided by Cisco Systems, Inc.との表示が出たので['a', 'v', 'c', '1']でリサイズできたのでしょうが、ファイルサイズはむしろ246MB→1.28GBに大きくなってしまいました...
保存したファイルを再度opencvで読み出してエンコードを調べたら、「'a', 'v', 'c', '1'」でしょうか?
保存したファイルを絶対パスで指定してエンコードを調べましたが、
828601953、['a', 'v', 'c', '1']
でした。
当方のmacでやってみました
https://mixkit.co/free-stock-video/portrait-of-a-woman-in-a-pool-1259/
から動画ファイルをダウンロードしました
ファイルサイズは 48MB でした
pythonで下記を実行したら、動画ファイルのエンコードは「'a', 'v', 'c', '1'」でした
import cv2
cap = cv2.VideoCapture("./mixkit-portrait-of-a-woman-in-a-pool-1259.mp4")
fourcc_org_int = int(cap.get(cv2.CAP_PROP_FOURCC))
fourcc_org = list((fourcc_org_int.to_bytes(4, 'little').decode('utf-8')))
print(fourcc_org)
そこで、
fourcc = cv2.VideoWriter_fourcc('a','v','c','1')
として、resizeやfps変更をしないで
writer = cv2.VideoWriter(temp_videopath, fourcc, fps, (width, height))
としてから、
while True:
ret, frame = cap.read()
if not ret:
break
writer.write(frame)
と、無加工で動画ファイルを作成したら、できたファイルのサイズは 47.3MB となり、元動画ファイルの 48MB に近いサイズになりました
(上記コードは必要最小限だけ書いてます)
こんな感じになると予想してたのですが、
> ファイルサイズはむしろ246MB→1.28GBに大きく
ですか
当方のmacで実行した際は、エラーが出なかったので「OpenH264」をインストールする必要はありませんでした
当方のmac内で使われたものと「OpenH264」で、性能に違いがあるのかもしれません
同じ縦横同じfpsの動画のサイズに影響を与える要素って、fourccだけなんでしょうか。
jpegみたいな品質の設定とかはないんですかね?
フレーム書き込み処理の所は私のだと下のようになっているんですが、jbpb0さんのと同じ書き方をしても結果って変わりませんかね
resize=1
while True:
ret, frame = cap.read()
if not ret:
break
cv2.imshow("Frame", frame)
frame = cv2.resize(frame,(int(width/resize), int(height/resize)))
writer.write(frame)
resize=1
while True:
空白ret, frame = cap.read()
空白if not ret:
空白空白break
空白cv2.imshow("Frame", frame)
空白frame = cv2.resize(frame,(int(width/resize), int(height/resize)))
空白writer.write(frame)
> jpegみたいな品質の設定とかはないんですかね?
ビットレートを変えたら、ファイルサイズは変わります
https://jbjbgame.com/post-5623/
https://github.com/opencv/opencv/issues/8961
https://stackoverflow.com/questions/38686359/opencv-videowriter-control-bitrate
当方のmacで確認した
> できたファイルのサイズは 47.3MB となり、元動画ファイルの 48MB に近いサイズになりました
では、ビットレートは下記の通りで、だいたい同じでした
・元ファイル:25715 kb/s
・opencvで作成したファイル:25359 kb/s
> ファイルサイズはむしろ246MB→1.28GBに大きく
の元動画ファイルと、opencvで作成した動画ファイルのそれぞれで、
右クリック→プロパティ→詳細
でビットレートを確認
https://pc-kaizen.com/windows10-check-the-bit-rate-of-the-video
してみてください
元動画ファイルよりもビットレートが増えてるのかも
windowsでも、同じ動画ファイル
https://mixkit.co/free-stock-video/portrait-of-a-woman-in-a-pool-1259/
でやってみましたが、macでの結果と同様に、元動画ファイルとopencvで作成したファイルは、ビットレートもファイルサイズもだいたい同じになりました
windowsではエラーが出たので「OpenH264」をインストールしましたが、結果はmacと同様だったので、「OpenH264」の性能が劣ってるわけではないようです
私が使った動画ファイルのビットレートが、たまたまopencvが作成する動画ファイルのビットレートと近かったので、ファイルサイズもだいたい同じになった、という気がします
ありがとうございます。ビットレートは考え付きませんでした。
ビデオ
データ速度 10093kbps→54420kbps
総ビットレート 10411kbps→54547kbps
オーディオ
ビットレート 316fps→126kbps
に変わっていました。(矢印右側がリサイズ後)
音声の処理はffmpegで以下のようにやりました。
import subprocess
import ffmpeg
#元ファイルから音声を抽出
#入力
stream = ffmpeg.input(input_filepath)
#出力
stream = ffmpeg.output(stream, "temp_audio.mp3")
#実行
ffmpeg.run(stream)
#音声ファイルとリサイズ後ファイルを結合
command = ["ffmpeg"
,"-i"
,temp_videopath
,"-i"
,"temp_audio.mp3"
,"-c:v"
,"copy"
,"-c:a"
,"aac"
,"-map"
,"0:v:0"
,"-map"
,"1:a:0"
,resize_videopath]
subprocess.run(command)
commandの内容は、調べている時に見つけたものをそのまま貼り付ける形で使っています。
音声ファイルと結合する前のリサイズ済み無音動画ファイルのサイズも確認しましたが、やはり大きかったです。なので、一番の原因はopencvの段階にあるんじゃないかとは思います。
> 音声の処理はffmpegで以下のようにやりました。
そこでffmpegを使うのなら、動画をリサイズしたりフレームレートを変えたりするところも、opencvを使わずにffmpegを使ったらいいと思います
https://jbjbgame.com/post-5623/#st-toc-h-3
のオプションで、
・映像と音声のビットレートと、コーデックは元動画ファイルと同じ
・フレームレートとサイズは、任意の値
とすれば、この質問の意図通りの結果になると思います
(ビットレートも変えていいかも)
そうですね、ffmpegで全部やれてしまえるならそっちの方が効率がよさそうですね。
元ファイルのビットレートに応じた演算をするためにffmpeg.probeからビットレートを取得しようとしているのですが、ffmpeg.probe(input_filepath)["streams"][0]["bit_rate"]で得たbit_rateの値が10117031でプロパティから見た値が10093kbpsと微妙に違うのですが、これは2進数からくる誤差と捉えて大丈夫ですかね?
> ffmpeg.probe(input_filepath)["streams"][0]["bit_rate"]で得たbit_rateの値が10117031でプロパティから見た値が10093kbpsと微妙に違う
何で違うのか分かりませんが、ffmpegで処理するのだから、ffmpegで取得した値を使えばいいと思いますよ
以下は、参考情報
python経由ではなく、コマンドプロンプトで直接
ffmpeg -i 動画ファイル名
または
ffprobe 動画ファイル名
を実行したら、「Duration:」で始まる行と、「Stream」で始まる行の両方にビットレートが表示されますが、下記によると「Stream」で始まる行の数値が動画作成時にエンコーダーに設定された数値らしいので、それを設定したらいいと思います
https://stackoverflow.com/questions/54608161/what-is-the-difference-of-duration-bitrate-and-stream-bitrate-in-ffmpeg-ffprobe
(ffmpeg実行だとoutputがどうとか言われるけど気にしない)
ffprobe -loglevel quiet -show_streams 動画ファイル名
を実行した結果の「bit_rate=数値」は、上記の「Stream」で始まる行の数値をkbpsではなくbps表示(3桁増える)したものです
https://www.ninton.co.jp/archives/3081
おそらく、下記と同じ数値だと思います
> ffmpeg.probe(input_filepath)["streams"][0]["bit_rate"]で得たbit_rateの値
ビットレート値の微妙な違いがリサイズ後の生成物に大きな影響を与えるというわけではないのなら気にせずやっていこうと思います。
.command = ["ffmpeg"
. , "-i", input_filepath
. , "-b:v", f"{bit_rate_k}k"
. , "-c:v", "h264"
. , "-c:a", "copy"
. , "-r", f"{fps}"
. , "-s", f"{width}x{height}"
. , resize_videopath]
.subprocess.run(command)
でやってみたところ、うまくいきました。同じ縦横、同じfps、同じビットレートでやってみるとほとんど同じ容量のものができました。
command=[]に特に問題が無いようでしたら、ベストアンサーとさせていただきたいので回答をお願いします。
opencvではなくffmpegでやる場合は、たしか元動画ファイルに音声がある場合は変換後の動画ファイルにも音声が残ったような記憶があります
それが合ってるなら、音声のビットレートも指定しないと、もしかしたら変わってしまうかもしれません
音声は容量的には少ないので、音声のビットレートが変わってもファイルサイズ的にはほとんど効きませんが、音声の音質が変わるのは実用上困るかもしれないので
あと、動画のビットレートを変えずに解像度(画素数)を減らすのと、解像度を変えずにビットレートを減らすのと、両方を(控えめに)減らすのと、変換後の画質とファイルサイズのバランス的にどの組み合わせが最良か、で変換のパラメータを決めたらいいと思います
実際にfps,画素数,ビットレートを下げて私が先程書いた通りのcommandで実行してみましたが、音声はちゃんと入ってました。
保険としてビットレート指定を入れておくとかは必要なんでしょうか?
右クリック→プロパティ→詳細
で、元動画ファイルと作成した動画ファイルそれぞれの音声(オーディオ)のビットレートを確認して、もしビットレートが著しく増えてたら、意味無いので元ファイルと同じ数値を指定したらいいと思います
ビットレートが著しく減ってる場合は、作成したファイルの音声を聞いて音質低下が気になるなら元ファイルと同じ数値を指定し、気にならないならそのままでいいと思います
音を聞いてプロパティを見てっていう手間をかけるなら最初から音声ビットレートを指定した方が無難そうですね...
音声ビットレートなどについては追々やっていきますが、質問の趣旨は達成できたので回答していただいてもよろしいでしょうか。回答していただかないとベストアンサーにできません。
回答1件
あなたの回答
tips
プレビュー