diff options
-rw-r--r-- | DOCS/interface-changes.rst | 1 | ||||
-rw-r--r-- | DOCS/man/options.rst | 7 | ||||
-rw-r--r-- | common/common.c | 31 | ||||
-rw-r--r-- | common/common.h | 1 | ||||
-rw-r--r-- | options/options.c | 1 | ||||
-rw-r--r-- | options/options.h | 2 | ||||
-rw-r--r-- | player/command.c | 8 | ||||
-rw-r--r-- | player/video.c | 28 | ||||
-rw-r--r-- | video/out/aspect.c | 15 |
9 files changed, 89 insertions, 5 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index d09073c1da..eeccd06851 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -54,6 +54,7 @@ Interface changes - add `hdr-metadata` property - change `--directory-mode` default to `lazy` - remove deprecated `video-aspect` property + - add `--video-crop` --- mpv 0.36.0 --- - add `--target-contrast` - Target luminance value is now also applied when ICC profile is used. diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index 34913ff9a7..ad4b5b89d7 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -1564,6 +1564,13 @@ Video software decoding and hardware decoding methods that copy the video back to system memory support all values between 0 and 359. +``--video-crop=<[W[xH]][+x+y]>``, ``--video-crop=<x:y>`` + Crop the video by starting at the x, y offset for w, h pixels. The crop is + applied to the source video rectangle (before anamorphic stretch) by the VO. + A crop rectangle that is not within the video rectangle will be ignored. + This works with hwdec, unlike the equivalent 'lavfi-crop'. Setting the crop + to '0x0' disables it. + ``--video-zoom=<value>`` Adjust the video display scale factor by the given value. The parameter is given log 2. For example, ``--video-zoom=0`` is unscaled, diff --git a/common/common.c b/common/common.c index 79f135a516..e59db7e906 100644 --- a/common/common.c +++ b/common/common.c @@ -126,6 +126,37 @@ bool mp_rect_equals(const struct mp_rect *rc1, const struct mp_rect *rc2) rc1->x1 == rc2->x1 && rc1->y1 == rc2->y1; } +// Rotate mp_rect by 90 degrees increments +void mp_rect_rotate(struct mp_rect *rc, int w, int h, int rotation) +{ + rotation %= 360; + + if (rotation >= 180) { + rotation -= 180; + MPSWAP(int, rc->x0, rc->x1); + MPSWAP(int, rc->y0, rc->y1); + } + + if (rotation == 90) { + *rc = (struct mp_rect) { + .x0 = rc->y1, + .y0 = rc->x0, + .x1 = rc->y0, + .y1 = rc->x1, + }; + } + + if (rc->x1 < rc->x0) { + rc->x0 = w - rc->x0; + rc->x1 = w - rc->x1; + } + + if (rc->y1 < rc->y0) { + rc->y0 = h - rc->y0; + rc->y1 = h - rc->y1; + } +} + // Compute rc1-rc2, put result in res_array, return number of rectangles in // res_array. In the worst case, there are 4 rectangles, so res_array must // provide that much storage space. diff --git a/common/common.h b/common/common.h index 93a8ded918..a30a5d6e0c 100644 --- a/common/common.h +++ b/common/common.h @@ -109,6 +109,7 @@ bool mp_rect_contains(struct mp_rect *rc, int x, int y); bool mp_rect_equals(const struct mp_rect *rc1, const struct mp_rect *rc2); int mp_rect_subtract(const struct mp_rect *rc1, const struct mp_rect *rc2, struct mp_rect res_array[4]); +void mp_rect_rotate(struct mp_rect *rc, int w, int h, int rotation); unsigned int mp_log2(uint32_t v); uint32_t mp_round_next_power_of_2(uint32_t v); diff --git a/options/options.c b/options/options.c index fd242f538b..4b8eb6dc3d 100644 --- a/options/options.c +++ b/options/options.c @@ -150,6 +150,7 @@ static const m_option_t mp_vo_opt_list[] = { {"video-margin-ratio-right", OPT_FLOAT(margin_x[1]), M_RANGE(0.0, 1.0)}, {"video-margin-ratio-top", OPT_FLOAT(margin_y[0]), M_RANGE(0.0, 1.0)}, {"video-margin-ratio-bottom", OPT_FLOAT(margin_y[1]), M_RANGE(0.0, 1.0)}, + {"video-crop", OPT_RECT(video_crop), .flags = UPDATE_IMGPAR}, {"video-unscaled", OPT_CHOICE(unscaled, {"no", 0}, {"yes", 1}, {"downscale-big", 2})}, {"wid", OPT_INT64(WinID)}, diff --git a/options/options.h b/options/options.h index 5e46a99b0b..3250729b48 100644 --- a/options/options.h +++ b/options/options.h @@ -73,6 +73,8 @@ typedef struct mp_vo_opts { struct m_geometry android_surface_size; int swapchain_depth; // max number of images to render ahead + + struct m_geometry video_crop; } mp_vo_opts; // Subtitle options needed by the subtitle decoders/renderers. diff --git a/player/command.c b/player/command.c index 55928eb2cd..55b0dd9449 100644 --- a/player/command.c +++ b/player/command.c @@ -2325,7 +2325,13 @@ static struct mp_image_params get_video_out_params(struct MPContext *mpctx) if (!mpctx->vo_chain) return (struct mp_image_params){0}; - return mpctx->vo_chain->filter->output_params; + struct mp_image_params o_params = mpctx->vo_chain->filter->output_params; + if (mpctx->video_out) { + m_rect_apply(&o_params.crop, o_params.w, o_params.h, + &mpctx->video_out->opts->video_crop); + } + + return o_params; } static int mp_property_vo_imgparams(void *ctx, struct m_property *prop, diff --git a/player/video.c b/player/video.c index a8556ba700..d9e371d9fd 100644 --- a/player/video.c +++ b/player/video.c @@ -1129,6 +1129,34 @@ void write_video(struct MPContext *mpctx) // Filter output is different from VO input? struct mp_image_params *p = &mpctx->next_frames[0]->params; + // Inject vo crop to notify and reconfig if needed + struct mp_rect rc; + m_rect_apply(&rc, p->w, p->h, &vo->opts->video_crop); + if (rc.x1 > 0 && rc.y1 > 0) + { + p->crop = rc; + if (!mp_image_crop_valid(p)) { + char *str = m_option_type_rect.print(NULL, &vo->opts->video_crop); + MP_WARN(vo, "Ignoring invalid --video-crop=%s for %dx%d image\n", + str, p->w, p->h); + talloc_free(str); + if (vo->params) { + p->crop = vo->params->crop; + vo->opts->video_crop = (struct m_geometry){ + .x = p->crop.x0, + .y = p->crop.y0, + .w = mp_rect_w(p->crop), + .h = mp_rect_h(p->crop), + .xy_valid = true, + .wh_valid = true, + }; + } + if (!mp_image_crop_valid(p)) { + p->crop = (struct mp_rect){0}; + vo->opts->video_crop = (struct m_geometry){0}; + } + } + } if (!vo->params || !mp_image_params_equal(p, vo->params)) { // Changing config deletes the current frame; wait until it's finished. if (vo_still_displaying(vo)) { diff --git a/video/out/aspect.c b/video/out/aspect.c index a295f8d3da..84fdb13b69 100644 --- a/video/out/aspect.c +++ b/video/out/aspect.c @@ -136,10 +136,6 @@ void mp_get_src_dst_rects(struct mp_log *log, struct mp_vo_opts *opts, int src_dw, src_dh; mp_image_params_get_dsize(video, &src_dw, &src_dh); - if (video->rotate % 180 == 90 && (vo_caps & VO_CAP_ROTATE90)) { - MPSWAP(int, src_w, src_h); - MPSWAP(int, src_dw, src_dh); - } window_w = MPMAX(1, window_w); window_h = MPMAX(1, window_h); @@ -155,6 +151,17 @@ void mp_get_src_dst_rects(struct mp_log *log, struct mp_vo_opts *opts, struct mp_rect dst = {0, 0, window_w, window_h}; struct mp_rect src = {0, 0, src_w, src_h}; + if (mp_image_crop_valid(video)) + src = video->crop; + + if (vo_caps & VO_CAP_ROTATE90) { + if (video->rotate % 180 == 90) { + MPSWAP(int, src_w, src_h); + MPSWAP(int, src_dw, src_dh); + } + mp_rect_rotate(&src, src_w, src_h, video->rotate); + } + struct mp_osd_res osd = { .w = window_w, .h = window_h, |