monolithic kernel

GoPro の動画ファイルの時刻がずれる問題

追記 2022-09-20

GoPro HERO11 BLACK では GoPro 本体にタイムゾーンの概念が導入され、EXIF にも正しい時刻が記録されるようになった。


GoPro で撮影した動画は撮影時刻がタイムゾーンの分だけずれてしまう問題がある。いつから問題になっているのかもわからないくらい長く存在し続け、まったく直る気配もない。そのため、運用でどうにかカバーできないか考えることにした。

以下、順を追って話していくが、結論としては時刻を修正することは諦めた。代わりに、 exiftool でファイル名にローカル時刻での時刻を埋め込んで、ファイル名で撮影順にソートできるようにした。末尾に PowerShell スクリプトも載せてある。

> exiftool '-FileName<CreateDate' -d '%Y%m%d-%H%M%S-%%f.%%e' -api QuickTimeUTC -GlobalTimeShift -9 *.mp4

まず気になるのは、この問題がなぜ起きるのか。GoPro のカメラ本体にはタイムゾーンの概念がない (少なくとも設定することも確認することもできない)。動画を撮影した際には、設定されている時刻を UTC とみなして書き込むようになっている。世の中のアプリは基本的に UTC で書き込まれているものとして読み出すため、ユーザーがローカル時刻を設定している場合、ローカル時刻と UTC の差がずれとして現れる。

つまり、最初に出てくる時刻設定でローカル時刻ではなく UTC で入力すれば、それが UTC として書き込まれるのでずれもなくせるわけである。もちろん UI 上も UTC の時刻が表示されるし、UTC で入れる前提で作られているとは思わないが、GoPro の時計を時計として使いたいことなんてないし、対処法のひとつとしては考えられる。

ただ、個人的にはこの方法は厳しいという結論に達した。その理由は、スマホとの連携にある。Quik アプリにはスマホ側の時計を GoPro に同期させる機能が存在するし、GoPro Labs を有効にしていれば QR コードで同期させることもできる。これらの機能を使って時刻を同期すると、スマホ側のローカル時刻が GoPro に設定されてしまうため、スマホが UTC になっている場合以外ではずれが生じることになる。さすがに GoPro のためにスマホを UTC にする気はないし、同期のときだけ一時的に変更するにしても面倒。

時刻を同期しなければよいと思うかもしれないが、個人的にはそれも現実的ではないと考えた。というのも、GoPro の本体時計は他のカメラとは比べ物にならないくらい勢いよくずれていくので、こまめに修正してあげる必要がある。その作業を手動でやるのは面倒すぎる。

ここまでで、撮影時点で正しい時刻が書き込まれることは諦め、ずれた時刻を補正する方向性を検討することにした。

exiftool を使うことで、作成時刻を編集できる。以下の場合、UTC から9時間ずれている場合を補正している。

# exiftool のインストールには Windows では scoop が使えた。macOS であれば Homebrew で。

exiftool '-time:all-=9' *.mp4

変更前と比べると、もろもろの時刻が9時間ずれていることがわかる。

> exiftool -a '-time:all' .\GX010012.MP4
File Modification Date/Time     : 2021:10:31 18:50:54+09:00
File Access Date/Time           : 2021:11:03 13:46:51+09:00
File Creation Date/Time         : 2021:10:31 18:50:51+09:00
Create Date                     : 2021:10:31 14:11:06
Modify Date                     : 2021:10:31 14:11:06
Track Create Date               : 2021:10:31 14:11:06
Track Modify Date               : 2021:10:31 14:11:06
Media Create Date               : 2021:10:31 14:11:06
Media Modify Date               : 2021:10:31 14:11:06
Track Create Date               : 2021:10:31 14:11:06
Track Modify Date               : 2021:10:31 14:11:06
Media Create Date               : 2021:10:31 14:11:06
Media Modify Date               : 2021:10:31 14:11:06
Track Create Date               : 2021:10:31 14:11:06
Track Modify Date               : 2021:10:31 14:11:06
Media Create Date               : 2021:10:31 14:11:06
Media Modify Date               : 2021:10:31 14:11:06
Track Create Date               : 2021:10:31 14:11:06
Track Modify Date               : 2021:10:31 14:11:06
Media Create Date               : 2021:10:31 14:11:06
Media Modify Date               : 2021:10:31 14:11:06
> exiftool -a '-time:all' .\GX010012.MP4
File Modification Date/Time     : 2021:11:03 15:07:16+09:00
File Access Date/Time           : 2021:11:03 15:08:37+09:00
File Creation Date/Time         : 2021:11:03 13:30:36+09:00
Create Date                     : 2021:10:31 05:11:06
Modify Date                     : 2021:10:31 05:11:06
Track Create Date               : 2021:10:31 05:11:06
Track Modify Date               : 2021:10:31 05:11:06
Media Create Date               : 2021:10:31 05:11:06
Media Modify Date               : 2021:10:31 05:11:06
Track Create Date               : 2021:10:31 05:11:06
Track Modify Date               : 2021:10:31 05:11:06
Media Create Date               : 2021:10:31 05:11:06
Media Modify Date               : 2021:10:31 05:11:06
Track Create Date               : 2021:10:31 05:11:06
Track Modify Date               : 2021:10:31 05:11:06
Media Create Date               : 2021:10:31 05:11:06
Media Modify Date               : 2021:10:31 05:11:06
Track Create Date               : 2021:10:31 05:11:06
Track Modify Date               : 2021:10:31 05:11:06
Media Create Date               : 2021:10:31 05:11:06
Media Modify Date               : 2021:10:31 05:11:06

これで解決かとも思ったのだが、ffmpeg でファイルを読み込むとタイムコードに変更が反映されないことが気になった。

Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '.\GX010012.MP4':
  Metadata:
    major_brand     : mp41
    minor_version   : 538120216
    compatible_brands: mp41
    creation_time   : 2021-10-31T05:11:06.000000Z
    firmware        : H21.01.01.10.70
  Duration: 00:00:22.72, start: 0.000000, bitrate: 60125 kb/s
    Chapter #0:0: start 11.561000, end 22.723000
    Stream #0:0(eng): Video: hevc (Main) (hvc1 / 0x31637668), yuvj420p(pc, bt709), 3840x2160 [SAR 1:1 DAR 16:9], 59843 kb/s, 59.94 fps, 59.94 tbr, 60k tbn, 59.94 tbc (default)
    Metadata:
      creation_time   : 2021-10-31T05:11:06.000000Z
      handler_name    : GoPro H.265
      encoder         : GoPro H.265 encoder
      timecode        : 14:10:15:42
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp, 189 kb/s (default)
    Metadata:
      creation_time   : 2021-10-31T05:11:06.000000Z
      handler_name    : GoPro AAC
      timecode        : 14:10:15:42
    Stream #0:2(eng): Data: none (tmcd / 0x64636D74), 0 kb/s (default)
    Metadata:
      creation_time   : 2021-10-31T05:11:06.000000Z
      handler_name    : GoPro TCD
      timecode        : 14:10:15:42
    Stream #0:3(eng): Data: bin_data (gpmd / 0x646D7067), 61 kb/s (default)
    Metadata:
      creation_time   : 2021-10-31T05:11:06.000000Z
      handler_name    : GoPro MET

気にする必要はないかも知れないが、個人的には気持ち悪いと感じる。ffmpeg での書き換えも試みたものの、おそらくメタデータが入っていると思われる #0:2 や #0:3 トラックが欠落するのを回避する方法がわからなかったり、うまく再生できないファイルが出力されたり。結局、うまく行ったとして、そもそも保管するためのファイルでオリジナルに不可逆な変更を入れるのはいかがなものかという結論に至った。

最終的には、ファイルの内容はずれたまま一切変更せず、ファイル名の先頭にローカル時刻をつけることにした。他のカメラで撮影した動画にも同じルールでファイル名をつけることで、ファイル名で撮影順にソートできるようになる。通常だとカメラによってファイル名の命名規則がバラバラだったり、逆に同じメーカーのカメラを複数台使うとファイル名が重複してしまったりと、ファイル名は鬼門なのだが、先頭に時刻を付与してしまえばそのあたりの問題をすべて回避できる。

> exiftool '-FileName<CreateDate' -d '%Y%m%d-%H%M%S-%%f.%%e' -api QuickTimeUTC -GlobalTimeShift -9 *.mp4

例えば GX010012.MP4 をリネームすると、20211031-141106-GX010012.MP4 のように先頭に時刻 (作業している PC のローカル時刻) が付与される。フォーマットは -d オプションで調整できる。

時刻が UTC で正しく書き込まれている他のメーカーのカメラの場合、-GlobalTimeShift -9 は不要で以下のようになる。

> exiftool '-FileName<CreateDate' -d '%Y%m%d-%H%M%S-%%f.%%e' -api QuickTimeUTC  *.mp4

念のためリネーム前後のファイルのハッシュ値を比較したところ一致していたため、意図せずファイルの内容が書き換わるといったことは起きていないはず。

# Google フォトなどのメタデータベースのシステムにインポートすると、ファイル名ではなくメタデータが参照されてずれが見えてしまうが、そこについては手動で直すことにした。ファイルを完全な状態で残すこととのトレードオフなので、どちらを取るかは人によると思う。

この方法は、副次的なメリットとしてファイル分割されたときの並び順もわかりやすくしてくれる。

例えば、以下のような8つのファイルがあるとする。

GX010308.MP4
GX010309.MP4
GX020308.MP4
GX020309.MP4
GX030308.MP4
GX030309.MP4
GX040308.MP4
GX040309.MP4

これは2回の動画撮影で作成されたファイル群である。末尾の4桁の数字が撮影ごとに変化する数字で、先頭の2桁がファイルサイズが 4GB に達して分割されるごとに増える数字である。つまり、末尾が 0308 のものを先頭の数字で 01, 02, 03, 04 と繋ぎ合わせると1回の撮影結果になり、末尾が 0309 のものも同様なのだが、ファイル名で並び変えるとぐちゃぐちゃになってしまう。

このようなファイルもリネームすると以下のようになり、きれいに撮影ごとに連続して並んでくれる。

20200101-132930-GX010308.MP4
20200101-133620-GX020308.MP4
20200101-134309-GX030308.MP4
20200101-134958-GX040308.MP4
20200101-142937-GX010309.MP4
20200101-143627-GX020309.MP4
20200101-144317-GX030309.MP4
20200101-145006-GX040309.MP4

PowerShell のスクリプトは以下の通り。ファイル名を見て、GoPro の動画なら9時間ずらし、そうでなければそのままの時刻でリネームするようにしている。

https://gist.github.com/mono0x/6ac8af8f4e6b57e601d0b8ac19141e12

これを書いていて、なんで GoPro なんか使っているんだろうという気持ちにもなったが、撮影結果のクオリティは高いと思っているし、競合も消えていっている中でなかなか他に乗り換えるわけにもいかず。少しでも快適に使えるようにして付き合っていきたい。