1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

googleフォトの空き容量を広げる(iphone動画の縮小編)

Last updated at Posted at 2022-11-03

この記述で、動画を縮小すると同時に、動画のメタデータと更新日時を撮影日時にセットすることが出来ます。撮影日時が入ることで、ローカルでもクラウドでも管理が楽になります。

環境
iPhone 11 iOS ver 15.1
Windows10 (iTtunes入り)

課題
・FHDで撮影した動画がgoogleフォトにアップロードされて15G制限の容量を圧迫している。
・iphoneとUSB接続したwindowsで読み込んだ動画(MOVファイル)は撮影日時データを持っている様だが、ファイルの更新日時には反映されていない。
・ffmpegを使って(Windows上で)縮小画像を簡単に得ることが出来るが、撮影日時データが失われるので、縮小動画をgoogleフォトにアップロードしたときに、作業日の日付になってしまう。

解決策
pythonで簡単なプログラムを作成し、撮影日時が反映された縮小動画をwindows上で作成する。
これをgoogleフォトにアップロードする。大きな元画像はブラウザなどでgoogleフォトにアクセスし別途削除する。削除対象はgoogleフォトで「mov」を検索することで見つけられる。また、縮小動画の作成の際はmp4ファイルとすることで識別しやすくした。
image.png

よく分からないこと
googleフォトで元画像がmovで検索出来るが、変換後画像をmp4で検索しても一部しか出てこない。反映されるのに時間がかかるのか?
しかし、jpgで検索すると先ほどアップロードした写真がちゃんと表示される。

その他
googoleフォトはクラウド側がなので、ローカルフォルダ内で縮小や加工をしても反映されない。このため、変換前の大きなサイズの動画や写真は手動で削除する必要がある。(良い方法があれば教えてください)

縮小動画作成の手順

ffmpegの準備

公式サイトから、ソースコードをダウンロードしてビルドする。のは面倒なので、公式のリンクからビルド済みのEXEファイルをダウンロードして解凍する。pathなど設定はpythonプログラムから直接指定するので特に不要。今回、リンク先からダウンロードしたのはffmpeg-2022-10-17-git-3bd0bf76fb-full_build.7z 7Z圧縮ファイルの解凍は「7-Zip File Manager」を使った。
https://ffmpeg.org/download.html#build-windows
https://www.gyan.dev/ffmpeg/builds/

pythonの実行環境

今回はminicondaでpython3.9.12(作業時最新)をダウンロードしインストールした。
anacondaでも良い。Sony NNCのpython環境を流用することもできる。
https://docs.conda.io/en/latest/miniconda.html
https://qiita.com/katakaku/items/39a2694d45a2c8fcebd0

エディタ

試行錯誤するなら必要。ここでは、VScodeを用いた。pythonのファイルを開いて、python拡張機能を追加する。pythonインタプリンタを指定するよう求められるので、anaconda miniconda等のpython.exeのありかを指定する。
https://azure.microsoft.com/ja-jp/products/visual-studio-code/

jupyternotebookでもよい。命令の実行だけなら、ターミナルで python test.py でも。

全体のプログラム

ライブラリ

subprocess os datetime glob の4つ。pipやcondaでインストールしなくても標準で入っている。

パスの指定

ffmpegと日付を含むメタデータを出力するtempファイルを指定している。
windowsで動かすので、区切り文字がバックスラッシュ2個であることに注意。
ffmpeg_path="D:\temp_ffmpeg\bin\ffmpeg.exe"
temp_file="D:\temp_ffmpeg\bin\temp.txt"

関数 get_mytime(mp4_file):

動画ファイルを引数として、撮影日時を返す。mp4でもmovでもいい。
コマンドラインで、

ffmpeg -i 動画ファイル

 と命令すると得られる出力(標準エラー出力)をtempファイルに保存する。
 なお、標準出力はリダイレクト でファイルに落とし込めるが、標準エラー出力は2>でリダイレクトする。
そのファイルから、creation_time をキーワードに、撮影日時を含む行を抽出し、「:」の位置を手がかりに撮影日時を抽出し戻り値とする。撮影日時は日本時間ではないので+0000と明言している。
subprocess.call(命令文 ,shell=True)とすると、DOS窓(コンソール)で打ち込んだ時と同じことが出来る。

メタデータを得る手段としては、

ffmpeg.exe -i 動画ファイル -f ffmetadata temp.txt

もあるが、日時が入っていないiphoneで撮影した動画ファイルもあったため、上記の法が堅牢である。

関数 kousin_time_set(my_time,out_mov_file):

縮小後の動画の更新日時(ファイルエクスプローラやファイルのプロパティで確認できる)を撮影時刻にセットする関数。引数として、get_mytime関数の戻り値と動画ファイルのパスを与える。
os.utime というメソッドを利用する。

本文

original_mov_file_folder="D:\temp_ffmpeg\original_mov\*.MOV"
out_mp4_file_folder="D:\temp_ffmpeg\out_mp4\"
入力動画用のフォルダと出力動画用のフォルダを指定する。

original_mov_files = glob.glob(original_mov_file_folder)
入力用フォルダの複数の動画のフルパスをリスト形式で得る。
以下、forループで動画ファイル1つずつループを回す。

out_mp4_file = out_mp4_file_folder + os.path.splitext(os.path.basename(original_mov_file))[0]+"_HD.mp4"
出力動画のファイル名を、オリジナルのファイル名に_HDを加え、拡張子をmp4にする。

エスケープ文字をうまくページで表せないので、画像で記載。
image.png

final_cmd として、ffmpegで動画を縮小しつつ、日時メタデータを加えるコマンドを作成する。
-vf scale=-1:ih*2/3 とすることで、元画像の2/3のサイズ(縦横の長さ)になる。ihが高さで、幅は-1としているのは自動設定の意味。FHDの2/3のサイズとするとHDサイズになる。ファイルサイズは約半分になる。
https://irilyuu.com/ffmpeg/ffmpeg-resize/
-c:a copy を加えることで、音声は再エンコードしない。処理時間も早くなる。

なお、GPUボードがあれば、-c:v h264_nvencを加えると処理が早い。(GTX1050で8-10倍速)
https://neos21.net/blog/2022/01/28-01.html
https://www.usagi1975.com/202107182149/
今回ダウンロードしたffmpegはオプションを加え、Nvidiaのドライバを更新するだけで利用できた。

動画作成後、ファイルの更新日時を撮影日時に合わせるため、kousin_time_set関数を実行して終わり。(これを利用して、オリジナルの動画の更新日時を修正することもできる)20221116追記:標準時を標準時と明記せずdatetimeメソッドに渡していたので、9時間ずれていたのを修正。tzinfo=datetime.timezone.utcを入れた。

以下、今回の全コード。パスを適当に改変して利用する。

import subprocess
import os
import datetime
import glob
ffmpeg_path="D:\\temp_ffmpeg\\bin\\ffmpeg.exe"
temp_file="D:\\temp_ffmpeg\\bin\\temp.txt"

# ファイルパスの区切りがLinuxでは/スラッシュだが、windowsではバックスラッシュ¥なのでエスケープが必要。

def get_mytime(mp4_file):

    if(os.path.isfile(temp_file) == True):
        os.remove(temp_file)#あらかじめTempファイルを削除する
        
    # 作成時刻などをtempファイルに出力する。標準エラー出力をtempファイルに入力する
    subprocess.call(ffmpeg_path + ' -i ' + mp4_file + ' 2> ' + temp_file ,shell=True)

    #tempファイルに出力した内容から、作成日時をmy_time文字列変数として抽出する
    with open(temp_file) as f:
        for i, line in enumerate(f):
            if 'creation_time' in line:# creation_timeを含む行を調べる
                break

    print(i)
    print(line)
    index = line.find(":")
    print(index)
    print(line[index+2:])
    my_time = line[index+2:index+21]#最後の改行は落とす
    print("+++++++++++++++++++++++++++")
    print(my_time)
    return my_time +'+0000'# 作成日時をmy_time文字列変数として戻す creation_timeは標準時なので、明記する


def kousin_time_set(my_time,out_mov_file):
    y=int(my_time[0:4])
    m=int(my_time[5:7])
    d=int(my_time[8:10])
    h=int(my_time[11:13])
    min=int(my_time[14:16])
    s=int(my_time[17:19])
    atime = datetime.datetime(year=y, month=m, day=d, hour=h, minute=min, second=s, microsecond=0,tzinfo=datetime.timezone.utc)

    print(y,m,d,h,m,s)

    os.utime(path=out_mov_file,times=(atime.timestamp(),atime.timestamp()))



original_mov_file_folder="D:\\temp_ffmpeg\\original_mov\\*.MOV"
out_mp4_file_folder="D:\\temp_ffmpeg\\out_mp4\\"

original_mov_files = glob.glob(original_mov_file_folder)

for original_mov_file in original_mov_files:

    #original_mov_file="D:\\temp_ffmpeg\\bin\\IMG_3515cp.MOV"
    #original_mov_file=original_mov_files[0] 1つめのファイルを個別に指定するとき

    out_mp4_file = out_mp4_file_folder + os.path.splitext(os.path.basename(original_mov_file))[0]+"_HD.mp4" 
    #元の名前にHDを加えて、拡張子をmp4に変える。パスも指定している。

    my_time=get_mytime(original_mov_file)

    meta_option = "-metadata" + " creation_time"+"=" + "\"" + my_time + "\""
    print(meta_option)

    #CPUのとき final_cmd = ffmpeg_path + " -i " + original_mov_file + " " + meta_option + " -vf scale=-1:ih*2/3 " + out_mp4_file
    final_cmd = ffmpeg_path + " -i " + original_mov_file + " " + meta_option + " -vf scale=-1:ih*2/3 " +"-c:v h264_nvenc "+ "-c:a copy "+out_mp4_file#GPU対応

    # -vf scale=-1:ih*2/3 とすると、元画像FHDの2/3の大きさでHD相当の大きさになる。

    subprocess.run(final_cmd, shell=True)#ffmpegのコマンドを実行して、縮小されたmp4ファイルを作成する。

    kousin_time_set(my_time,out_mp4_file)#作成した動画の更新日時を撮影日時にする。

その他のトライアル

このサイトから大きなヒントを得ましたが、そのままでは自分の環境では動かなかった。

簡潔に利用法が記述されているサイト。メタデータのコピーについて記載があるが、自分の環境では動作しなかった。

メタデータがグローバルやチャプターごとなど適用範囲があることを記述している。

公式サイト(翻訳して読むが難しい。wwwがあるのと、ないのとどっちを見るんだ?)

subprocessrun( )がうまく使えなかった。バージョンアップにより機能が次々増えている模様。 shell=Trueオプションを付けることでうまくいった

ファイル更新日時の操作については、以下のサイトを参考にしました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?