#! /bin/sh /usr/share/dpatch/dpatch-run ## 99-unnamed.dpatch by ## ## All lines beginning with `## DP:' are a description of the patch. ## DP: AFD processing. (Experimental.) @DPATCH@ diff --git a/src/post/planar/expand.c b/src/post/planar/expand.c --- a/src/post/planar/expand.c +++ b/src/post/planar/expand.c @@ -27,6 +27,7 @@ * */ +#include #include #include @@ -68,6 +69,8 @@ typedef struct expand_parameters_s { typedef struct expand_parameters_s { int enable_automatic_shift; int overlay_y_offset; + int afd_mode; + int afd_shoot_protect; double aspect; int centre_cut_out_mode; } expand_parameters_t; @@ -77,6 +80,10 @@ PARAM_ITEM(POST_PARAM_TYPE_BOOL, enable_ "enable automatic overlay shifting") PARAM_ITEM(POST_PARAM_TYPE_INT, overlay_y_offset, NULL, -500, 500, 0, "manually shift the overlay vertically") +PARAM_ITEM(POST_PARAM_TYPE_BOOL, afd_mode, NULL, 0, 1, 0, + "use AFD information if available") +PARAM_ITEM(POST_PARAM_TYPE_BOOL, afd_shoot_protect, NULL, 0, 1, 0, + "enable shoot&protect (intended for 4:3 display)") PARAM_ITEM(POST_PARAM_TYPE_DOUBLE, aspect, NULL, 1.0, 3.5, 0, "target aspect ratio") PARAM_ITEM(POST_PARAM_TYPE_BOOL, centre_cut_out_mode, NULL, 0, 1, 0, @@ -90,10 +97,17 @@ typedef struct post_expand_s { int enable_automatic_shift; int overlay_y_offset; + int afd_mode; + int afd_shoot_protect; double aspect; int top_bar_height; int centre_cut_out_mode; int cropping_active; + double stream_ratio, afd_ratio; + double prev_ratio; + int prev_afd; + int prev_shoot_protect; + int crop_x, crop_y; } post_expand_t; /* plugin class functions */ @@ -162,9 +176,13 @@ static post_plugin_t *expand_open_plugin this->enable_automatic_shift = 0; this->overlay_y_offset = 0; + this->afd_mode = 0; + this->afd_shoot_protect = 0; this->aspect = 4.0 / 3.0; this->centre_cut_out_mode = 0; this->cropping_active = 0; + this->crop_x = this->crop_y = 0; + this->prev_shoot_protect = -1; /* won't happen */ port = _x_post_intercept_video_port(&this->post, video_target[0], &input, &output); port->new_port.get_frame = expand_get_frame; @@ -209,6 +227,8 @@ static int expand_set_parameters(xine_po this->enable_automatic_shift = param->enable_automatic_shift; this->overlay_y_offset = param->overlay_y_offset; + this->afd_mode = param->afd_mode; + this->afd_shoot_protect = param->afd_shoot_protect; this->aspect = param->aspect; this->centre_cut_out_mode = param->centre_cut_out_mode; @@ -222,6 +242,8 @@ static int expand_get_parameters(xine_po param->enable_automatic_shift = this->enable_automatic_shift; param->overlay_y_offset = this->overlay_y_offset; + param->afd_mode = this->afd_mode; + param->afd_shoot_protect = this->afd_shoot_protect; param->aspect = this->aspect; param->centre_cut_out_mode = this->centre_cut_out_mode; @@ -273,13 +295,182 @@ static int is_pixel_black(vo_frame_t *fr } +/* Mode matrix: + * 4:3 16:9 + * Crop + * Nocrop + */ + +static inline int approx_eq (double a, double b) +{ + return fabs (a - b) < 1.0/64.0; +} + +static int translate_ratio(double ratio) +{ + if (approx_eq (ratio, 4.0/3.0)) + return 4; + if (approx_eq (ratio, 16.0/9.0)) + return 16; +/* + if (approx_eq (ratio, 14.0/9.0)) + return 14; +*/ + return 0; +} + +static int expand_afd(vo_frame_t *frame, xine_stream_t *stream) +{ + int afd = _x_stream_info_get_public(stream, XINE_STREAM_INFO_VIDEO_AFD); + post_video_port_t *port = (post_video_port_t *)frame->port; + post_expand_t *this = (post_expand_t *)port->post; + int ratio = translate_ratio (frame->ratio); + + if (afd == this->prev_afd && + (fabs (frame->ratio - this->prev_ratio) < 1.0 / 16.0) && + this->afd_shoot_protect == this->prev_shoot_protect) + goto unchanged; + + this->prev_afd = afd; + this->prev_ratio = frame->ratio; + + this->crop_x = 0; + this->crop_y = 0; + this->afd_ratio = 0; + this->cropping_active = 0; + + if (!ratio) + goto unchanged; + + switch (afd) + { + case XINE_VIDEO_AFD_NOT_PRESENT: + case XINE_VIDEO_AFD_SAME_AS_FRAME: + case XINE_VIDEO_AFD_RESERVED_12: + /* nothing to do */ + break; + + case XINE_VIDEO_AFD_4_3_CENTRE: + /* if stream is 16:9, crop it to 4:3 (3/4 width) */ + if (ratio == 16) + { + this->crop_x = frame->width / 8; + this->crop_y = 0; + this->afd_ratio = 4.0 / 3.0; + this->cropping_active = 1; + } + break; + + case XINE_VIDEO_AFD_16_9_CENTRE: + /* if stream is 4:3, crop it to 16:9 (3/4 height) */ + if (ratio == 4) + { + this->crop_x = 0; + this->crop_y = frame->height / 8; + this->afd_ratio = 16.0 / 9.0; + this->cropping_active = 1; + } + break; + + case XINE_VIDEO_AFD_14_9_CENTRE: + /* video is 14:9 - always crop */ + if (ratio == 4) + { + /* crop top & bottom (6/7 height) */ + this->crop_x = 0; + this->crop_y = frame->height / 14; + } + else /* ratio == 16 */ + { + /* crop sides (7/8 width) */ + this->crop_x = frame->width / 16; + this->crop_y = 0; + } + this->afd_ratio = 14.0 / 9.0; + this->cropping_active = 1; + break; + + case XINE_VIDEO_AFD_4_3_PROTECT_14_9: + /* optional cropping from 4:3 to 14:9 */ + this->crop_x = 0; + if (this->afd_shoot_protect) + { + this->crop_y = frame->height / 14; + this->afd_ratio = 14.0 / 9.0; + } + else + { + this->crop_y = 0; + this->afd_ratio = 4.0 / 3.0; + } + this->cropping_active = 1; + break; + + case XINE_VIDEO_AFD_16_9_PROTECT_14_9: + /* optional cropping from 16:9 to 14:9 */ + if (this->afd_shoot_protect) + { + this->crop_x = frame->width / 16; + this->afd_ratio = 14.0 / 9.0; + } + else + { + this->crop_x = 0; + this->afd_ratio = 16.0 / 9.0; + } + this->crop_y = 0; + this->cropping_active = 1; + break; + + case XINE_VIDEO_AFD_16_9_PROTECT_4_3: + /* optional cropping from 16:9 to 14:9 */ + if (this->afd_shoot_protect) + { + this->crop_x = frame->width / 8; + this->afd_ratio = 4.0 / 3.0; + } + else + { + this->crop_x = 0; + this->afd_ratio = 16.0 / 9.0; + } + this->crop_y = 0; + this->cropping_active = 1; + break; + + default: + /* unknown or reserved values; do nothing */ + break; + } + + /* DEBUG - development */ + (printf) ("AFD %d, stream = %d, using = %d, crop %d×%d\n", afd, + translate_ratio (frame->ratio), + translate_ratio (this->afd_ratio), + this->crop_x, this->crop_y); + +unchanged: + frame->crop_left += this->crop_x; + frame->crop_right += this->crop_x; + frame->crop_top += this->crop_y; + frame->crop_bottom += this->crop_y; + +// printf ("crop ←%d →%d ↑%d ↓%d\n", frame->crop_left, frame->crop_right, frame->crop_top, frame->crop_bottom); + + return this->cropping_active; +} + + static int expand_draw(vo_frame_t *frame, xine_stream_t *stream) { post_video_port_t *port = (post_video_port_t *)frame->port; post_expand_t *this = (post_expand_t *)port->post; int skip; - if (this->centre_cut_out_mode && !frame->bad_frame) + if (!frame->bad_frame && this->afd_mode && expand_afd (frame, stream)) + goto done; + + if (!frame->bad_frame && this->centre_cut_out_mode) { /* expected area of inner 4:3 image */ int centre_width = frame->width * (9 * 4) / (16 * 3); @@ -312,6 +503,8 @@ static int expand_draw(vo_frame_t *frame } } + done: + frame->ratio = this->aspect; _x_post_frame_copy_down(frame, frame->next); skip = frame->next->draw(frame->next, stream); @@ -336,12 +529,24 @@ static vo_frame_t *expand_get_frame(xine if (ratio <= 0.0) ratio = (double)width / (double)height; /* Calculate height of expanded frame */ - new_height = (double)height * ratio / this->aspect; + new_height = this->afd_mode ? height : ((double)height * ratio / this->aspect); new_height = (new_height + 1) & ~1; top_bar_height = (new_height - height) / 2; top_bar_height = (top_bar_height + 1) & ~1; this->top_bar_height = top_bar_height; + + if (this->afd_mode && + (format == XINE_IMGFMT_YV12 || format == XINE_IMGFMT_YUY2)) + { + frame = port->original_port->get_frame + (port->original_port, width, height, + this->afd_ratio ? this->afd_ratio : ratio, format, flags); + _x_post_inc_usage(port); + this->stream_ratio = frame->ratio = ratio; + frame = _x_post_intercept_video_frame(frame, port); + return frame; + } if (new_height > height && (format == XINE_IMGFMT_YV12 || format == XINE_IMGFMT_YUY2)) { @@ -404,7 +609,8 @@ static int expand_intercept_ovl(post_vid { post_expand_t *this = (post_expand_t *)port->post; - if (this->centre_cut_out_mode && this->cropping_active) return 0; + if ((this->centre_cut_out_mode | this->afd_mode) && this->cropping_active) + return 0; /* we always intercept overlay manager */ return 1;