summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-06-14 23:59:53 +0200
committerwm4 <wm4@nowhere>2013-06-15 18:35:09 +0200
commit0e2fb5d8e87768defdc49c025ffe74fc2ec3265b (patch)
tree20a33e6c825c1ec51c8cffbd860c36d7bb1b8796 /video
parent60631acd29fb04a3ec1de2c9a52ac859a50bbce9 (diff)
downloadmpv-0e2fb5d8e87768defdc49c025ffe74fc2ec3265b.tar.bz2
mpv-0e2fb5d8e87768defdc49c025ffe74fc2ec3265b.tar.xz
vo: redo video display rectangle calculations
This code calculates the source/display video rectangle for scaling with most VOs. It's responsible for clipping the display rectangle against the screen and adjusting the source rectangle accordingly. Until now, it assumed that the video was centered on the screen. Change this so that any rectangle is possible. Basically, the clipping is extended to two sides (e.g. left and right), instead of handling both at the same time. The rounding behavior slightly changes. It seems to be slightly better than before. On the other hand, the video is not strictly centered anymore (due to different rounding on either side). When using panscan controls, the video can "jitter" by 1 or 2 pixels around the center as the panscan value is changed.
Diffstat (limited to 'video')
-rw-r--r--video/out/vo.c73
1 files changed, 49 insertions, 24 deletions
diff --git a/video/out/vo.c b/video/out/vo.c
index bf4f1660e1..7b722f354e 100644
--- a/video/out/vo.c
+++ b/video/out/vo.c
@@ -466,25 +466,53 @@ static void print_video_rect(struct vo *vo, struct mp_rect src,
dst.x0, dst.y0, vo->dwidth - dst.x1, vo->dheight - dst.y1);
}
+// Clamp [start, end) to range [0, size) with various fallbacks.
+static void clamp_size(int size, int *start, int *end)
+{
+ *start = FFMAX(0, *start);
+ *end = FFMIN(size, *end);
+ if (*start >= *end) {
+ *start = 0;
+ *end = 1;
+ }
+}
+
+// Round source to a multiple of 2, this is at least needed for vo_direct3d
+// and ATI cards.
+#define VID_SRC_ROUND_UP(x) (((x) + 1) & ~1)
+
static void src_dst_split_scaling(int src_size, int dst_size,
- int scaled_src_size, int *src_start,
- int *src_end, int *dst_start, int *dst_end)
+ int scaled_src_size,
+ int *src_start, int *src_end,
+ int *dst_start, int *dst_end,
+ int *osd_margin_a, int *osd_margin_b)
{
- if (scaled_src_size > dst_size) {
- int border = src_size * (scaled_src_size - dst_size) / scaled_src_size;
- // round to a multiple of 2, this is at least needed for vo_direct3d
- // and ATI cards
- border = (border / 2 + 1) & ~1;
- *src_start = border;
- *src_end = src_size - border;
+ *src_start = 0;
+ *src_end = src_size;
+ *dst_start = (dst_size - scaled_src_size) / 2;
+ *dst_end = *dst_start + scaled_src_size;
+
+ // Distance of screen frame to video
+ *osd_margin_a = *dst_start;
+ *osd_margin_b = dst_size - *dst_end;
+
+ // Clip to screen
+ int s_src = *src_end - *src_start;
+ int s_dst = *dst_end - *dst_start;
+ if (*dst_start < 0) {
+ int border = -(*dst_start) * s_src / s_dst;
+ *src_start += VID_SRC_ROUND_UP(border);
*dst_start = 0;
- *dst_end = dst_size;
- } else {
- *src_start = 0;
- *src_end = src_size;
- *dst_start = (dst_size - scaled_src_size) / 2;
- *dst_end = *dst_start + scaled_src_size;
}
+ if (*dst_end > dst_size) {
+ int border = (*dst_end - dst_size) * s_src / s_dst;
+ *src_end -= VID_SRC_ROUND_UP(border);
+ *dst_end = dst_size;
+ }
+
+ // For sanity: avoid bothering VOs with corner cases
+ clamp_size(src_size, src_start, src_end);
+ clamp_size(dst_size, dst_start, dst_end);
}
// Calculate the appropriate source and destination rectangle to
@@ -495,6 +523,7 @@ static void src_dst_split_scaling(int src_size, int dst_size,
void vo_get_src_dst_rects(struct vo *vo, struct mp_rect *out_src,
struct mp_rect *out_dst, struct mp_osd_res *out_osd)
{
+ struct mp_vo_opts *opts = vo->opts;
int src_w = vo->aspdat.orgw;
int src_h = vo->aspdat.orgh;
struct mp_rect dst = {0, 0, vo->dwidth, vo->dheight};
@@ -505,19 +534,15 @@ void vo_get_src_dst_rects(struct vo *vo, struct mp_rect *out_src,
.display_par = vo->aspdat.monitor_par,
.video_par = vo->aspdat.par,
};
- if (vo->opts->keepaspect) {
+ if (opts->keepaspect) {
int scaled_width, scaled_height;
aspect_calc_panscan(vo, &scaled_width, &scaled_height);
- int border_w = vo->dwidth - scaled_width;
- int border_h = vo->dheight - scaled_height;
- osd.ml = border_w / 2;
- osd.mt = border_h / 2;
- osd.mr = border_w - osd.ml;
- osd.mb = border_h - osd.mt;
src_dst_split_scaling(src_w, vo->dwidth, scaled_width,
- &src.x0, &src.x1, &dst.x0, &dst.x1);
+ &src.x0, &src.x1, &dst.x0, &dst.x1,
+ &osd.ml, &osd.mr);
src_dst_split_scaling(src_h, vo->dheight, scaled_height,
- &src.y0, &src.y1, &dst.y0, &dst.y1);
+ &src.y0, &src.y1, &dst.y0, &dst.y1,
+ &osd.mt, &osd.mb);
}
*out_src = src;