1 /* $Id: render.c,v 1.17 2005/04/14 17:37:54 titer Exp $
3 This file is part of the HandBrake source code.
4 Homepage: <http://handbrake.m0k.org/>.
5 It may be used under the terms of the GNU General Public License. */
9 #include "ffmpeg/avcodec.h"
11 struct hb_work_private_s
15 ImgReSampleContext * context;
17 AVPicture pic_tmp_out;
18 hb_buffer_t * buf_scale;
19 hb_fifo_t * subtitle_queue;
22 int renderInit( hb_work_object_t *, hb_job_t * );
23 int renderWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
24 void renderClose( hb_work_object_t * );
26 hb_work_object_t hb_render =
35 static void ApplySub( hb_job_t * job, hb_buffer_t * buf,
38 hb_buffer_t * sub = *_sub;
39 hb_title_t * title = job->title;
40 int i, j, offset_top, offset_left;
41 uint8_t * lum, * alpha, * out;
48 /* If necessary, move the subtitle so it is not in a cropped zone.
49 When it won't fit, we center it so we loose as much on both ends.
50 Otherwise we try to leave a 20px margin around it. */
52 if( sub->height > title->height - job->crop[0] - job->crop[1] - 40 )
53 offset_top = job->crop[0] + ( title->height - job->crop[0] -
54 job->crop[1] - sub->height ) / 2;
55 else if( sub->y < job->crop[0] + 20 )
56 offset_top = job->crop[0] + 20;
57 else if( sub->y > title->height - job->crop[1] - 20 - sub->height )
58 offset_top = title->height - job->crop[1] - 20 - sub->height;
62 if( sub->width > title->width - job->crop[2] - job->crop[3] - 40 )
63 offset_left = job->crop[2] + ( title->width - job->crop[2] -
64 job->crop[3] - sub->width ) / 2;
65 else if( sub->x < job->crop[2] + 20 )
66 offset_left = job->crop[2] + 20;
67 else if( sub->x > title->width - job->crop[3] - 20 - sub->width )
68 offset_left = title->width - job->crop[3] - 20 - sub->width;
73 alpha = lum + sub->width * sub->height;
74 out = buf->data + offset_top * title->width + offset_left;
76 for( i = 0; i < sub->height; i++ )
78 if( offset_top + i >= 0 && offset_top + i < title->height )
80 for( j = 0; j < sub->width; j++ )
82 if( offset_left + j >= 0 && offset_left + j < title->width )
84 out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) +
85 (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4;
95 hb_buffer_close( _sub );
98 int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
99 hb_buffer_t ** buf_out )
101 hb_work_private_t * pv = w->private_data;
102 hb_job_t * job = pv->job;
103 hb_title_t * title = job->title;
104 hb_buffer_t * in = *buf_in, * buf_tmp_in = *buf_in;
106 int title_size = 3 * title->width * title->height / 2;
107 int job_size = 3 * job->width * job->height / 2;
111 /* If the input buffer is end of stream, send out an empty one to the next stage as well. */
112 *buf_out = hb_buffer_init(0);
116 /* Push subtitles onto queue just in case we need to delay a frame */
119 hb_fifo_push( pv->subtitle_queue, in->sub );
123 hb_fifo_push( pv->subtitle_queue, hb_buffer_init(0) );
126 /* Setup render buffer */
127 hb_buffer_t * buf_render = hb_buffer_init( job_size );
132 int filter_count = hb_list_count( job->filters );
135 for( i = 0; i < filter_count; i++ )
137 hb_filter_object_t * filter = hb_list_item( job->filters, i );
144 hb_buffer_t * buf_tmp_out = NULL;
146 int result = filter->work( buf_tmp_in,
151 filter->private_data );
154 * FILTER_OK: set temp buffer to filter buffer, continue
155 * FILTER_DELAY: set temp buffer to NULL, abort
156 * FILTER_DROP: set temp buffer to NULL, pop subtitle, abort
157 * FILTER_FAILED: leave temp buffer alone, continue
159 if( result == FILTER_OK )
161 buf_tmp_in = buf_tmp_out;
163 else if( result == FILTER_DELAY )
168 else if( result == FILTER_DROP )
170 hb_fifo_get( pv->subtitle_queue );
177 /* Apply subtitles */
180 hb_buffer_t * subtitles = hb_fifo_get( pv->subtitle_queue );
183 ApplySub( job, buf_tmp_in, &subtitles );
187 /* Apply crop/scale if specified */
188 if( buf_tmp_in && pv->context )
190 avpicture_fill( &pv->pic_tmp_in, buf_tmp_in->data,
192 title->width, title->height );
194 avpicture_fill( &pv->pic_tmp_out, buf_render->data,
196 job->width, job->height );
198 img_resample( pv->context, &pv->pic_tmp_out, &pv->pic_tmp_in );
200 hb_buffer_copy_settings( buf_render, buf_tmp_in );
202 buf_tmp_in = buf_render;
205 /* Set output to render buffer */
206 (*buf_out) = buf_render;
208 if( buf_tmp_in == NULL )
210 /* Teardown and cleanup buffers if we are emitting NULL */
211 if( buf_in && *buf_in )
213 hb_buffer_close( buf_in );
216 if( buf_out && *buf_out )
218 hb_buffer_close( buf_out );
222 else if( buf_tmp_in != buf_render )
224 /* Copy temporary results and settings into render buffer */
225 memcpy( buf_render->data, buf_tmp_in->data, buf_render->size );
226 hb_buffer_copy_settings( buf_render, buf_tmp_in );
232 void renderClose( hb_work_object_t * w )
234 hb_work_private_t * pv = w->private_data;
236 /* Cleanup subtitle queue */
237 if( pv->subtitle_queue )
239 hb_fifo_close( &pv->subtitle_queue );
242 /* Cleanup filters */
243 /* TODO: Move to work.c? */
244 if( pv->job->filters )
246 int filter_count = hb_list_count( pv->job->filters );
249 for( i = 0; i < filter_count; i++ )
251 hb_filter_object_t * filter = hb_list_item( pv->job->filters, i );
253 if( !filter ) continue;
255 filter->close( filter->private_data );
258 hb_list_close( &pv->job->filters );
261 /* Cleanup render work structure */
263 w->private_data = NULL;
266 int renderInit( hb_work_object_t * w, hb_job_t * job )
268 /* Allocate new private work object */
269 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
271 w->private_data = pv;
273 /* Get title and title size */
274 hb_title_t * title = job->title;
275 int title_size = 3 * title->width * title->height / 2;
277 /* If crop or scale is specified, setup rescale context */
278 if( job->crop[0] || job->crop[1] || job->crop[2] || job->crop[3] ||
279 job->width != title->width || job->height != title->height )
281 pv->context = img_resample_full_init(
282 job->width, job->height, title->width, title->height,
283 job->crop[0], job->crop[1], job->crop[2], job->crop[3],
287 /* Setup FIFO queue for subtitle cache */
288 pv->subtitle_queue = hb_fifo_init( 8 );
291 /* TODO: Move to work.c? */
294 int filter_count = hb_list_count( job->filters );
297 for( i = 0; i < filter_count; i++ )
299 hb_filter_object_t * filter = hb_list_item( job->filters, i );
301 if( !filter ) continue;
303 filter->private_data = filter->init( PIX_FMT_YUV420P,