summaryrefslogtreecommitdiffstats
path: root/libhb/render.c
diff options
context:
space:
mode:
authorjbrjake <[email protected]>2007-07-27 14:55:58 +0000
committerjbrjake <[email protected]>2007-07-27 14:55:58 +0000
commit5a4a250000ce8735639503aac2ee29def935865d (patch)
treed7efc0e7e44e06e80ba67827e137c970ac02743e /libhb/render.c
parent50c3c15c88172bb00dd787e39ce66eb11480717d (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.c234
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;
}