Menu

【Perl編】DVD(VRモード)の録画情報抽出

【はじめに】
デジタル放送の番組をDVDに録画するとき、ディスクはVRモードで初期化されます。そのディスクに保存した番組のタイトル情報はVR_MANGR.IFOというファイル内に記録されていま す。この情報をパソコンで抽出して、タブ区切りのテキストデータとして出力しデータベース化するのが、このソフトの機能です。
DVDをドライブに入れ、パソコンに認識されたら、このソフトのアイコンをクリックすれば、数秒でタイトル情報がdvdvr.txtに書き出されます。DVDを入れ替えてこの作業を繰り返せば、データが蓄積されてデータベースとして活用できます。
下の画像は出来上ったdvdvr.txtをメモ帳で開いた例です。



データベースを構築するときの課題は、(1)データの入力 (2)データと実物の紐付け の2つです。このうち(1)はこのソフトで対応できます。
(2)は管理番号を設定して、データと実物にこの番号を付け、実物を管理番号順に並べることによって解決できます。
このソフトでは、管理番号を1番目のデータの「録画年月日+半角スペース+タイトル名の頭10バイト」として、自動的に付加しています。
1行目は管理番号のみ、2行目からが録画データです。項目はタブで区切られており、Excelでも読み込めます。
  第1項目:管理番号
  第2項目:録画日(年/月/日)
  第3項目:長さ(時:分:秒)
  第4項目:放送局名
  第5項目:タイトル名(最大64バイト)

【環境】
OS:Windows
プログラム言語:Perl
対象DVD:VRモード(未ファイナライズDVDでも読み取り可。ビデオ・モードのDVDには対応していない)

【手順】
(1) Perlをインストールしていない人は、まずウェブから探してきてインストールする。たとえば以下のサイトからダウンロードできる(無料)。
http://www.activestate.com/activeperl/downloads
(2) メモ帳やテキスト・エディタで新しいテキスト・ファイルを作り、このページの # dvdvr.pl 以下をコピー&ペーストで貼り付ける。
(3) プログラム2行目の「H:」を自分のパソコンのDVDドライブのものに書き換える。
(4) このテキスト・ファイルを保存して閉じてから、ファイル名を dvdvr.pl に変える。警告メッセージ「拡張子を変更すると、ファイルが使えなくなる可能性があります。変更しますか?」が出るので「はい」をクリックする。Perlのアイコンに変わる。
(5) ドライブにDVDを挿入し、このアイコンをダブルクリックする。コマンドプロンプトの黒い窓が一瞬現れて消えたらDVDを取り出す。
(6) 出来た dvdvr.txt を開いて、データが書き込まれたことを確認する(書き込まれていなかったらビデオ・モードDVDの可能性がある)。
(7) 上記(5)を繰り返してデータを蓄積する。DVDは管理番号のラベルを貼るまで順序を変えないこと。

【利用法】
(1) 管理番号をシール(1cm×5cm程度)に印刷して、DVDケースに貼ったのち、管理番号順に並べます。
シール印刷のために管理番号だけを抽出するのは、バッチファイルで簡単にできます。たとえば次のような内容のテキスト・ファイルを作成し、拡張子をtxt からbatに変えて実行します(dvdvr.txtから管理番号で使っていない半角のコロン”:”がある行を除外してlabel.txtに出力します)。
  find /V ":" dvdvr.txt > label.txt
(2) dvdvr.txtをExcelで開いてみます。Excelの「開く」でファイル名の種類を「テキストファイル」に変え、dvdvr.txtを選んで開きます。各項目ごとにセルに分かれて表示されます。セル幅は適当に変更します。
(3) 検索をクリックすると検索窓が開くので、検索する文字列を入力し、「すべて検索」をクリックします。検索結果が検索窓の下に表示されるので、そのうちのひとつをクリックすると、表中の該当行にカーソルが飛びます。管理番号を見て、目的のDVDを探し出します。

【参考にしたサイト】
IFOファイルの構造は、下記サイトの情報を参考にさせていただきました。感謝します。
<メモwiki(主にコンピュータ関連)「DVD-RAMのIFOファイル」>
https://www28.atwiki.jp/jennychan/pages/19.html


【プログラム本体】

# dvdvr.pl
open(DISC, "< H:/DVD_RTAV/VR_MANGR.IFO")|| die "Can't open DVD\n";
open(TEXT, "+>> dvdvr.txt");
binmode DISC;
#date
seek(DISC, 0x0100, 0);
read(DISC, $entry, 4);
$top=unpack("N", $entry);
seek(DISC, $top+3, 0);
read(DISC, $b, 1);
$blk=unpack("C", $b);
$end=$top+60*$blk+10;
seek(DISC, $end-2, 0);
read(DISC, $c, 2);
$n=unpack("n", $c);
#tv
seek(DISC, 0x0160, 0);
read(DISC, $entry, 4);
$t=unpack("N", $entry);
$tv=$t+$n*4+8;
#title
seek(DISC, 0x0130, 0);
read(DISC, $entry, 4);
$a=unpack("N", $entry);
$pointer=$a+4;
for($i=1; $i<=$n; $i++) {
    #date
    $p=$end+4*($i-1);
    seek(DISC, $p, 0);
    read(DISC, $q, 4);
    $r=unpack("N", $q);
    seek(DISC, $top+$r+2, 0);
    read(DISC, $date, 5);
    @d=unpack("C5",$date);
    $yy=$d[0]*64+int($d[1]/4);
    $mm=$d[1]%4*4+int($d[2]/64);
    $dd=int($d[2]%64/2);
    $ymd=sprintf("%4d/%02d/%02d", $yy, $mm, $dd);
    #time
    seek(DISC, $top+$r+9, 0);
    read(DISC, $time, 12);
    @t=unpack("NnNn", $time);
    $tt=int(($t[2]-$t[0])/90000);
    $ss=$tt%60;
    $m=int($tt/60);
    $mn=$m%60;
    $hh=int($m/60);
    $hms=sprintf("%02d:%02d:%02d", $hh, $mn, $ss);
    #tv
    seek(DISC, $tv+1, 0);
    read(DISC, $l, 1);
    $ll=unpack("C", $l);
    seek(DISC, $tv+2, 0);
    read(DISC, $bc, $ll);
    $tv+=$ll+2;
    #title
    $p=$pointer+142*($i-1);
    seek(DISC, $p+68, 0);
    read(DISC, $title, 64);
    $title =~ s/\0*$//;
    #output
    if ($i == 1) {
    $head = $ymd." ".substr($title, 0, 10);
    print TEXT $head."\n";
    }
    $, = "\t";
    print TEXT $head, $ymd, $hms, $bc, $title."\n";
}
close(TEXT);
close(DISC);