VFRなmp4の作り方(2)

24fpsと30fpsが混合したmp4を作る自分的手順(自動化編)

mp4boxを利用すると、nhmlというmkvのtimecodeファイルと同じようなものを扱うことが出来る。
このnhmlファイルを上手く使って、面倒な分割作業なしにVFRなmp4を作る手順を考えてみた。

 DGDecode_mpeg2source("vfr.d2v")
 tfm(d2v="vfr.d2v")
 tdecimate(mode=3,hybrid=2,vfrDec=1,mkvOut="vfr-timecode.txt",tcfv1=false)
  • x264でvfr.avsをエンコードし、mp4形式で出力する。
  • mp4boxでvfr.mp4からnhmlファイルを抽出する。
 mp4box -nhml 1 vfr.mp4
  • nhmlファイル内のタイムスタンプをtimecodeファイルにあわせて修正。
 (とあるツール) vfr-timecode.txt vfr_track1.nhml > vfr_track1_tc.nhml
  • 修正済のnhmlファイルと音声ファイルから、mp4boxを使ってmp4を合成。
 mp4box -add vfr_track1_tc.nhml -add vfr.aac -new vfr.mp4

これで"vfr.mp4"が24fps/30fps混合のVFRなmp4になる。

とあるツール*1 *2(とりあえず動けばいいやスクリプト

#!/usr/bin/perl
# url - http://d.hatena.ne.jp/zmi/

$SEARCH_MAX = 6;

$tc = $ARGV[0];
$nhml = $ARGV[1];

open TC, $tc or die;
open NHML, $nhml or die;

# parse timecode file
while(<TC>){
    next if /^\#/;
    next unless /^([.\d]+)/;
    push tc, int($1 * 1000 + 0.5);
}
close TC;
$tcCount = @tc;

# parse nhml file
while(<NHML>){
    next unless	/<NHNTSample DTS="(\d+)".*?\/>/;
    push dtsList, $1;
}
seek(NHML, 0, 0);

# convert nhml
$frame = 0;
while(<NHML>){
    if(/<NHNTStream.*?>/){
	s/timeScale="\d+"/timeScale="1000000"/;
	print;
	next;
    }
    (print, next) unless
	   /<NHNTSample DTS="(\d+)" dataLength="(\d+)" CTSOffset="(\d+)"( isRAP="yes") \/>/
	or /<NHNTSample DTS="(\d+)" dataLength="(\d+)" CTSOffset="(\d+)" \/>/
	or /<NHNTSample DTS="(\d+)" dataLength="(\d+)" \/>/;
    
    next unless $frame < $tcCount;
	
    $dts = $1;
    $dataLength = $2;
    $ctsOffset = ($3 or 0);
    $isRap = $4;

    # convert timecode to dts/cts
    $cts = $dts + $ctsOffset;
    for($cnt = $frame; $cnt < ($frame + $SEARCH_MAX); $cnt++){
	if(abs($dtsList[$cnt] - $cts) <= 1){
	    $newCts = $tc[$cnt];
	    last;
	}
    }
    $newDts = $tc[$frame];
    if(($cnt == $frame + $SEARCH_MAX) or ($cnt >= $tcCount)){
	$newCtsOffset = ($tc[$frame] - $tc[$frame -1])
	    * int(($ctsOffset / ($dtsList[$frame] - $dtsList[$frame -1])) + 0.5);
    }else{
	$newCtsOffset = $newCts - $newDts;
    }
    
    print "<NHNTSample DTS=\"$newDts\" dataLength=\"$dataLength\" CTSOffset=\"$newCtsOffset\"$isRap />\n";
    $frame++;
}
close NHML;

*1:timecode format v2にしか対応していません

*2:exe版も作ったけど欲しい人いますかね?