Page Not Found
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
diff --git a/404.html b/404.html index 3b84fd942..76f6e872d 100644 --- a/404.html +++ b/404.html @@ -9,9 +9,9 @@ - - - + + +
We could not find what you were looking for.
Please contact the owner of the site that linked you to the original URL and let them know their link is broken.
width
of an input stream",id:"transition-that-changes-the-width-of-an-input-stream",level:3},{value:"Transition on one of the sibling components",id:"transition-on-one-of-the-sibling-components",level:3},{value:"Transition between different modes",id:"transition-between-different-modes",level:3},{value:"Different interpolation functions",id:"different-interpolation-functions",level:3}];function g(n){const e={a:"a",code:"code",h1:"h1",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"transitions-viewrescaler",children:"Transitions (View/Rescaler)"}),"\n",(0,i.jsxs)(e.p,{children:["This guide will show a few basic examples of animated transitions on ",(0,i.jsx)(e.code,{children:"View"}),"/",(0,i.jsx)(e.code,{children:"Rescaler"})," components."]}),"\n",(0,i.jsx)(e.h3,{id:"configure-inputs-and-output",children:"Configure inputs and output"}),"\n",(0,i.jsxs)(e.p,{children:['Start the compositor and configure 2 input streams and a single output stream as described in the "Simple scene"\nguide in the ',(0,i.jsx)(e.a,{href:"/docs/guides/quick-start#configure-inputs-and-output",children:'"Configure inputs and output"'})," section."]}),"\n",(0,i.jsxs)(e.h3,{id:"transition-that-changes-the-width-of-an-input-stream",children:["Transition that changes the ",(0,i.jsx)(e.code,{children:"width"})," of an input stream"]}),"\n",(0,i.jsxs)(s.A,{queryString:"lang",children:[(0,i.jsxs)(a.A,{value:"http",label:"HTTP",children:[(0,i.jsx)(e.p,{children:"Set initial scene for the transition:"}),(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n // highlight-start\n "width": 480,\n // highlight-end\n "child": { "type": "input_stream", "input_id": "input_1" },\n }\n ]\n }\n }\n}\n'})}),(0,i.jsxs)(e.p,{children:["A few seconds latter update a scene with a different ",(0,i.jsx)(e.code,{children:"width"}),":"]}),(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n // highlight-start\n "width": 1280,\n "transition": { "duration_ms": 2000 },\n // highlight-end\n "child": { "type": "input_stream", "input_id": "input_1" },\n }\n ]\n }\n }\n}\n'})})]}),(0,i.jsxs)(a.A,{value:"membrane",label:"Membrane Framework",children:[(0,i.jsxs)(e.p,{children:["Set initial scene for the transition and after few seconds update a component\nwith a different ",(0,i.jsx)(e.code,{children:"width"}),":"]}),(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n // highlight-start\n width: 480,\n // highlight-end\n child: %{ type: :input_stream, input_id: :input_1 },\n }\n ]\n }\n }\n Process.send_after(self(), :start_transition, 2000)\n {[notify_child: {:live_compositor, request}], state}\nend\n\ndef handle_info(:start_transition, _ctx, state)\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n // highlight-start\n width: 1280,\n transition: %{ duration_ms: 2000 },\n // highlight-end\n child: %{ type: :input_stream, input_id: :input_1 },\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})]})]}),"\n",(0,i.jsxs)(e.p,{children:["In the first update request, you can see that the rescaler has a width of 480, and in the second one, it is changed\nto 1280 and ",(0,i.jsx)(e.code,{children:"transition.duration_ms: 2000"})," was added."]}),"\n",(0,i.jsxs)(e.p,{children:["The component must have the same ",(0,i.jsx)(e.code,{children:'"id"'})," in both the initial state and the update that starts the\ntransition, otherwise it will switch immediately to the new state without a transition."]}),"\n",(0,i.jsxs)("div",{style:{textAlign:"center"},children:[(0,i.jsx)("img",{src:o,style:{width:600}}),(0,i.jsx)(e.p,{children:"Output stream"})]}),"\n",(0,i.jsx)(e.h3,{id:"transition-on-one-of-the-sibling-components",children:"Transition on one of the sibling components"}),"\n",(0,i.jsx)(e.p,{children:"In the above scenario you saw how transition on a single component behaves, but let's see what happens with\ncomponents that are not a part of the transition, but their size and position still depend on other components."}),"\n",(0,i.jsxs)(e.p,{children:["Add a second input stream wrapped with ",(0,i.jsx)(e.code,{children:"Rescaler"}),", but without any transition options."]}),"\n",(0,i.jsxs)(s.A,{queryString:"lang",children:[(0,i.jsxs)(a.A,{value:"http",label:"HTTP",children:[(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n // highlight-start\n "width": 480,\n // highlight-end\n "child": { "type": "input_stream", "input_id": "input_1" },\n },\n {\n "type": "rescaler",\n "child": { "type": "input_stream", "input_id": "input_2" },\n }\n ]\n }\n }\n}\n'})}),(0,i.jsxs)(e.p,{children:["Update a scene with a different ",(0,i.jsx)(e.code,{children:"width"}),":"]}),(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n // highlight-start\n "width": 1280,\n "transition": { "duration_ms": 2000 },\n // highlight-end\n "child": { "type": "input_stream", "input_id": "input_1" },\n },\n {\n "type": "rescaler",\n "child": { "type": "input_stream", "input_id": "input_2" },\n }\n ]\n }\n }\n}\n'})})]}),(0,i.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n // highlight-start\n width: 480,\n // highlight-end\n child: %{ type: :input_stream, input_id: :input_1 },\n },\n %{\n type: :rescaler,\n child: %{ type: :input_stream, input_id: :input_2 },\n }\n ]\n }\n }\n Process.send_after(self(), :start_transition, 2000)\n {[notify_child: {:live_compositor, request}], state}\nend\n\ndef handle_info(:start_transition, _ctx, state)\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n // highlight-start\n width: 1280,\n transition: %{ duration_ms: 2000 },\n // highlight-end\n child: %{ type: :input_stream, input_id: :input_1 },\n },\n %{\n type: :rescaler,\n child: %{ type: :input_stream, input_id: :input_2 },\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,i.jsxs)("div",{style:{textAlign:"center"},children:[(0,i.jsx)("img",{src:d,style:{width:600}}),(0,i.jsx)(e.p,{children:"Output stream"})]}),"\n",(0,i.jsx)(e.h3,{id:"transition-between-different-modes",children:"Transition between different modes"}),"\n",(0,i.jsx)(e.p,{children:"Currently, a state before the transition and after needs to use the same type of configuration. In particular:"}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsx)(e.li,{children:"It is not possible to transition a component between static and absolute positioning."}),"\n",(0,i.jsxs)(e.li,{children:["It is not possible to transition a component between using ",(0,i.jsx)(e.code,{children:"top"})," and ",(0,i.jsx)(e.code,{children:"bottom"})," fields (the same for ",(0,i.jsx)(e.code,{children:"left"}),"/",(0,i.jsx)(e.code,{children:"right"}),")."]}),"\n",(0,i.jsxs)(e.li,{children:["It is not possible to transition a component with known ",(0,i.jsx)(e.code,{children:"width"}),"/",(0,i.jsx)(e.code,{children:"height"})," to a state with dynamic ",(0,i.jsx)(e.code,{children:"width"}),"/",(0,i.jsx)(e.code,{children:"height"})," based\non the parent layout."]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["Let's try the same example as in the first scenario with a single input, but instead, change the ",(0,i.jsx)(e.code,{children:"Rescaler"})," component to be absolutely positioned in the second update."]}),"\n",(0,i.jsxs)(s.A,{queryString:"lang",children:[(0,i.jsxs)(a.A,{value:"http",label:"HTTP",children:[(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n // highlight-start\n "width": 480,\n // highlight-end\n "child": { "type": "input_stream", "input_id": "input_1" },\n }\n ]\n }\n }\n}\n'})}),(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n // highlight-start\n "width": 1280,\n "top": 0,\n "left": 0,\n "transition": { "duration_ms": 2000 },\n // highlight-end\n "child": { "type": "input_stream", "input_id": "input_1" },\n }\n ]\n }\n }\n}\n'})})]}),(0,i.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n // highlight-start\n width: 480,\n // highlight-end\n child: %{ type: :input_stream, input_id: :input_1 },\n }\n ]\n }\n }\n Process.send_after(self(), :start_transition, 2000)\n {[notify_child: {:live_compositor, request}], state}\nend\n\ndef handle_info(:start_transition, _ctx, state)\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n // highlight-start\n width: 1280,\n top: 0,\n left: 0,\n transition: %{ duration_ms: 2000 },\n // highlight-end\n child: %{ type: :input_stream, input_id: :input_1 },\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,i.jsxs)(e.p,{children:["As you can see on the resulting stream, the transition did not happen because the ",(0,i.jsx)(e.code,{children:"Rescaler"})," component\nin the initial scene was using static positioning and after the update it was positioned absolutely."]}),"\n",(0,i.jsxs)("div",{style:{textAlign:"center"},children:[(0,i.jsx)("img",{src:l,style:{width:600}}),(0,i.jsx)(e.p,{children:"Output stream"})]}),"\n",(0,i.jsx)(e.h3,{id:"different-interpolation-functions",children:"Different interpolation functions"}),"\n",(0,i.jsx)(e.p,{children:"All of the above examples use default linear interpolation, but there are also a few other\nmodes available."}),"\n",(0,i.jsxs)(s.A,{queryString:"lang",children:[(0,i.jsxs)(a.A,{value:"http",label:"HTTP",children:[(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n "width": 320, "height": 180, "top": 0, "left": 0,\n "child": { "type": "input_stream", "input_id": "input_1" },\n },\n {\n "type": "rescaler",\n "id": "rescaler_2",\n "width": 320, "height": 180, "top": 0, "left": 320,\n "child": { "type": "input_stream", "input_id": "input_2" },\n },\n {\n "type": "rescaler",\n "id": "rescaler_3",\n "width": 320, "height": 180, "top": 0, "left": 640,\n "child": { "type": "input_stream", "input_id": "input_3" },\n },\n {\n "type": "rescaler",\n "id": "rescaler_4",\n "width": 320, "height": 180, "top": 0, "left": 960,\n "child": { "type": "input_stream", "input_id": "input_4" },\n },\n ]\n }\n }\n}\n'})}),(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "id": "rescaler_1",\n "width": 320, "height": 180, "top": 540, "left": 0,\n "child": { "type": "input_stream", "input_id": "input_1" },\n "transition": { "duration_ms": 2000 },\n },\n {\n "type": "rescaler",\n "id": "rescaler_2",\n "width": 320, "height": 180, "top": 540, "left": 320,\n "child": { "type": "input_stream", "input_id": "input_2" },\n "transition": {\n "duration_ms": 2000, "easing_function": {"function_name": "bounce"}\n },\n },\n {\n "type": "rescaler",\n "id": "rescaler_3",\n "width": 320, "height": 180, "top": 540, "left": 640,\n "child": { "type": "input_stream", "input_id": "input_3" },\n "transition": {\n "duration_ms": 2000,\n "easing_function": {\n "function_name": "cubic_bezier",\n "points": [0.65, 0, 0.35, 1]\n }\n }\n },\n {\n "type": "rescaler",\n "id": "rescaler_4",\n "width": 320, "height": 180, "top": 540, "left": 960,\n "child": { "type": "input_stream", "input_id": "input_4" },\n "transition": {\n "duration_ms": 2000,\n "easing_function": {\n "function_name": "cubic_bezier",\n "points": [0.33, 1, 0.68, 1]\n }\n }\n }\n ]\n }\n }\n}\n'})})]}),(0,i.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n width: 320, height: 180, top: 0, left: 0,\n child: %{ type: :input_stream, input_id: :input_1 },\n },\n %{\n type: :rescaler,\n id: "rescaler_2",\n width: 320, height: 180, top: 0, left: 320,\n child: %{ type: :input_stream, input_id: :input_2 },\n },\n %{\n type: :rescaler,\n id: "rescaler_3",\n width: 320, height: 180, top: 0, left: 640,\n child: %{ type: :input_stream, input_id: :input_3 },\n },\n %{\n type: :rescaler,\n id: "rescaler_4",\n width: 320, height: 180, top: 0, left: 960,\n child: %{ type: :input_stream, input_id: :input_4 },\n }\n ]\n }\n }\n Process.send_after(self(), :start_transition, 2000)\n {[notify_child: {:live_compositor, request}], state}\nend\n\ndef handle_info(:start_transition, _ctx, state)\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n id: "rescaler_1",\n width: 320, height: 180, top: 0, left: 0,\n child: %{ type: :input_stream, input_id: :input_1 },\n transition: %{ duration_ms: 2000 },\n },\n %{\n type: :rescaler,\n id: "rescaler_2",\n width: 320, height: 180, top: 0, left: 320,\n child: %{ type: :input_stream, input_id: :input_2 },\n transition: %{\n duration_ms: 2000\n easing_function: %{ function_name: :bounce}\n },\n },\n %{\n type: :rescaler,\n id: "rescaler_3",\n width: 320, height: 180, top: 0, left: 640,\n child: %{ type: :input_stream, input_id: :input_3 },\n transition: %{\n duration_ms: 2000\n easing_function: %{\n function_name: :cubic_bezier,\n points: [0.65, 0, 0.35, 1]\n }\n }\n },\n %{\n type: :rescaler,\n id: "rescaler_4",\n width: 320, height: 180, top: 0, left: 960,\n child: %{ type: :input_stream, input_id: :input_4 },\n transition: %{\n duration_ms: 2000\n easing_function: %{\n function_name: :cubic_bezier,\n points: [0.33, 1, 0.68, 1]\n }\n }\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,i.jsxs)("div",{style:{textAlign:"center"},children:[(0,i.jsx)("img",{src:c,style:{width:600}}),(0,i.jsx)(e.p,{children:"Output stream"})]}),"\n",(0,i.jsxs)(e.ul,{children:["\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"Input 1"})," - Linear transition"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"Input 2"})," - Bounce transition"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"Input 3"})," - Cubic B\xe9zier transition with ",(0,i.jsx)(e.code,{children:"[0.65, 0, 0.35, 1]"})," points (",(0,i.jsx)(e.a,{href:"https://easings.net/#easeInOutCubic",children:(0,i.jsx)(e.code,{children:"easeInOutCubic"})}),")"]}),"\n",(0,i.jsxs)(e.li,{children:[(0,i.jsx)(e.code,{children:"Input 4"})," - Cubic B\xe9zier transition with ",(0,i.jsx)(e.code,{children:"[0.33, 1, 0.68, 1]"})," points (",(0,i.jsx)(e.a,{href:"https://easings.net/#easeOutCubic",children:(0,i.jsx)(e.code,{children:"easeOutCubic"})}),")"]}),"\n"]}),"\n",(0,i.jsxs)(e.p,{children:["Check out other popular Cubic B\xe9zier curves on ",(0,i.jsx)(e.a,{href:"https://easings.net",children:"https://easings.net"}),"."]})]})}function m(n={}){const{wrapper:e}={...(0,r.R)(),...n.components};return e?(0,i.jsx)(e,{...n,children:(0,i.jsx)(g,{...n})}):g(n)}},19365:(n,e,t)=>{t.d(e,{A:()=>a});t(96540);var i=t(18215);const r={tabItem:"tabItem_Ymn6"};var s=t(74848);function a(n){let{children:e,hidden:t,className:a}=n;return(0,s.jsx)("div",{role:"tabpanel",className:(0,i.A)(r.tabItem,a),hidden:t,children:e})}},11470:(n,e,t)=>{t.d(e,{A:()=>j});var i=t(96540),r=t(18215),s=t(23104),a=t(56347),o=t(205),d=t(57485),l=t(31682),c=t(89466);function u(n){return i.Children.toArray(n).filter((n=>"\n"!==n)).map((n=>{if(!n||(0,i.isValidElement)(n)&&function(n){const{props:e}=n;return!!e&&"object"==typeof e&&"value"in e}(n))return n;throw new Error(`Docusaurus error: Bad width
of an input stream",id:"transition-that-changes-the-width-of-an-input-stream",level:3},{value:"Transition on one of the sibling components",id:"transition-on-one-of-the-sibling-components",level:3},{value:"Transition between different modes",id:"transition-between-different-modes",level:3},{value:"Different interpolation functions",id:"different-interpolation-functions",level:3}];function g(n){const e={a:"a",code:"code",h1:"h1",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,r.R)(),...n.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(e.h1,{id:"transitions-viewrescaler",children:"Transitions (View/Rescaler)"}),"\n",(0,i.jsxs)(e.p,{children:["This guide will show a few basic examples of animated transitions on ",(0,i.jsx)(e.code,{children:"View"}),"/",(0,i.jsx)(e.code,{children:"Rescaler"})," components."]}),"\n",(0,i.jsx)(e.h3,{id:"configure-inputs-and-output",children:"Configure inputs and output"}),"\n",(0,i.jsxs)(e.p,{children:['Start the compositor and configure 2 input streams and a single output stream as described in the "Simple scene"\nguide in the ',(0,i.jsx)(e.a,{href:"/docs/guides/quick-start#configure-inputs-and-output",children:'"Configure inputs and output"'})," section."]}),"\n",(0,i.jsxs)(e.h3,{id:"transition-that-changes-the-width-of-an-input-stream",children:["Transition that changes the ",(0,i.jsx)(e.code,{children:"width"})," of an input stream"]}),"\n",(0,i.jsxs)(s.A,{queryString:"lang",children:[(0,i.jsx)(a.A,{value:"react",label:"React",children:(0,i.jsx)(e.pre,{children:(0,i.jsx)(e.code,{className:"language-tsx",children:'function App() {\n const [beforeTransition, setBeforeTransition] = useState(true);\n useEffect(() => {\n setTimeout(() => setBeforeTransition(false), 2000);\n }, []);\n\n return (\n CPU-only
",id:"cpu-only",level:3},{value:"CPU+GPU
",id:"cpugpu",level:3},{value:"How to use",id:"how-to-use",level:3}];function d(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"example-aws-ec2",children:"Example: AWS EC2"}),"\n",(0,i.jsx)(n.p,{children:"This is an example configuration that shows how to deploy LiveCompositor to an AWS EC2 instance with Terraform configuration."}),"\n",(0,i.jsxs)(n.p,{children:["All examples are located in the ",(0,i.jsx)(n.a,{href:"https://github.com/membraneframework-labs/live_compositor_deployment",children:"github.com/membraneframework-labs/live_compositor_deployment"})," repository:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"project"})," directory includes an example Membrane project that can consume multiple streams over RTMP and host the composed stream as an HLS playlist."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"aws-ec2-terraform"})," directory includes an example Terraform+Packer configuration for building an AMI (Amazon Machine Image) and deploying it to EC2."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Terraform"}),"\n",(0,i.jsx)(n.li,{children:"Packer"}),"\n",(0,i.jsx)(n.li,{children:"Elixir - required to build an example project"}),"\n",(0,i.jsx)(n.li,{children:"FFmpeg - used to send/receive streams from/to the compositor"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"cpu-vs-gpu-rendering-trade-off",children:"CPU vs GPU rendering trade-off"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"GPU+CPU"})," - LiveCompositor uses ",(0,i.jsx)(n.code,{children:"wgpu"})," (implementation of WebGPU standard written in Rust) for rendering. However, all decoding and\nencoding still happens on the CPU. When running on GPU the rendering cost should be negligible compared to the decoding/encoding."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CPU-only"})," - When running on a CPU-only instance, all ",(0,i.jsx)(n.code,{children:"WebGPU"})," code is emulated on the CPU. Unless your encoder quality is set very\nhigh, rendering will use most of the CPU processing time."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Actual price-to-performance can vary, but in general, CPU+GPU instances make more sense for fast encoder presets and complex rendering\npipelines. However, CPU-only can be more optimal when using simple layouts and prioritizing quality over performance with slower preset."}),"\n",(0,i.jsx)(n.h3,{id:"how-to-deploy",children:"How to deploy"}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["The example configuration is using ",(0,i.jsx)(n.code,{children:"us-east-1"})," region. If you want to use a different one make sure to change it both in Packer\nand Terraform configuration. Specifically, if you use EC2 instances with GPU, you might only have them available in some regions."]})}),"\n",(0,i.jsx)(n.h3,{id:"cpu-only",children:(0,i.jsx)(n.code,{children:"CPU-only"})}),"\n",(0,i.jsxs)(n.p,{children:["Go to ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/packer"})," directory and run"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"packer build membrane.pkr.hcl\n"})}),"\n",(0,i.jsxs)(n.p,{children:["to build an AMI image with an example Membrane project. At the end of the process, the terminal will print the AMI ID, that will\nbe needed in the next step (something like ",(0,i.jsx)(n.code,{children:"ami-0e18e9d7b8c037ec2"}),")."]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["The other ",(0,i.jsx)(n.code,{children:"pkr.hcl"})," file in this directory (",(0,i.jsx)(n.strong,{children:"standalone.pkr.hcl"}),") includes configuration for deploying just a standalone LiveCompositor\ninstance, so you can also go that route, but the rest of this guide assumes you are using the provided Membrane project."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Open ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/main.tf"}),", find ",(0,i.jsx)(n.code,{children:"aws_instance.demo_instance"})," definition and update the ",(0,i.jsx)(n.code,{children:"ami"})," field with the AMI ID from the previous step."]}),"\n",(0,i.jsxs)(n.p,{children:["In ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform"})," directory run:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"terraform apply\n"})}),"\n",(0,i.jsx)(n.h3,{id:"cpugpu",children:(0,i.jsx)(n.code,{children:"CPU+GPU"})}),"\n",(0,i.jsxs)(n.p,{children:["Go to ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/packer"})," directory and run"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'packer build -var "with-gpu=true" membrane.pkr.hcl\n'})}),"\n",(0,i.jsxs)(n.p,{children:["to build an AMI image with an example Membrane project. At the end of the process, the terminal will print the AMI ID that, will\nbe needed in the next step (something like ",(0,i.jsx)(n.code,{children:"ami-0e18e9d7b8c037ec2"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:["Open ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/main.tf"}),", find ",(0,i.jsx)(n.code,{children:"aws_instance.demo_instance"})," definition and update the ",(0,i.jsx)(n.code,{children:"ami"})," field with the AMI ID from the previous step."]}),"\n",(0,i.jsxs)(n.p,{children:["In ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform"})," directory run:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'terraform apply -var="with-gpu=true"\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Instances with GPU like ",(0,i.jsx)(n.code,{children:"g4dn.xlarge"})," are not available by default on AWS. You will need to request a quota increase from the AWS team to use them."]})}),"\n",(0,i.jsx)(n.h3,{id:"how-to-use",children:"How to use"}),"\n",(0,i.jsx)(n.p,{children:"After everything is deployed you can open your AWS dashboard and find the public IP of the newly deployed instance."}),"\n",(0,i.jsx)(n.p,{children:"To test the service, run in separate terminals:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["To receive the output stream","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"ffplay http://YOUR_INSTANCE_IP:9001/index.m3u8\n"})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["To send an example input stream","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"ffmpeg -re -f lavfi -i testsrc\n -vf scale=1280:720 -vcodec libx264 \\\n -profile:v baseline -preset fast -pix_fmt yuv420p \\\n -f flv rtmp://YOUR_INSTANCE_IP:9000/app/stream_key\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["You can run this command multiple times with different paths instead of ",(0,i.jsx)(n.code,{children:"app/stream_key"})," to connect multiple streams."]}),"\n"]}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>s,x:()=>l});var i=r(96540);const t={},o=i.createContext(t);function s(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/26033596.22fd6132.js b/assets/js/26033596.22fd6132.js
deleted file mode 100644
index f6d5bffb5..000000000
--- a/assets/js/26033596.22fd6132.js
+++ /dev/null
@@ -1 +0,0 @@
-"use strict";(self.webpackChunkcompositor_live=self.webpackChunkcompositor_live||[]).push([[6993],{73321:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>a,contentTitle:()=>s,default:()=>h,frontMatter:()=>o,metadata:()=>l,toc:()=>c});var i=r(74848),t=r(28453);const o={},s="Example: AWS EC2",l={id:"deployment/aws-ec2",title:"Example: AWS EC2",description:"This is an example configuration that shows how to deploy LiveCompositor to an AWS EC2 instance with Terraform configuration.",source:"@site/pages/deployment/aws-ec2.md",sourceDirName:"deployment",slug:"/deployment/aws-ec2",permalink:"/docs/deployment/aws-ec2",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"Configuration",permalink:"/docs/deployment/configuration"},next:{title:"Reference",permalink:"/docs/typescript/api"}},a={},c=[{value:"Prerequisites",id:"prerequisites",level:3},{value:"CPU vs GPU rendering trade-off",id:"cpu-vs-gpu-rendering-trade-off",level:3},{value:"How to deploy",id:"how-to-deploy",level:3},{value:"CPU-only
",id:"cpu-only",level:3},{value:"CPU+GPU
",id:"cpugpu",level:3},{value:"How to use",id:"how-to-use",level:3}];function d(e){const n={a:"a",admonition:"admonition",blockquote:"blockquote",code:"code",h1:"h1",h3:"h3",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.h1,{id:"example-aws-ec2",children:"Example: AWS EC2"}),"\n",(0,i.jsx)(n.p,{children:"This is an example configuration that shows how to deploy LiveCompositor to an AWS EC2 instance with Terraform configuration."}),"\n",(0,i.jsxs)(n.p,{children:["All examples are located in the ",(0,i.jsx)(n.a,{href:"https://github.com/membraneframework-labs/live_compositor_deployment",children:"github.com/membraneframework-labs/live_compositor_deployment"})," repository:"]}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"project"})," directory includes an example Membrane project that can consume multiple streams over RTMP and host the composed stream as an HLS playlist."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"aws-ec2-terraform"})," directory includes an example Terraform+Packer configuration for building an AMI (Amazon Machine Image) and deploying it to EC2."]}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsx)(n.li,{children:"Terraform"}),"\n",(0,i.jsx)(n.li,{children:"Packer"}),"\n",(0,i.jsx)(n.li,{children:"Elixir - required to build an example project"}),"\n",(0,i.jsx)(n.li,{children:"FFmpeg - used to send/receive streams from/to the compositor"}),"\n"]}),"\n",(0,i.jsx)(n.h3,{id:"cpu-vs-gpu-rendering-trade-off",children:"CPU vs GPU rendering trade-off"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"GPU+CPU"})," - LiveCompositor uses ",(0,i.jsx)(n.code,{children:"wgpu"})," (implementation of WebGPU standard written in Rust) for rendering. However, all decoding and\nencoding still happens on the CPU. When running on GPU the rendering cost should be negligible compared to the decoding/encoding."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"CPU-only"})," - When running on a CPU-only instance, all ",(0,i.jsx)(n.code,{children:"WebGPU"})," code is emulated on the CPU. Unless your encoder quality is set very\nhigh, rendering will use most of the CPU processing time."]}),"\n"]}),"\n",(0,i.jsx)(n.p,{children:"Actual price-to-performance can vary, but in general, CPU+GPU instances make more sense for fast encoder presets and complex rendering\npipelines. However, CPU-only can be more optimal when using simple layouts and prioritizing quality over performance with slower preset."}),"\n",(0,i.jsx)(n.h3,{id:"how-to-deploy",children:"How to deploy"}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["The example configuration is using ",(0,i.jsx)(n.code,{children:"us-east-1"})," region. If you want to use a different one make sure to change it both in Packer\nand Terraform configuration. Specifically, if you use EC2 instances with GPU, you might only have them available in some regions."]})}),"\n",(0,i.jsx)(n.h3,{id:"cpu-only",children:(0,i.jsx)(n.code,{children:"CPU-only"})}),"\n",(0,i.jsxs)(n.p,{children:["Go to ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/packer"})," directory and run"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"packer build membrane.pkr.hcl\n"})}),"\n",(0,i.jsxs)(n.p,{children:["to build an AMI image with an example Membrane project. At the end of the process, the terminal will print the AMI ID, that will\nbe needed in the next step (something like ",(0,i.jsx)(n.code,{children:"ami-0e18e9d7b8c037ec2"}),")."]}),"\n",(0,i.jsxs)(n.blockquote,{children:["\n",(0,i.jsxs)(n.p,{children:["The other ",(0,i.jsx)(n.code,{children:"pkr.hcl"})," file in this directory (",(0,i.jsx)(n.strong,{children:"standalone.pkr.hcl"}),") includes configuration for deploying just a standalone LiveCompositor\ninstance, so you can also go that route, but the rest of this guide assumes you are using the provided Membrane project."]}),"\n"]}),"\n",(0,i.jsxs)(n.p,{children:["Open ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/main.tf"}),", find ",(0,i.jsx)(n.code,{children:"aws_instance.demo_instance"})," definition and update the ",(0,i.jsx)(n.code,{children:"ami"})," field with the AMI ID from the previous step."]}),"\n",(0,i.jsxs)(n.p,{children:["In ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform"})," directory run:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:"terraform apply\n"})}),"\n",(0,i.jsx)(n.h3,{id:"cpugpu",children:(0,i.jsx)(n.code,{children:"CPU+GPU"})}),"\n",(0,i.jsxs)(n.p,{children:["Go to ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/packer"})," directory and run"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'packer build -var "with-gpu=true" membrane.pkr.hcl\n'})}),"\n",(0,i.jsxs)(n.p,{children:["to build an AMI image with an example Membrane project. At the end of the process, the terminal will print the AMI ID that, will\nbe needed in the next step (something like ",(0,i.jsx)(n.code,{children:"ami-0e18e9d7b8c037ec2"}),")."]}),"\n",(0,i.jsxs)(n.p,{children:["Open ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform/main.tf"}),", find ",(0,i.jsx)(n.code,{children:"aws_instance.demo_instance"})," definition and update the ",(0,i.jsx)(n.code,{children:"ami"})," field with the AMI ID from the previous step."]}),"\n",(0,i.jsxs)(n.p,{children:["In ",(0,i.jsx)(n.strong,{children:"aws-ec2-terraform"})," directory run:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-bash",children:'terraform apply -var="with-gpu=true"\n'})}),"\n",(0,i.jsx)(n.admonition,{type:"note",children:(0,i.jsxs)(n.p,{children:["Instances with GPU like ",(0,i.jsx)(n.code,{children:"g4dn.xlarge"})," are not available by default on AWS. You will need to request a quota increase from the AWS team to use them."]})}),"\n",(0,i.jsx)(n.h3,{id:"how-to-use",children:"How to use"}),"\n",(0,i.jsx)(n.p,{children:"After everything is deployed you can open your AWS dashboard and find the public IP of the newly deployed instance."}),"\n",(0,i.jsx)(n.p,{children:"To test the service, run in separate terminals:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["To receive the output stream","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"ffplay http://YOUR_INSTANCE_IP:9001/index.m3u8\n"})}),"\n"]}),"\n",(0,i.jsxs)(n.li,{children:["To send an example input stream","\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{children:"ffmpeg -re -f lavfi -i testsrc\n -vf scale=1280:720 -vcodec libx264 \\\n -profile:v baseline -preset fast -pix_fmt yuv420p \\\n -f flv rtmp://YOUR_INSTANCE_IP:9000/app/stream_key\n"})}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["You can run this command multiple times with different paths instead of ",(0,i.jsx)(n.code,{children:"app/stream_key"})," to connect multiple streams."]}),"\n"]}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:n}={...(0,t.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(d,{...e})}):d(e)}},28453:(e,n,r)=>{r.d(n,{R:()=>s,x:()=>l});var i=r(96540);const t={},o=i.createContext(t);function s(e){const n=i.useContext(o);return i.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:s(e.components),i.createElement(o.Provider,{value:n},e.children)}}}]);
\ No newline at end of file
diff --git a/assets/js/30f5821a.2ae71d7f.js b/assets/js/30f5821a.2ae71d7f.js
deleted file mode 100644
index 195e59221..000000000
--- a/assets/js/30f5821a.2ae71d7f.js
+++ /dev/null
@@ -1 +0,0 @@
-"use strict";(self.webpackChunkcompositor_live=self.webpackChunkcompositor_live||[]).push([[5829],{8050:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>f,contentTitle:()=>p,default:()=>A,frontMatter:()=>h,metadata:()=>y,toc:()=>b});var s=t(74848),i=t(28453),r=t(11470),a=t(19365);const o="data:image/webp;base64,UklGRpwGAABXRUJQVlA4IJAGAADwxACdASoABdACPu12tlMko6KhIAgAlh2J6W7hd2EbQAnsA99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvrAAA/v+dGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",c=t.p+"assets/images/basic_layouts_2-c5dfc4a7bc5c3c8cf38700ab270c2321.webp",l=t.p+"assets/images/basic_layouts_3-cd23fc29a3c6ba9fc0afb5400925926c.webp",u=t.p+"assets/images/basic_layouts_4-52e18a12081cc90cdac41e805195ef07.webp",d=t.p+"assets/images/basic_layouts_5-b417f13c80a11598f443eafcc7518041.webp",h={},p="Basic Layouts",y={id:"guides/basic-layouts",title:"Basic Layouts",description:"This guide will explain how to create simple scene that is combining input streams in a simple layout into single output stream.",source:"@site/pages/guides/basic-layouts.md",sourceDirName:"guides",slug:"/guides/basic-layouts",permalink:"/docs/guides/basic-layouts",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"sidebar",previous:{title:"How to receive output streams",permalink:"/docs/guides/receive-output"},next:{title:"Transitions (View/Rescaler)",permalink:"/docs/guides/view-transition"}},f={},b=[{value:"Configure inputs and output",id:"configure-inputs-and-output",level:3},{value:"Update scene to show an input",id:"update-scene-to-show-an-input",level:2},{value:"Resize input stream to fit inside the output",id:"resize-input-stream-to-fit-inside-the-output",level:2},{value:"Show both inputs side by side",id:"show-both-inputs-side-by-side",level:2},{value:"Place one of the inputs in the top right corner",id:"place-one-of-the-inputs-in-the-top-right-corner",level:2}];function m(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,i.R)(),...e.components};return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.h1,{id:"basic-layouts",children:"Basic Layouts"}),"\n",(0,s.jsx)(n.p,{children:"This guide will explain how to create simple scene that is combining input streams in a simple layout into single output stream."}),"\n",(0,s.jsx)(n.h3,{id:"configure-inputs-and-output",children:"Configure inputs and output"}),"\n",(0,s.jsxs)(n.p,{children:['Start the compositor and configure 2 input streams and a single output stream as described in the "Simple scene"\nguide in the ',(0,s.jsx)(n.a,{href:"/docs/guides/quick-start#configure-inputs-and-output",children:'"Configure inputs and output"'})," section."]}),"\n",(0,s.jsx)(n.p,{children:"After configuration you should see the following output:"}),"\n",(0,s.jsxs)("div",{style:{textAlign:"center"},children:[(0,s.jsx)("img",{src:o,style:{width:600}}),(0,s.jsx)(n.p,{children:"Output stream"})]}),"\n",(0,s.jsx)(n.h2,{id:"update-scene-to-show-an-input",children:"Update scene to show an input"}),"\n",(0,s.jsxs)(n.p,{children:["Update output to render a ",(0,s.jsx)(n.a,{href:"/docs/api/components/View",children:(0,s.jsx)(n.code,{children:"View"})})," component with an ",(0,s.jsx)(n.a,{href:"/docs/api/components/InputStream",children:(0,s.jsx)(n.code,{children:"InputStream"})})," as its child."]}),"\n",(0,s.jsxs)(r.A,{queryString:"lang",children:[(0,s.jsx)(a.A,{value:"http",label:"HTTP",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n { "type": "input_stream", "input_id": "input_1" }\n ]\n }\n }\n}\n'})})}),(0,s.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{ type: :input_stream, input_id: :input_1 }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,s.jsxs)(n.p,{children:["The input stream in the example has a resolution ",(0,s.jsx)(n.code,{children:"1920x1080"})," and it is rendered on the ",(0,s.jsx)(n.code,{children:"1270x720"})," output. As a result only part of the stream is visible."]}),"\n",(0,s.jsxs)("div",{style:{textAlign:"center"},children:[(0,s.jsx)("img",{src:c,style:{width:600}}),(0,s.jsx)(n.p,{children:"Output stream"})]}),"\n",(0,s.jsx)(n.h2,{id:"resize-input-stream-to-fit-inside-the-output",children:"Resize input stream to fit inside the output"}),"\n",(0,s.jsxs)(n.p,{children:["Wrap an ",(0,s.jsx)(n.a,{href:"/docs/api/components/InputStream",children:(0,s.jsx)(n.code,{children:"InputStream"})})," component with a ",(0,s.jsx)(n.a,{href:"/docs/api/components/Rescaler",children:(0,s.jsx)(n.code,{children:"Rescaler"})}),"."]}),"\n",(0,s.jsxs)(r.A,{queryString:"lang",children:[(0,s.jsx)(a.A,{value:"http",label:"HTTP",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "child": { "type": "input_stream", "input_id": "input_1" }\n }\n ]\n }\n }\n}\n'})})}),(0,s.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n child: %{ type: :input_stream, input_id: :input_1 }\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,s.jsx)(n.p,{children:"Input stream now fully fits inside the output."}),"\n",(0,s.jsxs)("div",{style:{textAlign:"center"},children:[(0,s.jsx)("img",{src:l,style:{width:600}}),(0,s.jsx)(n.p,{children:"Output stream"})]}),"\n",(0,s.jsxs)(n.admonition,{type:"note",children:[(0,s.jsx)(n.p,{children:"The same effect (for single input) could be achieved by either:"}),(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:["Setting ",(0,s.jsx)(n.code,{children:"InputStream"})," as a root directly. It would only work if aspect ratio of input and output is the same."]}),"\n",(0,s.jsxs)(n.li,{children:["Replacing ",(0,s.jsx)(n.code,{children:"View"})," component with a ",(0,s.jsx)(n.code,{children:"Rescaler"}),"."]}),"\n"]})]}),"\n",(0,s.jsx)(n.h2,{id:"show-both-inputs-side-by-side",children:"Show both inputs side by side"}),"\n",(0,s.jsxs)(n.p,{children:["Add another ",(0,s.jsx)(n.a,{href:"/docs/api/components/InputStream",children:(0,s.jsx)(n.code,{children:"InputStream"})})," wrapped with ",(0,s.jsx)(n.a,{href:"/docs/api/components/Rescaler",children:(0,s.jsx)(n.code,{children:"Rescaler"})}),"."]}),"\n",(0,s.jsxs)(r.A,{queryString:"lang",children:[(0,s.jsx)(a.A,{value:"http",label:"HTTP",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "child": { "type": "input_stream", "input_id": "input_1" }\n },\n {\n "type": "rescaler",\n "child": { "type": "input_stream", "input_id": "input_2" }\n }\n ]\n }\n }\n}\n'})})}),(0,s.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n child: %{ type: :input_stream, input_id: :input_1 }\n },\n %{\n type: :rescaler,\n child: %{ type: :input_stream, input_id: :input_2 }\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,s.jsxs)(n.p,{children:["By default, a ",(0,s.jsx)(n.code,{children:"View"})," component positions its children next to each other in a row. Each child without a defined width or\nheight fills available space inside the parent component. To place them in a column, set a ",(0,s.jsx)(n.code,{children:'direction: "column"'})," option."]}),"\n",(0,s.jsx)(n.p,{children:"In an example below we can see that:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsxs)(n.li,{children:[(0,s.jsx)(n.code,{children:"View"})," has 2 children components with unspecified dimensions, so they will divide available width exactly in half."]}),"\n",(0,s.jsxs)(n.li,{children:["Each ",(0,s.jsx)(n.code,{children:"Rescaler"})," component has a size ",(0,s.jsx)(n.code,{children:"640x720"})," (half of ",(0,s.jsx)(n.code,{children:"1280x720"}),"), but it needs to fit an input stream with ",(0,s.jsx)(n.code,{children:"16:9"})," aspect ratio."]}),"\n"]}),"\n",(0,s.jsxs)("div",{style:{textAlign:"center"},children:[(0,s.jsx)("img",{src:u,style:{width:600}}),(0,s.jsx)(n.p,{children:"Output stream"})]}),"\n",(0,s.jsx)(n.h2,{id:"place-one-of-the-inputs-in-the-top-right-corner",children:"Place one of the inputs in the top right corner"}),"\n",(0,s.jsxs)(n.p,{children:["Specify ",(0,s.jsx)(n.code,{children:"width"})," and ",(0,s.jsx)(n.code,{children:"height"})," of one of the ",(0,s.jsx)(n.code,{children:"Rescaler"})," components and position it using ",(0,s.jsx)(n.code,{children:"top"}),"/",(0,s.jsx)(n.code,{children:"right"})," options in the corner."]}),"\n",(0,s.jsxs)(r.A,{queryString:"lang",children:[(0,s.jsx)(a.A,{value:"http",label:"HTTP",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-http",children:'POST: /api/output/output_1/update\nContent-Type: application/json\n\n{\n "video": {\n "root": {\n "type": "view",\n "background_color_rgba": "#4d4d4dff",\n "children": [\n {\n "type": "rescaler",\n "child": { "type": "input_stream", "input_id": "input_1" }\n },\n {\n "type": "rescaler",\n "width": 320,\n "height": 180,\n "top": 20,\n "right": 20,\n "child": { "type": "input_stream", "input_id": "input_2" }\n }\n ]\n }\n }\n}\n'})})}),(0,s.jsx)(a.A,{value:"membrane",label:"Membrane Framework",children:(0,s.jsx)(n.pre,{children:(0,s.jsx)(n.code,{className:"language-elixir",children:'def handle_setup(ctx, state) do\n request = %LiveCompositor.Request.UpdateVideoOutput{\n output_id: "output_1",\n root: %{\n type: :view,\n background_color_rgba: "#4d4d4dff",\n children: [\n %{\n type: :rescaler,\n child: %{ type: :input_stream, input_id: :input_1 }\n },\n %{\n type: :rescaler,\n width: 320,\n height: 180,\n top: 20,\n right: 20,\n child: %{ type: :input_stream, input_id: :input_2 }\n }\n ]\n }\n }\n {[notify_child: {:live_compositor, request}], state}\nend\n'})})})]}),"\n",(0,s.jsxs)(n.p,{children:["When you specify ",(0,s.jsx)(n.code,{children:"top"}),"/",(0,s.jsx)(n.code,{children:"right"})," options on the ",(0,s.jsx)(n.code,{children:"Rescaler"})," component, the ",(0,s.jsx)(n.code,{children:"View"})," component does not take that component\ninto account when calculating the row layout of its children. See ",(0,s.jsx)(n.a,{href:"/docs/api/components/View#absolute-positioning",children:"absolute positioning"})," to learn more."]}),"\n",(0,s.jsx)(n.p,{children:"As a result:"}),"\n",(0,s.jsxs)(n.ul,{children:["\n",(0,s.jsx)(n.li,{children:"The first child extends to the full width of a parent."}),"\n",(0,s.jsx)(n.li,{children:"The second component takes the specified size, and it is positioned in the top-right corner (20px from border)."}),"\n"]}),"\n",(0,s.jsxs)("div",{style:{textAlign:"center"},children:[(0,s.jsx)("img",{src:d,style:{width:600}}),(0,s.jsx)(n.p,{children:"Output stream"})]})]})}function A(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,s.jsx)(n,{...e,children:(0,s.jsx)(m,{...e})}):m(e)}},19365:(e,n,t)=>{t.d(n,{A:()=>a});t(96540);var s=t(18215);const i={tabItem:"tabItem_Ymn6"};var r=t(74848);function a(e){let{children:n,hidden:t,className:a}=e;return(0,r.jsx)("div",{role:"tabpanel",className:(0,s.A)(i.tabItem,a),hidden:t,children:n})}},11470:(e,n,t)=>{t.d(n,{A:()=>g});var s=t(96540),i=t(18215),r=t(23104),a=t(56347),o=t(205),c=t(57485),l=t(31682),u=t(89466);function d(e){return s.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,s.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad LiveCompositor
",id:"livecompositor",level:2},{value:"new LiveCompositor()
",id:"new-livecompositor",level:3},{value:"init()
",id:"init",level:3},{value:"start()
",id:"start",level:3},{value:"Outputs configuration",id:"outputs-configuration",level:3},{value:"Register output",id:"register-output",level:4},{value:"Unregister output",id:"unregister-output",level:4},{value:"Inputs configuration",id:"inputs-configuration",level:3},{value:"Register input",id:"register-input",level:4},{value:"Unregister input",id:"unregister-input",level:4},{value:"Renderers configuration",id:"renderers-configuration",level:3},{value:"Register image",id:"register-image",level:4},{value:"Unregister image",id:"unregister-image",level:4},{value:"Register shader",id:"register-shader",level:4},{value:"Unregister shader",id:"unregister-shader",level:4},{value:"Register web renderer instance",id:"register-web-renderer-instance",level:4},{value:"Unregister web renderer instance",id:"unregister-web-renderer-instance",level:4}];function a(e){const r={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(r.h1,{id:"reference",children:"Reference"}),"\n",(0,n.jsxs)(r.p,{children:["Packages like ",(0,n.jsx)(r.code,{children:"@live-compositor/node"})," export ",(0,n.jsx)(r.code,{children:"LiveCompositor"})," class that is a main entity used to interact with or control Live Compositor server instance."]}),"\n",(0,n.jsx)(r.h2,{id:"livecompositor",children:(0,n.jsx)(r.code,{children:"LiveCompositor"})}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tsx",children:'import LiveCompositor from "@live-compositor/node"\n'})}),"\n",(0,n.jsx)(r.h3,{id:"new-livecompositor",children:(0,n.jsx)(r.code,{children:"new LiveCompositor()"})}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tsx",children:"new LiveCompositor(manager?: CompositorManager)\n"})}),"\n",(0,n.jsxs)(r.p,{children:["Creates new compositor configuration. You have to call ",(0,n.jsx)(r.code,{children:"init"})," first before this object can be used."]}),"\n",(0,n.jsxs)(r.p,{children:[(0,n.jsx)(r.code,{children:"CompositorManager"})," configures how the client code will connect and manage the LiveCompositor server."]}),"\n",(0,n.jsxs)(r.ul,{children:["\n",(0,n.jsxs)(r.li,{children:["(",(0,n.jsx)(r.strong,{children:"default"}),") ",(0,n.jsx)(r.code,{children:"LocallySpawnedInstance"})," from ",(0,n.jsx)(r.code,{children:"@live-compositor/node"})," downloads LiveCompositor binaries and starts the server on the local machine."]}),"\n",(0,n.jsxs)(r.li,{children:[(0,n.jsx)(r.code,{children:"ExistingInstance"})," from ",(0,n.jsx)(r.code,{children:"@live-compositor/node"})," connects to already existing compositor instance."]}),"\n"]}),"\n",(0,n.jsx)(r.h3,{id:"init",children:(0,n.jsx)(r.code,{children:"init()"})}),"\n",(0,n.jsx)(r.pre,{children:(0,n.jsx)(r.code,{className:"language-tsx",children:"LiveCompositor.init(): Promise