summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/interface-changes.rst1
-rw-r--r--DOCS/man/options.rst7
-rw-r--r--common/common.c31
-rw-r--r--common/common.h1
-rw-r--r--options/options.c1
-rw-r--r--options/options.h2
-rw-r--r--player/command.c8
-rw-r--r--player/video.c28
-rw-r--r--video/out/aspect.c15
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,