diff options
author | jbrjake <[email protected]> | 2007-07-27 14:55:58 +0000 |
---|---|---|
committer | jbrjake <[email protected]> | 2007-07-27 14:55:58 +0000 |
commit | 5a4a250000ce8735639503aac2ee29def935865d (patch) | |
tree | d7efc0e7e44e06e80ba67827e137c970ac02743e /libhb/render.c | |
parent | 50c3c15c88172bb00dd787e39ce66eb11480717d (diff) |
This huge patch from huevos_rancheros ports a number of video filters from mencoder to HandBrake: yadif+mcdeint, hqdn3d, pp7, and pullup+softskip+harddup. What this means is that HB now has stateless inverse telecine, temporal denoising, and motion-adaptive deinterlacing!
HandBrake is growing up =)
Thank you, huevos_rancheros!
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@749 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb/render.c')
-rw-r--r-- | libhb/render.c | 234 |
1 files changed, 174 insertions, 60 deletions
diff --git a/libhb/render.c b/libhb/render.c index b6f793fea..20b581383 100644 --- a/libhb/render.c +++ b/libhb/render.c @@ -13,10 +13,10 @@ struct hb_work_private_s hb_job_t * job; ImgReSampleContext * context; - AVPicture pic_raw; - AVPicture pic_deint; - AVPicture pic_render; - hb_buffer_t * buf_deint; + AVPicture pic_tmp_in; + AVPicture pic_tmp_out; + hb_buffer_t * buf_scale; + hb_fifo_t * subtitle_queue; }; int renderInit( hb_work_object_t *, hb_job_t * ); @@ -101,80 +101,180 @@ int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_job_t * job = pv->job; hb_title_t * title = job->title; - hb_buffer_t * in = *buf_in, * buf; + hb_buffer_t * in = *buf_in, * buf_tmp_in = *buf_in; + int title_size = 3 * title->width * title->height / 2; + int job_size = 3 * job->width * job->height / 2; + if(!in->data) { /* If the input buffer is end of stream, send out an empty one to the next stage as well. */ - *buf_out = hb_buffer_init(0); - return HB_WORK_OK; + *buf_out = hb_buffer_init(0); + return HB_WORK_OK; } - - avpicture_fill( &pv->pic_raw, in->data, PIX_FMT_YUV420P, - title->width, title->height ); - - buf = hb_buffer_init( 3 * job->width * job->height / 2 ); - buf->start = in->start; - buf->stop = in->stop; - - if( job->deinterlace && pv->context ) + + /* Push subtitles onto queue just in case we need to delay a frame */ + if( in->sub ) { - avpicture_fill( &pv->pic_render, buf->data, PIX_FMT_YUV420P, - job->width, job->height ); - avpicture_deinterlace( &pv->pic_deint, &pv->pic_raw, - PIX_FMT_YUV420P, title->width, - title->height ); - ApplySub( job, pv->buf_deint, &in->sub ); - img_resample( pv->context, &pv->pic_render, &pv->pic_deint ); + hb_fifo_push( pv->subtitle_queue, in->sub ); } - else if( job->deinterlace ) + else { - avpicture_fill( &pv->pic_deint, buf->data, PIX_FMT_YUV420P, - job->width, job->height ); - avpicture_deinterlace( &pv->pic_deint, &pv->pic_raw, - PIX_FMT_YUV420P, title->width, - title->height ); - ApplySub( job, buf, &in->sub ); + hb_fifo_push( pv->subtitle_queue, hb_buffer_init(0) ); } - else if( pv->context ) + + /* Setup render buffer */ + hb_buffer_t * buf_render = hb_buffer_init( job_size ); + + /* Apply filters */ + if( job->filters ) { - ApplySub( job, in, &in->sub ); - avpicture_fill( &pv->pic_render, buf->data, PIX_FMT_YUV420P, - job->width, job->height ); - img_resample( pv->context, &pv->pic_render, &pv->pic_raw ); - } - else + int filter_count = hb_list_count( job->filters ); + int i; + + for( i = 0; i < filter_count; i++ ) + { + hb_filter_object_t * filter = hb_list_item( job->filters, i ); + + if( !filter ) + { + continue; + } + + hb_buffer_t * buf_tmp_out = NULL; + + int result = filter->work( buf_tmp_in, + &buf_tmp_out, + PIX_FMT_YUV420P, + title->width, + title->height, + filter->private_data ); + + /* + * FILTER_OK: set temp buffer to filter buffer, continue + * FILTER_DELAY: set temp buffer to NULL, abort + * FILTER_DROP: set temp buffer to NULL, pop subtitle, abort + * FILTER_FAILED: leave temp buffer alone, continue + */ + if( result == FILTER_OK ) + { + buf_tmp_in = buf_tmp_out; + } + else if( result == FILTER_DELAY ) + { + buf_tmp_in = NULL; + break; + } + else if( result == FILTER_DROP ) + { + hb_fifo_get( pv->subtitle_queue ); + buf_tmp_in = NULL; + break; + } + } + } + + /* Apply subtitles */ + if( buf_tmp_in ) { - hb_buffer_close( &buf ); - ApplySub( job, in, &in->sub ); - buf = in; - *buf_in = NULL; + hb_buffer_t * subtitles = hb_fifo_get( pv->subtitle_queue ); + if( subtitles ) + { + ApplySub( job, buf_tmp_in, &subtitles ); + } } + + /* Apply crop/scale if specified */ + if( buf_tmp_in && pv->context ) + { + avpicture_fill( &pv->pic_tmp_in, buf_tmp_in->data, + PIX_FMT_YUV420P, + title->width, title->height ); + + avpicture_fill( &pv->pic_tmp_out, buf_render->data, + PIX_FMT_YUV420P, + job->width, job->height ); + + img_resample( pv->context, &pv->pic_tmp_out, &pv->pic_tmp_in ); + + hb_buffer_copy_settings( buf_render, buf_tmp_in ); + + buf_tmp_in = buf_render; + } - (*buf_out) = buf; + /* Set output to render buffer */ + (*buf_out) = buf_render; + + if( buf_tmp_in == NULL ) + { + /* Teardown and cleanup buffers if we are emitting NULL */ + if( buf_in && *buf_in ) + { + hb_buffer_close( buf_in ); + *buf_in = NULL; + } + if( buf_out && *buf_out ) + { + hb_buffer_close( buf_out ); + *buf_out = NULL; + } + } + else if( buf_tmp_in != buf_render ) + { + /* Copy temporary results and settings into render buffer */ + memcpy( buf_render->data, buf_tmp_in->data, buf_render->size ); + hb_buffer_copy_settings( buf_render, buf_tmp_in ); + } return HB_WORK_OK; } void renderClose( hb_work_object_t * w ) { - hb_work_private_t * pv = w->private_data; + hb_work_private_t * pv = w->private_data; + + /* Cleanup subtitle queue */ + if( pv->subtitle_queue ) + { + hb_fifo_close( &pv->subtitle_queue ); + } + /* Cleanup filters */ + /* TODO: Move to work.c? */ + if( pv->job->filters ) + { + int filter_count = hb_list_count( pv->job->filters ); + int i; + + for( i = 0; i < filter_count; i++ ) + { + hb_filter_object_t * filter = hb_list_item( pv->job->filters, i ); + + if( !filter ) continue; + + filter->close( filter->private_data ); + } + + hb_list_close( &pv->job->filters ); + } + + /* Cleanup render work structure */ free( pv ); - w->private_data = NULL; + w->private_data = NULL; } int renderInit( hb_work_object_t * w, hb_job_t * job ) -{ - hb_title_t * title; - +{ + /* Allocate new private work object */ hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) ); - w->private_data = pv; - - title = job->title; - pv->job = job; + w->private_data = pv; + /* Get title and title size */ + hb_title_t * title = job->title; + int title_size = 3 * title->width * title->height / 2; + + /* If crop or scale is specified, setup rescale context */ if( job->crop[0] || job->crop[1] || job->crop[2] || job->crop[3] || job->width != title->width || job->height != title->height ) { @@ -182,16 +282,30 @@ int renderInit( hb_work_object_t * w, hb_job_t * job ) job->width, job->height, title->width, title->height, job->crop[0], job->crop[1], job->crop[2], job->crop[3], 0, 0, 0, 0 ); - } - - if( job->deinterlace ) + } + + /* Setup FIFO queue for subtitle cache */ + pv->subtitle_queue = hb_fifo_init( 8 ); + + /* Setup filters */ + /* TODO: Move to work.c? */ + if( job->filters ) { - /* Allocate a constant buffer used for deinterlacing */ - pv->buf_deint = hb_buffer_init( 3 * title->width * - title->height / 2 ); - avpicture_fill( &pv->pic_deint, pv->buf_deint->data, - PIX_FMT_YUV420P, title->width, title->height ); - } + int filter_count = hb_list_count( job->filters ); + int i; + + for( i = 0; i < filter_count; i++ ) + { + hb_filter_object_t * filter = hb_list_item( job->filters, i ); + if( !filter ) continue; + + filter->private_data = filter->init( PIX_FMT_YUV420P, + title->width, + title->height, + filter->settings ); + } + } + return 0; } |