diff options
Diffstat (limited to 'libhb/rendersub.c')
-rw-r--r-- | libhb/rendersub.c | 222 |
1 files changed, 148 insertions, 74 deletions
diff --git a/libhb/rendersub.c b/libhb/rendersub.c index dee178d19..ab0fbcf76 100644 --- a/libhb/rendersub.c +++ b/libhb/rendersub.c @@ -11,24 +11,29 @@ #include "hbffmpeg.h" #include <ass/ass.h> +#define ABS(a) ((a) > 0 ? (a) : (-(a))) + struct hb_filter_private_s { // Common - int crop[4]; - int type; + int crop[4]; + int type; + struct SwsContext * sws; + int sws_width; + int sws_height; // VOBSUB - hb_list_t * sub_list; // List of active subs + hb_list_t * sub_list; // List of active subs // SSA - ASS_Library * ssa; - ASS_Renderer * renderer; - ASS_Track * ssaTrack; - uint8_t script_initialized; + ASS_Library * ssa; + ASS_Renderer * renderer; + ASS_Track * ssaTrack; + uint8_t script_initialized; // SRT - int line; - hb_buffer_t * current_sub; + int line; + hb_buffer_t * current_sub; }; // VOBSUB @@ -182,84 +187,144 @@ static void blend( hb_buffer_t *dst, hb_buffer_t *src, int left, int top ) // as the original title diminsions static void ApplySub( hb_filter_private_t * pv, hb_buffer_t * buf, hb_buffer_t * sub ) { - int top, left, margin_top, margin_percent; - - if ( !pv->ssa ) - { - /* - * Percent of height of picture that form a margin that subtitles - * should not be displayed within. - */ - margin_percent = 2; + blend( buf, sub, sub->f.x, sub->f.y ); +} - /* - * If necessary, move the subtitle so it is not in a cropped zone. - * When it won't fit, we center it so we lose as much on both ends. - * Otherwise we try to leave a 20px or 2% margin around it. - */ - margin_top = ( ( buf->f.height - pv->crop[0] - pv->crop[1] ) * - margin_percent ) / 100; +static hb_buffer_t * ScaleSubtitle(hb_filter_private_t *pv, + hb_buffer_t *sub, hb_buffer_t *buf) +{ + hb_buffer_t * scaled; + double xfactor = 1., yfactor = 1.; - if( margin_top > 20 ) - { - /* - * A maximum margin of 20px regardless of height of the picture. - */ - margin_top = 20; - } + // Do we need to rescale subtitles? + if (sub->f.window_width > 0 && sub->f.window_height > 0) + { - if( sub->f.height > buf->f.height - pv->crop[0] - pv->crop[1] - - ( margin_top * 2 ) ) - { - /* - * The subtitle won't fit in the cropped zone, so center - * it vertically so we fit in as much as we can. - */ - top = pv->crop[0] + ( buf->f.height - pv->crop[0] - - pv->crop[1] - sub->f.height ) / 2; - } - else if( sub->f.y < pv->crop[0] + margin_top ) + // TODO: Factor aspect ratio + // For now, assume subtitle and video PAR is the same. + xfactor = (double)buf->f.width / sub->f.window_width; + yfactor = (double)buf->f.height / sub->f.window_height; + // The video may have been cropped. This will make xfactor != yfactor + // even though video and subtitles are the same PAR. So use the + // larger of as the scale factor. + if (xfactor > yfactor) { - /* - * The subtitle fits in the cropped zone, but is currently positioned - * within our top margin, so move it outside of our margin. - */ - top = pv->crop[0] + margin_top; + yfactor = xfactor; } - else if( sub->f.y > buf->f.height - pv->crop[1] - margin_top - sub->f.height ) + else { - /* - * The subtitle fits in the cropped zone, and is not within the top - * margin but is within the bottom margin, so move it to be above - * the margin. - */ - top = buf->f.height - pv->crop[1] - margin_top - sub->f.height; + xfactor = yfactor; } - else + } + if (ABS(xfactor - 1) > 0.01 || ABS(yfactor - 1) > 0.01) + { + AVPicture pic_in, pic_out; + int width, height; + + width = sub->f.width * xfactor; + height = sub->f.height * yfactor; + scaled = hb_frame_buffer_init(AV_PIX_FMT_YUVA420P, width, height); + scaled->f.x = sub->f.x * xfactor; + scaled->f.y = sub->f.y * yfactor; + + hb_avpicture_fill(&pic_in, sub); + hb_avpicture_fill(&pic_out, scaled); + + if (pv->sws == NULL || + pv->sws_width != width || + pv->sws_height != height) { - /* - * The subtitle is fine where it is. - */ - top = sub->f.y; + if (pv->sws!= NULL) + sws_freeContext(pv->sws); + pv->sws = hb_sws_get_context( + sub->f.width, sub->f.height, sub->f.fmt, + scaled->f.width, scaled->f.height, sub->f.fmt, + SWS_LANCZOS|SWS_ACCURATE_RND); + pv->sws_width = width; + pv->sws_height = height; } + sws_scale(pv->sws, + (const uint8_t* const *)pic_in.data, pic_in.linesize, + 0, sub->f.height, pic_out.data, pic_out.linesize); + } + else + { + scaled = hb_buffer_dup(sub); + } - if( sub->f.width > buf->f.width - pv->crop[2] - pv->crop[3] - 40 ) - left = pv->crop[2] + ( buf->f.width - pv->crop[2] - - pv->crop[3] - sub->f.width ) / 2; - else if( sub->f.x < pv->crop[2] + 20 ) - left = pv->crop[2] + 20; - else if( sub->f.x > buf->f.width - pv->crop[3] - 20 - sub->f.width ) - left = buf->f.width - pv->crop[3] - 20 - sub->f.width; - else - left = sub->f.x; + int top, left, margin_top, margin_percent; + + /* + * Percent of height of picture that form a margin that subtitles + * should not be displayed within. + */ + margin_percent = 2; + + /* + * If necessary, move the subtitle so it is not in a cropped zone. + * When it won't fit, we center it so we lose as much on both ends. + * Otherwise we try to leave a 20px or 2% margin around it. + */ + margin_top = ( ( buf->f.height - pv->crop[0] - pv->crop[1] ) * + margin_percent ) / 100; + + if( margin_top > 20 ) + { + /* + * A maximum margin of 20px regardless of height of the picture. + */ + margin_top = 20; + } + + if( scaled->f.height > buf->f.height - pv->crop[0] - pv->crop[1] - + ( margin_top * 2 ) ) + { + /* + * The subtitle won't fit in the cropped zone, so center + * it vertically so we fit in as much as we can. + */ + top = pv->crop[0] + ( buf->f.height - pv->crop[0] - + pv->crop[1] - scaled->f.height ) / 2; + } + else if( scaled->f.y < pv->crop[0] + margin_top ) + { + /* + * The subtitle fits in the cropped zone, but is currently positioned + * within our top margin, so move it outside of our margin. + */ + top = pv->crop[0] + margin_top; + } + else if( scaled->f.y > buf->f.height - pv->crop[1] - margin_top - scaled->f.height ) + { + /* + * The subtitle fits in the cropped zone, and is not within the top + * margin but is within the bottom margin, so move it to be above + * the margin. + */ + top = buf->f.height - pv->crop[1] - margin_top - scaled->f.height; } else { - top = sub->f.y; - left = sub->f.x; + /* + * The subtitle is fine where it is. + */ + top = scaled->f.y; } - blend( buf, sub, left, top ); + if( scaled->f.width > buf->f.width - pv->crop[2] - pv->crop[3] - 40 ) + left = pv->crop[2] + ( buf->f.width - pv->crop[2] - + pv->crop[3] - scaled->f.width ) / 2; + else if( scaled->f.x < pv->crop[2] + 20 ) + left = pv->crop[2] + 20; + else if( scaled->f.x > buf->f.width - pv->crop[3] - 20 - scaled->f.width ) + left = buf->f.width - pv->crop[3] - 20 - scaled->f.width; + else + left = scaled->f.x; + + scaled->f.x = left; + scaled->f.y = top; + + return scaled; } // Assumes that the input buffer has the same dimensions @@ -290,7 +355,9 @@ static void ApplyVOBSubs( hb_filter_private_t * pv, hb_buffer_t * buf ) // after it. Render the subtitle into the frame. while ( sub ) { - ApplySub( pv, buf, sub ); + hb_buffer_t *scaled = ScaleSubtitle(pv, sub, buf); + ApplySub( pv, buf, scaled ); + hb_buffer_close(&scaled); sub = sub->next; } ii++; @@ -775,7 +842,9 @@ static void ApplyPGSSubs( hb_filter_private_t * pv, hb_buffer_t * buf ) sub = hb_list_item( pv->sub_list, 0 ); if ( sub->s.start <= buf->s.start ) { - ApplySub( pv, buf, sub ); + hb_buffer_t *scaled = ScaleSubtitle(pv, sub, buf); + ApplySub( pv, buf, scaled ); + hb_buffer_close(&scaled); } } } @@ -950,6 +1019,11 @@ static int hb_rendersub_work( hb_filter_object_t * filter, static void hb_rendersub_close( hb_filter_object_t * filter ) { hb_filter_private_t * pv = filter->private_data; + + if (pv->sws != NULL) + { + sws_freeContext(pv->sws); + } switch( pv->type ) { case VOBSUB: |