PanasonicデジタルビデオカメラのビデオファイルをMacにバックアップ

前置き

数ヶ月前にPanasonicデジタルビデオカメラ W570M というやつを購入した。
ビデオカメラ自体はワイプ撮影機能があってなかなか楽しいんだけど、バックアップというかアーカイブというか、PCへの取り込みがどうもいまく行かないんだよね。

標準取り込みソフトとして、Windows用の「HD Writer LE 3.0」というソフトが付いてくるんだけど、ウチの環境(Mac mini El Capitan に VMware FusionWindows 10 環境)では、どうもうまく取り込んでくれない。取り込もうとしてもデバイスを認識してくれないんだよね。以前、Yosemite のときだったかWindows 8.1 のときだったかは、ちゃんとデバイス認識して取り込めてたのだけど。

じゃあ iMovie で取り込めば良いかというと、ファイルサイズがでかくなりすぎるのでアーカイブ用途としては不適切。やっぱり日付フォルダ配下のデータファイルとして保存しておきたい。が、公式ソフトのアップデートを待ってても、そもそも仮想環境はサポート対象外だったりするので全然ダメっぽい。

というわけで、Macでm2tsファイルをバックアップするRubyスクリプトを作った。

概要

公式では m2ts の他にメタデータファイルっぽいものもセットで作っていたが、実際必要なのは m2ts だけだろうということで、m2ts のみ取り込み。最近は m2ts のままでも iMovie で編集できるし、QuickTimeで再生もできるので、わざわざフォーマット変換しない。

基本的にカメラ内で m2ts ファイルを作っているのでそのままコピーすれば良いんだけど、ファイル名を撮影開始日時にしたい&日付フォルダ配下に置きたいのでスクリプトにしてある。カメラ内のファイル名はただの連番だからね。

実は m2ts 内には撮影開始日時は無いようなので、「撮影終了日時 - 撮影時間」で撮影開始日時を算出している。

準備

m2ts ファイルのメタデータを取るために、mediainfo の CLI 版を利用しているので、事前に以下をインストールしておく必要がある。
http://mediaarea.net/download/binary/mediainfo/0.7.80/MediaInfo_CLI_0.7.80_Mac.dmg

使い方

1. カメラをUSB接続してマウント
2. スクリプト実行
→ 指定ディレクトリ配下に、撮影開始日時から YYYY-MM-DD/YYYY-MM-DD_hhmmss.m2ts としてコピー。
※ 既に同名同サイズのファイルが存在している場合はコピーしない。取り込み済みのため。
3. 必要に応じてNASなどに更にバックアップ

Rubyスクリプト
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-

require 'open3'
require 'fileutils'
require 'time'

# mediainfoコマンド名
MEDIAINFO = 'mediainfo'

@local_backup_root = '/Users/craftone/Movies/PanaW570M'
@stream_folder = '/Volumes/CAM_MEM/AVCHD/BDMV/STREAM'
@stream_file_glob = @stream_folder + '/*.MTS'


# check video files
files = Dir.glob(@stream_file_glob)
if files.size == 0
  puts "ファイルがありません。カメラがマウントされていない可能性があります。"
  exit 1
end

# check mediainfo command
o, e, s = Open3.capture3("which #{MEDIAINFO}")
unless s == 0
  puts "必須コマンド #{MEDIAINFO} がインストールされていないか、パスが通っていません。"
  exit 1
end

FileUtils.mkdir_p(@local_backup_root)
unless File.directory?(@local_backup_root)
  puts "ローカルバックアップディレクトリが作成できませんでした。"
  exit 1
end

files.each do |f|
  print f + " "
  o, e, s = Open3.capture3("#{MEDIAINFO} -F #{f}")
  infos = o.split("\n")
  #puts infos.join("\n")
  mtime_line = infos.find{|item| item.start_with?("File last modification date (local)")}
  duration_line = infos.find{|item| item =~ /^Duration.*\d\d:\d\d:\d\d\.\d\d\d$/}
  mtime = Time.parse(mtime_line[-19,19])

  # "Duration : 12:23:34.000" -> [12,23,34]
  dr = duration_line[0..-4].split(':')[1..3].map(&:to_i)
  dr_sec = dr[0] * 3600 + dr[1] * 60 + dr[2]
  stime = mtime - dr_sec

  dst_dir_name = stime.strftime('%Y-%m-%d')
  dst_dir_path = [@local_backup_root, dst_dir_name].join('/')
  FileUtils.mkdir_p(dst_dir_path)

  dst_file_name = dst_dir_name + "_" + stime.strftime('%H%M%S.m2ts')
  dst_path = [@local_backup_root, dst_dir_name, dst_file_name].join('/')


  if File.exists?(dst_path) and File.size(dst_path) == File.size(f)
    puts "is already copied to #{dst_path}."
  else
    print "is being copied to #{dst_path} ... "
    FileUtils.cp_r(f, dst_path, remove_destination: true)
    if File.size(dst_path) == File.size(f)
      puts "done."
    else
      puts "CHECK ERROR!! Please retry backup!"
    end
  end
end