Moves the filters' logging info to work.c, adds parameter info. I also changed the...
[HandBrake.git] / libhb / render.c
bloba49bdfadac7b4f38e2a384cf0f1d9a65d6ec24ab
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. */
7 #include "hb.h"
9 #include "ffmpeg/avcodec.h"
10 #include "ffmpeg/swscale.h"
12 struct hb_work_private_s
14 hb_job_t * job;
16 struct SwsContext * context;
17 AVPicture pic_tmp_in;
18 AVPicture pic_tmp_crop;
19 AVPicture pic_tmp_out;
20 hb_buffer_t * buf_scale;
21 hb_fifo_t * subtitle_queue;
24 int renderInit( hb_work_object_t *, hb_job_t * );
25 int renderWork( hb_work_object_t *, hb_buffer_t **, hb_buffer_t ** );
26 void renderClose( hb_work_object_t * );
28 hb_work_object_t hb_render =
30 WORK_RENDER,
31 "Renderer",
32 renderInit,
33 renderWork,
34 renderClose
37 static void ApplySub( hb_job_t * job, hb_buffer_t * buf,
38 hb_buffer_t ** _sub )
40 hb_buffer_t * sub = *_sub;
41 hb_title_t * title = job->title;
42 int i, j, offset_top, offset_left;
43 uint8_t * lum, * alpha, * out;
45 if( !sub )
47 return;
50 /* If necessary, move the subtitle so it is not in a cropped zone.
51 When it won't fit, we center it so we loose as much on both ends.
52 Otherwise we try to leave a 20px margin around it. */
54 if( sub->height > title->height - job->crop[0] - job->crop[1] - 40 )
55 offset_top = job->crop[0] + ( title->height - job->crop[0] -
56 job->crop[1] - sub->height ) / 2;
57 else if( sub->y < job->crop[0] + 20 )
58 offset_top = job->crop[0] + 20;
59 else if( sub->y > title->height - job->crop[1] - 20 - sub->height )
60 offset_top = title->height - job->crop[1] - 20 - sub->height;
61 else
62 offset_top = sub->y;
64 if( sub->width > title->width - job->crop[2] - job->crop[3] - 40 )
65 offset_left = job->crop[2] + ( title->width - job->crop[2] -
66 job->crop[3] - sub->width ) / 2;
67 else if( sub->x < job->crop[2] + 20 )
68 offset_left = job->crop[2] + 20;
69 else if( sub->x > title->width - job->crop[3] - 20 - sub->width )
70 offset_left = title->width - job->crop[3] - 20 - sub->width;
71 else
72 offset_left = sub->x;
74 lum = sub->data;
75 alpha = lum + sub->width * sub->height;
76 out = buf->data + offset_top * title->width + offset_left;
78 for( i = 0; i < sub->height; i++ )
80 if( offset_top + i >= 0 && offset_top + i < title->height )
82 for( j = 0; j < sub->width; j++ )
84 if( offset_left + j >= 0 && offset_left + j < title->width )
86 out[j] = ( (uint16_t) out[j] * ( 16 - (uint16_t) alpha[j] ) +
87 (uint16_t) lum[j] * (uint16_t) alpha[j] ) >> 4;
92 lum += sub->width;
93 alpha += sub->width;
94 out += title->width;
97 hb_buffer_close( _sub );
100 int renderWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
101 hb_buffer_t ** buf_out )
103 hb_work_private_t * pv = w->private_data;
104 hb_job_t * job = pv->job;
105 hb_title_t * title = job->title;
106 hb_buffer_t * in = *buf_in, * buf_tmp_in = *buf_in;
108 if(!in->data)
110 /* If the input buffer is end of stream, send out an empty one to the next stage as well. */
111 *buf_out = hb_buffer_init(0);
112 return HB_WORK_OK;
115 /* Push subtitles onto queue just in case we need to delay a frame */
116 if( in->sub )
118 hb_fifo_push( pv->subtitle_queue, in->sub );
120 else
122 hb_fifo_push( pv->subtitle_queue, hb_buffer_init(0) );
125 /* Setup render buffer */
126 hb_buffer_t * buf_render = hb_buffer_init( 3 * job->width * job->height / 2 );
128 /* Apply filters */
129 if( job->filters )
131 int filter_count = hb_list_count( job->filters );
132 int i;
134 for( i = 0; i < filter_count; i++ )
136 hb_filter_object_t * filter = hb_list_item( job->filters, i );
138 if( !filter )
140 continue;
143 hb_buffer_t * buf_tmp_out = NULL;
145 int result = filter->work( buf_tmp_in,
146 &buf_tmp_out,
147 PIX_FMT_YUV420P,
148 title->width,
149 title->height,
150 filter->private_data );
153 * FILTER_OK: set temp buffer to filter buffer, continue
154 * FILTER_DELAY: set temp buffer to NULL, abort
155 * FILTER_DROP: set temp buffer to NULL, pop subtitle, abort
156 * FILTER_FAILED: leave temp buffer alone, continue
158 if( result == FILTER_OK )
160 buf_tmp_in = buf_tmp_out;
162 else if( result == FILTER_DELAY )
164 buf_tmp_in = NULL;
165 break;
167 else if( result == FILTER_DROP )
169 hb_fifo_get( pv->subtitle_queue );
170 buf_tmp_in = NULL;
171 break;
176 /* Apply subtitles */
177 if( buf_tmp_in )
179 hb_buffer_t * subtitles = hb_fifo_get( pv->subtitle_queue );
180 if( subtitles )
182 ApplySub( job, buf_tmp_in, &subtitles );
186 /* Apply crop/scale if specified */
187 if( buf_tmp_in && pv->context )
189 avpicture_fill( &pv->pic_tmp_in, buf_tmp_in->data,
190 PIX_FMT_YUV420P,
191 title->width, title->height );
193 avpicture_fill( &pv->pic_tmp_out, buf_render->data,
194 PIX_FMT_YUV420P,
195 job->width, job->height );
197 // Crop; this alters the pointer to the data to point to the correct place for cropped frame
198 av_picture_crop( &pv->pic_tmp_crop, &pv->pic_tmp_in, PIX_FMT_YUV420P,
199 job->crop[0], job->crop[2] );
201 // Scale pic_crop into pic_render according to the context set up in renderInit
202 sws_scale(pv->context,
203 pv->pic_tmp_crop.data, pv->pic_tmp_crop.linesize,
204 0, title->height - (job->crop[0] + job->crop[1]),
205 pv->pic_tmp_out.data, pv->pic_tmp_out.linesize);
207 hb_buffer_copy_settings( buf_render, buf_tmp_in );
209 buf_tmp_in = buf_render;
212 /* Set output to render buffer */
213 (*buf_out) = buf_render;
215 if( buf_tmp_in == NULL )
217 /* Teardown and cleanup buffers if we are emitting NULL */
218 if( buf_in && *buf_in )
220 hb_buffer_close( buf_in );
221 *buf_in = NULL;
223 if( buf_out && *buf_out )
225 hb_buffer_close( buf_out );
226 *buf_out = NULL;
229 else if( buf_tmp_in != buf_render )
231 /* Copy temporary results and settings into render buffer */
232 memcpy( buf_render->data, buf_tmp_in->data, buf_render->size );
233 hb_buffer_copy_settings( buf_render, buf_tmp_in );
236 return HB_WORK_OK;
239 void renderClose( hb_work_object_t * w )
241 hb_work_private_t * pv = w->private_data;
243 /* Cleanup subtitle queue */
244 if( pv->subtitle_queue )
246 hb_fifo_close( &pv->subtitle_queue );
249 /* Cleanup filters */
250 /* TODO: Move to work.c? */
251 if( pv->job->filters )
253 int filter_count = hb_list_count( pv->job->filters );
254 int i;
256 for( i = 0; i < filter_count; i++ )
258 hb_filter_object_t * filter = hb_list_item( pv->job->filters, i );
260 if( !filter ) continue;
262 filter->close( filter->private_data );
265 hb_list_close( &pv->job->filters );
268 /* Cleanup render work structure */
269 free( pv );
270 w->private_data = NULL;
273 int renderInit( hb_work_object_t * w, hb_job_t * job )
275 /* Allocate new private work object */
276 hb_work_private_t * pv = calloc( 1, sizeof( hb_work_private_t ) );
277 pv->job = job;
278 w->private_data = pv;
280 /* Get title and title size */
281 hb_title_t * title = job->title;
283 /* If crop or scale is specified, setup rescale context */
284 if( job->crop[0] || job->crop[1] || job->crop[2] || job->crop[3] ||
285 job->width != title->width || job->height != title->height )
287 pv->context = sws_getContext(title->width - (job->crop[2] + job->crop[3]),
288 title->height - (job->crop[0] + job->crop[1]),
289 PIX_FMT_YUV420P,
290 job->width, job->height, PIX_FMT_YUV420P,
291 SWS_LANCZOS, NULL, NULL, NULL);
294 /* Setup FIFO queue for subtitle cache */
295 pv->subtitle_queue = hb_fifo_init( 8 );
297 /* Setup filters */
298 /* TODO: Move to work.c? */
299 if( job->filters )
301 int filter_count = hb_list_count( job->filters );
302 int i;
304 for( i = 0; i < filter_count; i++ )
306 hb_filter_object_t * filter = hb_list_item( job->filters, i );
308 if( !filter ) continue;
310 filter->private_data = filter->init( PIX_FMT_YUV420P,
311 title->width,
312 title->height,
313 filter->settings );
317 return 0;