summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjbrjake <[email protected]>2007-11-10 01:51:36 +0000
committerjbrjake <[email protected]>2007-11-10 01:51:36 +0000
commitd95e8d52105a29a03750232c47949b37dc3075dc (patch)
tree94e4f7b25d65b692259241c7049dede3c9568ab7
parent5e6725417750adb69ccbca26d1c7cbdbfd4fd142 (diff)
First attempt at variable frame rate detelecining for NTSC video sources.
This check-in includes the library code as well as the CLI implementation. Only works with MP4 and MKV, untested with high profile, results may vary with mixed content, consult a physician if condition persists for longer than four hours. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1051 b64f7644-9d1e-0410-96f1-a4d463321fa5
-rw-r--r--libhb/common.h3
-rw-r--r--libhb/detelecine.c19
-rw-r--r--libhb/muxmp4.c9
-rw-r--r--libhb/render.c71
-rw-r--r--libhb/work.c21
-rw-r--r--test/test.c16
6 files changed, 128 insertions, 11 deletions
diff --git a/libhb/common.h b/libhb/common.h
index 1cf6cdb59..8a45d7eb7 100644
--- a/libhb/common.h
+++ b/libhb/common.h
@@ -172,7 +172,8 @@ struct hb_job_s
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
diff --git a/libhb/detelecine.c b/libhb/detelecine.c
index 93b153c8d..368341dd7 100644
--- a/libhb/detelecine.c
+++ b/libhb/detelecine.c
@@ -975,7 +975,7 @@ int hb_detelecine_work( const hb_buffer_t * buf_in,
}
else
{
- goto output_frame;
+ goto discard_frame;
}
}
@@ -987,7 +987,7 @@ int hb_detelecine_work( const hb_buffer_t * buf_in,
if (!frame)
{
- goto output_frame;
+ goto discard_frame;
}
if( frame->length < 2 )
{
@@ -995,19 +995,19 @@ int hb_detelecine_work( const hb_buffer_t * buf_in,
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 @@ int hb_detelecine_work( const hb_buffer_t * buf_in,
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;
+
}
diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c
index 2f375e832..d279667ee 100644
--- a/libhb/muxmp4.c
+++ b/libhb/muxmp4.c
@@ -393,7 +393,14 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data,
/* 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
diff --git a/libhb/render.c b/libhb/render.c
index edbd18a80..07f38897e 100644
--- a/libhb/render.c
+++ b/libhb/render.c
@@ -19,6 +19,10 @@ struct hb_work_private_s
AVPicture pic_tmp_out;
hb_buffer_t * buf_scale;
hb_fifo_t * subtitle_queue;
+ hb_fifo_t * delay_queue;
+ int frames_to_extend;
+ int dropped_frames;
+ int extended_frames;
};
int renderInit( hb_work_object_t *, hb_job_t * );
@@ -153,10 +157,14 @@ int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_job_t * job = pv->job;
hb_title_t * title = job->title;
hb_buffer_t * in = *buf_in, * buf_tmp_in = *buf_in;
+ hb_buffer_t * ivtc_buffer = NULL;
if(!in->data)
{
- /* If the input buffer is end of stream, send out an empty one to the next stage as well. */
+ /* If the input buffer is end of stream, send out an empty one
+ * to the next stage as well. Note that this will result in us
+ * losing the current contents of the delay queue.
+ */
*buf_out = hb_buffer_init(0);
return HB_WORK_OK;
}
@@ -227,6 +235,11 @@ int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
{
hb_fifo_get( pv->subtitle_queue );
buf_tmp_in = NULL;
+ if( job->vfr )
+ {
+ pv->frames_to_extend += 4;
+ pv->dropped_frames++;
+ }
break;
}
}
@@ -291,6 +304,49 @@ int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
memcpy( buf_render->data, buf_tmp_in->data, buf_render->size );
hb_buffer_copy_settings( buf_render, buf_tmp_in );
}
+
+ if (*buf_out)
+ {
+ hb_fifo_push( pv->delay_queue, *buf_out );
+ *buf_out = NULL;
+ }
+
+ /*
+ * Keep the last three frames in our queue, this ensures that we have the last
+ * two always in there should we need to rewrite the durations on them.
+ */
+ if( hb_fifo_size( pv->delay_queue ) >= 3 )
+ {
+ *buf_out = hb_fifo_get( pv->delay_queue );
+ }
+
+ if( *buf_out )
+ {
+ if( pv->frames_to_extend )
+ {
+ /*
+ * A frame's been dropped by VFR detelecine.
+ * Gotta make up the lost time. This will also
+ * slow down the video to 23.976fps.
+ * The dropped frame ran for 3003 ticks, so
+ * divvy it up amongst the 4 frames left behind.
+ * This is what the delay_queue is for;
+ * telecined sequences start 2 frames before
+ * the dropped frame, so to slow down the right
+ * ones you need a 2 frame delay between
+ * reading input and writing output.
+ */
+ ivtc_buffer = *buf_out;
+
+ if (pv->frames_to_extend % 4)
+ ivtc_buffer->stop += 751;
+ else
+ ivtc_buffer->stop += 750;
+
+ pv->frames_to_extend--;
+ pv->extended_frames++;
+ }
+ }
return HB_WORK_OK;
}
@@ -299,12 +355,21 @@ void renderClose( hb_work_object_t * w )
{
hb_work_private_t * pv = w->private_data;
+ hb_log("render: dropped frames: %i (%i ticks)", pv->dropped_frames, (pv->dropped_frames * 3003) );
+ hb_log("render: extended frames: %i (%i ticks)", pv->extended_frames, ( ( pv->extended_frames / 4 ) * 3003 ) );
+ hb_log("render: Lost time: %i frames (%i ticks)", (pv->dropped_frames * 4) - (pv->extended_frames), (pv->dropped_frames * 3003) - ( ( pv->extended_frames / 4 ) * 3003 ) );
+
/* Cleanup subtitle queue */
if( pv->subtitle_queue )
{
hb_fifo_close( &pv->subtitle_queue );
}
+ if( pv->delay_queue )
+ {
+ hb_fifo_close( &pv->delay_queue );
+ }
+
/* Cleanup filters */
/* TODO: Move to work.c? */
if( pv->job->filters )
@@ -352,6 +417,10 @@ int renderInit( hb_work_object_t * w, hb_job_t * job )
/* Setup FIFO queue for subtitle cache */
pv->subtitle_queue = hb_fifo_init( 8 );
+ pv->delay_queue = hb_fifo_init( 8 );
+ pv->frames_to_extend = 0;
+ pv->dropped_frames = 0;
+ pv->extended_frames = 0;
/* Setup filters */
/* TODO: Move to work.c? */
diff --git a/libhb/work.c b/libhb/work.c
index 22e081532..fdeace025 100644
--- a/libhb/work.c
+++ b/libhb/work.c
@@ -160,6 +160,27 @@ static void do_job( hb_job_t * job, int cpu_count )
job->crop[0], job->crop[1], job->crop[2], job->crop[3] );
hb_log( " + grayscale %s", job->grayscale ? "on" : "off" );
+ if ( job->vfr )
+ {
+ job->vrate_base = 900900;
+
+ int detelecine_present = 0;
+ if ( job->filters )
+ {
+ for( i = 0; i < hb_list_count( job->filters ); i++ )
+ {
+ hb_filter_object_t * filter = hb_list_item( job->filters, i );
+ if (filter->id == FILTER_DETELECINE)
+ detelecine_present = 1;
+ }
+ }
+
+ if (!detelecine_present)
+ hb_list_add( job->filters, &hb_filter_detelecine );
+
+ hb_log("work: VFR mode -- Switching FPS to 29.97 and detelecining.");
+ }
+
if( job->filters )
{
hb_log(" + filters");
diff --git a/test/test.c b/test/test.c
index 4ddefdfdb..e3f7274c2 100644
--- a/test/test.c
+++ b/test/test.c
@@ -69,6 +69,7 @@ static char * turbo_opts = "ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-
static int largeFileSize = 0;
static int preset = 0;
static char * preset_name = 0;
+static int vfr = 0;
/* Exit cleanly on Ctrl-C */
static volatile int die = 0;
@@ -877,6 +878,9 @@ static int HandleEvents( hb_handle_t * h )
job->maxWidth = maxWidth;
if (maxHeight)
job->maxHeight = maxHeight;
+
+ if (vfr)
+ job->vfr = 1;
if( subtitle_force )
{
@@ -1177,14 +1181,16 @@ static void ShowHelp()
"\n"
- "### Advanced H264 Options----------------------------------------------------\n\n"
+ "### Advanced Options---------------------------------------------------------\n\n"
" -x, --x264opts <string> 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 on NTSC content\n"
+ );
}
/****************************************************************************
@@ -1285,6 +1291,7 @@ static int ParseOptions( int argc, char ** argv )
{ "maxWidth", required_argument, NULL, 'X' },
{ "preset", required_argument, NULL, 'Z' },
{ "preset-list", no_argument, NULL, 'z' },
+ { "vfr", no_argument, NULL, 'V' },
{ 0, 0, 0, 0 }
};
@@ -1293,7 +1300,7 @@ static int ParseOptions( int argc, char ** argv )
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:Z:z",
+ "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:VZ:z",
long_options, &option_index );
if( c < 0 )
{
@@ -1613,6 +1620,9 @@ static int ParseOptions( int argc, char ** argv )
case 'X':
maxWidth = atoi (optarg );
break;
+ case 'V':
+ vfr = 1;
+ break;
default:
fprintf( stderr, "unknown option (%s)\n", argv[optind] );