--- mp4.c Thu Dec 3 17:33:39 2009+++ mp4_vfr.c Sun Nov 15 15:11:46 2009@@ -124,9 +124,10 @@ static int open_file( char *psz_filename, hnd_t *p_handle ) { mp4_hnd_t *p_mp4;+ FILE *fh; *p_handle = NULL;- FILE *fh = fopen( psz_filename, "w" );+ fh = fopen( psz_filename, "w" ); if( !fh ) return -1; else if( !x264_is_regular_file( fh ) )@@ -265,16 +266,101 @@ return i_size; }+//static int set_eop( hnd_t handle, x264_picture_t *p_picture )+//{+// mp4_hnd_t *p_mp4 = handle;+// uint64_t dts = (uint64_t)p_mp4->i_numframe * p_mp4->i_time_inc;+// uint64_t pts = (uint64_t)p_picture->i_pts;+// int32_t offset = p_mp4->i_init_delay + pts - dts;+//+// p_mp4->p_sample->IsRAP = p_picture->i_type == X264_TYPE_IDR ? 1 : 0;+// p_mp4->p_sample->DTS = dts;+// p_mp4->p_sample->CTS_Offset = offset;+// gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample );+//+// p_mp4->p_sample->dataLength = 0;+// p_mp4->i_numframe++;+//+// return 0;+//}++#include "pts.h" static int set_eop( hnd_t handle, x264_picture_t *p_picture ) { mp4_hnd_t *p_mp4 = handle;- uint64_t dts = (uint64_t)p_mp4->i_numframe * p_mp4->i_time_inc;- uint64_t pts = (uint64_t)p_picture->i_pts;- int32_t offset = p_mp4->i_init_delay + pts - dts;+ int64_t cts;+ int64_t dts;+ int32_t offset;+ int32_t dts_delay;+ int32_t cts_delay;+ int32_t delta_time = p_mp4->i_time_inc / 4;+ int32_t delay_frames = p_mp4->i_init_delay / p_mp4->i_time_inc;+ int32_t ts_diff = 0;+ int i;+ static int64_t before_dts;+ if( p_mp4->i_numframe == 0 )+ before_dts = -1;++ //DTS:ピクチャをデコードしメモリに配置する時刻。+ //DTS: The timestamp when a picture is decoded and put into memory.+ //CTS:ピクチャを合成する時刻。+ //CTS: The timestamp of when a picture is made.+ //PTS:ピクチャを表示する時刻。+ //PTS: The timestamp of when a picture is shown. + //CTS_Offset = CTS-DTS、つまり、ピクチャがメモリに存在する時刻。+ //CTS_Offset = CTS-DTS, in other words, the time area when a picture is in memory.++ cts = p_picture->i_pts;+ // 映像は、B-Frame-Delay分先読みしておかなければならない。+ // しかし、それだと1番目のピクチャのDTSは負の値になるため、全体的に映像をInit_Delay分遅らせる処置をとる。+ // We must read enough pictures to fill the B-frame delay.+ // But, with such a way, the DTS of the first picture will end up negative, and therefore we counter it by delaying the picture overall by Init_Delay.++ // x264の方式(MP4Boxも)は、B-Frame-DelayをCTSに与えることで参照系の事前デコードを行う、というもの。+ // 初期ディレイ0化とは、B-Frame-DelayをDTSに与えることにより、ディレイを隠蔽する。+ // The way x264 (and MP4Box as well) do it, is that they do decoding reference'ally by presenting the B-frame delay in CTS.+ // Making the initial delay into zero is a scheme for hiding the delay by giving the B-frame delay to the DTS.+ if( ptsList.initDelayAnable )+ {+ dts_delay = 0;+ cts_delay = p_mp4->i_init_delay;+ }+ else+ {+ for( i = MAX( 0, p_mp4->i_numframe - delay_frames ); i<p_mp4->i_numframe; i++ )+ ts_diff += ptsList.pts[i + 1] - ptsList.pts[i];++ dts_delay = MAX( p_mp4->i_init_delay, ts_diff );+ cts_delay = 0;+ }++ // 理想系はCTS_offset=0であるが、参照系分の事前デコードが必要なことから、CTSとDTS間での差が生じる。+ // By theory, CTS_offset is zero, but as prior decoding of the references is needed, they start to differ.+ // その差を都度計算しDTSからPTS、CTS_offsetを導く方法と、PTSからディレイ分を差し引いてDTSとする方法は、理論上の違いはない。+ // There is no difference in theory between calculating the difference every time, and getting the PTS and CTS_offset from the DTS, and by deducting the delay from PTS. + // 違いがあるとすれば、DTSの刻み幅となる。(VFRの場合)+ // Should we have a difference, there is a stride in the DTS (when doing VFR).+ dts = 0;+ if( dts_delay < ptsList.pts[p_mp4->i_numframe] )+ dts = ptsList.pts[p_mp4->i_numframe] - dts_delay;++ // 前回のDTSよりも値は大きくなければならない。+ // The value must be bigger than the previous.+ if( dts <= before_dts )+ dts = before_dts + delta_time;++ // CTS_Offsetの算出+ // Calculating the CTS_Offset+ offset = cts - dts + cts_delay;++ // オフセットの計算で負になってしまった場合。+ // Should the offset become negative by the calculation.+ if( offset < 0 )+ {+ dts += offset;+ offset = 0;++ // 前回のDTSよりも値は大きくなければならない。+ // The value must be bigger than the previous one.+ // でも、それでエンコ停止してしまうのは悲しいので、DTSを補正して回避+ // But, since it'd be sad if the encode should stop by this, we correct the DTS and evade the problem.+ if(dts <= before_dts){+ // デバッグ用に異常情報出力。+ // Output of the error for debugging purposes.+ x264_log( ptsList.h, X264_LOG_ERROR, "VFR-Timing Error <%8d> type = %d, pts = %8I64d, dts = %8I64d, b_dts = %8I64d, cts_offset = %5d, cts = %8I64d¥r¥n",+ p_mp4->i_numframe, p_picture->i_type, ptsList.pts[p_mp4->i_numframe], dts, before_dts, offset, cts);+ dts = before_dts + delta_time; // ここで表示タイミングが狂う。+ // This is where the show timing goes amiss.+ }+ } p_mp4->p_sample->IsRAP = p_picture->i_type == X264_TYPE_IDR ? 1 : 0;- p_mp4->p_sample->DTS = dts;+ p_mp4->p_sample->DTS = before_dts = dts; p_mp4->p_sample->CTS_Offset = offset;+++ // 今回ピクチャの書き出し+ // Writing out the current picture. gf_isom_add_sample( p_mp4->p_file, p_mp4->i_track, p_mp4->i_descidx, p_mp4->p_sample ); p_mp4->p_sample->dataLength = 0;