diff options
| author | Carl Hetherington <cth@carlh.net> | 2021-09-27 13:43:19 +0200 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2021-09-27 13:43:19 +0200 |
| commit | 952084c4221c5708e02c783284cf0f7239c6b4c4 (patch) | |
| tree | c1521dab0586b6c33e02c9338c94abdc6b4c2ea9 | |
| parent | 6e3e984162ca7a181bc7c98d90c295e88e4e7f6c (diff) | |
| parent | 81b9ea804cb9953bb1a4074f208f63374adbf09b (diff) | |
Merge branch 'better-gl' into v2.15.x
This changes the GL video view to use more modern GL (GLSL etc.) It
also special-cases JPEG2000 video playback and does scaling and
colourspace conversion on the GPU.
72 files changed, 2251 insertions, 788 deletions
diff --git a/doc/design/video.svg b/doc/design/video.svg index c9985b1b6..59122b46f 100644 --- a/doc/design/video.svg +++ b/doc/design/video.svg @@ -1,6 +1,4 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<!-- Created with Inkscape (http://www.inkscape.org/) --> - <svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" @@ -14,11 +12,54 @@ viewBox="0 0 744.09448819 1052.3622047" id="svg2" version="1.1" - inkscape:version="0.91 r13725" + inkscape:version="1.0.2 (e86c870, 2021-01-15)" sodipodi:docname="video.svg"> <defs id="defs4"> <marker + style="overflow:visible;" + id="marker3668" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="scale(0.4) rotate(180) translate(10,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path3666" /> + </marker> + <marker + style="overflow:visible;" + id="marker2973" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="scale(0.4) rotate(180) translate(10,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path2971" /> + </marker> + <marker + style="overflow:visible;" + id="marker1688" + refX="0.0" + refY="0.0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true" + inkscape:collect="always"> + <path + transform="scale(0.4) rotate(180) translate(10,0)" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1;fill:#000000;fill-opacity:1" + d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z " + id="path1434" /> + </marker> + <marker inkscape:isstock="true" style="overflow:visible;" id="marker10547" @@ -295,6 +336,104 @@ d="M 0,0 5,-5 -12.5,0 5,5 0,0 Z" id="path8484-9" /> </marker> + <marker + style="overflow:visible" + id="marker1688-3" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path1434-7" /> + </marker> + <marker + style="overflow:visible" + id="marker1688-3-2" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path1434-7-8" /> + </marker> + <marker + style="overflow:visible" + id="marker1688-3-29" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path1434-7-3" /> + </marker> + <marker + style="overflow:visible" + id="marker1688-3-29-9" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path1434-7-3-4" /> + </marker> + <marker + style="overflow:visible" + id="marker3668-5" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path3666-6" /> + </marker> + <marker + style="overflow:visible" + id="marker1688-3-29-9-2" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path1434-7-3-4-5" /> + </marker> + <marker + style="overflow:visible" + id="marker1688-3-29-9-2-7" + refX="0" + refY="0" + orient="auto" + inkscape:stockid="Arrow1Mend" + inkscape:isstock="true"> + <path + transform="matrix(-0.4,0,0,-0.4,-4,0)" + style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;stroke-opacity:1" + d="M 0,0 5,-5 -12.5,0 5,5 Z" + id="path1434-7-3-4-5-4" /> + </marker> </defs> <sodipodi:namedview id="base" @@ -303,22 +442,23 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="12.895211" - inkscape:cx="-38.958419" - inkscape:cy="710.99114" + inkscape:zoom="1.6119014" + inkscape:cx="436.93023" + inkscape:cy="615.356" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" showguides="true" inkscape:guide-bbox="true" - inkscape:window-width="1280" - inkscape:window-height="995" - inkscape:window-x="86" - inkscape:window-y="0" + inkscape:window-width="1920" + inkscape:window-height="1016" + inkscape:window-x="0" + inkscape:window-y="27" inkscape:window-maximized="1" inkscape:showpageshadow="true" showborder="false" - inkscape:snap-global="false" /> + inkscape:snap-global="false" + inkscape:document-rotation="0" /> <metadata id="metadata7"> <rdf:RDF> @@ -327,7 +467,7 @@ <dc:format>image/svg+xml</dc:format> <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> - <dc:title></dc:title> + <dc:title /> </cc:Work> </rdf:RDF> </metadata> @@ -350,200 +490,204 @@ sodipodi:nodetypes="cccc" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="157.97063" y="145.07965" - id="text3355-3" - sodipodi:linespacing="125%"><tspan + id="text3355-3"><tspan sodipodi:role="line" id="tspan3357-6" x="157.97063" - y="145.07965">Player</tspan></text> + y="145.07965" + style="font-size:14px;line-height:1.25">Player</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="261.11292" y="79.787865" - id="text3405" - sodipodi:linespacing="125%"><tspan + id="text3405"><tspan sodipodi:role="line" id="tspan3407" x="261.11292" - y="79.787865">Call <tspan + y="79.787865" + style="font-size:8px;line-height:1.25">Call <tspan style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';fill:#ff0000" id="tspan3425">give(<tspan style="fill:#0000ff" id="tspan4943">ImageProxy</tspan>)</tspan></tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="158.08263" y="27.967474" - id="text3459" - sodipodi:linespacing="125%"><tspan + id="text3459"><tspan sodipodi:role="line" id="tspan3461" x="158.08263" - y="27.967474">FFmpegDecoder</tspan><tspan + y="27.967474" + style="font-size:14px;line-height:1.25">FFmpegDecoder</tspan><tspan sodipodi:role="line" x="158.08263" y="45.467476" - id="tspan3463">DCPDecoder</tspan><tspan + id="tspan3463" + style="font-size:14px;line-height:1.25">DCPDecoder</tspan><tspan sodipodi:role="line" x="158.08263" y="62.967476" - id="tspan3465">VideoMXFDecoder</tspan><tspan + id="tspan3465" + style="font-size:14px;line-height:1.25">VideoMXFDecoder</tspan><tspan sodipodi:role="line" x="158.08263" y="80.467476" - id="tspan3467">ImageDecoder</tspan></text> + id="tspan3467" + style="font-size:14px;line-height:1.25">ImageDecoder</tspan></text> <text xml:space="preserve" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="750.14496" y="30.933632" - id="text3503" - sodipodi:linespacing="125%"><tspan + id="text3503"><tspan sodipodi:role="line" id="tspan3505" x="750.14496" - y="30.933632" /></text> + y="30.933632" + style="font-size:40px;line-height:1.25">Â </tspan></text> <text xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="730.14496" y="42.362206" - id="text3507" - sodipodi:linespacing="125%"><tspan + id="text3507"><tspan sodipodi:role="line" id="tspan3509" x="730.14496" - y="42.362206" /></text> + y="42.362206" + style="font-size:40px;line-height:1.25">Â </tspan></text> <text xml:space="preserve" - style="font-style:normal;font-weight:normal;font-size:40px;line-height:125%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" x="730.14496" y="48.076488" - id="text3511" - sodipodi:linespacing="125%"><tspan + id="text3511"><tspan sodipodi:role="line" id="tspan3513" x="730.14496" - y="48.076488" /></text> + y="48.076488" + style="font-size:40px;line-height:1.25">Â </tspan></text> <g id="g6532" transform="translate(1.07113,-2.4356439)"> <text - sodipodi:linespacing="125%" id="text3427" y="32.95697" x="365.3392" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan id="tspan3431" y="32.95697" x="365.3392" - sodipodi:role="line">RawImageProxy</tspan><tspan + sodipodi:role="line" + style="font-size:14px;line-height:1.25">RawImageProxy</tspan><tspan id="tspan3495" y="50.45697" x="365.3392" - sodipodi:role="line">MagickImageProxy</tspan><tspan + sodipodi:role="line" + style="font-size:14px;line-height:1.25">MagickImageProxy</tspan><tspan id="tspan3497" y="67.95697" x="365.3392" - sodipodi:role="line">J2KImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:14px;line-height:1.25">J2KImageProxy</tspan></text> <text - sodipodi:linespacing="125%" id="text3515" y="32.793625" x="468.0589" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="32.793625" x="468.0589" id="tspan3517" - sodipodi:role="line">image in any pixel format and colourspace</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">image in any pixel format and colourspace</tspan></text> <text - sodipodi:linespacing="125%" id="text3519" y="50.478642" x="489.33072" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="50.478642" x="489.33072" id="tspan3521" - sodipodi:role="line">image assumed to be 24-bit RGB</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">image assumed to be 24-bit RGB</tspan></text> <text - sodipodi:linespacing="125%" id="text3523" y="68.05394" x="468.04465" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="68.05394" x="468.04465" id="tspan3525" - sodipodi:role="line">image in J2K which could be sRGB or XYZ</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">image in J2K which could be sRGB or XYZ</tspan></text> </g> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="158.96458" y="114.28626" - id="text3598" - sodipodi:linespacing="125%"><tspan + id="text3598"><tspan sodipodi:role="line" id="tspan3600" x="158.96458" - y="114.28626">VideoDecoder</tspan></text> + y="114.28626" + style="font-size:14px;line-height:1.25">VideoDecoder</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="210.7205" y="145.7095" - id="text4752" - sodipodi:linespacing="125%"><tspan + id="text4752"><tspan sodipodi:role="line" id="tspan4754" x="210.7205" y="145.7095" - style="font-size:8px">Add <tspan - style="fill:#0000ff;-inkscape-font-specification:'latin modern mono';font-family:'latin modern mono';font-weight:normal;font-style:normal;font-stretch:normal;font-variant:normal" + style="font-size:8px;line-height:1.25">Add <tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';fill:#0000ff" id="tspan4945">ColourConversion</tspan> from Content</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="232.61076" y="210.91785" - id="text4774" - sodipodi:linespacing="125%"><tspan + id="text4774"><tspan sodipodi:role="line" id="tspan4776" x="232.61076" - y="210.91785">Encoder</tspan></text> + y="210.91785" + style="font-size:14px;line-height:1.25">Encoder</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="80.230049" y="210.91785" - id="text4778" - sodipodi:linespacing="125%"><tspan + id="text4778"><tspan sodipodi:role="line" id="tspan4780" x="80.230049" - y="210.91785">FilmViewer</tspan></text> + y="210.91785" + style="font-size:14px;line-height:1.25">FilmViewer</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="80.358047" y="223.85684" - id="text4853" - sodipodi:linespacing="125%"><tspan + id="text4853"><tspan sodipodi:role="line" id="tspan4855" x="80.358047" - y="223.85684">Call <tspan + y="223.85684" + style="font-size:8px;line-height:1.25">Call <tspan style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'" id="tspan4949"><tspan style="fill:#0000ff" @@ -552,34 +696,35 @@ id="tspan4953">image</tspan></tspan> telling</tspan><tspan sodipodi:role="line" x="80.358047" - y="234.18263" - id="tspan4857">FFmpeg to convert to RGB</tspan></text> + y="234.08084" + id="tspan4857" + style="font-size:8px;line-height:1.25">FFmpeg to convert to RGB</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="232.70876" y="236.76064" - id="text4774-3" - sodipodi:linespacing="125%"><tspan + id="text4774-3"><tspan sodipodi:role="line" id="tspan4776-1" x="232.70876" - y="236.76064">DCPVideo</tspan><tspan + y="236.76064" + style="font-size:14px;line-height:1.25">DCPVideo</tspan><tspan sodipodi:role="line" x="232.70876" y="254.26064" - id="tspan4893" /></text> + id="tspan4893" + style="font-size:14px;line-height:1.25">Â </tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="232.97478" y="246.51703" - id="text4895" - sodipodi:linespacing="125%"><tspan + id="text4895"><tspan sodipodi:role="line" x="232.97478" y="246.51703" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:1.25;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'" id="tspan4931"><tspan id="tspan8152" style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';fill:#ff0000">encode_locally()</tspan></tspan></text> @@ -613,16 +758,16 @@ id="rect7578" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0292846px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580" y="173.77292" x="385.19406" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="173.77292" x="385.19406" id="tspan7582" - sodipodi:role="line">RawImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">RawImageProxy</tspan></text> <g transform="translate(-68.230852,57.45182)" id="g7700"> @@ -635,15 +780,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604" - sodipodi:linespacing="125%"><tspan + id="text7604"><tspan sodipodi:role="line" id="tspan7606" x="471.76764" - y="126.86294">YUV</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">YUV</tspan></text> </g> </g> <g @@ -657,16 +802,16 @@ id="rect7578-0" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0292846px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1" y="173.77292" x="385.19406" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="173.77292" x="385.19406" id="tspan7582-3" - sodipodi:role="line">RawImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">RawImageProxy</tspan></text> <g transform="translate(-68.230852,57.45182)" id="g7700-7"> @@ -679,15 +824,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2" - sodipodi:linespacing="125%"><tspan + id="text7604-2"><tspan sodipodi:role="line" id="tspan7606-64" x="471.76764" - y="126.86294">RGB</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">RGB</tspan></text> </g> </g> <g @@ -701,16 +846,16 @@ id="rect7578-0-2" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.1262238px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-0" y="211.11105" x="453.9198" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="211.11105" x="453.9198" id="tspan7582-3-2" - sodipodi:role="line">MagickImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">MagickImageProxy</tspan></text> <g transform="translate(6.5830841,94.789948)" id="g7700-7-9"> @@ -723,15 +868,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-9" - sodipodi:linespacing="125%"><tspan + id="text7604-2-9"><tspan sodipodi:role="line" id="tspan7606-64-9" x="471.76764" - y="126.86294">RGB</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">RGB</tspan></text> </g> </g> <g @@ -745,16 +890,16 @@ id="rect7578-0-2-5" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0356878px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-0-1" y="239.25938" x="404.95599" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="239.25938" x="404.95599" id="tspan7582-3-2-0" - sodipodi:role="line">J2KImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">J2KImageProxy</tspan></text> <g transform="translate(-48.084616,122.93827)" id="g7700-7-9-3"> @@ -767,15 +912,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-9-8" - sodipodi:linespacing="125%"><tspan + id="text7604-2-9-8"><tspan sodipodi:role="line" id="tspan7606-64-9-8" x="471.76764" - y="126.86294">RGB</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">RGB</tspan></text> </g> </g> <g @@ -789,16 +934,16 @@ id="rect7578-0-2-5-0" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0356878px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-0-1-4" y="239.25938" x="404.95599" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="239.25938" x="404.95599" id="tspan7582-3-2-0-6" - sodipodi:role="line">J2KImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">J2KImageProxy</tspan></text> <g transform="translate(-48.084616,122.93827)" id="g7700-7-9-3-7"> @@ -811,29 +956,28 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-9-8-0" - sodipodi:linespacing="125%"><tspan + id="text7604-2-9-8-0"><tspan sodipodi:role="line" id="tspan7606-64-9-8-9" x="471.76764" - y="126.86294">XYZ</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">XYZ</tspan></text> </g> </g> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="705.09467" y="244.12233" - id="text8237" - sodipodi:linespacing="125%"><tspan + id="text8237"><tspan sodipodi:role="line" id="tspan8239" x="705.09467" y="244.12233" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:1.25;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'"><tspan style="fill:#0000ff" id="tspan8257">Player</tspan>::<tspan style="fill:#ff0000" @@ -851,15 +995,15 @@ y="264.45612" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="705.1507" y="279.21188" - id="text8400" - sodipodi:linespacing="125%"><tspan + id="text8400"><tspan sodipodi:role="line" id="tspan8402" x="705.1507" - y="279.21188"><tspan + y="279.21188" + style="font-size:8px;line-height:1.25"><tspan style="fill:#0000ff" id="tspan8428">DCP</tspan>::<tspan style="fill:#ff0000" @@ -882,16 +1026,16 @@ id="rect8285" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#eeaaff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text8154" y="244.55614" x="348.75104" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="244.55614" x="348.75104" id="tspan8156" - sodipodi:role="line">To RGB48LE</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">To RGB48LE</tspan></text> </g> <path style="fill:none;fill-rule:evenodd;stroke:#999999;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker8482-3)" @@ -915,28 +1059,28 @@ inkscape:connector-curvature="0" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="51.75613" y="226.5392" id="text9567" - sodipodi:linespacing="125%" - transform="matrix(0.88644001,-0.4628435,0.4628435,0.88644001,0,0)"><tspan + transform="rotate(-27.570746)"><tspan sodipodi:role="line" id="tspan9569" x="51.75613" - y="226.5392">Preview</tspan></text> + y="226.5392" + style="font-size:8px;line-height:1.25">Preview</tspan></text> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="277.17169" y="36.546879" id="text9571" - sodipodi:linespacing="125%" - transform="matrix(0.87866652,0.47743601,-0.47743601,0.87866652,0,0)"><tspan + transform="rotate(28.518077)"><tspan sodipodi:role="line" id="tspan9573" x="277.17169" - y="36.546879">Encode</tspan></text> + y="36.546879" + style="font-size:8px;line-height:1.25">Encode</tspan></text> <g id="g9672"> <g @@ -951,15 +1095,15 @@ y="235.07904" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="348.75104" y="244.55614" - id="text8154-0" - sodipodi:linespacing="125%"><tspan + id="text8154-0"><tspan sodipodi:role="line" id="tspan8156-4" x="348.75104" - y="244.55614">To XYZ12LE</tspan></text> + y="244.55614" + style="font-size:8px;line-height:1.25">To XYZ12LE</tspan></text> </g> </g> <g @@ -977,15 +1121,15 @@ y="235.07904" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="348.75104" y="244.55614" - id="text8154-0-1" - sodipodi:linespacing="125%"><tspan + id="text8154-0-1"><tspan sodipodi:role="line" id="tspan8156-4-6" x="348.75104" - y="244.55614">To XYZ12LE</tspan></text> + y="244.55614" + style="font-size:8px;line-height:1.25">To XYZ12LE</tspan></text> </g> </g> <g @@ -1003,15 +1147,15 @@ y="235.07904" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="348.75104" y="244.55614" - id="text8154-0-9" - sodipodi:linespacing="125%"><tspan + id="text8154-0-9"><tspan sodipodi:role="line" id="tspan8156-4-64" x="348.75104" - y="244.55614">To XYZ12LE</tspan></text> + y="244.55614" + style="font-size:8px;line-height:1.25">To XYZ12LE</tspan></text> </g> </g> <g @@ -1029,15 +1173,15 @@ y="235.07904" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="348.75104" y="244.55614" - id="text8154-0-10" - sodipodi:linespacing="125%"><tspan + id="text8154-0-10"><tspan sodipodi:role="line" id="tspan8156-4-2" x="348.75104" - y="244.55614">To XYZ12LE</tspan></text> + y="244.55614" + style="font-size:8px;line-height:1.25">To XYZ12LE</tspan></text> </g> </g> <rect @@ -1058,16 +1202,16 @@ id="rect7578-9" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0292846px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-17" y="173.77292" x="385.19406" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="173.77292" x="385.19406" id="tspan7582-0" - sodipodi:role="line">RawImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">RawImageProxy</tspan></text> <g transform="translate(-68.230852,57.45182)" id="g7700-6"> @@ -1080,15 +1224,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-8" - sodipodi:linespacing="125%"><tspan + id="text7604-8"><tspan sodipodi:role="line" id="tspan7606-5" x="471.76764" - y="126.86294">YUV</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">YUV</tspan></text> </g> </g> <g @@ -1102,16 +1246,16 @@ id="rect7578-0-9" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0292846px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-4" y="173.77292" x="385.19406" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="173.77292" x="385.19406" id="tspan7582-3-1" - sodipodi:role="line">RawImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">RawImageProxy</tspan></text> <g transform="translate(-68.230852,57.45182)" id="g7700-7-5"> @@ -1124,15 +1268,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-1" - sodipodi:linespacing="125%"><tspan + id="text7604-2-1"><tspan sodipodi:role="line" id="tspan7606-64-5" x="471.76764" - y="126.86294">RGB</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">RGB</tspan></text> </g> </g> <g @@ -1146,16 +1290,16 @@ id="rect7578-0-2-4" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.1262238px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-0-9" y="211.11105" x="453.9198" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="211.11105" x="453.9198" id="tspan7582-3-2-8" - sodipodi:role="line">MagickImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">MagickImageProxy</tspan></text> <g transform="translate(6.5830841,94.789948)" id="g7700-7-9-38"> @@ -1168,15 +1312,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-9-2" - sodipodi:linespacing="125%"><tspan + id="text7604-2-9-2"><tspan sodipodi:role="line" id="tspan7606-64-9-2" x="471.76764" - y="126.86294">RGB</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">RGB</tspan></text> </g> </g> <g @@ -1190,16 +1334,16 @@ id="rect7578-0-2-5-7" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0356878px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-0-1-0" y="239.25938" x="404.95599" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="239.25938" x="404.95599" id="tspan7582-3-2-0-3" - sodipodi:role="line">J2KImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">J2KImageProxy</tspan></text> <g transform="translate(-48.084616,122.93827)" id="g7700-7-9-3-4"> @@ -1212,15 +1356,15 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-9-8-6" - sodipodi:linespacing="125%"><tspan + id="text7604-2-9-8-6"><tspan sodipodi:role="line" id="tspan7606-64-9-8-3" x="471.76764" - y="126.86294">RGB</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">RGB</tspan></text> </g> </g> <g @@ -1234,16 +1378,16 @@ id="rect7578-0-2-5-0-4" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffaaaa;fill-opacity:1;fill-rule:nonzero;stroke:#1a1a1a;stroke-width:1.0356878px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text7580-1-0-1-4-4" y="239.25938" x="404.95599" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#0000ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="239.25938" x="404.95599" id="tspan7582-3-2-0-6-3" - sodipodi:role="line">J2KImageProxy</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">J2KImageProxy</tspan></text> <g transform="translate(-48.084616,122.93827)" id="g7700-7-9-3-7-9"> @@ -1256,29 +1400,28 @@ y="118.93896" /> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="471.76764" y="126.86294" - id="text7604-2-9-8-0-2" - sodipodi:linespacing="125%"><tspan + id="text7604-2-9-8-0-2"><tspan sodipodi:role="line" id="tspan7606-64-9-8-9-5" x="471.76764" - y="126.86294">XYZ</tspan></text> + y="126.86294" + style="font-size:8px;line-height:1.25">XYZ</tspan></text> </g> </g> <text xml:space="preserve" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" x="5.1282115" y="332.96237" - id="text8237-8" - sodipodi:linespacing="125%"><tspan + id="text8237-8"><tspan sodipodi:role="line" id="tspan8239-9" x="5.1282115" y="332.96237" - style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'"><tspan + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:1.25;font-family:'latin modern mono';-inkscape-font-specification:'latin modern mono'"><tspan style="fill:#0000ff" id="tspan8257-0">Player</tspan>::<tspan style="fill:#ff0000" @@ -1304,16 +1447,350 @@ id="rect8285-5" style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#eeaaff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" /> <text - sodipodi:linespacing="125%" id="text8154-1" y="244.55614" x="354.7998" - style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:8px;line-height:125%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" + style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:'latin modern roman';-inkscape-font-specification:'latin modern roman, ';text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#008000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" xml:space="preserve"><tspan y="244.55614" x="354.7998" id="tspan8156-0" - sodipodi:role="line">To RGB24</tspan></text> + sodipodi:role="line" + style="font-size:8px;line-height:1.25">To RGB24</tspan></text> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="-309.2775" + y="554.51569" + id="text1175" + transform="translate(32.203591,-61.256847)"><tspan + sodipodi:role="line" + id="tspan1173" + x="-309.2775" + y="554.51569" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">Decoder</tspan></text> + <g + id="g1275" + transform="translate(11.680627,-39.263855)"> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="-215.04077" + y="510.54083" + id="text1198" + transform="translate(-17.813399,3.8499265)"><tspan + sodipodi:role="line" + id="tspan1196" + x="-215.04077" + y="510.54083" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">ContentVideo</tspan><tspan + sodipodi:role="line" + x="-215.04077" + y="528.04083" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1200"> </tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="-160.62468" + y="559.99548" + id="text1211" + transform="translate(-64.169864,-34.683152)"><tspan + sodipodi:role="line" + id="tspan1209" + x="-160.62468" + y="559.99548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">ImageProxy</tspan><tspan + sodipodi:role="line" + x="-160.62468" + y="572.49548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1213" /><tspan + sodipodi:role="line" + x="-160.62468" + y="584.99548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1217" /><tspan + sodipodi:role="line" + x="-160.62468" + y="597.49548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1219" /></text> </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-309.2775" + y="554.51569" + id="text1175-2" + transform="translate(173.8463,-61.256847)"><tspan + sodipodi:role="line" + id="tspan1173-9" + x="-309.2775" + y="554.51569" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">Player</tspan></text> + <g + id="g1275-1" + transform="translate(149.15963,-38.395575)"> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="-215.04077" + y="510.54083" + id="text1198-2" + transform="translate(-17.813399,3.8499265)"><tspan + sodipodi:role="line" + id="tspan1196-7" + x="-215.04077" + y="510.54083" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">PlayerVideo</tspan><tspan + sodipodi:role="line" + x="-215.04077" + y="528.04083" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1200-0"> </tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="-160.62468" + y="559.99548" + id="text1211-9" + transform="translate(-64.169864,-34.683152)"><tspan + sodipodi:role="line" + id="tspan1209-3" + x="-160.62468" + y="559.99548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">ImageProxy</tspan><tspan + sodipodi:role="line" + x="-160.62468" + y="572.49548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1217-6" /><tspan + sodipodi:role="line" + x="-160.62468" + y="584.99548" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#008080;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan1219-2" /></text> + </g> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-309.2775" + y="554.51569" + id="text1175-2-6" + transform="translate(312.02999,-57.755915)"><tspan + sodipodi:role="line" + id="tspan1173-9-1" + x="-309.2775" + y="554.51569" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-309.2775" + y="554.51569" + id="text1175-2-8" + transform="translate(308.1405,-61.256847)"><tspan + sodipodi:role="line" + id="tspan1173-9-7" + x="-309.2775" + y="554.51569" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">Butler</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="-87.686157" + y="420.73074" + id="text1390" + transform="translate(4.0571512,20.445338)"><tspan + sodipodi:role="line" + id="tspan1388" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">DCPEncoder</tspan></text> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688)" + d="m -111.77743,479.80479 43.572482,-33.42047" + id="path1411" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-87.686157" + y="420.73074" + id="text1390-0" + transform="translate(164.6192,124.17483)"><tspan + sodipodi:role="line" + id="tspan1388-2" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">FFmpegEncoder</tspan></text> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688-3)" + d="M 33.640882,498.46273 77.213364,531.8832" + id="path1411-5" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-87.686157" + y="420.73074" + id="text1390-0-9" + transform="translate(167.72734,29.633718)"><tspan + sodipodi:role="line" + id="tspan1388-2-2" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">VideoView</tspan></text> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688-3-2)" + d="M 34.296475,481.15447 77.868957,447.734" + id="path1411-5-9" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-87.686157" + y="420.73074" + id="text1390-0-9-7" + transform="translate(265.11469,-6.3252721)"><tspan + sodipodi:role="line" + id="tspan1388-2-2-3" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">SimpleVideoView</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-87.686157" + y="420.73074" + id="text1390-0-9-6" + transform="translate(265.31069,64.227674)"><tspan + sodipodi:role="line" + id="tspan1388-2-2-1" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">GLVideoView</tspan></text> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688-3-29)" + d="m 147.31102,448.44631 27.54102,32.33461" + id="path1411-5-1" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688-3-29-9)" + d="m 147.83317,443.8501 27.54102,-32.33461" + id="path1411-5-1-7" + sodipodi:nodetypes="cc" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="336.05344" + y="420.61581" + id="text2864" + transform="translate(-31.120846,-23.390024)"><tspan + sodipodi:role="line" + id="tspan2862" + x="336.05344" + y="420.61581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">calls PlayerVideo::image(), hence make_image() which</tspan><tspan + sodipodi:role="line" + x="336.05344" + y="438.11581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan2885">does crop_scale_window(), so the PlayerVideo's </tspan><tspan + sodipodi:role="line" + x="336.05344" + y="455.61581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan2887">ImageProxy must be PADDED.</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="336.05344" + y="420.61581" + id="text2864-3" + transform="translate(2.3793434,115.28813)"><tspan + sodipodi:role="line" + id="tspan2862-6" + x="336.05344" + y="420.61581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">calls PlayerVideo::raw_image(), and passes</tspan><tspan + sodipodi:role="line" + x="336.05344" + y="438.11581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan2957">the result to GL, so the PlayerVideo's</tspan><tspan + sodipodi:role="line" + x="336.05344" + y="455.61581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan2959">ImageProxy must be COMPACT.</tspan><tspan + sodipodi:role="line" + x="336.05344" + y="473.11581" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan2887-0" /></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;opacity:1;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + x="309.21796" + y="618.7019" + id="text3143" + transform="translate(5.5245543,46.014145)"><tspan + sodipodi:role="line" + x="309.21796" + y="618.7019" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan3145">[ImageProxy's image may be made</tspan><tspan + sodipodi:role="line" + x="309.21796" + y="636.2019" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan3149">by ImageProxy::prepare() or by the</tspan><tspan + sodipodi:role="line" + x="309.21796" + y="653.7019" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#ff0000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1" + id="tspan4786">decoder which made the ImageProxy]</tspan></text> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-variation-settings:normal;opacity:1;vector-effect:none;fill-opacity:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;marker-end:url(#marker3668);stop-color:#000000;stop-opacity:1" + d="m -219.14841,490.17833 h 79.16702" + id="path3184" /> + <path + style="font-variation-settings:normal;vector-effect:none;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker-end:url(#marker3668-5);stop-color:#000000" + d="M -85.603289,490.17833 H -6.4362693" + id="path3184-9" /> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-87.686157" + y="420.73074" + id="text1390-0-9-6-3" + transform="translate(395.74642,92.267467)"><tspan + sodipodi:role="line" + id="tspan1388-2-2-1-7" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">[J2K optimised]</tspan></text> + <text + xml:space="preserve" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000" + x="-87.686157" + y="420.73074" + id="text1390-0-9-6-3-4" + transform="translate(395.74227,43.24724)"><tspan + sodipodi:role="line" + id="tspan1388-2-2-1-7-5" + x="-87.686157" + y="420.73074" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14px;line-height:1.25;font-family:'Latin Modern Mono';-inkscape-font-specification:'Latin Modern Mono';font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:0px;word-spacing:0px;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;vector-effect:none;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;stop-color:#000000;stop-opacity:1">[supporting any source]</tspan></text> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688-3-29-9-2)" + d="m 264.09526,481.80247 43.33723,-22.7705" + id="path1411-5-1-7-4" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;stroke:#000000;stroke-width:0.9375px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-end:url(#marker1688-3-29-9-2-7)" + d="m 263.91609,485.60031 43.33723,22.7705" + id="path1411-5-1-7-4-4" + sodipodi:nodetypes="cc" /> </g> </svg> diff --git a/hacks/gl-notes b/hacks/gl-notes new file mode 100644 index 000000000..0b1b11c2e --- /dev/null +++ b/hacks/gl-notes @@ -0,0 +1,17 @@ +4.3 with compute shaders "came out in 2012" +Anything before 3.0 is deprecated (especially anything with glBegin/glEnd) + +https://stackoverflow.com/questions/14300569/opengl-glbegin-glend +"The direct mode API with glBegin and glEnd is deprecated, largely for performance reasons." +"Using VBOs scales better" + +OpenGL 3.3 tutorials (written 2012) +http://www.opengl-tutorial.org/ + +An intro to modern OpenGL (written 2010) +https://duriansoftware.com/joe/an-intro-to-modern-opengl.-table-of-contents + +Learning Modern 3D Graphics Programming (written 2012) +https://web.archive.org/web/20140209181347/http://www.arcsynthesis.org/gltut/ + +"Since OpenGL3.3 most old stuff was moved to compatibility profile, while modern features are core profile; the latter requires self-written shaders, but they should be pretty simple for your case). diff --git a/hacks/gl/modern.cc b/hacks/gl/modern.cc new file mode 100644 index 000000000..748547e47 --- /dev/null +++ b/hacks/gl/modern.cc @@ -0,0 +1,319 @@ +#include <QtGui/QGuiApplication> +#include <QtGui/QKeyEvent> +#include <QtGui/QOpenGLWindow> +#include <QtGui/QOpenGLBuffer> +#include <QtGui/QOpenGLFunctions> +#include <QtGui/QOpenGLShaderProgram> +#include <QtGui/QOpenGLVertexArrayObject> +static QString vertexShader = +"#version 100\n" +"\n" +"attribute vec3 vertexPosition;\n" +"attribute vec3 vertexNormal;\n" +"attribute vec3 vertexColor;\n" +"attribute vec2 texCoord2d;\n" +"\n" +"uniform mat4 modelViewMatrix;\n" +"uniform mat3 normalMatrix;\n" +"uniform mat4 projectionMatrix;\n" +"\n" +"struct LightSource\n" +"{\n" +" vec3 ambient;\n" +" vec3 diffuse;\n" +" vec3 specular;\n" +" vec3 position;\n" +"};\n" +"uniform LightSource lightSource;\n" +"\n" +"struct LightModel\n" +"{\n" +" vec3 ambient;\n" +"};\n" +"uniform LightModel lightModel;\n" +"\n" +"struct Material {\n" +" vec3 emission;\n" +" vec3 specular;\n" +" float shininess;\n" +"};\n" +"uniform Material material;\n" +"\n" +"varying vec3 v_color;\n" +"varying vec2 v_texCoord2d;\n" +"\n" +"void main()\n" +"{\n" +" vec3 normal = normalize(normalMatrix * vertexNormal); // normal vector \n" +" vec3 position = vec3(modelViewMatrix * vec4(vertexPosition, 1)); // vertex pos in eye coords \n" +" vec3 halfVector = normalize(lightSource.position + vec3(0,0,1)); // light half vector \n" +" float nDotVP = dot(normal, normalize(lightSource.position)); // normal . light direction \n" +" float nDotHV = max(0.f, dot(normal, halfVector)); // normal . light half vector \n" +" float pf = mix(0.f, pow(nDotHV, material.shininess), step(0.f, nDotVP)); // power factor \n" +"\n" +" vec3 ambient = lightSource.ambient;\n" +" vec3 diffuse = lightSource.diffuse * nDotVP;\n" +" vec3 specular = lightSource.specular * pf;\n" +" vec3 sceneColor = material.emission + vertexColor * lightModel.ambient;\n" +"\n" +" v_color = clamp(sceneColor + \n" +" ambient * vertexColor + \n" +" diffuse * vertexColor + \n" +" specular * material.specular, 0.f, 1.f );\n" +"\n" +" v_texCoord2d = texCoord2d;\n" +"\n" +" gl_Position = projectionMatrix * modelViewMatrix * vec4(vertexPosition, 1);\n" +"}\n" +; +static QString fragmentShader = +"#version 100\n" +"precision lowp vec3;\n" +"precision lowp vec2;\n" +"uniform sampler2D texUnit;\n" +"\n" +"varying vec3 v_color;\n" +"varying vec2 v_texCoord2d;\n" +"\n" +"void main()\n" +"{\n" +" gl_FragColor = vec4(v_color, 1) * texture2D(texUnit, v_texCoord2d);\n" +"}\n" +; +/* +* Texture copied and modifided modified from: +* <a href="https://www.opengl.org/archives/resources/code/samples/mjktips/TexShadowReflectLight.html +*/ +static char *circles[] = { +"................", +"................", +"......xxxx......", +"....xxxxxxxx....", +"...xxxxxxxxxx...", +"...xxx....xxx...", +"..xxx......xxx..", +"..xxx......xxx..", +"..xxx......xxx..", +"..xxx......xxx..", +"...xxx....xxx...", +"...xxxxxxxxxx...", +"....xxxxxxxx....", +"......xxxx......", +"................", +"................", +}; +struct Window : QOpenGLWindow, QOpenGLFunctions +{ +Window() : +m_vbo(QOpenGLBuffer::VertexBuffer), +m_ibo(QOpenGLBuffer::IndexBuffer) +{ +} +void createShaderProgram() +{ +if ( !m_pgm.addShaderFromSourceCode( QOpenGLShader::Vertex, vertexShader)) { +qDebug() << "Error in vertex shader:" << m_pgm.log(); +exit(1); +} +if ( !m_pgm.addShaderFromSourceCode( QOpenGLShader::Fragment, fragmentShader)) { +qDebug() << "Error in fragment shader:" << m_pgm.log(); +exit(1); +} +if ( !m_pgm.link() ) { +qDebug() << "Error linking shader program:" << m_pgm.log(); +exit(1); +} +} +void createGeometry() +{ +// Initialize and bind the VAO that's going to capture all this vertex state +m_vao.create(); +m_vao.bind(); +// we need 24 vertices, 24 normals, and 24 colors (6 faces, 4 vertices per face) +// since we can't share normal data at the corners (each corner gets 3 normals) +// and since we're not using glVertexAttribDivisor (not available in ES 2.0) +struct Vertex { +GLfloat position[3], +normal [3], +color [3], +texcoord[2]; +} attribs[24]= { +// Top face (y = 1.0f) +{ { 1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 0.0f, 0.0f} }, // Green +{ {-1.0f, 1.0f, -1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 0.0f, 1.0f} }, // Green +{ {-1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 1.0f, 1.0f} }, // Green +{ { 1.0f, 1.0f, 1.0f}, {0.0f, 1.0f, 0.0f}, {0.0f, 1.0f, 0.0f}, { 1.0f, 0.0f} }, // Green +// Bottom face (y = -1.0f) +{ { 1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 0.0f, 0.0f} }, // Orange +{ {-1.0f, -1.0f, 1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 0.0f, 1.0f} }, // Orange +{ {-1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 1.0f, 1.0f} }, // Orange +{ { 1.0f, -1.0f, -1.0f}, {0.0f, -1.0f, 0.0f}, {1.0f, 0.5f, 0.0f}, { 1.0f, 0.0f} }, // Orange +// Front face (z = 1.0f) +{ { 1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 0.0f, 0.0f} }, // Red +{ {-1.0f, 1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 0.0f, 1.0f} }, // Red +{ {-1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 1.0f, 1.0f} }, // Red +{ { 1.0f, -1.0f, 1.0f}, {0.0f, 0.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, { 1.0f, 0.0f} }, // Red +// Back face (z = -1.0f) +{ { 1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 0.0f, 0.0f} }, // Yellow +{ {-1.0f, -1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 0.0f, 1.0f} }, // Yellow +{ {-1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 1.0f, 1.0f} }, // Yellow +{ { 1.0f, 1.0f, -1.0f}, {0.0f, 0.0f, -1.0f}, {1.0f, 1.0f, 0.0f}, { 1.0f, 0.0f} }, // Yellow +// Left face (x = -1.0f) +{ {-1.0f, 1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 0.0f, 0.0f} }, // Blue +{ {-1.0f, 1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 0.0f, 1.0f} }, // Blue +{ {-1.0f, -1.0f, -1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 1.0f, 1.0f} }, // Blue +{ {-1.0f, -1.0f, 1.0f}, {-1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}, { 1.0f, 0.0f} }, // Blue +// Right face (x = 1.0f) +{ {1.0f, 1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 0.0f, 0.0f} }, // Magenta +{ {1.0f, 1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 0.0f, 1.0f} }, // Magenta +{ {1.0f, -1.0f, 1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 1.0f, 1.0f} }, // Magenta +{ {1.0f, -1.0f, -1.0f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 1.0f}, { 1.0f, 0.0f} }, // Magenta +}; +// Put all the attribute data in a FBO +m_vbo.create(); +m_vbo.setUsagePattern( QOpenGLBuffer::StaticDraw ); +m_vbo.bind(); +m_vbo.allocate(&attribs, sizeof(attribs)); +// Configure the vertex streams for this attribute data layout +m_pgm.enableAttributeArray("vertexPosition"); +m_pgm.setAttributeBuffer("vertexPosition", GL_FLOAT, offsetof(Vertex, position), 3, sizeof(Vertex) ); +m_pgm.enableAttributeArray("vertexNormal"); +m_pgm.setAttributeBuffer("vertexNormal", GL_FLOAT, offsetof(Vertex, normal), 3, sizeof(Vertex) ); +m_pgm.enableAttributeArray("vertexColor"); +m_pgm.setAttributeBuffer("vertexColor", GL_FLOAT, offsetof(Vertex, color), 3, sizeof(Vertex) ); +m_pgm.enableAttributeArray("texCoord2d"); +m_pgm.setAttributeBuffer("texCoord2d", GL_FLOAT, offsetof(Vertex, texcoord), 3, sizeof(Vertex) ); +// we need 36 indices (6 faces, 2 triangles per face, 3 vertices per triangle) +struct { +GLubyte cube[36]; +} indices; +m_cnt=0; for (GLsizei i=0, v=0; v<6*4; v+=4) +{ +// first triangle (ccw winding) +indices.cube[i++] = v + 0; +indices.cube[i++] = v + 1; +indices.cube[i++] = v + 2; +// second triangle (ccw winding) +indices.cube[i++] = v + 0; +indices.cube[i++] = v + 2; +indices.cube[i++] = v + 3; +m_cnt = i; +} +// Put all the index data in a IBO +m_ibo.create(); +m_ibo.setUsagePattern( QOpenGLBuffer::StaticDraw ); +m_ibo.bind(); +m_ibo.allocate(&indices, sizeof(indices)); +// Okay, we've finished setting up the vao +m_vao.release(); +} +void createTexture(void) +{ +GLubyte image[16][16][3]; +GLubyte *loc; +int s, t; +/* Setup RGB image for the texture. */ +loc = (GLubyte*) image; +for (t = 0; t < 16; t++) { +for (s = 0; s < 16; s++) { +if (circles[t][s] == 'x') { +/* Nice green. */ +loc[0] = 0x1f; +loc[1] = 0x8f; +loc[2] = 0x1f; +} else { +/* Light gray. */ +loc[0] = 0xaa; +loc[1] = 0xaa; +loc[2] = 0xaa; +} +loc += 3; +} +} +glGenTextures (1, &m_tex); +glBindTexture (GL_TEXTURE_2D, m_tex); +glPixelStorei (GL_UNPACK_ALIGNMENT, 1); +glTexImage2D (GL_TEXTURE_2D, 0, 3, 16, 16, 0, GL_RGB, GL_UNSIGNED_BYTE, image); +glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); +glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); +glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); +} +void initializeGL() +{ +QOpenGLFunctions::initializeOpenGLFunctions(); +createShaderProgram(); m_pgm.bind(); +// Set lighting information +m_pgm.setUniformValue("lightSource.ambient", QVector3D( 0.0f, 0.0f, 0.0f )); // opengl fixed-function default +m_pgm.setUniformValue("lightSource.diffuse", QVector3D( 1.0f, 1.0f, 1.0f )); // opengl fixed-function default +m_pgm.setUniformValue("lightSource.specular", QVector3D( 1.0f, 1.0f, 1.0f )); // opengl fixed-function default +m_pgm.setUniformValue("lightSource.position", QVector3D( 1.0f, 1.0f, 1.0f )); // NOT DEFAULT VALUE +m_pgm.setUniformValue("lightModel.ambient", QVector3D( 0.2f, 0.2f, 0.2f )); // opengl fixed-function default +m_pgm.setUniformValue("material.emission", QVector3D( 0.0f, 0.0f, 0.0f )); // opengl fixed-function default +m_pgm.setUniformValue("material.specular", QVector3D( 1.0f, 1.0f, 1.0f )); // NOT DEFAULT VALUE +m_pgm.setUniformValue("material.shininess", 10.0f); // NOT DEFAULT VALUE +createGeometry(); +m_view.setToIdentity(); +glEnable(GL_DEPTH_TEST); +glEnable(GL_TEXTURE_2D); +glActiveTexture(GL_TEXTURE0); +m_pgm.setUniformValue("texUnit", 0); +createTexture(); +glClearColor(.5f,.5f,.5f,1.f); +} +void resizeGL(int w, int h) +{ +glViewport(0, 0, w, h); +m_projection.setToIdentity(); +if (w <= h) +m_projection.ortho(-2.f, 2.f, -2.f*h/w, 2.f*h/w, -2.f, 2.f); +else +m_projection.ortho(-2.f*w/h, 2.f*w/h, -2.f, 2.f, -2.f, 2.f); +update(); +} +void paintGL() +{ +static unsigned cnt; +glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +glActiveTexture(GL_TEXTURE0); +glBindTexture(GL_TEXTURE_2D, m_tex); +QMatrix4x4 model; +model.rotate(cnt%360, 1,0,0); +model.rotate(45, 0,0,1); +QMatrix4x4 mv = m_view * model; +m_pgm.bind(); +m_pgm.setUniformValue("modelViewMatrix", mv); +m_pgm.setUniformValue("normalMatrix", mv.normalMatrix()); +m_pgm.setUniformValue("projectionMatrix", m_projection); +m_vao.bind(); +glDrawElements(GL_TRIANGLES, m_cnt, GL_UNSIGNED_BYTE, 0); +update(); +++cnt; +} +void keyPressEvent(QKeyEvent * ev) +{ +switch (ev->key()) { +case Qt::Key_Escape: +exit(0); +break; +default: +QOpenGLWindow::keyPressEvent(ev); +break; +} +} +QMatrix4x4 m_projection, m_view; +QOpenGLShaderProgram m_pgm; +QOpenGLVertexArrayObject m_vao; +QOpenGLBuffer m_vbo; +QOpenGLBuffer m_ibo; +GLuint m_tex; +GLsizei m_cnt; +}; +int main(int argc, char *argv[]) +{ +QGuiApplication a(argc,argv); +Window w; +w.setWidth(640); w.setHeight(480); +w.show(); +return a.exec(); +} diff --git a/hacks/gl/shader.cc b/hacks/gl/shader.cc new file mode 100644 index 000000000..8d5f5fe70 --- /dev/null +++ b/hacks/gl/shader.cc @@ -0,0 +1,50 @@ +#include <wx/wx.h> +#include <wx/glcanvas.h> + + + +class GLCanvas +{ +public: + GLCanvas (wxFrame* parent) + { + _canvas = new wxGLCanvas(parent); + Bind(wxEVT_PAINT, bind(&GLCanvas::paint, this); + } + + wxWindow* get() + { + return _canvas; + } + + void paint() + { + + } + + +private: + wxGLCanvas* _canvas; +}; + + + +class MyApp : public wxApp +{ +public: + bool OnInit() + { + auto sizer = new wxBoxSizer(wxHORIZONTAL); + _frame = new wxFrame(nullptr, wxID_ANY, wxT("Hello world")); + _canvas = new GLCanvas(_frame); + sizer->Add(_canvas->get(), 1, wxEXPAND); + _frame->SetSizerAndFit(sizer); + _frame->Show(); + return true; + } + +private: + wxFrame* _frame; + GLCanvas* _canvas; +}; + diff --git a/platform/windows/wscript b/platform/windows/wscript index 6c8d47aac..ed5f5d4f2 100644 --- a/platform/windows/wscript +++ b/platform/windows/wscript @@ -164,6 +164,7 @@ File "%static_deps%/bin/libgpg-error-0.dll" File "%static_deps%/bin/libpangoft2-1.0-0.dll" File "%static_deps%/bin/libx264-155.dll" File "%static_deps%/bin/libwebp-7.dll" +File "%static_deps%/bin/GLEW.dll" """, file=f) if bits == 32: diff --git a/src/lib/bitmap_text.h b/src/lib/bitmap_text.h index b8861c10a..46b6fd142 100644 --- a/src/lib/bitmap_text.h +++ b/src/lib/bitmap_text.h @@ -31,12 +31,12 @@ class Image; class BitmapText { public: - BitmapText (std::shared_ptr<Image> i, dcpomatic::Rect<double> r) + BitmapText (std::shared_ptr<const Image> i, dcpomatic::Rect<double> r) : image (i) , rectangle (r) {} - std::shared_ptr<Image> image; + std::shared_ptr<const Image> image; /** Area that the subtitle covers on its corresponding video, expressed in * proportions of the image size; e.g. rectangle.x = 0.5 would mean that * the rectangle starts half-way across the video. diff --git a/src/lib/butler.cc b/src/lib/butler.cc index 5a8e646aa..5a5cc4912 100644 --- a/src/lib/butler.cc +++ b/src/lib/butler.cc @@ -57,7 +57,7 @@ using namespace boost::placeholders; /** @param pixel_format Pixel format functor that will be used when calling ::image on PlayerVideos coming out of this * butler. This will be used (where possible) to prepare the PlayerVideos so that calling image() on them is quick. - * @param aligned Same as above for the `aligned' flag. + * @param alignment Same as above for the `alignment' value. * @param fast Same as above for the `fast' flag. */ Butler::Butler ( @@ -67,8 +67,9 @@ Butler::Butler ( int audio_channels, function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, - bool aligned, - bool fast + Image::Alignment alignment, + bool fast, + bool prepare_only_proxy ) : _film (film) , _player (player) @@ -83,8 +84,9 @@ Butler::Butler ( , _disable_audio (false) , _pixel_format (pixel_format) , _video_range (video_range) - , _aligned (aligned) + , _alignment (alignment) , _fast (fast) + , _prepare_only_proxy (prepare_only_proxy) { _player_video_connection = _player->Video.connect (bind (&Butler::video, this, _1, _2)); _player_audio_connection = _player->Audio.connect (bind (&Butler::audio, this, _1, _2, _3)); @@ -323,7 +325,7 @@ try /* If the weak_ptr cannot be locked the video obviously no longer requires any work */ if (video) { LOG_TIMING("start-prepare in %1", thread_id()); - video->prepare (_pixel_format, _video_range, _aligned, _fast); + video->prepare (_pixel_format, _video_range, _alignment, _fast, _prepare_only_proxy); LOG_TIMING("finish-prepare in %1", thread_id()); } } diff --git a/src/lib/butler.h b/src/lib/butler.h index a231fd099..cd3891754 100644 --- a/src/lib/butler.h +++ b/src/lib/butler.h @@ -45,8 +45,9 @@ public: int audio_channels, std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, - bool aligned, - bool fast + Image::Alignment alignment, + bool fast, + bool prepare_only_proxy ); ~Butler (); @@ -124,9 +125,17 @@ private: std::function<AVPixelFormat (AVPixelFormat)> _pixel_format; VideoRange _video_range; - bool _aligned; + Image::Alignment _alignment; bool _fast; + /** true to ask PlayerVideo::prepare to only prepare the ImageProxy and not also + * the final image. We want to do this when the viewer is intending to call + * PlayerVideo::raw_image() and do the things in PlayerVideo::make_imgae() itself: + * this is the case for the GLVideoView which can do scale, pixfmt conversion etc. + * in the shader. + */ + bool _prepare_only_proxy = false; + /** If we are waiting to be refilled following a seek, this is the time we were seeking to. */ diff --git a/src/lib/content_text.h b/src/lib/content_text.h index c6d7d6ec2..5edb9af20 100644 --- a/src/lib/content_text.h +++ b/src/lib/content_text.h @@ -48,7 +48,7 @@ private: class ContentBitmapText : public ContentText { public: - ContentBitmapText (dcpomatic::ContentTime f, std::shared_ptr<Image> im, dcpomatic::Rect<double> r) + ContentBitmapText (dcpomatic::ContentTime f, std::shared_ptr<const Image> im, dcpomatic::Rect<double> r) : ContentText (f) , sub (im, r) {} diff --git a/src/lib/dcp_video.cc b/src/lib/dcp_video.cc index 4a505a7e1..3a85a5ac6 100644 --- a/src/lib/dcp_video.cc +++ b/src/lib/dcp_video.cc @@ -59,19 +59,21 @@ DCPOMATIC_ENABLE_WARNINGS #include "i18n.h" + using std::cout; using std::make_shared; using std::shared_ptr; using std::string; -using dcp::Size; using dcp::ArrayData; using dcp::raw_convert; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif + #define DCI_COEFFICENT (48.0 / 52.37) + /** Construct a DCP video frame. * @param frame Input frame. * @param index Index of the frame within the DCP. @@ -103,7 +105,7 @@ DCPVideo::convert_to_xyz (shared_ptr<const PlayerVideo> frame, dcp::NoteHandler { shared_ptr<dcp::OpenJPEGImage> xyz; - auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, true, false); + auto image = frame->image (bind(&PlayerVideo::keep_xyz_or_rgb, _1), VideoRange::FULL, false); if (frame->colour_conversion()) { xyz = dcp::rgb_to_xyz ( image->data()[0], diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index fe27cb7dd..1d688c318 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -41,7 +41,7 @@ Encoder::Encoder (std::shared_ptr<const Film> film, std::weak_ptr<Job> job) : _film (film) , _job (job) - , _player (new Player(film)) + , _player (new Player(film, Image::Alignment::PADDED)) { } diff --git a/src/lib/exceptions.cc b/src/lib/exceptions.cc index ebb607b94..3f87a2ebe 100644 --- a/src/lib/exceptions.cc +++ b/src/lib/exceptions.cc @@ -132,6 +132,13 @@ GLError::GLError (char const* last, int e) } +GLError::GLError (char const* message) + : runtime_error (message) +{ + +} + + CopyError::CopyError (string m, optional<int> n) : runtime_error (String::compose("%1%2", m, n ? String::compose(" (%1)", *n) : "")) , _message (m) diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index d0ba1f068..9b7837a46 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -378,6 +378,7 @@ class GLError : public std::runtime_error { public: GLError (char const* last, int e); + GLError (char const* message); }; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 72372fca8..2baa99876 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -18,31 +18,33 @@ */ + /** @file src/ffmpeg_decoder.cc * @brief A decoder using FFmpeg to decode content. */ -#include "filter.h" -#include "exceptions.h" -#include "image.h" -#include "util.h" -#include "log.h" + +#include "audio_buffers.h" +#include "audio_content.h" +#include "audio_decoder.h" +#include "compose.hpp" #include "dcpomatic_log.h" -#include "ffmpeg_decoder.h" -#include "text_decoder.h" +#include "exceptions.h" #include "ffmpeg_audio_stream.h" -#include "ffmpeg_subtitle_stream.h" -#include "video_filter_graph.h" -#include "audio_buffers.h" #include "ffmpeg_content.h" -#include "raw_image_proxy.h" -#include "video_decoder.h" +#include "ffmpeg_decoder.h" +#include "ffmpeg_subtitle_stream.h" #include "film.h" -#include "audio_decoder.h" -#include "compose.hpp" -#include "text_content.h" -#include "audio_content.h" +#include "filter.h" #include "frame_interval_checker.h" +#include "image.h" +#include "log.h" +#include "raw_image_proxy.h" +#include "text_content.h" +#include "text_decoder.h" +#include "util.h" +#include "video_decoder.h" +#include "video_filter_graph.h" #include <dcp/subtitle_string.h> #include <sub/ssa_reader.h> #include <sub/subtitle.h> @@ -52,28 +54,22 @@ extern "C" { #include <libavformat/avformat.h> } #include <boost/algorithm/string.hpp> -#include <vector> #include <iomanip> #include <iostream> +#include <vector> #include <stdint.h> #include "i18n.h" + using std::cout; -using std::string; -using std::vector; -using std::list; +using std::dynamic_pointer_cast; +using std::make_shared; using std::min; -using std::pair; -using std::max; -using std::map; using std::shared_ptr; -using std::make_shared; -using std::make_pair; -using boost::is_any_of; -using boost::split; +using std::string; +using std::vector; using boost::optional; -using std::dynamic_pointer_cast; using dcp::Size; using namespace dcpomatic; @@ -86,7 +82,7 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr<const Film> film, shared_ptr<const FFmp video = make_shared<VideoDecoder>(this, c); _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate(film)); /* It doesn't matter what size or pixel format this is, it just needs to be black */ - _black_image.reset (new Image (AV_PIX_FMT_RGB24, dcp::Size (128, 128), true)); + _black_image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (128, 128), Image::Alignment::PADDED); _black_image->make_black (); } else { _pts_offset = {}; @@ -684,7 +680,7 @@ FFmpegDecoder::process_bitmap_subtitle (AVSubtitleRect const * rect, ContentTime /* Note BGRA is expressed little-endian, so the first byte in the word is B, second G, third R, fourth A. */ - auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), true); + auto image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (rect->w, rect->h), Image::Alignment::PADDED); #ifdef DCPOMATIC_HAVE_AVSUBTITLERECT_PICT /* Start of the first line in the subtitle */ diff --git a/src/lib/ffmpeg_encoder.cc b/src/lib/ffmpeg_encoder.cc index 61ca1ae00..dd773168a 100644 --- a/src/lib/ffmpeg_encoder.cc +++ b/src/lib/ffmpeg_encoder.cc @@ -18,26 +18,25 @@ */ + +#include "butler.h" +#include "cross.h" #include "ffmpeg_encoder.h" #include "film.h" +#include "image.h" #include "job.h" +#include "log.h" #include "player.h" #include "player_video.h" -#include "log.h" -#include "image.h" -#include "cross.h" -#include "butler.h" #include "compose.hpp" #include <iostream> #include "i18n.h" + using std::cout; using std::list; using std::make_shared; -using std::map; -using std::pair; -using std::runtime_error; using std::shared_ptr; using std::string; using std::weak_ptr; @@ -48,6 +47,7 @@ using namespace dcpomatic; using namespace boost::placeholders; #endif + /** @param key Key to use to encrypt MP4 outputs */ FFmpegEncoder::FFmpegEncoder ( shared_ptr<const Film> film, @@ -108,7 +108,7 @@ FFmpegEncoder::FFmpegEncoder ( } _butler = std::make_shared<Butler>( - _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, true, false + _film, _player, map, _output_audio_channels, bind(&PlayerVideo::force, _1, FFmpegFileEncoder::pixel_format(format)), VideoRange::VIDEO, Image::Alignment::PADDED, false, false ); } diff --git a/src/lib/ffmpeg_file_encoder.cc b/src/lib/ffmpeg_file_encoder.cc index 533fd151c..705557f79 100644 --- a/src/lib/ffmpeg_file_encoder.cc +++ b/src/lib/ffmpeg_file_encoder.cc @@ -19,16 +19,16 @@ */ +#include "compose.hpp" +#include "cross.h" #include "ffmpeg_encoder.h" #include "ffmpeg_wrapper.h" #include "film.h" +#include "image.h" #include "job.h" +#include "log.h" #include "player.h" #include "player_video.h" -#include "log.h" -#include "image.h" -#include "cross.h" -#include "compose.hpp" extern "C" { #include <libavutil/channel_layout.h> } @@ -39,13 +39,9 @@ extern "C" { using std::cout; using std::make_shared; -using std::pair; -using std::runtime_error; using std::shared_ptr; using std::string; -using std::weak_ptr; using boost::bind; -using boost::optional; using namespace dcpomatic; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -406,7 +402,6 @@ FFmpegFileEncoder::video (shared_ptr<PlayerVideo> video, DCPTime time) auto image = video->image ( bind (&PlayerVideo::force, _1, _pixel_format), VideoRange::VIDEO, - true, false ); diff --git a/src/lib/ffmpeg_image_proxy.cc b/src/lib/ffmpeg_image_proxy.cc index e7d5b424d..4b3c3084c 100644 --- a/src/lib/ffmpeg_image_proxy.cc +++ b/src/lib/ffmpeg_image_proxy.cc @@ -122,7 +122,7 @@ FFmpegImageProxy::avio_seek (int64_t const pos, int whence) ImageProxy::Result -FFmpegImageProxy::image (optional<dcp::Size>) const +FFmpegImageProxy::image (Image::Alignment alignment, optional<dcp::Size>) const { auto constexpr name_for_errors = "FFmpegImageProxy::image"; @@ -205,7 +205,7 @@ FFmpegImageProxy::image (optional<dcp::Size>) const throw DecodeError (N_("avcodec_receive_frame"), name_for_errors, r, *_path); } - _image = make_shared<Image>(frame); + _image = make_shared<Image>(frame, alignment); av_packet_unref (&packet); av_frame_free (&frame); diff --git a/src/lib/ffmpeg_image_proxy.h b/src/lib/ffmpeg_image_proxy.h index 21109c9d6..48317ed75 100644 --- a/src/lib/ffmpeg_image_proxy.h +++ b/src/lib/ffmpeg_image_proxy.h @@ -32,6 +32,7 @@ public: FFmpegImageProxy (std::shared_ptr<Socket> socket); Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; diff --git a/src/lib/hints.cc b/src/lib/hints.cc index 64122db8d..46704ebf8 100644 --- a/src/lib/hints.cc +++ b/src/lib/hints.cc @@ -51,11 +51,8 @@ using std::cout; using std::make_shared; using std::max; -using std::min; -using std::pair; using std::shared_ptr; using std::string; -using std::vector; using std::weak_ptr; using boost::optional; using boost::bind; @@ -408,7 +405,7 @@ try emit (bind(boost::ref(Progress), _("Examining audio, subtitles and closed captions"))); } - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->set_ignore_video (); if (check_loudness_done) { /* We don't need to analyse audio because we already loaded a suitable analysis */ diff --git a/src/lib/image.cc b/src/lib/image.cc index 8e6c5717b..a4e04bb62 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -64,8 +64,8 @@ using std::string; using dcp::Size; -/** The memory alignment, in bytes, used for each row of an image if aligment is requested */ -#define ALIGNMENT 64 +/** The memory alignment, in bytes, used for each row of an image if Alignment::PADDED is requested */ +int constexpr ALIGNMENT = 64; /* U/V black value for 8-bit colour */ static uint8_t const eight_bit_uv = (1 << 7) - 1; @@ -177,19 +177,19 @@ Image::crop_scale_window ( VideoRange video_range, AVPixelFormat out_format, VideoRange out_video_range, - bool out_aligned, + Alignment out_alignment, bool fast ) const { /* Empirical testing suggests that sws_scale() will crash if - the input image is not aligned. + the input image is not padded. */ - DCPOMATIC_ASSERT (aligned ()); + DCPOMATIC_ASSERT (alignment() == Alignment::PADDED); DCPOMATIC_ASSERT (out_size.width >= inter_size.width); DCPOMATIC_ASSERT (out_size.height >= inter_size.height); - auto out = make_shared<Image>(out_format, out_size, out_aligned); + auto out = make_shared<Image>(out_format, out_size, out_alignment); out->make_black (); auto in_desc = av_pix_fmt_desc_get (_pixel_format); @@ -310,27 +310,27 @@ Image::crop_scale_window ( } shared_ptr<Image> -Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const { - return scale(size(), yuv_to_rgb, out_format, out_aligned, fast); + return scale(size(), yuv_to_rgb, out_format, out_alignment, fast); } /** @param out_size Size to scale to. * @param yuv_to_rgb YUVToRGB transform transform to use, if required. * @param out_format Output pixel format. - * @param out_aligned true to make an aligned output image. + * @param out_aligment Output alignment. * @param fast Try to be fast at the possible expense of quality; at present this means using * fast bilinear rather than bicubic scaling. */ shared_ptr<Image> -Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool out_aligned, bool fast) const +Image::scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment out_alignment, bool fast) const { /* Empirical testing suggests that sws_scale() will crash if - the input image is not aligned. + the input image alignment is not PADDED. */ - DCPOMATIC_ASSERT (aligned ()); + DCPOMATIC_ASSERT (alignment() == Alignment::PADDED); - auto scaled = make_shared<Image>(out_format, out_size, out_aligned); + auto scaled = make_shared<Image>(out_format, out_size, out_alignment); auto scale_context = sws_getContext ( size().width, size().height, pixel_format(), out_size.width, out_size.height, out_format, @@ -736,7 +736,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV420P: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -771,7 +771,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV420P10: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -806,7 +806,7 @@ Image::alpha_blend (shared_ptr<const Image> other, Position<int> position) } case AV_PIX_FMT_YUV422P10LE: { - auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, false, false); + auto yuv = other->convert_pixel_format (dcp::YUVToRGB::REC709, _pixel_format, Alignment::COMPACT, false); dcp::Size const ts = size(); dcp::Size const os = yuv->size(); for (int ty = start_ty, oy = start_oy; ty < ts.height && oy < os.height; ++ty, ++oy) { @@ -934,16 +934,17 @@ Image::bytes_per_pixel (int c) const * * @param p Pixel format. * @param s Size in pixels. - * @param aligned true to make each row of this image aligned to a ALIGNMENT-byte boundary. + * @param alignment PADDED to make each row of this image aligned to a ALIGNMENT-byte boundary, otherwise COMPACT. */ -Image::Image (AVPixelFormat p, dcp::Size s, bool aligned) +Image::Image (AVPixelFormat p, dcp::Size s, Alignment alignment) : _size (s) , _pixel_format (p) - , _aligned (aligned) + , _alignment (alignment) { allocate (); } + void Image::allocate () { @@ -958,7 +959,7 @@ Image::allocate () for (int i = 0; i < planes(); ++i) { _line_size[i] = ceil (_size.width * bytes_per_pixel(i)); - _stride[i] = stride_round_up (i, _line_size, _aligned ? ALIGNMENT : 1); + _stride[i] = stride_round_up (i, _line_size, _alignment == Alignment::PADDED ? ALIGNMENT : 1); /* The assembler function ff_rgb24ToY_avx (in libswscale/x86/input.asm) uses a 16-byte fetch to read three bytes (R/G/B) of image data. @@ -1011,7 +1012,7 @@ Image::Image (Image const & other) : std::enable_shared_from_this<Image>(other) , _size (other._size) , _pixel_format (other._pixel_format) - , _aligned (other._aligned) + , _alignment (other._alignment) { allocate (); @@ -1027,10 +1028,10 @@ Image::Image (Image const & other) } } -Image::Image (AVFrame const * frame) +Image::Image (AVFrame const * frame, Alignment alignment) : _size (frame->width, frame->height) , _pixel_format (static_cast<AVPixelFormat>(frame->format)) - , _aligned (true) + , _alignment (alignment) { DCPOMATIC_ASSERT (_pixel_format != AV_PIX_FMT_NONE); @@ -1049,10 +1050,10 @@ Image::Image (AVFrame const * frame) } } -Image::Image (shared_ptr<const Image> other, bool aligned) +Image::Image (shared_ptr<const Image> other, Alignment alignment) : _size (other->_size) , _pixel_format (other->_pixel_format) - , _aligned (aligned) + , _alignment (alignment) { allocate (); @@ -1093,7 +1094,7 @@ Image::swap (Image & other) std::swap (_stride[i], other._stride[i]); } - std::swap (_aligned, other._aligned); + std::swap (_alignment, other._alignment); } Image::~Image () @@ -1131,22 +1132,23 @@ Image::size () const return _size; } -bool -Image::aligned () const +Image::Alignment +Image::alignment () const { - return _aligned; + return _alignment; } PositionImage -merge (list<PositionImage> images) +merge (list<PositionImage> images, Image::Alignment alignment) { if (images.empty ()) { return {}; } if (images.size() == 1) { - return images.front (); + images.front().image = Image::ensure_alignment(images.front().image, alignment); + return images.front(); } dcpomatic::Rect<int> all (images.front().position, images.front().image->size().width, images.front().image->size().height); @@ -1154,7 +1156,7 @@ merge (list<PositionImage> images) all.extend (dcpomatic::Rect<int>(i.position, i.image->size().width, i.image->size().height)); } - auto merged = make_shared<Image>(images.front().image->pixel_format(), dcp::Size(all.width, all.height), true); + auto merged = make_shared<Image>(images.front().image->pixel_format(), dcp::Size(all.width, all.height), alignment); merged->make_transparent (); for (auto const& i: images) { merged->alpha_blend (i.image, i.position - all.position()); @@ -1167,7 +1169,7 @@ merge (list<PositionImage> images) bool operator== (Image const & a, Image const & b) { - if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.aligned() != b.aligned()) { + if (a.planes() != b.planes() || a.pixel_format() != b.pixel_format() || a.alignment() != b.alignment()) { return false; } @@ -1312,16 +1314,18 @@ Image::fade (float f) } } + shared_ptr<const Image> -Image::ensure_aligned (shared_ptr<const Image> image) +Image::ensure_alignment (shared_ptr<const Image> image, Image::Alignment alignment) { - if (image->aligned()) { + if (image->alignment() == alignment) { return image; } - return make_shared<Image>(image, true); + return make_shared<Image>(image, alignment); } + size_t Image::memory_used () const { @@ -1393,7 +1397,7 @@ Image::as_png () const DCPOMATIC_ASSERT (bytes_per_pixel(0) == 4); DCPOMATIC_ASSERT (planes() == 1); if (pixel_format() != AV_PIX_FMT_RGBA) { - return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png(); + return convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png(); } /* error handling? */ diff --git a/src/lib/image.h b/src/lib/image.h index cb8f11ffc..128b546b5 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -40,10 +40,15 @@ class Socket; class Image : public std::enable_shared_from_this<Image> { public: - Image (AVPixelFormat p, dcp::Size s, bool aligned); - explicit Image (AVFrame const *); + enum class Alignment { + COMPACT, + PADDED + }; + + Image (AVPixelFormat p, dcp::Size s, Alignment alignment); + explicit Image (AVFrame const *, Alignment alignment); explicit Image (Image const &); - Image (std::shared_ptr<const Image>, bool); + Image (std::shared_ptr<const Image>, Alignment alignment); Image& operator= (Image const &); ~Image (); @@ -53,7 +58,7 @@ public: /** @return array of sizes of the data in each line, in bytes (including any alignment padding) */ int const * stride () const; dcp::Size size () const; - bool aligned () const; + Alignment alignment () const; int planes () const; int vertical_factor (int) const; @@ -61,8 +66,8 @@ public: dcp::Size sample_size (int) const; float bytes_per_pixel (int) const; - std::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; - std::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, bool aligned, bool fast) const; + std::shared_ptr<Image> convert_pixel_format (dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; + std::shared_ptr<Image> scale (dcp::Size out_size, dcp::YUVToRGB yuv_to_rgb, AVPixelFormat out_format, Alignment alignment, bool fast) const; std::shared_ptr<Image> crop_scale_window ( Crop crop, dcp::Size inter_size, @@ -71,7 +76,7 @@ public: VideoRange video_range, AVPixelFormat out_format, VideoRange out_video_range, - bool aligned, + Alignment alignment, bool fast ) const; @@ -94,7 +99,7 @@ public: void png_error (char const * message); - static std::shared_ptr<const Image> ensure_aligned (std::shared_ptr<const Image> image); + static std::shared_ptr<const Image> ensure_alignment (std::shared_ptr<const Image> image, Alignment alignment); private: friend struct pixel_formats_test; @@ -112,10 +117,10 @@ private: uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in bytes (without any alignment padding bytes) int* _stride; ///< array of strides for each line, in bytes (including any alignment padding bytes) - bool _aligned; + Alignment _alignment; }; -extern PositionImage merge (std::list<PositionImage> images); +extern PositionImage merge (std::list<PositionImage> images, Image::Alignment alignment); extern bool operator== (Image const & a, Image const & b); #endif diff --git a/src/lib/image_examiner.cc b/src/lib/image_examiner.cc index 89d1517ce..ae12d7adb 100644 --- a/src/lib/image_examiner.cc +++ b/src/lib/image_examiner.cc @@ -67,7 +67,7 @@ ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const Imag delete[] buffer; } else { FFmpegImageProxy proxy(content->path(0)); - _video_size = proxy.image().image->size(); + _video_size = proxy.image(Image::Alignment::COMPACT).image->size(); } if (content->still ()) { diff --git a/src/lib/image_proxy.h b/src/lib/image_proxy.h index 22946ed98..a37be580f 100644 --- a/src/lib/image_proxy.h +++ b/src/lib/image_proxy.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington <cth@carlh.net> + Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,13 +18,17 @@ */ + #ifndef DCPOMATIC_IMAGE_PROXY_H #define DCPOMATIC_IMAGE_PROXY_H + /** @file src/lib/image_proxy.h * @brief ImageProxy and subclasses. */ + +#include "image.h" extern "C" { #include <libavutil/pixfmt.h> } @@ -32,6 +36,7 @@ extern "C" { #include <boost/optional.hpp> #include <boost/utility.hpp> + class Image; class Socket; @@ -43,6 +48,7 @@ namespace cxml { class Node; } + /** @class ImageProxy * @brief A class which holds an Image, and can produce it on request. * @@ -64,7 +70,7 @@ public: ImageProxy& operator= (ImageProxy const&) = delete; struct Result { - Result (std::shared_ptr<Image> image_, int log2_scaling_) + Result (std::shared_ptr<const Image> image_, int log2_scaling_) : image (image_) , log2_scaling (log2_scaling_) , error (false) @@ -76,8 +82,7 @@ public: , error (error_) {} - /** Image (which will be aligned) */ - std::shared_ptr<Image> image; + std::shared_ptr<const Image> image; /** log2 of any scaling down that has already been applied to the image; * e.g. if the image is already half the size of the original, this value * will be 1. @@ -92,6 +97,7 @@ public: * can be used as an optimisation. */ virtual Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const = 0; @@ -103,10 +109,12 @@ public: * This method may be called in a different thread to image(). * @return log2 of any scaling down that will be applied to the image. */ - virtual int prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; } + virtual int prepare (Image::Alignment, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const { return 0; } virtual size_t memory_used () const = 0; }; + std::shared_ptr<ImageProxy> image_proxy_factory (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); + #endif diff --git a/src/lib/j2k_image_proxy.cc b/src/lib/j2k_image_proxy.cc index 144da396d..00d3cf2ef 100644 --- a/src/lib/j2k_image_proxy.cc +++ b/src/lib/j2k_image_proxy.cc @@ -42,10 +42,8 @@ DCPOMATIC_ENABLE_WARNINGS using std::cout; using std::dynamic_pointer_cast; -using std::make_pair; using std::make_shared; using std::max; -using std::pair; using std::shared_ptr; using std::string; using boost::optional; @@ -108,7 +106,7 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc if (xml->optional_number_child<int>("Eye")) { _eye = static_cast<dcp::Eye>(xml->number_child<int>("Eye")); } - shared_ptr<ArrayData> data(new ArrayData(xml->number_child<int>("Size"))); + auto data = make_shared<ArrayData>(xml->number_child<int>("Size")); /* This only matters when we are using J2KImageProxy for the preview, which will never use this constructor (which is only used for passing data to encode servers). So we can put anything in here. It's a bit of a hack. @@ -120,7 +118,7 @@ J2KImageProxy::J2KImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc int -J2KImageProxy::prepare (optional<dcp::Size> target_size) const +J2KImageProxy::prepare (Image::Alignment alignment, optional<dcp::Size> target_size) const { boost::mutex::scoped_lock lm (_mutex); @@ -145,7 +143,7 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const try { /* XXX: should check that potentially trashing _data here doesn't matter */ auto decompressed = dcp::decompress_j2k (const_cast<uint8_t*>(_data->data()), _data->size(), reduce); - _image.reset (new Image (_pixel_format, decompressed->size(), true)); + _image = make_shared<Image>(_pixel_format, decompressed->size(), alignment); int const shift = 16 - decompressed->precision (0); @@ -169,7 +167,7 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const } } } catch (dcp::J2KDecompressionError& e) { - _image = make_shared<Image>(_pixel_format, _size, true); + _image = make_shared<Image>(_pixel_format, _size, alignment); _image->make_black (); _error = true; } @@ -182,9 +180,9 @@ J2KImageProxy::prepare (optional<dcp::Size> target_size) const ImageProxy::Result -J2KImageProxy::image (optional<dcp::Size> target_size) const +J2KImageProxy::image (Image::Alignment alignment, optional<dcp::Size> target_size) const { - int const r = prepare (target_size); + int const r = prepare (alignment, target_size); /* I think this is safe without a lock on mutex. _image is guaranteed to be set up when prepare() has happened. diff --git a/src/lib/j2k_image_proxy.h b/src/lib/j2k_image_proxy.h index 5235d8e42..d925bef86 100644 --- a/src/lib/j2k_image_proxy.h +++ b/src/lib/j2k_image_proxy.h @@ -57,6 +57,7 @@ public: J2KImageProxy (dcp::ArrayData data, dcp::Size size, AVPixelFormat pixel_format); Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; @@ -64,7 +65,7 @@ public: void write_to_socket (std::shared_ptr<Socket>) const; /** @return true if our image is definitely the same as another, false if it is probably not */ bool same (std::shared_ptr<const ImageProxy>) const; - int prepare (boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; + int prepare (Image::Alignment alignment, boost::optional<dcp::Size> = boost::optional<dcp::Size>()) const; std::shared_ptr<const dcp::Data> j2k () const { return _data; diff --git a/src/lib/player.cc b/src/lib/player.cc index 5de089ba9..7951926e6 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -70,7 +70,6 @@ using std::dynamic_pointer_cast; using std::list; using std::make_pair; using std::make_shared; -using std::map; using std::max; using std::min; using std::min; @@ -95,11 +94,12 @@ int const PlayerProperty::DCP_DECODE_REDUCTION = 704; int const PlayerProperty::PLAYBACK_LENGTH = 705; -Player::Player (shared_ptr<const Film> film) +Player::Player (shared_ptr<const Film> film, Image::Alignment subtitle_alignment) : _film (film) , _suspended (0) , _tolerant (film->tolerant()) , _audio_merger (_film->audio_frame_rate()) + , _subtitle_alignment (subtitle_alignment) { construct (); } @@ -331,7 +331,7 @@ Player::set_video_container_size (dcp::Size s) _video_container_size = s; - _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_container_size, true)); + _black_image = make_shared<Image>(AV_PIX_FMT_RGB24, _video_container_size, Image::Alignment::PADDED); _black_image->make_black (); } @@ -827,7 +827,7 @@ Player::open_subtitles_for_frame (DCPTime time) const return {}; } - return merge (captions); + return merge (captions, _subtitle_alignment); } @@ -1055,7 +1055,7 @@ Player::bitmap_text_start (weak_ptr<Piece> wp, weak_ptr<const TextContent> wc, C } dcp::Size scaled_size (width, height); - ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), true, _fast), subtitle.sub.rectangle)); + ps.bitmap.push_back (BitmapText(image->scale(scaled_size, dcp::YUVToRGB::REC601, image->pixel_format(), Image::Alignment::PADDED, _fast), subtitle.sub.rectangle)); DCPTime from (content_time_to_dcp (piece, subtitle.from())); _active_texts[static_cast<int>(text->type())].add_from (wc, ps, from); diff --git a/src/lib/player.h b/src/lib/player.h index 6cefbe232..b74aeeefd 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -34,6 +34,7 @@ #include "content_video.h" #include "empty.h" #include "film.h" +#include "image.h" #include "piece.h" #include "player_text.h" #include "position_image.h" @@ -76,7 +77,7 @@ public: class Player : public std::enable_shared_from_this<Player> { public: - Player (std::shared_ptr<const Film>); + Player (std::shared_ptr<const Film>, Image::Alignment subtitle_alignment); Player (std::shared_ptr<const Film>, std::shared_ptr<const Playlist> playlist); Player (Player const& Player) = delete; @@ -233,6 +234,9 @@ private: dcpomatic::DCPTime _playback_length; + /** Alignment for subtitle images that we create */ + Image::Alignment _subtitle_alignment = Image::Alignment::PADDED; + boost::signals2::scoped_connection _film_changed_connection; boost::signals2::scoped_connection _playlist_change_connection; boost::signals2::scoped_connection _playlist_content_change_connection; diff --git a/src/lib/player_video.cc b/src/lib/player_video.cc index b0e75972c..7c36af31b 100644 --- a/src/lib/player_video.cc +++ b/src/lib/player_video.cc @@ -94,7 +94,7 @@ PlayerVideo::PlayerVideo (shared_ptr<cxml::Node> node, shared_ptr<Socket> socket if (node->optional_number_child<int>("SubtitleX")) { auto image = make_shared<Image> ( - AV_PIX_FMT_BGRA, dcp::Size(node->number_child<int>("SubtitleWidth"), node->number_child<int>("SubtitleHeight")), true + AV_PIX_FMT_BGRA, dcp::Size(node->number_child<int>("SubtitleWidth"), node->number_child<int>("SubtitleHeight")), Image::Alignment::PADDED ); image->read_from_socket (socket); @@ -110,33 +110,40 @@ PlayerVideo::set_text (PositionImage image) } shared_ptr<Image> -PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const { /* XXX: this assumes that image() and prepare() are only ever called with the same parameters (except crop, inter size, out size, fade) */ boost::mutex::scoped_lock lm (_mutex); if (!_image || _crop != _image_crop || _inter_size != _image_inter_size || _out_size != _image_out_size || _fade != _image_fade) { - make_image (pixel_format, video_range, aligned, fast); + make_image (pixel_format, video_range, fast); } return _image; } + +shared_ptr<const Image> +PlayerVideo::raw_image () const +{ + return _in->image(Image::Alignment::COMPACT, _inter_size).image; +} + + /** Create an image for this frame. A lock must be held on _mutex. * @param pixel_format Function which is called to decide what pixel format the output image should be; * it is passed the pixel format of the input image from the ImageProxy, and should return the desired * output pixel format. Two functions force and keep_xyz_or_rgb are provided for use here. - * @param aligned true if the output image should be aligned to 32-byte boundaries. * @param fast true to be fast at the expense of quality. */ void -PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const +PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const { _image_crop = _crop; _image_inter_size = _inter_size; _image_out_size = _out_size; _image_fade = _fade; - auto prox = _in->image (_inter_size); + auto prox = _in->image (Image::Alignment::PADDED, _inter_size); _error = prox.error; auto total_crop = _crop; @@ -172,11 +179,11 @@ PlayerVideo::make_image (function<AVPixelFormat (AVPixelFormat)> pixel_format, V } _image = prox.image->crop_scale_window ( - total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, aligned, fast + total_crop, _inter_size, _out_size, yuv_to_rgb, _video_range, pixel_format (prox.image->pixel_format()), video_range, Image::Alignment::COMPACT, fast ); if (_text) { - _image->alpha_blend (Image::ensure_aligned (_text->image), _text->position); + _image->alpha_blend (_text->image, _text->position); } if (_fade) { @@ -290,12 +297,12 @@ PlayerVideo::keep_xyz_or_rgb (AVPixelFormat p) } void -PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) +PlayerVideo::prepare (function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only) { - _in->prepare (_inter_size); + _in->prepare (alignment, _inter_size); boost::mutex::scoped_lock lm (_mutex); - if (!_image) { - make_image (pixel_format, video_range, aligned, fast); + if (!_image && !proxy_only) { + make_image (pixel_format, video_range, fast); } } diff --git a/src/lib/player_video.h b/src/lib/player_video.h index f29684832..237d2e3fe 100644 --- a/src/lib/player_video.h +++ b/src/lib/player_video.h @@ -23,11 +23,12 @@ #define DCPOMATIC_PLAYER_VIDEO_H -#include "types.h" -#include "position.h" -#include "dcpomatic_time.h" #include "colour_conversion.h" +#include "dcpomatic_time.h" +#include "image.h" +#include "position.h" #include "position_image.h" +#include "types.h" extern "C" { #include <libavutil/pixfmt.h> } @@ -70,9 +71,13 @@ public: std::shared_ptr<PlayerVideo> shallow_copy () const; void set_text (PositionImage); + boost::optional<PositionImage> text () const { + return _text; + } - void prepare (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast); - std::shared_ptr<Image> image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void prepare (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, Image::Alignment alignment, bool fast, bool proxy_only); + std::shared_ptr<Image> image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const; + std::shared_ptr<const Image> raw_image () const; static AVPixelFormat force (AVPixelFormat, AVPixelFormat); static AVPixelFormat keep_xyz_or_rgb (AVPixelFormat); @@ -105,6 +110,10 @@ public: return _inter_size; } + dcp::Size out_size () const { + return _out_size; + } + bool same (std::shared_ptr<const PlayerVideo> other) const; size_t memory_used () const; @@ -118,7 +127,7 @@ public: } private: - void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool aligned, bool fast) const; + void make_image (std::function<AVPixelFormat (AVPixelFormat)> pixel_format, VideoRange video_range, bool fast) const; std::shared_ptr<const ImageProxy> _in; Crop _crop; diff --git a/src/lib/position_image.h b/src/lib/position_image.h index 2b7e7080a..ee352647c 100644 --- a/src/lib/position_image.h +++ b/src/lib/position_image.h @@ -35,12 +35,12 @@ class PositionImage public: PositionImage () {} - PositionImage (std::shared_ptr<Image> i, Position<int> p) + PositionImage (std::shared_ptr<const Image> i, Position<int> p) : image (i) , position (p) {} - std::shared_ptr<Image> image; + std::shared_ptr<const Image> image; Position<int> position; bool same (PositionImage const & other) const; diff --git a/src/lib/raw_image_proxy.cc b/src/lib/raw_image_proxy.cc index fed40c45e..fb0d16df8 100644 --- a/src/lib/raw_image_proxy.cc +++ b/src/lib/raw_image_proxy.cc @@ -58,15 +58,16 @@ RawImageProxy::RawImageProxy (shared_ptr<cxml::Node> xml, shared_ptr<Socket> soc xml->number_child<int>("Width"), xml->number_child<int>("Height") ); - _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, true); + _image = make_shared<Image>(static_cast<AVPixelFormat>(xml->number_child<int>("PixelFormat")), size, Image::Alignment::PADDED); _image->read_from_socket (socket); } ImageProxy::Result -RawImageProxy::image (optional<dcp::Size>) const +RawImageProxy::image (Image::Alignment alignment, optional<dcp::Size>) const { - return Result (_image, 0); + /* This ensure_alignment could be wasteful */ + return Result (Image::ensure_alignment(_image, alignment), 0); } @@ -95,7 +96,7 @@ RawImageProxy::same (shared_ptr<const ImageProxy> other) const return false; } - return (*_image.get()) == (*rp->image().image.get()); + return (*_image.get()) == (*rp->image(_image->alignment()).image.get()); } diff --git a/src/lib/raw_image_proxy.h b/src/lib/raw_image_proxy.h index ec30f5a29..c9885654b 100644 --- a/src/lib/raw_image_proxy.h +++ b/src/lib/raw_image_proxy.h @@ -33,6 +33,7 @@ public: RawImageProxy (std::shared_ptr<cxml::Node> xml, std::shared_ptr<Socket> socket); Result image ( + Image::Alignment alignment, boost::optional<dcp::Size> size = boost::optional<dcp::Size> () ) const; diff --git a/src/lib/render_text.cc b/src/lib/render_text.cc index 7bb7d6b45..94b412856 100644 --- a/src/lib/render_text.cc +++ b/src/lib/render_text.cc @@ -48,8 +48,6 @@ using std::min; using std::pair; using std::shared_ptr; using std::string; -using boost::optional; -using boost::algorithm::replace_all; using namespace dcpomatic; @@ -95,8 +93,10 @@ set_source_rgba (Cairo::RefPtr<Cairo::Context> context, dcp::Colour colour, floa static shared_ptr<Image> create_image (dcp::Size size) { - /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha */ - auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, false); + /* FFmpeg BGRA means first byte blue, second byte green, third byte red, fourth byte alpha. + * This must be COMPACT as we're using it with Cairo::ImageSurface::create + */ + auto image = make_shared<Image>(AV_PIX_FMT_BGRA, size, Image::Alignment::COMPACT); image->make_black (); return image; } @@ -105,6 +105,11 @@ create_image (dcp::Size size) static Cairo::RefPtr<Cairo::ImageSurface> create_surface (shared_ptr<Image> image) { + /* XXX: I don't think it's guaranteed that format_stride_for_width will return a stride without any padding, + * so it's lucky that this works. + */ + DCPOMATIC_ASSERT (image->alignment() == Image::Alignment::COMPACT); + DCPOMATIC_ASSERT (image->pixel_format() == AV_PIX_FMT_BGRA); return Cairo::ImageSurface::create ( image->data()[0], Cairo::FORMAT_ARGB32, diff --git a/src/lib/text_decoder.cc b/src/lib/text_decoder.cc index 6ee6ed079..8111154e3 100644 --- a/src/lib/text_decoder.cc +++ b/src/lib/text_decoder.cc @@ -61,7 +61,7 @@ TextDecoder::TextDecoder ( * of the video frame) */ void -TextDecoder::emit_bitmap_start (ContentTime from, shared_ptr<Image> image, dcpomatic::Rect<double> rect) +TextDecoder::emit_bitmap_start (ContentTime from, shared_ptr<const Image> image, dcpomatic::Rect<double> rect) { BitmapStart (ContentBitmapText (from, image, rect)); _position = from; @@ -286,7 +286,7 @@ TextDecoder::emit_plain (ContentTimePeriod period, sub::Subtitle const & s) * of the video frame) */ void -TextDecoder::emit_bitmap (ContentTimePeriod period, shared_ptr<Image> image, dcpomatic::Rect<double> rect) +TextDecoder::emit_bitmap (ContentTimePeriod period, shared_ptr<const Image> image, dcpomatic::Rect<double> rect) { emit_bitmap_start (period.from, image, rect); emit_stop (period.to); diff --git a/src/lib/text_decoder.h b/src/lib/text_decoder.h index 6e96b6b91..d1355afb0 100644 --- a/src/lib/text_decoder.h +++ b/src/lib/text_decoder.h @@ -52,8 +52,8 @@ public: return _position; } - void emit_bitmap_start (dcpomatic::ContentTime from, std::shared_ptr<Image> image, dcpomatic::Rect<double> rect); - void emit_bitmap (dcpomatic::ContentTimePeriod period, std::shared_ptr<Image> image, dcpomatic::Rect<double> rect); + void emit_bitmap_start (dcpomatic::ContentTime from, std::shared_ptr<const Image> image, dcpomatic::Rect<double> rect); + void emit_bitmap (dcpomatic::ContentTimePeriod period, std::shared_ptr<const Image> image, dcpomatic::Rect<double> rect); void emit_plain_start (dcpomatic::ContentTime from, std::list<dcp::SubtitleString> s); void emit_plain_start (dcpomatic::ContentTime from, sub::Subtitle const & subtitle); void emit_plain (dcpomatic::ContentTimePeriod period, std::list<dcp::SubtitleString> s); diff --git a/src/lib/util.cc b/src/lib/util.cc index 0646a4787..d3af74376 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -22,31 +22,33 @@ * @brief Some utility functions and classes. */ + #define UNICODE 1 -#include "util.h" -#include "exceptions.h" -#include "dcp_content_type.h" -#include "filter.h" + +#include "audio_buffers.h" +#include "audio_processor.h" #include "cinema_sound_processor.h" +#include "compose.hpp" #include "config.h" -#include "ratio.h" -#include "job.h" #include "cross.h" -#include "video_content.h" -#include "rect.h" -#include "digester.h" -#include "audio_processor.h" #include "crypto.h" -#include "compose.hpp" -#include "audio_buffers.h" -#include "string_text.h" -#include "font.h" -#include "render_text.h" +#include "dcp_content_type.h" +#include "digester.h" +#include "exceptions.h" #include "ffmpeg_image_proxy.h" +#include "filter.h" +#include "font.h" #include "image.h" -#include "text_decoder.h" +#include "job.h" #include "job_manager.h" +#include "ratio.h" +#include "rect.h" +#include "render_text.h" +#include "string_text.h" +#include "text_decoder.h" +#include "util.h" +#include "video_content.h" #include "warnings.h" #include <dcp/decrypted_kdm.h> #include <dcp/locale_convert.h> @@ -93,25 +95,23 @@ DCPOMATIC_ENABLE_WARNINGS #include "i18n.h" -using std::string; -using std::wstring; -using std::setfill; -using std::ostream; + +using std::bad_alloc; +using std::cout; using std::endl; -using std::vector; -using std::min; -using std::max; -using std::map; -using std::list; -using std::multimap; using std::istream; +using std::list; +using std::make_pair; +using std::make_shared; +using std::map; +using std::min; +using std::ostream; using std::pair; -using std::cout; -using std::bad_alloc; using std::set_terminate; -using std::make_pair; using std::shared_ptr; -using std::make_shared; +using std::string; +using std::vector; +using std::wstring; using boost::thread; using boost::optional; using boost::lexical_cast; @@ -122,6 +122,7 @@ using dcp::raw_convert; using dcp::locale_convert; using namespace dcpomatic; + /** Path to our executable, required by the stacktrace stuff and filled * in during App::onInit(). */ @@ -956,7 +957,7 @@ emit_subtitle_image (ContentTimePeriod period, dcp::SubtitleImage sub, dcp::Size { /* XXX: this is rather inefficient; decoding the image just to get its size */ FFmpegImageProxy proxy (sub.png_image()); - auto image = proxy.image().image; + auto image = proxy.image(Image::Alignment::PADDED).image; /* set up rect with height and width */ dcpomatic::Rect<double> rect(0, 0, image->size().width / double(size.width), image->size().height / double(size.height)); diff --git a/src/lib/video_filter_graph.cc b/src/lib/video_filter_graph.cc index a61da6773..0c7e23b05 100644 --- a/src/lib/video_filter_graph.cc +++ b/src/lib/video_filter_graph.cc @@ -38,7 +38,6 @@ using std::make_shared; using std::pair; using std::shared_ptr; using std::string; -using std::vector; VideoFilterGraph::VideoFilterGraph (dcp::Size s, AVPixelFormat p, dcp::Fraction r) @@ -59,7 +58,7 @@ VideoFilterGraph::process (AVFrame* frame) list<pair<shared_ptr<Image>, int64_t>> images; if (_copy) { - images.push_back (make_pair(make_shared<Image>(frame), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared<Image>(frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); } else { int r = av_buffersrc_write_frame (_buffer_src_context, frame); if (r < 0) { @@ -71,7 +70,7 @@ VideoFilterGraph::process (AVFrame* frame) break; } - images.push_back (make_pair(make_shared<Image>(_frame), frame->best_effort_timestamp)); + images.push_back (make_pair(make_shared<Image>(_frame, Image::Alignment::PADDED), frame->best_effort_timestamp)); av_frame_unref (_frame); } } diff --git a/src/tools/dcpomatic_player.cc b/src/tools/dcpomatic_player.cc index 7181ad129..e409b9731 100644 --- a/src/tools/dcpomatic_player.cc +++ b/src/tools/dcpomatic_player.cc @@ -139,20 +139,9 @@ class DOMFrame : public wxFrame { public: DOMFrame () - : wxFrame (0, -1, _("DCP-o-matic Player")) - , _dual_screen (0) - , _update_news_requested (false) - , _info (0) + : wxFrame (nullptr, -1, _("DCP-o-matic Player")) , _mode (Config::instance()->player_mode()) - , _config_dialog (0) - , _file_menu (0) - , _history_items (0) - , _history_position (0) - , _history_separator (0) - , _system_information_dialog (0) - , _view_full_screen (0) - , _view_dual_screen (0) - , _main_sizer (new wxBoxSizer (wxVERTICAL)) + , _main_sizer (new wxBoxSizer(wxVERTICAL)) { dcpomatic_log = make_shared<NullLog>(); @@ -199,7 +188,7 @@ public: */ _overall_panel = new wxPanel (this, wxID_ANY); - _viewer.reset (new FilmViewer (_overall_panel)); + _viewer = make_shared<FilmViewer>(_overall_panel); if (Config::instance()->player_mode() == Config::PLAYER_MODE_DUAL) { auto pc = new PlaylistControls (_overall_panel, _viewer); _controls = pc; @@ -208,6 +197,7 @@ public: _controls = new StandardControls (_overall_panel, _viewer, false); } _viewer->set_dcp_decode_reduction (Config::instance()->decode_reduction ()); + _viewer->set_optimise_for_j2k (true); _viewer->PlaybackPermitted.connect (bind(&DOMFrame::playback_permitted, this)); _viewer->Started.connect (bind(&DOMFrame::playback_started, this, _1)); _viewer->Stopped.connect (bind(&DOMFrame::playback_stopped, this, _1)); @@ -255,7 +245,7 @@ public: reset_film (); - UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this)); + UpdateChecker::instance()->StateChanged.connect (boost::bind(&DOMFrame::update_checker_state_changed, this)); setup_screen (); _stress.LoadDCP.connect (boost::bind(&DOMFrame::load_dcp, this, _1)); @@ -1038,30 +1028,30 @@ private: _viewer->seek (_film->length() - _viewer->one_video_frame(), true); } - wxFrame* _dual_screen; - bool _update_news_requested; - PlayerInformation* _info; + wxFrame* _dual_screen = nullptr; + bool _update_news_requested = false; + PlayerInformation* _info = nullptr; Config::PlayerMode _mode; - wxPreferencesEditor* _config_dialog; - wxPanel* _overall_panel; - wxMenu* _file_menu; - wxMenuItem* _view_cpl; - wxMenu* _cpl_menu; - int _history_items; - int _history_position; - wxMenuItem* _history_separator; + wxPreferencesEditor* _config_dialog = nullptr; + wxPanel* _overall_panel = nullptr; + wxMenu* _file_menu = nullptr; + wxMenuItem* _view_cpl = nullptr; + wxMenu* _cpl_menu = nullptr; + int _history_items = 0; + int _history_position = 0; + wxMenuItem* _history_separator = nullptr; shared_ptr<FilmViewer> _viewer; Controls* _controls; - SystemInformationDialog* _system_information_dialog; + SystemInformationDialog* _system_information_dialog = nullptr; std::shared_ptr<Film> _film; boost::signals2::scoped_connection _config_changed_connection; boost::signals2::scoped_connection _examine_job_connection; - wxMenuItem* _file_add_ov; - wxMenuItem* _file_add_kdm; - wxMenuItem* _tools_verify; - wxMenuItem* _view_full_screen; - wxMenuItem* _view_dual_screen; - wxSizer* _main_sizer; + wxMenuItem* _file_add_ov = nullptr; + wxMenuItem* _file_add_kdm = nullptr; + wxMenuItem* _tools_verify = nullptr; + wxMenuItem* _view_full_screen = nullptr; + wxMenuItem* _view_dual_screen = nullptr; + wxSizer* _main_sizer = nullptr; PlayerStressTester _stress; }; @@ -1106,7 +1096,6 @@ class App : public wxApp public: App () : wxApp () - , _frame (0) { #ifdef DCPOMATIC_LINUX XInitThreads (); @@ -1117,7 +1106,7 @@ private: bool OnInit () { - wxSplashScreen* splash = 0; + wxSplashScreen* splash = nullptr; try { wxInitAllImageHandlers (); @@ -1167,7 +1156,7 @@ private: _frame->Maximize (); if (splash) { splash->Destroy (); - splash = 0; + splash = nullptr; } _frame->Show (); @@ -1292,7 +1281,7 @@ private: message_dialog (_frame, std_to_wx (m)); } - DOMFrame* _frame; + DOMFrame* _frame = nullptr; string _dcp_to_load; boost::optional<string> _stress; }; diff --git a/src/tools/server_test.cc b/src/tools/server_test.cc index 6c7371253..ff3295599 100644 --- a/src/tools/server_test.cc +++ b/src/tools/server_test.cc @@ -155,7 +155,7 @@ main (int argc, char* argv[]) film = make_shared<Film>(film_dir); film->read_metadata (); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->Video.connect (bind(&process_video, _1)); while (!player->pass ()) {} } catch (std::exception& e) { diff --git a/src/wx/controls.cc b/src/wx/controls.cc index 700769a50..29f4aeaa3 100644 --- a/src/wx/controls.cc +++ b/src/wx/controls.cc @@ -144,13 +144,13 @@ Controls::Controls (wxWindow* parent, shared_ptr<FilmViewer> viewer, bool editor _jump_to_selected->SetValue (Config::instance()->jump_to_selected ()); } - _viewer->Started.connect (boost::bind(&Controls::started, this)); - _viewer->Stopped.connect (boost::bind(&Controls::stopped, this)); + viewer->Started.connect (boost::bind(&Controls::started, this)); + viewer->Stopped.connect (boost::bind(&Controls::stopped, this)); Bind (wxEVT_TIMER, boost::bind(&Controls::update_position, this)); _timer.Start (80, wxTIMER_CONTINUOUS); - set_film (_viewer->film()); + set_film (viewer->film()); setup_sensitivity (); @@ -186,7 +186,12 @@ Controls::stopped () void Controls::update_position () { - if (!_slider_being_moved && !_viewer->pending_idle_get()) { + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + + if (!_slider_being_moved && !viewer->pending_idle_get()) { update_position_label (); update_position_slider (); } @@ -196,14 +201,24 @@ Controls::update_position () void Controls::eye_changed () { - _viewer->set_eyes (_eye->GetSelection() == 0 ? Eyes::LEFT : Eyes::RIGHT); + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + + viewer->set_eyes (_eye->GetSelection() == 0 ? Eyes::LEFT : Eyes::RIGHT); } void Controls::outline_content_changed () { - _viewer->set_outline_content (_outline_content->GetValue()); + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + + viewer->set_outline_content (_outline_content->GetValue()); } @@ -211,13 +226,14 @@ Controls::outline_content_changed () void Controls::slider_moved (bool page) { - if (!_film) { + auto viewer = _viewer.lock (); + if (!_film || !viewer) { return; } if (!page && !_slider_being_moved) { /* This is the first event of a drag; stop playback for the duration of the drag */ - _viewer->suspend (); + viewer->suspend (); _slider_being_moved = true; } @@ -228,10 +244,10 @@ Controls::slider_moved (bool page) */ bool accurate = false; if (t >= _film->length ()) { - t = _film->length() - _viewer->one_video_frame(); + t = _film->length() - viewer->one_video_frame(); accurate = true; } - _viewer->seek (t, accurate); + viewer->seek (t, accurate); update_position_label (); log ( @@ -245,8 +261,13 @@ Controls::slider_moved (bool page) void Controls::slider_released () { + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + /* Restart after a drag */ - _viewer->resume (); + viewer->resume (); _slider_being_moved = false; } @@ -259,10 +280,15 @@ Controls::update_position_slider () return; } + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + auto const len = _film->length (); if (len.get ()) { - int const new_slider_position = 4096 * _viewer->position().get() / len.get(); + int const new_slider_position = 4096 * viewer->position().get() / len.get(); if (new_slider_position != _slider->GetValue()) { _slider->SetValue (new_slider_position); } @@ -279,10 +305,15 @@ Controls::update_position_label () return; } + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + double const fps = _film->video_frame_rate (); /* Count frame number from 1 ... not sure if this is the best idea */ - checked_set (_frame_number, wxString::Format (wxT("%ld"), lrint (_viewer->position().seconds() * fps) + 1)); - checked_set (_timecode, time_to_timecode (_viewer->position(), fps)); + checked_set (_frame_number, wxString::Format (wxT("%ld"), lrint (viewer->position().seconds() * fps) + 1)); + checked_set (_timecode, time_to_timecode (viewer->position(), fps)); } @@ -297,7 +328,12 @@ Controls::active_jobs_changed (optional<string> j) DCPTime Controls::nudge_amount (wxKeyboardState& ev) { - auto amount = _viewer->one_video_frame (); + auto viewer = _viewer.lock (); + if (!viewer) { + return {}; + } + + auto amount = viewer->one_video_frame (); if (ev.ShiftDown() && !ev.ControlDown()) { amount = DCPTime::from_seconds (1); @@ -314,7 +350,10 @@ Controls::nudge_amount (wxKeyboardState& ev) void Controls::rewind_clicked (wxMouseEvent& ev) { - _viewer->seek (DCPTime(), true); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->seek (DCPTime(), true); + } ev.Skip(); } @@ -322,28 +361,40 @@ Controls::rewind_clicked (wxMouseEvent& ev) void Controls::back_frame () { - _viewer->seek_by (-_viewer->one_video_frame(), true); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->seek_by (-viewer->one_video_frame(), true); + } } void Controls::forward_frame () { - _viewer->seek_by (_viewer->one_video_frame(), true); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->seek_by (viewer->one_video_frame(), true); + } } void Controls::back_clicked (wxKeyboardState& ev) { - _viewer->seek_by (-nudge_amount(ev), true); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->seek_by (-nudge_amount(ev), true); + } } void Controls::forward_clicked (wxKeyboardState& ev) { - _viewer->seek_by (nudge_amount(ev), true); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->seek_by (nudge_amount(ev), true); + } } @@ -376,9 +427,14 @@ Controls::setup_sensitivity () void Controls::timecode_clicked () { - auto dialog = new PlayheadToTimecodeDialog (this, _viewer->position(), _film->video_frame_rate()); + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + + auto dialog = new PlayheadToTimecodeDialog (this, viewer->position(), _film->video_frame_rate()); if (dialog->ShowModal() == wxID_OK) { - _viewer->seek (dialog->get(), true); + viewer->seek (dialog->get(), true); } dialog->Destroy (); } @@ -387,9 +443,14 @@ Controls::timecode_clicked () void Controls::frame_number_clicked () { - auto dialog = new PlayheadToFrameDialog (this, _viewer->position(), _film->video_frame_rate()); + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + + auto dialog = new PlayheadToFrameDialog (this, viewer->position(), _film->video_frame_rate()); if (dialog->ShowModal() == wxID_OK) { - _viewer->seek (dialog->get(), true); + viewer->seek (dialog->get(), true); } dialog->Destroy (); } diff --git a/src/wx/controls.h b/src/wx/controls.h index 9a22d7709..377960425 100644 --- a/src/wx/controls.h +++ b/src/wx/controls.h @@ -79,7 +79,7 @@ protected: wxBoxSizer* _button_sizer; std::shared_ptr<Film> _film; wxSlider* _slider; - std::shared_ptr<FilmViewer> _viewer; + std::weak_ptr<FilmViewer> _viewer; boost::optional<std::string> _active_job; private: diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index c7e154fa5..0131aa294 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -63,17 +63,11 @@ extern "C" { using std::bad_alloc; using std::cout; using std::dynamic_pointer_cast; -using std::exception; -using std::list; -using std::make_pair; using std::make_shared; using std::max; -using std::min; -using std::pair; using std::shared_ptr; using std::string; using std::vector; -using std::weak_ptr; using boost::optional; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -96,10 +90,10 @@ FilmViewer::FilmViewer (wxWindow* p) { switch (Config::instance()->video_view_type()) { case Config::VIDEO_VIEW_OPENGL: - _video_view = new GLVideoView (this, p); + _video_view = std::make_shared<GLVideoView>(this, p); break; case Config::VIDEO_VIEW_SIMPLE: - _video_view = new SimpleVideoView (this, p); + _video_view = std::make_shared<SimpleVideoView>(this, p); break; } @@ -169,7 +163,7 @@ FilmViewer::set_film (shared_ptr<Film> film) } try { - _player = make_shared<Player>(_film); + _player = make_shared<Player>(_film, _optimise_for_j2k ? Image::Alignment::COMPACT : Image::Alignment::PADDED); _player->set_fast (); if (_dcp_decode_reduction) { _player->set_dcp_decode_reduction (_dcp_decode_reduction); @@ -214,6 +208,8 @@ FilmViewer::recreate_butler () return; } + auto const j2k_gl_optimised = dynamic_pointer_cast<GLVideoView>(_video_view) && _optimise_for_j2k; + _butler = std::make_shared<Butler>( _film, _player, @@ -221,8 +217,9 @@ FilmViewer::recreate_butler () _audio_channels, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, - false, - true + j2k_gl_optimised ? Image::Alignment::COMPACT : Image::Alignment::PADDED, + true, + j2k_gl_optimised ); if (!Config::instance()->sound() && !_audio.isStreamOpen()) { @@ -281,21 +278,22 @@ FilmViewer::calculate_sizes () auto const view_ratio = float(_video_view->get()->GetSize().x) / _video_view->get()->GetSize().y; auto const film_ratio = container ? container->ratio () : 1.78; + dcp::Size out_size; if (view_ratio < film_ratio) { /* panel is less widscreen than the film; clamp width */ - _out_size.width = _video_view->get()->GetSize().x; - _out_size.height = lrintf (_out_size.width / film_ratio); + out_size.width = _video_view->get()->GetSize().x; + out_size.height = lrintf (out_size.width / film_ratio); } else { /* panel is more widescreen than the film; clamp height */ - _out_size.height = _video_view->get()->GetSize().y; - _out_size.width = lrintf (_out_size.height * film_ratio); + out_size.height = _video_view->get()->GetSize().y; + out_size.width = lrintf (out_size.height * film_ratio); } /* Catch silly values */ - _out_size.width = max (64, _out_size.width); - _out_size.height = max (64, _out_size.height); + out_size.width = max (64, out_size.width); + out_size.height = max (64, out_size.height); - _player->set_video_container_size (_out_size); + _player->set_video_container_size (out_size); } @@ -771,3 +769,12 @@ FilmViewer::image_changed (shared_ptr<PlayerVideo> pv) { emit (boost::bind(boost::ref(ImageChanged), pv)); } + + +void +FilmViewer::set_optimise_for_j2k (bool o) +{ + _optimise_for_j2k = o; + _video_view->set_optimise_for_j2k (o); +} + diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 2efe448c9..5e5bb7916 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -62,7 +62,7 @@ public: return _video_view->get(); } - VideoView const * video_view () const { + std::shared_ptr<const VideoView> video_view () const { return _video_view; } @@ -98,6 +98,7 @@ public: void set_outline_subtitles (boost::optional<dcpomatic::Rect<double>>); void set_eyes (Eyes e); void set_pad_black (bool p); + void set_optimise_for_j2k (bool o); void slow_refresh (); @@ -115,9 +116,6 @@ public: } /* Some accessors and utility methods that VideoView classes need */ - dcp::Size out_size () const { - return _out_size; - } bool outline_content () const { return _outline_content; } @@ -172,13 +170,10 @@ private: std::shared_ptr<Film> _film; std::shared_ptr<Player> _player; - VideoView* _video_view = nullptr; + std::shared_ptr<VideoView> _video_view; bool _coalesce_player_changes = false; std::vector<int> _pending_player_changes; - /** Size of our output (including padding if we have any) */ - dcp::Size _out_size; - RtAudio _audio; int _audio_channels = 0; unsigned int _audio_block_size = 1024; @@ -193,6 +188,11 @@ private: boost::optional<int> _dcp_decode_reduction; + /** true to assume that this viewer is only being used for JPEG2000 sources + * so it can optimise accordingly. + */ + bool _optimise_for_j2k = false; + ClosedCaptionsDialog* _closed_captions_dialog = nullptr; bool _outline_content = false; diff --git a/src/wx/gl_video_view.cc b/src/wx/gl_video_view.cc index 7bf9e3adc..04e0bac46 100644 --- a/src/wx/gl_video_view.cc +++ b/src/wx/gl_video_view.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2018-2019 Carl Hetherington <cth@carlh.net> + Copyright (C) 2018-2021 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,6 +18,11 @@ */ + +#ifdef DCPOMATIC_WINDOWS +#include <GL/glew.h> +#endif + #include "gl_video_view.h" #include "film_viewer.h" #include "wx_util.h" @@ -31,10 +36,9 @@ #include <iostream> #ifdef DCPOMATIC_OSX -#include <OpenGL/glu.h> -#include <OpenGL/glext.h> -#include <OpenGL/CGLTypes.h> +#define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED #include <OpenGL/OpenGL.h> +#include <OpenGL/gl3.h> #endif #ifdef DCPOMATIC_LINUX @@ -44,12 +48,13 @@ #ifdef DCPOMATIC_WINDOWS #include <GL/glu.h> -#include <GL/glext.h> #include <GL/wglext.h> #endif + using std::cout; using std::shared_ptr; +using std::string; using boost::optional; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; @@ -69,12 +74,19 @@ check_gl_error (char const * last) GLVideoView::GLVideoView (FilmViewer* viewer, wxWindow *parent) : VideoView (viewer) , _context (nullptr) - , _have_storage (false) , _vsync_enabled (false) , _playing (false) , _one_shot (false) { - _canvas = new wxGLCanvas (parent, wxID_ANY, 0, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE); + wxGLAttributes attributes; + /* We don't need a depth buffer, and indeed there is apparently a bug with Windows/Intel HD 630 + * which puts green lines over the OpenGL display if you have a non-zero depth buffer size. + * https://community.intel.com/t5/Graphics/Request-for-details-on-Intel-HD-630-green-lines-in-OpenGL-apps/m-p/1202179 + */ + attributes.PlatformDefaults().MinRGBA(8, 8, 8, 8).DoubleBuffer().Depth(0).EndList(); + _canvas = new wxGLCanvas ( + parent, attributes, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxFULL_REPAINT_ON_RESIZE + ); _canvas->Bind (wxEVT_PAINT, boost::bind(&GLVideoView::update, this)); _canvas->Bind (wxEVT_SIZE, boost::bind(&GLVideoView::size_changed, this, _1)); @@ -101,8 +113,6 @@ GLVideoView::~GLVideoView () _thread.interrupt (); _thread.join (); } catch (...) {} - - glDeleteTextures (1, &_id); } void @@ -130,9 +140,18 @@ GLVideoView::update () return; } + /* It appears important to do this from the GUI thread; if we do it from the GL thread + * on Linux we get strange failures to create the context for any version of GL higher + * than 3.2. + */ + ensure_context (); + #ifdef DCPOMATIC_OSX /* macOS gives errors if we don't do this (and therefore [NSOpenGLContext setView:]) from the main thread */ - ensure_context (); + if (!_setup_shaders_done) { + setup_shaders (); + _setup_shaders_done = true; + } #endif if (!_thread.joinable()) { @@ -140,34 +159,307 @@ GLVideoView::update () } request_one_shot (); + + rethrow (); } +static constexpr char vertex_source[] = +"#version 330 core\n" +"\n" +"layout (location = 0) in vec3 in_pos;\n" +"layout (location = 1) in vec2 in_tex_coord;\n" +"\n" +"out vec2 TexCoord;\n" +"\n" +"void main()\n" +"{\n" +" gl_Position = vec4(in_pos, 1.0);\n" +" TexCoord = in_tex_coord;\n" +"}\n"; + + +/* Bicubic interpolation stolen from https://stackoverflow.com/questions/13501081/efficient-bicubic-filtering-code-in-glsl */ +static constexpr char fragment_source[] = +"#version 330 core\n" +"\n" +"in vec2 TexCoord;\n" +"\n" +"uniform sampler2D texture_sampler;\n" +/* type = 0: draw border + * type = 1: draw XYZ image + * type = 2: draw RGB image + */ +"uniform int type = 0;\n" +"uniform vec4 border_colour;\n" +"uniform mat4 colour_conversion;\n" +"\n" +"out vec4 FragColor;\n" +"\n" +"vec4 cubic(float x)\n" +"\n" +"#define IN_GAMMA 2.2\n" +"#define OUT_GAMMA 0.384615385\n" // 1 / 2.6 +"#define DCI_COEFFICIENT 0.91655528\n" // 48 / 53.37 +"\n" +"{\n" +" float x2 = x * x;\n" +" float x3 = x2 * x;\n" +" vec4 w;\n" +" w.x = -x3 + 3 * x2 - 3 * x + 1;\n" +" w.y = 3 * x3 - 6 * x2 + 4;\n" +" w.z = -3 * x3 + 3 * x2 + 3 * x + 1;\n" +" w.w = x3;\n" +" return w / 6.f;\n" +"}\n" +"\n" +"vec4 texture_bicubic(sampler2D sampler, vec2 tex_coords)\n" +"{\n" +" vec2 tex_size = textureSize(sampler, 0);\n" +" vec2 inv_tex_size = 1.0 / tex_size;\n" +"\n" +" tex_coords = tex_coords * tex_size - 0.5;\n" +"\n" +" vec2 fxy = fract(tex_coords);\n" +" tex_coords -= fxy;\n" +"\n" +" vec4 xcubic = cubic(fxy.x);\n" +" vec4 ycubic = cubic(fxy.y);\n" +"\n" +" vec4 c = tex_coords.xxyy + vec2 (-0.5, +1.5).xyxy;\n" +"\n" +" vec4 s = vec4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);\n" +" vec4 offset = c + vec4 (xcubic.yw, ycubic.yw) / s;\n" +"\n" +" offset *= inv_tex_size.xxyy;\n" +"\n" +" vec4 sample0 = texture(sampler, offset.xz);\n" +" vec4 sample1 = texture(sampler, offset.yz);\n" +" vec4 sample2 = texture(sampler, offset.xw);\n" +" vec4 sample3 = texture(sampler, offset.yw);\n" +"\n" +" float sx = s.x / (s.x + s.y);\n" +" float sy = s.z / (s.z + s.w);\n" +"\n" +" return mix(\n" +" mix(sample3, sample2, sx), mix(sample1, sample0, sx)\n" +" , sy);\n" +"}\n" +"\n" +"void main()\n" +"{\n" +" switch (type) {\n" +" case 0:\n" +" FragColor = border_colour;\n" +" break;\n" +" case 1:\n" +" FragColor = texture_bicubic(texture_sampler, TexCoord);\n" +" FragColor.x = pow(FragColor.x, IN_GAMMA) / DCI_COEFFICIENT;\n" +" FragColor.y = pow(FragColor.y, IN_GAMMA) / DCI_COEFFICIENT;\n" +" FragColor.z = pow(FragColor.z, IN_GAMMA) / DCI_COEFFICIENT;\n" +" FragColor = colour_conversion * FragColor;\n" +" FragColor.x = pow(FragColor.x, OUT_GAMMA);\n" +" FragColor.y = pow(FragColor.y, OUT_GAMMA);\n" +" FragColor.z = pow(FragColor.z, OUT_GAMMA);\n" +" break;\n" +" case 2:\n" +" FragColor = texture_bicubic(texture_sampler, TexCoord);\n" +" break;\n" +" }\n" +"}\n"; + + void GLVideoView::ensure_context () { if (!_context) { - _context = new wxGLContext (_canvas); - _canvas->SetCurrent (*_context); + wxGLContextAttrs attrs; + attrs.PlatformDefaults().CoreProfile().OGLVersion(4, 1).EndList(); + _context = new wxGLContext (_canvas, nullptr, &attrs); + if (!_context->IsOK()) { + throw GLError ("Making GL context", -1); + } } } + +/* Offset of video texture triangles in indices */ +static constexpr int indices_video_texture = 0; +/* Offset of subtitle texture triangles in indices */ +static constexpr int indices_subtitle_texture = 6; +/* Offset of border lines in indices */ +static constexpr int indices_border = 12; + +static constexpr unsigned int indices[] = { + 0, 1, 3, // video texture triangle #1 + 1, 2, 3, // video texture triangle #2 + 4, 5, 7, // subtitle texture triangle #1 + 5, 6, 7, // subtitle texture triangle #2 + 8, 9, // border line #1 + 9, 10, // border line #2 + 10, 11, // border line #3 + 11, 8, // border line #4 +}; + + void -GLVideoView::draw (Position<int> inter_position, dcp::Size inter_size) +GLVideoView::setup_shaders () { - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - check_gl_error ("glClear"); + DCPOMATIC_ASSERT (_canvas); + DCPOMATIC_ASSERT (_context); + auto r = _canvas->SetCurrent (*_context); + DCPOMATIC_ASSERT (r); + +#ifdef DCPOMATIC_WINDOWS + r = glewInit(); + if (r != GLEW_OK) { + throw GLError(reinterpret_cast<char const*>(glewGetErrorString(r))); + } +#endif - glClearColor (0.0f, 0.0f, 0.0f, 1.0f); - check_gl_error ("glClearColor"); - glEnable (GL_TEXTURE_2D); - check_gl_error ("glEnable GL_TEXTURE_2D"); + auto get_information = [this](GLenum name) { + auto s = glGetString (name); + if (s) { + _information[name] = std::string (reinterpret_cast<char const *>(s)); + } + }; + + get_information (GL_VENDOR); + get_information (GL_RENDERER); + get_information (GL_VERSION); + get_information (GL_SHADING_LANGUAGE_VERSION); + + glGenVertexArrays(1, &_vao); + check_gl_error ("glGenVertexArrays"); + GLuint vbo; + glGenBuffers(1, &vbo); + check_gl_error ("glGenBuffers"); + GLuint ebo; + glGenBuffers(1, &ebo); + check_gl_error ("glGenBuffers"); + + glBindVertexArray(_vao); + check_gl_error ("glBindVertexArray"); + + glBindBuffer(GL_ARRAY_BUFFER, vbo); + check_gl_error ("glBindBuffer"); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); + check_gl_error ("glBindBuffer"); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); + check_gl_error ("glBufferData"); + + /* position attribute to vertex shader (location = 0) */ + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), nullptr); + glEnableVertexAttribArray(0); + /* texture coord attribute to vertex shader (location = 1) */ + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float))); + glEnableVertexAttribArray(1); + check_gl_error ("glEnableVertexAttribArray"); + + auto compile = [](GLenum type, char const* source) -> GLuint { + auto shader = glCreateShader(type); + DCPOMATIC_ASSERT (shader); + GLchar const * src[] = { static_cast<GLchar const *>(source) }; + glShaderSource(shader, 1, src, nullptr); + check_gl_error ("glShaderSource"); + glCompileShader(shader); + check_gl_error ("glCompileShader"); + GLint ok; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + if (!ok) { + GLint log_length; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); + string log; + if (log_length > 0) { + char* log_char = new char[log_length]; + glGetShaderInfoLog(shader, log_length, nullptr, log_char); + log = string(log_char); + delete[] log_char; + } + glDeleteShader(shader); + throw GLError(String::compose("Could not compile shader (%1)", log).c_str(), -1); + } + return shader; + }; + + auto vertex_shader = compile (GL_VERTEX_SHADER, vertex_source); + auto fragment_shader = compile (GL_FRAGMENT_SHADER, fragment_source); + + auto program = glCreateProgram(); + check_gl_error ("glCreateProgram"); + glAttachShader (program, vertex_shader); + check_gl_error ("glAttachShader"); + glAttachShader (program, fragment_shader); + check_gl_error ("glAttachShader"); + glLinkProgram (program); + check_gl_error ("glLinkProgram"); + GLint ok; + glGetProgramiv (program, GL_LINK_STATUS, &ok); + if (!ok) { + GLint log_length; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); + string log; + if (log_length > 0) { + char* log_char = new char[log_length]; + glGetProgramInfoLog(program, log_length, nullptr, log_char); + log = string(log_char); + delete[] log_char; + } + glDeleteProgram (program); + throw GLError(String::compose("Could not link shader (%1)", log).c_str(), -1); + } + glDeleteShader (vertex_shader); + glDeleteShader (fragment_shader); + + glUseProgram (program); + + _fragment_type = glGetUniformLocation (program, "type"); + check_gl_error ("glGetUniformLocation"); + set_border_colour (program); + + auto conversion = dcp::ColourConversion::rec709_to_xyz(); + boost::numeric::ublas::matrix<double> matrix = conversion.xyz_to_rgb (); + GLfloat gl_matrix[] = { + static_cast<float>(matrix(0, 0)), static_cast<float>(matrix(0, 1)), static_cast<float>(matrix(0, 2)), 0.0f, + static_cast<float>(matrix(1, 0)), static_cast<float>(matrix(1, 1)), static_cast<float>(matrix(1, 2)), 0.0f, + static_cast<float>(matrix(2, 0)), static_cast<float>(matrix(2, 1)), static_cast<float>(matrix(2, 2)), 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + }; + + auto colour_conversion = glGetUniformLocation (program, "colour_conversion"); + check_gl_error ("glGetUniformLocation"); + glUniformMatrix4fv (colour_conversion, 1, GL_TRUE, gl_matrix); + + glLineWidth (2.0f); glEnable (GL_BLEND); - check_gl_error ("glEnable GL_BLEND"); - glDisable (GL_DEPTH_TEST); - check_gl_error ("glDisable GL_DEPTH_TEST"); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + /* Reserve space for the GL_ARRAY_BUFFER */ + glBufferData(GL_ARRAY_BUFFER, 12 * 5 * sizeof(float), nullptr, GL_STATIC_DRAW); + check_gl_error ("glBufferData"); +} + + +void +GLVideoView::set_border_colour (GLuint program) +{ + auto uniform = glGetUniformLocation (program, "border_colour"); + check_gl_error ("glGetUniformLocation"); + auto colour = outline_content_colour (); + glUniform4f (uniform, colour.Red() / 255.0f, colour.Green() / 255.0f, colour.Blue() / 255.0f, 1.0f); + check_gl_error ("glUniform4f"); +} + + +void +GLVideoView::draw (Position<int>, dcp::Size) +{ + auto pad = pad_colour(); + glClearColor(pad.Red() / 255.0, pad.Green() / 255.0, pad.Blue() / 255.0, 1.0); + glClear (GL_COLOR_BUFFER_BIT); + check_gl_error ("glClear"); + auto const size = _canvas_size.load(); int const width = size.GetWidth(); int const height = size.GetHeight(); @@ -178,83 +470,21 @@ GLVideoView::draw (Position<int> inter_position, dcp::Size inter_size) glViewport (0, 0, width, height); check_gl_error ("glViewport"); - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - -DCPOMATIC_DISABLE_WARNINGS - gluOrtho2D (0, width, height, 0); -DCPOMATIC_ENABLE_WARNINGS - check_gl_error ("gluOrtho2d"); - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - - glTranslatef (0, 0, 0); - - dcp::Size const out_size = _viewer->out_size (); - - if (_size) { - /* Render our image (texture) */ - glBegin (GL_QUADS); - glTexCoord2f (0, 1); - glVertex2f (0, _size->height); - glTexCoord2f (1, 1); - glVertex2f (_size->width, _size->height); - glTexCoord2f (1, 0); - glVertex2f (_size->width, 0); - glTexCoord2f (0, 0); - glVertex2f (0, 0); - glEnd (); - } else { - /* No image, so just fill with black */ - glBegin (GL_QUADS); - glColor3ub (0, 0, 0); - glVertex2f (0, 0); - glVertex2f (out_size.width, 0); - glVertex2f (out_size.width, out_size.height); - glVertex2f (0, out_size.height); - glVertex2f (0, 0); - glEnd (); - } - if (!_viewer->pad_black() && out_size.width < width) { - glBegin (GL_QUADS); - /* XXX: these colours are right for GNOME; may need adjusting for other OS */ - glColor3ub (240, 240, 240); - glVertex2f (out_size.width, 0); - glVertex2f (width, 0); - glVertex2f (width, height); - glVertex2f (out_size.width, height); - glEnd (); - glColor3ub (255, 255, 255); + glBindVertexArray(_vao); + check_gl_error ("glBindVertexArray"); + glUniform1i(_fragment_type, _optimise_for_j2k ? 1 : 2); + _video_texture->bind(); + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_INT, reinterpret_cast<void*>(indices_video_texture * sizeof(int))); + if (_have_subtitle_to_render) { + glUniform1i(_fragment_type, 2); + _subtitle_texture->bind(); + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_INT, reinterpret_cast<void*>(indices_subtitle_texture * sizeof(int))); } - - if (!_viewer->pad_black() && out_size.height < height) { - glColor3ub (240, 240, 240); - int const gap = (height - out_size.height) / 2; - glBegin (GL_QUADS); - glVertex2f (0, 0); - glVertex2f (width, 0); - glVertex2f (width, gap); - glVertex2f (0, gap); - glEnd (); - glBegin (GL_QUADS); - glVertex2f (0, gap + out_size.height + 1); - glVertex2f (width, gap + out_size.height + 1); - glVertex2f (width, 2 * gap + out_size.height + 2); - glVertex2f (0, 2 * gap + out_size.height + 2); - glEnd (); - glColor3ub (255, 255, 255); - } - if (_viewer->outline_content()) { - glColor3ub (255, 0, 0); - glBegin (GL_LINE_LOOP); - glVertex2f (inter_position.x, inter_position.y + (height - out_size.height) / 2); - glVertex2f (inter_position.x + inter_size.width, inter_position.y + (height - out_size.height) / 2); - glVertex2f (inter_position.x + inter_size.width, inter_position.y + (height - out_size.height) / 2 + inter_size.height); - glVertex2f (inter_position.x, inter_position.y + (height - out_size.height) / 2 + inter_size.height); - glEnd (); - glColor3ub (255, 255, 255); + glUniform1i(_fragment_type, 0); + glDrawElements (GL_LINES, 8, GL_UNSIGNED_INT, reinterpret_cast<void*>(indices_border * sizeof(int))); + check_gl_error ("glDrawElements"); } glFlush(); @@ -263,33 +493,109 @@ DCPOMATIC_ENABLE_WARNINGS _canvas->SwapBuffers(); } + void -GLVideoView::set_image (shared_ptr<const Image> image) +GLVideoView::set_image (shared_ptr<const PlayerVideo> pv) { - if (!image) { - _size = optional<dcp::Size>(); - return; + shared_ptr<const Image> video = _optimise_for_j2k ? pv->raw_image() : pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, true); + + /* Only the player's black frames should be aligned at this stage, so this should + * almost always have no work to do. + */ + video = Image::ensure_alignment (video, Image::Alignment::COMPACT); + + /** If _optimise_for_j2k is true we render a XYZ image, doing the colourspace + * conversion, scaling and video range conversion in the GL shader. + * Othewise we render a RGB image without any shader-side processing. + */ + + /* XXX: video range conversion */ + + _video_texture->set (video); + + auto const text = pv->text(); + _have_subtitle_to_render = static_cast<bool>(text) && _optimise_for_j2k; + if (_have_subtitle_to_render) { + /* opt: only do this if it's a new subtitle? */ + DCPOMATIC_ASSERT (text->image->alignment() == Image::Alignment::COMPACT); + _subtitle_texture->set (text->image); } - DCPOMATIC_ASSERT (image->pixel_format() == AV_PIX_FMT_RGB24); - DCPOMATIC_ASSERT (!image->aligned()); - if (image->size() != _size) { - _have_storage = false; + auto const canvas_size = _canvas_size.load(); + int const canvas_width = canvas_size.GetWidth(); + int const canvas_height = canvas_size.GetHeight(); + auto inter_position = player_video().first->inter_position(); + auto inter_size = player_video().first->inter_size(); + auto out_size = player_video().first->out_size(); + + _last_canvas_size.set_next (canvas_size); + _last_video_size.set_next (video->size()); + _last_inter_position.set_next (inter_position); + _last_inter_size.set_next (inter_size); + _last_out_size.set_next (out_size); + + auto x_pixels_to_gl = [canvas_width](int x) { + return (x * 2.0f / canvas_width) - 1.0f; + }; + + auto y_pixels_to_gl = [canvas_height](int y) { + return (y * 2.0f / canvas_height) - 1.0f; + }; + + if (_last_canvas_size.changed() || _last_inter_position.changed() || _last_inter_size.changed() || _last_out_size.changed()) { + float const video_x1 = x_pixels_to_gl(_optimise_for_j2k ? inter_position.x : 0); + float const video_x2 = x_pixels_to_gl(_optimise_for_j2k ? (inter_position.x + inter_size.width) : out_size.width); + float const video_y1 = y_pixels_to_gl(_optimise_for_j2k ? inter_position.y : 0); + float const video_y2 = y_pixels_to_gl(_optimise_for_j2k ? (inter_position.y + inter_size.height) : out_size.height); + float video_vertices[] = { + // positions // texture coords + video_x2, video_y2, 0.0f, 1.0f, 0.0f, // video texture top right (index 0) + video_x2, video_y1, 0.0f, 1.0f, 1.0f, // video texture bottom right (index 1) + video_x1, video_y1, 0.0f, 0.0f, 1.0f, // video texture bottom left (index 2) + video_x1, video_y2, 0.0f, 0.0f, 0.0f, // video texture top left (index 3) + }; + + glBufferSubData (GL_ARRAY_BUFFER, 0, sizeof(video_vertices), video_vertices); + check_gl_error ("glBufferSubData (video)"); + + float const border_x1 = x_pixels_to_gl(inter_position.x); + float const border_y1 = y_pixels_to_gl(inter_position.y); + float const border_x2 = x_pixels_to_gl(inter_position.x + inter_size.width); + float const border_y2 = y_pixels_to_gl(inter_position.y + inter_size.height); + + float border_vertices[] = { + // positions // texture coords + border_x1, border_y1, 0.0f, 0.0f, 0.0f, // border bottom left (index 4) + border_x1, border_y2, 0.0f, 0.0f, 0.0f, // border top left (index 5) + border_x2, border_y2, 0.0f, 0.0f, 0.0f, // border top right (index 6) + border_x2, border_y1, 0.0f, 0.0f, 0.0f, // border bottom right (index 7) + }; + + glBufferSubData (GL_ARRAY_BUFFER, 8 * 5 * sizeof(float), sizeof(border_vertices), border_vertices); + check_gl_error ("glBufferSubData (border)"); } - _size = image->size (); - glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - check_gl_error ("glPixelStorei"); - if (_have_storage) { - glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, _size->width, _size->height, GL_RGB, GL_UNSIGNED_BYTE, image->data()[0]); - check_gl_error ("glTexSubImage2D"); - } else { - glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, _size->width, _size->height, 0, GL_RGB, GL_UNSIGNED_BYTE, image->data()[0]); - _have_storage = true; - check_gl_error ("glTexImage2D"); + if (_have_subtitle_to_render) { + float const subtitle_x1 = x_pixels_to_gl(inter_position.x + text->position.x); + float const subtitle_x2 = x_pixels_to_gl(inter_position.x + text->position.x + text->image->size().width); + float const subtitle_y1 = y_pixels_to_gl(inter_position.y + text->position.y + text->image->size().height); + float const subtitle_y2 = y_pixels_to_gl(inter_position.y + text->position.y); + + float vertices[] = { + // positions // texture coords + subtitle_x2, subtitle_y1, 0.0f, 1.0f, 0.0f, // subtitle texture top right (index 4) + subtitle_x2, subtitle_y2, 0.0f, 1.0f, 1.0f, // subtitle texture bottom right (index 5) + subtitle_x1, subtitle_y2, 0.0f, 0.0f, 1.0f, // subtitle texture bottom left (index 6) + subtitle_x1, subtitle_y1, 0.0f, 0.0f, 0.0f, // subtitle texture top left (index 7) + }; + + glBufferSubData (GL_ARRAY_BUFFER, 4 * 5 * sizeof(float), sizeof(vertices), vertices); + check_gl_error ("glBufferSubData (subtitle)"); } + /* opt: where should these go? */ + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); check_gl_error ("glTexParameteri"); @@ -299,6 +605,7 @@ GLVideoView::set_image (shared_ptr<const Image> image) check_gl_error ("glTexParameterf"); } + void GLVideoView::start () { @@ -321,7 +628,7 @@ void GLVideoView::thread_playing () { if (length() != dcpomatic::DCPTime()) { - dcpomatic::DCPTime const next = position() + one_video_frame(); + auto const next = position() + one_video_frame(); if (next >= length()) { _viewer->finished (); @@ -346,9 +653,9 @@ GLVideoView::thread_playing () void GLVideoView::set_image_and_draw () { - shared_ptr<PlayerVideo> pv = player_video().first; + auto pv = player_video().first; if (pv) { - set_image (pv->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true)); + set_image (pv); draw (pv->inter_position(), pv->inter_size()); _viewer->image_changed (pv); } @@ -367,12 +674,10 @@ try */ WXGLSetCurrentContext (_context->GetWXGLContext()); #else - /* We must call this here on Linux otherwise we get no image (for reasons - * that aren't clear). However, doing ensure_context() from this thread - * on macOS gives - * "[NSOpenGLContext setView:] must be called from the main thread". - */ - ensure_context (); + if (!_setup_shaders_done) { + setup_shaders (); + _setup_shaders_done = true; + } #endif #if defined(DCPOMATIC_LINUX) && defined(DCPOMATIC_HAVE_GLX_SWAP_INTERVAL_EXT) @@ -403,12 +708,8 @@ try _vsync_enabled = true; #endif - glGenTextures (1, &_id); - check_gl_error ("glGenTextures"); - glBindTexture (GL_TEXTURE_2D, _id); - check_gl_error ("glBindTexture"); - glPixelStorei (GL_UNPACK_ALIGNMENT, 1); - check_gl_error ("glPixelStorei"); + _video_texture.reset(new Texture(_optimise_for_j2k ? 2 : 1)); + _subtitle_texture.reset(new Texture(1)); while (true) { boost::mutex::scoped_lock lm (_playing_mutex); @@ -432,7 +733,7 @@ try * without also deleting the wxGLCanvas. */ } -catch (boost::thread_interrupted& e) +catch (...) { store_current (); } @@ -455,3 +756,77 @@ GLVideoView::request_one_shot () _thread_work_condition.notify_all (); } + +Texture::Texture (GLint unpack_alignment) + : _unpack_alignment (unpack_alignment) +{ + glGenTextures (1, &_name); + check_gl_error ("glGenTextures"); +} + + +Texture::~Texture () +{ + glDeleteTextures (1, &_name); +} + + +void +Texture::bind () +{ + glBindTexture(GL_TEXTURE_2D, _name); + check_gl_error ("glBindTexture"); +} + + +void +Texture::set (shared_ptr<const Image> image) +{ + auto const create = !_size || image->size() != _size; + _size = image->size(); + + glPixelStorei (GL_UNPACK_ALIGNMENT, _unpack_alignment); + check_gl_error ("glPixelStorei"); + + DCPOMATIC_ASSERT (image->alignment() == Image::Alignment::COMPACT); + + GLint internal_format; + GLenum format; + GLenum type; + + switch (image->pixel_format()) { + case AV_PIX_FMT_BGRA: + internal_format = GL_RGBA8; + format = GL_BGRA; + type = GL_UNSIGNED_BYTE; + break; + case AV_PIX_FMT_RGBA: + internal_format = GL_RGBA8; + format = GL_RGBA; + type = GL_UNSIGNED_BYTE; + break; + case AV_PIX_FMT_RGB24: + internal_format = GL_RGBA8; + format = GL_RGB; + type = GL_UNSIGNED_BYTE; + break; + case AV_PIX_FMT_XYZ12: + internal_format = GL_RGBA12; + format = GL_RGB; + type = GL_UNSIGNED_SHORT; + break; + default: + throw PixelFormatError ("Texture::set", image->pixel_format()); + } + + bind (); + + if (create) { + glTexImage2D (GL_TEXTURE_2D, 0, internal_format, _size->width, _size->height, 0, format, type, image->data()[0]); + check_gl_error ("glTexImage2D"); + } else { + glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, _size->width, _size->height, format, type, image->data()[0]); + check_gl_error ("glTexSubImage2D"); + } +} + diff --git a/src/wx/gl_video_view.h b/src/wx/gl_video_view.h index 36edd6b8b..d7f8429af 100644 --- a/src/wx/gl_video_view.h +++ b/src/wx/gl_video_view.h @@ -34,27 +34,51 @@ DCPOMATIC_ENABLE_WARNINGS #undef Success #undef Status + +class Texture +{ +public: + Texture (GLint unpack_alignment); + ~Texture (); + + Texture (Texture const&) = delete; + Texture& operator= (Texture const&) = delete; + + void bind (); + void set (std::shared_ptr<const Image> image); + +private: + GLuint _name; + GLint _unpack_alignment; + boost::optional<dcp::Size> _size; +}; + + class GLVideoView : public VideoView { public: GLVideoView (FilmViewer* viewer, wxWindow* parent); ~GLVideoView (); - wxWindow* get () const { + wxWindow* get () const override { return _canvas; } - void update (); - void start (); - void stop (); + void update () override; + void start () override; + void stop () override; - NextFrameResult display_next_frame (bool); + NextFrameResult display_next_frame (bool) override; bool vsync_enabled () const { return _vsync_enabled; } + std::map<GLenum, std::string> information () const { + return _information; + } + private: - void set_image (std::shared_ptr<const Image> image); + void set_image (std::shared_ptr<const PlayerVideo> pv); void set_image_and_draw (); void draw (Position<int> inter_position, dcp::Size inter_size); void thread (); @@ -63,15 +87,43 @@ private: void check_for_butler_errors (); void ensure_context (); void size_changed (wxSizeEvent const &); + void setup_shaders (); + void set_border_colour (GLuint program); wxGLCanvas* _canvas; wxGLContext* _context; - boost::atomic<wxSize> _canvas_size; + template <class T> + class Last + { + public: + void set_next (T const& next) { + _next = next; + } + + bool changed () const { + return !_value || *_value != _next; + } + + void update () { + _value = _next; + } + + private: + boost::optional<T> _value; + T _next; + }; + + Last<wxSize> _last_canvas_size; + Last<dcp::Size> _last_video_size; + Last<Position<int>> _last_inter_position; + Last<dcp::Size> _last_inter_size; + Last<dcp::Size> _last_out_size; - GLuint _id; - boost::optional<dcp::Size> _size; - bool _have_storage; + boost::atomic<wxSize> _canvas_size; + std::unique_ptr<Texture> _video_texture; + std::unique_ptr<Texture> _subtitle_texture; + bool _have_subtitle_to_render = false; bool _vsync_enabled; boost::thread _thread; @@ -80,5 +132,11 @@ private: boost::atomic<bool> _playing; boost::atomic<bool> _one_shot; + GLuint _vao; + GLint _fragment_type; + bool _setup_shaders_done = false; + std::shared_ptr<wxTimer> _timer; + + std::map<GLenum, std::string> _information; }; diff --git a/src/wx/playlist_controls.cc b/src/wx/playlist_controls.cc index d65cb0fcc..129e0ceca 100644 --- a/src/wx/playlist_controls.cc +++ b/src/wx/playlist_controls.cc @@ -109,7 +109,7 @@ PlaylistControls::PlaylistControls (wxWindow* parent, shared_ptr<FilmViewer> vie _previous_button->Bind (wxEVT_BUTTON, boost::bind(&PlaylistControls::previous_clicked, this)); _spl_view->Bind (wxEVT_LIST_ITEM_SELECTED, boost::bind(&PlaylistControls::spl_selection_changed, this)); _spl_view->Bind (wxEVT_LIST_ITEM_DESELECTED, boost::bind(&PlaylistControls::spl_selection_changed, this)); - _viewer->Finished.connect (boost::bind(&PlaylistControls::viewer_finished, this)); + viewer->Finished.connect (boost::bind(&PlaylistControls::viewer_finished, this)); _refresh_spl_view->Bind (wxEVT_BUTTON, boost::bind(&PlaylistControls::update_playlist_directory, this)); _refresh_content_view->Bind (wxEVT_BUTTON, boost::bind(&ContentView::update, _content_view)); @@ -148,18 +148,26 @@ PlaylistControls::deselect_playlist () void PlaylistControls::play_clicked () { - _viewer->start (); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->start (); + } } void PlaylistControls::setup_sensitivity () { + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + Controls::setup_sensitivity (); bool const active_job = _active_job && *_active_job != "examine_content"; bool const c = _film && !_film->content().empty() && !active_job; - _play_button->Enable (c && !_viewer->playing()); - _pause_button->Enable (_viewer->playing()); - _spl_view->Enable (!_viewer->playing()); + _play_button->Enable (c && !viewer->playing()); + _pause_button->Enable (viewer->playing()); + _spl_view->Enable (!viewer->playing()); _next_button->Enable (can_do_next()); _previous_button->Enable (can_do_previous()); } @@ -167,14 +175,22 @@ PlaylistControls::setup_sensitivity () void PlaylistControls::pause_clicked () { - _viewer->stop (); + auto viewer = _viewer.lock (); + if (viewer) { + viewer->stop (); + } } void PlaylistControls::stop_clicked () { - _viewer->stop (); - _viewer->seek (DCPTime(), true); + auto viewer = _viewer.lock (); + if (!viewer) { + return; + } + + viewer->stop (); + viewer->seek (DCPTime(), true); if (_selected_playlist) { _selected_playlist_position = 0; update_current_content (); @@ -436,7 +452,8 @@ PlaylistControls::update_current_content () void PlaylistControls::viewer_finished () { - if (!_selected_playlist) { + auto viewer = _viewer.lock (); + if (!_selected_playlist || !viewer) { return; } @@ -444,7 +461,7 @@ PlaylistControls::viewer_finished () if (_selected_playlist_position < int(_playlists[*_selected_playlist].get().size())) { /* Next piece of content on the SPL */ update_current_content (); - _viewer->start (); + viewer->start (); } else { /* Finished the whole SPL */ _selected_playlist_position = 0; diff --git a/src/wx/simple_video_view.cc b/src/wx/simple_video_view.cc index f5499ad9d..1ac56bbfe 100644 --- a/src/wx/simple_video_view.cc +++ b/src/wx/simple_video_view.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + Copyright (C) 2019-2021 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,21 +18,23 @@ */ -#include "simple_video_view.h" + +#include "closed_captions_dialog.h" #include "film_viewer.h" +#include "simple_video_view.h" #include "wx_util.h" -#include "closed_captions_dialog.h" -#include "lib/image.h" -#include "lib/dcpomatic_log.h" #include "lib/butler.h" +#include "lib/dcpomatic_log.h" +#include "lib/image.h" #include <dcp/util.h> #include <wx/wx.h> #include <boost/bind/bind.hpp> + using std::max; +using std::shared_ptr; using std::string; using boost::optional; -using std::shared_ptr; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif @@ -57,18 +59,21 @@ SimpleVideoView::SimpleVideoView (FilmViewer* viewer, wxWindow* parent) _timer.Bind (wxEVT_TIMER, boost::bind(&SimpleVideoView::timer, this)); } + void SimpleVideoView::paint () { _state_timer.set("paint-panel"); wxPaintDC dc (_panel); - dcp::Size const out_size = _viewer->out_size (); - wxSize const panel_size = _panel->GetSize (); + auto const panel_size = _panel->GetSize (); - if (!out_size.width || !out_size.height || !_image || out_size != _image->size()) { + dcp::Size out_size; + if (!_image) { dc.Clear (); } else { + DCPOMATIC_ASSERT (_image->alignment() == Image::Alignment::COMPACT); + out_size = _image->size(); wxImage frame (out_size.width, out_size.height, _image->data()[0], true); wxBitmap frame_bitmap (frame); dc.DrawBitmap (frame_bitmap, 0, max(0, (panel_size.GetHeight() - out_size.height) / 2)); @@ -112,6 +117,7 @@ SimpleVideoView::paint () _state_timer.unset(); } + void SimpleVideoView::refresh_panel () { @@ -121,6 +127,7 @@ SimpleVideoView::refresh_panel () _state_timer.unset (); } + void SimpleVideoView::timer () { @@ -144,6 +151,7 @@ SimpleVideoView::timer () } } + void SimpleVideoView::start () { @@ -151,6 +159,7 @@ SimpleVideoView::start () timer (); } + /** Try to get a frame from the butler and display it. * @param non_blocking true to return false quickly if no video is available quickly (i.e. we are waiting for the butler). * false to ask the butler to block until it has video (unless it is suspended). @@ -175,11 +184,12 @@ SimpleVideoView::display_next_frame (bool non_blocking) return SUCCESS; } + void SimpleVideoView::update () { if (!player_video().first) { - set_image (shared_ptr<Image>()); + _image.reset (); refresh_panel (); return; } @@ -212,9 +222,7 @@ SimpleVideoView::update () _state_timer.set ("get image"); - set_image ( - player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true) - ); + _image = player_video().first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, true); _state_timer.set ("ImageChanged"); _viewer->image_changed (player_video().first); diff --git a/src/wx/simple_video_view.h b/src/wx/simple_video_view.h index 31756b5d8..cbb162023 100644 --- a/src/wx/simple_video_view.h +++ b/src/wx/simple_video_view.h @@ -33,19 +33,15 @@ class SimpleVideoView : public VideoView public: SimpleVideoView (FilmViewer* viewer, wxWindow* parent); - wxWindow* get () const { + wxWindow* get () const override { return _panel; } - void update (); - void start (); - NextFrameResult display_next_frame (bool non_blocking); + void update () override; + void start () override; + NextFrameResult display_next_frame (bool non_blocking) override; private: - void set_image (std::shared_ptr<const Image> image) { - _image = image; - } - void refresh_panel (); void paint (); void timer (); diff --git a/src/wx/standard_controls.cc b/src/wx/standard_controls.cc index 1e4ecc8d7..6196c1b5c 100644 --- a/src/wx/standard_controls.cc +++ b/src/wx/standard_controls.cc @@ -63,14 +63,15 @@ StandardControls::play_clicked () void StandardControls::check_play_state () { - if (!_film || _film->video_frame_rate() == 0) { + auto viewer = _viewer.lock (); + if (!_film || _film->video_frame_rate() == 0 || !viewer) { return; } if (_play_button->GetValue()) { - _viewer->start (); + viewer->start (); } else { - _viewer->stop (); + viewer->stop (); } } diff --git a/src/wx/system_information_dialog.cc b/src/wx/system_information_dialog.cc index 968cd5740..1c8dd8d00 100644 --- a/src/wx/system_information_dialog.cc +++ b/src/wx/system_information_dialog.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + Copyright (C) 2019-2021 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -18,10 +18,12 @@ */ + +#include "film_viewer.h" +#include "gl_video_view.h" #include "system_information_dialog.h" #include "wx_util.h" -#include "gl_video_view.h" -#include "film_viewer.h" + #ifdef DCPOMATIC_OSX #include <OpenGL/glu.h> @@ -31,27 +33,42 @@ #include <GL/glext.h> #endif + using std::string; using std::weak_ptr; using std::shared_ptr; + SystemInformationDialog::SystemInformationDialog (wxWindow* parent, weak_ptr<FilmViewer> weak_viewer) : TableDialog (parent, _("System information"), 2, 1, false) { - shared_ptr<FilmViewer> viewer = weak_viewer.lock (); - GLVideoView const * gl = viewer ? dynamic_cast<GLVideoView const *>(viewer->video_view()) : 0; + auto viewer = weak_viewer.lock (); + shared_ptr<const GLVideoView> gl; + if (viewer) { + gl = std::dynamic_pointer_cast<const GLVideoView>(viewer->video_view()); + } if (!gl) { add (_("OpenGL version"), true); add (_("unknown (OpenGL not enabled in DCP-o-matic)"), false); } else { - add (_("OpenGL version"), true); - char const * v = (char const *) glGetString (GL_VERSION); - if (v) { - add (std_to_wx(v), false); - } else { - add (_("unknown"), false); - } + + auto information = gl->information(); + auto add_string = [this, &information](GLenum name, wxString label) { + add (label, true); + auto i = information.find(name); + if (i != information.end()) { + add (std_to_wx(i->second), false); + } else { + add (_("unknown"), false); + } + }; + + add_string (GL_VENDOR, _("Vendor")); + add_string (GL_RENDERER, _("Renderer")); + add_string (GL_VERSION, _("Version")); + add_string (GL_SHADING_LANGUAGE_VERSION, _("Shading language version")); + add (_("vsync"), true); add (gl->vsync_enabled() ? _("enabled") : _("not enabled"), false); } diff --git a/src/wx/system_information_dialog.h b/src/wx/system_information_dialog.h index 5b9efa234..49e617a6e 100644 --- a/src/wx/system_information_dialog.h +++ b/src/wx/system_information_dialog.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2019 Carl Hetherington <cth@carlh.net> + Copyright (C) 2019-2021 Carl Hetherington <cth@carlh.net> This file is part of DCP-o-matic. @@ -25,9 +25,9 @@ class FilmViewer; + class SystemInformationDialog : public TableDialog { public: SystemInformationDialog (wxWindow* parent, std::weak_ptr<FilmViewer> viewer); - }; diff --git a/src/wx/video_view.cc b/src/wx/video_view.cc index 4d80e2535..1d10beb30 100644 --- a/src/wx/video_view.cc +++ b/src/wx/video_view.cc @@ -28,7 +28,6 @@ #include <sys/time.h> -using std::pair; using std::shared_ptr; using boost::optional; diff --git a/src/wx/video_view.h b/src/wx/video_view.h index 9517a3bf4..5353f213f 100644 --- a/src/wx/video_view.h +++ b/src/wx/video_view.h @@ -127,6 +127,10 @@ public: _three_d = t; } + void set_optimise_for_j2k (bool o) { + _optimise_for_j2k = o; + } + protected: NextFrameResult get_next_frame (bool non_blocking); boost::optional<int> time_until_next_frame () const; @@ -168,6 +172,8 @@ protected: StateTimer _state_timer; + bool _optimise_for_j2k = false; + private: /** Mutex protecting all the state in this class */ mutable boost::mutex _mutex; diff --git a/src/wx/video_waveform_plot.cc b/src/wx/video_waveform_plot.cc index 2e45f3493..07b2955b3 100644 --- a/src/wx/video_waveform_plot.cc +++ b/src/wx/video_waveform_plot.cc @@ -155,7 +155,7 @@ VideoWaveformPlot::create_waveform () auto const image_size = _image->size(); int const waveform_height = GetSize().GetHeight() - _vertical_margin * 2; - _waveform = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (image_size.width, waveform_height), true); + _waveform = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (image_size.width, waveform_height), Image::Alignment::PADDED); for (int x = 0; x < image_size.width; ++x) { @@ -182,7 +182,7 @@ VideoWaveformPlot::create_waveform () _waveform = _waveform->scale ( dcp::Size (GetSize().GetWidth() - _x_axis_width, waveform_height), - dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false + dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false ); } diff --git a/src/wx/wscript b/src/wx/wscript index b868292f5..50c078f2b 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -209,7 +209,7 @@ def configure(conf): mandatory=True) if conf.env.TARGET_LINUX: - conf.env.append_value('CXXFLAGS', ['-DGLX_GLXEXT_PROTOTYPES']) + conf.env.append_value('CXXFLAGS', ['-DGL_GLEXT_PROTOTYPES', '-DGLX_GLXEXT_PROTOTYPES']) if conf.env.TARGET_WINDOWS: conf.env.append_value('CXXFLAGS', ['-DWGL_WGLEXT_PROTOTYPES']) @@ -277,6 +277,8 @@ def configure(conf): if conf.env.TARGET_WINDOWS or conf.env.TARGET_LINUX: conf.check_cfg(package='gl', args='--cflags --libs', uselib_store='GL', mandatory=True) conf.check_cfg(package='glu', args='--cflags --libs', uselib_store='GLU', mandatory=True) + if conf.env.TARGET_WINDOWS: + conf.check_cfg(package='glew', args='--cflags --libs', uselib_store='GLEW', mandatory=True) else: conf.env.STLIB_GL = 'gl' conf.env.STLIB_GLU = 'glu' @@ -311,7 +313,7 @@ def build(bld): if bld.env.TARGET_LINUX: obj.uselib += 'GTK GL GLU ' if bld.env.TARGET_WINDOWS: - obj.uselib += 'WINSOCK2 OLE32 DSOUND WINMM KSUSER GL GLU ' + obj.uselib += 'WINSOCK2 OLE32 DSOUND WINMM KSUSER GL GLU GLEW ' if bld.env.TARGET_OSX: obj.framework = ['CoreAudio', 'OpenGL'] obj.use = 'libdcpomatic2' diff --git a/test/butler_test.cc b/test/butler_test.cc index dbd7a287e..787d1c324 100644 --- a/test/butler_test.cc +++ b/test/butler_test.cc @@ -59,7 +59,7 @@ BOOST_AUTO_TEST_CASE (butler_test1) map.set (i, i, 1); } - Butler butler (film, make_shared<Player>(film), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, false); + Butler butler (film, make_shared<Player>(film, Image::Alignment::COMPACT), map, 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, false, false); BOOST_CHECK (butler.get_video(true, 0).second == DCPTime()); BOOST_CHECK (butler.get_video(true, 0).second == DCPTime::from_frames(1, 24)); diff --git a/test/client_server_test.cc b/test/client_server_test.cc index f518f9383..7a99f7227 100644 --- a/test/client_server_test.cc +++ b/test/client_server_test.cc @@ -66,7 +66,7 @@ do_remote_encode (shared_ptr<DCPVideo> frame, EncodeServerDescription descriptio BOOST_AUTO_TEST_CASE (client_server_test_rgb) { - auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (1998, 1080), true); + auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size (1998, 1080), Image::Alignment::PADDED); uint8_t* p = image->data()[0]; for (int y = 0; y < 1080; ++y) { @@ -79,7 +79,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb) p += image->stride()[0]; } - auto sub_image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (100, 200), true); + auto sub_image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (100, 200), Image::Alignment::PADDED); p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { uint8_t* q = p; @@ -153,7 +153,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_rgb) BOOST_AUTO_TEST_CASE (client_server_test_yuv) { - auto image = make_shared<Image>(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), true); + auto image = make_shared<Image>(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), Image::Alignment::PADDED); for (int i = 0; i < image->planes(); ++i) { uint8_t* p = image->data()[i]; @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv) } } - auto sub_image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (100, 200), true); + auto sub_image = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (100, 200), Image::Alignment::PADDED); uint8_t* p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { uint8_t* q = p; @@ -236,7 +236,7 @@ BOOST_AUTO_TEST_CASE (client_server_test_yuv) BOOST_AUTO_TEST_CASE (client_server_test_j2k) { - auto image = make_shared<Image>(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), true); + auto image = make_shared<Image>(AV_PIX_FMT_YUV420P, dcp::Size (1998, 1080), Image::Alignment::PADDED); for (int i = 0; i < image->planes(); ++i) { uint8_t* p = image->data()[i]; diff --git a/test/dcp_decoder_test.cc b/test/dcp_decoder_test.cc index a52a0ccc5..66cd402c4 100644 --- a/test/dcp_decoder_test.cc +++ b/test/dcp_decoder_test.cc @@ -87,7 +87,7 @@ BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) ov_content = make_shared<DCPContent>(ov->dir(ov->dcp_name(false))); test->examine_and_add_content (ov_content); BOOST_REQUIRE (!wait_for_jobs()); - auto player = make_shared<Player>(test); + auto player = make_shared<Player>(test, Image::Alignment::COMPACT); auto decoder = std::dynamic_pointer_cast<DCPDecoder>(player->_pieces.front()->decoder); BOOST_REQUIRE (decoder); @@ -105,7 +105,7 @@ BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) auto vf_content = make_shared<DCPContent>(vf->dir(vf->dcp_name(false))); test->examine_and_add_content (vf_content); BOOST_REQUIRE (!wait_for_jobs()); - player.reset (new Player(test)); + player = make_shared<Player>(test, Image::Alignment::COMPACT); decoder = std::dynamic_pointer_cast<DCPDecoder>(player->_pieces.front()->decoder); BOOST_REQUIRE (decoder); @@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE (check_reuse_old_data_test) auto encrypted_content = make_shared<DCPContent>(encrypted->dir(encrypted->dcp_name(false))); test->examine_and_add_content (encrypted_content); BOOST_REQUIRE (!wait_for_jobs()); - player = make_shared<Player>(test); + player = make_shared<Player>(test, Image::Alignment::COMPACT); decoder = std::dynamic_pointer_cast<DCPDecoder>(player->_pieces.front()->decoder); BOOST_REQUIRE (decoder); diff --git a/test/dcp_playback_test.cc b/test/dcp_playback_test.cc index ef1b623e7..2ab7eaec3 100644 --- a/test/dcp_playback_test.cc +++ b/test/dcp_playback_test.cc @@ -28,9 +28,7 @@ using std::make_shared; -using std::pair; -using std::shared_ptr; -using boost::optional; +using std::make_shared; #if BOOST_VERSION >= 106100 using namespace boost::placeholders; #endif @@ -47,13 +45,14 @@ BOOST_AUTO_TEST_CASE (dcp_playback_test) auto butler = std::make_shared<Butler>( film, - shared_ptr<Player>(new Player(film)), + make_shared<Player>(film, Image::Alignment::PADDED), AudioMapping(6, 6), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, - false, - true + Image::Alignment::PADDED, + true, + false ); auto audio_buffer = new float[2000 * 6]; @@ -64,7 +63,7 @@ BOOST_AUTO_TEST_CASE (dcp_playback_test) } /* assuming DCP is 24fps/48kHz */ butler->get_audio (audio_buffer, 2000); - p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true); + p.first->image(bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, true); } delete[] audio_buffer; } diff --git a/test/ffmpeg_audio_only_test.cc b/test/ffmpeg_audio_only_test.cc index a68f7cf57..40c909b39 100644 --- a/test/ffmpeg_audio_only_test.cc +++ b/test/ffmpeg_audio_only_test.cc @@ -101,7 +101,7 @@ test (boost::filesystem::path file) ref_buffer_size = info.samplerate * info.channels; ref_buffer = new float[ref_buffer_size]; - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->Audio.connect (bind (&audio, _1, info.channels)); while (!player->pass ()) {} diff --git a/test/ffmpeg_audio_test.cc b/test/ffmpeg_audio_test.cc index 5a36b99f4..6bdadce97 100644 --- a/test/ffmpeg_audio_test.cc +++ b/test/ffmpeg_audio_test.cc @@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test2) film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); while (!player->pass ()) {} } @@ -148,7 +148,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test3) film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->set_fast (); while (!player->pass ()) {} } @@ -162,7 +162,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_audio_test4) film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->set_fast (); BOOST_CHECK_NO_THROW (while (!player->pass()) {}); } diff --git a/test/ffmpeg_decoder_sequential_test.cc b/test/ffmpeg_decoder_sequential_test.cc index b2069a8b1..73eea719f 100644 --- a/test/ffmpeg_decoder_sequential_test.cc +++ b/test/ffmpeg_decoder_sequential_test.cc @@ -75,7 +75,7 @@ ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int film->examine_and_add_content (content); BOOST_REQUIRE (!wait_for_jobs()); film->write_metadata (); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); BOOST_REQUIRE (content->video_frame_rate()); BOOST_CHECK_CLOSE (content->video_frame_rate().get(), fps, 0.01); diff --git a/test/image_test.cc b/test/image_test.cc index 3993b3efb..7369bd24f 100644 --- a/test/image_test.cc +++ b/test/image_test.cc @@ -39,13 +39,12 @@ using std::cout; using std::list; using std::make_shared; -using std::shared_ptr; using std::string; BOOST_AUTO_TEST_CASE (aligned_image_test) { - auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), true); + auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), Image::Alignment::PADDED); BOOST_CHECK_EQUAL (s->planes(), 1); /* 192 is 150 aligned to the nearest 64 bytes */ BOOST_CHECK_EQUAL (s->stride()[0], 192); @@ -72,7 +71,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]); /* assignment operator */ - auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), false); + auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), Image::Alignment::COMPACT); *u = *s; BOOST_CHECK_EQUAL (u->planes(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 192); @@ -96,7 +95,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_AUTO_TEST_CASE (compact_image_test) { - auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), false); + auto s = new Image (AV_PIX_FMT_RGB24, dcp::Size (50, 50), Image::Alignment::COMPACT); BOOST_CHECK_EQUAL (s->planes(), 1); BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3); BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3); @@ -122,7 +121,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_CHECK_EQUAL (t->stride()[0], s->stride()[0]); /* assignment operator */ - auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), true); + auto u = new Image (AV_PIX_FMT_YUV422P, dcp::Size (150, 150), Image::Alignment::PADDED); *u = *s; BOOST_CHECK_EQUAL (u->planes(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 50 * 3); @@ -148,10 +147,10 @@ void alpha_blend_test_one (AVPixelFormat format, string suffix) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "prophet_frame.tiff"); - auto raw = proxy->image().image; - auto background = raw->convert_pixel_format (dcp::YUVToRGB::REC709, format, true, false); + auto raw = proxy->image(Image::Alignment::PADDED).image; + auto background = raw->convert_pixel_format (dcp::YUVToRGB::REC709, format, Image::Alignment::PADDED, false); - auto overlay = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size(431, 891), true); + auto overlay = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size(431, 891), Image::Alignment::PADDED); overlay->make_transparent (); for (int y = 0; y < 128; ++y) { @@ -180,7 +179,7 @@ alpha_blend_test_one (AVPixelFormat format, string suffix) background->alpha_blend (overlay, Position<int> (13, 17)); - auto save = background->convert_pixel_format (dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false); + auto save = background->convert_pixel_format (dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false); write_image (save, "build/test/image_test_" + suffix + ".png"); check_image ("build/test/image_test_" + suffix + ".png", TestPaths::private_data() / ("image_test_" + suffix + ".png")); @@ -205,7 +204,7 @@ BOOST_AUTO_TEST_CASE (merge_test1) { int const stride = 48 * 4; - auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 48), false); + auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 48), Image::Alignment::COMPACT); A->make_transparent (); auto a = A->data()[0]; @@ -221,7 +220,7 @@ BOOST_AUTO_TEST_CASE (merge_test1) list<PositionImage> all; all.push_back (PositionImage (A, Position<int>(0, 0))); - auto merged = merge (all); + auto merged = merge (all, Image::Alignment::COMPACT); BOOST_CHECK (merged.position == Position<int>(0, 0)); BOOST_CHECK_EQUAL (memcmp (merged.image->data()[0], A->data()[0], stride * 48), 0); @@ -231,7 +230,7 @@ BOOST_AUTO_TEST_CASE (merge_test1) /** Test merge (list<PositionImage>) with two images */ BOOST_AUTO_TEST_CASE (merge_test2) { - auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 1), false); + auto A = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 1), Image::Alignment::COMPACT); A->make_transparent (); auto a = A->data()[0]; for (int x = 0; x < 16; ++x) { @@ -241,7 +240,7 @@ BOOST_AUTO_TEST_CASE (merge_test2) a[x * 4 + 3] = 255; } - auto B = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 1), false); + auto B = make_shared<Image>(AV_PIX_FMT_BGRA, dcp::Size (48, 1), Image::Alignment::COMPACT); B->make_transparent (); auto b = B->data()[0]; for (int x = 0; x < 16; ++x) { @@ -254,7 +253,7 @@ BOOST_AUTO_TEST_CASE (merge_test2) list<PositionImage> all; all.push_back (PositionImage(A, Position<int>(0, 0))); all.push_back (PositionImage(B, Position<int>(0, 0))); - auto merged = merge (all); + auto merged = merge (all, Image::Alignment::COMPACT); BOOST_CHECK (merged.position == Position<int>(0, 0)); @@ -274,11 +273,11 @@ BOOST_AUTO_TEST_CASE (merge_test2) BOOST_AUTO_TEST_CASE (crop_scale_window_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/flat_red.png"); - auto raw = proxy->image().image; + auto raw = proxy->image(Image::Alignment::PADDED).image; auto out = raw->crop_scale_window( - Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_YUV420P, VideoRange::FULL, true, false + Crop(), dcp::Size(1998, 836), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_YUV420P, VideoRange::FULL, Image::Alignment::PADDED, false ); - auto save = out->scale(dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, false, false); + auto save = out->scale(dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::COMPACT, false); write_image(save, "build/test/crop_scale_window_test.png"); check_image("test/data/crop_scale_window_test.png", "build/test/crop_scale_window_test.png"); } @@ -287,12 +286,12 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test) /** Special cases of Image::crop_scale_window which triggered some valgrind warnings */ BOOST_AUTO_TEST_CASE (crop_scale_window_test2) { - auto image = make_shared<Image>(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), true); + auto image = make_shared<Image>(AV_PIX_FMT_XYZ12LE, dcp::Size(2048, 858), Image::Alignment::PADDED); image->crop_scale_window ( - Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(279, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); image->crop_scale_window ( - Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(2048, 0, 0, 0), dcp::Size(1069, 448), dcp::Size(1069, 578), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); } @@ -300,9 +299,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test2) BOOST_AUTO_TEST_CASE (crop_scale_window_test3) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image().image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, true, false); + auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); write_image(cropped, "build/test/crop_scale_window_test3.png"); check_image("test/data/crop_scale_window_test3.png", "build/test/crop_scale_window_test3.png"); @@ -312,9 +311,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test3) BOOST_AUTO_TEST_CASE (crop_scale_window_test4) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image().image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, true, false); + auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, Image::Alignment::COMPACT, false ); write_image(cropped, "build/test/crop_scale_window_test4.png"); check_image("test/data/crop_scale_window_test4.png", "build/test/crop_scale_window_test4.png", 35000); @@ -324,9 +323,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test4) BOOST_AUTO_TEST_CASE (crop_scale_window_test5) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image().image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, true, false); + auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::COMPACT, false ); write_image(cropped, "build/test/crop_scale_window_test5.png"); check_image("test/data/crop_scale_window_test5.png", "build/test/crop_scale_window_test5.png"); @@ -336,9 +335,9 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test5) BOOST_AUTO_TEST_CASE (crop_scale_window_test6) { auto proxy = make_shared<FFmpegImageProxy>(TestPaths::private_data() / "player_seek_test_0.png"); - auto xyz = proxy->image().image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, true, false); + auto xyz = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_XYZ12LE, Image::Alignment::PADDED, false); auto cropped = xyz->crop_scale_window( - Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, false, false + Crop(512, 0, 0, 0), dcp::Size(1486, 1080), dcp::Size(1998, 1080), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_XYZ12LE, VideoRange::FULL, Image::Alignment::COMPACT, false ); write_image(cropped, "build/test/crop_scale_window_test6.png"); check_image("test/data/crop_scale_window_test6.png", "build/test/crop_scale_window_test6.png", 35000); @@ -351,7 +350,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) using namespace boost::filesystem; for (int left_crop = 0; left_crop < 8; ++left_crop) { auto proxy = make_shared<FFmpegImageProxy>("test/data/rgb_grey_testcard.png"); - auto yuv = proxy->image().image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_YUV420P, true, false); + auto yuv = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_YUV420P, Image::Alignment::PADDED, false); int rounded = left_crop - (left_crop % 2); auto cropped = yuv->crop_scale_window( Crop(left_crop, 0, 0, 0), @@ -361,7 +360,7 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) VideoRange::VIDEO, AV_PIX_FMT_RGB24, VideoRange::VIDEO, - true, + Image::Alignment::PADDED, false ); path file = String::compose("crop_scale_window_test7-%1.png", left_crop); @@ -374,8 +373,8 @@ BOOST_AUTO_TEST_CASE (crop_scale_window_test7) BOOST_AUTO_TEST_CASE (as_png_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/3d_test/000001.png"); - auto image_rgb = proxy->image().image; - auto image_bgr = image_rgb->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_BGRA, true, false); + auto image_rgb = proxy->image(Image::Alignment::PADDED).image; + auto image_bgr = image_rgb->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_BGRA, Image::Alignment::PADDED, false); image_rgb->as_png().write ("build/test/as_png_rgb.png"); image_bgr->as_png().write ("build/test/as_png_bgr.png"); @@ -388,11 +387,11 @@ BOOST_AUTO_TEST_CASE (as_png_test) static void fade_test_format_black (AVPixelFormat f, string name) { - Image yuv (f, dcp::Size(640, 480), true); + Image yuv (f, dcp::Size(640, 480), Image::Alignment::PADDED); yuv.make_black (); yuv.fade (0); string const filename = "fade_test_black_" + name + ".png"; - yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png().write("build/test/" + filename); + yuv.convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png().write("build/test/" + filename); check_image ("test/data/" + filename, "build/test/" + filename); } @@ -402,10 +401,10 @@ static void fade_test_format_red (AVPixelFormat f, float amount, string name) { auto proxy = make_shared<FFmpegImageProxy>("test/data/flat_red.png"); - auto red = proxy->image().image->convert_pixel_format(dcp::YUVToRGB::REC709, f, true, false); + auto red = proxy->image(Image::Alignment::PADDED).image->convert_pixel_format(dcp::YUVToRGB::REC709, f, Image::Alignment::PADDED, false); red->fade (amount); string const filename = "fade_test_red_" + name + ".png"; - red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, true, false)->as_png().write("build/test/" + filename); + red->convert_pixel_format(dcp::YUVToRGB::REC709, AV_PIX_FMT_RGBA, Image::Alignment::PADDED, false)->as_png().write("build/test/" + filename); check_image ("test/data/" + filename, "build/test/" + filename); } @@ -482,9 +481,9 @@ BOOST_AUTO_TEST_CASE (make_black_test) int N = 0; for (auto i: pix_fmts) { - auto foo = make_shared<Image>(i, in_size, true); + auto foo = make_shared<Image>(i, in_size, Image::Alignment::PADDED); foo->make_black (); - auto bar = foo->scale (out_size, dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, true, false); + auto bar = foo->scale (out_size, dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); uint8_t* p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { @@ -506,7 +505,7 @@ BOOST_AUTO_TEST_CASE (make_black_test) BOOST_AUTO_TEST_CASE (make_part_black_test) { auto proxy = make_shared<FFmpegImageProxy>("test/data/flat_red.png"); - auto original = proxy->image().image; + auto original = proxy->image(Image::Alignment::PADDED).image; list<AVPixelFormat> pix_fmts = { AV_PIX_FMT_RGB24, @@ -526,9 +525,9 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) int N = 0; for (auto i: pix_fmts) { for (auto j: positions) { - auto foo = original->convert_pixel_format(dcp::YUVToRGB::REC601, i, true, false); + auto foo = original->convert_pixel_format(dcp::YUVToRGB::REC601, i, Image::Alignment::PADDED, false); foo->make_part_black (j.first, j.second); - auto bar = foo->convert_pixel_format (dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, true, false); + auto bar = foo->convert_pixel_format (dcp::YUVToRGB::REC601, AV_PIX_FMT_RGB24, Image::Alignment::PADDED, false); auto p = bar->data()[0]; for (int y = 0; y < bar->size().height; ++y) { @@ -569,10 +568,10 @@ BOOST_AUTO_TEST_CASE (make_part_black_test) */ BOOST_AUTO_TEST_CASE (over_crop_test) { - auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(128, 128), true); + auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(128, 128), Image::Alignment::PADDED); image->make_black (); auto scaled = image->crop_scale_window ( - Crop(0, 0, 128, 128), dcp::Size(1323, 565), dcp::Size(1349, 565), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, true, true + Crop(0, 0, 128, 128), dcp::Size(1323, 565), dcp::Size(1349, 565), dcp::YUVToRGB::REC709, VideoRange::FULL, AV_PIX_FMT_RGB24, VideoRange::FULL, Image::Alignment::PADDED, true ); string const filename = "over_crop_test.png"; write_image (scaled, "build/test/" + filename); diff --git a/test/low_bitrate_test.cc b/test/low_bitrate_test.cc index 33ce2635d..7050dd771 100644 --- a/test/low_bitrate_test.cc +++ b/test/low_bitrate_test.cc @@ -35,10 +35,26 @@ using std::make_shared; BOOST_AUTO_TEST_CASE (low_bitrate_test) { - auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(1998, 1080), true); + auto image = make_shared<Image>(AV_PIX_FMT_RGB24, dcp::Size(1998, 1080), Image::Alignment::PADDED); image->make_black (); + auto proxy = make_shared<RawImageProxy>(image); - auto frame = make_shared<PlayerVideo>(proxy, Crop(), boost::optional<double>(), dcp::Size(1998, 1080), dcp::Size(1998, 1080), Eyes::BOTH, Part::WHOLE, boost::optional<ColourConversion>(), VideoRange::FULL, std::weak_ptr<Content>(), boost::optional<Frame>(), false); + + auto frame = make_shared<PlayerVideo>( + proxy, + Crop(), + boost::optional<double>(), + dcp::Size(1998, 1080), + dcp::Size(1998, 1080), + Eyes::BOTH, + Part::WHOLE, + boost::optional<ColourConversion>(), + VideoRange::FULL, + std::weak_ptr<Content>(), + boost::optional<Frame>(), + false + ); + auto dcp_video = make_shared<DCPVideo>(frame, 0, 24, 100000000, Resolution::TWO_K); auto j2k = dcp_video->encode_locally(); BOOST_REQUIRE (j2k.size() >= 16536); diff --git a/test/overlap_video_test.cc b/test/overlap_video_test.cc index 724f4e75b..3c969921d 100644 --- a/test/overlap_video_test.cc +++ b/test/overlap_video_test.cc @@ -40,7 +40,6 @@ using std::dynamic_pointer_cast; using std::make_shared; -using std::shared_ptr; BOOST_AUTO_TEST_CASE (overlap_video_test1) @@ -57,7 +56,7 @@ BOOST_AUTO_TEST_CASE (overlap_video_test1) B->video->set_length (24); B->set_position (film, dcpomatic::DCPTime::from_seconds(1)); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); auto pieces = player->_pieces; BOOST_REQUIRE_EQUAL (pieces.size(), 2U); BOOST_CHECK_EQUAL (pieces.front()->content, A); diff --git a/test/pixel_formats_test.cc b/test/pixel_formats_test.cc index f59c594e9..12a95bd69 100644 --- a/test/pixel_formats_test.cc +++ b/test/pixel_formats_test.cc @@ -88,7 +88,7 @@ BOOST_AUTO_TEST_CASE (pixel_formats_test) f->height = 480; f->format = static_cast<int> (i.format); av_frame_get_buffer (f, true); - Image t (f); + Image t (f, Image::Alignment::COMPACT); BOOST_CHECK_EQUAL(t.planes(), i.planes); BOOST_CHECK_EQUAL(t.sample_size(0).height, i.lines[0]); BOOST_CHECK_EQUAL(t.sample_size(1).height, i.lines[1]); diff --git a/test/player_test.cc b/test/player_test.cc index c325537fa..5ed772193 100644 --- a/test/player_test.cc +++ b/test/player_test.cc @@ -25,21 +25,21 @@ */ -#include "lib/film.h" -#include "lib/ffmpeg_content.h" -#include "lib/dcp_content_type.h" -#include "lib/ratio.h" #include "lib/audio_buffers.h" -#include "lib/player.h" -#include "lib/video_content.h" -#include "lib/image_content.h" -#include "lib/string_text_file_content.h" -#include "lib/content_factory.h" -#include "lib/dcp_content.h" -#include "lib/text_content.h" #include "lib/butler.h" #include "lib/compose.hpp" +#include "lib/content_factory.h" #include "lib/cross.h" +#include "lib/dcp_content.h" +#include "lib/dcp_content_type.h" +#include "lib/ffmpeg_content.h" +#include "lib/film.h" +#include "lib/image_content.h" +#include "lib/player.h" +#include "lib/ratio.h" +#include "lib/string_text_file_content.h" +#include "lib/text_content.h" +#include "lib/video_content.h" #include "test.h" #include <boost/test/unit_test.hpp> #include <boost/algorithm/string.hpp> @@ -48,7 +48,6 @@ using std::cout; using std::list; -using std::pair; using std::shared_ptr; using std::make_shared; using boost::bind; @@ -84,7 +83,7 @@ BOOST_AUTO_TEST_CASE (player_silence_padding_test) accumulated = std::make_shared<AudioBuffers>(film->audio_channels(), 0); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->Audio.connect (bind (&accumulate, _1, _2)); while (!player->pass ()) {} BOOST_REQUIRE (accumulated->frames() >= 48000); @@ -164,7 +163,7 @@ BOOST_AUTO_TEST_CASE (player_subframe_test) /* Length should be rounded up from B's length to the next video frame */ BOOST_CHECK (film->length() == DCPTime::from_frames(3 * 24 + 1, 24)); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->setup_pieces (); BOOST_REQUIRE_EQUAL (player->_black._periods.size(), 1U); BOOST_CHECK (player->_black._periods.front() == DCPTimePeriod(DCPTime::from_frames(3 * 24, 24), DCPTime::from_frames(3 * 24 + 1, 24))); @@ -206,7 +205,7 @@ BOOST_AUTO_TEST_CASE (player_interleave_test) film->examine_and_add_content (s); BOOST_REQUIRE (!wait_for_jobs ()); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->Video.connect (bind (&video, _1, _2)); player->Audio.connect (bind (&audio, _1, _2)); video_frames = audio_frames = 0; @@ -229,12 +228,12 @@ BOOST_AUTO_TEST_CASE (player_seek_test) BOOST_REQUIRE (!wait_for_jobs ()); dcp->only_text()->set_use (true); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->set_fast (); player->set_always_burn_open_subtitles (); player->set_play_referenced (); - auto butler = std::make_shared<Butler>(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true); + auto butler = std::make_shared<Butler>(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::PADDED, true, false); butler->disable_audio(); for (int i = 0; i < 10; ++i) { @@ -242,7 +241,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test) butler->seek (t, true); auto video = butler->get_video(true, 0); BOOST_CHECK_EQUAL(video.second.get(), t.get()); - write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true), String::compose("build/test/player_seek_test_%1.png", i)); + write_image(video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, true), String::compose("build/test/player_seek_test_%1.png", i)); /* This 14.08 is empirically chosen (hopefully) to accept changes in rendering between the reference and a test machine (17.10 and 16.04 seem to anti-alias a little differently) but to reject gross errors e.g. missing fonts or missing text altogether. @@ -261,12 +260,12 @@ BOOST_AUTO_TEST_CASE (player_seek_test2) BOOST_REQUIRE (!wait_for_jobs ()); dcp->only_text()->set_use (true); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->set_fast (); player->set_always_burn_open_subtitles (); player->set_play_referenced (); - auto butler = std::make_shared<Butler>(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true); + auto butler = std::make_shared<Butler>(film, player, AudioMapping(), 2, bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::PADDED, true, false); butler->disable_audio(); butler->seek(DCPTime::from_seconds(5), true); @@ -277,7 +276,7 @@ BOOST_AUTO_TEST_CASE (player_seek_test2) auto video = butler->get_video(true, 0); BOOST_CHECK_EQUAL(video.second.get(), t.get()); write_image( - video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true), String::compose("build/test/player_seek_test2_%1.png", i) + video.first->image(bind(PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, true), String::compose("build/test/player_seek_test2_%1.png", i) ); check_image(TestPaths::private_data() / String::compose("player_seek_test2_%1.png", i), String::compose("build/test/player_seek_test2_%1.png", i), 14.08); } @@ -335,7 +334,7 @@ BOOST_AUTO_TEST_CASE (player_ignore_video_and_audio_test) text->only_text()->set_type (TextType::CLOSED_CAPTION); text->only_text()->set_use (true); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->set_ignore_video (); player->set_ignore_audio (); @@ -355,9 +354,9 @@ BOOST_AUTO_TEST_CASE (player_trim_crash) film->examine_and_add_content (boon); BOOST_REQUIRE (!wait_for_jobs()); - auto player = std::make_shared<Player>(film); + auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT); player->set_fast (); - auto butler = std::make_shared<Butler>(film, player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, false, true); + auto butler = std::make_shared<Butler>(film, player, AudioMapping(), 6, bind(&PlayerVideo::force, _1, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::COMPACT, true, false); /* Wait for the butler to fill */ dcpomatic_sleep_seconds (5); diff --git a/test/test.cc b/test/test.cc index 4dab0cff1..8417b30d2 100644 --- a/test/test.cc +++ b/test/test.cc @@ -364,9 +364,9 @@ double rms_error (boost::filesystem::path ref, boost::filesystem::path check) { FFmpegImageProxy ref_proxy (ref); - auto ref_image = ref_proxy.image().image; + auto ref_image = ref_proxy.image(Image::Alignment::COMPACT).image; FFmpegImageProxy check_proxy (check); - auto check_image = check_proxy.image().image; + auto check_image = check_proxy.image(Image::Alignment::COMPACT).image; BOOST_REQUIRE_EQUAL (ref_image->pixel_format(), check_image->pixel_format()); AVPixelFormat const format = ref_image->pixel_format(); diff --git a/test/time_calculation_test.cc b/test/time_calculation_test.cc index ffe77c2b7..4ab5d0942 100644 --- a/test/time_calculation_test.cc +++ b/test/time_calculation_test.cc @@ -36,7 +36,6 @@ using std::list; using std::make_shared; -using std::shared_ptr; using std::string; using namespace dcpomatic; @@ -197,7 +196,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test1) film->set_sequence (false); film->add_content (content); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); /* Position 0, no trim, content rate = DCP rate */ content->set_position (film, DCPTime()); @@ -206,7 +205,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test1) film->set_video_frame_rate (24); player->setup_pieces (); BOOST_REQUIRE_EQUAL (player->_pieces.size(), 1U); - shared_ptr<Piece> piece = player->_pieces.front (); + auto piece = player->_pieces.front(); BOOST_CHECK_EQUAL (player->dcp_to_content_video (piece, DCPTime ()), 0); BOOST_CHECK_EQUAL (player->dcp_to_content_video (piece, DCPTime::from_seconds (0.5)), 12); BOOST_CHECK_EQUAL (player->dcp_to_content_video (piece, DCPTime::from_seconds (3.0)), 72); @@ -403,7 +402,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test2) film->set_sequence (false); film->add_content (content); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); /* Position 0, no trim, content rate = DCP rate */ content->set_position (film, DCPTime()); @@ -412,7 +411,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test2) film->set_video_frame_rate (24); player->setup_pieces (); BOOST_REQUIRE_EQUAL (player->_pieces.size(), 1U); - shared_ptr<Piece> piece = player->_pieces.front (); + auto piece = player->_pieces.front (); BOOST_CHECK_EQUAL (player->content_video_to_dcp (piece, 0).get(), 0); BOOST_CHECK_EQUAL (player->content_video_to_dcp (piece, 12).get(), DCPTime::from_seconds(0.5).get()); BOOST_CHECK_EQUAL (player->content_video_to_dcp (piece, 72).get(), DCPTime::from_seconds(3.0).get()); @@ -580,7 +579,7 @@ BOOST_AUTO_TEST_CASE (player_time_calculation_test3) film->set_sequence (false); film->add_content (content); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); /* Position 0, no trim, video/audio content rate = video/audio DCP rate */ content->set_position (film, DCPTime()); diff --git a/test/upmixer_a_test.cc b/test/upmixer_a_test.cc index 0dc496275..af6c8b9e2 100644 --- a/test/upmixer_a_test.cc +++ b/test/upmixer_a_test.cc @@ -89,7 +89,7 @@ BOOST_AUTO_TEST_CASE (upmixer_a_test) Ls = sf_open ("build/test/upmixer_a_test/Ls.wav", SFM_WRITE, &info); Rs = sf_open ("build/test/upmixer_a_test/Rs.wav", SFM_WRITE, &info); - auto player = make_shared<Player>(film); + auto player = make_shared<Player>(film, Image::Alignment::COMPACT); player->Audio.connect (bind (&write, _1, _2)); while (!player->pass()) {} diff --git a/test/vf_test.cc b/test/vf_test.cc index b7e976041..4db48dd60 100644 --- a/test/vf_test.cc +++ b/test/vf_test.cc @@ -291,7 +291,7 @@ BOOST_AUTO_TEST_CASE (vf_test5) make_and_verify_dcp (vf, {dcp::VerificationNote::Code::EXTERNAL_ASSET}); /* Check that the selected reel assets are right */ - auto player = make_shared<Player>(vf); + auto player = make_shared<Player>(vf, Image::Alignment::COMPACT); auto a = player->get_reel_assets(); BOOST_REQUIRE_EQUAL (a.size(), 4U); auto i = a.begin(); diff --git a/test/video_level_test.cc b/test/video_level_test.cc index be54cd3f9..ada9b602a 100644 --- a/test/video_level_test.cc +++ b/test/video_level_test.cc @@ -54,7 +54,6 @@ using std::min; -using std::make_pair; using std::max; using std::pair; using std::string; @@ -71,7 +70,7 @@ static shared_ptr<Image> grey_image (dcp::Size size, uint8_t pixel) { - auto grey = make_shared<Image>(AV_PIX_FMT_RGB24, size, true); + auto grey = make_shared<Image>(AV_PIX_FMT_RGB24, size, Image::Alignment::PADDED); for (int y = 0; y < size.height; ++y) { uint8_t* p = grey->data()[0] + y * grey->stride()[0]; for (int x = 0; x < size.width; ++x) { @@ -94,7 +93,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_image_full_range_not_changed) write_image (grey_image(size, grey_pixel), file); FFmpegImageProxy proxy (file); - ImageProxy::Result result = proxy.image (); + ImageProxy::Result result = proxy.image (Image::Alignment::COMPACT); BOOST_REQUIRE (!result.error); for (int y = 0; y < size.height; ++y) { @@ -128,7 +127,7 @@ BOOST_AUTO_TEST_CASE (ffmpeg_image_video_range_expanded) BOOST_REQUIRE (!player->pass()); } - auto image = player_video->image ([](AVPixelFormat f) { return f; }, VideoRange::FULL, true, false); + auto image = player_video->image ([](AVPixelFormat f) { return f; }, VideoRange::FULL, false); for (int y = 0; y < size.height; ++y) { uint8_t* p = image->data()[0] + y * image->stride()[0]; @@ -214,7 +213,7 @@ pixel_range (shared_ptr<const Film> film, shared_ptr<const Content> content) BOOST_REQUIRE (!decoder->pass()); } - return pixel_range (content_video->image->image().image); + return pixel_range (content_video->image->image(Image::Alignment::COMPACT).image); } |
