3 Copyright (c) 2003-2015 HandBrake Team
4 This file is part of the HandBrake source code
5 Homepage: <http://handbrake.fr/>.
6 It may be used under the terms of the GNU General Public License v2.
7 For full terms see the file COPYING file or visit http://www.gnu.org/licenses/gpl-2.0.html
14 struct hb_filter_private_s
21 hb_list_t
* sub_list
; // List of active subs
25 ASS_Renderer
* renderer
;
27 uint8_t script_initialized
;
31 hb_buffer_t
* current_sub
;
35 static int vobsub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
);
37 static int vobsub_work( hb_filter_object_t
* filter
,
38 hb_buffer_t
** buf_in
,
39 hb_buffer_t
** buf_out
);
41 static void vobsub_close( hb_filter_object_t
* filter
);
45 static int ssa_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
);
47 static int ssa_work( hb_filter_object_t
* filter
,
48 hb_buffer_t
** buf_in
,
49 hb_buffer_t
** buf_out
);
51 static void ssa_close( hb_filter_object_t
* filter
);
55 static int textsub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
);
56 static int cc608sub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
);
58 static int textsub_work( hb_filter_object_t
* filter
,
59 hb_buffer_t
** buf_in
,
60 hb_buffer_t
** buf_out
);
62 static void textsub_close( hb_filter_object_t
* filter
);
66 static int pgssub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
);
68 static int pgssub_work ( hb_filter_object_t
* filter
,
69 hb_buffer_t
** buf_in
,
70 hb_buffer_t
** buf_out
);
72 static void pgssub_close( hb_filter_object_t
* filter
);
76 static int hb_rendersub_init( hb_filter_object_t
* filter
,
77 hb_filter_init_t
* init
);
79 static int hb_rendersub_post_init( hb_filter_object_t
* filter
, hb_job_t
*job
);
81 static int hb_rendersub_work( hb_filter_object_t
* filter
,
82 hb_buffer_t
** buf_in
,
83 hb_buffer_t
** buf_out
);
85 static void hb_rendersub_close( hb_filter_object_t
* filter
);
87 hb_filter_object_t hb_filter_render_sub
=
89 .id
= HB_FILTER_RENDER_SUB
,
91 .name
= "Subtitle renderer",
93 .init
= hb_rendersub_init
,
94 .post_init
= hb_rendersub_post_init
,
95 .work
= hb_rendersub_work
,
96 .close
= hb_rendersub_close
,
99 static void blend( hb_buffer_t
*dst
, hb_buffer_t
*src
, int left
, int top
)
104 uint8_t *y_in
, *y_out
;
105 uint8_t *u_in
, *u_out
;
106 uint8_t *v_in
, *v_out
;
107 uint8_t *a_in
, alpha
;
120 if( src
->f
.width
- x0
> dst
->f
.width
- left
)
122 ww
= dst
->f
.width
- left
+ x0
;
125 if( src
->f
.height
- y0
> dst
->f
.height
- top
)
127 hh
= dst
->f
.height
- top
+ y0
;
130 for( yy
= y0
; yy
< hh
; yy
++ )
132 y_in
= src
->plane
[0].data
+ yy
* src
->plane
[0].stride
;
133 y_out
= dst
->plane
[0].data
+ ( yy
+ top
) * dst
->plane
[0].stride
;
134 a_in
= src
->plane
[3].data
+ yy
* src
->plane
[3].stride
;
135 for( xx
= x0
; xx
< ww
; xx
++ )
139 * Merge the luminance and alpha with the picture
142 ( (uint16_t)y_out
[left
+ xx
] * ( 255 - alpha
) +
143 (uint16_t)y_in
[xx
] * alpha
) / 255;
148 // Assumes source and dest are the same PIX_FMT
151 if( dst
->plane
[1].height
< dst
->plane
[0].height
)
153 if( dst
->plane
[1].width
< dst
->plane
[0].width
)
156 for( yy
= y0
>> hshift
; yy
< hh
>> hshift
; yy
++ )
158 u_in
= src
->plane
[1].data
+ yy
* src
->plane
[1].stride
;
159 u_out
= dst
->plane
[1].data
+ ( yy
+ ( top
>> hshift
) ) * dst
->plane
[1].stride
;
160 v_in
= src
->plane
[2].data
+ yy
* src
->plane
[2].stride
;
161 v_out
= dst
->plane
[2].data
+ ( yy
+ ( top
>> hshift
) ) * dst
->plane
[2].stride
;
162 a_in
= src
->plane
[3].data
+ ( yy
<< hshift
) * src
->plane
[3].stride
;
164 for( xx
= x0
>> wshift
; xx
< ww
>> wshift
; xx
++ )
166 alpha
= a_in
[xx
<< wshift
];
168 // Blend averge U and alpha
169 u_out
[(left
>> wshift
) + xx
] =
170 ( (uint16_t)u_out
[(left
>> wshift
) + xx
] * ( 255 - alpha
) +
171 (uint16_t)u_in
[xx
] * alpha
) / 255;
174 v_out
[(left
>> wshift
) + xx
] =
175 ( (uint16_t)v_out
[(left
>> wshift
) + xx
] * ( 255 - alpha
) +
176 (uint16_t)v_in
[xx
] * alpha
) / 255;
181 // Assumes that the input buffer has the same dimensions
182 // as the original title diminsions
183 static void ApplySub( hb_filter_private_t
* pv
, hb_buffer_t
* buf
, hb_buffer_t
* sub
)
185 int top
, left
, margin_top
, margin_percent
;
190 * Percent of height of picture that form a margin that subtitles
191 * should not be displayed within.
196 * If necessary, move the subtitle so it is not in a cropped zone.
197 * When it won't fit, we center it so we lose as much on both ends.
198 * Otherwise we try to leave a 20px or 2% margin around it.
200 margin_top
= ( ( buf
->f
.height
- pv
->crop
[0] - pv
->crop
[1] ) *
201 margin_percent
) / 100;
203 if( margin_top
> 20 )
206 * A maximum margin of 20px regardless of height of the picture.
211 if( sub
->f
.height
> buf
->f
.height
- pv
->crop
[0] - pv
->crop
[1] -
215 * The subtitle won't fit in the cropped zone, so center
216 * it vertically so we fit in as much as we can.
218 top
= pv
->crop
[0] + ( buf
->f
.height
- pv
->crop
[0] -
219 pv
->crop
[1] - sub
->f
.height
) / 2;
221 else if( sub
->f
.y
< pv
->crop
[0] + margin_top
)
224 * The subtitle fits in the cropped zone, but is currently positioned
225 * within our top margin, so move it outside of our margin.
227 top
= pv
->crop
[0] + margin_top
;
229 else if( sub
->f
.y
> buf
->f
.height
- pv
->crop
[1] - margin_top
- sub
->f
.height
)
232 * The subtitle fits in the cropped zone, and is not within the top
233 * margin but is within the bottom margin, so move it to be above
236 top
= buf
->f
.height
- pv
->crop
[1] - margin_top
- sub
->f
.height
;
241 * The subtitle is fine where it is.
246 if( sub
->f
.width
> buf
->f
.width
- pv
->crop
[2] - pv
->crop
[3] - 40 )
247 left
= pv
->crop
[2] + ( buf
->f
.width
- pv
->crop
[2] -
248 pv
->crop
[3] - sub
->f
.width
) / 2;
249 else if( sub
->f
.x
< pv
->crop
[2] + 20 )
250 left
= pv
->crop
[2] + 20;
251 else if( sub
->f
.x
> buf
->f
.width
- pv
->crop
[3] - 20 - sub
->f
.width
)
252 left
= buf
->f
.width
- pv
->crop
[3] - 20 - sub
->f
.width
;
262 blend( buf
, sub
, left
, top
);
265 // Assumes that the input buffer has the same dimensions
266 // as the original title diminsions
267 static void ApplyVOBSubs( hb_filter_private_t
* pv
, hb_buffer_t
* buf
)
270 hb_buffer_t
*sub
, *next
;
272 for( ii
= 0; ii
< hb_list_count(pv
->sub_list
); )
274 sub
= hb_list_item( pv
->sub_list
, ii
);
275 if (ii
+ 1 < hb_list_count(pv
->sub_list
))
276 next
= hb_list_item( pv
->sub_list
, ii
+ 1 );
280 if ((sub
->s
.stop
!= AV_NOPTS_VALUE
&& sub
->s
.stop
<= buf
->s
.start
) ||
281 (next
!= NULL
&& sub
->s
.stop
== AV_NOPTS_VALUE
&& next
->s
.start
<= buf
->s
.start
))
283 // Subtitle stop is in the past, delete it
284 hb_list_rem( pv
->sub_list
, sub
);
285 hb_buffer_close( &sub
);
287 else if( sub
->s
.start
<= buf
->s
.start
)
289 // The subtitle has started before this frame and ends
290 // after it. Render the subtitle into the frame.
293 ApplySub( pv
, buf
, sub
);
300 // The subtitle starts in the future. No need to continue.
306 static int vobsub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
)
308 hb_filter_private_t
* pv
= filter
->private_data
;
310 pv
->sub_list
= hb_list_init();
315 static void vobsub_close( hb_filter_object_t
* filter
)
317 hb_filter_private_t
* pv
= filter
->private_data
;
325 hb_list_empty( &pv
->sub_list
);
328 filter
->private_data
= NULL
;
331 static int vobsub_work( hb_filter_object_t
* filter
,
332 hb_buffer_t
** buf_in
,
333 hb_buffer_t
** buf_out
)
335 hb_filter_private_t
* pv
= filter
->private_data
;
336 hb_buffer_t
* in
= *buf_in
;
339 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
343 return HB_FILTER_DONE
;
346 // Get any pending subtitles and add them to the active
348 while( ( sub
= hb_fifo_get( filter
->subtitle
->fifo_out
) ) )
350 hb_list_add( pv
->sub_list
, sub
);
353 ApplyVOBSubs( pv
, in
);
360 static uint8_t ssaAlpha( ASS_Image
*frame
, int x
, int y
)
362 unsigned frameA
= ( frame
->color
) & 0xff;
363 unsigned gliphA
= frame
->bitmap
[y
*frame
->stride
+ x
];
365 // Alpha for this pixel is the frame opacity (255 - frameA)
366 // multiplied by the gliph alfa (gliphA) for this pixel
367 unsigned alpha
= (255 - frameA
) * gliphA
>> 8;
369 return (uint8_t)alpha
;
372 static hb_buffer_t
* RenderSSAFrame( hb_filter_private_t
* pv
, ASS_Image
* frame
)
377 unsigned r
= ( frame
->color
>> 24 ) & 0xff;
378 unsigned g
= ( frame
->color
>> 16 ) & 0xff;
379 unsigned b
= ( frame
->color
>> 8 ) & 0xff;
381 int yuv
= hb_rgb2yuv((r
<< 16) | (g
<< 8) | b
);
383 unsigned frameY
= (yuv
>> 16) & 0xff;
384 unsigned frameV
= (yuv
>> 8 ) & 0xff;
385 unsigned frameU
= (yuv
>> 0 ) & 0xff;
387 sub
= hb_frame_buffer_init( AV_PIX_FMT_YUVA420P
, frame
->w
, frame
->h
);
391 uint8_t *y_out
, *u_out
, *v_out
, *a_out
;
392 y_out
= sub
->plane
[0].data
;
393 u_out
= sub
->plane
[1].data
;
394 v_out
= sub
->plane
[2].data
;
395 a_out
= sub
->plane
[3].data
;
397 for( yy
= 0; yy
< frame
->h
; yy
++ )
399 for( xx
= 0; xx
< frame
->w
; xx
++ )
402 if( ( yy
& 1 ) == 0 )
404 u_out
[xx
>>1] = frameU
;
405 v_out
[xx
>>1] = frameV
;
407 a_out
[xx
] = ssaAlpha( frame
, xx
, yy
);;
409 y_out
+= sub
->plane
[0].stride
;
410 if( ( yy
& 1 ) == 0 )
412 u_out
+= sub
->plane
[1].stride
;
413 v_out
+= sub
->plane
[2].stride
;
415 a_out
+= sub
->plane
[3].stride
;
417 sub
->f
.width
= frame
->w
;
418 sub
->f
.height
= frame
->h
;
419 sub
->f
.x
= frame
->dst_x
+ pv
->crop
[2];
420 sub
->f
.y
= frame
->dst_y
+ pv
->crop
[0];
425 static void ApplySSASubs( hb_filter_private_t
* pv
, hb_buffer_t
* buf
)
427 ASS_Image
*frameList
;
430 frameList
= ass_render_frame( pv
->renderer
, pv
->ssaTrack
,
431 buf
->s
.start
/ 90, NULL
);
436 for (frame
= frameList
; frame
; frame
= frame
->next
) {
437 sub
= RenderSSAFrame( pv
, frame
);
440 ApplySub( pv
, buf
, sub
);
441 hb_buffer_close( &sub
);
446 static void ssa_log(int level
, const char *fmt
, va_list args
, void *data
)
448 if ( level
< 5 ) // same as default verbosity when no callback is set
450 hb_valog( 1, "[ass]", fmt
, args
);
454 static int ssa_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
)
456 hb_filter_private_t
* pv
= filter
->private_data
;
458 pv
->ssa
= ass_library_init();
460 hb_error( "decssasub: libass initialization failed\n" );
464 // Redirect libass output to hb_log
465 ass_set_message_cb( pv
->ssa
, ssa_log
, NULL
);
467 // Load embedded fonts
468 hb_list_t
* list_attachment
= job
->list_attachment
;
470 for ( i
= 0; i
< hb_list_count(list_attachment
); i
++ )
472 hb_attachment_t
* attachment
= hb_list_item( list_attachment
, i
);
474 if ( attachment
->type
== FONT_TTF_ATTACH
||
475 attachment
->type
== FONT_OTF_ATTACH
)
485 ass_set_extract_fonts( pv
->ssa
, 1 );
486 ass_set_style_overrides( pv
->ssa
, NULL
);
488 pv
->renderer
= ass_renderer_init( pv
->ssa
);
489 if ( !pv
->renderer
) {
490 hb_log( "decssasub: renderer initialization failed\n" );
494 ass_set_use_margins( pv
->renderer
, 0 );
495 ass_set_hinting( pv
->renderer
, ASS_HINTING_LIGHT
); // VLC 1.0.4 uses this
496 ass_set_font_scale( pv
->renderer
, 1.0 );
497 ass_set_line_spacing( pv
->renderer
, 1.0 );
499 // Setup default font family
501 // SSA v4.00 requires that "Arial" be the default font
502 const char *font
= NULL
;
503 const char *family
= "Arial";
504 // NOTE: This can sometimes block for several *seconds*.
505 // It seems that process_fontdata() for some embedded fonts is slow.
506 ass_set_fonts( pv
->renderer
, font
, family
, /*haveFontConfig=*/1, NULL
, 1 );
509 pv
->ssaTrack
= ass_new_track( pv
->ssa
);
510 if ( !pv
->ssaTrack
) {
511 hb_log( "decssasub: ssa track initialization failed\n" );
515 int height
= job
->title
->geometry
.height
- job
->crop
[0] - job
->crop
[1];
516 int width
= job
->title
->geometry
.width
- job
->crop
[2] - job
->crop
[3];
517 ass_set_frame_size( pv
->renderer
, width
, height
);
519 double par
= (double)job
->par
.num
/ job
->par
.den
;
520 ass_set_aspect_ratio( pv
->renderer
, 1, par
);
525 static void ssa_close( hb_filter_object_t
* filter
)
527 hb_filter_private_t
* pv
= filter
->private_data
;
535 ass_free_track( pv
->ssaTrack
);
537 ass_renderer_done( pv
->renderer
);
539 ass_library_done( pv
->ssa
);
542 filter
->private_data
= NULL
;
545 static int ssa_work( hb_filter_object_t
* filter
,
546 hb_buffer_t
** buf_in
,
547 hb_buffer_t
** buf_out
)
549 hb_filter_private_t
* pv
= filter
->private_data
;
550 hb_buffer_t
* in
= *buf_in
;
553 if (!pv
->script_initialized
)
555 // NOTE: The codec extradata is expected to be in MKV format
556 // I would like to initialize this in ssa_post_init, but when we are
557 // transcoding text subtitles to SSA, the extradata does not
558 // get initialized until the decoder is initialized. Since
559 // decoder initialization happens after filter initialization,
560 // we need to postpone this.
561 ass_process_codec_private(pv
->ssaTrack
,
562 (char*)filter
->subtitle
->extradata
,
563 filter
->subtitle
->extradata_size
);
564 pv
->script_initialized
= 1;
566 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
570 return HB_FILTER_DONE
;
573 // Get any pending subtitles and add them to the active
575 while( ( sub
= hb_fifo_get( filter
->subtitle
->fifo_out
) ) )
577 // Parse MKV-SSA packet
578 // SSA subtitles always have an explicit stop time, so we
579 // do not need to do special processing for stop == AV_NOPTS_VALUE
580 ass_process_chunk( pv
->ssaTrack
, (char*)sub
->data
, sub
->size
,
582 (sub
->s
.stop
- sub
->s
.start
) / 90 );
583 hb_buffer_close(&sub
);
586 ApplySSASubs( pv
, in
);
593 static int cc608sub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
)
595 // Text subtitles for which we create a dummy ASS header need
596 // to have the header rewritten with the correct dimensions.
597 int height
= job
->title
->geometry
.height
- job
->crop
[0] - job
->crop
[1];
598 int width
= job
->title
->geometry
.width
- job
->crop
[2] - job
->crop
[3];
599 int safe_height
= 0.8 * job
->title
->geometry
.height
;
600 // Use fixed widht font for CC
601 hb_subtitle_add_ssa_header(filter
->subtitle
, "Courier New",
602 .08 * safe_height
, width
, height
);
603 return ssa_post_init(filter
, job
);
606 static int textsub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
)
608 // Text subtitles for which we create a dummy ASS header need
609 // to have the header rewritten with the correct dimensions.
610 int height
= job
->title
->geometry
.height
- job
->crop
[0] - job
->crop
[1];
611 int width
= job
->title
->geometry
.width
- job
->crop
[2] - job
->crop
[3];
612 hb_subtitle_add_ssa_header(filter
->subtitle
, "Arial",
613 .066 * job
->title
->geometry
.height
,
615 return ssa_post_init(filter
, job
);
618 static void textsub_close( hb_filter_object_t
* filter
)
620 return ssa_close(filter
);
623 static void process_sub(hb_filter_private_t
*pv
, hb_buffer_t
*sub
)
628 // libass expects every chunk to have a unique sequence number
629 // since we are repeating subs in some cases, we need to replace
630 // the sequence number.
631 tmp
= strchr((char*)sub
->data
, ',');
635 ssa
= hb_strdup_printf("%d%s", ++pv
->line
, tmp
);
637 // Parse MKV-SSA packet
638 // SSA subtitles always have an explicit stop time, so we
639 // do not need to do special processing for stop == AV_NOPTS_VALUE
640 start
= sub
->s
.start
;
641 dur
= sub
->s
.stop
- sub
->s
.start
;
642 ass_process_chunk(pv
->ssaTrack
, ssa
, sub
->size
, start
, dur
);
646 static int textsub_work(hb_filter_object_t
* filter
,
647 hb_buffer_t
** buf_in
,
648 hb_buffer_t
** buf_out
)
650 hb_filter_private_t
* pv
= filter
->private_data
;
651 hb_buffer_t
* in
= *buf_in
;
654 if (!pv
->script_initialized
)
656 ass_process_codec_private(pv
->ssaTrack
,
657 (char*)filter
->subtitle
->extradata
,
658 filter
->subtitle
->extradata_size
);
659 pv
->script_initialized
= 1;
662 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
666 return HB_FILTER_DONE
;
669 int in_start_ms
= in
->s
.start
/ 90;
671 // Get any pending subtitles and add them to the active
673 while ((sub
= hb_fifo_get(filter
->subtitle
->fifo_out
)))
675 // libass expects times in ms. So to make the math easy,
676 // convert to ms immediately.
678 if (sub
->s
.stop
!= AV_NOPTS_VALUE
)
683 // Subtitle formats such as CC can have stop times
684 // that are not known until an "erase display" command
685 // is encountered in the stream. For these formats
686 // current_sub is the currently active subtitle for which
687 // we do not yet know the stop time. We do not currently
688 // support overlapping subtitles of this type.
689 if (pv
->current_sub
!= NULL
)
691 // Next sub start time tells us the stop time of the
692 // current sub when it is not known in advance.
693 pv
->current_sub
->s
.stop
= sub
->s
.start
;
694 process_sub(pv
, pv
->current_sub
);
695 hb_buffer_close(&pv
->current_sub
);
697 if (sub
->s
.start
== sub
->s
.stop
)
699 // Zero duration sub used to "clear" previous sub that had
700 // an unknown duration
701 hb_buffer_close(&sub
);
703 else if (sub
->s
.stop
== AV_NOPTS_VALUE
)
705 // We don't know the duration of this sub. So we will
706 // apply it to every video frame until we see a "clear" sub.
707 pv
->current_sub
= sub
;
708 pv
->current_sub
->s
.stop
= pv
->current_sub
->s
.start
;
712 // Duration of this subtitle is known, so we can just
713 // process it normally.
714 process_sub(pv
, sub
);
715 hb_buffer_close(&sub
);
718 if (pv
->current_sub
!= NULL
&& pv
->current_sub
->s
.start
<= in_start_ms
)
720 // We don't know the duration of this subtitle, but we know
721 // that it started before the current video frame and that
722 // it is still active. So render it on this video frame.
723 pv
->current_sub
->s
.start
= pv
->current_sub
->s
.stop
;
724 pv
->current_sub
->s
.stop
= in_start_ms
+ 1;
725 process_sub(pv
, pv
->current_sub
);
728 ApplySSASubs(pv
, in
);
735 static void ApplyPGSSubs( hb_filter_private_t
* pv
, hb_buffer_t
* buf
)
738 hb_buffer_t
* old_sub
;
741 // Each PGS subtitle supersedes anything that preceded it.
742 // Find the active subtitle (if there is one), and delete
743 // everything before it.
744 for( index
= hb_list_count( pv
->sub_list
) - 1; index
> 0; index
-- )
746 sub
= hb_list_item( pv
->sub_list
, index
);
747 if ( sub
->s
.start
<= buf
->s
.start
)
751 old_sub
= hb_list_item( pv
->sub_list
, index
- 1);
752 hb_list_rem( pv
->sub_list
, old_sub
);
753 hb_buffer_close( &old_sub
);
759 // Some PGS subtitles have no content and only serve to clear
760 // the screen. If any of these are at the front of our list,
761 // we can now get rid of them.
762 while ( hb_list_count( pv
->sub_list
) > 0 )
764 sub
= hb_list_item( pv
->sub_list
, 0 );
765 if (sub
->f
.width
!= 0 && sub
->f
.height
!= 0)
768 hb_list_rem( pv
->sub_list
, sub
);
769 hb_buffer_close( &sub
);
772 // Check to see if there's an active subtitle, and apply it.
773 if ( hb_list_count( pv
->sub_list
) > 0)
775 sub
= hb_list_item( pv
->sub_list
, 0 );
776 if ( sub
->s
.start
<= buf
->s
.start
)
780 ApplySub( pv
, buf
, sub
);
787 static int pgssub_post_init( hb_filter_object_t
* filter
, hb_job_t
* job
)
789 hb_filter_private_t
* pv
= filter
->private_data
;
791 pv
->sub_list
= hb_list_init();
796 static void pgssub_close( hb_filter_object_t
* filter
)
798 hb_filter_private_t
* pv
= filter
->private_data
;
806 hb_list_empty( &pv
->sub_list
);
809 filter
->private_data
= NULL
;
812 static int pgssub_work( hb_filter_object_t
* filter
,
813 hb_buffer_t
** buf_in
,
814 hb_buffer_t
** buf_out
)
816 hb_filter_private_t
* pv
= filter
->private_data
;
817 hb_buffer_t
* in
= *buf_in
;
820 if (in
->s
.flags
& HB_BUF_FLAG_EOF
)
824 return HB_FILTER_DONE
;
827 // Get any pending subtitles and add them to the active
829 while ( ( sub
= hb_fifo_get( filter
->subtitle
->fifo_out
) ) )
831 hb_list_add( pv
->sub_list
, sub
);
834 ApplyPGSSubs( pv
, in
);
841 static int hb_rendersub_init( hb_filter_object_t
* filter
,
842 hb_filter_init_t
* init
)
844 filter
->private_data
= calloc( 1, sizeof(struct hb_filter_private_s
) );
845 hb_filter_private_t
* pv
= filter
->private_data
;
846 hb_subtitle_t
*subtitle
;
849 // Find the subtitle we need
850 for( ii
= 0; ii
< hb_list_count(init
->job
->list_subtitle
); ii
++ )
852 subtitle
= hb_list_item( init
->job
->list_subtitle
, ii
);
853 if( subtitle
&& subtitle
->config
.dest
== RENDERSUB
)
856 filter
->subtitle
= subtitle
;
857 pv
->type
= subtitle
->source
;
861 if( filter
->subtitle
== NULL
)
863 hb_log("rendersub: no subtitle marked for burn");
869 static int hb_rendersub_post_init( hb_filter_object_t
* filter
, hb_job_t
*job
)
871 hb_filter_private_t
* pv
= filter
->private_data
;
873 pv
->crop
[0] = job
->crop
[0];
874 pv
->crop
[1] = job
->crop
[1];
875 pv
->crop
[2] = job
->crop
[2];
876 pv
->crop
[3] = job
->crop
[3];
882 return vobsub_post_init( filter
, job
);
887 return ssa_post_init( filter
, job
);
894 return textsub_post_init( filter
, job
);
899 return cc608sub_post_init( filter
, job
);
904 return pgssub_post_init( filter
, job
);
909 hb_log("rendersub: unsupported subtitle format %d", pv
->type
);
916 static int hb_rendersub_work( hb_filter_object_t
* filter
,
917 hb_buffer_t
** buf_in
,
918 hb_buffer_t
** buf_out
)
920 hb_filter_private_t
* pv
= filter
->private_data
;
925 return vobsub_work( filter
, buf_in
, buf_out
);
930 return ssa_work( filter
, buf_in
, buf_out
);
938 return textsub_work( filter
, buf_in
, buf_out
);
943 return pgssub_work( filter
, buf_in
, buf_out
);
948 hb_error("rendersub: unsupported subtitle format %d", pv
->type
);
954 static void hb_rendersub_close( hb_filter_object_t
* filter
)
956 hb_filter_private_t
* pv
= filter
->private_data
;
961 vobsub_close( filter
);
974 textsub_close( filter
);
979 pgssub_close( filter
);
984 hb_error("rendersub: unsupported subtitle format %d", pv
->type
);