Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f124cfacfb | |||
| 4e14404726 | |||
| db77846f1b | |||
| 57fa627bed | |||
| 9dbfd34566 | |||
| 3dc2a77529 | |||
| 7dbce62182 | |||
| bb84350591 | |||
| 7db7f4b89e | |||
| e5b2d2306f | |||
| 54b166d33f | |||
| 344029f195 | |||
| 4837ab2786 | |||
| e38f57af46 | |||
| e667c6b869 | |||
| 0b344eb52a |
+1
-1
@@ -124,7 +124,7 @@ make -f Makefile.dev release-arch
|
||||
- [x] (clean) static functions at top of files
|
||||
- [x] Configurable key codes
|
||||
- [x] Monitor improvements
|
||||
- [ ] Ignore some values in auto random
|
||||
- [x] Ignore some values in auto random
|
||||
- [x] build without video in
|
||||
- [ ] Update README monitor/keymap
|
||||
- [x] Auto reconnect midi input
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
pkgname=forge-steel
|
||||
pkgver=1.1.2
|
||||
pkgver=1.2.1
|
||||
pkgrel=1
|
||||
pkgdesc="Fusion Of Real Time Generative Effects"
|
||||
arch=('i686' 'pentium4' 'x86_64' 'arm' 'armv7h' 'armv6h' 'aarch64' 'riscv64')
|
||||
depends=('glfw>=1:3', 'v4l-utils>=1.32', 'alsa-lib>=1.2', 'libglvnd>=1.7')
|
||||
url="https://git.klemek.fr/klemek/forge-steel"
|
||||
source=("${pkgname}-steel-${pkgver}.tar.gz::https://git.klemek.fr/klemek/forge-steel/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
||||
sha256sums=('cf4b280fba47d649ab33596d43872a70dd443ed6d15dc587b9dac4e5db294e06')
|
||||
sha256sums=('57559bde7a524e3c9e70de4bc9b675a5a086590a8d85697cebd80c0ebd09f149')
|
||||
srcdir=build
|
||||
backup=("usr/share/${pkgname}")
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[](https://git.klemek.fr/klemek/forge-steel/actions?workflow=lint.yml) [](https://git.klemek.fr/klemek/forge-steel/actions?workflow=build.yml) 
|
||||
[](https://git.klemek.fr/klemek/forge-steel/actions?workflow=lint.yml) [](https://git.klemek.fr/klemek/forge-steel/actions?workflow=build.yml) 
|
||||
|
||||
<!-- omit from toc -->
|
||||
# F.O.R.G.E. (Steel)
|
||||
@@ -174,9 +174,9 @@ These are configurable in the [`forge_project.cfg`](#forge_projectcfg).
|
||||
### CLI arguments
|
||||
|
||||
```txt
|
||||
forge steel-VERSION
|
||||
forge steel-dev
|
||||
|
||||
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vb=COUNT] [-vr / -nvr] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf]
|
||||
usage: forge [-h] [-v] [-p=PROJECT_PATH] [-c=CFG_FILE] [-hr] [-s=SCREEN] [-m=SCREEN] [-mo] [-w] [-t=TEMPO] [-d] [-ar / -nar] [-arc=CYCLES] [-vi=FILE] [-vs=SIZE] [-vb=COUNT] [-vr / -nvr] [-vf=FOURCC] [-is=SIZE] [-ls / -nls] [-ss / -nss] [-mr / -nmr] [-tm] [-tf]
|
||||
|
||||
Fusion Of Real-time Generative Effects.
|
||||
|
||||
@@ -196,10 +196,11 @@ options:
|
||||
-nar, --no-auto-random do not randomize state (default)
|
||||
-arc, --auto-random-cycle auto random cycle length (default: 4)
|
||||
-vi, --video-in path to video capture device (multiple allowed)
|
||||
-vb, --video-buffers number of video buffers to use (default: 2)
|
||||
-vb, --video-buffers number of video buffers to use (default: 1)
|
||||
-vs, --video-size video capture desired height (default: internal texture height)
|
||||
-vr, --video-reconnect auto-reconnect video (default)
|
||||
-nvr, --no-video-reconnect do not auto-reconnect video
|
||||
-vf, --video-fourcc video codec fourcc (default: YUYV)
|
||||
-is, --internal-size internal texture height (default: 720)
|
||||
-ls, --load-state load saved state (default)
|
||||
-nls, --no-load-state do not load saved state
|
||||
@@ -262,6 +263,28 @@ Working with pages and items, you can use the following predefined sources and e
|
||||
|
||||
See the [printable version](./docs/forge_default_mapping.pdf).
|
||||
|
||||
### Available hotkeys
|
||||
|
||||
| Hotkey | Function |
|
||||
| ------ | -------- |
|
||||
| <kbd>Shift</kbd> + <kbd>F</kbd> | Switch between shader-decoded or hardware decoded YUYV |
|
||||
| <kbd>M</kbd> | Projection mapping 1 |
|
||||
| <kbd>Shift</kbd> + <kbd>M</kbd> | Projection mapping 2 |
|
||||
| <kbd>Ctrl</kbd> + <kbd>M</kbd> | Projection mapping 3 |
|
||||
| <kbd>Ctrl</kbd> + <kbd>Shift</kbd> + <kbd>M</kbd> | Projection mapping 4 |
|
||||
|
||||
### Projection Mappings
|
||||
|
||||
In any of the projection mapping mode, use the nanoKONTROL2 last 4 columns to control 4 on-screen points:
|
||||
|
||||
| Midi Control | Function |
|
||||
| ------ | -------- |
|
||||
| Fader N | point N - X position |
|
||||
| Knob N | point N - Y position |
|
||||
| Last column top button | activate projection mapping |
|
||||
| Last column middle button | invert projection mapping |
|
||||
| Last column bottom button | show projection borders |
|
||||
|
||||
## Making your own FORGE project
|
||||
|
||||
You want to embrace the "user" in "user-defined"? It's time to make your own project.
|
||||
@@ -499,7 +522,7 @@ You can check your device real FPS on [V4L2 UCP](https://github.com/HedgeHawk/v4
|
||||
|
||||
### My video feed got strange lines
|
||||
|
||||
You need to decode the [V4L2 YUYV format](https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuyv.html).
|
||||
You may need to decode the [V4L2 YUYV format](https://www.kernel.org/doc/html/v4.8/media/uapi/v4l/pixfmt-yuyv.html).
|
||||
|
||||
The code is available in the default project [default/inc_yuyv.glsl](./default/inc_yuyv.glsl)
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
AC_INIT([forge], [steel-1.1.2], [klemek.dev@proton.me])
|
||||
AC_INIT([forge], [steel-1.2.1], [klemek.dev@proton.me])
|
||||
AM_INIT_AUTOMAKE
|
||||
AC_PROG_CC
|
||||
|
||||
|
||||
@@ -235,10 +235,14 @@ GROUP_1_6_Y=19
|
||||
GROUP_1_6_Z=
|
||||
|
||||
# Same for group 2
|
||||
GROUP_2_ACTIVE_COUNT=3
|
||||
GROUP_2_ACTIVE_COUNT=7
|
||||
GROUP_2_ACTIVE_1=36
|
||||
GROUP_2_ACTIVE_2=68
|
||||
GROUP_2_ACTIVE_3=52
|
||||
GROUP_2_ACTIVE_4=1077
|
||||
GROUP_2_ACTIVE_5=11077
|
||||
GROUP_2_ACTIVE_6=101077
|
||||
GROUP_2_ACTIVE_7=111077
|
||||
GROUP_2_COUNT=7
|
||||
GROUP_2_1_X=37
|
||||
GROUP_2_1_Y=53
|
||||
@@ -269,7 +273,72 @@ GROUP_3_1_Y=58
|
||||
GROUP_3_1_Z=
|
||||
GROUP_3_2_X=0
|
||||
GROUP_3_2_Y=16
|
||||
GROUP_3_2_Z=
|
||||
GROUP_3_2_Z=11089
|
||||
|
||||
# Auto-Random Ignore (ARI) prefixes
|
||||
ARI_COUNT=62
|
||||
ARI_1=GROUP_3_1_Y
|
||||
ARI_2=GROUP_3_2_Z
|
||||
ARI_3=GROUP_2_5_4
|
||||
ARI_4=GROUP_2_5_4
|
||||
ARI_5=GROUP_2_5_4
|
||||
ARI_6=GROUP_2_2_X_4
|
||||
ARI_7=GROUP_2_2_Y_4
|
||||
ARI_8=GROUP_2_2_Z_4
|
||||
ARI_9=GROUP_2_4_X_4
|
||||
ARI_10=GROUP_2_4_Y_4
|
||||
ARI_11=GROUP_2_4_Z_4
|
||||
ARI_12=GROUP_2_6_X_4
|
||||
ARI_13=GROUP_2_6_Y_4
|
||||
ARI_14=GROUP_2_6_Z_4
|
||||
ARI_15=GROUP_2_7_X_4
|
||||
ARI_16=GROUP_2_7_Y_4
|
||||
ARI_17=GROUP_2_7_Z_4
|
||||
ARI_18=GROUP_2_5_5
|
||||
ARI_19=GROUP_2_5_5
|
||||
ARI_20=GROUP_2_5_5
|
||||
ARI_21=GROUP_2_2_X_5
|
||||
ARI_22=GROUP_2_2_Y_5
|
||||
ARI_23=GROUP_2_2_Z_5
|
||||
ARI_24=GROUP_2_4_X_5
|
||||
ARI_25=GROUP_2_4_Y_5
|
||||
ARI_26=GROUP_2_4_Z_5
|
||||
ARI_27=GROUP_2_6_X_5
|
||||
ARI_28=GROUP_2_6_Y_5
|
||||
ARI_29=GROUP_2_6_Z_5
|
||||
ARI_30=GROUP_2_7_X_5
|
||||
ARI_31=GROUP_2_7_Y_5
|
||||
ARI_32=GROUP_2_7_Z_5
|
||||
ARI_33=GROUP_2_5_6
|
||||
ARI_34=GROUP_2_5_6
|
||||
ARI_35=GROUP_2_5_6
|
||||
ARI_36=GROUP_2_2_X_6
|
||||
ARI_37=GROUP_2_2_Y_6
|
||||
ARI_38=GROUP_2_2_Z_6
|
||||
ARI_39=GROUP_2_4_X_6
|
||||
ARI_40=GROUP_2_4_Y_6
|
||||
ARI_41=GROUP_2_4_Z_6
|
||||
ARI_42=GROUP_2_6_X_6
|
||||
ARI_43=GROUP_2_6_Y_6
|
||||
ARI_44=GROUP_2_6_Z_6
|
||||
ARI_45=GROUP_2_7_X_6
|
||||
ARI_46=GROUP_2_7_Y_6
|
||||
ARI_47=GROUP_2_7_Z_6
|
||||
ARI_48=GROUP_2_5_7
|
||||
ARI_49=GROUP_2_5_7
|
||||
ARI_50=GROUP_2_5_7
|
||||
ARI_51=GROUP_2_2_X_7
|
||||
ARI_52=GROUP_2_2_Y_7
|
||||
ARI_53=GROUP_2_2_Z_7
|
||||
ARI_54=GROUP_2_4_X_7
|
||||
ARI_55=GROUP_2_4_Y_7
|
||||
ARI_56=GROUP_2_4_Z_7
|
||||
ARI_57=GROUP_2_6_X_7
|
||||
ARI_58=GROUP_2_6_Y_7
|
||||
ARI_59=GROUP_2_6_Z_7
|
||||
ARI_60=GROUP_2_7_X_7
|
||||
ARI_61=GROUP_2_7_Y_7
|
||||
ARI_62=GROUP_2_7_Z_7
|
||||
|
||||
# =====
|
||||
# OTHER
|
||||
|
||||
+4
-1
@@ -15,9 +15,12 @@ uniform sampler2D iTex1;
|
||||
uniform sampler2D iTex3;
|
||||
uniform int iInputFormat1;
|
||||
uniform vec2 iInputResolution1;
|
||||
uniform vec3 iGroup3_1[2];
|
||||
|
||||
void main() {
|
||||
if (iInputFormat1 == YUYV_FOURCC) {
|
||||
if (iGroup3_1[1].z > 0) {
|
||||
fragColor = texture(iTex1, vUV * vec2(1, -1));
|
||||
} else if (iInputFormat1 == YUYV_FOURCC) {
|
||||
fragColor = yuyvTex(iTex1, vUV, int(iInputResolution1.x));
|
||||
} else {
|
||||
fragColor = texture(iTex0, vUV);
|
||||
|
||||
+4
-1
@@ -15,9 +15,12 @@ uniform sampler2D iTex2;
|
||||
uniform sampler2D iTex4;
|
||||
uniform int iInputFormat2;
|
||||
uniform vec2 iInputResolution2;
|
||||
uniform vec3 iGroup3_1[2];
|
||||
|
||||
void main() {
|
||||
if (iInputFormat2 == YUYV_FOURCC) {
|
||||
if (iGroup3_1[1].z > 0) {
|
||||
fragColor = texture(iTex2, vUV * vec2(1, -1));
|
||||
} else if (iInputFormat2 == YUYV_FOURCC) {
|
||||
fragColor = yuyvTex(iTex2, vUV, int(iInputResolution2.x));
|
||||
} else {
|
||||
fragColor = texture(iTex0, vUV);
|
||||
|
||||
+1
-5
@@ -16,15 +16,11 @@ uniform sampler2D iTex0;
|
||||
uniform int iSeed8;
|
||||
uniform vec3 iGroup2_3[7];
|
||||
uniform vec3 iGroup3_1[2];
|
||||
uniform int iDemo;
|
||||
uniform int iAutoRand;
|
||||
|
||||
void main() {
|
||||
vec4 color = fx_stage(vUV, iTex9, iTex0, iSeed8, iGroup2_3[0], iGroup2_3[1].xy, iGroup2_3[2], iGroup2_3[3].xy, iGroup2_3[4], iGroup2_3[5].xy, iGroup2_3[6]);
|
||||
|
||||
if (iDemo < 1 && iAutoRand < 1) {
|
||||
color = mix(color, vec4(0), iGroup3_1[0].y);
|
||||
}
|
||||
color = mix(color, vec4(0), iGroup3_1[0].y);
|
||||
|
||||
fragColor = color;
|
||||
}
|
||||
|
||||
+102
-1
@@ -6,8 +6,109 @@
|
||||
in vec2 vUV;
|
||||
out vec4 fragColor;
|
||||
|
||||
#include inc_map.glsl
|
||||
|
||||
uniform sampler2D iTex0;
|
||||
uniform vec3 iGroup2_4[7];
|
||||
uniform vec3 iGroup2_5[7];
|
||||
uniform vec3 iGroup2_6[7];
|
||||
uniform vec3 iGroup2_7[7];
|
||||
|
||||
void main() {
|
||||
fragColor = texture(iTex0, vUV);
|
||||
bool visible = (iGroup2_4[4].x + iGroup2_5[4].x + iGroup2_6[4].x + iGroup2_7[4].x) > 0;
|
||||
bool invert = (iGroup2_4[4].y + iGroup2_5[4].y + iGroup2_6[4].y + iGroup2_7[4].y) > 0;
|
||||
float rect = clamp(iGroup2_4[4].z + iGroup2_5[4].z + iGroup2_6[4].z + iGroup2_7[4].z, 0, 1);
|
||||
bool modified = false;
|
||||
|
||||
vec2 uv = mix(vec2(0), vUV, base_mask(vUV));
|
||||
|
||||
if (iGroup2_4[4].x > 0) {
|
||||
vec2 p11 = vec2(iGroup2_4[6].xy);
|
||||
vec2 p12 = vec2(iGroup2_4[1].xy);
|
||||
vec2 p13 = vec2(iGroup2_4[3].xy);
|
||||
vec2 p14 = vec2(iGroup2_4[5].xy);
|
||||
|
||||
p12.x = 1 - p12.x;
|
||||
p13.y = 1 - p13.y;
|
||||
p14.x = 1 - p14.x;
|
||||
p14.y = 1 - p14.y;
|
||||
|
||||
vec2 uv1 = project_4p(vUV, p11, p12, p13, p14);
|
||||
uv1 = mix(vec2(0), uv1, base_mask(uv1));
|
||||
uv = uv1;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (iGroup2_5[4].x > 0) {
|
||||
vec2 p21 = vec2(iGroup2_5[6].xy);
|
||||
vec2 p22 = vec2(iGroup2_5[1].xy);
|
||||
vec2 p23 = vec2(iGroup2_5[3].xy);
|
||||
vec2 p24 = vec2(iGroup2_5[5].xy);
|
||||
|
||||
p22.x = 1 - p22.x;
|
||||
p23.y = 1 - p23.y;
|
||||
p24.x = 1 - p24.x;
|
||||
p24.y = 1 - p24.y;
|
||||
|
||||
vec2 uv2 = project_4p(vUV, p21, p22, p23, p24);
|
||||
uv2 = mix(vec2(0), uv2, base_mask(uv2));
|
||||
if (modified) {
|
||||
uv = mix(uv, uv2, step(0.0001, length(uv2)));
|
||||
} else {
|
||||
uv = uv2;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (iGroup2_6[4].x > 0) {
|
||||
vec2 p31 = vec2(iGroup2_6[6].xy);
|
||||
vec2 p32 = vec2(iGroup2_6[1].xy);
|
||||
vec2 p33 = vec2(iGroup2_6[3].xy);
|
||||
vec2 p34 = vec2(iGroup2_6[5].xy);
|
||||
|
||||
p32.x = 1 - p32.x;
|
||||
p33.y = 1 - p33.y;
|
||||
p34.x = 1 - p34.x;
|
||||
p34.y = 1 - p34.y;
|
||||
|
||||
vec2 uv3 = project_4p(vUV, p31, p32, p33, p34);
|
||||
uv3 = mix(vec2(0), uv3, base_mask(uv3));
|
||||
if (modified) {
|
||||
uv = mix(uv, uv3, step(0.0001, length(uv3)));
|
||||
} else {
|
||||
uv = uv3;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (iGroup2_7[4].x > 0) {
|
||||
vec2 p41 = vec2(iGroup2_7[6].xy);
|
||||
vec2 p42 = vec2(iGroup2_7[1].xy);
|
||||
vec2 p43 = vec2(iGroup2_7[3].xy);
|
||||
vec2 p44 = vec2(iGroup2_7[5].xy);
|
||||
|
||||
p42.x = 1 - p42.x;
|
||||
p43.y = 1 - p43.y;
|
||||
p44.x = 1 - p44.x;
|
||||
p44.y = 1 - p44.y;
|
||||
|
||||
vec2 uv4 = project_4p(vUV, p41, p42, p43, p44);
|
||||
uv4 = mix(vec2(0), uv4, base_mask(uv4));
|
||||
if (modified) {
|
||||
uv = mix(uv, uv4, step(0.0001, length(uv4)));
|
||||
} else {
|
||||
uv = uv4;
|
||||
}
|
||||
modified = true;
|
||||
}
|
||||
|
||||
vec4 color = texture(iTex0, invert ? vUV : uv);
|
||||
|
||||
if (visible) {
|
||||
float mask = step(0.0001, length(uv));
|
||||
color *= mix(mask, 1 - mask, invert ? 1 : 0);
|
||||
color = mix(color, color + mask * vec4(1), rect * (step(uv.x, 0.01) + step(uv.y, 0.01) + step(1 - uv.y, 0.01) + step(1 - uv.x, 0.01)));
|
||||
}
|
||||
|
||||
fragColor = color;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef INC_MAP
|
||||
#define INC_MAP
|
||||
|
||||
vec2 project_4p(vec2 uv, vec2 p1, vec2 p2, vec2 p3, vec2 p4) {
|
||||
float k1 = (p4.y - p3.y) / (p2.y - p3.y);
|
||||
float k2 = (p3.y - p1.y) / (p2.y - p3.y);
|
||||
float a = (p4.x - p3.x + k1 * p3.x - k1 * p2.x) / (p1.x - p3.x - k2 * p3.x + k2 * p2.x);
|
||||
float b = k1 + a * k2;
|
||||
float c = 1 - a - b;
|
||||
// https://math.stackexchange.com/questions/296794/finding-the-transform-matrix-from-4-projected-points-with-javascript/339033#339033
|
||||
mat3 projection_a = mat3(
|
||||
a * p1.x, a * p1.y, a,
|
||||
b * p2.x, b * p2.y, b,
|
||||
c * p3.x, c * p3.y, c
|
||||
);
|
||||
mat3 projection_a_prime = inverse(projection_a);
|
||||
mat3 projection_b = mat3(
|
||||
0, 0, -1,
|
||||
1, 0, 1,
|
||||
0, 1, 1
|
||||
);
|
||||
vec3 tmp = projection_b * projection_a_prime * vec3(uv, 1);
|
||||
return tmp.xy / tmp.z;
|
||||
}
|
||||
|
||||
float base_mask(vec2 uv) {
|
||||
return step(0, uv.x) * step(-1, -uv.x) * step(0, uv.y) * step(-1, -uv.y);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -8,8 +8,8 @@
|
||||
uniform int iDemo;
|
||||
|
||||
uniform sampler2D iTex0;
|
||||
uniform sampler2D iTex5;
|
||||
uniform sampler2D iTex6;
|
||||
uniform sampler2D iTex3;
|
||||
uniform sampler2D iTex4;
|
||||
|
||||
subroutine vec4 src_stage_sub(vec2 vUV, int seed, vec3 b1, vec2 f1, vec3 b2, vec2 f2, vec3 b3, vec2 f3);
|
||||
|
||||
@@ -298,7 +298,7 @@ subroutine ( src_stage_sub ) vec4 src_6(vec2 vUV, int seed, vec3 b1, vec2 f1, ve
|
||||
return src_2(vUV, seed, b1, f1, b2, f2, b3, f3);
|
||||
}
|
||||
|
||||
return src_thru(vUV, iTex5, seed, b1, f1, b2, f2, b3, f3);
|
||||
return src_thru(vUV, iTex3, seed, b1, f1, b2, f2, b3, f3);
|
||||
}
|
||||
|
||||
#include inc_cp437.glsl
|
||||
@@ -462,7 +462,7 @@ subroutine ( src_stage_sub ) vec4 src_11(vec2 vUV, int seed, vec3 b1, vec2 f1, v
|
||||
return src_3(vUV, seed, b1, f1, b2, f2, b3, f3);
|
||||
}
|
||||
|
||||
return src_thru(vUV, iTex6, seed, b1, f1, b2, f2, b3, f3);
|
||||
return src_thru(vUV, iTex4, seed, b1, f1, b2, f2, b3, f3);
|
||||
}
|
||||
|
||||
// SRC 12 : Scales
|
||||
|
||||
+23
-7
@@ -3,11 +3,27 @@
|
||||
|
||||
const int YUYV_FOURCC = 1448695129;
|
||||
|
||||
const mat3x3 yuyv_to_rgb = {{1,1,1},{0,-0.39465,2.03211},{1.13983,-0.5806,0}};
|
||||
// https://en.wikipedia.org/wiki/Y%E2%80%B2UV
|
||||
const mat3x3 yuyv_to_rgb_bt709 = {
|
||||
{
|
||||
1,
|
||||
1,
|
||||
1
|
||||
},
|
||||
{
|
||||
0,
|
||||
-0.21482,
|
||||
2.12798
|
||||
},
|
||||
{
|
||||
1.28033,
|
||||
-0.38059,
|
||||
0
|
||||
}
|
||||
};
|
||||
|
||||
vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
|
||||
float w = base_width - 1;
|
||||
|
||||
int x = int(vUV.x * w);
|
||||
|
||||
int xU = x - x % 2;
|
||||
@@ -17,12 +33,12 @@ vec4 yuyvTex(sampler2D tex, vec2 vUV, int base_width) {
|
||||
vec4 tV = texture(tex, vec2(xV / w, 1 - vUV.y));
|
||||
|
||||
vec3 yuv = vec3(
|
||||
x % 2 == 0 ? tU.x : tV.x,
|
||||
tU.y - 0.5,
|
||||
tV.y - 0.5
|
||||
);
|
||||
x % 2 == 0 ? tU.x : tV.x,
|
||||
tU.y - 0.5,
|
||||
tV.y - 0.5
|
||||
);
|
||||
|
||||
return vec4(yuyv_to_rgb * yuv, 1.0);
|
||||
return vec4(yuyv_to_rgb_bt709 * yuv, 1.0);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+10
-2
@@ -34,6 +34,7 @@ static void print_help(int status_code) {
|
||||
"[-vs=SIZE] "
|
||||
"[-vb=COUNT] "
|
||||
"[-vr / -nvr] "
|
||||
"[-vf=FOURCC] "
|
||||
#endif /* VIDEO_IN */
|
||||
"[-is=SIZE] "
|
||||
"[-ls / -nls] "
|
||||
@@ -65,11 +66,12 @@ static void print_help(int status_code) {
|
||||
" -vi, --video-in path to video capture device (multiple "
|
||||
"allowed)\n"
|
||||
" -vb, --video-buffers number of video buffers to use (default: "
|
||||
"2)\n"
|
||||
"1)\n"
|
||||
" -vs, --video-size video capture desired height (default: "
|
||||
"internal texture height)\n"
|
||||
" -vr, --video-reconnect auto-reconnect video (default)\n"
|
||||
" -nvr, --no-video-reconnect do not auto-reconnect video\n"
|
||||
" -vf, --video-fourcc video codec fourcc (default: YUYV)\n"
|
||||
#endif /* VIDEO_IN */
|
||||
" -is, --internal-size internal texture height (default: 720)\n"
|
||||
" -ls, --load-state load saved state (default)\n"
|
||||
@@ -139,9 +141,10 @@ void args_parse(Parameters *params, int argc, char **argv) {
|
||||
params->auto_random_cycle = 4;
|
||||
#ifdef VIDEO_IN
|
||||
params->video_in.length = 0;
|
||||
params->video_buffers = 2;
|
||||
params->video_buffers = 1;
|
||||
params->video_size = 0;
|
||||
params->video_reconnect = true;
|
||||
strlcpy(params->video_fourcc, "YUYV", 5);
|
||||
#endif /* VIDEO_IN */
|
||||
params->internal_size = 720;
|
||||
params->load_state = true;
|
||||
@@ -243,6 +246,11 @@ void args_parse(Parameters *params, int argc, char **argv) {
|
||||
params->video_reconnect = true;
|
||||
} else if (is_arg(arg, "-nvr") || is_arg(arg, "--no-video-reconnect")) {
|
||||
params->video_reconnect = false;
|
||||
} else if (is_arg(arg, "-vf") || is_arg(arg, "--video-fourcc")) {
|
||||
if (strlen(value) == 0) {
|
||||
invalid_value(arg, value);
|
||||
}
|
||||
strlcpy(params->video_fourcc, value, 5);
|
||||
} else {
|
||||
invalid_arg(arg);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,16 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value) {
|
||||
return ARRAY_NOT_FOUND;
|
||||
}
|
||||
|
||||
bool arr_string_match(StringArray array, const char *needle) {
|
||||
for (unsigned int i = 0; i < array.length; i++) {
|
||||
if (strncmp(array.values[i], needle, strlen(array.values[i])) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index) {
|
||||
if (offsets.length == 0) {
|
||||
return 0;
|
||||
|
||||
@@ -7,4 +7,6 @@ unsigned int arr_uint_index_of(UintArray array, unsigned int value);
|
||||
|
||||
unsigned int arr_uint_remap_index(UintArray offsets, unsigned int *index);
|
||||
|
||||
bool arr_string_match(StringArray array, const char *needle);
|
||||
|
||||
#endif /* ARR_H */
|
||||
|
||||
+8
-2
@@ -85,7 +85,8 @@ static void init_inputs() {
|
||||
|
||||
for (unsigned int i = 0; i < init_params.video_in.length; i++) {
|
||||
video_init(&video_captures.values[i], init_params.video_in.values[i],
|
||||
init_params.video_size, init_params.video_buffers, true);
|
||||
init_params.video_size, init_params.video_buffers,
|
||||
init_params.video_fourcc, true);
|
||||
|
||||
if (!video_captures.values[i].error) {
|
||||
context.input_resolutions[i][0] = video_captures.values[i].width;
|
||||
@@ -125,7 +126,8 @@ background_reconnect_video_captures(__attribute__((unused)) void *args) {
|
||||
if (video_captures.values[i].disconnected) {
|
||||
video_free(&video_captures.values[i]);
|
||||
video_init(&video_captures.values[i], init_params.video_in.values[i],
|
||||
init_params.video_size, init_params.video_buffers, false);
|
||||
init_params.video_size, init_params.video_buffers,
|
||||
init_params.video_fourcc, false);
|
||||
|
||||
if (!video_captures.values[i].error) {
|
||||
context.input_resolutions[i][0] = video_captures.values[i].width;
|
||||
@@ -313,6 +315,10 @@ static bool init(const Parameters *params) {
|
||||
}
|
||||
|
||||
#ifdef VIDEO_IN
|
||||
if (params->output && params->monitor) {
|
||||
window_use(window_output, &context);
|
||||
}
|
||||
|
||||
shaders_link_inputs(&program, &project, &video_captures,
|
||||
init_params.video_buffers);
|
||||
#endif /* VIDEO_IN */
|
||||
|
||||
@@ -245,12 +245,6 @@ static bool link_input_to_texture(ShaderProgram *program, VideoCapture *input,
|
||||
return false;
|
||||
}
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, input->width, input->height, 0, GL_RGB,
|
||||
GL_UNSIGNED_BYTE, 0);
|
||||
if (check_glerror(program, "link_input_to_texture/glTexImage2D")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://registry.khronos.org/OpenGL/extensions/EXT/EXT_EGL_image_storage.txt
|
||||
glEGLImageTargetTexStorageEXT(GL_TEXTURE_2D, dma_image, NULL);
|
||||
if (check_eglerror(program,
|
||||
|
||||
+77
-22
@@ -98,11 +98,15 @@ static void randomize(Context *context, StateConfig state_config) {
|
||||
l = state_config.values_offsets.values[part] +
|
||||
k * state_config.group_counts.values[part] + j;
|
||||
|
||||
if (arr_uint_index_of(state_config.fader_codes,
|
||||
state_config.codes.values[i]) != ARRAY_NOT_FOUND) {
|
||||
context->values[l][i % 3] = (float)rand_uint(MIDI_MAX + 1) / MIDI_MAX;
|
||||
} else {
|
||||
context->values[l][i % 3] = rand_uint(2) == 1 ? 1 : 0;
|
||||
if (arr_uint_index_of(state_config.random_ignored, (l * 3) + (i % 3)) ==
|
||||
ARRAY_NOT_FOUND) {
|
||||
if (arr_uint_index_of(state_config.fader_codes,
|
||||
state_config.codes.values[i]) !=
|
||||
ARRAY_NOT_FOUND) {
|
||||
context->values[l][i % 3] = (float)rand_uint(MIDI_MAX + 1) / MIDI_MAX;
|
||||
} else {
|
||||
context->values[l][i % 3] = rand_uint(2) == 1 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -271,6 +275,8 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
||||
unsigned int offset;
|
||||
unsigned int count;
|
||||
unsigned int length;
|
||||
unsigned int value_offset;
|
||||
StringArray ignored_codes;
|
||||
char name[STR_LEN];
|
||||
|
||||
length = config_file_get_int(config, "SELECT_PAGE_COUNT", 0);
|
||||
@@ -312,6 +318,18 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
||||
config_file_get_int(config, name, UNSET_MIDI_CODE);
|
||||
}
|
||||
|
||||
length = config_file_get_int(config, "ARI_COUNT", 0);
|
||||
if (length > ARRAY_SIZE) {
|
||||
length = ARRAY_SIZE;
|
||||
}
|
||||
ignored_codes.length = length;
|
||||
|
||||
for (unsigned int i = 0; i < ignored_codes.length; i++) {
|
||||
snprintf(name, STR_LEN, "ARI_%d", i + 1);
|
||||
strlcpy(ignored_codes.values[i],
|
||||
config_file_get_str(config, name, "unkown"), STR_LEN);
|
||||
}
|
||||
|
||||
length = config_file_get_int(config, "GROUP_COUNT", 0);
|
||||
if (length > ARRAY_SIZE) {
|
||||
length = ARRAY_SIZE;
|
||||
@@ -361,26 +379,60 @@ void state_parse_config(StateConfig *state_config, const ConfigFile *config) {
|
||||
length = ARRAY_SIZE;
|
||||
}
|
||||
state_config->codes.length = count * 3;
|
||||
state_config->random_ignored.length = 0;
|
||||
|
||||
for (unsigned int i = 0; i < state_config->group_counts.length; i++) {
|
||||
offset = state_config->group_offsets.values[i];
|
||||
value_offset = state_config->values_offsets.values[i];
|
||||
for (unsigned int j = 0; j < state_config->group_counts.values[i]; j++) {
|
||||
if ((offset + j) * 3 < ARRAY_SIZE) {
|
||||
snprintf(name, STR_LEN, "GROUP_%d_%d_X", i + 1, j + 1);
|
||||
state_config->codes.values[(offset + j) * 3] =
|
||||
config_file_get_int(config, name, UNSET_MIDI_CODE);
|
||||
for (unsigned int k = 0;
|
||||
k < state_config->group_active_counts.values[i]; k++) {
|
||||
snprintf(name, STR_LEN, "GROUP_%d_%d_X_%d", i + 1, j + 1, k + 1);
|
||||
if (arr_string_match(ignored_codes, name)) {
|
||||
state_config->random_ignored
|
||||
.values[state_config->random_ignored.length++] =
|
||||
(value_offset + k * state_config->group_counts.values[i] + j) *
|
||||
3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset + j) * 3 + 1 < ARRAY_SIZE) {
|
||||
snprintf(name, STR_LEN, "GROUP_%d_%d_Y", i + 1, j + 1);
|
||||
state_config->codes.values[(offset + j) * 3 + 1] =
|
||||
config_file_get_int(config, name, UNSET_MIDI_CODE);
|
||||
for (unsigned int k = 0;
|
||||
k < state_config->group_active_counts.values[i]; k++) {
|
||||
snprintf(name, STR_LEN, "GROUP_%d_%d_Y_%d", i + 1, j + 1, k + 1);
|
||||
if (arr_string_match(ignored_codes, name)) {
|
||||
state_config->random_ignored
|
||||
.values[state_config->random_ignored.length++] =
|
||||
(value_offset + k * state_config->group_counts.values[i] + j) *
|
||||
3 +
|
||||
1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((offset + j) * 3 + 2 < ARRAY_SIZE) {
|
||||
snprintf(name, STR_LEN, "GROUP_%d_%d_Z", i + 1, j + 1);
|
||||
state_config->codes.values[(offset + j) * 3 + 2] =
|
||||
config_file_get_int(config, name, UNSET_MIDI_CODE);
|
||||
for (unsigned int k = 0;
|
||||
k < state_config->group_active_counts.values[i]; k++) {
|
||||
snprintf(name, STR_LEN, "GROUP_%d_%d_Z_%d", i + 1, j + 1, k + 1);
|
||||
if (arr_string_match(ignored_codes, name)) {
|
||||
state_config->random_ignored
|
||||
.values[state_config->random_ignored.length++] =
|
||||
(value_offset + k * state_config->group_counts.values[i] + j) *
|
||||
3 +
|
||||
2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -477,6 +529,9 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
unsigned int j;
|
||||
unsigned int k;
|
||||
unsigned int part;
|
||||
bool found;
|
||||
|
||||
found = false;
|
||||
|
||||
// PAGE CHANGE
|
||||
i = arr_uint_index_of(state_config.select_page_codes, code);
|
||||
@@ -485,7 +540,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
context->page = i;
|
||||
update_page(context, state_config, midi);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// TARGET CHANGE
|
||||
@@ -495,7 +550,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
context->selected = i;
|
||||
update_page(context, state_config, midi);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// ITEM CHANGE
|
||||
@@ -506,7 +561,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
context->page * state_config.select_item_codes.length + i;
|
||||
update_page(context, state_config, midi);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// ACTIVE CHANGE
|
||||
@@ -518,7 +573,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
update_active(context, state_config, midi, true);
|
||||
update_values(context, state_config, midi);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// VALUE CHANGE
|
||||
@@ -540,7 +595,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
safe_midi_write(midi, code, MIDI_MAX);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// TAP TEMPO
|
||||
@@ -549,7 +604,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
if (value > 0) {
|
||||
tempo_tap(&context->tempo);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// OTHER KEYS
|
||||
@@ -559,7 +614,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
randomize(context, state_config);
|
||||
update_values(context, state_config, midi);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_reset) {
|
||||
@@ -568,7 +623,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
reset(context);
|
||||
update_values(context, state_config, midi);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_demo) {
|
||||
@@ -576,7 +631,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
log_info((context->demo ? "[%d] Demo OFF" : "[%d] Demo ON"), code);
|
||||
context->demo = !context->demo;
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_autorand) {
|
||||
@@ -585,7 +640,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
log_info("[%d] Auto Random %s", code,
|
||||
context->auto_random ? "ON" : "OFF");
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_autorand_down) {
|
||||
@@ -595,7 +650,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
}
|
||||
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_autorand_up) {
|
||||
@@ -603,7 +658,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
context->auto_random_cycle += 1;
|
||||
log_info("[%d] Auto Random Cycle: %d", code, context->auto_random_cycle);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_tempo_up) {
|
||||
@@ -611,7 +666,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
tempo_set(&context->tempo, context->tempo.tempo + 1);
|
||||
log_info("[%d] Tempo: %f", code, context->tempo);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
if (code == state_config.key_tempo_down) {
|
||||
@@ -621,7 +676,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
}
|
||||
log_info("[%d] Tempo: %f", code, context->tempo.tempo);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// LOAD STATE
|
||||
@@ -632,7 +687,7 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
log_info("[%d] Loading state %d", code, i + 1);
|
||||
load_from_index_file(context, state_config, i + 1);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
// SAVE STATE
|
||||
@@ -643,10 +698,10 @@ static bool compute_event(Context *context, StateConfig state_config,
|
||||
log_info("[%d] Saving state %d", code, i + 1);
|
||||
save_to_index_file(context, state_config, i + 1);
|
||||
}
|
||||
return true;
|
||||
found = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return found;
|
||||
}
|
||||
|
||||
void state_midi_event(Context *context, StateConfig state_config,
|
||||
|
||||
+7
-1
@@ -7,7 +7,13 @@
|
||||
#include "config.h"
|
||||
#include "tempo.h"
|
||||
|
||||
static long now_ms() { return 1000 * clock() / CLOCKS_PER_SEC; }
|
||||
static long now_ms() {
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
|
||||
return 0;
|
||||
}
|
||||
return 1000 * ts.tv_sec + ts.tv_nsec / 1e6;
|
||||
}
|
||||
|
||||
static void reset_tap_chain(Tempo *tempo, long t) {
|
||||
tempo->last_reset = t;
|
||||
|
||||
+8
-4
@@ -1,3 +1,4 @@
|
||||
#include <bits/time.h>
|
||||
#include <limits.h>
|
||||
#include <time.h>
|
||||
|
||||
@@ -8,7 +9,7 @@
|
||||
void timer_init(Timer *timer, const unsigned int target) {
|
||||
timer->counter = 0;
|
||||
timer->target = target;
|
||||
timer->start = clock();
|
||||
clock_gettime(CLOCK_REALTIME, &timer->start);
|
||||
}
|
||||
|
||||
bool timer_inc(Timer *timer) {
|
||||
@@ -17,13 +18,16 @@ bool timer_inc(Timer *timer) {
|
||||
}
|
||||
|
||||
double timer_reset(Timer *timer) {
|
||||
clock_t stop;
|
||||
struct timespec stop;
|
||||
double secs;
|
||||
double per_secs;
|
||||
|
||||
stop = clock();
|
||||
if (clock_gettime(CLOCK_REALTIME, &stop) != 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
secs = (double)(stop - timer->start) / CLOCKS_PER_SEC;
|
||||
secs = (double)(stop.tv_sec - timer->start.tv_sec) +
|
||||
(double)(stop.tv_nsec - timer->start.tv_nsec) / 1e9;
|
||||
per_secs = (double)timer->counter / secs;
|
||||
|
||||
timer->start = stop;
|
||||
|
||||
+3
-1
@@ -50,6 +50,7 @@ typedef struct Parameters {
|
||||
unsigned int video_buffers;
|
||||
unsigned int video_size;
|
||||
bool video_reconnect;
|
||||
char video_fourcc[5];
|
||||
#endif /* VIDEO_IN */
|
||||
unsigned int internal_size;
|
||||
bool load_state;
|
||||
@@ -250,6 +251,7 @@ typedef struct StateConfig {
|
||||
UintArray codes;
|
||||
UintArray fader_codes;
|
||||
UintArray values_offsets;
|
||||
UintArray random_ignored;
|
||||
|
||||
unsigned int value_count;
|
||||
|
||||
@@ -279,7 +281,7 @@ typedef struct StateBackgroundWriteArgs {
|
||||
// timer.c
|
||||
|
||||
typedef struct Timer {
|
||||
clock_t start;
|
||||
struct timespec start;
|
||||
unsigned int counter;
|
||||
unsigned int target;
|
||||
} Timer;
|
||||
|
||||
+26
-9
@@ -16,7 +16,6 @@
|
||||
#include "timer.h"
|
||||
#include "video.h"
|
||||
|
||||
static const unsigned int pixel_format = V4L2_PIX_FMT_YUYV;
|
||||
static const enum v4l2_buf_type buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
|
||||
static void ioctl_error(VideoCapture *video_capture, const char *operation,
|
||||
@@ -70,6 +69,19 @@ static void ioctl_error(VideoCapture *video_capture, const char *operation,
|
||||
video_capture->error = true;
|
||||
}
|
||||
|
||||
static void fourcc_to_string(unsigned int fourcc, char *str) {
|
||||
str[0] = (char)(fourcc & 0xFF);
|
||||
str[1] = (char)((fourcc >> 8) & 0xFF);
|
||||
str[2] = (char)((fourcc >> 16) & 0xFF);
|
||||
str[3] = (char)((fourcc >> 24) & 0xFF);
|
||||
str[4] = '\0';
|
||||
}
|
||||
|
||||
static int string_to_fourcc(const char *str) {
|
||||
return (unsigned int)str[0] | ((unsigned int)str[1] << 8) |
|
||||
((unsigned int)str[2] << 16) | ((unsigned int)str[3] << 24);
|
||||
}
|
||||
|
||||
static void open_device(VideoCapture *video_capture, const char *name,
|
||||
bool log_error) {
|
||||
strlcpy(video_capture->name, name, STR_LEN);
|
||||
@@ -112,7 +124,8 @@ static bool check_caps(VideoCapture *video_capture) {
|
||||
}
|
||||
|
||||
static bool get_available_sizes(VideoCapture *video_capture,
|
||||
unsigned int preferred_height) {
|
||||
unsigned int preferred_height,
|
||||
unsigned int pixel_format) {
|
||||
struct v4l2_frmsizeenum fmt_enum;
|
||||
unsigned int index;
|
||||
bool found = false;
|
||||
@@ -165,8 +178,9 @@ static bool get_available_sizes(VideoCapture *video_capture,
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool set_format(VideoCapture *video_capture) {
|
||||
static bool set_format(VideoCapture *video_capture, unsigned int pixel_format) {
|
||||
struct v4l2_format fmt;
|
||||
char fourcc[STR_LEN];
|
||||
|
||||
memset(&fmt, 0, sizeof(fmt));
|
||||
|
||||
@@ -187,9 +201,9 @@ static bool set_format(VideoCapture *video_capture) {
|
||||
video_capture->pixelformat = fmt.fmt.pix.pixelformat;
|
||||
video_capture->bytesperline = fmt.fmt.pix.bytesperline;
|
||||
|
||||
log_info("(%s) Format fourcc: %c%c%c%c", video_capture->name,
|
||||
fmt.fmt.pix.pixelformat, fmt.fmt.pix.pixelformat >> 8,
|
||||
fmt.fmt.pix.pixelformat >> 16, fmt.fmt.pix.pixelformat >> 24);
|
||||
fourcc_to_string(fmt.fmt.pix.pixelformat, fourcc);
|
||||
|
||||
log_info("(%s) Format fourcc: %s", video_capture->name, fourcc);
|
||||
log_info("(%s) Resolution: %dx%d", video_capture->name, fmt.fmt.pix.width,
|
||||
fmt.fmt.pix.height);
|
||||
|
||||
@@ -326,7 +340,7 @@ static unsigned int read_video(VideoCapture *video_capture) {
|
||||
|
||||
void video_init(VideoCapture *video_capture, const char *name,
|
||||
unsigned int preferred_height, unsigned int buffer_count,
|
||||
bool log_error) {
|
||||
const char *video_fourcc, bool log_error) {
|
||||
open_device(video_capture, name, log_error);
|
||||
|
||||
if (video_capture->error) {
|
||||
@@ -339,13 +353,14 @@ void video_init(VideoCapture *video_capture, const char *name,
|
||||
return;
|
||||
}
|
||||
|
||||
if (!get_available_sizes(video_capture, preferred_height)) {
|
||||
if (!get_available_sizes(video_capture, preferred_height,
|
||||
string_to_fourcc(video_fourcc))) {
|
||||
video_capture->error = true;
|
||||
video_free(video_capture);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!set_format(video_capture)) {
|
||||
if (!set_format(video_capture, string_to_fourcc(video_fourcc))) {
|
||||
video_capture->error = true;
|
||||
video_free(video_capture);
|
||||
return;
|
||||
@@ -413,6 +428,8 @@ void *video_background_read(void *args) {
|
||||
video_capture->name);
|
||||
video_capture->disconnected = true;
|
||||
context->input_formats[input_index] = 0;
|
||||
context->input_resolutions[input_index][0] = 0;
|
||||
context->input_resolutions[input_index][1] = 0;
|
||||
}
|
||||
free(process_args);
|
||||
pthread_exit(NULL);
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
|
||||
void video_init(VideoCapture *video_capture, const char *name,
|
||||
unsigned int preferred_height, unsigned int buffer_count,
|
||||
bool log_error);
|
||||
const char *video_fourcc, bool log_error);
|
||||
|
||||
void *video_background_read(void *args);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user