Index: libhb/render.c =================================================================== --- libhb/render.c (revision 1472) +++ libhb/render.c (working copy) @@ -207,6 +207,7 @@ hb_title_t * title = job->title; hb_buffer_t * in = *buf_in, * buf_tmp_in = *buf_in; hb_buffer_t * ivtc_buffer = NULL; + hb_buffer_t * buf_render = NULL; if(!in->data) { @@ -246,9 +247,6 @@ in->new_chap = 0; } - /* Setup render buffer */ - hb_buffer_t * buf_render = hb_buffer_init( 3 * job->width * job->height / 2 ); - /* Apply filters */ if( job->filters ) { @@ -339,6 +337,117 @@ pv->last_stop[0] = pv->last_start[0] + (in->stop - in->start); } + /* + * Process the buffers in a delayed fashion if doing VFR + */ + if ( job->vfr ) + { + if ( buf_tmp_in ) + { + hb_buffer_t *duplicate; + /* + * Duplicate frame. + */ + duplicate = hb_buffer_init( buf_tmp_in->size ); + hb_buffer_copy_settings( duplicate, buf_tmp_in ); + memcpy( duplicate->data, buf_tmp_in->data, buf_tmp_in->size ); + duplicate->sequence = buf_tmp_in->sequence; + hb_fifo_push( pv->delay_queue, duplicate ); + buf_tmp_in = 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 ) + { + /* + * pop off the oldest and replace our buffer with it + */ + buf_tmp_in = hb_fifo_get( pv->delay_queue ); + } + + if( buf_tmp_in ) + { + /* The current frame exists. That means it hasn't been dropped by a filter. + Make it accessible as ivtc_buffer so we can edit its duration if needed. */ + ivtc_buffer = buf_tmp_in; + + if( pv->lost_time[3] > 0 ) + { + /* + * A frame's been dropped earlier by VFR detelecine. + * Gotta make up the lost time. This will also + * slow down the video. + * The dropped frame's has to be accounted for, 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. + */ + + /* We want to extend the outputted frame's duration by the value + stored in the 4th slot of the lost_time array. Because we need + to adjust all the values in the array so they're contiguous, + extend the duration inside the array first, before applying + it to the current frame buffer. */ + pv->last_stop[3] += pv->lost_time[3]; + + /* Log how much time has been added back in to the video. */ + pv->total_gained_time += pv->lost_time[3]; + + /* We've pulled the 4th value from the lost_time array + and added it to the last_stop array's 4th slot. Now, rotate the + lost_time array so the 4th slot now holds the 3rd's value, and + so on down the line, and set the 0 index to a value of 0. */ + int i; + for( i=2; i >= 0; i--) + { + pv->lost_time[i+1] = pv->lost_time[i]; + } + pv->lost_time[0] = 0; + + /* Log how many frames have had their durations extended. */ + pv->extended_frames++; + } + + /* We can't use the given time stamps. Previous frames + might already have been extended, throwing off the + raw values fed to render.c. Instead, their + stop and start times are stored in arrays. + The 4th cached frame will be the to use. + If it needed its duration extended to make up + lost time, it will have happened above. */ + ivtc_buffer->start = pv->last_start[3]; + ivtc_buffer->stop = pv->last_stop[3]; + + /* Set the 3rd cached frame to start when this one stops, + and so on down the line. If any of them need to be + extended as well to make up lost time, it'll be handled + on the next loop through the renderer. */ + int i; + for (i = 2; i >= 0; i--) + { + int temp_duration = pv->last_stop[i] - pv->last_start[i]; + pv->last_start[i] = pv->last_stop[i+1]; + pv->last_stop[i] = pv->last_start[i] + temp_duration; + } + + /* If we have a pending chapter mark and this frame is at + or after the time of the mark, mark this frame & clear + our pending mark. */ + if( pv->chapter_time && pv->chapter_time <= ivtc_buffer->start ) + { + ivtc_buffer->new_chap = pv->chapter_val; + pv->chapter_time = 0; + } + + } + } + /* Apply subtitles */ if( buf_tmp_in ) { @@ -349,6 +458,13 @@ } } + /* + * Setup render buffer into which we will copy the original input frame + * resizing and cropping as appropriate. This is the buffer that we will + * output. + */ + buf_render = hb_buffer_init( 3 * job->width * job->height / 2 ); + /* Apply crop/scale if specified */ if( buf_tmp_in && pv->context ) { @@ -371,16 +487,26 @@ pv->pic_tmp_out.data, pv->pic_tmp_out.linesize); hb_buffer_copy_settings( buf_render, buf_tmp_in ); + + if( job->vfr ) + { + /* + * When doing VFR the buffer is a duplicate, so don't leak it. + */ + hb_buffer_close( &buf_tmp_in ); + } buf_tmp_in = buf_render; } /* Set output to render buffer */ - (*buf_out) = buf_render; + *buf_out = buf_render; if( buf_tmp_in == NULL ) { - /* Teardown and cleanup buffers if we are emitting NULL */ + /* + * Teardown and cleanup buffers if we are emitting NULL. + */ if( buf_in && *buf_in ) { hb_buffer_close( buf_in ); @@ -391,110 +517,22 @@ hb_buffer_close( buf_out ); *buf_out = NULL; } - } - else if( buf_tmp_in != buf_render ) + } else if( buf_tmp_in != buf_render ) { - /* Copy temporary results and settings into render buffer */ + /* + * Didn't do any resizing or rescaling, so Copy temporary + * results and settings into unused render buffer + */ memcpy( buf_render->data, buf_tmp_in->data, buf_render->size ); hb_buffer_copy_settings( buf_render, buf_tmp_in ); - } - - if (*buf_out && job->vfr) - { - 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( job->vfr ) - { - if( hb_fifo_size( pv->delay_queue ) >= 3 ) + + if( job->vfr ) { - *buf_out = hb_fifo_get( pv->delay_queue ); - } - } - - if( *buf_out && job->vfr) - { - /* The current frame exists. That means it hasn't been dropped by a filter. - Make it accessible as ivtc_buffer so we can edit its duration if needed. */ - ivtc_buffer = *buf_out; - - if( pv->lost_time[3] > 0 ) - { /* - * A frame's been dropped earlier by VFR detelecine. - * Gotta make up the lost time. This will also - * slow down the video. - * The dropped frame's has to be accounted for, 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. + * When doing VFR this is a duplicate and needs freeing */ - - /* We want to extend the outputted frame's duration by the value - stored in the 4th slot of the lost_time array. Because we need - to adjust all the values in the array so they're contiguous, - extend the duration inside the array first, before applying - it to the current frame buffer. */ - pv->last_stop[3] += pv->lost_time[3]; - - /* Log how much time has been added back in to the video. */ - pv->total_gained_time += pv->lost_time[3]; - - /* We've pulled the 4th value from the lost_time array - and added it to the last_stop array's 4th slot. Now, rotate the - lost_time array so the 4th slot now holds the 3rd's value, and - so on down the line, and set the 0 index to a value of 0. */ - int i; - for( i=2; i >= 0; i--) - { - pv->lost_time[i+1] = pv->lost_time[i]; - } - pv->lost_time[0] = 0; - - /* Log how many frames have had their durations extended. */ - pv->extended_frames++; + hb_buffer_close( &buf_tmp_in ); } - - /* We can't use the given time stamps. Previous frames - might already have been extended, throwing off the - raw values fed to render.c. Instead, their - stop and start times are stored in arrays. - The 4th cached frame will be the to use. - If it needed its duration extended to make up - lost time, it will have happened above. */ - ivtc_buffer->start = pv->last_start[3]; - ivtc_buffer->stop = pv->last_stop[3]; - - /* Set the 3rd cached frame to start when this one stops, - and so on down the line. If any of them need to be - extended as well to make up lost time, it'll be handled - on the next loop through the renderer. */ - int i; - for (i = 2; i >= 0; i--) - { - int temp_duration = pv->last_stop[i] - pv->last_start[i]; - pv->last_start[i] = pv->last_stop[i+1]; - pv->last_stop[i] = pv->last_start[i] + temp_duration; - } - - /* If we have a pending chapter mark and this frame is at - or after the time of the mark, mark this frame & clear - our pending mark. */ - if( pv->chapter_time && pv->chapter_time <= ivtc_buffer->start ) - { - ivtc_buffer->new_chap = pv->chapter_val; - pv->chapter_time = 0; - } - } return HB_WORK_OK;