Index: test/test.c =================================================================== --- test/test.c (revision 1034) +++ test/test.c (working copy) @@ -67,6 +67,7 @@ static int turbo_opts_enabled = 0; static char * turbo_opts = "ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0"; static int largeFileSize = 0; +static int vfr = 0; /* Exit cleanly on Ctrl-C */ static volatile int die = 0; @@ -633,6 +634,9 @@ job->maxWidth = maxWidth; if (maxHeight) job->maxHeight = maxHeight; + + if (vfr) + job->vfr = 1; if( subtitle_force ) { @@ -928,14 +932,15 @@ "\n" - "### Advanced H264 Options----------------------------------------------------\n\n" + "### Advanced Options---------------------------------------------------------\n\n" " -x, --x264opts Specify advanced x264 options in the\n" " same style as mencoder:\n" " option1=value1:option2=value2\n" " -T, --turbo When using 2-pass use the turbo options\n" " on the first pass to improve speed\n" " (only works with x264, affects PSNR by about 0.05dB,\n" - " and increases first pass speed two to four times)\n"); + " and increases first pass speed two to four times)\n" + " -V, --vfr Perform variable framerate detelecine\n"); } /**************************************************************************** @@ -991,7 +996,7 @@ { "crf", no_argument, NULL, 'Q' }, { "x264opts", required_argument, NULL, 'x' }, { "turbo", no_argument, NULL, 'T' }, - + { "vfr", no_argument, NULL, 'V' }, { "maxHeight", required_argument, NULL, 'Y' }, { "maxWidth", required_argument, NULL, 'X' }, @@ -1002,7 +1007,7 @@ int c; c = getopt_long( argc, argv, - "hvuC:f:4i:o:t:Lc:ma:6:s:UFN:e:E:2d789gpP::w:l:n:b:q:S:B:r:R:Qx:TY:X:", + "hvuC:f:4i:o:t:Lc:ma:6:s:UFN:e:E:2d789gpP::w:l:n:b:q:S:B:r:R:Qx:TY:X:V", long_options, &option_index ); if( c < 0 ) { @@ -1315,6 +1320,11 @@ case 'X': maxWidth = atoi (optarg ); break; + case 'V': + vfr = 1; + detelecine = 1; + vrate = 900900; + break; default: fprintf( stderr, "unknown option (%s)\n", argv[optind] ); Index: libhb/detelecine.c =================================================================== --- libhb/detelecine.c (revision 1034) +++ libhb/detelecine.c (working copy) @@ -975,7 +975,7 @@ } else { - goto output_frame; + goto discard_frame; } } @@ -987,7 +987,7 @@ if (!frame) { - goto output_frame; + goto discard_frame; } if( frame->length < 2 ) { @@ -995,19 +995,19 @@ if( !(buf_in->flags & PIC_FLAG_REPEAT_FIRST_FIELD) ) { - goto output_frame; + goto discard_frame; } frame = pullup_get_frame( ctx ); if( !frame ) { - goto output_frame; + goto discard_frame; } if( frame->length < 2 ) { pullup_release_frame( frame ); - goto output_frame; + goto discard_frame; } } } @@ -1034,6 +1034,15 @@ output_frame: *buf_out = pv->buf_out; return FILTER_OK; + +/* This and all discard_frame calls shown above are + the result of me restoring the functionality in + pullup that huevos_rancheros disabled because + HB couldn't handle it. */ +discard_frame: + *buf_out = pv->buf_out; + return FILTER_DROP; + } Index: libhb/muxmp4.c =================================================================== --- libhb/muxmp4.c (revision 1034) +++ libhb/muxmp4.c (working copy) @@ -393,7 +393,14 @@ /* Because we use the audio samplerate as the timescale, we have to use potentially variable durations so the video doesn't go out of sync */ - duration = ( buf->stop * job->arate / 90000 ) - m->sum_dur; + if ( job->vfr ) + { + duration = ( ( buf->stop * job->arate / 90000 ) - ( buf->start * job->arate / 90000 ) ); + } + else + { + duration = ( buf->stop * job->arate / 90000 ) - m->sum_dur; + } m->sum_dur += duration; } else Index: libhb/render.c =================================================================== --- libhb/render.c (revision 1034) +++ libhb/render.c (working copy) @@ -9,6 +9,10 @@ #include "ffmpeg/avcodec.h" #include "ffmpeg/swscale.h" +/* Used for keeping track of when frames are dropped by detelecine. */ +uint32_t dropped_frames = 0; +uint32_t extended_durations = 0; + struct hb_work_private_s { hb_job_t * job; @@ -225,8 +229,20 @@ } else if( result == FILTER_DROP ) { - hb_fifo_get( pv->subtitle_queue ); - buf_tmp_in = NULL; + /* A drop means detelecine's latched its teeth onto + something and has duped frames to discard. */ + + if ( job->vfr ) + { + dropped_frames++; + hb_fifo_get( pv->subtitle_queue ); + buf_tmp_in = NULL; + } + else + { + buf_tmp_in = buf_tmp_out; + } + break; } } @@ -271,6 +287,24 @@ /* Set output to render buffer */ (*buf_out) = buf_render; + if ( buf_tmp_in ) + { + /* Pass VFR NTSC IVTC frame durations on through the workflow. + I totally wish I could slip some cryptic abbreviations into + the last sentence. + + (90090000 / 120000) is the rational equivalent of 750.75. + That's the number of ticks by which a 23.976 frame is + longer than a 29.97 frame. God I hate fractions. + */ + + if ( (dropped_frames) &&( dropped_frames * 4 ) > extended_durations ) + { + buf_render->stop = buf_render->stop + (90090000 / 120000); + extended_durations++; + } + } + if( buf_tmp_in == NULL ) { /* Teardown and cleanup buffers if we are emitting NULL */ @@ -297,6 +331,10 @@ void renderClose( hb_work_object_t * w ) { + hb_log("RENDER: dropped frames: %i (%i ticks)", dropped_frames, (dropped_frames * 3003) ); + hb_log("RENDER: extended frames: %i (%i ticks)", extended_durations, (extended_durations * (90090000 / 120000) ) ); + hb_log("RENDER: Lost time: %i ticks", (dropped_frames * 3003) - (extended_durations * (90090000 / 120000) ) ); + hb_work_private_t * pv = w->private_data; /* Cleanup subtitle queue */ Index: libhb/common.h =================================================================== --- libhb/common.h (revision 1034) +++ libhb/common.h (working copy) @@ -172,7 +172,8 @@ int crf; char *x264opts; int areBframes; - + int vfr; + /* Audio tracks: audios: Indexes in hb_title_t's audios list, starting from 0. -1 indicates the end of the list