YUYV422.hpp
1 #pragma once
2 #include <Gfx/Graph/decoders/ColorSpace.hpp>
3 #include <Gfx/Graph/decoders/GPUVideoDecoder.hpp>
4 extern "C" {
5 #include <libavformat/avformat.h>
6 }
7 
8 namespace score::gfx
9 {
16 {
17  static const constexpr auto frag = R"_(#version 450
18 
19 )_" SCORE_GFX_VIDEO_UNIFORMS R"_(
20 
21 layout(binding=3) uniform sampler2D u_tex;
22 
23 layout(location = 0) in vec2 v_texcoord;
24 layout(location = 0) out vec4 fragColor;
25 
26 %2
27 
28 vec4 processTexture(vec4 tex) {
29  vec4 processed = convert_to_rgb(tex);
30  { %1 }
31  return processed;
32 }
33 
34 void main() {
35  vec4 tex = texture(u_tex, v_texcoord);
36  float y = tex.r;
37  float u = tex.g;
38  float v = tex.a;
39 
40  fragColor = processTexture(vec4(y,u,v, 1.));
41 }
42 )_";
43 
45  : decoder{d}
46  {
47  }
48 
49  Video::ImageFormat& decoder;
50  std::pair<QShader, QShader> init(RenderList& r) override
51  {
52  auto& rhi = *r.state.rhi;
53 
54  const auto w = decoder.width, h = decoder.height;
55  // Y
56  {
57  auto tex = rhi.newTexture(QRhiTexture::RGBA8, {w / 2, h}, 1, QRhiTexture::Flag{});
58  tex->create();
59 
60  auto sampler = rhi.newSampler(
61  QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
62  QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
63  sampler->create();
64  samplers.push_back({sampler, tex});
65  }
66 
68  r.state, vertexShader(), QString(frag).arg("").arg(colorMatrix(decoder)));
69  }
70 
71  void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
72  {
73  setYPixels(res, frame.data[0], frame.linesize[0]);
74  }
75 
76  void
77  setYPixels(QRhiResourceUpdateBatch& res, uint8_t* pixels, int stride) const noexcept
78  {
79  const auto w = decoder.width, h = decoder.height;
80  auto y_tex = samplers[0].texture;
81 
82  QRhiTextureUploadEntry entry{0, 0, createTextureUpload(pixels, w, h, 2, stride)};
83 
84  QRhiTextureUploadDescription desc{entry};
85  res.uploadTexture(y_tex, desc);
86  }
87 };
88 
95 {
96  static const constexpr auto frag = R"_(#version 450
97 
98 )_" SCORE_GFX_VIDEO_UNIFORMS R"_(
99 
100 layout(binding=3) uniform sampler2D u_tex;
101 
102 layout(location = 0) in vec2 v_texcoord;
103 layout(location = 0) out vec4 fragColor;
104 
105 %2
106 
107 vec4 processTexture(vec4 tex) {
108  vec4 processed = convert_to_rgb(tex);
109  { %1 }
110  return processed;
111 }
112 
113 void main() {
114  // For U0 Y0 V0 Y1 macropixel, lookup Y0 or Y1 based on whether
115  // the original texture x coord is even or odd.
116  vec4 uyvy = texture(u_tex, v_texcoord);
117  float y;
118  if (fract(floor(v_texcoord.x * renderer.renderSize.x + 0.5) / 2.0) > 0.0)
119  y = uyvy.a; // odd so choose Y1
120  else
121  y = uyvy.g; // even so choose Y0
122  float u = uyvy.r;
123  float v = uyvy.b;
124 
125  fragColor = processTexture(vec4(y,u,v, 1.));
126 }
127 )_";
128 
130  : decoder{d}
131  {
132  }
133 
134  Video::ImageFormat& decoder;
135  std::pair<QShader, QShader> init(RenderList& r) override
136  {
137  auto& rhi = *r.state.rhi;
138 
139  const auto w = decoder.width, h = decoder.height;
140  // Y
141  {
142  auto tex = rhi.newTexture(QRhiTexture::RGBA8, {w / 2, h}, 1, QRhiTexture::Flag{});
143  tex->create();
144 
145  auto sampler = rhi.newSampler(
146  QRhiSampler::Linear, QRhiSampler::Linear, QRhiSampler::None,
147  QRhiSampler::ClampToEdge, QRhiSampler::ClampToEdge);
148  sampler->create();
149  samplers.push_back({sampler, tex});
150  }
151 
153  r.state, vertexShader(), QString(frag).arg("").arg(colorMatrix(decoder)));
154  }
155 
156  void exec(RenderList&, QRhiResourceUpdateBatch& res, AVFrame& frame) override
157  {
158  auto y_tex = samplers[0].texture;
159 
160  auto pixels = frame.data[0];
161  auto stride = frame.linesize[0];
162  QRhiTextureUploadEntry entry{
163  0, 0, createTextureUpload(pixels, frame.width, frame.height, 2, stride)};
164 
165  QRhiTextureUploadDescription desc{entry};
166  res.uploadTexture(y_tex, desc);
167  }
168 };
169 
170 }
Processes and renders a video frame on the GPU.
Definition: GPUVideoDecoder.hpp:43
static QRhiTextureSubresourceUploadDescription createTextureUpload(uint8_t *pixels, int w, int h, int bytesPerPixel, int stride)
Utility method to create a QRhiTextureSubresourceUploadDescription.
Definition: GPUVideoDecoder.cpp:22
List of nodes to be rendered to an output.
Definition: RenderList.hpp:19
RenderState & state
RenderState corresponding to this RenderList.
Definition: RenderList.hpp:89
Graphics rendering pipeline for ossia score.
Definition: Filter/PreviewWidget.hpp:12
std::pair< QShader, QShader > makeShaders(const RenderState &v, QString vert, QString frag)
Get a pair of compiled vertex / fragment shaders from GLSL 4.5 sources.
Definition: score-plugin-gfx/Gfx/Graph/Utils.cpp:342
Definition: VideoInterface.hpp:16
Decodes UYVY422 video, mostly used for NDI.
Definition: YUYV422.hpp:95
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition: YUYV422.hpp:156
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition: YUYV422.hpp:135
Decodes YUYV422 video.
Definition: YUYV422.hpp:16
void exec(RenderList &, QRhiResourceUpdateBatch &res, AVFrame &frame) override
Decode and upload a video frame to the GPU.
Definition: YUYV422.hpp:71
std::pair< QShader, QShader > init(RenderList &r) override
Initialize a GPUVideoDecoder.
Definition: YUYV422.hpp:50