Skip to content

Commit bae35e7

Browse files
committed
Supports YUV422 8bit UYVY and YUV422 10bit v210
1 parent 76040a0 commit bae35e7

File tree

8 files changed

+286
-21
lines changed

8 files changed

+286
-21
lines changed

HDR10Capture2019/00README.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ Extract all and run HDR10Capture.exe
33

44
Tested capture card: DeckLink Mini Recorder 4K.
55

6+
Version 1.3
7+
8+
-Support to capture YUV422 8bit UYVY and YUV422 10bit v210.
9+
610
Version 1.2
711

812
-File overwrite error.

HDR10Capture2019/MLAVICommon.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ uint32_t MLStringToFourCC(const char* s);
88
const std::string MLFourCCtoString(uint32_t fourcc);
99

1010
enum MLAviImageFormat {
11-
MLIF_Unknown,
11+
MLIF_Unknown = -1,
12+
MLIF_YUV422_UYVY,
1213
MLIF_YUV422_v210,
1314
MLIF_RGB10bit_r210,
1415
MLIF_RGB12bit_R12B,

HDR10Capture2019/MLAviWriter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,8 @@ uint32_t
390390
MLAviImageFormatToFourcc(MLAviImageFormat t)
391391
{
392392
switch (t) {
393+
case MLIF_YUV422_UYVY:
394+
return MLStringToFourCC("UYVY");
393395
case MLIF_YUV422_v210:
394396
return MLStringToFourCC("v210");
395397
case MLIF_RGB10bit_r210:
@@ -406,6 +408,8 @@ int
406408
MLAviImageFormatToBitsPerPixel(MLAviImageFormat t)
407409
{
408410
switch (t) {
411+
case MLIF_YUV422_UYVY:
412+
return 16;
409413
case MLIF_YUV422_v210:
410414
return 20;
411415
case MLIF_RGB10bit_r210:

HDR10Capture2019/MLConverter.cpp

Lines changed: 215 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,86 @@ HtoNS(uint16_t v)
2929
((v >> 8) & 0xff);
3030
}
3131

32+
static float
33+
Saturate01(const float v)
34+
{
35+
if (v < 0) {
36+
return 0;
37+
} else if (1.0f < v) {
38+
return 1.0f;
39+
} else {
40+
return v;
41+
}
42+
}
43+
44+
/// <summary>
45+
/// 0~1の範囲のfloat値のYUVを0~1の範囲のfloat値のRGBにする。
46+
/// </summary>
47+
static void
48+
YuvToRgb(
49+
const float y, const float u, const float v,
50+
float* r_return, float *g_return, float *b_return)
51+
{
52+
*r_return = Saturate01(1.1644f * y + 0.0000f * u + 1.5960f * v - 0.8742f);
53+
*g_return = Saturate01(1.1644f * y - 0.3918f * u - 0.8130f * v + 0.5317f);
54+
*b_return = Saturate01(1.1644f * y + 2.0172f * u + 0.0000f * v - 1.0856f);
55+
}
56+
57+
/// <summary>
58+
/// 8bit YUV → 8bit RGB
59+
/// </summary>
60+
static void
61+
Yuv8ToRgb8(
62+
const uint8_t y8, const uint8_t u8, const uint8_t v8,
63+
uint8_t* r8_return, uint8_t* g8_return, uint8_t* b8_return)
64+
{
65+
const float y = y8 / 255.0f;
66+
const float u = u8 / 255.0f;
67+
const float v = v8 / 255.0f;
68+
69+
const float r = Saturate01(1.1644f * y + 0.0000f * u + 1.5960f * v - 0.8742f);
70+
const float g = Saturate01(1.1644f * y - 0.3918f * u - 0.8130f * v + 0.5317f);
71+
const float b = Saturate01(1.1644f * y + 2.0172f * u + 0.0000f * v - 1.0856f);
72+
73+
*r8_return = (uint8_t)(r * 255.0f);
74+
*g8_return = (uint8_t)(g * 255.0f);
75+
*b8_return = (uint8_t)(b * 255.0f);
76+
}
77+
78+
/// <summary>
79+
/// 10bit YUV → 10bit RGB
80+
/// </summary>
81+
static void
82+
Yuv10ToRgb10(
83+
const uint16_t y10, const uint16_t u10, const uint16_t v10,
84+
uint16_t* r10_return, uint16_t* g10_return, uint16_t* b10_return)
85+
{
86+
const float y = y10 / 1023.0f;
87+
const float u = u10 / 1023.0f;
88+
const float v = v10 / 1023.0f;
89+
90+
const float r = Saturate01(1.1644f * y + 0.0000f * u + 1.5960f * v - 0.8742f);
91+
const float g = Saturate01(1.1644f * y - 0.3918f * u - 0.8130f * v + 0.5317f);
92+
const float b = Saturate01(1.1644f * y + 2.0172f * u + 0.0000f * v - 1.0856f);
93+
94+
*r10_return = (uint16_t)(r * 1023.0f);
95+
*g10_return = (uint16_t)(g * 1023.0f);
96+
*b10_return = (uint16_t)(b * 1023.0f);
97+
}
98+
99+
/// <summary>
100+
/// 0~1の範囲のfloat値のRGBを0~1の範囲のfloat値のYUVにする。
101+
/// </summary>
102+
static void
103+
RgbToYuv(
104+
const float r, const float g, const float b,
105+
float* y_return, float* u_return, float* v_return)
106+
{
107+
*y_return = Saturate01( 0.2568f * r + 0.5041f * g + 0.0979f * b + 0.0627f);
108+
*u_return = Saturate01(-0.1482f * r - 0.2910f * g + 0.4392f * b + 0.5020f);
109+
*v_return = Saturate01( 0.4392f * r - 0.3678f * g - 0.0714f * b + 0.5020f);
110+
}
111+
32112
static const float pq_m1 = 0.1593017578125f; // ( 2610.0 / 4096.0 ) / 4.0;
33113
static const float pq_m2 = 78.84375f; // ( 2523.0 / 4096.0 ) * 128.0;
34114
static const float pq_c1 = 0.8359375f; // 3424.0 / 4096.0 or pq_c3 - pq_c2 + 1.0;
@@ -68,6 +148,134 @@ MLConverter::MLConverter(void)
68148
}
69149
}
70150

151+
void
152+
MLConverter::Uyvy8bitToR8G8B8A8(const uint32_t* pFrom, uint32_t* pTo, const int width, const int height)
153+
{
154+
// widthは2で割り切れる。
155+
assert((width & 1) == 0);
156+
157+
const uint32_t a = 0xff;
158+
159+
#pragma omp parallel for
160+
for (int y = 0; y < height; ++y) {
161+
for (int x2 = 0; x2 < width/2; ++x2) {
162+
//2ピクセルずつ処理。
163+
164+
//入力のUYVY: 2ピクセルが1個のuint32に入る。
165+
const int readP = x2 + y * (width/2);
166+
//出力: 1ピクセルが1個のuint32に入る。
167+
const int writeP = (x2 * 2) + y * width;
168+
169+
// bmdFormat8BitYUV: UYVY
170+
// ビッグエンディアンのUYVU
171+
// w LSB
172+
// YYYYYYYY VVVVVVVV YYYYYYYY UUUUUUUU
173+
// 76543210 76543210 76543210 76543210
174+
const uint32_t w = pFrom[readP];
175+
176+
const uint32_t y0 = (w >> 8) & 0xff;
177+
const uint32_t y1 = (w >> 24) & 0xff;
178+
179+
const uint32_t u = (w >> 0) & 0xff;
180+
const uint32_t v = (w >> 16) & 0xff;
181+
182+
// yuv → RGB
183+
uint8_t r, g, b;
184+
185+
Yuv8ToRgb8(y0, u, v, &r, &g, &b);
186+
pTo[writeP + 0] = (a << 24) + (b << 16) + (g << 8) + r;
187+
188+
Yuv8ToRgb8(y1, u, v, &r, &g, &b);
189+
pTo[writeP + 1] = (a << 24) + (b << 16) + (g << 8) + r;
190+
}
191+
}
192+
}
193+
/// <summary>
194+
/// bmdFormat10BitYUV v210 → DXGI_FORMAT_R10G10B10A2_UNORM
195+
/// </summary>
196+
void
197+
MLConverter::Yuv422_10bitToR10G10B10A2(const uint32_t* pFrom, uint32_t* pTo, const int width, const int height)
198+
{
199+
const uint32_t a = 0x3;
200+
201+
assert((width % 48) == 0);
202+
203+
#pragma omp parallel for
204+
for (int y = 0; y < height; ++y) {
205+
for (int x6 = 0; x6 < width/6; ++x6) {
206+
// 6ピクセルずつ処理。
207+
208+
//入力のv210: 6ピクセルが4個のuint32に入る。
209+
const int readP = x6*4 + y * (width *4 / 6);
210+
211+
// 出力:1ピクセルが1個のuint32に入る。
212+
const int writeP = (x6 * 6) + y * width;
213+
214+
// bmdFormat10BitYUV v210
215+
const uint32_t w0 = pFrom[readP + 0];
216+
const uint32_t w1 = pFrom[readP + 1];
217+
const uint32_t w2 = pFrom[readP + 2];
218+
const uint32_t w3 = pFrom[readP + 3];
219+
220+
// w0 LSB
221+
// --vvvvvv vvvvyyyy yyyyyyuu uuuuuuuu
222+
// --000000 00000000 00000000 00000000 pixelIdx
223+
// --987654 32109876 54321098 76543210
224+
225+
// w1 LSB
226+
// --yyyyyy yyyyuuuu uuuuuuyy yyyyyyyy
227+
// --222222 22222222 22222211 11111111 pixelIdx
228+
// --987654 32109876 54321098 76543210
229+
230+
// w0 LSB
231+
// --uuuuuu uuuuyyyy yyyyyyvv vvvvvvvv
232+
// --444444 44443333 33333322 22222222 pixelIdx
233+
// --987654 32109876 54321098 76543210
234+
// w0 LSB
235+
// --yyyyyy yyyyvvvv vvvvvvyy yyyyyyyy
236+
// --555555 55554444 44444444 44444444 pixelIdx
237+
// --987654 32109876 54321098 76543210
238+
239+
const uint32_t u0 = (w0 >> 0) & 0x3ff;
240+
const uint32_t y0 = (w0 >> 10) & 0x3ff;
241+
const uint32_t v0 = (w0 >> 20) & 0x3ff;
242+
243+
const uint32_t y1 = (w1 >> 0) & 0x3ff;
244+
const uint32_t u2 = (w1 >> 10) & 0x3ff;
245+
const uint32_t y2 = (w1 >> 20) & 0x3ff;
246+
247+
const uint32_t v2 = (w2 >> 0) & 0x3ff;
248+
const uint32_t y3 = (w2 >> 10) & 0x3ff;
249+
const uint32_t u4 = (w2 >> 20) & 0x3ff;
250+
251+
const uint32_t y4 = (w3 >> 0) & 0x3ff;
252+
const uint32_t v4 = (w3 >> 10) & 0x3ff;
253+
const uint32_t y5 = (w3 >> 20) & 0x3ff;
254+
255+
// yuv → RGB
256+
uint16_t r, g, b;
257+
258+
Yuv10ToRgb10(y0, u0, v0, &r, &g, &b);
259+
pTo[writeP + 0] = (a << 30) + (b << 20) + (g << 10) + r;
260+
261+
Yuv10ToRgb10(y1, u0, v0, &r, &g, &b);
262+
pTo[writeP + 1] = (a << 30) + (b << 20) + (g << 10) + r;
263+
264+
Yuv10ToRgb10(y2, u2, v2, &r, &g, &b);
265+
pTo[writeP + 2] = (a << 30) + (b << 20) + (g << 10) + r;
266+
267+
Yuv10ToRgb10(y3, u2, v2, &r, &g, &b);
268+
pTo[writeP + 3] = (a << 30) + (b << 20) + (g << 10) + r;
269+
270+
Yuv10ToRgb10(y4, u4, v4, &r, &g, &b);
271+
pTo[writeP + 4] = (a << 30) + (b << 20) + (g << 10) + r;
272+
273+
Yuv10ToRgb10(y5, u4, v4, &r, &g, &b);
274+
pTo[writeP + 5] = (a << 30) + (b << 20) + (g << 10) + r;
275+
}
276+
}
277+
}
278+
71279
void
72280
MLConverter::Argb8bitToR8G8B8A8(const uint32_t* pFrom, uint32_t* pTo, const int width, const int height)
73281
{
@@ -78,16 +286,16 @@ MLConverter::Argb8bitToR8G8B8A8(const uint32_t* pFrom, uint32_t* pTo, const int
78286

79287
// bmdFormat8BitARGB
80288
// ビッグエンディアンのA8R8G8B8 → リトルエンディアンのR8G8B8A8
81-
const uint32_t v = NtoHL(pFrom[pos]);
289+
const uint32_t w = pFrom[pos];
82290

83-
// v LSB
84-
// AAAAAAAA RRRRRRRR GGGGGGGG BBBBBBBB
291+
// w LSB
292+
// BBBBBBBB GGGGGGGG RRRRRRRR AAAAAAAA
85293
// 76543210 76543210 76543210 76543210
86294

87-
const uint32_t a = (v >> 24) & 0xff;
88-
const uint32_t r = (v >> 16) & 0xff;
89-
const uint32_t g = (v >> 8) & 0xff;
90-
const uint32_t b = (v >> 0) & 0xff;
295+
const uint8_t a = (w >> 0) & 0xff;
296+
const uint8_t r = (w >> 8) & 0xff;
297+
const uint8_t g = (w >> 16) & 0xff;
298+
const uint8_t b = (w >> 24) & 0xff;
91299
pTo[pos] = (a << 24) + (b << 16) + (g << 8) + r;
92300
}
93301
}

HDR10Capture2019/MLConverter.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@ class MLConverter {
88
MLConverter(void);
99
~MLConverter(void) { }
1010

11+
/// <summary>
12+
/// bmdFormat8BitYUV UYVY ¨ DXGI_FORMAT_R8G8B8A8_UNORM
13+
/// </summary>
14+
static void Uyvy8bitToR8G8B8A8(const uint32_t* pFrom, uint32_t* pTo, const int width, const int height);
15+
16+
/// <summary>
17+
/// bmdFormat10BitYUV v210 ¨ DXGI_FORMAT_R10G10B10A2_UNORM
18+
/// </summary>
19+
static void Yuv422_10bitToR10G10B10A2(const uint32_t* pFrom, uint32_t* pTo, const int width, const int height);
20+
1121
/// <summary>
1222
/// bmdFormat8BitARGB ¨ DXGI_FORMAT_R8G8B8A8_UNORM
1323
/// </summary>

HDR10Capture2019/MLDX12App.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,10 @@ MLAviImageFormat
971971
BMDPixelFormatToMLAviImageFormat(BMDPixelFormat t)
972972
{
973973
switch (t) {
974+
case bmdFormat8BitYUV:
975+
return MLIF_YUV422_UYVY;
976+
case bmdFormat10BitYUV:
977+
return MLIF_YUV422_v210;
974978
case bmdFormat10BitRGB:
975979
return MLIF_RGB10bit_r210;
976980
case bmdFormat12BitRGB:
@@ -1084,8 +1088,10 @@ MLDX12App::ShowVideoCaptureWindow(void)
10841088
BMDFieldDominanceToStr(fmt.fieldDominance),
10851089
BMDDetectedVideoInputFormatFlagsToStr(mVCU.DetectedVideoInputFormatFlags()).c_str());
10861090

1087-
if (mVCU.DetectedVideoInputFormatFlags() & bmdDetectedVideoInputRGB444) {
1091+
if ((mVCU.DetectedVideoInputFormatFlags() & bmdDetectedVideoInputRGB444) ||
1092+
(mVCU.DetectedVideoInputFormatFlags() & bmdDetectedVideoInputYCbCr422)) {
10881093
// キャプチャー可能。
1094+
ImGui::Text("Captured As: %s", BMDPixelFormatToStr(fmt.pixelFormat));
10891095
} else {
10901096
// キャプチャー不可。対応してない。
10911097
ImGui::Text("Unsupported format! %s",

0 commit comments

Comments
 (0)