fumiLab

fumiが作ったもの、やったことについて書いていきます。

miniDVテープの取り込み時に日時がおかしくなる問題を修正する

miniDVテープをデジタル化するときに日付データがなくてGoogle Photoなどのサービスにアップすると大昔のデータなのに2025年と表示されてしまい、困ったのでツールを作りました。(とは言っても半分くらいAIが作ってくれました)

ダビングの仕方

これは以前書いたのでこちらをご覧ください。

fumimaker.net

戦略

mediainfoで見ると以下のようになっています。

Format                                   : AVI
Format/Info                              : Audio Video Interleave
Commercial name                          : DVCPRO
Format settings                          : BitmapInfoHeader / WaveFormatEx
File size                                : 1.34 GiB
Duration                                 : 6 min 25 s
Overall bit rate mode                    : Constant
Overall bit rate                         : 29.8 Mb/s
Frame rate                               : 29.970 FPS
Recorded date                            : 2001-05-01 11:07:52.000

Video
ID                                       : 0
Format                                   : DV
Commercial name                          : DVCPRO
Codec ID                                 : dvsd
Codec ID/Hint                            : Sony
Duration                                 : 6 min 25 s
Bit rate mode                            : Constant
Bit rate                                 : 24.4 Mb/s
Width                                    : 720 pixels
Height                                   : 480 pixels
Display aspect ratio                     : 4:3
Frame rate mode                          : Constant
Frame rate                               : 29.970 (30000/1001) FPS
Original frame rate                      : 29.970 (29970/1000) FPS
Standard                                 : NTSC
Color space                              : YUV
Chroma subsampling                       : 4:1:1
Bit depth                                : 8 bits
Scan type                                : Interlaced
Scan order                               : Bottom Field First
Compression mode                         : Lossy
Bits/(Pixel*Frame)                       : 2.357
Time code of first frame                 : 00:58:39;07
Time code source                         : Subcode time code
Stream size                              : 1.29 GiB (97%)
Encoding settings                        : ae mode=full automatic / wb mode=automatic / white balance= / fcm=manual focus

Audio
ID                                       : 1
Format                                   : PCM
Format settings                          : Little / Signed
Codec ID                                 : 1
Duration                                 : 6 min 25 s
Bit rate mode                            : Constant
Bit rate                                 : 1 024 kb/s
Channel(s)                               : 2 channels
Sampling rate                            : 32.0 kHz
Bit depth                                : 16 bits
Stream size                              : 47.1 MiB (3%)
Alignment                                : Aligned on interleaves
Interleave, duration                     : 33  ms (1.00 video frame)

DV形式、DVCPROというもののようです。 Recoded Dateというのがありますね!これがなかったら詰んでましたがあったので助かりました。これを使ってサービスが撮影日時を認識できるようにします。詳しいコンテナの実装はこの辺にありそうです。

www.videoalpha.jp

手順としては以下です。

  • AVI動画
  • ファイル名を日時に変更するrename.pyを実行(必要な人向け)
  • AVI動画を任意のツールで圧縮エンコード
  • mp4のexifに撮影日時として書き込むserch_and_setExif.py を実行

AVIコンテナはEXIFが存在しないので現代的なmp4コンテナに収めるときにどうしよう問題があります。なので、一度AVI→日付付きAVI→mp4エンコードEXIF付きmp4としました。

なお、一度日付付きAVIとしてる理由はわかりやすいからです。別に、AVI→mp4エンコードEXIF書き込みとしても問題ないです。一応AVIファイルもアーカイブ用のHDDに保存しておきたかったのでこうしてます。

注意

大事な動画データですので、スクリプトを実行する前に動作に問題がないか、確かめてから本番を実行してください。必ず、先にコピーしてテストディレクトリで実行してください。

筆者はいかなる損失に対しても責任を負いません。

動作確認済みの環境

  • MacOS LinuxももちろんOKです。Windowsは...WSLを使うのが最も簡単な手段かもしれないです。PS版も需要があれば作ります。 subprocessなので、パスだけ直せばWindowsでも動くはずです...動作は未確認。
  • Python 3.10.12 なんでも動くと思います。
  • exiftool
  • mediainfo

ファイル名を日時に変更する

mediainfoをインストールしてください。コマンドから使うのでCLI版が必要です。デスクチップ版も便利なので入れて損ないです。

mediaarea.net

使い方

スクリプトGitHubにあります。

github.com

python rename.py "/path/to/your/video"/dir

ディレクトリを動画が置いてあるところにしてください。今回は同じディレクトリに置いてます。

-rwx------@ 1 fumi  staff   369060664  1  2 16:55 2001-05-01-103426.avi
-rwx------@ 1 fumi  staff   218615516  1  2 16:55 2001-05-01-103656.avi
-rwx------@ 1 fumi  staff   439185504  1  2 16:55 2001-05-01-104506.avi
-rwx------@ 1 fumi  staff  1438340196  1  2 16:55 2001-05-01-110752.avi
-rwx------@ 1 fumi  staff   348545416  1  2 16:55 2001-05-01-112422.avi
-rw-r--r--@ 1 fumi  staff        1675  1  4 00:44 rename.py
-rw-r--r--@ 1 fumi  staff        2393  1  3 02:08 serch_and_setExif.py

ちゃんと日時がaviファイルに入ってれば同一ディレクトリのaviファイルを探してmediainfoのrecoded dateにファイル名を変更してくれます。

> python rename.py    /your/path/                                                              ✔  at 00:28:19Renamed: 20250102200831.avi -> 2000-05-11-081019.avi
Renamed: 20250103201621.avi -> 1998-12-10-112504.avi
Renamed: 20250102215541.avi -> 1999-09-06-172403.avi
Renamed: 20250103142213.avi -> 1999-05-05-184932.avi
Renamed: 20250102233753.avi -> 1999-03-11-215045.avi
Renamed: 20250102182444.avi -> 1999-08-15-142603.avi
Renamed: 20250102175027.avi -> 1999-08-17-210528.avi
Renamed: 20250102155526.avi -> 2001-02-12-171835.avi
Renamed: 20250102183606.avi -> 1999-08-15-145835.avi
Renamed: 20250102163902.avi -> 2001-05-01-103656.avi
Renamed: 20250103130054.avi -> 1999-04-30-153925.avi

mp4のexifに撮影日時として書き込む

serch_and_setExif.pyを使って同一ファイル名のAVI動画とmp4動画を探して、mediainfoで抽出したrecoded dateをexiftoolを使って書き込みます。mp4コンテナであればいいのでavc(h.264)でもheif(h.265)でも構いません。 Exiftoolが入ってる必要があります。ここから入れてください。 exiftool.org

python serch_and_setExif.py "/path/to/your/video" これのディレクトリを動画が置いてあるところにしてください。今回は同じディレクトリに置いてます。 実行できるとこのようになります。

> python serch_and_setExif.py                                                          
    1 image files updated
Metadata written to ./1998-12-31-152525.mp4
    1 image files updated
Metadata written to ./1998-12-31-171935.mp4
    1 image files updated
Metadata written to ./1998-12-30-215320.mp4
    1 image files updated
Metadata written to ./1998-12-30-194932.mp4

確認するとちゃんとCreateDateなどが修正されてると思います。認識されるか、GooglePhotosに突っ込んで確認してみてください。

exiftool -j './avi_files/test/1998-12-30-194932.mp4'
[{
  "SourceFile": "./avi_files/test/1998-12-30-194932.mp4",
  "ExifToolVersion": 13.11,
  "FileName": "1998-12-30-194932.mp4",
  "Directory": "./avi_files/test",
  "FileSize": "232 MB",
  "FileModifyDate": "2025:01:04 00:52:43+09:00",
  "FileAccessDate": "2025:01:04 00:52:43+09:00",
  "FileInodeChangeDate": "2025:01:04 00:52:43+09:00",
  "FilePermissions": "-rw-r--r--",
  "FileType": "MP4",
  "FileTypeExtension": "mp4",
  "MIMEType": "video/mp4",
  "MajorBrand": "MP4 v2 [ISO 14496-14]",
  "MinorVersion": "0.0.0",
  "CompatibleBrands": ["mp42","mp41"],
  "MovieHeaderVersion": 0,
  "TimeScale": 90000,
  "Duration": "0:03:01",
  "PreferredRate": 1,
  "PreferredVolume": "100.00%",
  "PreviewTime": "0 s",
  "PreviewDuration": "0 s",
  "PosterTime": "0 s",
  "SelectionTime": "0 s",
  "SelectionDuration": "0 s",
  "CurrentTime": "0 s",
  "NextTrackID": 3,
  "TrackHeaderVersion": 0,
  "TrackCreateDate": "2025:01:02 16:28:01",
  "TrackModifyDate": "2025:01:02 16:28:01",
  "TrackID": 2,
  "TrackDuration": "0:03:01",
  "TrackLayer": 0,
  "TrackVolume": "100.00%",
  "Balance": 0,
  "AudioFormat": "mp4a",
  "AudioChannels": 2,
  "AudioBitsPerSample": 16,
  "MatrixStructure": "1 0 0 0 1 0 0 0 1",
  "ImageWidth": 654,
  "ImageHeight": 480,
  "MediaHeaderVersion": 0,
  "MediaCreateDate": "1998:12:30 10:49:32",
  "MediaModifyDate": "1998:12:30 10:49:32",
  "MediaTimeScale": 30000,
  "MediaDuration": "0:03:01",
  "MediaLanguageCode": "eng",
  "GraphicsMode": "srcCopy",
  "OpColor": "0 0 0",
  "HandlerType": "Alias Data",
  "HandlerDescription": "Alias Data Handler",
  "CompressorID": "avc1",
  "SourceImageWidth": 720,
  "SourceImageHeight": 480,
  "XResolution": 72,
  "YResolution": 72,
  "CompressorName": "AVC Coding",
  "BitDepth": 24,
  "StartTimecode": "00;01;29;04",
  "XMPToolkit": "Image::ExifTool 13.11",
  "Format": "H.264",
  "Orientation": "Horizontal (normal)",
  "CreateDate": "1998:12:30 10:49:32",
  "MetadataDate": "2025:01:03 01:28:26+09:00",
  "ModifyDate": "1998:12:30 10:49:32",
  
---省略
}

動画が存在しないと以下のようになります。

> python serch_and_setExif.py   "your/path/"                                                                 ✔  took 12s   at 00:28:36  
MP4 file not found for ./1999-08-09-095536.avi
MP4 file not found for ./1999-03-14-105041.avi
MP4 file not found for ./1999-03-20-220908.avi

(余談)エンコード

今回はAdobe Media Encoderを使ってAVI(DVCPRO)をmp4(h.265)にVBR 8Mbpsでエンコードしました。ファイルサイズは大体1/2—1/6くらいになってるようです。解像度も低いのでもっと絞れると思いますが、意外とブロックノイズが見えるのでこれくらいにしておきました。

Adobe使ってない人はXmediaEncoderとかでいけると思います。

-rw-r--r--@ 1 fumi  staff    56584759  1  3 17:40 2003-09-23-113903.mp4
-rwx------@ 1 fumi  staff  1299582516 12 31 15:24 2003-09-23-114153.avi
-rw-r--r--@ 1 fumi  staff   332879571  1  3 17:41 2003-09-23-114153.mp4
-rwx------@ 1 fumi  staff   188029152 12 31 15:24 2003-09-23-120615.avi
-rw-r--r--@ 1 fumi  staff    45623023  1  3 17:40 2003-09-23-120615.mp4
-rwx------@ 1 fumi  staff   476610280 12 31 15:24 2003-09-23-125425.avi
-rw-r--r--@ 1 fumi  staff   120132999  1  3 17:40 2003-09-23-125425.mp4
-rwx------@ 1 fumi  staff  2560532688 12 31 15:24 2003-09-23-131705.avi
-rw-r--r--@ 1 fumi  staff   657000369  1  3 17:41 2003-09-23-131705.mp4
-rw-r--r--@ 1 fumi  staff        1684  1  3 00:31 rename.py
-rw-r--r--@ 1 fumi  staff        2393  1  3 02:08 serch_and_setExif.py

ffmpegでカッコよく実行したかったのですがAVIファイルが破損してるとのエラーが出てしまい、諦めました。修復オプションや保存し直しも試したのですがダメでした。残念。

ffmpeg -i 2002-11-29-112655.avi -c:v hevc_videotoolbox -b:v 6M output.mp4 -codec copy
ffmpeg version 7.1 Copyright (c) 2000-2024 the FFmpeg developers
  built with Apple clang version 16.0.0 (clang-1600.0.26.4)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1_3 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.100 / 61. 19.100
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Trailing option(s) found in the command: may be ignored.
[avi @ 0x12b62c6f0] ODML index invalid
    Last message repeated 1 times
[aist#0:1/pcm_s16le @ 0x12b62d480] Guessed Channel Layout: stereo
Input #0, avi, from '2002-11-29-112655.avi':
  Duration: 00:18:53.73, start: 0.000000, bitrate: 29799 kb/s
  Stream #0:0: Video: dvvideo (dvsd / 0x64737664), yuv411p, 720x480 [SAR 8:9 DAR 4:3], 28771 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn
  Stream #0:1: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 32000 Hz, stereo, s16, 1024 kb/s
File 'output.mp4' already exists. Overwrite? [y/N] y
Stream mapping:
  Stream #0:0 -> #0:0 (dvvideo (native) -> hevc (hevc_videotoolbox))
  Stream #0:1 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mp4, to 'output.mp4':
  Metadata:
    encoder         : Lavf61.7.100
  Stream #0:0: Video: hevc (hev1 / 0x31766568), yuv420p(tv, bottom coded first (swapped)), 720x480 [SAR 8:9 DAR 4:3], q=2-31, 6000 kb/s, 29.97 fps, 30k tbn
      Metadata:
        encoder         : Lavc61.19.100 hevc_videotoolbox
  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 32000 Hz, stereo, fltp, 128 kb/s
      Metadata:
        encoder         : Lavc61.19.100 aac
[dvvideo @ 0x12b632cc0] Concealing bitstream errors:00:07.60 bitrate=6064.7kbits/s speed=15.2x    
    Last message repeated 20 times
[dvvideo @ 0x12b633290] Concealing bitstream errors
    Last message repeated 14 times
[dvvideo @ 0x12b633860] Concealing bitstream errors:01:09.66 bitrate=6140.7kbits/s speed=23.1x    
    Last message repeated 12 times
[dvvideo @ 0x12b634400] Concealing bitstream errors:02:36.32 bitrate=6144.3kbits/s speed=23.9x    
    Last message repeated 34 times
[dvvideo @ 0x12b633e30] Concealing bitstream errors:04:15.62 bitrate=6144.9kbits/s speed=24.2x    
    Last message repeated 11 times
[dvvideo @ 0x12b633e30] Concealing bitstream errors:06:32.22 bitrate=6138.1kbits/s speed=24.3x    
    Last message repeated 10 times
[dvvideo @ 0x12b6326f0] Concealing bitstream errors:14:06.87 bitrate=6141.3kbits/s speed=24.3x    
    Last message repeated 14 times
[dvvideo @ 0x12b634400] Concealing bitstream errors
    Last message repeated 134 times
[out#0/mp4 @ 0x12b62d6a0] video:832133KiB audio:17634KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.068265%
frame=33978 fps=730 q=-0.0 Lsize=  850347KiB time=00:18:45.66 bitrate=6188.4kbits/s speed=24.2x    
[aac @ 0x12b635a40] Qavg: 757.993
ffmpeg -i 2002-11-29-112655.avi -c:v hevc_videotoolbox -b:v 6M output.mp4 -codec copy
ffmpeg version 7.1 Copyright (c) 2000-2024 the FFmpeg developers
  built with Apple clang version 16.0.0 (clang-1600.0.26.4)
  configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1_3 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
  libavutil      59. 39.100 / 59. 39.100
  libavcodec     61. 19.100 / 61. 19.100
  libavformat    61.  7.100 / 61.  7.100
  libavdevice    61.  3.100 / 61.  3.100
  libavfilter    10.  4.100 / 10.  4.100
  libswscale      8.  3.100 /  8.  3.100
  libswresample   5.  3.100 /  5.  3.100
  libpostproc    58.  3.100 / 58.  3.100
Trailing option(s) found in the command: may be ignored.
[avi @ 0x12b62c6f0] ODML index invalid
    Last message repeated 1 times
[aist#0:1/pcm_s16le @ 0x12b62d480] Guessed Channel Layout: stereo
Input #0, avi, from '2002-11-29-112655.avi':
  Duration: 00:18:53.73, start: 0.000000, bitrate: 29799 kb/s
  Stream #0:0: Video: dvvideo (dvsd / 0x64737664), yuv411p, 720x480 [SAR 8:9 DAR 4:3], 28771 kb/s, 29.97 fps, 29.97 tbr, 29.97 tbn
  Stream #0:1: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 32000 Hz, stereo, s16, 1024 kb/s
File 'output.mp4' already exists. Overwrite? [y/N] y
Stream mapping:
  Stream #0:0 -> #0:0 (dvvideo (native) -> hevc (hevc_videotoolbox))
  Stream #0:1 -> #0:1 (pcm_s16le (native) -> aac (native))
Press [q] to stop, [?] for help
Output #0, mp4, to 'output.mp4':
  Metadata:
    encoder         : Lavf61.7.100
  Stream #0:0: Video: hevc (hev1 / 0x31766568), yuv420p(tv, bottom coded first (swapped)), 720x480 [SAR 8:9 DAR 4:3], q=2-31, 6000 kb/s, 29.97 fps, 30k tbn
      Metadata:
        encoder         : Lavc61.19.100 hevc_videotoolbox
  Stream #0:1: Audio: aac (LC) (mp4a / 0x6134706D), 32000 Hz, stereo, fltp, 128 kb/s
      Metadata:
        encoder         : Lavc61.19.100 aac
[dvvideo @ 0x12b632cc0] Concealing bitstream errors:00:07.60 bitrate=6064.7kbits/s speed=15.2x    
    Last message repeated 20 times
[dvvideo @ 0x12b633290] Concealing bitstream errors
    Last message repeated 14 times
[dvvideo @ 0x12b633860] Concealing bitstream errors:01:09.66 bitrate=6140.7kbits/s speed=23.1x    
    Last message repeated 12 times
[dvvideo @ 0x12b634400] Concealing bitstream errors:02:36.32 bitrate=6144.3kbits/s speed=23.9x    
    Last message repeated 34 times
[dvvideo @ 0x12b633e30] Concealing bitstream errors:04:15.62 bitrate=6144.9kbits/s speed=24.2x    
    Last message repeated 11 times
[dvvideo @ 0x12b633e30] Concealing bitstream errors:06:32.22 bitrate=6138.1kbits/s speed=24.3x    
    Last message repeated 10 times
[dvvideo @ 0x12b6326f0] Concealing bitstream errors:14:06.87 bitrate=6141.3kbits/s speed=24.3x    
    Last message repeated 14 times
[dvvideo @ 0x12b634400] Concealing bitstream errors
    Last message repeated 134 times
[out#0/mp4 @ 0x12b62d6a0] video:832133KiB audio:17634KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.068265%
frame=33978 fps=730 q=-0.0 Lsize=  850347KiB time=00:18:45.66 bitrate=6188.4kbits/s speed=24.2x    
[aac @ 0x12b635a40] Qavg: 757.993

なぜかWindowsのMedia Encoderだけうまくいきました。MacのMedia encoderはそもそも非対応っぽいです。OS標準のエンコーダもありますが、非対応でした。

avconvert:  invalid configuration (preset name Preset640x480) with file:///Users/fumi/2001-04-15-113339.avi    Presets compatible with file:///Users/fumi/2001-04-15-113339.avi:        Preset640x480        Preset960x540        Preset1280x720        Preset1920x1080        Preset3840x2160        PresetAppleM4A        PresetAppleM4V480pSD        PresetAppleM4V720pHD        PresetAppleM4V1080pHD        PresetAppleM4VAppleTV        PresetAppleM4VCellular        PresetAppleM4ViPod        PresetAppleM4VWiFi        PresetAppleProRes422LPCM        PresetAppleProRes4444LPCM        PresetHEVC1920x1080        PresetHEVC3840x2160        PresetHEVC7680x4320        PresetHEVCHighestQuality        PresetHighestQuality        PresetLowQuality        PresetMediumQuality