4545local assdraw = require ' mp.assdraw'
4646local active = false
4747local active_mode = " " -- same possible values as opts.mode
48+ local rect_centered = false
49+ local rect_keepaspect = false
4850local needs_drawing = false
4951local crop_first_corner = nil -- in normalized video space
5052local crop_cursor = {
@@ -56,11 +58,28 @@ function redraw()
5658 needs_drawing = true
5759end
5860
59- function sort_corners (c1 , c2 )
60- local r1 , r2 = {}, {}
61- if c1 .x < c2 .x then r1 .x , r2 .x = c1 .x , c2 .x else r1 .x , r2 .x = c2 .x , c1 .x end
62- if c1 .y < c2 .y then r1 .y , r2 .y = c1 .y , c2 .y else r1 .y , r2 .y = c2 .y , c1 .y end
63- return r1 , r2
61+ function rect_from_two_points (p1 , p2 , centered , ratio )
62+ local c1 = {p1 .x , p1 .y }
63+ local c2 = {p2 .x , p2 .y }
64+ if ratio then
65+ -- adjust position of p2, such
66+ if math.abs (c2 [1 ] - c1 [1 ]) < ratio * math.abs (c2 [2 ] - c1 [2 ]) then
67+ local is_left = c2 [1 ] < c1 [1 ] and - 1 or 1
68+ c2 [1 ] = c1 [1 ] + is_left * math.abs (c2 [2 ] - c1 [2 ]) * ratio
69+ else
70+ local is_up = c2 [2 ] < c1 [2 ] and - 1 or 1
71+ c2 [2 ] = c1 [2 ] + is_up * math.abs (c2 [1 ] - c1 [1 ]) / ratio
72+ end
73+ end
74+ if centered then
75+ -- p1 is center => convert it into corner
76+ c1 [1 ] = c1 [1 ] - (c2 [1 ] - c1 [1 ])
77+ c1 [2 ] = c1 [2 ] - (c2 [2 ] - c1 [2 ])
78+ end
79+ -- sort corners
80+ if c1 [1 ] > c2 [1 ] then c1 [1 ], c2 [1 ] = c2 [1 ], c1 [1 ] end
81+ if c1 [2 ] > c2 [2 ] then c1 [2 ], c2 [2 ] = c2 [2 ], c1 [2 ] end
82+ return { x = c1 [1 ], y = c1 [2 ] }, { x = c2 [1 ], y = c2 [2 ] }
6483end
6584
6685function clamp (low , value , high )
@@ -94,23 +113,6 @@ function video_norm_to_screen(point, dim)
94113 }
95114end
96115
97- function position_to_ensure_ratio (moving , fixed , ratio )
98- -- corners are in screen coordinates
99- local x = moving .x
100- local y = moving .y
101- if math.abs (x - fixed .x ) < ratio * math.abs (y - fixed .y ) then
102- local is_left = x < fixed .x and - 1 or 1
103- x = fixed .x + is_left * math.abs (y - fixed .y ) * ratio
104- else
105- local is_up = y < fixed .y and - 1 or 1
106- y = fixed .y + is_up * math.abs (x - fixed .x ) / ratio
107- end
108- return {
109- x = x ,
110- y = y ,
111- }
112- end
113-
114116function draw_shade (ass , unshaded , window )
115117 ass :new_event ()
116118 ass :pos (0 , 0 )
@@ -212,19 +214,15 @@ function draw_crop_zone()
212214 x = crop_cursor .x ,
213215 y = crop_cursor .y ,
214216 }
215- if active_mode == " soft" then
216- if crop_first_corner then
217- cursor = position_to_ensure_ratio (cursor , video_norm_to_screen (crop_first_corner , dim ), dim .w / dim .h )
218- end
219- elseif active_mode == " hard" or active_mode == " delogo" then
220- cursor = clamp_point ({ x = dim .ml , y = dim .mt }, cursor , { x = dim .w - dim .mr , y = dim .h - dim .mb })
221- end
222217 local ass = assdraw .ass_new ()
223218
224219 if crop_first_corner and (opts .draw_shade or opts .draw_frame ) then
225- local first_corner = video_norm_to_screen (crop_first_corner , dim )
226220 local frame = {}
227- frame .top_left , frame .bottom_right = sort_corners (first_corner , cursor )
221+ frame .top_left , frame .bottom_right = rect_from_two_points (
222+ video_norm_to_screen (crop_first_corner , dim ),
223+ cursor ,
224+ rect_centered ,
225+ rect_keepaspect and dim .w / dim .h )
228226 -- don't draw shade over non-visible video parts
229227 if opts .draw_shade then
230228 local window = {
@@ -263,24 +261,30 @@ function draw_crop_zone()
263261 end
264262end
265263
266- function crop_video (x , y , w , h , dim )
264+ function crop_video (x1 , y1 , x2 , y2 )
267265 if active_mode == " soft" then
266+ local w = x2 - x1
267+ local h = y2 - y1
268268 local dim = mp .get_property_native (" osd-dimensions" )
269269 if not dim then return end
270270
271271 local zoom = mp .get_property_number (" video-zoom" )
272- local newZoom2 = math.log (dim .w * (2 ^ zoom ) / (dim .w - dim .ml - dim .mr ) / w ) / math.log (2 )
273272 local newZoom1 = math.log (dim .h * (2 ^ zoom ) / (dim .h - dim .mt - dim .mb ) / h ) / math.log (2 )
274- mp .set_property (" video-zoom" , (newZoom1 + newZoom2 ) / 2 ) -- they should be ~ the same, but let's not play favorites
275- mp .set_property (" video-pan-x" , 0.5 - (x + w / 2 ))
276- mp .set_property (" video-pan-y" , 0.5 - (y + h / 2 ))
273+ local newZoom2 = math.log (dim .w * (2 ^ zoom ) / (dim .w - dim .ml - dim .mr ) / w ) / math.log (2 )
274+ mp .set_property (" video-zoom" , math.min (newZoom1 , newZoom2 ))
275+ mp .set_property (" video-pan-x" , 0.5 - (x1 + w / 2 ))
276+ mp .set_property (" video-pan-y" , 0.5 - (y1 + h / 2 ))
277277 elseif active_mode == " hard" or active_mode == " delogo" then
278+ x1 = clamp (0 , x1 , 1 )
279+ y1 = clamp (0 , y1 , 1 )
280+ x2 = clamp (0 , x2 , 1 )
281+ y2 = clamp (0 , y2 , 1 )
278282 local vop = mp .get_property_native (" video-out-params" )
279283 local vf_table = mp .get_property_native (" vf" )
280- local x = math.floor (x * vop .w )
281- local y = math.floor (y * vop .h )
282- local w = math.floor (w * vop .w )
283- local h = math.floor (h * vop .h )
284+ local x = math.floor (x1 * vop .w + 0.5 )
285+ local y = math.floor (y1 * vop .h + 0.5 )
286+ local w = math.floor (( x2 - x1 ) * vop .w + 0.5 )
287+ local h = math.floor (( y2 - y1 ) * vop .h + 0.5 )
284288 if active_mode == " delogo" then
285289 -- delogo is a little special and needs some padding to function
286290 w = math.min (vop .w - 1 , w )
@@ -304,23 +308,19 @@ function update_crop_zone_state()
304308 cancel_crop ()
305309 return
306310 end
307- local corner
308- if active_mode == " soft" then
309- if crop_first_corner then
310- corner = position_to_ensure_ratio (crop_cursor , video_norm_to_screen (crop_first_corner , dim ), dim .w / dim .h )
311- else
312- corner = crop_cursor
313- end
314- elseif active_mode == " hard" or active_mode == " delogo" then
315- corner = clamp_point ({ x = dim .ml , y = dim .mt }, crop_cursor , { x = dim .w - dim .mr , y = dim .h - dim .mb })
316- end
317- local corner_video = screen_to_video_norm (corner , dim )
311+ local corner = crop_cursor
318312 if crop_first_corner == nil then
319- crop_first_corner = corner_video
313+ crop_first_corner = screen_to_video_norm ( crop_cursor , dim )
320314 redraw ()
321315 else
322- local c1 , c2 = sort_corners (crop_first_corner , corner_video )
323- crop_video (c1 .x , c1 .y , c2 .x - c1 .x , c2 .y - c1 .y )
316+ local c1 , c2 = rect_from_two_points (
317+ video_norm_to_screen (crop_first_corner , dim ),
318+ crop_cursor ,
319+ rect_centered ,
320+ rect_keepaspect and dim .w / dim .h )
321+ local c1norm = screen_to_video_norm (c1 , dim )
322+ local c2norm = screen_to_video_norm (c2 , dim )
323+ crop_video (c1norm .x , c1norm .y , c2norm .x , c2norm .y )
324324 cancel_crop ()
325325 end
326326end
0 commit comments