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"
10 #include "ffmpeg/swscale.h"
12 struct hb_work_private_s
16 struct SwsContext
* context
;
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
=
37 static void ApplySub( hb_job_t
* job
, hb_buffer_t
* buf
,
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
;
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
;
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
;
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;
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
;
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);
115 /* Push subtitles onto queue just in case we need to delay a frame */
118 hb_fifo_push( pv
->subtitle_queue
, in
->sub
);
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 );
131 int filter_count
= hb_list_count( job
->filters
);
134 for( i
= 0; i
< filter_count
; i
++ )
136 hb_filter_object_t
* filter
= hb_list_item( job
->filters
, i
);
143 hb_buffer_t
* buf_tmp_out
= NULL
;
145 int result
= filter
->work( buf_tmp_in
,
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
)
167 else if( result
== FILTER_DROP
)
169 hb_fifo_get( pv
->subtitle_queue
);
176 /* Apply subtitles */
179 hb_buffer_t
* subtitles
= hb_fifo_get( pv
->subtitle_queue
);
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
,
191 title
->width
, title
->height
);
193 avpicture_fill( &pv
->pic_tmp_out
, buf_render
->data
,
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
);
223 if( buf_out
&& *buf_out
)
225 hb_buffer_close( buf_out
);
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
);
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
);
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 */
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
) );
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]),
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 );
298 /* TODO: Move to work.c? */
301 int filter_count
= hb_list_count( job
->filters
);
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
,