mirror of
https://github.com/vondas-network/videobeaux.git
synced 2025-12-05 15:30:02 +01:00
added lagkage and updating
This commit is contained in:
402
docs/docs-lagkage-examples.txt
Normal file
402
docs/docs-lagkage-examples.txt
Normal file
@@ -0,0 +1,402 @@
|
|||||||
|
LAGKAGE – CORE FUNCTIONALITY EXAMPLES (v2)
|
||||||
|
========================================
|
||||||
|
|
||||||
|
Program:
|
||||||
|
lagkage (Videobeaux)
|
||||||
|
|
||||||
|
Base usage pattern:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 -o out/NAME.mp4 --layout-json lagkage_layouts/LAYOUT.json --force
|
||||||
|
|
||||||
|
This file contains 20+ examples demonstrating:
|
||||||
|
- place vs free positioning
|
||||||
|
- images / videos / GIFs
|
||||||
|
- sequence_direction variations
|
||||||
|
- per-layer zoom
|
||||||
|
- per-layer crop
|
||||||
|
- combinations of the above
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 01 – Minimal logo + sticker (place + free)
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_minimal.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Top-right logo bug using place mode
|
||||||
|
- Free-position looping GIF sticker at lower-left area
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex01_minimal_logo_sticker.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_minimal.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 02 – Same layout, different base
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_minimal.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Reuses the same layout with a different base video (e.g. a show cut)
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base_show.mp4 \
|
||||||
|
-o out/ex02_minimal_logo_sticker_show.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_minimal.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 03 – Dual PIP + logo + lower third
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_pip_dual.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Logo in top-left
|
||||||
|
- Left and right PIP cameras using free mode
|
||||||
|
- Image lower-third band
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex03_pip_dual_show.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_pip_dual.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 04 – Dual PIP, backward stacking
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_pip_dual.json
|
||||||
|
(Edit JSON: "sequence_direction": "backward")
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Same positions as Example 03
|
||||||
|
- Backward stacking puts higher layer_number on top
|
||||||
|
- Good for making sure logo always ends above other overlays
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex04_pip_dual_backward.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_pip_dual.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 05 – Stickers + VHS noise overlay
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_stickers.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Full-frame looping VHS noise (low opacity)
|
||||||
|
- Circus and bunny GIF stickers
|
||||||
|
- Floating logo
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex05_stickers_vhs_noise.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_stickers.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 06 – Freeform showcase (cams, gifs, masks, noise)
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_freeform_showcase.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Multiple layers:
|
||||||
|
- top-right logo, top-left screen
|
||||||
|
- left/right PIP cams, mask on edge, lower band
|
||||||
|
- circus & bunny GIFs, center VHS noise
|
||||||
|
- All positioned using free mode coordinates
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex06_freeform_showcase.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_freeform_showcase.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 07 – 3-up horizontal video grid
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_grid_3up.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Three video tiles left/center/right
|
||||||
|
- Small logo in top-left
|
||||||
|
- Good for side-by-side comparison or triptych views
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex07_grid_3up.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_grid_3up.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 08 – 4-up grid (quad cam)
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_grid_4up.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Four camera feeds in a 2x2 grid
|
||||||
|
- Classic multi-cam surveillance / gallery layout
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex08_grid_4up.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_grid_4up.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 09 – Heavy VHS wash + mask + logo
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_vhs_heavy.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- VHS noise strongly overlayed (higher opacity)
|
||||||
|
- Center mask image
|
||||||
|
- Top-center logo
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex09_vhs_heavy_mask_logo.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_vhs_heavy.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 10 – Logo wall + mid screens
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_logo_wall.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Logos in all four corners using place mode
|
||||||
|
- Two mid-frame screen images using free mode
|
||||||
|
- Good for brand-heavy overlays
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex10_logo_wall.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_logo_wall.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 11 – Random spray of gifs + center logo
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_random_spray.json
|
||||||
|
(sequence_direction set to "random")
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Circus and bunny GIFs in four corners/edges
|
||||||
|
- Logo in center
|
||||||
|
- Randomized stacking order each run (depending on code behavior)
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex11_random_spray.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_random_spray.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 12 – Story mode: lower third + mask + tiny PIP
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_story_mode.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Wide lower-third band defined via free mode
|
||||||
|
- Side mask element
|
||||||
|
- Small corner PIP video + logo
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex12_story_mode_package.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_story_mode.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 13 – Freeform scatter demo
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_freeform_showcase.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Same freeform layout as Example 06
|
||||||
|
- Emphasis on scattered positioning to test boundaries
|
||||||
|
- Demonstrates partially off-screen elements
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex13_freeform_scatter.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_freeform_showcase.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 14 – Minimal zoom-only sticker
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_minimal_zoomcrop.json
|
||||||
|
(Create JSON from README example)
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Corner logo
|
||||||
|
- One GIF sticker with zoom > 1.0 but no crop, so content is pushed in
|
||||||
|
- Demonstrates per-layer zoom inside fixed box
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex14_minimal_zoom_sticker.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_minimal_zoomcrop.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 15 – Center-cropped GIF in the corner
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_cropped_gif_corner.json
|
||||||
|
(GIF layer has crop_x/crop_y/crop_w/crop_h set to central 50%)
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Uses only the core of a noisy or busy GIF
|
||||||
|
- Placed bottom-right as a cropped badge
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex15_cropped_gif_corner.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_cropped_gif_corner.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 16 – Zoomed-in PIP camera box
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_zoomed_pip.json
|
||||||
|
(PIP layer has zoom > 1.0)
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Small PIP box, but content is zoomed in
|
||||||
|
- Good for focusing on a region of the camera feed without changing frame size
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex16_zoomed_pip_box.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_zoomed_pip.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 17 – Combined crop + zoom (GIF)
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_crop_zoom_gif.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Layer crops to middle 60% of GIF
|
||||||
|
- Then applies zoom=1.8 inside overlay box
|
||||||
|
- Great for punching into the “interesting” part of the animation
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex17_crop_zoom_gif.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_crop_zoom_gif.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 18 – Split-screen: left static, right zoom+crop
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_splitscreen_zoomcrop.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Left side: standard PIP video
|
||||||
|
- Right side: same video source but with crop+zoom on a different region
|
||||||
|
- Demonstrates comparative views of the same source file
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex18_splitscreen_zoomcrop.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_splitscreen_zoomcrop.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 19 – Multi-logo scatter + zoomed center logo
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_logo_scatter_zoom_center.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Logos in corners and midpoints using place + free
|
||||||
|
- Center logo uses zoom to feel larger within a fixed box
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex19_logo_scatter_zoom_center.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_logo_scatter_zoom_center.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------
|
||||||
|
EXAMPLE 20 – Full package: PIPs, stickers, crop+zoom, noise
|
||||||
|
------------------------------------------------------------
|
||||||
|
|
||||||
|
Layout:
|
||||||
|
lagkage_layouts/layout_full_package_showcase.json
|
||||||
|
|
||||||
|
Description:
|
||||||
|
- Combines:
|
||||||
|
- Base logo
|
||||||
|
- Dual PIPs
|
||||||
|
- Multiple GIF stickers (some cropped, some zoomed)
|
||||||
|
- VHS noise layer at low opacity
|
||||||
|
- Designed as an “everything on” stress test for lagkage
|
||||||
|
|
||||||
|
Command:
|
||||||
|
videobeaux -P lagkage -i media/base.mp4 \
|
||||||
|
-o out/ex20_full_package_showcase.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_full_package_showcase.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
|
||||||
|
END
|
||||||
BIN
lagkage_all_layouts_zoomcrop_examples.zip
Normal file
BIN
lagkage_all_layouts_zoomcrop_examples.zip
Normal file
Binary file not shown.
88
lagkage_examples_zoomcrop.txt
Normal file
88
lagkage_examples_zoomcrop.txt
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
Lagkage Zoom + Crop Example Commands
|
||||||
|
====================================
|
||||||
|
|
||||||
|
These examples assume:
|
||||||
|
- You are in the project root.
|
||||||
|
- Base video is at: media/base.mp4
|
||||||
|
- JSON layouts are in: lagkage_layouts/
|
||||||
|
- Output directory: out/
|
||||||
|
|
||||||
|
1) Corner logo with zoom
|
||||||
|
------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex01_logo_corner_zoom.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex01_logo_corner_zoom.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
2) GIF sticker with zoom + crop
|
||||||
|
-------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex02_gif_zoomcrop_sticker.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex02_gif_zoomcrop_sticker.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
3) Dual PIP, right pane zoomed
|
||||||
|
------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex03_dual_pip_zoom_right.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex03_dual_pip_zoom_right.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
4) Lower-third band via crop
|
||||||
|
----------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex04_lower_third_crop_band.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex04_lower_third_crop_band.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
5) Center mask, cropped + zoomed
|
||||||
|
--------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex05_mask_crop_zoom_center.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex05_mask_crop_zoom_center.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
6) Freeform spray (GIFs + logo, random sequence)
|
||||||
|
------------------------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex06_freeform_spray_zoom.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex06_freeform_spray_zoom.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
7) Logo grid with zoomed center
|
||||||
|
-------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex07_logo_grid_zoom_center.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex07_logo_grid_zoom_center.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
8) Story mode: band + zoomed PIP + logo
|
||||||
|
---------------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex08_story_mode_zoom.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex08_story_mode_zoom.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
9) Split-screen: left zoom+crop, right normal
|
||||||
|
---------------------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex09_split_screen_zoom_left.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex09_split_screen_zoom_left.json \
|
||||||
|
--force
|
||||||
|
|
||||||
|
10) Full showcase (logos, bands, PIPs, GIFs)
|
||||||
|
--------------------------------------------
|
||||||
|
videobeaux -P lagkage \
|
||||||
|
-i media/base.mp4 \
|
||||||
|
-o out/ex10_full_showcase_zoomcrop.mp4 \
|
||||||
|
--layout-json lagkage_layouts/layout_ex10_full_showcase_zoomcrop.json \
|
||||||
|
--force
|
||||||
93
lagkage_layouts/layout_big_6.json
Normal file
93
lagkage_layouts/layout_big_6.json
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_top_right_free",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 20,
|
||||||
|
"pos_y": 420,
|
||||||
|
"size": 30,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "cropped_circus",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_right",
|
||||||
|
"size": 20,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.0,
|
||||||
|
"crop_x": 25,
|
||||||
|
"crop_y": 25,
|
||||||
|
"crop_w": 50,
|
||||||
|
"crop_h": 50
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "zoomed_bunny",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 200,
|
||||||
|
"pos_y": 500,
|
||||||
|
"size": 15,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 2.0
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
"layer_number": 6,
|
||||||
|
"name": "gross_lower_band_free",
|
||||||
|
"filename": "../media/gross.jpg",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 180,
|
||||||
|
"pos_y": 180,
|
||||||
|
"size": 25,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 7,
|
||||||
|
"name": "circus_sticker_top_center_free",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 60,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 50,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 8,
|
||||||
|
"name": "bunny_sticker_right_mid_free",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 50,
|
||||||
|
"pos_y": 365,
|
||||||
|
"size": 75,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 9,
|
||||||
|
"name": "vhs_noise_center_free",
|
||||||
|
"filename": "../media/media.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 175,
|
||||||
|
"pos_y": 350,
|
||||||
|
"size": 60,
|
||||||
|
"opacity": 0.3,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
34
lagkage_layouts/layout_crop_zoom_gif.json
Normal file
34
lagkage_layouts/layout_crop_zoom_gif.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_top_center",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 840,
|
||||||
|
"pos_y": 40,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "crop_zoom_circus",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 260,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 22,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.8,
|
||||||
|
"crop_x": 20,
|
||||||
|
"crop_y": 20,
|
||||||
|
"crop_w": 60,
|
||||||
|
"crop_h": 60,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
31
lagkage_layouts/layout_cropped_gif_corner.json
Normal file
31
lagkage_layouts/layout_cropped_gif_corner.json
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "corner_logo",
|
||||||
|
"filename": "../media/logo.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "cropped_circus_corner",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_right",
|
||||||
|
"size": 20,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"crop_x": 25,
|
||||||
|
"crop_y": 25,
|
||||||
|
"crop_w": 50,
|
||||||
|
"crop_h": 50,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
16
lagkage_layouts/layout_ex01_logo_corner_zoom.json
Normal file
16
lagkage_layouts/layout_ex01_logo_corner_zoom.json
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_zoom_top_right",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 42,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"zoom": 4.5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
21
lagkage_layouts/layout_ex02_gif_zoomcrop_sticker.json
Normal file
21
lagkage_layouts/layout_ex02_gif_zoomcrop_sticker.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "gif_zoomcrop_sticker",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 150,
|
||||||
|
"pos_y": 420,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.8,
|
||||||
|
"crop_x": 10,
|
||||||
|
"crop_y": 10,
|
||||||
|
"crop_w": 80,
|
||||||
|
"crop_h": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
28
lagkage_layouts/layout_ex03_dual_pip_zoom_right.json
Normal file
28
lagkage_layouts/layout_ex03_dual_pip_zoom_right.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "pip_left_normal",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 28,
|
||||||
|
"opacity": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_right_zoomed",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1180,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 28,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.7
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
lagkage_layouts/layout_ex04_lower_third_crop_band.json
Normal file
20
lagkage_layouts/layout_ex04_lower_third_crop_band.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "lower_third_band_crop",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 260,
|
||||||
|
"pos_y": 780,
|
||||||
|
"size": 54,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"crop_x": 0,
|
||||||
|
"crop_y": 20,
|
||||||
|
"crop_w": 100,
|
||||||
|
"crop_h": 60
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
20
lagkage_layouts/layout_ex05_mask_crop_zoom_center.json
Normal file
20
lagkage_layouts/layout_ex05_mask_crop_zoom_center.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "mask_center_zoomcrop",
|
||||||
|
"filename": "../media/mask1.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "center",
|
||||||
|
"size": 30,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"zoom": 1.6,
|
||||||
|
"crop_x": 10,
|
||||||
|
"crop_y": 10,
|
||||||
|
"crop_w": 80,
|
||||||
|
"crop_h": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
39
lagkage_layouts/layout_ex06_freeform_spray_zoom.json
Normal file
39
lagkage_layouts/layout_ex06_freeform_spray_zoom.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "random",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "circus_left_zoom",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 120,
|
||||||
|
"pos_y": 200,
|
||||||
|
"size": 20,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "bunny_right_zoom",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 100,
|
||||||
|
"pos_y": 320,
|
||||||
|
"size": 26,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 2.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "logo_center",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "center",
|
||||||
|
"size": 48,
|
||||||
|
"opacity": 4.95
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
56
lagkage_layouts/layout_ex07_logo_grid_zoom_center.json
Normal file
56
lagkage_layouts/layout_ex07_logo_grid_zoom_center.json
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_tl",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "logo_tr",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "logo_bl",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "logo_br",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_right",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "logo_center_zoom",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "center",
|
||||||
|
"size": 16,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"zoom": 1.7
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
37
lagkage_layouts/layout_ex08_story_mode_zoom.json
Normal file
37
lagkage_layouts/layout_ex08_story_mode_zoom.json
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "band_bottom",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 220,
|
||||||
|
"pos_y": 800,
|
||||||
|
"size": 60,
|
||||||
|
"opacity": 0.95
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_top_right_zoom",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 22,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.6
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "logo_top_left",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 12,
|
||||||
|
"opacity": 0.95
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
32
lagkage_layouts/layout_ex09_split_screen_zoom_left.json
Normal file
32
lagkage_layouts/layout_ex09_split_screen_zoom_left.json
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "pip_left_zoomcrop",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 42,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.8,
|
||||||
|
"crop_x": 10,
|
||||||
|
"crop_y": 10,
|
||||||
|
"crop_w": 80,
|
||||||
|
"crop_h": 80
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_right_normal",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1040,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 42,
|
||||||
|
"opacity": 1.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
76
lagkage_layouts/layout_ex10_full_showcase_zoomcrop.json
Normal file
76
lagkage_layouts/layout_ex10_full_showcase_zoomcrop.json
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "corner_logo",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.95
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_left",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 120,
|
||||||
|
"pos_y": 220,
|
||||||
|
"size": 24,
|
||||||
|
"opacity": 1.0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "pip_right_zoom",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1180,
|
||||||
|
"pos_y": 220,
|
||||||
|
"size": 24,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "lower_third_band",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 260,
|
||||||
|
"pos_y": 780,
|
||||||
|
"size": 54,
|
||||||
|
"opacity": 0.95
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "circus_zoomcrop",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 420,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.8,
|
||||||
|
"crop_x": 20,
|
||||||
|
"crop_y": 20,
|
||||||
|
"crop_w": 60,
|
||||||
|
"crop_h": 60
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 6,
|
||||||
|
"name": "bunny_free",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1320,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 16,
|
||||||
|
"opacity": 1.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
113
lagkage_layouts/layout_freeform_showcase.json
Normal file
113
lagkage_layouts/layout_freeform_showcase.json
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_top_right_free",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1500,
|
||||||
|
"pos_y": 40,
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "screen_top_left_free",
|
||||||
|
"filename": "../media/screen.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 120,
|
||||||
|
"pos_y": 70,
|
||||||
|
"size": 12,
|
||||||
|
"opacity": 0.8,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "pip_cam_a_left_mid_free",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 260,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 24,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "pip_cam_b_right_low_free",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1180,
|
||||||
|
"pos_y": 540,
|
||||||
|
"size": 34,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "mask_left_edge_half_off_free",
|
||||||
|
"filename": "../media/mask1.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": -50,
|
||||||
|
"pos_y": 360,
|
||||||
|
"size": 22,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 6,
|
||||||
|
"name": "gross_lower_band_free",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 340,
|
||||||
|
"pos_y": 780,
|
||||||
|
"size": 50,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 7,
|
||||||
|
"name": "circus_sticker_top_center_free",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 760,
|
||||||
|
"pos_y": 120,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 8,
|
||||||
|
"name": "bunny_sticker_right_mid_free",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1450,
|
||||||
|
"pos_y": 320,
|
||||||
|
"size": 13,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 9,
|
||||||
|
"name": "vhs_noise_center_free",
|
||||||
|
"filename": "../media/media.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 0,
|
||||||
|
"pos_y": 0,
|
||||||
|
"size": 110,
|
||||||
|
"opacity": 0.3,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
106
lagkage_layouts/layout_full_package_showcase.json
Normal file
106
lagkage_layouts/layout_full_package_showcase.json
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "corner_logo",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_left",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 120,
|
||||||
|
"pos_y": 200,
|
||||||
|
"size": 24,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "pip_right",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1180,
|
||||||
|
"pos_y": 200,
|
||||||
|
"size": 24,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.4,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "lower_third_band",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 260,
|
||||||
|
"pos_y": 780,
|
||||||
|
"size": 54,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "mask_left_edge",
|
||||||
|
"filename": "../media/mask1.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": -40,
|
||||||
|
"pos_y": 320,
|
||||||
|
"size": 26,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 6,
|
||||||
|
"name": "circus_sticker_zoomcrop",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 420,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.8,
|
||||||
|
"crop_x": 20,
|
||||||
|
"crop_y": 20,
|
||||||
|
"crop_w": 60,
|
||||||
|
"crop_h": 60,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 7,
|
||||||
|
"name": "bunny_sticker_free",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1320,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 16,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 8,
|
||||||
|
"name": "vhs_noise_background",
|
||||||
|
"filename": "../media/media.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 0,
|
||||||
|
"pos_y": 0,
|
||||||
|
"size": 110,
|
||||||
|
"opacity": 0.3,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
52
lagkage_layouts/layout_grid_3up.json
Normal file
52
lagkage_layouts/layout_grid_3up.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_top_left_small",
|
||||||
|
"filename": "../media/logo.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "tile_left",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 28,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "tile_center",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 640,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 28,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "tile_right",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1200,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 28,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
53
lagkage_layouts/layout_grid_4up.json
Normal file
53
lagkage_layouts/layout_grid_4up.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "cam_tl",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 80,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "cam_tr",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1040,
|
||||||
|
"pos_y": 80,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "cam_bl",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 540,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "cam_br",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1040,
|
||||||
|
"pos_y": 540,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
85
lagkage_layouts/layout_logo_scatter_zoom_center.json
Normal file
85
lagkage_layouts/layout_logo_scatter_zoom_center.json
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_tl",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "logo_tr",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "logo_bl",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "logo_br",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_right",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "logo_mid_left",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 220,
|
||||||
|
"pos_y": 360,
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 6,
|
||||||
|
"name": "logo_mid_right",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1400,
|
||||||
|
"pos_y": 360,
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 7,
|
||||||
|
"name": "logo_center_zoomed",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "center",
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"zoom": 1.6,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
73
lagkage_layouts/layout_logo_wall.json
Normal file
73
lagkage_layouts/layout_logo_wall.json
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_tl",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "logo_tr",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "logo_bl",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "logo_br",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "bottom_right",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "screen_mid_left",
|
||||||
|
"filename": "../media/screen.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 200,
|
||||||
|
"pos_y": 300,
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.8,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 6,
|
||||||
|
"name": "screen_mid_right",
|
||||||
|
"filename": "../media/screen.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1300,
|
||||||
|
"pos_y": 300,
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.8,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
28
lagkage_layouts/layout_minimal.json
Normal file
28
lagkage_layouts/layout_minimal.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "corner_logo",
|
||||||
|
"filename": "../media/logo.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 12,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "looping_sticker",
|
||||||
|
"filename": "../media/sticker.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 160,
|
||||||
|
"pos_y": 420,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
33
lagkage_layouts/layout_minimal_zoomcrop.json
Normal file
33
lagkage_layouts/layout_minimal_zoomcrop.json
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "corner_logo",
|
||||||
|
"filename": "../media/logo.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 12,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "zoomcrop_sticker",
|
||||||
|
"filename": "../media/sticker.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 160,
|
||||||
|
"pos_y": 420,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.5,
|
||||||
|
"crop_x": 10,
|
||||||
|
"crop_y": 10,
|
||||||
|
"crop_w": 80,
|
||||||
|
"crop_h": 80,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
52
lagkage_layouts/layout_pip_dual.json
Normal file
52
lagkage_layouts/layout_pip_dual.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "logo_top_left",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 16,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_cam_left",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 120,
|
||||||
|
"size": 26,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "pip_cam_right",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1180,
|
||||||
|
"pos_y": 120,
|
||||||
|
"size": 26,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "lower_third_band",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 260,
|
||||||
|
"pos_y": 780,
|
||||||
|
"size": 54,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
64
lagkage_layouts/layout_random_spray.json
Normal file
64
lagkage_layouts/layout_random_spray.json
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "random",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "circus_left",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 120,
|
||||||
|
"pos_y": 200,
|
||||||
|
"size": 22,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "circus_right",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1400,
|
||||||
|
"pos_y": 100,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "bunny_low_left",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 640,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "bunny_low_right",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1480,
|
||||||
|
"pos_y": 640,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 5,
|
||||||
|
"name": "logo_center",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "center",
|
||||||
|
"size": 20,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
34
lagkage_layouts/layout_splitscreen_zoomcrop.json
Normal file
34
lagkage_layouts/layout_splitscreen_zoomcrop.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "pip_left_normal",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 80,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "pip_right_zoomcrop",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1040,
|
||||||
|
"pos_y": 160,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.6,
|
||||||
|
"crop_x": 15,
|
||||||
|
"crop_y": 15,
|
||||||
|
"crop_w": 70,
|
||||||
|
"crop_h": 70,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
53
lagkage_layouts/layout_stickers.json
Normal file
53
lagkage_layouts/layout_stickers.json
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "vhs_noise_center_overlay",
|
||||||
|
"filename": "../media/media.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 0,
|
||||||
|
"pos_y": 0,
|
||||||
|
"size": 110,
|
||||||
|
"opacity": 0.3,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "circus_sticker",
|
||||||
|
"filename": "../media/circus.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 220,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "bunny_sticker",
|
||||||
|
"filename": "../media/bunny.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1460,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "logo_floating",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1500,
|
||||||
|
"pos_y": 40,
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
51
lagkage_layouts/layout_story_mode.json
Normal file
51
lagkage_layouts/layout_story_mode.json
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "lower_third_band",
|
||||||
|
"filename": "../media/gross.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 200,
|
||||||
|
"pos_y": 800,
|
||||||
|
"size": 60,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "mask_right_mid",
|
||||||
|
"filename": "../media/mask1.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 1200,
|
||||||
|
"pos_y": 360,
|
||||||
|
"size": 28,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "pip_corner_small",
|
||||||
|
"filename": "../media/faith.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 20,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 4,
|
||||||
|
"name": "logo_top_left_small",
|
||||||
|
"filename": "../media/logo.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 10,
|
||||||
|
"opacity": 0.9,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
41
lagkage_layouts/layout_vhs_heavy.json
Normal file
41
lagkage_layouts/layout_vhs_heavy.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "vhs_noise_full",
|
||||||
|
"filename": "../media/media.gif",
|
||||||
|
"type": "gif",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 0,
|
||||||
|
"pos_y": 0,
|
||||||
|
"size": 120,
|
||||||
|
"opacity": 0.5,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "mask_center",
|
||||||
|
"filename": "../media/mask1.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 640,
|
||||||
|
"pos_y": 260,
|
||||||
|
"size": 40,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 3,
|
||||||
|
"name": "logo_top_center",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "free",
|
||||||
|
"pos_x": 840,
|
||||||
|
"pos_y": 40,
|
||||||
|
"size": 18,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
28
lagkage_layouts/layout_zoomed_pip.json
Normal file
28
lagkage_layouts/layout_zoomed_pip.json
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
{
|
||||||
|
"sequence_direction": "forward",
|
||||||
|
"layers": [
|
||||||
|
{
|
||||||
|
"layer_number": 1,
|
||||||
|
"name": "pip_zoomed_small",
|
||||||
|
"filename": "../media/schwwaaa.mp4",
|
||||||
|
"type": "video",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_right",
|
||||||
|
"size": 22,
|
||||||
|
"opacity": 1.0,
|
||||||
|
"zoom": 1.8,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"layer_number": 2,
|
||||||
|
"name": "logo_top_left",
|
||||||
|
"filename": "../media/reem.png",
|
||||||
|
"type": "img",
|
||||||
|
"mode": "place",
|
||||||
|
"place": "top_left",
|
||||||
|
"size": 14,
|
||||||
|
"opacity": 0.95,
|
||||||
|
"blend_mode": "normal"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,13 +3,14 @@
|
|||||||
# Compose multiple visual layers (images/gifs/videos) on top of a base video
|
# Compose multiple visual layers (images/gifs/videos) on top of a base video
|
||||||
# using a single JSON layout file.
|
# using a single JSON layout file.
|
||||||
#
|
#
|
||||||
# GIF layers are preprocessed into finite MP4s that loop for roughly the base
|
# GIF layers are preprocessed into finite videos that loop for roughly the base
|
||||||
# video duration, so the main overlay graph stays simple and stable.
|
# video duration, so the main overlay graph stays simple and stable.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import subprocess
|
import subprocess
|
||||||
|
import tempfile
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from videobeaux.utils.ffmpeg_operations import run_ffmpeg_with_progress
|
from videobeaux.utils.ffmpeg_operations import run_ffmpeg_with_progress
|
||||||
@@ -17,155 +18,185 @@ from videobeaux.utils.ffmpeg_operations import run_ffmpeg_with_progress
|
|||||||
|
|
||||||
def register_arguments(parser):
|
def register_arguments(parser):
|
||||||
parser.description = (
|
parser.description = (
|
||||||
"Compose multiple visual layers (images/gifs/videos) on a base video "
|
"Compose a base video with layered media defined by a JSON layout "
|
||||||
"using a JSON layout file. All layers are sized & positioned relative "
|
"(images / videos / GIFs) using the lagkage compositor."
|
||||||
"to the base video dimensions."
|
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--layout-json",
|
"--layout-json",
|
||||||
|
dest="layout_json",
|
||||||
required=True,
|
required=True,
|
||||||
help="Path to JSON layout describing all layers."
|
type=str,
|
||||||
|
help="Path to layout JSON describing layers.",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--sequence-direction",
|
"--sequence-direction",
|
||||||
|
dest="sequence_direction",
|
||||||
choices=["forward", "backward", "random"],
|
choices=["forward", "backward", "random"],
|
||||||
help="Override sequence_direction in the JSON (optional)."
|
default=None,
|
||||||
|
help="Override sequence_direction from JSON (forward|backward|random).",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _load_layout(path: Path):
|
# ----------------- ffprobe helpers -----------------
|
||||||
with open(path, "r", encoding="utf-8") as f:
|
|
||||||
layout = json.load(f)
|
|
||||||
if "layers" not in layout or not layout["layers"]:
|
|
||||||
raise ValueError("Layout JSON must contain a non-empty 'layers' array.")
|
|
||||||
return layout
|
|
||||||
|
|
||||||
|
|
||||||
def _resolve_sequence(layout, override=None):
|
|
||||||
seq = override or layout.get("sequence_direction", "forward")
|
|
||||||
layers = layout["layers"]
|
|
||||||
layers_sorted = sorted(layers, key=lambda L: L.get("layer_number", 0))
|
|
||||||
|
|
||||||
if seq == "forward":
|
|
||||||
ordered = layers_sorted
|
|
||||||
elif seq == "backward":
|
|
||||||
ordered = list(reversed(layers_sorted))
|
|
||||||
elif seq == "random":
|
|
||||||
ordered = layers_sorted[:]
|
|
||||||
random.shuffle(ordered)
|
|
||||||
else:
|
|
||||||
ordered = layers_sorted
|
|
||||||
|
|
||||||
return seq, ordered
|
|
||||||
|
|
||||||
|
|
||||||
def _probe_base_info(path: str):
|
def _probe_base_info(path: str):
|
||||||
"""Return (width, height, duration_seconds) for the base video."""
|
"""
|
||||||
|
Return (width, height, duration_seconds) for the base video.
|
||||||
|
"""
|
||||||
cmd = [
|
cmd = [
|
||||||
"ffprobe",
|
"ffprobe",
|
||||||
"-v", "error",
|
"-v",
|
||||||
"-select_streams", "v:0",
|
"error",
|
||||||
"-show_entries", "stream=width,height",
|
"-select_streams",
|
||||||
"-show_entries", "format=duration",
|
"v:0",
|
||||||
"-of", "json",
|
"-show_entries",
|
||||||
|
"stream=width,height",
|
||||||
|
"-show_entries",
|
||||||
|
"format=duration",
|
||||||
|
"-of",
|
||||||
|
"json",
|
||||||
path,
|
path,
|
||||||
]
|
]
|
||||||
proc = subprocess.run(cmd, capture_output=True, text=True)
|
proc = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise RuntimeError(
|
raise RuntimeError(f"ffprobe failed for base {path}: {proc.stderr}")
|
||||||
f"ffprobe failed for {path} (code {proc.returncode}): {proc.stderr}"
|
info = json.loads(proc.stdout)
|
||||||
)
|
|
||||||
|
|
||||||
data = json.loads(proc.stdout)
|
|
||||||
streams = data.get("streams") or []
|
|
||||||
if not streams:
|
|
||||||
raise RuntimeError(f"No video stream found in {path}")
|
|
||||||
|
|
||||||
s0 = streams[0]
|
|
||||||
width = int(s0.get("width", 0) or 0)
|
|
||||||
height = int(s0.get("height", 0) or 0)
|
|
||||||
if width <= 0 or height <= 0:
|
|
||||||
raise RuntimeError(f"Invalid video size from ffprobe for {path}: {width}x{height}")
|
|
||||||
|
|
||||||
fmt = data.get("format") or {}
|
|
||||||
dur_str = fmt.get("duration") or "0"
|
|
||||||
try:
|
|
||||||
duration = float(dur_str)
|
|
||||||
except ValueError:
|
|
||||||
duration = 0.0
|
|
||||||
|
|
||||||
if duration <= 0:
|
|
||||||
duration = 0.0
|
|
||||||
|
|
||||||
|
width = int(info["streams"][0]["width"])
|
||||||
|
height = int(info["streams"][0]["height"])
|
||||||
|
duration = float(info["format"]["duration"])
|
||||||
return width, height, duration
|
return width, height, duration
|
||||||
|
|
||||||
|
|
||||||
def _place_expr(layer):
|
def _probe_video_size(path: str):
|
||||||
"""Return (x, y) expressions for the overlay filter."""
|
"""
|
||||||
mode = layer.get("mode", "free")
|
Return (width, height) of the first video/image stream.
|
||||||
|
"""
|
||||||
|
cmd = [
|
||||||
|
"ffprobe",
|
||||||
|
"-v",
|
||||||
|
"error",
|
||||||
|
"-select_streams",
|
||||||
|
"v:0",
|
||||||
|
"-show_entries",
|
||||||
|
"stream=width,height",
|
||||||
|
"-of",
|
||||||
|
"csv=s=x:p=0",
|
||||||
|
path,
|
||||||
|
]
|
||||||
|
proc = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
if proc.returncode != 0:
|
||||||
|
raise RuntimeError(f"ffprobe size failed for {path}: {proc.stderr}")
|
||||||
|
line = proc.stdout.strip()
|
||||||
|
if not line:
|
||||||
|
raise RuntimeError(f"ffprobe size returned empty output for {path}")
|
||||||
|
w_str, h_str = line.split("x")
|
||||||
|
return int(w_str), int(h_str)
|
||||||
|
|
||||||
if mode == "free":
|
|
||||||
x = str(layer.get("pos_x", 0))
|
|
||||||
y = str(layer.get("pos_y", 0))
|
|
||||||
return x, y
|
|
||||||
|
|
||||||
slot = layer.get("place", "center")
|
# ----------------- small helpers -----------------
|
||||||
|
|
||||||
if slot == "top_left":
|
|
||||||
return "0", "0"
|
|
||||||
if slot == "top_right":
|
|
||||||
return "W-w", "0"
|
|
||||||
if slot == "bottom_left":
|
|
||||||
return "0", "H-h"
|
|
||||||
if slot == "bottom_right":
|
|
||||||
return "W-w", "H-h"
|
|
||||||
|
|
||||||
return "(W-w)/2", "(H-h)/2"
|
def _even(x: int) -> int:
|
||||||
|
"""
|
||||||
|
Force an integer to be even (needed for some codecs / filters).
|
||||||
|
"""
|
||||||
|
return x if x % 2 == 0 else x + 1
|
||||||
|
|
||||||
|
|
||||||
def _preprocess_gif(src: str, base_duration: float, tmp_dir: Path, idx: int) -> str:
|
def _preprocess_gif(src: str, base_duration: float, tmp_dir: Path, idx: int) -> str:
|
||||||
"""
|
"""
|
||||||
Transcode a GIF to a looping video with alpha that roughly matches
|
Convert GIF to a looping RGBA video with even dimensions and alpha.
|
||||||
the base duration.
|
Returns path to the temp video file.
|
||||||
|
|
||||||
IMPORTANT:
|
- Loops the GIF for approximately base_duration.
|
||||||
- We force even dimensions so filters/encoders don't choke.
|
- Forces even width/height.
|
||||||
- We use an alpha-capable codec (qtrle in a MOV container),
|
- Keeps alpha via format=rgba + qtrle.
|
||||||
so transparency is preserved instead of being flattened.
|
|
||||||
"""
|
"""
|
||||||
tmp_dir.mkdir(parents=True, exist_ok=True)
|
tmp_dir.mkdir(parents=True, exist_ok=True)
|
||||||
# Use .mov since qtrle is typically stored in a QuickTime container
|
out_path = tmp_dir / f"gif_pre_{idx:03d}.mov"
|
||||||
temp_path = tmp_dir / f"lagkage_gif_{idx}.mov"
|
|
||||||
|
vf = "scale=trunc(iw/2)*2:trunc(ih/2)*2,format=rgba"
|
||||||
|
|
||||||
cmd = [
|
cmd = [
|
||||||
"ffmpeg",
|
"ffmpeg",
|
||||||
"-hide_banner",
|
"-hide_banner",
|
||||||
"-loglevel", "error",
|
"-loglevel",
|
||||||
"-ignore_loop", "0",
|
"error",
|
||||||
"-stream_loop", "-1",
|
|
||||||
"-i", src,
|
|
||||||
# Make width/height even and ensure we have RGBA (with alpha)
|
|
||||||
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2,format=rgba",
|
|
||||||
]
|
|
||||||
|
|
||||||
# If we know the base duration, trim to that; otherwise just loop and
|
|
||||||
# let the main overlay graph's base video duration cap play-out.
|
|
||||||
if base_duration > 0:
|
|
||||||
cmd += ["-t", f"{base_duration:.3f}"]
|
|
||||||
|
|
||||||
cmd += [
|
|
||||||
# Alpha-capable codec
|
|
||||||
"-c:v", "qtrle",
|
|
||||||
"-an",
|
|
||||||
"-y",
|
"-y",
|
||||||
str(temp_path),
|
"-ignore_loop",
|
||||||
|
"0",
|
||||||
|
"-stream_loop",
|
||||||
|
"-1",
|
||||||
|
"-i",
|
||||||
|
src,
|
||||||
|
"-t",
|
||||||
|
f"{base_duration:.3f}",
|
||||||
|
"-vf",
|
||||||
|
vf,
|
||||||
|
"-c:v",
|
||||||
|
"qtrle",
|
||||||
|
"-an",
|
||||||
|
str(out_path),
|
||||||
]
|
]
|
||||||
|
|
||||||
proc = subprocess.run(cmd)
|
proc = subprocess.run(cmd)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
raise RuntimeError(f"GIF preprocess failed for {src} (code {proc.returncode})")
|
raise RuntimeError(f"GIF preprocess failed for {src} (code {proc.returncode})")
|
||||||
|
|
||||||
return str(temp_path)
|
return str(out_path)
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_place_coordinates(place: str, base_w: int, base_h: int,
|
||||||
|
box_w: int, box_h: int):
|
||||||
|
"""
|
||||||
|
Compute overlay x,y for place mode, given base and box dimensions.
|
||||||
|
"""
|
||||||
|
place = (place or "center").lower()
|
||||||
|
if place == "top_left":
|
||||||
|
return 0, 0
|
||||||
|
elif place == "top_right":
|
||||||
|
return base_w - box_w, 0
|
||||||
|
elif place == "bottom_left":
|
||||||
|
return 0, base_h - box_h
|
||||||
|
elif place == "bottom_right":
|
||||||
|
return base_w - box_w, base_h - box_h
|
||||||
|
elif place == "center":
|
||||||
|
return (base_w - box_w) // 2, (base_h - box_h) // 2
|
||||||
|
else:
|
||||||
|
# Fallback to center for unknown place values
|
||||||
|
return (base_w - box_w) // 2, (base_h - box_h) // 2
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_overlay_box(base_w: int, src_w: int, src_h: int, size_pct: float):
|
||||||
|
"""
|
||||||
|
Compute the final overlay box width/height (even integers) based on:
|
||||||
|
- base width
|
||||||
|
- layer source aspect ratio
|
||||||
|
- size percentage of base width.
|
||||||
|
"""
|
||||||
|
if size_pct <= 0:
|
||||||
|
size_pct = 1.0
|
||||||
|
|
||||||
|
target_w = int(base_w * (size_pct / 100.0))
|
||||||
|
if target_w < 2:
|
||||||
|
target_w = 2
|
||||||
|
target_w = _even(target_w)
|
||||||
|
|
||||||
|
if src_h > 0:
|
||||||
|
ar = src_w / src_h
|
||||||
|
target_h = int(target_w / ar) if ar > 0 else target_w
|
||||||
|
else:
|
||||||
|
target_h = target_w
|
||||||
|
|
||||||
|
if target_h < 2:
|
||||||
|
target_h = 2
|
||||||
|
target_h = _even(target_h)
|
||||||
|
|
||||||
|
return target_w, target_h
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------- main entry -----------------
|
||||||
|
|
||||||
|
|
||||||
def run(args):
|
def run(args):
|
||||||
@@ -173,78 +204,147 @@ def run(args):
|
|||||||
if not layout_path.exists():
|
if not layout_path.exists():
|
||||||
raise FileNotFoundError(f"Layout JSON not found: {layout_path}")
|
raise FileNotFoundError(f"Layout JSON not found: {layout_path}")
|
||||||
|
|
||||||
layout = _load_layout(layout_path)
|
# Load layout JSON
|
||||||
seq, ordered_layers = _resolve_sequence(layout, args.sequence_direction)
|
layout = json.loads(layout_path.read_text())
|
||||||
|
layers = layout.get("layers", [])
|
||||||
|
if not isinstance(layers, list) or not layers:
|
||||||
|
raise ValueError("Layout JSON has no 'layers' array or it's empty.")
|
||||||
|
|
||||||
|
# Determine sequence direction
|
||||||
|
seq_dir = args.sequence_direction or layout.get("sequence_direction", "forward")
|
||||||
|
if seq_dir not in ("forward", "backward", "random"):
|
||||||
|
seq_dir = "forward"
|
||||||
|
|
||||||
|
# Order layers by layer_number, then adjust sequence if needed
|
||||||
|
ordered_layers = sorted(layers, key=lambda L: L.get("layer_number", 0))
|
||||||
|
if seq_dir == "backward":
|
||||||
|
ordered_layers = list(reversed(ordered_layers))
|
||||||
|
elif seq_dir == "random":
|
||||||
|
ordered_layers = random.sample(ordered_layers, len(ordered_layers))
|
||||||
|
|
||||||
base_input = args.input
|
base_input = args.input
|
||||||
if not base_input:
|
if not base_input:
|
||||||
raise ValueError("Global --input (base video) is required for json_layers.")
|
raise ValueError("Global --input (base video) is required for lagkage.")
|
||||||
|
|
||||||
# 1) Probe base video info once
|
# Probe base
|
||||||
base_w, base_h, base_duration = _probe_base_info(base_input)
|
base_w, base_h, base_duration = _probe_base_info(base_input)
|
||||||
|
|
||||||
# 2) Prepare inputs for main ffmpeg call
|
# Temp dir for GIF preprocess
|
||||||
# index 0: base video
|
tmp_dir = Path(tempfile.mkdtemp(prefix="lagkage_gifs_"))
|
||||||
# index 1..N: layer sources (with GIFs preprocessed to MP4)
|
|
||||||
inputs_for_ffmpeg = [("base", base_input)]
|
|
||||||
layer_inputs = [] # (layer_dict, input_index, target_width_px)
|
|
||||||
|
|
||||||
# Folder to hold temp GIF->MP4 files (next to the output file)
|
# 1) Build input list for ffmpeg
|
||||||
tmp_dir = Path(args.output).with_suffix("")
|
# input 0 = base, 1..N = overlays
|
||||||
|
input_files = [base_input]
|
||||||
|
overlay_specs = [] # (input_index, layer_dict, src_w, src_h)
|
||||||
|
|
||||||
for idx, layer in enumerate(ordered_layers, start=1):
|
for idx, layer in enumerate(ordered_layers, start=1):
|
||||||
filename = layer.get("filename")
|
filename = layer.get("filename")
|
||||||
if not filename:
|
if not filename:
|
||||||
raise ValueError(f"Layer missing 'filename': {layer}")
|
raise ValueError(f"Layer missing 'filename': {layer}")
|
||||||
|
|
||||||
# Resolve relative to layout JSON file
|
# Relative paths are relative to the layout JSON directory.
|
||||||
if not os.path.isabs(filename):
|
if not os.path.isabs(filename):
|
||||||
src = str(layout_path.parent / filename)
|
src = str(layout_path.parent / filename)
|
||||||
else:
|
else:
|
||||||
src = filename
|
src = filename
|
||||||
|
|
||||||
size_pct = float(layer.get("size", 100)) / 100.0
|
|
||||||
target_w = max(1, int(base_w * size_pct))
|
|
||||||
|
|
||||||
layer_type = (layer.get("type") or "").lower()
|
layer_type = (layer.get("type") or "").lower()
|
||||||
|
|
||||||
# If GIF, pre-process to finite-length MP4 that loops to base duration
|
# If GIF, pre-process to finite-length video that loops to base duration
|
||||||
if layer_type == "gif":
|
if layer_type == "gif":
|
||||||
overlay_src = _preprocess_gif(src, base_duration, tmp_dir, idx)
|
overlay_src = _preprocess_gif(src, base_duration, tmp_dir, idx)
|
||||||
else:
|
else:
|
||||||
overlay_src = src
|
overlay_src = src
|
||||||
|
|
||||||
inputs_for_ffmpeg.append(("video", overlay_src))
|
src_w, src_h = _probe_video_size(overlay_src)
|
||||||
layer_inputs.append((layer, len(inputs_for_ffmpeg) - 1, target_w))
|
|
||||||
|
|
||||||
# 3) Build filter_complex
|
input_files.append(overlay_src)
|
||||||
|
in_index = len(input_files) - 1
|
||||||
|
overlay_specs.append((in_index, layer, src_w, src_h))
|
||||||
|
|
||||||
|
# 2) Build filter_complex
|
||||||
filter_parts = []
|
filter_parts = []
|
||||||
|
|
||||||
# Base video label is [0:v] directly (like overlay_img_pro)
|
# Start with base video
|
||||||
current_label = "[0:v]"
|
current_label = "[0:v]"
|
||||||
|
|
||||||
for idx, (layer, input_index, target_w) in enumerate(layer_inputs, start=1):
|
for idx, (in_index, layer, src_w, src_h) in enumerate(overlay_specs, start=1):
|
||||||
lay_in = f"[{input_index}:v]"
|
size_pct = float(layer.get("size", 100.0))
|
||||||
lay_alpha = f"[lay{idx}]"
|
opacity = float(layer.get("opacity", 1.0))
|
||||||
|
if opacity < 0.0:
|
||||||
|
opacity = 0.0
|
||||||
|
if opacity > 1.0:
|
||||||
|
opacity = 1.0
|
||||||
|
|
||||||
|
zoom = float(layer.get("zoom", 1.0))
|
||||||
|
if zoom < 1.0:
|
||||||
|
zoom = 1.0
|
||||||
|
|
||||||
|
# Compute final overlay box size on the base
|
||||||
|
box_w, box_h = _compute_overlay_box(base_w, src_w, src_h, size_pct)
|
||||||
|
|
||||||
|
mode = (layer.get("mode") or "place").lower()
|
||||||
|
|
||||||
|
if mode == "free":
|
||||||
|
x_expr = str(int(layer.get("pos_x", 0)))
|
||||||
|
y_expr = str(int(layer.get("pos_y", 0)))
|
||||||
|
else:
|
||||||
|
place = layer.get("place", "center")
|
||||||
|
px, py = _compute_place_coordinates(place, base_w, base_h, box_w, box_h)
|
||||||
|
x_expr, y_expr = str(px), str(py)
|
||||||
|
|
||||||
|
in_label = f"[{in_index}:v]"
|
||||||
|
layer_label = f"[lay{idx}]"
|
||||||
next_label = f"[tmp{idx}]"
|
next_label = f"[tmp{idx}]"
|
||||||
|
|
||||||
opacity = float(layer.get("opacity", 1.0))
|
layer_filters = []
|
||||||
# blend_mode is kept for future use but ignored here
|
|
||||||
_blend_mode = (layer.get("blend_mode") or "normal").lower()
|
|
||||||
|
|
||||||
x_expr, y_expr = _place_expr(layer)
|
# Optional crop (percent of source, BEFORE zoom/scale)
|
||||||
|
cx = layer.get("crop_x")
|
||||||
|
cy = layer.get("crop_y")
|
||||||
|
cw = layer.get("crop_w")
|
||||||
|
ch = layer.get("crop_h")
|
||||||
|
if cx is not None and cy is not None and cw is not None and ch is not None:
|
||||||
|
try:
|
||||||
|
cx_f = float(cx) / 100.0
|
||||||
|
cy_f = float(cy) / 100.0
|
||||||
|
cw_f = float(cw) / 100.0
|
||||||
|
ch_f = float(ch) / 100.0
|
||||||
|
layer_filters.append(
|
||||||
|
f"crop=in_w*{cw_f}:in_h*{ch_f}:in_w*{cx_f}:in_h*{cy_f}"
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
# If parsing fails, skip cropping instead of blowing up.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Zoom INSIDE fixed box:
|
||||||
|
# 1) scale up to zoom * box size
|
||||||
|
# 2) crop center back down to box_w x box_h
|
||||||
|
scaled_w = _even(int(box_w * zoom))
|
||||||
|
scaled_h = _even(int(box_h * zoom))
|
||||||
|
if scaled_w < 2:
|
||||||
|
scaled_w = 2
|
||||||
|
if scaled_h < 2:
|
||||||
|
scaled_h = 2
|
||||||
|
|
||||||
|
layer_filters.append(f"scale={scaled_w}:{scaled_h}")
|
||||||
|
|
||||||
|
if zoom > 1.0:
|
||||||
|
layer_filters.append(
|
||||||
|
f"crop={box_w}:{box_h}:(iw-{box_w})/2:(ih-{box_h})/2"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Force RGBA and apply opacity
|
||||||
|
layer_filters.append("format=rgba")
|
||||||
|
layer_filters.append(f"colorchannelmixer=aa={opacity}")
|
||||||
|
|
||||||
# scale + alpha
|
|
||||||
filter_parts.append(
|
filter_parts.append(
|
||||||
f"{lay_in}"
|
f"{in_label}{','.join(layer_filters)}{layer_label}"
|
||||||
f"scale={target_w}:-1,"
|
|
||||||
f"format=rgba,colorchannelmixer=aa={opacity}"
|
|
||||||
f"{lay_alpha}"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# overlay
|
# Overlay on top of current composite
|
||||||
filter_parts.append(
|
filter_parts.append(
|
||||||
f"{current_label}{lay_alpha}"
|
f"{current_label}{layer_label}"
|
||||||
f"overlay=x={x_expr}:y={y_expr}:format=auto"
|
f"overlay=x={x_expr}:y={y_expr}:format=auto"
|
||||||
f"{next_label}"
|
f"{next_label}"
|
||||||
)
|
)
|
||||||
@@ -256,20 +356,16 @@ def run(args):
|
|||||||
|
|
||||||
filter_complex = ";".join(filter_parts)
|
filter_complex = ";".join(filter_parts)
|
||||||
|
|
||||||
# 4) Build main ffmpeg command
|
# 3) Build main ffmpeg command
|
||||||
command = [
|
command = ["ffmpeg", "-hide_banner", "-loglevel", "error"]
|
||||||
"ffmpeg",
|
|
||||||
"-err_detect", "ignore_err",
|
|
||||||
"-fflags", "+discardcorrupt+genpts",
|
|
||||||
]
|
|
||||||
|
|
||||||
for _typ, src in inputs_for_ffmpeg:
|
for path in input_files:
|
||||||
command.extend(["-i", src])
|
command.extend(["-i", path])
|
||||||
|
|
||||||
command.extend([
|
command.extend([
|
||||||
"-filter_complex", filter_complex,
|
"-filter_complex", filter_complex,
|
||||||
"-map", out_label,
|
"-map", out_label,
|
||||||
"-map", "0:a",
|
"-map", "0:a?",
|
||||||
"-c:v", "libx264",
|
"-c:v", "libx264",
|
||||||
"-profile:v", "high",
|
"-profile:v", "high",
|
||||||
"-level:v", "4.2",
|
"-level:v", "4.2",
|
||||||
@@ -280,5 +376,4 @@ def run(args):
|
|||||||
])
|
])
|
||||||
|
|
||||||
final_cmd = (command[:1] + ["-y"] + command[1:]) if args.force else command
|
final_cmd = (command[:1] + ["-y"] + command[1:]) if args.force else command
|
||||||
|
|
||||||
run_ffmpeg_with_progress(final_cmd, args.input, args.output)
|
run_ffmpeg_with_progress(final_cmd, args.input, args.output)
|
||||||
|
|||||||
Reference in New Issue
Block a user