Make clang-format more aggressive

clang-format always manages to mix spaces into tab-based indentation.
Since we already require an exact tab-width of 8 it makes more sense to
use spaces.
This commit is contained in:
Benjamin Schaaf
2021-11-13 00:00:03 +11:00
parent a92104e27c
commit 772db36877
32 changed files with 4155 additions and 3861 deletions

View File

@@ -13,7 +13,7 @@ AccessModifierOffset: -4
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false AlignConsecutiveDeclarations: false
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0 AlignEscapedNewlines: Right
AlignOperands: true AlignOperands: true
AlignTrailingComments: false AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false
@@ -26,8 +26,8 @@ AlwaysBreakAfterDefinitionReturnType: All
AlwaysBreakAfterReturnType: None AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false AlwaysBreakTemplateDeclarations: false
BinPackArguments: true BinPackArguments: false
BinPackParameters: true BinPackParameters: false
BraceWrapping: BraceWrapping:
AfterClass: false AfterClass: false
AfterControlStatement: false AfterControlStatement: false
@@ -37,24 +37,24 @@ BraceWrapping:
AfterObjCDeclaration: false AfterObjCDeclaration: false
AfterStruct: false AfterStruct: false
AfterUnion: false AfterUnion: false
#AfterExternBlock: false # Unknown to clang-format-5.0 AfterExternBlock: false
BeforeCatch: false BeforeCatch: false
BeforeElse: false BeforeElse: false
IndentBraces: false IndentBraces: false
#SplitEmptyFunction: true # Unknown to clang-format-4.0 SplitEmptyFunction: true
#SplitEmptyRecord: true # Unknown to clang-format-4.0 SplitEmptyRecord: true
#SplitEmptyNamespace: true # Unknown to clang-format-4.0 SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom BreakBeforeBraces: Custom
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0 BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false BreakBeforeTernaryOperators: false
BreakConstructorInitializersBeforeComma: false BreakConstructorInitializersBeforeComma: false
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0 BreakConstructorInitializers: BeforeComma
BreakAfterJavaFieldAnnotations: false BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: false BreakStringLiterals: false
ColumnLimit: 85 ColumnLimit: 85
CommentPragmas: '^ IWYU pragma:' CommentPragmas: '^ IWYU pragma:'
#CompactNamespaces: false # Unknown to clang-format-4.0 CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 8 ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8 ContinuationIndentWidth: 8
@@ -62,7 +62,7 @@ Cpp11BracedListStyle: false
DerivePointerAlignment: false DerivePointerAlignment: false
DisableFormat: false DisableFormat: false
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: false
#FixNamespaceComments: false # Unknown to clang-format-4.0 FixNamespaceComments: false
# Taken from: # Taken from:
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \ # git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
@@ -494,13 +494,13 @@ ForEachMacros:
- 'xbc_node_for_each_key_value' - 'xbc_node_for_each_key_value'
- 'zorro_for_each_dev' - 'zorro_for_each_dev'
#IncludeBlocks: Preserve # Unknown to clang-format-5.0 IncludeBlocks: Preserve
IncludeCategories: IncludeCategories:
- Regex: '.*' - Regex: '.*'
Priority: 1 Priority: 1
IncludeIsMainRegex: '(Test)?$' IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: false IndentCaseLabels: false
#IndentPPDirectives: None # Unknown to clang-format-5.0 IndentPPDirectives: None
IndentWidth: 8 IndentWidth: 8
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave JavaScriptQuotes: Leave
@@ -510,31 +510,31 @@ MacroBlockBegin: ''
MacroBlockEnd: '' MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0 ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 8 ObjCBlockIndentWidth: 8
ObjCSpaceAfterProperty: true ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: true ObjCSpaceBeforeProtocolList: true
# Taken from git's rules # Taken from git's rules
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0 #PenaltyBreakAssignment: 10
PenaltyBreakBeforeFirstCallParameter: 30 #PenaltyBreakBeforeFirstCallParameter: 30
PenaltyBreakComment: 10 #PenaltyBreakComment: 10
PenaltyBreakFirstLessLess: 0 #PenaltyBreakFirstLessLess: 0
PenaltyBreakString: 10 #PenaltyBreakString: 10
PenaltyExcessCharacter: 100 #PenaltyExcessCharacter: 100
PenaltyReturnTypeOnItsOwnLine: 60 #PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Right PointerAlignment: Right
ReflowComments: false ReflowComments: true
SortIncludes: false SortIncludes: true
#SortUsingDeclarations: false # Unknown to clang-format-4.0 SortUsingDeclarations: false
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
SpaceAfterTemplateKeyword: true SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true SpaceBeforeAssignmentOperators: true
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0 SpaceBeforeCtorInitializerColon: true
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0 SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements SpaceBeforeParens: ControlStatements
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0 SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1 SpacesBeforeTrailingComments: 1
SpacesInAngles: false SpacesInAngles: false
@@ -544,5 +544,5 @@ SpacesInParentheses: false
SpacesInSquareBrackets: false SpacesInSquareBrackets: false
Standard: Cpp03 Standard: Cpp03
TabWidth: 8 TabWidth: 8
UseTab: Always UseTab: Never
... ...

View File

@@ -1,9 +1,3 @@
.build_template: &build_definition
script:
- meson build
- ninja -C build
- ninja -C build test
build:debian: build:debian:
image: debian:bookworm-slim image: debian:bookworm-slim
before_script: before_script:

View File

@@ -9,5 +9,5 @@ varying vec2 uv;
void void
main() main()
{ {
gl_FragColor = vec4(texture2D(texture, uv).rgb, 1); gl_FragColor = vec4(texture2D(texture, uv).rgb, 1);
} }

View File

@@ -12,7 +12,7 @@ varying vec2 uv;
void void
main() main()
{ {
uv = tex_coord; uv = tex_coord;
gl_Position = vec4(transform * vec3(vert, 1), 1); gl_Position = vec4(transform * vec3(vert, 1), 1);
} }

View File

@@ -13,30 +13,31 @@ varying vec2 bottom_right_uv;
void void
main() main()
{ {
// Note the coordinates for texture samples need to be a varying, as the // Note the coordinates for texture samples need to be a varying, as the
// Mali-400 has this as a fast path allowing 32-bit floats. Otherwise // Mali-400 has this as a fast path allowing 32-bit floats. Otherwise
// they end up as 16-bit floats and that's not accurate enough. // they end up as 16-bit floats and that's not accurate enough.
vec4 samples = vec4(texture2D(texture, top_left_uv).r, vec4 samples = vec4(texture2D(texture, top_left_uv).r,
texture2D(texture, top_right_uv).r, texture2D(texture, top_right_uv).r,
texture2D(texture, bottom_left_uv).r, texture2D(texture, bottom_left_uv).r,
texture2D(texture, bottom_right_uv).r); texture2D(texture, bottom_right_uv).r);
// Assume BGGR for now. Currently this just takes 3 of the four samples // Assume BGGR for now. Currently this just takes 3 of the four samples
// for each pixel, there's room here to do some better debayering. // for each pixel, there's room here to do some better debayering.
vec3 color = vec3(samples.w, (samples.y + samples.z) / 2.0, samples.x); vec3 color = vec3(samples.w, (samples.y + samples.z) / 2.0, samples.x);
// Some crude blacklevel correction to make the preview a bit nicer, this should be an uniform // Some crude blacklevel correction to make the preview a bit nicer, this
vec3 corrected = color - 0.02; // should be an uniform
vec3 corrected = color - 0.02;
// Apply the color matrices // Apply the color matrices
//vec3 corrected = color_matrix * color2; // vec3 corrected = color_matrix * color2;
// Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/ // Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/
vec3 srgb_color = vec3 srgb_color =
(vec3(1.138) * inversesqrt(corrected) - vec3(0.138)) * corrected; (vec3(1.138) * inversesqrt(corrected) - vec3(0.138)) * corrected;
// Slow SRGB estimate // Slow SRGB estimate
// vec3 srgb_color = pow(color, vec3(1.0 / 2.2)); // vec3 srgb_color = pow(color, vec3(1.0 / 2.2));
gl_FragColor = vec4(srgb_color, 1); gl_FragColor = vec4(srgb_color, 1);
} }

View File

@@ -16,10 +16,10 @@ varying vec2 bottom_right_uv;
void void
main() main()
{ {
top_left_uv = tex_coord - pixel_size / 2.0; top_left_uv = tex_coord - pixel_size / 2.0;
bottom_right_uv = tex_coord + pixel_size / 2.0; bottom_right_uv = tex_coord + pixel_size / 2.0;
top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y); top_right_uv = vec2(top_left_uv.x, bottom_right_uv.y);
bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y); bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y);
gl_Position = vec4(transform * vec3(vert, 1), 1); gl_Position = vec4(transform * vec3(vert, 1), 1);
} }

View File

@@ -7,5 +7,5 @@ uniform vec4 color;
void void
main() main()
{ {
gl_FragColor = color; gl_FragColor = color;
} }

View File

@@ -7,5 +7,5 @@ attribute vec2 vert;
void void
main() main()
{ {
gl_Position = vec4(vert, 0, 1); gl_Position = vec4(vert, 0, 1);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +1,24 @@
#pragma once #pragma once
#include <linux/v4l2-subdev.h> #include <linux/v4l2-subdev.h>
#include <sys/wait.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <sys/wait.h>
typedef enum { typedef enum {
MP_PIXEL_FMT_UNSUPPORTED, MP_PIXEL_FMT_UNSUPPORTED,
MP_PIXEL_FMT_BGGR8, MP_PIXEL_FMT_BGGR8,
MP_PIXEL_FMT_GBRG8, MP_PIXEL_FMT_GBRG8,
MP_PIXEL_FMT_GRBG8, MP_PIXEL_FMT_GRBG8,
MP_PIXEL_FMT_RGGB8, MP_PIXEL_FMT_RGGB8,
MP_PIXEL_FMT_BGGR10P, MP_PIXEL_FMT_BGGR10P,
MP_PIXEL_FMT_GBRG10P, MP_PIXEL_FMT_GBRG10P,
MP_PIXEL_FMT_GRBG10P, MP_PIXEL_FMT_GRBG10P,
MP_PIXEL_FMT_RGGB10P, MP_PIXEL_FMT_RGGB10P,
MP_PIXEL_FMT_UYVY, MP_PIXEL_FMT_UYVY,
MP_PIXEL_FMT_YUYV, MP_PIXEL_FMT_YUYV,
MP_PIXEL_FMT_MAX, MP_PIXEL_FMT_MAX,
} MPPixelFormat; } MPPixelFormat;
const char *mp_pixel_format_to_str(MPPixelFormat pixel_format); const char *mp_pixel_format_to_str(MPPixelFormat pixel_format);
@@ -34,23 +34,23 @@ uint32_t mp_pixel_format_pixel_depth(MPPixelFormat pixel_format);
uint32_t mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width); uint32_t mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width);
uint32_t mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width); uint32_t mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width);
uint32_t mp_pixel_format_height_to_colors(MPPixelFormat pixel_format, uint32_t mp_pixel_format_height_to_colors(MPPixelFormat pixel_format,
uint32_t height); uint32_t height);
typedef struct { typedef struct {
MPPixelFormat pixel_format; MPPixelFormat pixel_format;
struct v4l2_fract frame_interval; struct v4l2_fract frame_interval;
uint32_t width; uint32_t width;
uint32_t height; uint32_t height;
} MPCameraMode; } MPCameraMode;
bool mp_camera_mode_is_equivalent(const MPCameraMode *m1, const MPCameraMode *m2); bool mp_camera_mode_is_equivalent(const MPCameraMode *m1, const MPCameraMode *m2);
typedef struct { typedef struct {
uint32_t index; uint32_t index;
uint8_t *data; uint8_t *data;
int fd; int fd;
} MPBuffer; } MPBuffer;
typedef struct _MPCamera MPCamera; typedef struct _MPCamera MPCamera;
@@ -85,21 +85,21 @@ MPCameraModeList *mp_camera_mode_list_next(MPCameraModeList *list);
void mp_camera_mode_list_free(MPCameraModeList *list); void mp_camera_mode_list_free(MPCameraModeList *list);
typedef struct { typedef struct {
uint32_t id; uint32_t id;
uint32_t type; uint32_t type;
char name[32]; char name[32];
int32_t min; int32_t min;
int32_t max; int32_t max;
int32_t step; int32_t step;
int32_t default_value; int32_t default_value;
uint32_t flags; uint32_t flags;
uint32_t element_size; uint32_t element_size;
uint32_t element_count; uint32_t element_count;
uint32_t dimensions_count; uint32_t dimensions_count;
uint32_t dimensions[V4L2_CTRL_MAX_DIMS]; uint32_t dimensions[V4L2_CTRL_MAX_DIMS];
} MPControl; } MPControl;
const char *mp_control_id_to_str(uint32_t id); const char *mp_control_id_to_str(uint32_t id);

View File

@@ -1,14 +1,14 @@
#include "camera_config.h" #include "camera_config.h"
#include "ini.h"
#include "config.h" #include "config.h"
#include "ini.h"
#include "matrix.h" #include "matrix.h"
#include <assert.h>
#include <glib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <glib.h>
#include <assert.h>
static struct mp_camera_config cameras[MP_MAX_CAMERAS]; static struct mp_camera_config cameras[MP_MAX_CAMERAS];
static size_t num_cameras = 0; static size_t num_cameras = 0;
@@ -19,268 +19,284 @@ static char *exif_model;
static bool static bool
find_config(char *conffile) find_config(char *conffile)
{ {
char buf[512]; char buf[512];
FILE *fp; FILE *fp;
if (access("/proc/device-tree/compatible", F_OK) != -1) { if (access("/proc/device-tree/compatible", F_OK) != -1) {
// Reads to compatible string of the current device tree, looks like: // Reads to compatible string of the current device tree, looks like:
// pine64,pinephone-1.2\0allwinner,sun50i-a64\0 // pine64,pinephone-1.2\0allwinner,sun50i-a64\0
fp = fopen("/proc/device-tree/compatible", "r"); fp = fopen("/proc/device-tree/compatible", "r");
fgets(buf, 512, fp); fgets(buf, 512, fp);
fclose(fp); fclose(fp);
// Check config/%dt.ini in the current working directory // Check config/%dt.ini in the current working directory
sprintf(conffile, "config/%s.ini", buf); sprintf(conffile, "config/%s.ini", buf);
if (access(conffile, F_OK) != -1) { if (access(conffile, F_OK) != -1) {
printf("Found config file at %s\n", conffile); printf("Found config file at %s\n", conffile);
return true; return true;
} }
// Check for a config file in XDG_CONFIG_HOME // Check for a config file in XDG_CONFIG_HOME
sprintf(conffile, "%s/megapixels/config/%s.ini", sprintf(conffile,
g_get_user_config_dir(), buf); "%s/megapixels/config/%s.ini",
if (access(conffile, F_OK) != -1) { g_get_user_config_dir(),
printf("Found config file at %s\n", conffile); buf);
return true; if (access(conffile, F_OK) != -1) {
} printf("Found config file at %s\n", conffile);
return true;
}
// Check user overridden /etc/megapixels/config/$dt.ini // Check user overridden /etc/megapixels/config/$dt.ini
sprintf(conffile, "%s/megapixels/config/%s.ini", SYSCONFDIR, buf); sprintf(conffile, "%s/megapixels/config/%s.ini", SYSCONFDIR, buf);
if (access(conffile, F_OK) != -1) { if (access(conffile, F_OK) != -1) {
printf("Found config file at %s\n", conffile); printf("Found config file at %s\n", conffile);
return true; return true;
} }
// Check packaged /usr/share/megapixels/config/$dt.ini // Check packaged /usr/share/megapixels/config/$dt.ini
sprintf(conffile, "%s/megapixels/config/%s.ini", DATADIR, buf); sprintf(conffile, "%s/megapixels/config/%s.ini", DATADIR, buf);
if (access(conffile, F_OK) != -1) { if (access(conffile, F_OK) != -1) {
printf("Found config file at %s\n", conffile); printf("Found config file at %s\n", conffile);
return true; return true;
} }
printf("%s not found\n", conffile); printf("%s not found\n", conffile);
} else { } else {
printf("Could not read device name from device tree\n"); printf("Could not read device name from device tree\n");
} }
// If all else fails, fall back to /etc/megapixels.ini // If all else fails, fall back to /etc/megapixels.ini
sprintf(conffile, "/etc/megapixels.ini"); sprintf(conffile, "/etc/megapixels.ini");
if (access(conffile, F_OK) != -1) { if (access(conffile, F_OK) != -1) {
printf("Found config file at %s\n", conffile); printf("Found config file at %s\n", conffile);
return true; return true;
} }
return false; return false;
} }
static int static int
strtoint(const char *nptr, char **endptr, int base) strtoint(const char *nptr, char **endptr, int base)
{ {
long x = strtol(nptr, endptr, base); long x = strtol(nptr, endptr, base);
assert(x <= INT_MAX); assert(x <= INT_MAX);
return (int)x; return (int)x;
} }
static bool static bool
config_handle_camera_mode(const char *prefix, MPCameraMode *mode, const char *name, config_handle_camera_mode(const char *prefix,
const char *value) MPCameraMode *mode,
const char *name,
const char *value)
{ {
int prefix_length = strlen(prefix); int prefix_length = strlen(prefix);
if (strncmp(prefix, name, prefix_length) != 0) if (strncmp(prefix, name, prefix_length) != 0)
return false; return false;
name += prefix_length; name += prefix_length;
if (strcmp(name, "width") == 0) { if (strcmp(name, "width") == 0) {
mode->width = strtoint(value, NULL, 10); mode->width = strtoint(value, NULL, 10);
} else if (strcmp(name, "height") == 0) { } else if (strcmp(name, "height") == 0) {
mode->height = strtoint(value, NULL, 10); mode->height = strtoint(value, NULL, 10);
} else if (strcmp(name, "rate") == 0) { } else if (strcmp(name, "rate") == 0) {
mode->frame_interval.numerator = 1; mode->frame_interval.numerator = 1;
mode->frame_interval.denominator = strtoint(value, NULL, 10); mode->frame_interval.denominator = strtoint(value, NULL, 10);
} else if (strcmp(name, "fmt") == 0) { } else if (strcmp(name, "fmt") == 0) {
mode->pixel_format = mp_pixel_format_from_str(value); mode->pixel_format = mp_pixel_format_from_str(value);
if (mode->pixel_format == MP_PIXEL_FMT_UNSUPPORTED) { if (mode->pixel_format == MP_PIXEL_FMT_UNSUPPORTED) {
g_printerr("Unsupported pixelformat %s\n", value); g_printerr("Unsupported pixelformat %s\n", value);
exit(1); exit(1);
} }
} else { } else {
return false; return false;
} }
return true; return true;
} }
static int static int
config_ini_handler(void *user, const char *section, const char *name, config_ini_handler(void *user,
const char *value) const char *section,
const char *name,
const char *value)
{ {
if (strcmp(section, "device") == 0) { if (strcmp(section, "device") == 0) {
if (strcmp(name, "make") == 0) { if (strcmp(name, "make") == 0) {
exif_make = strdup(value); exif_make = strdup(value);
} else if (strcmp(name, "model") == 0) { } else if (strcmp(name, "model") == 0) {
exif_model = strdup(value); exif_model = strdup(value);
} else { } else {
g_printerr("Unknown key '%s' in [device]\n", name); g_printerr("Unknown key '%s' in [device]\n", name);
exit(1); exit(1);
} }
} else { } else {
if (num_cameras == MP_MAX_CAMERAS) { if (num_cameras == MP_MAX_CAMERAS) {
g_printerr("More cameras defined than NUM_CAMERAS\n"); g_printerr("More cameras defined than NUM_CAMERAS\n");
exit(1); exit(1);
} }
size_t index = 0; size_t index = 0;
for (; index < num_cameras; ++index) { for (; index < num_cameras; ++index) {
if (strcmp(cameras[index].cfg_name, section) == 0) { if (strcmp(cameras[index].cfg_name, section) == 0) {
break; break;
} }
} }
if (index == num_cameras) { if (index == num_cameras) {
printf("Adding camera %s from config\n", section); printf("Adding camera %s from config\n", section);
++num_cameras; ++num_cameras;
cameras[index].index = index; cameras[index].index = index;
strcpy(cameras[index].cfg_name, section); strcpy(cameras[index].cfg_name, section);
} }
struct mp_camera_config *cc = &cameras[index]; struct mp_camera_config *cc = &cameras[index];
if (config_handle_camera_mode("capture-", &cc->capture_mode, name, if (config_handle_camera_mode(
value)) { "capture-", &cc->capture_mode, name, value)) {
} else if (config_handle_camera_mode("preview-", &cc->preview_mode, } else if (config_handle_camera_mode(
name, value)) { "preview-", &cc->preview_mode, name, value)) {
} else if (strcmp(name, "rotate") == 0) { } else if (strcmp(name, "rotate") == 0) {
cc->rotate = strtoint(value, NULL, 10); cc->rotate = strtoint(value, NULL, 10);
} else if (strcmp(name, "mirrored") == 0) { } else if (strcmp(name, "mirrored") == 0) {
cc->mirrored = strcmp(value, "true") == 0; cc->mirrored = strcmp(value, "true") == 0;
} else if (strcmp(name, "driver") == 0) { } else if (strcmp(name, "driver") == 0) {
strcpy(cc->dev_name, value); strcpy(cc->dev_name, value);
} else if (strcmp(name, "media-driver") == 0) { } else if (strcmp(name, "media-driver") == 0) {
strcpy(cc->media_dev_name, value); strcpy(cc->media_dev_name, value);
} else if (strcmp(name, "media-links") == 0) { } else if (strcmp(name, "media-links") == 0) {
char **linkdefs = g_strsplit(value, ",", 0); char **linkdefs = g_strsplit(value, ",", 0);
for (int i = 0; i < MP_MAX_LINKS && linkdefs[i] != NULL; for (int i = 0; i < MP_MAX_LINKS && linkdefs[i] != NULL;
++i) { ++i) {
char **linkdef = g_strsplit(linkdefs[i], "->", 2); char **linkdef = g_strsplit(linkdefs[i], "->", 2);
char **porta = g_strsplit(linkdef[0], ":", 2); char **porta = g_strsplit(linkdef[0], ":", 2);
char **portb = g_strsplit(linkdef[1], ":", 2); char **portb = g_strsplit(linkdef[1], ":", 2);
strcpy(cc->media_links[i].source_name, porta[0]); strcpy(cc->media_links[i].source_name, porta[0]);
strcpy(cc->media_links[i].target_name, portb[0]); strcpy(cc->media_links[i].target_name, portb[0]);
cc->media_links[i].source_port = cc->media_links[i].source_port =
strtoint(porta[1], NULL, 10); strtoint(porta[1], NULL, 10);
cc->media_links[i].target_port = cc->media_links[i].target_port =
strtoint(portb[1], NULL, 10); strtoint(portb[1], NULL, 10);
g_strfreev(portb); g_strfreev(portb);
g_strfreev(porta); g_strfreev(porta);
g_strfreev(linkdef); g_strfreev(linkdef);
++cc->num_media_links; ++cc->num_media_links;
} }
g_strfreev(linkdefs); g_strfreev(linkdefs);
} else if (strcmp(name, "colormatrix") == 0) { } else if (strcmp(name, "colormatrix") == 0) {
sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f", sscanf(value,
cc->colormatrix + 0, cc->colormatrix + 1, "%f,%f,%f,%f,%f,%f,%f,%f,%f",
cc->colormatrix + 2, cc->colormatrix + 3, cc->colormatrix + 0,
cc->colormatrix + 4, cc->colormatrix + 5, cc->colormatrix + 1,
cc->colormatrix + 6, cc->colormatrix + 7, cc->colormatrix + 2,
cc->colormatrix + 8); cc->colormatrix + 3,
} else if (strcmp(name, "forwardmatrix") == 0) { cc->colormatrix + 4,
sscanf(value, "%f,%f,%f,%f,%f,%f,%f,%f,%f", cc->colormatrix + 5,
cc->forwardmatrix + 0, cc->forwardmatrix + 1, cc->colormatrix + 6,
cc->forwardmatrix + 2, cc->forwardmatrix + 3, cc->colormatrix + 7,
cc->forwardmatrix + 4, cc->forwardmatrix + 5, cc->colormatrix + 8);
cc->forwardmatrix + 6, cc->forwardmatrix + 7, } else if (strcmp(name, "forwardmatrix") == 0) {
cc->forwardmatrix + 8); sscanf(value,
} else if (strcmp(name, "whitelevel") == 0) { "%f,%f,%f,%f,%f,%f,%f,%f,%f",
cc->whitelevel = strtoint(value, NULL, 10); cc->forwardmatrix + 0,
} else if (strcmp(name, "blacklevel") == 0) { cc->forwardmatrix + 1,
cc->blacklevel = strtoint(value, NULL, 10); cc->forwardmatrix + 2,
} else if (strcmp(name, "focallength") == 0) { cc->forwardmatrix + 3,
cc->focallength = strtof(value, NULL); cc->forwardmatrix + 4,
} else if (strcmp(name, "cropfactor") == 0) { cc->forwardmatrix + 5,
cc->cropfactor = strtof(value, NULL); cc->forwardmatrix + 6,
} else if (strcmp(name, "fnumber") == 0) { cc->forwardmatrix + 7,
cc->fnumber = strtod(value, NULL); cc->forwardmatrix + 8);
} else if (strcmp(name, "iso-min") == 0) { } else if (strcmp(name, "whitelevel") == 0) {
cc->iso_min = strtod(value, NULL); cc->whitelevel = strtoint(value, NULL, 10);
} else if (strcmp(name, "iso-max") == 0) { } else if (strcmp(name, "blacklevel") == 0) {
cc->iso_max = strtod(value, NULL); cc->blacklevel = strtoint(value, NULL, 10);
} else if (strcmp(name, "flash-path") == 0) { } else if (strcmp(name, "focallength") == 0) {
strcpy(cc->flash_path, value); cc->focallength = strtof(value, NULL);
cc->has_flash = true; } else if (strcmp(name, "cropfactor") == 0) {
} else if (strcmp(name, "flash-display") == 0) { cc->cropfactor = strtof(value, NULL);
cc->flash_display = strcmp(value, "true") == 0; } else if (strcmp(name, "fnumber") == 0) {
cc->fnumber = strtod(value, NULL);
} else if (strcmp(name, "iso-min") == 0) {
cc->iso_min = strtod(value, NULL);
} else if (strcmp(name, "iso-max") == 0) {
cc->iso_max = strtod(value, NULL);
} else if (strcmp(name, "flash-path") == 0) {
strcpy(cc->flash_path, value);
cc->has_flash = true;
} else if (strcmp(name, "flash-display") == 0) {
cc->flash_display = strcmp(value, "true") == 0;
if (cc->flash_display) { if (cc->flash_display) {
cc->has_flash = true; cc->has_flash = true;
} }
} else { } else {
g_printerr("Unknown key '%s' in [%s]\n", name, section); g_printerr("Unknown key '%s' in [%s]\n", name, section);
exit(1); exit(1);
} }
} }
return 1; return 1;
} }
void void
calculate_matrices() calculate_matrices()
{ {
for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) { for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) {
if (cameras[i].colormatrix != NULL && if (cameras[i].colormatrix != NULL &&
cameras[i].forwardmatrix != NULL) { cameras[i].forwardmatrix != NULL) {
multiply_matrices(cameras[i].colormatrix, multiply_matrices(cameras[i].colormatrix,
cameras[i].forwardmatrix, cameras[i].forwardmatrix,
cameras[i].previewmatrix); cameras[i].previewmatrix);
} }
} }
} }
bool bool
mp_load_config() mp_load_config()
{ {
char file[512]; char file[512];
if (!find_config(file)) { if (!find_config(file)) {
g_printerr("Could not find any config file\n"); g_printerr("Could not find any config file\n");
return false; return false;
} }
int result = ini_parse(file, config_ini_handler, NULL); int result = ini_parse(file, config_ini_handler, NULL);
if (result == -1) { if (result == -1) {
g_printerr("Config file not found\n"); g_printerr("Config file not found\n");
return false; return false;
} }
if (result == -2) { if (result == -2) {
g_printerr("Could not allocate memory to parse config file\n"); g_printerr("Could not allocate memory to parse config file\n");
return false; return false;
} }
if (result != 0) { if (result != 0) {
g_printerr("Could not parse config file\n"); g_printerr("Could not parse config file\n");
return false; return false;
} }
calculate_matrices(); calculate_matrices();
return true; return true;
} }
const char * const char *
mp_get_device_make() mp_get_device_make()
{ {
return exif_make; return exif_make;
} }
const char * const char *
mp_get_device_model() mp_get_device_model()
{ {
return exif_model; return exif_model;
} }
const struct mp_camera_config * const struct mp_camera_config *
mp_get_camera_config(size_t index) mp_get_camera_config(size_t index)
{ {
if (index >= num_cameras) if (index >= num_cameras)
return NULL; return NULL;
return &cameras[index]; return &cameras[index];
} }

View File

@@ -9,42 +9,42 @@
#define MP_MAX_LINKS 10 #define MP_MAX_LINKS 10
struct mp_media_link_config { struct mp_media_link_config {
char source_name[100]; char source_name[100];
char target_name[100]; char target_name[100];
int source_port; int source_port;
int target_port; int target_port;
}; };
struct mp_camera_config { struct mp_camera_config {
size_t index; size_t index;
char cfg_name[100]; char cfg_name[100];
char dev_name[260]; char dev_name[260];
char media_dev_name[260]; char media_dev_name[260];
MPCameraMode capture_mode; MPCameraMode capture_mode;
MPCameraMode preview_mode; MPCameraMode preview_mode;
int rotate; int rotate;
bool mirrored; bool mirrored;
struct mp_media_link_config media_links[MP_MAX_LINKS]; struct mp_media_link_config media_links[MP_MAX_LINKS];
int num_media_links; int num_media_links;
float colormatrix[9]; float colormatrix[9];
float forwardmatrix[9]; float forwardmatrix[9];
float previewmatrix[9]; float previewmatrix[9];
int blacklevel; int blacklevel;
int whitelevel; int whitelevel;
float focallength; float focallength;
float cropfactor; float cropfactor;
double fnumber; double fnumber;
int iso_min; int iso_min;
int iso_max; int iso_max;
char flash_path[260]; char flash_path[260];
bool flash_display; bool flash_display;
bool has_flash; bool has_flash;
}; };
bool mp_load_config(); bool mp_load_config();

View File

@@ -11,453 +11,458 @@
bool bool
mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length) mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length)
{ {
char uevent_path[256]; char uevent_path[256];
snprintf(uevent_path, 256, "/sys/dev/char/%d:%d/uevent", devnode.major, snprintf(uevent_path,
devnode.minor); 256,
"/sys/dev/char/%d:%d/uevent",
devnode.major,
devnode.minor);
FILE *f = fopen(uevent_path, "r"); FILE *f = fopen(uevent_path, "r");
if (!f) { if (!f) {
return false; return false;
} }
char line[512]; char line[512];
while (fgets(line, 512, f)) { while (fgets(line, 512, f)) {
if (strncmp(line, "DEVNAME=", 8) == 0) { if (strncmp(line, "DEVNAME=", 8) == 0) {
// Drop newline // Drop newline
int length = strlen(line); int length = strlen(line);
if (line[length - 1] == '\n') if (line[length - 1] == '\n')
line[length - 1] = '\0'; line[length - 1] = '\0';
snprintf(path, length, "/dev/%s", line + 8); snprintf(path, length, "/dev/%s", line + 8);
return true; return true;
} }
} }
fclose(f); fclose(f);
return false; return false;
} }
struct _MPDevice { struct _MPDevice {
int fd; int fd;
struct media_device_info info; struct media_device_info info;
struct media_v2_entity *entities; struct media_v2_entity *entities;
size_t num_entities; size_t num_entities;
struct media_v2_interface *interfaces; struct media_v2_interface *interfaces;
size_t num_interfaces; size_t num_interfaces;
struct media_v2_pad *pads; struct media_v2_pad *pads;
size_t num_pads; size_t num_pads;
struct media_v2_link *links; struct media_v2_link *links;
size_t num_links; size_t num_links;
}; };
static void static void
errno_printerr(const char *s) errno_printerr(const char *s)
{ {
g_printerr("MPDevice: %s error %d, %s\n", s, errno, strerror(errno)); g_printerr("MPDevice: %s error %d, %s\n", s, errno, strerror(errno));
} }
static int static int
xioctl(int fd, int request, void *arg) xioctl(int fd, int request, void *arg)
{ {
int r; int r;
do { do {
r = ioctl(fd, request, arg); r = ioctl(fd, request, arg);
} while (r == -1 && errno == EINTR); } while (r == -1 && errno == EINTR);
return r; return r;
} }
MPDevice * MPDevice *
mp_device_find(const char *driver_name) mp_device_find(const char *driver_name)
{ {
MPDeviceList *list = mp_device_list_new(); MPDeviceList *list = mp_device_list_new();
MPDevice *found_device = mp_device_list_find_remove(&list, driver_name); MPDevice *found_device = mp_device_list_find_remove(&list, driver_name);
mp_device_list_free(list); mp_device_list_free(list);
return found_device; return found_device;
} }
MPDevice * MPDevice *
mp_device_open(const char *path) mp_device_open(const char *path)
{ {
int fd = open(path, O_RDWR); int fd = open(path, O_RDWR);
if (fd == -1) { if (fd == -1) {
errno_printerr("open"); errno_printerr("open");
return NULL; return NULL;
} }
return mp_device_new(fd); return mp_device_new(fd);
} }
MPDevice * MPDevice *
mp_device_new(int fd) mp_device_new(int fd)
{ {
// Get the topology of the media device // Get the topology of the media device
struct media_v2_topology topology = {}; struct media_v2_topology topology = {};
if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1 || if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1 ||
topology.num_entities == 0) { topology.num_entities == 0) {
close(fd); close(fd);
return NULL; return NULL;
} }
// Create the device // Create the device
MPDevice *device = calloc(1, sizeof(MPDevice)); MPDevice *device = calloc(1, sizeof(MPDevice));
device->fd = fd; device->fd = fd;
device->entities = device->entities =
calloc(topology.num_entities, sizeof(struct media_v2_entity)); calloc(topology.num_entities, sizeof(struct media_v2_entity));
device->num_entities = topology.num_entities; device->num_entities = topology.num_entities;
device->interfaces = device->interfaces =
calloc(topology.num_interfaces, sizeof(struct media_v2_interface)); calloc(topology.num_interfaces, sizeof(struct media_v2_interface));
device->num_interfaces = topology.num_interfaces; device->num_interfaces = topology.num_interfaces;
device->pads = calloc(topology.num_pads, sizeof(struct media_v2_pad)); device->pads = calloc(topology.num_pads, sizeof(struct media_v2_pad));
device->num_pads = topology.num_pads; device->num_pads = topology.num_pads;
device->links = calloc(topology.num_links, sizeof(struct media_v2_link)); device->links = calloc(topology.num_links, sizeof(struct media_v2_link));
device->num_links = topology.num_links; device->num_links = topology.num_links;
// Get the actual devices and interfaces // Get the actual devices and interfaces
topology.ptr_entities = (uint64_t)device->entities; topology.ptr_entities = (uint64_t)device->entities;
topology.ptr_interfaces = (uint64_t)device->interfaces; topology.ptr_interfaces = (uint64_t)device->interfaces;
topology.ptr_pads = (uint64_t)device->pads; topology.ptr_pads = (uint64_t)device->pads;
topology.ptr_links = (uint64_t)device->links; topology.ptr_links = (uint64_t)device->links;
if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1) { if (xioctl(fd, MEDIA_IOC_G_TOPOLOGY, &topology) == -1) {
errno_printerr("MEDIA_IOC_G_TOPOLOGY"); errno_printerr("MEDIA_IOC_G_TOPOLOGY");
mp_device_close(device); mp_device_close(device);
return NULL; return NULL;
} }
// Get device info // Get device info
if (xioctl(fd, MEDIA_IOC_DEVICE_INFO, &device->info) == -1) { if (xioctl(fd, MEDIA_IOC_DEVICE_INFO, &device->info) == -1) {
errno_printerr("MEDIA_IOC_DEVICE_INFO"); errno_printerr("MEDIA_IOC_DEVICE_INFO");
mp_device_close(device); mp_device_close(device);
return NULL; return NULL;
} }
return device; return device;
} }
void void
mp_device_close(MPDevice *device) mp_device_close(MPDevice *device)
{ {
close(device->fd); close(device->fd);
free(device->entities); free(device->entities);
free(device->interfaces); free(device->interfaces);
free(device->pads); free(device->pads);
free(device->links); free(device->links);
free(device); free(device);
} }
bool bool
mp_device_setup_link(MPDevice *device, uint32_t source_pad_id, uint32_t sink_pad_id, mp_device_setup_link(MPDevice *device,
bool enabled) uint32_t source_pad_id,
uint32_t sink_pad_id,
bool enabled)
{ {
const struct media_v2_pad *source_pad = const struct media_v2_pad *source_pad =
mp_device_get_pad(device, source_pad_id); mp_device_get_pad(device, source_pad_id);
g_return_val_if_fail(source_pad, false); g_return_val_if_fail(source_pad, false);
const struct media_v2_pad *sink_pad = mp_device_get_pad(device, sink_pad_id); const struct media_v2_pad *sink_pad = mp_device_get_pad(device, sink_pad_id);
g_return_val_if_fail(sink_pad, false); g_return_val_if_fail(sink_pad, false);
struct media_link_desc link = {}; struct media_link_desc link = {};
link.flags = enabled ? MEDIA_LNK_FL_ENABLED : 0; link.flags = enabled ? MEDIA_LNK_FL_ENABLED : 0;
link.source.entity = source_pad->entity_id; link.source.entity = source_pad->entity_id;
link.source.index = 0; link.source.index = 0;
link.sink.entity = sink_pad->entity_id; link.sink.entity = sink_pad->entity_id;
link.sink.index = 0; link.sink.index = 0;
if (xioctl(device->fd, MEDIA_IOC_SETUP_LINK, &link) == -1) { if (xioctl(device->fd, MEDIA_IOC_SETUP_LINK, &link) == -1) {
errno_printerr("MEDIA_IOC_SETUP_LINK"); errno_printerr("MEDIA_IOC_SETUP_LINK");
return false; return false;
} }
return true; return true;
} }
const struct media_v2_entity * const struct media_v2_entity *
mp_device_find_entity(const MPDevice *device, const char *driver_name) mp_device_find_entity(const MPDevice *device, const char *driver_name)
{ {
int length = strlen(driver_name); int length = strlen(driver_name);
// Find the entity from the name // Find the entity from the name
for (uint32_t i = 0; i < device->num_entities; ++i) { for (uint32_t i = 0; i < device->num_entities; ++i) {
if (strncmp(device->entities[i].name, driver_name, length) == 0) { if (strncmp(device->entities[i].name, driver_name, length) == 0) {
return &device->entities[i]; return &device->entities[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_entity * const struct media_v2_entity *
mp_device_find_entity_type(const MPDevice *device, const uint32_t type) mp_device_find_entity_type(const MPDevice *device, const uint32_t type)
{ {
// Find the entity from the entity type // Find the entity from the entity type
for (uint32_t i = 0; i < device->num_entities; ++i) { for (uint32_t i = 0; i < device->num_entities; ++i) {
if (device->entities[i].function == type) { if (device->entities[i].function == type) {
return &device->entities[i]; return &device->entities[i];
} }
} }
return NULL; return NULL;
} }
const struct media_device_info * const struct media_device_info *
mp_device_get_info(const MPDevice *device) mp_device_get_info(const MPDevice *device)
{ {
return &device->info; return &device->info;
} }
const struct media_v2_entity * const struct media_v2_entity *
mp_device_get_entity(const MPDevice *device, uint32_t id) mp_device_get_entity(const MPDevice *device, uint32_t id)
{ {
for (int i = 0; i < device->num_entities; ++i) { for (int i = 0; i < device->num_entities; ++i) {
if (device->entities[i].id == id) { if (device->entities[i].id == id) {
return &device->entities[i]; return &device->entities[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_entity * const struct media_v2_entity *
mp_device_get_entities(const MPDevice *device) mp_device_get_entities(const MPDevice *device)
{ {
return device->entities; return device->entities;
} }
size_t size_t
mp_device_get_num_entities(const MPDevice *device) mp_device_get_num_entities(const MPDevice *device)
{ {
return device->num_entities; return device->num_entities;
} }
const struct media_v2_interface * const struct media_v2_interface *
mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id) mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id)
{ {
// Find the interface through the link // Find the interface through the link
const struct media_v2_link *link = mp_device_find_link_to(device, entity_id); const struct media_v2_link *link = mp_device_find_link_to(device, entity_id);
if (!link) { if (!link) {
return NULL; return NULL;
} }
return mp_device_get_interface(device, link->source_id); return mp_device_get_interface(device, link->source_id);
} }
const struct media_v2_interface * const struct media_v2_interface *
mp_device_get_interface(const MPDevice *device, uint32_t id) mp_device_get_interface(const MPDevice *device, uint32_t id)
{ {
for (int i = 0; i < device->num_interfaces; ++i) { for (int i = 0; i < device->num_interfaces; ++i) {
if (device->interfaces[i].id == id) { if (device->interfaces[i].id == id) {
return &device->interfaces[i]; return &device->interfaces[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_interface * const struct media_v2_interface *
mp_device_get_interfaces(const MPDevice *device) mp_device_get_interfaces(const MPDevice *device)
{ {
return device->interfaces; return device->interfaces;
} }
size_t size_t
mp_device_get_num_interfaces(const MPDevice *device) mp_device_get_num_interfaces(const MPDevice *device)
{ {
return device->num_interfaces; return device->num_interfaces;
} }
const struct media_v2_pad * const struct media_v2_pad *
mp_device_get_pad_from_entity(const MPDevice *device, uint32_t entity_id) mp_device_get_pad_from_entity(const MPDevice *device, uint32_t entity_id)
{ {
for (int i = 0; i < device->num_pads; ++i) { for (int i = 0; i < device->num_pads; ++i) {
if (device->pads[i].entity_id == entity_id) { if (device->pads[i].entity_id == entity_id) {
return &device->pads[i]; return &device->pads[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_pad * const struct media_v2_pad *
mp_device_get_pad(const MPDevice *device, uint32_t id) mp_device_get_pad(const MPDevice *device, uint32_t id)
{ {
for (int i = 0; i < device->num_pads; ++i) { for (int i = 0; i < device->num_pads; ++i) {
if (device->pads[i].id == id) { if (device->pads[i].id == id) {
return &device->pads[i]; return &device->pads[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_pad * const struct media_v2_pad *
mp_device_get_pads(const MPDevice *device) mp_device_get_pads(const MPDevice *device)
{ {
return device->pads; return device->pads;
} }
size_t size_t
mp_device_get_num_pads(const MPDevice *device) mp_device_get_num_pads(const MPDevice *device)
{ {
return device->num_pads; return device->num_pads;
} }
const struct media_v2_link * const struct media_v2_link *
mp_device_find_entity_link(const MPDevice *device, uint32_t entity_id) mp_device_find_entity_link(const MPDevice *device, uint32_t entity_id)
{ {
const struct media_v2_pad *pad = const struct media_v2_pad *pad =
mp_device_get_pad_from_entity(device, entity_id); mp_device_get_pad_from_entity(device, entity_id);
const struct media_v2_link *link = mp_device_find_link_to(device, pad->id); const struct media_v2_link *link = mp_device_find_link_to(device, pad->id);
if (link) { if (link) {
return link; return link;
} }
return mp_device_find_link_from(device, pad->id); return mp_device_find_link_from(device, pad->id);
} }
const struct media_v2_link * const struct media_v2_link *
mp_device_find_link_from(const MPDevice *device, uint32_t source) mp_device_find_link_from(const MPDevice *device, uint32_t source)
{ {
for (int i = 0; i < device->num_links; ++i) { for (int i = 0; i < device->num_links; ++i) {
if (device->links[i].source_id == source) { if (device->links[i].source_id == source) {
return &device->links[i]; return &device->links[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_link * const struct media_v2_link *
mp_device_find_link_to(const MPDevice *device, uint32_t sink) mp_device_find_link_to(const MPDevice *device, uint32_t sink)
{ {
for (int i = 0; i < device->num_links; ++i) { for (int i = 0; i < device->num_links; ++i) {
if (device->links[i].sink_id == sink) { if (device->links[i].sink_id == sink) {
return &device->links[i]; return &device->links[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_link * const struct media_v2_link *
mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink) mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink)
{ {
for (int i = 0; i < device->num_links; ++i) { for (int i = 0; i < device->num_links; ++i) {
if (device->links[i].source_id == source && if (device->links[i].source_id == source &&
device->links[i].sink_id == sink) { device->links[i].sink_id == sink) {
return &device->links[i]; return &device->links[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_link * const struct media_v2_link *
mp_device_get_link(const MPDevice *device, uint32_t id) mp_device_get_link(const MPDevice *device, uint32_t id)
{ {
for (int i = 0; i < device->num_links; ++i) { for (int i = 0; i < device->num_links; ++i) {
if (device->links[i].id == id) { if (device->links[i].id == id) {
return &device->links[i]; return &device->links[i];
} }
} }
return NULL; return NULL;
} }
const struct media_v2_link * const struct media_v2_link *
mp_device_get_links(const MPDevice *device) mp_device_get_links(const MPDevice *device)
{ {
return device->links; return device->links;
} }
size_t size_t
mp_device_get_num_links(const MPDevice *device) mp_device_get_num_links(const MPDevice *device)
{ {
return device->num_links; return device->num_links;
} }
struct _MPDeviceList { struct _MPDeviceList {
MPDevice *device; MPDevice *device;
MPDeviceList *next; MPDeviceList *next;
}; };
MPDeviceList * MPDeviceList *
mp_device_list_new() mp_device_list_new()
{ {
MPDeviceList *current = NULL; MPDeviceList *current = NULL;
// Enumerate media device files // Enumerate media device files
struct dirent *dir; struct dirent *dir;
DIR *d = opendir("/dev"); DIR *d = opendir("/dev");
while ((dir = readdir(d)) != NULL) { while ((dir = readdir(d)) != NULL) {
if (strncmp(dir->d_name, "media", 5) == 0) { if (strncmp(dir->d_name, "media", 5) == 0) {
char path[261]; char path[261];
snprintf(path, 261, "/dev/%s", dir->d_name); snprintf(path, 261, "/dev/%s", dir->d_name);
MPDevice *device = mp_device_open(path); MPDevice *device = mp_device_open(path);
if (device) { if (device) {
MPDeviceList *next = malloc(sizeof(MPDeviceList)); MPDeviceList *next = malloc(sizeof(MPDeviceList));
next->device = device; next->device = device;
next->next = current; next->next = current;
current = next; current = next;
} }
} }
} }
closedir(d); closedir(d);
return current; return current;
} }
void void
mp_device_list_free(MPDeviceList *device_list) mp_device_list_free(MPDeviceList *device_list)
{ {
while (device_list) { while (device_list) {
MPDeviceList *tmp = device_list; MPDeviceList *tmp = device_list;
device_list = tmp->next; device_list = tmp->next;
mp_device_close(tmp->device); mp_device_close(tmp->device);
free(tmp); free(tmp);
} }
} }
MPDevice * MPDevice *
mp_device_list_find_remove(MPDeviceList **list, const char *driver_name) mp_device_list_find_remove(MPDeviceList **list, const char *driver_name)
{ {
MPDevice *found_device = NULL; MPDevice *found_device = NULL;
int length = strlen(driver_name); int length = strlen(driver_name);
while (*list) { while (*list) {
MPDevice *device = mp_device_list_get(*list); MPDevice *device = mp_device_list_get(*list);
const struct media_device_info *info = mp_device_get_info(device); const struct media_device_info *info = mp_device_get_info(device);
if (strncmp(info->driver, driver_name, length) == 0) { if (strncmp(info->driver, driver_name, length) == 0) {
found_device = mp_device_list_remove(list); found_device = mp_device_list_remove(list);
break; break;
} }
list = &(*list)->next; list = &(*list)->next;
} }
return found_device; return found_device;
} }
MPDevice * MPDevice *
mp_device_list_remove(MPDeviceList **device_list) mp_device_list_remove(MPDeviceList **device_list)
{ {
MPDevice *device = (*device_list)->device; MPDevice *device = (*device_list)->device;
if ((*device_list)->next) { if ((*device_list)->next) {
MPDeviceList *tmp = (*device_list)->next; MPDeviceList *tmp = (*device_list)->next;
**device_list = *tmp; **device_list = *tmp;
free(tmp); free(tmp);
} else { } else {
free(*device_list); free(*device_list);
*device_list = NULL; *device_list = NULL;
} }
return device; return device;
} }
MPDevice * MPDevice *
mp_device_list_get(const MPDeviceList *device_list) mp_device_list_get(const MPDeviceList *device_list)
{ {
return device_list->device; return device_list->device;
} }
MPDeviceList * MPDeviceList *
mp_device_list_next(const MPDeviceList *device_list) mp_device_list_next(const MPDeviceList *device_list)
{ {
return device_list->next; return device_list->next;
} }

View File

@@ -5,8 +5,8 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
bool mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, bool
int length); mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length);
typedef struct _MPDevice MPDevice; typedef struct _MPDevice MPDevice;
@@ -15,35 +15,37 @@ MPDevice *mp_device_open(const char *path);
MPDevice *mp_device_new(int fd); MPDevice *mp_device_new(int fd);
void mp_device_close(MPDevice *device); void mp_device_close(MPDevice *device);
bool mp_device_setup_link(MPDevice *device, uint32_t source_pad_id, bool mp_device_setup_link(MPDevice *device,
uint32_t sink_pad_id, bool enabled); uint32_t source_pad_id,
uint32_t sink_pad_id,
bool enabled);
const struct media_device_info *mp_device_get_info(const MPDevice *device); const struct media_device_info *mp_device_get_info(const MPDevice *device);
const struct media_v2_entity *mp_device_find_entity(const MPDevice *device, const struct media_v2_entity *mp_device_find_entity(const MPDevice *device,
const char *driver_name); const char *driver_name);
const struct media_v2_entity *mp_device_find_entity_type(const MPDevice *device, const struct media_v2_entity *mp_device_find_entity_type(const MPDevice *device,
const uint32_t type); const uint32_t type);
const struct media_v2_entity *mp_device_get_entity(const MPDevice *device, const struct media_v2_entity *mp_device_get_entity(const MPDevice *device,
uint32_t id); uint32_t id);
const struct media_v2_entity *mp_device_get_entities(const MPDevice *device); const struct media_v2_entity *mp_device_get_entities(const MPDevice *device);
size_t mp_device_get_num_entities(const MPDevice *device); size_t mp_device_get_num_entities(const MPDevice *device);
const struct media_v2_interface * const struct media_v2_interface *
mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id); mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id);
const struct media_v2_interface *mp_device_get_interface(const MPDevice *device, const struct media_v2_interface *mp_device_get_interface(const MPDevice *device,
uint32_t id); uint32_t id);
const struct media_v2_interface *mp_device_get_interfaces(const MPDevice *device); const struct media_v2_interface *mp_device_get_interfaces(const MPDevice *device);
size_t mp_device_get_num_interfaces(const MPDevice *device); size_t mp_device_get_num_interfaces(const MPDevice *device);
const struct media_v2_pad *mp_device_get_pad_from_entity(const MPDevice *device, const struct media_v2_pad *mp_device_get_pad_from_entity(const MPDevice *device,
uint32_t entity_id); uint32_t entity_id);
const struct media_v2_pad *mp_device_get_pad(const MPDevice *device, uint32_t id); const struct media_v2_pad *mp_device_get_pad(const MPDevice *device, uint32_t id);
const struct media_v2_pad *mp_device_get_pads(const MPDevice *device); const struct media_v2_pad *mp_device_get_pads(const MPDevice *device);
size_t mp_device_get_num_pads(const MPDevice *device); size_t mp_device_get_num_pads(const MPDevice *device);
const struct media_v2_link *mp_device_find_entity_link(const MPDevice *device, const struct media_v2_link *mp_device_find_entity_link(const MPDevice *device,
uint32_t entity_id); uint32_t entity_id);
const struct media_v2_link *mp_device_find_link_from(const MPDevice *device, const struct media_v2_link *mp_device_find_link_from(const MPDevice *device,
uint32_t source); uint32_t source);
const struct media_v2_link *mp_device_find_link_to(const MPDevice *device, const struct media_v2_link *mp_device_find_link_to(const MPDevice *device,
uint32_t sink); uint32_t sink);
const struct media_v2_link * const struct media_v2_link *
mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink); mp_device_find_link_between(const MPDevice *device, uint32_t source, uint32_t sink);
const struct media_v2_link *mp_device_get_link(const MPDevice *device, uint32_t id); const struct media_v2_link *mp_device_get_link(const MPDevice *device, uint32_t id);
@@ -56,7 +58,7 @@ MPDeviceList *mp_device_list_new();
void mp_device_list_free(MPDeviceList *device_list); void mp_device_list_free(MPDeviceList *device_list);
MPDevice *mp_device_list_find_remove(MPDeviceList **device_list, MPDevice *mp_device_list_find_remove(MPDeviceList **device_list,
const char *driver_name); const char *driver_name);
MPDevice *mp_device_list_remove(MPDeviceList **device_list); MPDevice *mp_device_list_remove(MPDeviceList **device_list);
MPDevice *mp_device_list_get(const MPDeviceList *device_list); MPDevice *mp_device_list_get(const MPDeviceList *device_list);

View File

@@ -1,51 +1,51 @@
#include "flash.h" #include "flash.h"
#include "gtk/gtk.h" #include "gtk/gtk.h"
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdio.h>
#include <unistd.h>
typedef enum { typedef enum {
FLASH_TYPE_LED, FLASH_TYPE_LED,
FLASH_TYPE_DISPLAY, FLASH_TYPE_DISPLAY,
} FlashType; } FlashType;
typedef struct { typedef struct {
char path[260]; char path[260];
int fd; int fd;
} MPLEDFlash; } MPLEDFlash;
typedef struct { typedef struct {
} MPDisplayFlash; } MPDisplayFlash;
struct _MPFlash { struct _MPFlash {
FlashType type; FlashType type;
union { union {
MPLEDFlash led; MPLEDFlash led;
MPDisplayFlash display; MPDisplayFlash display;
}; };
}; };
MPFlash * MPFlash *
mp_led_flash_from_path(const char *path) mp_led_flash_from_path(const char *path)
{ {
MPFlash *flash = malloc(sizeof(MPFlash)); MPFlash *flash = malloc(sizeof(MPFlash));
flash->type = FLASH_TYPE_LED; flash->type = FLASH_TYPE_LED;
strncpy(flash->led.path, path, 259); strncpy(flash->led.path, path, 259);
char mpath[275]; char mpath[275];
snprintf(mpath, 275, "%s/flash_strobe", path); snprintf(mpath, 275, "%s/flash_strobe", path);
flash->led.fd = open(mpath, O_WRONLY); flash->led.fd = open(mpath, O_WRONLY);
if (flash->led.fd == -1) { if (flash->led.fd == -1) {
g_printerr("Failed to open %s\n", mpath); g_printerr("Failed to open %s\n", mpath);
free(flash); free(flash);
return NULL; return NULL;
} }
return flash; return flash;
} }
static GtkWidget *flash_window = NULL; static GtkWidget *flash_window = NULL;
@@ -55,160 +55,174 @@ static int dbus_old_brightness = 0;
static void static void
dbus_brightness_init(GObject *src, GAsyncResult *res, gpointer *user_data) dbus_brightness_init(GObject *src, GAsyncResult *res, gpointer *user_data)
{ {
GError *err = NULL; GError *err = NULL;
dbus_brightness_proxy = g_dbus_proxy_new_finish(res, &err); dbus_brightness_proxy = g_dbus_proxy_new_finish(res, &err);
if (!dbus_brightness_proxy || err) { if (!dbus_brightness_proxy || err) {
printf("Failed to connect to dbus brightness service %s\n", printf("Failed to connect to dbus brightness service %s\n",
err->message); err->message);
g_object_unref(err); g_object_unref(err);
return; return;
} }
} }
void void
mp_flash_gtk_init(GDBusConnection *conn) mp_flash_gtk_init(GDBusConnection *conn)
{ {
g_dbus_proxy_new(conn, G_DBUS_PROXY_FLAGS_NONE, NULL, g_dbus_proxy_new(conn,
"org.gnome.SettingsDaemon.Power", G_DBUS_PROXY_FLAGS_NONE,
"/org/gnome/SettingsDaemon/Power", NULL,
"org.gnome.SettingsDaemon.Power.Screen", NULL, "org.gnome.SettingsDaemon.Power",
(GAsyncReadyCallback)dbus_brightness_init, NULL); "/org/gnome/SettingsDaemon/Power",
"org.gnome.SettingsDaemon.Power.Screen",
NULL,
(GAsyncReadyCallback)dbus_brightness_init,
NULL);
// Create a full screen full white window as a flash // Create a full screen full white window as a flash
GtkWidget *window = gtk_window_new(); GtkWidget *window = gtk_window_new();
// gtk_window_set_accept_focus(GTK_WINDOW(flash->display.window), FALSE); // gtk_window_set_accept_focus(GTK_WINDOW(flash->display.window), FALSE);
gtk_window_set_decorated(GTK_WINDOW(window), FALSE); gtk_window_set_decorated(GTK_WINDOW(window), FALSE);
gtk_window_fullscreen(GTK_WINDOW(window)); gtk_window_fullscreen(GTK_WINDOW(window));
GtkStyleContext *context; GtkStyleContext *context;
context = gtk_widget_get_style_context(window); context = gtk_widget_get_style_context(window);
gtk_style_context_add_class(context, "flash"); gtk_style_context_add_class(context, "flash");
flash_window = window; flash_window = window;
} }
void void
mp_flash_gtk_clean() mp_flash_gtk_clean()
{ {
gtk_window_destroy(GTK_WINDOW(flash_window)); gtk_window_destroy(GTK_WINDOW(flash_window));
g_object_unref(dbus_brightness_proxy); g_object_unref(dbus_brightness_proxy);
} }
MPFlash * MPFlash *
mp_create_display_flash() mp_create_display_flash()
{ {
MPFlash *flash = malloc(sizeof(MPFlash)); MPFlash *flash = malloc(sizeof(MPFlash));
flash->type = FLASH_TYPE_DISPLAY; flash->type = FLASH_TYPE_DISPLAY;
return flash; return flash;
} }
void void
mp_flash_free(MPFlash *flash) mp_flash_free(MPFlash *flash)
{ {
switch (flash->type) { switch (flash->type) {
case FLASH_TYPE_LED: case FLASH_TYPE_LED:
close(flash->led.fd); close(flash->led.fd);
break; break;
case FLASH_TYPE_DISPLAY: case FLASH_TYPE_DISPLAY:
break; break;
} }
free(flash); free(flash);
} }
static void static void
set_display_brightness(int brightness) set_display_brightness(int brightness)
{ {
g_dbus_proxy_call( g_dbus_proxy_call(dbus_brightness_proxy,
dbus_brightness_proxy, "org.freedesktop.DBus.Properties.Set", "org.freedesktop.DBus.Properties.Set",
g_variant_new("(ssv)", "org.gnome.SettingsDaemon.Power.Screen", g_variant_new("(ssv)",
"Brightness", g_variant_new("i", brightness)), "org.gnome.SettingsDaemon.Power.Screen",
G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL); "Brightness",
g_variant_new("i", brightness)),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
NULL,
NULL);
} }
static void static void
brightness_received(GDBusProxy *proxy, GAsyncResult *res, gpointer user_data) brightness_received(GDBusProxy *proxy, GAsyncResult *res, gpointer user_data)
{ {
GError *error = NULL; GError *error = NULL;
GVariant *result = g_dbus_proxy_call_finish(proxy, res, &error); GVariant *result = g_dbus_proxy_call_finish(proxy, res, &error);
if (!result) { if (!result) {
printf("Failed to get display brightness: %s\n", error->message); printf("Failed to get display brightness: %s\n", error->message);
g_object_unref(error); g_object_unref(error);
return; return;
} }
GVariant *values = g_variant_get_child_value(result, 0); GVariant *values = g_variant_get_child_value(result, 0);
if (g_variant_n_children(values) == 0) { if (g_variant_n_children(values) == 0) {
return; return;
} }
GVariant *brightness = g_variant_get_child_value(values, 0); GVariant *brightness = g_variant_get_child_value(values, 0);
dbus_old_brightness = g_variant_get_int32(brightness); dbus_old_brightness = g_variant_get_int32(brightness);
g_variant_unref(result); g_variant_unref(result);
} }
static bool static bool
show_display_flash(MPFlash *flash) show_display_flash(MPFlash *flash)
{ {
if (!flash_window) if (!flash_window)
return false; return false;
gtk_widget_show(flash_window); gtk_widget_show(flash_window);
// First get brightness and then set brightness to 100% // First get brightness and then set brightness to 100%
if (!dbus_brightness_proxy) if (!dbus_brightness_proxy)
return false; return false;
g_dbus_proxy_call( g_dbus_proxy_call(dbus_brightness_proxy,
dbus_brightness_proxy, "org.freedesktop.DBus.Properties.Get", "org.freedesktop.DBus.Properties.Get",
g_variant_new("(ss)", "org.gnome.SettingsDaemon.Power.Screen", g_variant_new("(ss)",
"Brightness"), "org.gnome.SettingsDaemon.Power.Screen",
G_DBUS_CALL_FLAGS_NONE, -1, NULL, "Brightness"),
(GAsyncReadyCallback)brightness_received, NULL); G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
(GAsyncReadyCallback)brightness_received,
NULL);
set_display_brightness(100); set_display_brightness(100);
return false; return false;
} }
void void
mp_flash_enable(MPFlash *flash) mp_flash_enable(MPFlash *flash)
{ {
switch (flash->type) { switch (flash->type) {
case FLASH_TYPE_LED: case FLASH_TYPE_LED:
lseek(flash->led.fd, 0, SEEK_SET); lseek(flash->led.fd, 0, SEEK_SET);
dprintf(flash->led.fd, "1\n"); dprintf(flash->led.fd, "1\n");
break; break;
case FLASH_TYPE_DISPLAY: case FLASH_TYPE_DISPLAY:
g_main_context_invoke(NULL, (GSourceFunc)show_display_flash, flash); g_main_context_invoke(NULL, (GSourceFunc)show_display_flash, flash);
break; break;
} }
} }
static bool static bool
hide_display_flash(MPFlash *flash) hide_display_flash(MPFlash *flash)
{ {
if (!flash_window) if (!flash_window)
return false; return false;
gtk_widget_hide(flash_window); gtk_widget_hide(flash_window);
set_display_brightness(dbus_old_brightness); set_display_brightness(dbus_old_brightness);
return false; return false;
} }
void void
mp_flash_disable(MPFlash *flash) mp_flash_disable(MPFlash *flash)
{ {
switch (flash->type) { switch (flash->type) {
case FLASH_TYPE_LED: case FLASH_TYPE_LED:
// Flash gets reset automatically // Flash gets reset automatically
break; break;
case FLASH_TYPE_DISPLAY: case FLASH_TYPE_DISPLAY:
g_main_context_invoke(NULL, (GSourceFunc)hide_display_flash, flash); g_main_context_invoke(NULL, (GSourceFunc)hide_display_flash, flash);
break; break;
} }
} }

View File

@@ -1,240 +1,256 @@
#include "gl_util.h" #include "gl_util.h"
#include <assert.h>
#include <gdk/gdk.h>
#include <gio/gio.h>
#include <gmodule.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h>
#include <gio/gio.h>
#include <gmodule.h>
#include <gdk/gdk.h>
void void
gl_util_check_error(const char *file, int line) gl_util_check_error(const char *file, int line)
{ {
GLenum error = glGetError(); GLenum error = glGetError();
const char *name; const char *name;
switch (error) { switch (error) {
case GL_NO_ERROR: case GL_NO_ERROR:
return; // no error return; // no error
case GL_INVALID_ENUM: case GL_INVALID_ENUM:
name = "GL_INVALID_ENUM"; name = "GL_INVALID_ENUM";
break; break;
case GL_INVALID_VALUE: case GL_INVALID_VALUE:
name = "GL_INVALID_VALUE"; name = "GL_INVALID_VALUE";
break; break;
case GL_INVALID_OPERATION: case GL_INVALID_OPERATION:
name = "GL_INVALID_OPERATION"; name = "GL_INVALID_OPERATION";
break; break;
case GL_INVALID_FRAMEBUFFER_OPERATION: case GL_INVALID_FRAMEBUFFER_OPERATION:
name = "GL_INVALID_FRAMEBUFFER_OPERATION"; name = "GL_INVALID_FRAMEBUFFER_OPERATION";
break; break;
case GL_OUT_OF_MEMORY: case GL_OUT_OF_MEMORY:
name = "GL_OUT_OF_MEMORY"; name = "GL_OUT_OF_MEMORY";
break; break;
default: default:
name = "UNKNOWN ERROR!"; name = "UNKNOWN ERROR!";
break; break;
} }
printf("GL error at %s:%d - %s\n", file, line, name); printf("GL error at %s:%d - %s\n", file, line, name);
// raise(SIGTRAP); // raise(SIGTRAP);
} }
GLuint GLuint
gl_util_load_shader(const char *resource, GLenum type, const char **extra_sources, gl_util_load_shader(const char *resource,
size_t num_extra) GLenum type,
const char **extra_sources,
size_t num_extra)
{ {
GdkGLContext *context = gdk_gl_context_get_current(); GdkGLContext *context = gdk_gl_context_get_current();
assert(context); assert(context);
GLuint shader = glCreateShader(type); GLuint shader = glCreateShader(type);
if (shader == 0) { if (shader == 0) {
return 0; return 0;
} }
GBytes *bytes = g_resources_lookup_data(resource, 0, NULL); GBytes *bytes = g_resources_lookup_data(resource, 0, NULL);
if (!bytes) { if (!bytes) {
printf("Failed to load shader resource %s\n", resource); printf("Failed to load shader resource %s\n", resource);
return 0; return 0;
} }
// Build #define for OpenGL context information // Build #define for OpenGL context information
gboolean is_es = gdk_gl_context_get_use_es(context); gboolean is_es = gdk_gl_context_get_use_es(context);
int major, minor; int major, minor;
gdk_gl_context_get_version(context, &major, &minor); gdk_gl_context_get_version(context, &major, &minor);
char context_info_buf[128]; char context_info_buf[128];
snprintf(context_info_buf, 128, snprintf(context_info_buf,
"#define %s\n#define GL_%d\n#define GL_%d_%d\n", 128,
is_es ? "GL_ES" : "GL_NO_ES", major, major, minor); "#define %s\n#define GL_%d\n#define GL_%d_%d\n",
is_es ? "GL_ES" : "GL_NO_ES",
major,
major,
minor);
gsize glib_size = 0; gsize glib_size = 0;
const GLchar *source = g_bytes_get_data(bytes, &glib_size); const GLchar *source = g_bytes_get_data(bytes, &glib_size);
if (glib_size == 0 || glib_size > INT_MAX) { if (glib_size == 0 || glib_size > INT_MAX) {
printf("Invalid size for resource\n"); printf("Invalid size for resource\n");
return 0; return 0;
} }
const GLchar **sources = malloc((num_extra + 1) * sizeof(GLchar *)); const GLchar **sources = malloc((num_extra + 1) * sizeof(GLchar *));
GLint *sizes = malloc((num_extra + 1) * sizeof(GLint)); GLint *sizes = malloc((num_extra + 1) * sizeof(GLint));
for (size_t i = 0; i < num_extra; ++i) { for (size_t i = 0; i < num_extra; ++i) {
sources[i] = extra_sources[i]; sources[i] = extra_sources[i];
sizes[i] = -1; sizes[i] = -1;
} }
sources[num_extra] = source; sources[num_extra] = source;
sizes[num_extra] = glib_size; sizes[num_extra] = glib_size;
glShaderSource(shader, num_extra + 1, sources, sizes); glShaderSource(shader, num_extra + 1, sources, sizes);
glCompileShader(shader); glCompileShader(shader);
check_gl(); check_gl();
free(sources); free(sources);
free(sizes); free(sizes);
g_bytes_unref(bytes); g_bytes_unref(bytes);
// Check compile status // Check compile status
GLint success; GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success); glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (success == GL_FALSE) { if (success == GL_FALSE) {
printf("Shader compilation failed for %s\n", resource); printf("Shader compilation failed for %s\n", resource);
glDeleteShader(shader); glDeleteShader(shader);
return 0; return 0;
} }
GLint log_length; GLint log_length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length); glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) { if (log_length > 0) {
char *log = malloc(sizeof(char) * log_length); char *log = malloc(sizeof(char) * log_length);
glGetShaderInfoLog(shader, log_length - 1, &log_length, log); glGetShaderInfoLog(shader, log_length - 1, &log_length, log);
printf("Shader %s log: %s\n", resource, log); printf("Shader %s log: %s\n", resource, log);
free(log); free(log);
glDeleteShader(shader); glDeleteShader(shader);
return 0; return 0;
} }
return shader; return shader;
} }
GLuint GLuint
gl_util_link_program(GLuint *shaders, size_t num_shaders) gl_util_link_program(GLuint *shaders, size_t num_shaders)
{ {
GLuint program = glCreateProgram(); GLuint program = glCreateProgram();
for (size_t i = 0; i < num_shaders; ++i) { for (size_t i = 0; i < num_shaders; ++i) {
glAttachShader(program, shaders[i]); glAttachShader(program, shaders[i]);
} }
glLinkProgram(program); glLinkProgram(program);
check_gl(); check_gl();
GLint success; GLint success;
glGetProgramiv(program, GL_LINK_STATUS, &success); glGetProgramiv(program, GL_LINK_STATUS, &success);
if (success == GL_FALSE) { if (success == GL_FALSE) {
printf("Program linking failed\n"); printf("Program linking failed\n");
} }
GLint log_length; GLint log_length;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length); glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_length);
if (log_length > 0) { if (log_length > 0) {
char *log = malloc(sizeof(char) * log_length); char *log = malloc(sizeof(char) * log_length);
glGetProgramInfoLog(program, log_length - 1, &log_length, log); glGetProgramInfoLog(program, log_length - 1, &log_length, log);
printf("Program log: %s\n", log); printf("Program log: %s\n", log);
free(log); free(log);
} }
check_gl(); check_gl();
return program; return program;
} }
static const GLfloat quad_data[] = { static const GLfloat quad_data[] = {
// Vertices // Vertices
-1, -1,
-1, -1,
1, 1,
-1, -1,
-1, -1,
1, 1,
1, 1,
1, 1,
// Texcoords // Texcoords
0, 0,
0, 0,
1, 1,
0, 0,
0, 0,
1, 1,
1, 1,
1, 1,
}; };
GLuint GLuint
gl_util_new_quad() gl_util_new_quad()
{ {
GdkGLContext *context = gdk_gl_context_get_current(); GdkGLContext *context = gdk_gl_context_get_current();
assert(context); assert(context);
if (gdk_gl_context_get_use_es(context)) { if (gdk_gl_context_get_use_es(context)) {
return 0; return 0;
} else { } else {
GLuint buffer; GLuint buffer;
glGenBuffers(1, &buffer); glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer); glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, glBufferData(GL_ARRAY_BUFFER,
GL_STATIC_DRAW); sizeof(quad_data),
check_gl(); quad_data,
GL_STATIC_DRAW);
check_gl();
glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ARRAY_BUFFER, 0);
check_gl(); check_gl();
return buffer; return buffer;
} }
} }
void void
gl_util_bind_quad(GLuint buffer) gl_util_bind_quad(GLuint buffer)
{ {
GdkGLContext *context = gdk_gl_context_get_current(); GdkGLContext *context = gdk_gl_context_get_current();
assert(context); assert(context);
if (gdk_gl_context_get_use_es(context)) { if (gdk_gl_context_get_use_es(context)) {
glVertexAttribPointer(GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, glVertexAttribPointer(
quad_data); GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, 0, 0, quad_data);
check_gl(); check_gl();
glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE); glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE);
check_gl(); check_gl();
glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, 0, 0, glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE,
quad_data + 8); 2,
check_gl(); GL_FLOAT,
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE); 0,
check_gl(); 0,
} else { quad_data + 8);
glBindBuffer(GL_ARRAY_BUFFER, buffer); check_gl();
check_gl(); glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE);
check_gl();
} else {
glBindBuffer(GL_ARRAY_BUFFER, buffer);
check_gl();
glVertexAttribPointer(GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, glVertexAttribPointer(
GL_FALSE, 0, 0); GL_UTIL_VERTEX_ATTRIBUTE, 2, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE); glEnableVertexAttribArray(GL_UTIL_VERTEX_ATTRIBUTE);
check_gl(); check_gl();
glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE, 2, GL_FLOAT, glVertexAttribPointer(GL_UTIL_TEX_COORD_ATTRIBUTE,
GL_FALSE, 0, (void *)(8 * sizeof(float))); 2,
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE); GL_FLOAT,
check_gl(); GL_FALSE,
} 0,
(void *)(8 * sizeof(float)));
glEnableVertexAttribArray(GL_UTIL_TEX_COORD_ATTRIBUTE);
check_gl();
}
} }
void void
gl_util_draw_quad(GLuint buffer) gl_util_draw_quad(GLuint buffer)
{ {
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
check_gl(); check_gl();
} }

View File

@@ -9,8 +9,10 @@
#define check_gl() gl_util_check_error(__FILE__, __LINE__) #define check_gl() gl_util_check_error(__FILE__, __LINE__)
void gl_util_check_error(const char *file, int line); void gl_util_check_error(const char *file, int line);
GLuint gl_util_load_shader(const char *resource, GLenum type, GLuint gl_util_load_shader(const char *resource,
const char **extra_sources, size_t num_extra); GLenum type,
const char **extra_sources,
size_t num_extra);
GLuint gl_util_link_program(GLuint *shaders, size_t num_shaders); GLuint gl_util_link_program(GLuint *shaders, size_t num_shaders);
GLuint gl_util_new_quad(); GLuint gl_util_new_quad();

View File

@@ -8,142 +8,150 @@
#define TEX_COORD_ATTRIBUTE 1 #define TEX_COORD_ATTRIBUTE 1
struct _GLES2Debayer { struct _GLES2Debayer {
GLuint frame_buffer; GLuint frame_buffer;
GLuint program; GLuint program;
GLuint uniform_transform; GLuint uniform_transform;
GLuint uniform_pixel_size; GLuint uniform_pixel_size;
GLuint uniform_texture; GLuint uniform_texture;
GLuint uniform_color_matrix; GLuint uniform_color_matrix;
GLuint quad; GLuint quad;
}; };
GLES2Debayer * GLES2Debayer *
gles2_debayer_new(MPPixelFormat format) gles2_debayer_new(MPPixelFormat format)
{ {
if (format != MP_PIXEL_FMT_BGGR8) { if (format != MP_PIXEL_FMT_BGGR8) {
return NULL; return NULL;
} }
GLuint frame_buffer; GLuint frame_buffer;
glGenFramebuffers(1, &frame_buffer); glGenFramebuffers(1, &frame_buffer);
check_gl(); check_gl();
GLuint shaders[] = { GLuint shaders[] = {
gl_util_load_shader("/org/postmarketos/Megapixels/debayer.vert", gl_util_load_shader("/org/postmarketos/Megapixels/debayer.vert",
GL_VERTEX_SHADER, NULL, 0), GL_VERTEX_SHADER,
gl_util_load_shader("/org/postmarketos/Megapixels/debayer.frag", NULL,
GL_FRAGMENT_SHADER, NULL, 0), 0),
}; gl_util_load_shader("/org/postmarketos/Megapixels/debayer.frag",
GL_FRAGMENT_SHADER,
NULL,
0),
};
GLuint program = gl_util_link_program(shaders, 2); GLuint program = gl_util_link_program(shaders, 2);
glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert"); glBindAttribLocation(program, VERTEX_ATTRIBUTE, "vert");
glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord"); glBindAttribLocation(program, TEX_COORD_ATTRIBUTE, "tex_coord");
check_gl(); check_gl();
GLES2Debayer *self = malloc(sizeof(GLES2Debayer)); GLES2Debayer *self = malloc(sizeof(GLES2Debayer));
self->frame_buffer = frame_buffer; self->frame_buffer = frame_buffer;
self->program = program; self->program = program;
self->uniform_transform = glGetUniformLocation(self->program, "transform"); self->uniform_transform = glGetUniformLocation(self->program, "transform");
self->uniform_pixel_size = glGetUniformLocation(self->program, "pixel_size"); self->uniform_pixel_size = glGetUniformLocation(self->program, "pixel_size");
self->uniform_texture = glGetUniformLocation(self->program, "texture"); self->uniform_texture = glGetUniformLocation(self->program, "texture");
self->uniform_color_matrix = self->uniform_color_matrix =
glGetUniformLocation(self->program, "color_matrix"); glGetUniformLocation(self->program, "color_matrix");
check_gl(); check_gl();
self->quad = gl_util_new_quad(); self->quad = gl_util_new_quad();
return self; return self;
} }
void void
gles2_debayer_free(GLES2Debayer *self) gles2_debayer_free(GLES2Debayer *self)
{ {
glDeleteFramebuffers(1, &self->frame_buffer); glDeleteFramebuffers(1, &self->frame_buffer);
glDeleteProgram(self->program); glDeleteProgram(self->program);
free(self); free(self);
} }
void void
gles2_debayer_use(GLES2Debayer *self) gles2_debayer_use(GLES2Debayer *self)
{ {
glUseProgram(self->program); glUseProgram(self->program);
check_gl(); check_gl();
gl_util_bind_quad(self->quad); gl_util_bind_quad(self->quad);
} }
void void
gles2_debayer_configure(GLES2Debayer *self, const uint32_t dst_width, gles2_debayer_configure(GLES2Debayer *self,
const uint32_t dst_height, const uint32_t src_width, const uint32_t dst_width,
const uint32_t src_height, const uint32_t rotation, const uint32_t dst_height,
const bool mirrored, const float *colormatrix, const uint32_t src_width,
const uint8_t blacklevel) const uint32_t src_height,
const uint32_t rotation,
const bool mirrored,
const float *colormatrix,
const uint8_t blacklevel)
{ {
glViewport(0, 0, dst_width, dst_height); glViewport(0, 0, dst_width, dst_height);
check_gl(); check_gl();
GLfloat rotation_list[4] = { 0, -1, 0, 1 }; GLfloat rotation_list[4] = { 0, -1, 0, 1 };
int rotation_index = 4 - rotation / 90; int rotation_index = 4 - rotation / 90;
GLfloat sin_rot = rotation_list[rotation_index]; GLfloat sin_rot = rotation_list[rotation_index];
GLfloat cos_rot = rotation_list[(rotation_index + 1) % 4]; GLfloat cos_rot = rotation_list[(rotation_index + 1) % 4];
GLfloat scale_x = mirrored ? 1 : -1; GLfloat scale_x = mirrored ? 1 : -1;
GLfloat matrix[9] = { GLfloat matrix[9] = {
// clang-format off // clang-format off
cos_rot * scale_x, sin_rot, 0, cos_rot * scale_x, sin_rot, 0,
-sin_rot * scale_x, cos_rot, 0, -sin_rot * scale_x, cos_rot, 0,
0, 0, 1, 0, 0, 1,
// clang-format on // clang-format on
}; };
glUniformMatrix3fv(self->uniform_transform, 1, GL_FALSE, matrix); glUniformMatrix3fv(self->uniform_transform, 1, GL_FALSE, matrix);
check_gl(); check_gl();
GLfloat pixel_size_x = 1.0f / src_width; GLfloat pixel_size_x = 1.0f / src_width;
GLfloat pixel_size_y = 1.0f / src_height; GLfloat pixel_size_y = 1.0f / src_height;
glUniform2f(self->uniform_pixel_size, pixel_size_x, pixel_size_y); glUniform2f(self->uniform_pixel_size, pixel_size_x, pixel_size_y);
check_gl(); check_gl();
if (colormatrix) { if (colormatrix) {
GLfloat transposed[9]; GLfloat transposed[9];
for (int i = 0; i < 3; ++i) for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j) for (int j = 0; j < 3; ++j)
transposed[i + j * 3] = colormatrix[j + i * 3]; transposed[i + j * 3] = colormatrix[j + i * 3];
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, glUniformMatrix3fv(
transposed); self->uniform_color_matrix, 1, GL_FALSE, transposed);
} else { } else {
static const GLfloat identity[9] = { static const GLfloat identity[9] = {
// clang-format off // clang-format off
1, 0, 0, 1, 0, 0,
0, 1, 0, 0, 1, 0,
0, 0, 1, 0, 0, 1,
// clang-format on // clang-format on
}; };
glUniformMatrix3fv(self->uniform_color_matrix, 1, GL_FALSE, glUniformMatrix3fv(
identity); self->uniform_color_matrix, 1, GL_FALSE, identity);
} }
check_gl(); check_gl();
} }
void void
gles2_debayer_process(GLES2Debayer *self, GLuint dst_id, GLuint source_id) gles2_debayer_process(GLES2Debayer *self, GLuint dst_id, GLuint source_id)
{ {
glBindFramebuffer(GL_FRAMEBUFFER, self->frame_buffer); glBindFramebuffer(GL_FRAMEBUFFER, self->frame_buffer);
glBindTexture(GL_TEXTURE_2D, dst_id); glBindTexture(GL_TEXTURE_2D, dst_id);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, glFramebufferTexture2D(
dst_id, 0); GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_id, 0);
check_gl(); check_gl();
assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, source_id); glBindTexture(GL_TEXTURE_2D, source_id);
glUniform1i(self->uniform_texture, 0); glUniform1i(self->uniform_texture, 0);
check_gl(); check_gl();
gl_util_draw_quad(self->quad); gl_util_draw_quad(self->quad);
} }

View File

@@ -10,10 +10,14 @@ void gles2_debayer_free(GLES2Debayer *self);
void gles2_debayer_use(GLES2Debayer *self); void gles2_debayer_use(GLES2Debayer *self);
void gles2_debayer_configure(GLES2Debayer *self, const uint32_t dst_width, void gles2_debayer_configure(GLES2Debayer *self,
const uint32_t dst_height, const uint32_t src_width, const uint32_t dst_width,
const uint32_t src_height, const uint32_t rotation, const uint32_t dst_height,
const bool mirrored, const float *colormatrix, const uint32_t src_width,
const uint8_t blacklevel); const uint32_t src_height,
const uint32_t rotation,
const bool mirrored,
const float *colormatrix,
const uint8_t blacklevel);
void gles2_debayer_process(GLES2Debayer *self, GLuint dst_id, GLuint source_id); void gles2_debayer_process(GLES2Debayer *self, GLuint dst_id, GLuint source_id);

View File

@@ -14,51 +14,51 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
struct media_link_info { struct media_link_info {
unsigned int source_entity_id; unsigned int source_entity_id;
unsigned int target_entity_id; unsigned int target_entity_id;
char source_fname[260]; char source_fname[260];
char target_fname[260]; char target_fname[260];
}; };
struct camera_info { struct camera_info {
size_t device_index; size_t device_index;
unsigned int pad_id; unsigned int pad_id;
char dev_fname[260]; char dev_fname[260];
int fd; int fd;
MPCamera *camera; MPCamera *camera;
MPFlash *flash; MPFlash *flash;
int gain_ctrl; int gain_ctrl;
int gain_max; int gain_max;
bool has_auto_focus_continuous; bool has_auto_focus_continuous;
bool has_auto_focus_start; bool has_auto_focus_start;
// unsigned int entity_id; // unsigned int entity_id;
// enum v4l2_buf_type type; // enum v4l2_buf_type type;
// char media_dev_fname[260]; // char media_dev_fname[260];
// char video_dev_fname[260]; // char video_dev_fname[260];
// int media_fd; // int media_fd;
// struct mp_media_link media_links[MP_MAX_LINKS]; // struct mp_media_link media_links[MP_MAX_LINKS];
// int num_media_links; // int num_media_links;
// int gain_ctrl; // int gain_ctrl;
}; };
struct device_info { struct device_info {
const char *media_dev_name; // owned by camera config const char *media_dev_name; // owned by camera config
MPDevice *device; MPDevice *device;
unsigned int interface_pad_id; unsigned int interface_pad_id;
int video_fd; int video_fd;
}; };
static struct camera_info cameras[MP_MAX_CAMERAS]; static struct camera_info cameras[MP_MAX_CAMERAS];
@@ -83,11 +83,11 @@ static int device_rotation;
static bool save_dng; static bool save_dng;
struct control_state { struct control_state {
bool gain_is_manual; bool gain_is_manual;
int gain; int gain;
bool exposure_is_manual; bool exposure_is_manual;
int exposure; int exposure;
}; };
static struct control_state desired_controls = {}; static struct control_state desired_controls = {};
@@ -103,288 +103,294 @@ static GSource *capture_source;
static void static void
setup_camera(MPDeviceList **device_list, const struct mp_camera_config *config) setup_camera(MPDeviceList **device_list, const struct mp_camera_config *config)
{ {
// Find device info // Find device info
size_t device_index = 0; size_t device_index = 0;
for (; device_index < num_devices; ++device_index) { for (; device_index < num_devices; ++device_index) {
if (strcmp(config->media_dev_name, if (strcmp(config->media_dev_name,
devices[device_index].media_dev_name) == 0) { devices[device_index].media_dev_name) == 0) {
break; break;
} }
} }
if (device_index == num_devices) { if (device_index == num_devices) {
device_index = num_devices; device_index = num_devices;
// Initialize new device // Initialize new device
struct device_info *info = &devices[device_index]; struct device_info *info = &devices[device_index];
info->media_dev_name = config->media_dev_name; info->media_dev_name = config->media_dev_name;
info->device = mp_device_list_find_remove(device_list, info->device = mp_device_list_find_remove(device_list,
info->media_dev_name); info->media_dev_name);
if (!info->device) { if (!info->device) {
g_printerr("Could not find /dev/media* node matching '%s'\n", g_printerr("Could not find /dev/media* node matching '%s'\n",
info->media_dev_name); info->media_dev_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
const struct media_v2_entity *entity = const struct media_v2_entity *entity =
mp_device_find_entity_type(info->device, MEDIA_ENT_F_IO_V4L); mp_device_find_entity_type(info->device, MEDIA_ENT_F_IO_V4L);
if (!entity) { if (!entity) {
g_printerr("Could not find device video entity\n"); g_printerr("Could not find device video entity\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
const struct media_v2_pad *pad = const struct media_v2_pad *pad =
mp_device_get_pad_from_entity(info->device, entity->id); mp_device_get_pad_from_entity(info->device, entity->id);
info->interface_pad_id = pad->id; info->interface_pad_id = pad->id;
const struct media_v2_interface *interface = const struct media_v2_interface *interface =
mp_device_find_entity_interface(info->device, entity->id); mp_device_find_entity_interface(info->device, entity->id);
char dev_name[260]; char dev_name[260];
if (!mp_find_device_path(interface->devnode, dev_name, 260)) { if (!mp_find_device_path(interface->devnode, dev_name, 260)) {
g_printerr("Could not find video path\n"); g_printerr("Could not find video path\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
info->video_fd = open(dev_name, O_RDWR); info->video_fd = open(dev_name, O_RDWR);
if (info->video_fd == -1) { if (info->video_fd == -1) {
g_printerr("Could not open %s: %s\n", dev_name, g_printerr("Could not open %s: %s\n",
strerror(errno)); dev_name,
exit(EXIT_FAILURE); strerror(errno));
} exit(EXIT_FAILURE);
}
++num_devices; ++num_devices;
} }
{ {
struct camera_info *info = &cameras[config->index]; struct camera_info *info = &cameras[config->index];
struct device_info *dev_info = &devices[device_index]; struct device_info *dev_info = &devices[device_index];
info->device_index = device_index; info->device_index = device_index;
const struct media_v2_entity *entity = const struct media_v2_entity *entity =
mp_device_find_entity(dev_info->device, config->dev_name); mp_device_find_entity(dev_info->device, config->dev_name);
if (!entity) { if (!entity) {
g_printerr("Could not find camera entity matching '%s'\n", g_printerr("Could not find camera entity matching '%s'\n",
config->dev_name); config->dev_name);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
const struct media_v2_pad *pad = const struct media_v2_pad *pad =
mp_device_get_pad_from_entity(dev_info->device, entity->id); mp_device_get_pad_from_entity(dev_info->device, entity->id);
info->pad_id = pad->id; info->pad_id = pad->id;
// Make sure the camera starts out as disabled // Make sure the camera starts out as disabled
mp_device_setup_link(dev_info->device, info->pad_id, mp_device_setup_link(dev_info->device,
dev_info->interface_pad_id, false); info->pad_id,
dev_info->interface_pad_id,
false);
const struct media_v2_interface *interface = const struct media_v2_interface *interface =
mp_device_find_entity_interface(dev_info->device, mp_device_find_entity_interface(dev_info->device,
entity->id); entity->id);
if (!mp_find_device_path(interface->devnode, info->dev_fname, 260)) { if (!mp_find_device_path(interface->devnode, info->dev_fname, 260)) {
g_printerr("Could not find camera device path\n"); g_printerr("Could not find camera device path\n");
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
info->fd = open(info->dev_fname, O_RDWR); info->fd = open(info->dev_fname, O_RDWR);
if (info->fd == -1) { if (info->fd == -1) {
g_printerr("Could not open %s: %s\n", info->dev_fname, g_printerr("Could not open %s: %s\n",
strerror(errno)); info->dev_fname,
exit(EXIT_FAILURE); strerror(errno));
} exit(EXIT_FAILURE);
}
info->camera = mp_camera_new(dev_info->video_fd, info->fd); info->camera = mp_camera_new(dev_info->video_fd, info->fd);
// Start with the capture format, this works around a bug with // Start with the capture format, this works around a bug with
// the ov5640 driver where it won't allow setting the preview // the ov5640 driver where it won't allow setting the preview
// format initially. // format initially.
MPCameraMode mode = config->capture_mode; MPCameraMode mode = config->capture_mode;
mp_camera_set_mode(info->camera, &mode); mp_camera_set_mode(info->camera, &mode);
// Trigger continuous auto focus if the sensor supports it // Trigger continuous auto focus if the sensor supports it
if (mp_camera_query_control(info->camera, V4L2_CID_FOCUS_AUTO, if (mp_camera_query_control(
NULL)) { info->camera, V4L2_CID_FOCUS_AUTO, NULL)) {
info->has_auto_focus_continuous = true; info->has_auto_focus_continuous = true;
mp_camera_control_set_bool_bg(info->camera, mp_camera_control_set_bool_bg(
V4L2_CID_FOCUS_AUTO, true); info->camera, V4L2_CID_FOCUS_AUTO, true);
} }
if (mp_camera_query_control(info->camera, V4L2_CID_AUTO_FOCUS_START, if (mp_camera_query_control(
NULL)) { info->camera, V4L2_CID_AUTO_FOCUS_START, NULL)) {
info->has_auto_focus_start = true; info->has_auto_focus_start = true;
} }
MPControl control; MPControl control;
if (mp_camera_query_control(info->camera, V4L2_CID_GAIN, &control)) { if (mp_camera_query_control(info->camera, V4L2_CID_GAIN, &control)) {
info->gain_ctrl = V4L2_CID_GAIN; info->gain_ctrl = V4L2_CID_GAIN;
info->gain_max = control.max; info->gain_max = control.max;
} else if (mp_camera_query_control( } else if (mp_camera_query_control(
info->camera, V4L2_CID_ANALOGUE_GAIN, &control)) { info->camera, V4L2_CID_ANALOGUE_GAIN, &control)) {
info->gain_ctrl = V4L2_CID_ANALOGUE_GAIN; info->gain_ctrl = V4L2_CID_ANALOGUE_GAIN;
info->gain_max = control.max; info->gain_max = control.max;
} }
// Setup flash // Setup flash
if (config->flash_path[0]) { if (config->flash_path[0]) {
info->flash = mp_led_flash_from_path(config->flash_path); info->flash = mp_led_flash_from_path(config->flash_path);
} else if (config->flash_display) { } else if (config->flash_display) {
info->flash = mp_create_display_flash(); info->flash = mp_create_display_flash();
} else { } else {
info->flash = NULL; info->flash = NULL;
} }
} }
} }
static void static void
setup(MPPipeline *pipeline, const void *data) setup(MPPipeline *pipeline, const void *data)
{ {
MPDeviceList *device_list = mp_device_list_new(); MPDeviceList *device_list = mp_device_list_new();
for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) { for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) {
const struct mp_camera_config *config = mp_get_camera_config(i); const struct mp_camera_config *config = mp_get_camera_config(i);
if (!config) { if (!config) {
break; break;
} }
setup_camera(&device_list, config); setup_camera(&device_list, config);
} }
mp_device_list_free(device_list); mp_device_list_free(device_list);
} }
static void static void
clean_cameras() clean_cameras()
{ {
for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) { for (size_t i = 0; i < MP_MAX_CAMERAS; ++i) {
struct camera_info *info = &cameras[i]; struct camera_info *info = &cameras[i];
if (info->camera) { if (info->camera) {
mp_camera_free(info->camera); mp_camera_free(info->camera);
info->camera = NULL; info->camera = NULL;
} }
} }
} }
void void
mp_io_pipeline_start() mp_io_pipeline_start()
{ {
mp_process_pipeline_start(); mp_process_pipeline_start();
pipeline = mp_pipeline_new(); pipeline = mp_pipeline_new();
mp_pipeline_invoke(pipeline, setup, NULL, 0); mp_pipeline_invoke(pipeline, setup, NULL, 0);
} }
void void
mp_io_pipeline_stop() mp_io_pipeline_stop()
{ {
if (capture_source) { if (capture_source) {
g_source_destroy(capture_source); g_source_destroy(capture_source);
} }
clean_cameras(); clean_cameras();
mp_pipeline_free(pipeline); mp_pipeline_free(pipeline);
mp_process_pipeline_stop(); mp_process_pipeline_stop();
} }
static void static void
update_process_pipeline() update_process_pipeline()
{ {
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
// Grab the latest control values // Grab the latest control values
if (!current_controls.gain_is_manual) { if (!current_controls.gain_is_manual) {
current_controls.gain = current_controls.gain =
mp_camera_control_get_int32(info->camera, info->gain_ctrl); mp_camera_control_get_int32(info->camera, info->gain_ctrl);
} }
if (!current_controls.exposure_is_manual) { if (!current_controls.exposure_is_manual) {
current_controls.exposure = current_controls.exposure =
mp_camera_control_get_int32(info->camera, V4L2_CID_EXPOSURE); mp_camera_control_get_int32(info->camera, V4L2_CID_EXPOSURE);
} }
struct mp_process_pipeline_state pipeline_state = { struct mp_process_pipeline_state pipeline_state = {
.camera = camera, .camera = camera,
.mode = mode, .mode = mode,
.burst_length = burst_length, .burst_length = burst_length,
.save_dng = save_dng, .save_dng = save_dng,
.preview_width = preview_width, .preview_width = preview_width,
.preview_height = preview_height, .preview_height = preview_height,
.device_rotation = device_rotation, .device_rotation = device_rotation,
.gain_is_manual = current_controls.gain_is_manual, .gain_is_manual = current_controls.gain_is_manual,
.gain = current_controls.gain, .gain = current_controls.gain,
.gain_max = info->gain_max, .gain_max = info->gain_max,
.exposure_is_manual = current_controls.exposure_is_manual, .exposure_is_manual = current_controls.exposure_is_manual,
.exposure = current_controls.exposure, .exposure = current_controls.exposure,
.has_auto_focus_continuous = info->has_auto_focus_continuous, .has_auto_focus_continuous = info->has_auto_focus_continuous,
.has_auto_focus_start = info->has_auto_focus_start, .has_auto_focus_start = info->has_auto_focus_start,
}; };
mp_process_pipeline_update_state(&pipeline_state); mp_process_pipeline_update_state(&pipeline_state);
} }
static void static void
focus(MPPipeline *pipeline, const void *data) focus(MPPipeline *pipeline, const void *data)
{ {
want_focus = true; want_focus = true;
} }
void void
mp_io_pipeline_focus() mp_io_pipeline_focus()
{ {
mp_pipeline_invoke(pipeline, focus, NULL, 0); mp_pipeline_invoke(pipeline, focus, NULL, 0);
} }
static void static void
capture(MPPipeline *pipeline, const void *data) capture(MPPipeline *pipeline, const void *data)
{ {
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
captures_remaining = burst_length; captures_remaining = burst_length;
// Disable the autogain/exposure while taking the burst // Disable the autogain/exposure while taking the burst
mp_camera_control_set_int32(info->camera, V4L2_CID_AUTOGAIN, 0); mp_camera_control_set_int32(info->camera, V4L2_CID_AUTOGAIN, 0);
mp_camera_control_set_int32(info->camera, V4L2_CID_EXPOSURE_AUTO, mp_camera_control_set_int32(
V4L2_EXPOSURE_MANUAL); info->camera, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL);
// Change camera mode for capturing // Change camera mode for capturing
mp_process_pipeline_sync(); mp_process_pipeline_sync();
mp_camera_stop_capture(info->camera); mp_camera_stop_capture(info->camera);
mode = camera->capture_mode; mode = camera->capture_mode;
mp_camera_set_mode(info->camera, &mode); mp_camera_set_mode(info->camera, &mode);
just_switched_mode = true; just_switched_mode = true;
mp_camera_start_capture(info->camera); mp_camera_start_capture(info->camera);
// Enable flash // Enable flash
if (info->flash && flash_enabled) { if (info->flash && flash_enabled) {
mp_flash_enable(info->flash); mp_flash_enable(info->flash);
} }
update_process_pipeline(); update_process_pipeline();
mp_process_pipeline_capture(); mp_process_pipeline_capture();
} }
void void
mp_io_pipeline_capture() mp_io_pipeline_capture()
{ {
mp_pipeline_invoke(pipeline, capture, NULL, 0); mp_pipeline_invoke(pipeline, capture, NULL, 0);
} }
static void static void
release_buffer(MPPipeline *pipeline, const uint32_t *buffer_index) release_buffer(MPPipeline *pipeline, const uint32_t *buffer_index)
{ {
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
mp_camera_release_buffer(info->camera, *buffer_index); mp_camera_release_buffer(info->camera, *buffer_index);
} }
void void
mp_io_pipeline_release_buffer(uint32_t buffer_index) mp_io_pipeline_release_buffer(uint32_t buffer_index)
{ {
mp_pipeline_invoke(pipeline, (MPPipelineCallback)release_buffer, mp_pipeline_invoke(pipeline,
&buffer_index, sizeof(uint32_t)); (MPPipelineCallback)release_buffer,
&buffer_index,
sizeof(uint32_t));
} }
static pid_t focus_continuous_task = 0; static pid_t focus_continuous_task = 0;
@@ -392,228 +398,238 @@ static pid_t start_focus_task = 0;
static void static void
start_focus(struct camera_info *info) start_focus(struct camera_info *info)
{ {
// only run 1 manual focus at once // only run 1 manual focus at once
if (!mp_camera_check_task_complete(info->camera, start_focus_task) || if (!mp_camera_check_task_complete(info->camera, start_focus_task) ||
!mp_camera_check_task_complete(info->camera, focus_continuous_task)) !mp_camera_check_task_complete(info->camera, focus_continuous_task))
return; return;
if (info->has_auto_focus_continuous) { if (info->has_auto_focus_continuous) {
focus_continuous_task = mp_camera_control_set_bool_bg( focus_continuous_task = mp_camera_control_set_bool_bg(
info->camera, V4L2_CID_FOCUS_AUTO, 1); info->camera, V4L2_CID_FOCUS_AUTO, 1);
} else if (info->has_auto_focus_start) { } else if (info->has_auto_focus_start) {
start_focus_task = mp_camera_control_set_bool_bg( start_focus_task = mp_camera_control_set_bool_bg(
info->camera, V4L2_CID_AUTO_FOCUS_START, 1); info->camera, V4L2_CID_AUTO_FOCUS_START, 1);
} }
} }
static void static void
update_controls() update_controls()
{ {
// Don't update controls while capturing // Don't update controls while capturing
if (captures_remaining > 0) { if (captures_remaining > 0) {
return; return;
} }
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
if (want_focus) { if (want_focus) {
start_focus(info); start_focus(info);
want_focus = false; want_focus = false;
} }
if (current_controls.gain_is_manual != desired_controls.gain_is_manual) { if (current_controls.gain_is_manual != desired_controls.gain_is_manual) {
mp_camera_control_set_bool_bg(info->camera, V4L2_CID_AUTOGAIN, mp_camera_control_set_bool_bg(info->camera,
!desired_controls.gain_is_manual); V4L2_CID_AUTOGAIN,
} !desired_controls.gain_is_manual);
}
if (desired_controls.gain_is_manual && if (desired_controls.gain_is_manual &&
current_controls.gain != desired_controls.gain) { current_controls.gain != desired_controls.gain) {
mp_camera_control_set_int32_bg(info->camera, info->gain_ctrl, mp_camera_control_set_int32_bg(
desired_controls.gain); info->camera, info->gain_ctrl, desired_controls.gain);
} }
if (current_controls.exposure_is_manual != if (current_controls.exposure_is_manual !=
desired_controls.exposure_is_manual) { desired_controls.exposure_is_manual) {
mp_camera_control_set_int32_bg(info->camera, V4L2_CID_EXPOSURE_AUTO, mp_camera_control_set_int32_bg(info->camera,
desired_controls.exposure_is_manual ? V4L2_CID_EXPOSURE_AUTO,
V4L2_EXPOSURE_MANUAL : desired_controls.exposure_is_manual ?
V4L2_EXPOSURE_AUTO); V4L2_EXPOSURE_MANUAL :
} V4L2_EXPOSURE_AUTO);
}
if (desired_controls.exposure_is_manual && if (desired_controls.exposure_is_manual &&
current_controls.exposure != desired_controls.exposure) { current_controls.exposure != desired_controls.exposure) {
mp_camera_control_set_int32_bg(info->camera, V4L2_CID_EXPOSURE, mp_camera_control_set_int32_bg(
desired_controls.exposure); info->camera, V4L2_CID_EXPOSURE, desired_controls.exposure);
} }
current_controls = desired_controls; current_controls = desired_controls;
} }
static void static void
on_frame(MPBuffer buffer, void *_data) on_frame(MPBuffer buffer, void *_data)
{ {
// Only update controls right after a frame was captured // Only update controls right after a frame was captured
update_controls(); update_controls();
// When the mode is switched while capturing we get a couple blank frames, // When the mode is switched while capturing we get a couple blank frames,
// presumably from buffers made ready during the switch. Ignore these. // presumably from buffers made ready during the switch. Ignore these.
if (just_switched_mode) { if (just_switched_mode) {
if (blank_frame_count < 20) { if (blank_frame_count < 20) {
// Only check a 10x10 area // Only check a 10x10 area
size_t test_size = size_t test_size =
MIN(10, mode.width) * MIN(10, mode.height); MIN(10, mode.width) * MIN(10, mode.height);
bool image_is_blank = true; bool image_is_blank = true;
for (size_t i = 0; i < test_size; ++i) { for (size_t i = 0; i < test_size; ++i) {
if (buffer.data[i] != 0) { if (buffer.data[i] != 0) {
image_is_blank = false; image_is_blank = false;
} }
} }
if (image_is_blank) { if (image_is_blank) {
++blank_frame_count; ++blank_frame_count;
return; return;
} }
} else { } else {
printf("Blank image limit reached, resulting capture may be blank\n"); printf("Blank image limit reached, resulting capture may be blank\n");
} }
just_switched_mode = false; just_switched_mode = false;
blank_frame_count = 0; blank_frame_count = 0;
} }
// Send the image off for processing // Send the image off for processing
mp_process_pipeline_process_image(buffer); mp_process_pipeline_process_image(buffer);
if (captures_remaining > 0) { if (captures_remaining > 0) {
--captures_remaining; --captures_remaining;
if (captures_remaining == 0) { if (captures_remaining == 0) {
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
// Restore the auto exposure and gain if needed // Restore the auto exposure and gain if needed
if (!current_controls.exposure_is_manual) { if (!current_controls.exposure_is_manual) {
mp_camera_control_set_int32_bg( mp_camera_control_set_int32_bg(
info->camera, V4L2_CID_EXPOSURE_AUTO, info->camera,
V4L2_EXPOSURE_AUTO); V4L2_CID_EXPOSURE_AUTO,
} V4L2_EXPOSURE_AUTO);
}
if (!current_controls.gain_is_manual) { if (!current_controls.gain_is_manual) {
mp_camera_control_set_bool_bg( mp_camera_control_set_bool_bg(
info->camera, V4L2_CID_AUTOGAIN, true); info->camera, V4L2_CID_AUTOGAIN, true);
} }
// Go back to preview mode // Go back to preview mode
mp_process_pipeline_sync(); mp_process_pipeline_sync();
mp_camera_stop_capture(info->camera); mp_camera_stop_capture(info->camera);
mode = camera->preview_mode; mode = camera->preview_mode;
mp_camera_set_mode(info->camera, &mode); mp_camera_set_mode(info->camera, &mode);
just_switched_mode = true; just_switched_mode = true;
mp_camera_start_capture(info->camera); mp_camera_start_capture(info->camera);
// Disable flash // Disable flash
if (info->flash) { if (info->flash) {
mp_flash_disable(info->flash); mp_flash_disable(info->flash);
} }
update_process_pipeline(); update_process_pipeline();
} }
} }
} }
static void static void
update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state) update_state(MPPipeline *pipeline, const struct mp_io_pipeline_state *state)
{ {
// Make sure the state isn't updated more than it needs to be by checking // Make sure the state isn't updated more than it needs to be by checking
// whether this state change actually changes anything. // whether this state change actually changes anything.
bool has_changed = false; bool has_changed = false;
if (camera != state->camera) { if (camera != state->camera) {
has_changed = true; has_changed = true;
if (camera) { if (camera) {
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
struct device_info *dev_info = &devices[info->device_index]; struct device_info *dev_info = &devices[info->device_index];
mp_process_pipeline_sync(); mp_process_pipeline_sync();
mp_camera_stop_capture(info->camera); mp_camera_stop_capture(info->camera);
mp_device_setup_link(dev_info->device, info->pad_id, mp_device_setup_link(dev_info->device,
dev_info->interface_pad_id, false); info->pad_id,
} dev_info->interface_pad_id,
false);
}
if (capture_source) { if (capture_source) {
g_source_destroy(capture_source); g_source_destroy(capture_source);
capture_source = NULL; capture_source = NULL;
} }
camera = state->camera; camera = state->camera;
if (camera) { if (camera) {
struct camera_info *info = &cameras[camera->index]; struct camera_info *info = &cameras[camera->index];
struct device_info *dev_info = &devices[info->device_index]; struct device_info *dev_info = &devices[info->device_index];
mp_device_setup_link(dev_info->device, info->pad_id, mp_device_setup_link(dev_info->device,
dev_info->interface_pad_id, true); info->pad_id,
dev_info->interface_pad_id,
true);
mode = camera->preview_mode; mode = camera->preview_mode;
mp_camera_set_mode(info->camera, &mode); mp_camera_set_mode(info->camera, &mode);
mp_camera_start_capture(info->camera); mp_camera_start_capture(info->camera);
capture_source = mp_pipeline_add_capture_source( capture_source = mp_pipeline_add_capture_source(
pipeline, info->camera, on_frame, NULL); pipeline, info->camera, on_frame, NULL);
current_controls.gain_is_manual = current_controls.gain_is_manual =
mp_camera_control_get_bool(info->camera, mp_camera_control_get_bool(info->camera,
V4L2_CID_AUTOGAIN) == 0; V4L2_CID_AUTOGAIN) == 0;
current_controls.gain = mp_camera_control_get_int32( current_controls.gain = mp_camera_control_get_int32(
info->camera, info->gain_ctrl); info->camera, info->gain_ctrl);
current_controls.exposure_is_manual = current_controls.exposure_is_manual =
mp_camera_control_get_int32( mp_camera_control_get_int32(
info->camera, V4L2_CID_EXPOSURE_AUTO) == info->camera, V4L2_CID_EXPOSURE_AUTO) ==
V4L2_EXPOSURE_MANUAL; V4L2_EXPOSURE_MANUAL;
current_controls.exposure = mp_camera_control_get_int32( current_controls.exposure = mp_camera_control_get_int32(
info->camera, V4L2_CID_EXPOSURE); info->camera, V4L2_CID_EXPOSURE);
} }
} }
has_changed = has_changed || burst_length != state->burst_length || has_changed = has_changed || burst_length != state->burst_length ||
preview_width != state->preview_width || preview_width != state->preview_width ||
preview_height != state->preview_height || preview_height != state->preview_height ||
device_rotation != state->device_rotation; device_rotation != state->device_rotation;
burst_length = state->burst_length; burst_length = state->burst_length;
preview_width = state->preview_width; preview_width = state->preview_width;
preview_height = state->preview_height; preview_height = state->preview_height;
device_rotation = state->device_rotation; device_rotation = state->device_rotation;
save_dng = state->save_dng; save_dng = state->save_dng;
if (camera) { if (camera) {
struct control_state previous_desired = desired_controls; struct control_state previous_desired = desired_controls;
desired_controls.gain_is_manual = state->gain_is_manual; desired_controls.gain_is_manual = state->gain_is_manual;
desired_controls.gain = state->gain; desired_controls.gain = state->gain;
desired_controls.exposure_is_manual = state->exposure_is_manual; desired_controls.exposure_is_manual = state->exposure_is_manual;
desired_controls.exposure = state->exposure; desired_controls.exposure = state->exposure;
has_changed = has_changed || has_changed = has_changed ||
memcmp(&previous_desired, &desired_controls, memcmp(&previous_desired,
sizeof(struct control_state)) != 0 || &desired_controls,
flash_enabled != state->flash_enabled; sizeof(struct control_state)) != 0 ||
flash_enabled != state->flash_enabled;
flash_enabled = state->flash_enabled; flash_enabled = state->flash_enabled;
} }
assert(has_changed); assert(has_changed);
update_process_pipeline(); update_process_pipeline();
} }
void void
mp_io_pipeline_update_state(const struct mp_io_pipeline_state *state) mp_io_pipeline_update_state(const struct mp_io_pipeline_state *state)
{ {
mp_pipeline_invoke(pipeline, (MPPipelineCallback)update_state, state, mp_pipeline_invoke(pipeline,
sizeof(struct mp_io_pipeline_state)); (MPPipelineCallback)update_state,
state,
sizeof(struct mp_io_pipeline_state));
} }

View File

@@ -3,23 +3,23 @@
#include "camera_config.h" #include "camera_config.h"
struct mp_io_pipeline_state { struct mp_io_pipeline_state {
const struct mp_camera_config *camera; const struct mp_camera_config *camera;
int burst_length; int burst_length;
int preview_width; int preview_width;
int preview_height; int preview_height;
int device_rotation; int device_rotation;
bool gain_is_manual; bool gain_is_manual;
int gain; int gain;
bool exposure_is_manual; bool exposure_is_manual;
int exposure; int exposure;
bool save_dng; bool save_dng;
bool flash_enabled; bool flash_enabled;
}; };
void mp_io_pipeline_start(); void mp_io_pipeline_start();

1287
src/main.c

File diff suppressed because it is too large Load Diff

View File

@@ -1,26 +1,26 @@
#pragma once #pragma once
#include "camera_config.h" #include "camera_config.h"
#include "zbar_pipeline.h"
#include "process_pipeline.h"
#include "gtk/gtk.h" #include "gtk/gtk.h"
#include "process_pipeline.h"
#include "zbar_pipeline.h"
struct mp_main_state { struct mp_main_state {
const struct mp_camera_config *camera; const struct mp_camera_config *camera;
MPCameraMode mode; MPCameraMode mode;
int image_width; int image_width;
int image_height; int image_height;
bool gain_is_manual; bool gain_is_manual;
int gain; int gain;
int gain_max; int gain_max;
bool exposure_is_manual; bool exposure_is_manual;
int exposure; int exposure;
bool has_auto_focus_continuous; bool has_auto_focus_continuous;
bool has_auto_focus_start; bool has_auto_focus_start;
}; };
void mp_main_update_state(const struct mp_main_state *state); void mp_main_update_state(const struct mp_main_state *state);

View File

@@ -3,24 +3,24 @@
void void
print_matrix(float m[9]) print_matrix(float m[9])
{ {
printf(" [%.2f %.2f %.2f] \n", m[0], m[1], m[2]); printf(" [%.2f %.2f %.2f] \n", m[0], m[1], m[2]);
printf(" [%.2f %.2f %.2f] \n", m[3], m[4], m[5]); printf(" [%.2f %.2f %.2f] \n", m[3], m[4], m[5]);
printf(" [%.2f %.2f %.2f] \n\n", m[6], m[7], m[8]); printf(" [%.2f %.2f %.2f] \n\n", m[6], m[7], m[8]);
} }
void void
multiply_matrices(float a[9], float b[9], float out[9]) multiply_matrices(float a[9], float b[9], float out[9])
{ {
// zero out target matrix // zero out target matrix
for (int i = 0; i < 9; i++) { for (int i = 0; i < 9; i++) {
out[i] = 0; out[i] = 0;
} }
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
for (int k = 0; k < 3; k++) { for (int k = 0; k < 3; k++) {
out[i * 3 + j] += a[i * 3 + k] * b[k * 3 + j]; out[i * 3 + j] += a[i * 3 + k] * b[k * 3 + j];
} }
} }
} }
} }

View File

@@ -1,135 +1,144 @@
#include "pipeline.h" #include "pipeline.h"
#include <gtk/gtk.h>
#include <glib-unix.h>
#include <assert.h> #include <assert.h>
#include <glib-unix.h>
#include <gtk/gtk.h>
struct _MPPipeline { struct _MPPipeline {
GMainContext *main_context; GMainContext *main_context;
GMainLoop *main_loop; GMainLoop *main_loop;
pthread_t thread; pthread_t thread;
}; };
static void * static void *
thread_main_loop(void *arg) thread_main_loop(void *arg)
{ {
MPPipeline *pipeline = arg; MPPipeline *pipeline = arg;
g_main_loop_run(pipeline->main_loop); g_main_loop_run(pipeline->main_loop);
return NULL; return NULL;
} }
MPPipeline * MPPipeline *
mp_pipeline_new() mp_pipeline_new()
{ {
MPPipeline *pipeline = malloc(sizeof(MPPipeline)); MPPipeline *pipeline = malloc(sizeof(MPPipeline));
pipeline->main_context = g_main_context_new(); pipeline->main_context = g_main_context_new();
pipeline->main_loop = g_main_loop_new(pipeline->main_context, false); pipeline->main_loop = g_main_loop_new(pipeline->main_context, false);
int res = int res =
pthread_create(&pipeline->thread, NULL, thread_main_loop, pipeline); pthread_create(&pipeline->thread, NULL, thread_main_loop, pipeline);
assert(res == 0); assert(res == 0);
return pipeline; return pipeline;
} }
struct invoke_args { struct invoke_args {
MPPipeline *pipeline; MPPipeline *pipeline;
MPPipelineCallback callback; MPPipelineCallback callback;
}; };
static bool static bool
invoke_impl(struct invoke_args *args) invoke_impl(struct invoke_args *args)
{ {
args->callback(args->pipeline, args + 1); args->callback(args->pipeline, args + 1);
return false; return false;
} }
void void
mp_pipeline_invoke(MPPipeline *pipeline, MPPipelineCallback callback, mp_pipeline_invoke(MPPipeline *pipeline,
const void *data, size_t size) MPPipelineCallback callback,
const void *data,
size_t size)
{ {
if (pthread_self() != pipeline->thread) { if (pthread_self() != pipeline->thread) {
struct invoke_args *args = malloc(sizeof(struct invoke_args) + size); struct invoke_args *args = malloc(sizeof(struct invoke_args) + size);
args->pipeline = pipeline; args->pipeline = pipeline;
args->callback = callback; args->callback = callback;
if (size > 0) { if (size > 0) {
memcpy(args + 1, data, size); memcpy(args + 1, data, size);
} }
g_main_context_invoke_full(pipeline->main_context, g_main_context_invoke_full(pipeline->main_context,
G_PRIORITY_DEFAULT, G_PRIORITY_DEFAULT,
(GSourceFunc)invoke_impl, args, free); (GSourceFunc)invoke_impl,
} else { args,
callback(pipeline, data); free);
} } else {
callback(pipeline, data);
}
} }
static bool static bool
unlock_mutex(GMutex *mutex) unlock_mutex(GMutex *mutex)
{ {
g_mutex_unlock(mutex); g_mutex_unlock(mutex);
return false; return false;
} }
void void
mp_pipeline_sync(MPPipeline *pipeline) mp_pipeline_sync(MPPipeline *pipeline)
{ {
GMutex mutex; GMutex mutex;
g_mutex_init(&mutex); g_mutex_init(&mutex);
g_mutex_lock(&mutex); g_mutex_lock(&mutex);
g_main_context_invoke_full(pipeline->main_context, G_PRIORITY_LOW, g_main_context_invoke_full(pipeline->main_context,
(GSourceFunc)unlock_mutex, &mutex, NULL); G_PRIORITY_LOW,
g_mutex_lock(&mutex); (GSourceFunc)unlock_mutex,
g_mutex_unlock(&mutex); &mutex,
NULL);
g_mutex_lock(&mutex);
g_mutex_unlock(&mutex);
g_mutex_clear(&mutex); g_mutex_clear(&mutex);
} }
void void
mp_pipeline_free(MPPipeline *pipeline) mp_pipeline_free(MPPipeline *pipeline)
{ {
g_main_loop_quit(pipeline->main_loop); g_main_loop_quit(pipeline->main_loop);
// Force the main thread loop to wake up, otherwise we might not exit // Force the main thread loop to wake up, otherwise we might not exit
g_main_context_wakeup(pipeline->main_context); g_main_context_wakeup(pipeline->main_context);
void *r; void *r;
pthread_join(pipeline->thread, &r); pthread_join(pipeline->thread, &r);
free(pipeline); free(pipeline);
} }
struct capture_source_args { struct capture_source_args {
MPCamera *camera; MPCamera *camera;
void (*callback)(MPBuffer, void *); void (*callback)(MPBuffer, void *);
void *user_data; void *user_data;
}; };
static bool static bool
on_capture(int fd, GIOCondition condition, struct capture_source_args *args) on_capture(int fd, GIOCondition condition, struct capture_source_args *args)
{ {
MPBuffer buffer; MPBuffer buffer;
if (mp_camera_capture_buffer(args->camera, &buffer)) { if (mp_camera_capture_buffer(args->camera, &buffer)) {
args->callback(buffer, args->user_data); args->callback(buffer, args->user_data);
} }
return true; return true;
} }
// Not thread safe // Not thread safe
GSource * GSource *
mp_pipeline_add_capture_source(MPPipeline *pipeline, MPCamera *camera, mp_pipeline_add_capture_source(MPPipeline *pipeline,
void (*callback)(MPBuffer, void *), void *user_data) MPCamera *camera,
void (*callback)(MPBuffer, void *),
void *user_data)
{ {
int video_fd = mp_camera_get_video_fd(camera); int video_fd = mp_camera_get_video_fd(camera);
GSource *video_source = g_unix_fd_source_new(video_fd, G_IO_IN); GSource *video_source = g_unix_fd_source_new(video_fd, G_IO_IN);
struct capture_source_args *args = struct capture_source_args *args =
malloc(sizeof(struct capture_source_args)); malloc(sizeof(struct capture_source_args));
args->camera = camera; args->camera = camera;
args->callback = callback; args->callback = callback;
args->user_data = user_data; args->user_data = user_data;
g_source_set_callback(video_source, (GSourceFunc)on_capture, args, free); g_source_set_callback(video_source, (GSourceFunc)on_capture, args, free);
g_source_attach(video_source, pipeline->main_context); g_source_attach(video_source, pipeline->main_context);
return video_source; return video_source;
} }

View File

@@ -9,12 +9,15 @@ typedef struct _MPPipeline MPPipeline;
typedef void (*MPPipelineCallback)(MPPipeline *, const void *); typedef void (*MPPipelineCallback)(MPPipeline *, const void *);
MPPipeline *mp_pipeline_new(); MPPipeline *mp_pipeline_new();
void mp_pipeline_invoke(MPPipeline *pipeline, MPPipelineCallback callback, void mp_pipeline_invoke(MPPipeline *pipeline,
const void *data, size_t size); MPPipelineCallback callback,
const void *data,
size_t size);
// Wait until all pending tasks have completed // Wait until all pending tasks have completed
void mp_pipeline_sync(MPPipeline *pipeline); void mp_pipeline_sync(MPPipeline *pipeline);
void mp_pipeline_free(MPPipeline *pipeline); void mp_pipeline_free(MPPipeline *pipeline);
GSource *mp_pipeline_add_capture_source(MPPipeline *pipeline, MPCamera *camera, GSource *mp_pipeline_add_capture_source(MPPipeline *pipeline,
void (*callback)(MPBuffer, void *), MPCamera *camera,
void *user_data); void (*callback)(MPBuffer, void *),
void *user_data);

File diff suppressed because it is too large Load Diff

View File

@@ -5,27 +5,27 @@
typedef struct _GdkSurface GdkSurface; typedef struct _GdkSurface GdkSurface;
struct mp_process_pipeline_state { struct mp_process_pipeline_state {
const struct mp_camera_config *camera; const struct mp_camera_config *camera;
MPCameraMode mode; MPCameraMode mode;
int burst_length; int burst_length;
int preview_width; int preview_width;
int preview_height; int preview_height;
int device_rotation; int device_rotation;
bool gain_is_manual; bool gain_is_manual;
int gain; int gain;
int gain_max; int gain_max;
bool exposure_is_manual; bool exposure_is_manual;
int exposure; int exposure;
bool has_auto_focus_continuous; bool has_auto_focus_continuous;
bool has_auto_focus_start; bool has_auto_focus_start;
bool save_dng; bool save_dng;
}; };
void mp_process_pipeline_start(); void mp_process_pipeline_start();

View File

@@ -1,20 +1,20 @@
#include "zbar_pipeline.h" #include "zbar_pipeline.h"
#include "pipeline.h"
#include "main.h"
#include "io_pipeline.h" #include "io_pipeline.h"
#include <zbar.h> #include "main.h"
#include "pipeline.h"
#include <assert.h> #include <assert.h>
#include <zbar.h>
struct _MPZBarImage { struct _MPZBarImage {
uint8_t *data; uint8_t *data;
MPPixelFormat pixel_format; MPPixelFormat pixel_format;
int width; int width;
int height; int height;
int rotation; int rotation;
bool mirrored; bool mirrored;
_Atomic int ref_count; _Atomic int ref_count;
}; };
static MPPipeline *pipeline; static MPPipeline *pipeline;
@@ -27,237 +27,251 @@ static zbar_image_scanner_t *scanner;
static void static void
setup(MPPipeline *pipeline, const void *data) setup(MPPipeline *pipeline, const void *data)
{ {
scanner = zbar_image_scanner_create(); scanner = zbar_image_scanner_create();
zbar_image_scanner_set_config(scanner, 0, ZBAR_CFG_ENABLE, 1); zbar_image_scanner_set_config(scanner, 0, ZBAR_CFG_ENABLE, 1);
} }
void void
mp_zbar_pipeline_start() mp_zbar_pipeline_start()
{ {
pipeline = mp_pipeline_new(); pipeline = mp_pipeline_new();
mp_pipeline_invoke(pipeline, setup, NULL, 0); mp_pipeline_invoke(pipeline, setup, NULL, 0);
} }
void void
mp_zbar_pipeline_stop() mp_zbar_pipeline_stop()
{ {
mp_pipeline_free(pipeline); mp_pipeline_free(pipeline);
} }
static bool static bool
is_3d_code(zbar_symbol_type_t type) is_3d_code(zbar_symbol_type_t type)
{ {
switch (type) { switch (type) {
case ZBAR_EAN2: case ZBAR_EAN2:
case ZBAR_EAN5: case ZBAR_EAN5:
case ZBAR_EAN8: case ZBAR_EAN8:
case ZBAR_UPCE: case ZBAR_UPCE:
case ZBAR_ISBN10: case ZBAR_ISBN10:
case ZBAR_UPCA: case ZBAR_UPCA:
case ZBAR_EAN13: case ZBAR_EAN13:
case ZBAR_ISBN13: case ZBAR_ISBN13:
case ZBAR_I25: case ZBAR_I25:
case ZBAR_DATABAR: case ZBAR_DATABAR:
case ZBAR_DATABAR_EXP: case ZBAR_DATABAR_EXP:
case ZBAR_CODABAR: case ZBAR_CODABAR:
case ZBAR_CODE39: case ZBAR_CODE39:
case ZBAR_CODE93: case ZBAR_CODE93:
case ZBAR_CODE128: case ZBAR_CODE128:
return false; return false;
case ZBAR_COMPOSITE: case ZBAR_COMPOSITE:
case ZBAR_PDF417: case ZBAR_PDF417:
case ZBAR_QRCODE: case ZBAR_QRCODE:
case ZBAR_SQCODE: case ZBAR_SQCODE:
return true; return true;
default: default:
return false; return false;
} }
} }
static inline void static inline void
map_coords(int *x, int *y, int width, int height, int rotation, bool mirrored) map_coords(int *x, int *y, int width, int height, int rotation, bool mirrored)
{ {
int x_r, y_r; int x_r, y_r;
if (rotation == 0) { if (rotation == 0) {
x_r = *x; x_r = *x;
y_r = *y; y_r = *y;
} else if (rotation == 90) { } else if (rotation == 90) {
x_r = *y; x_r = *y;
y_r = height - *x - 1; y_r = height - *x - 1;
} else if (rotation == 270) { } else if (rotation == 270) {
x_r = width - *y - 1; x_r = width - *y - 1;
y_r = *x; y_r = *x;
} else { } else {
x_r = width - *x - 1; x_r = width - *x - 1;
y_r = height - *y - 1; y_r = height - *y - 1;
} }
if (mirrored) { if (mirrored) {
x_r = width - x_r - 1; x_r = width - x_r - 1;
} }
*x = x_r; *x = x_r;
*y = y_r; *y = y_r;
} }
static MPZBarCode static MPZBarCode
process_symbol(const MPZBarImage *image, int width, int height, process_symbol(const MPZBarImage *image,
const zbar_symbol_t *symbol) int width,
int height,
const zbar_symbol_t *symbol)
{ {
if (image->rotation == 90 || image->rotation == 270) { if (image->rotation == 90 || image->rotation == 270) {
int tmp = width; int tmp = width;
width = height; width = height;
height = tmp; height = tmp;
} }
MPZBarCode code; MPZBarCode code;
unsigned loc_size = zbar_symbol_get_loc_size(symbol); unsigned loc_size = zbar_symbol_get_loc_size(symbol);
assert(loc_size > 0); assert(loc_size > 0);
zbar_symbol_type_t type = zbar_symbol_get_type(symbol); zbar_symbol_type_t type = zbar_symbol_get_type(symbol);
if (is_3d_code(type) && loc_size == 4) { if (is_3d_code(type) && loc_size == 4) {
for (unsigned i = 0; i < loc_size; ++i) { for (unsigned i = 0; i < loc_size; ++i) {
code.bounds_x[i] = zbar_symbol_get_loc_x(symbol, i); code.bounds_x[i] = zbar_symbol_get_loc_x(symbol, i);
code.bounds_y[i] = zbar_symbol_get_loc_y(symbol, i); code.bounds_y[i] = zbar_symbol_get_loc_y(symbol, i);
} }
} else { } else {
int min_x = zbar_symbol_get_loc_x(symbol, 0); int min_x = zbar_symbol_get_loc_x(symbol, 0);
int min_y = zbar_symbol_get_loc_y(symbol, 0); int min_y = zbar_symbol_get_loc_y(symbol, 0);
int max_x = min_x, max_y = min_y; int max_x = min_x, max_y = min_y;
for (unsigned i = 1; i < loc_size; ++i) { for (unsigned i = 1; i < loc_size; ++i) {
int x = zbar_symbol_get_loc_x(symbol, i); int x = zbar_symbol_get_loc_x(symbol, i);
int y = zbar_symbol_get_loc_y(symbol, i); int y = zbar_symbol_get_loc_y(symbol, i);
min_x = MIN(min_x, x); min_x = MIN(min_x, x);
min_y = MIN(min_y, y); min_y = MIN(min_y, y);
max_x = MAX(max_x, x); max_x = MAX(max_x, x);
max_y = MAX(max_y, y); max_y = MAX(max_y, y);
} }
code.bounds_x[0] = min_x; code.bounds_x[0] = min_x;
code.bounds_y[0] = min_y; code.bounds_y[0] = min_y;
code.bounds_x[1] = max_x; code.bounds_x[1] = max_x;
code.bounds_y[1] = min_y; code.bounds_y[1] = min_y;
code.bounds_x[2] = max_x; code.bounds_x[2] = max_x;
code.bounds_y[2] = max_y; code.bounds_y[2] = max_y;
code.bounds_x[3] = min_x; code.bounds_x[3] = min_x;
code.bounds_y[3] = max_y; code.bounds_y[3] = max_y;
} }
for (uint8_t i = 0; i < 4; ++i) { for (uint8_t i = 0; i < 4; ++i) {
map_coords(&code.bounds_x[i], &code.bounds_y[i], width, height, map_coords(&code.bounds_x[i],
image->rotation, image->mirrored); &code.bounds_y[i],
} width,
height,
image->rotation,
image->mirrored);
}
const char *data = zbar_symbol_get_data(symbol); const char *data = zbar_symbol_get_data(symbol);
unsigned int data_size = zbar_symbol_get_data_length(symbol); unsigned int data_size = zbar_symbol_get_data_length(symbol);
code.type = zbar_get_symbol_name(type); code.type = zbar_get_symbol_name(type);
code.data = strndup(data, data_size + 1); code.data = strndup(data, data_size + 1);
code.data[data_size] = 0; code.data[data_size] = 0;
return code; return code;
} }
static void static void
process_image(MPPipeline *pipeline, MPZBarImage **_image) process_image(MPPipeline *pipeline, MPZBarImage **_image)
{ {
MPZBarImage *image = *_image; MPZBarImage *image = *_image;
assert(image->pixel_format == MP_PIXEL_FMT_BGGR8 || assert(image->pixel_format == MP_PIXEL_FMT_BGGR8 ||
image->pixel_format == MP_PIXEL_FMT_GBRG8 || image->pixel_format == MP_PIXEL_FMT_GBRG8 ||
image->pixel_format == MP_PIXEL_FMT_GRBG8 || image->pixel_format == MP_PIXEL_FMT_GRBG8 ||
image->pixel_format == MP_PIXEL_FMT_RGGB8); image->pixel_format == MP_PIXEL_FMT_RGGB8);
// Create a grayscale image for scanning from the current preview. // Create a grayscale image for scanning from the current preview.
// Rotate/mirror correctly. // Rotate/mirror correctly.
int width = image->width / 2; int width = image->width / 2;
int height = image->height / 2; int height = image->height / 2;
uint8_t *data = malloc(width * height * sizeof(uint8_t)); uint8_t *data = malloc(width * height * sizeof(uint8_t));
size_t i = 0; size_t i = 0;
for (int y = 0; y < image->height; y += 2) { for (int y = 0; y < image->height; y += 2) {
for (int x = 0; x < image->width; x += 2) { for (int x = 0; x < image->width; x += 2) {
data[i++] = image->data[x + image->width * y]; data[i++] = image->data[x + image->width * y];
} }
} }
// Create image for zbar // Create image for zbar
zbar_image_t *zbar_image = zbar_image_create(); zbar_image_t *zbar_image = zbar_image_create();
zbar_image_set_format(zbar_image, zbar_fourcc('Y', '8', '0', '0')); zbar_image_set_format(zbar_image, zbar_fourcc('Y', '8', '0', '0'));
zbar_image_set_size(zbar_image, width, height); zbar_image_set_size(zbar_image, width, height);
zbar_image_set_data(zbar_image, data, width * height * sizeof(uint8_t), zbar_image_set_data(zbar_image,
zbar_image_free_data); data,
width * height * sizeof(uint8_t),
zbar_image_free_data);
int res = zbar_scan_image(scanner, zbar_image); int res = zbar_scan_image(scanner, zbar_image);
assert(res >= 0); assert(res >= 0);
if (res > 0) { if (res > 0) {
MPZBarScanResult *result = malloc(sizeof(MPZBarScanResult)); MPZBarScanResult *result = malloc(sizeof(MPZBarScanResult));
result->size = res; result->size = res;
const zbar_symbol_t *symbol = zbar_image_first_symbol(zbar_image); const zbar_symbol_t *symbol = zbar_image_first_symbol(zbar_image);
for (int i = 0; i < MIN(res, 8); ++i) { for (int i = 0; i < MIN(res, 8); ++i) {
assert(symbol != NULL); assert(symbol != NULL);
result->codes[i] = result->codes[i] =
process_symbol(image, width, height, symbol); process_symbol(image, width, height, symbol);
symbol = zbar_symbol_next(symbol); symbol = zbar_symbol_next(symbol);
} }
mp_main_set_zbar_result(result); mp_main_set_zbar_result(result);
} else { } else {
mp_main_set_zbar_result(NULL); mp_main_set_zbar_result(NULL);
} }
zbar_image_destroy(zbar_image); zbar_image_destroy(zbar_image);
mp_zbar_image_unref(image); mp_zbar_image_unref(image);
++frames_processed; ++frames_processed;
} }
void void
mp_zbar_pipeline_process_image(MPZBarImage *image) mp_zbar_pipeline_process_image(MPZBarImage *image)
{ {
// If we haven't processed the previous frame yet, drop this one // If we haven't processed the previous frame yet, drop this one
if (frames_received != frames_processed) { if (frames_received != frames_processed) {
mp_zbar_image_unref(image); mp_zbar_image_unref(image);
return; return;
} }
++frames_received; ++frames_received;
mp_pipeline_invoke(pipeline, (MPPipelineCallback)process_image, &image, mp_pipeline_invoke(pipeline,
sizeof(MPZBarImage *)); (MPPipelineCallback)process_image,
&image,
sizeof(MPZBarImage *));
} }
MPZBarImage * MPZBarImage *
mp_zbar_image_new(uint8_t *data, MPPixelFormat pixel_format, int width, int height, mp_zbar_image_new(uint8_t *data,
int rotation, bool mirrored) MPPixelFormat pixel_format,
int width,
int height,
int rotation,
bool mirrored)
{ {
MPZBarImage *image = malloc(sizeof(MPZBarImage)); MPZBarImage *image = malloc(sizeof(MPZBarImage));
image->data = data; image->data = data;
image->pixel_format = pixel_format; image->pixel_format = pixel_format;
image->width = width; image->width = width;
image->height = height; image->height = height;
image->rotation = rotation; image->rotation = rotation;
image->mirrored = mirrored; image->mirrored = mirrored;
image->ref_count = 1; image->ref_count = 1;
return image; return image;
} }
MPZBarImage * MPZBarImage *
mp_zbar_image_ref(MPZBarImage *image) mp_zbar_image_ref(MPZBarImage *image)
{ {
++image->ref_count; ++image->ref_count;
return image; return image;
} }
void void
mp_zbar_image_unref(MPZBarImage *image) mp_zbar_image_unref(MPZBarImage *image)
{ {
if (--image->ref_count == 0) { if (--image->ref_count == 0) {
free(image->data); free(image->data);
free(image); free(image);
} }
} }

View File

@@ -5,15 +5,15 @@
typedef struct _MPZBarImage MPZBarImage; typedef struct _MPZBarImage MPZBarImage;
typedef struct { typedef struct {
int bounds_x[4]; int bounds_x[4];
int bounds_y[4]; int bounds_y[4];
char *data; char *data;
const char *type; const char *type;
} MPZBarCode; } MPZBarCode;
typedef struct { typedef struct {
MPZBarCode codes[8]; MPZBarCode codes[8];
uint8_t size; uint8_t size;
} MPZBarScanResult; } MPZBarScanResult;
void mp_zbar_pipeline_start(); void mp_zbar_pipeline_start();
@@ -21,7 +21,11 @@ void mp_zbar_pipeline_stop();
void mp_zbar_pipeline_process_image(MPZBarImage *image); void mp_zbar_pipeline_process_image(MPZBarImage *image);
MPZBarImage *mp_zbar_image_new(uint8_t *data, MPPixelFormat pixel_format, int width, MPZBarImage *mp_zbar_image_new(uint8_t *data,
int height, int rotation, bool mirrored); MPPixelFormat pixel_format,
int width,
int height,
int rotation,
bool mirrored);
MPZBarImage *mp_zbar_image_ref(MPZBarImage *image); MPZBarImage *mp_zbar_image_ref(MPZBarImage *image);
void mp_zbar_image_unref(MPZBarImage *image); void mp_zbar_image_unref(MPZBarImage *image);

View File

@@ -9,203 +9,208 @@
double double
get_time() get_time()
{ {
struct timeval t; struct timeval t;
struct timezone tzp; struct timezone tzp;
gettimeofday(&t, &tzp); gettimeofday(&t, &tzp);
return t.tv_sec + t.tv_usec * 1e-6; return t.tv_sec + t.tv_usec * 1e-6;
} }
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
if (argc != 2 && argc != 3) { if (argc != 2 && argc != 3) {
printf("Usage: %s <media_device_name> [<sub_device_name>]\n", printf("Usage: %s <media_device_name> [<sub_device_name>]\n",
argv[0]); argv[0]);
return 1; return 1;
} }
char *video_name = argv[1]; char *video_name = argv[1];
char *subdev_name = NULL; char *subdev_name = NULL;
if (argc == 3) { if (argc == 3) {
subdev_name = argv[2]; subdev_name = argv[2];
} }
double find_start = get_time(); double find_start = get_time();
// First find the device // First find the device
MPDevice *device = mp_device_find(video_name); MPDevice *device = mp_device_find(video_name);
if (!device) { if (!device) {
printf("Device not found\n"); printf("Device not found\n");
return 1; return 1;
} }
double find_end = get_time(); double find_end = get_time();
printf("Finding the device took %fms\n", (find_end - find_start) * 1000); printf("Finding the device took %fms\n", (find_end - find_start) * 1000);
int video_fd; int video_fd;
uint32_t video_entity_id; uint32_t video_entity_id;
{ {
const struct media_v2_entity *entity = const struct media_v2_entity *entity =
mp_device_find_entity(device, video_name); mp_device_find_entity(device, video_name);
if (!entity) { if (!entity) {
printf("Unable to find video device interface\n"); printf("Unable to find video device interface\n");
return 1; return 1;
} }
video_entity_id = entity->id; video_entity_id = entity->id;
const struct media_v2_interface *iface = const struct media_v2_interface *iface =
mp_device_find_entity_interface(device, video_entity_id); mp_device_find_entity_interface(device, video_entity_id);
char buf[256]; char buf[256];
if (!mp_find_device_path(iface->devnode, buf, 256)) { if (!mp_find_device_path(iface->devnode, buf, 256)) {
printf("Unable to find video device path\n"); printf("Unable to find video device path\n");
return 1; return 1;
} }
video_fd = open(buf, O_RDWR); video_fd = open(buf, O_RDWR);
if (video_fd == -1) { if (video_fd == -1) {
printf("Unable to open video device\n"); printf("Unable to open video device\n");
return 1; return 1;
} }
} }
int subdev_fd = -1; int subdev_fd = -1;
if (subdev_name) { if (subdev_name) {
const struct media_v2_entity *entity = const struct media_v2_entity *entity =
mp_device_find_entity(device, subdev_name); mp_device_find_entity(device, subdev_name);
if (!entity) { if (!entity) {
printf("Unable to find sub-device\n"); printf("Unable to find sub-device\n");
return 1; return 1;
} }
const struct media_v2_pad *source_pad = const struct media_v2_pad *source_pad =
mp_device_get_pad_from_entity(device, entity->id); mp_device_get_pad_from_entity(device, entity->id);
const struct media_v2_pad *sink_pad = const struct media_v2_pad *sink_pad =
mp_device_get_pad_from_entity(device, video_entity_id); mp_device_get_pad_from_entity(device, video_entity_id);
// Disable other links // Disable other links
const struct media_v2_entity *entities = const struct media_v2_entity *entities =
mp_device_get_entities(device); mp_device_get_entities(device);
for (int i = 0; i < mp_device_get_num_entities(device); ++i) { for (int i = 0; i < mp_device_get_num_entities(device); ++i) {
if (entities[i].id != video_entity_id && if (entities[i].id != video_entity_id &&
entities[i].id != entity->id) { entities[i].id != entity->id) {
const struct media_v2_pad *pad = const struct media_v2_pad *pad =
mp_device_get_pad_from_entity( mp_device_get_pad_from_entity(
device, entities[i].id); device, entities[i].id);
mp_device_setup_link(device, pad->id, sink_pad->id, mp_device_setup_link(
false); device, pad->id, sink_pad->id, false);
} }
} }
// Then enable ours // Then enable ours
mp_device_setup_link(device, source_pad->id, sink_pad->id, true); mp_device_setup_link(device, source_pad->id, sink_pad->id, true);
const struct media_v2_interface *iface = const struct media_v2_interface *iface =
mp_device_find_entity_interface(device, entity->id); mp_device_find_entity_interface(device, entity->id);
char buf[256]; char buf[256];
if (!mp_find_device_path(iface->devnode, buf, 256)) { if (!mp_find_device_path(iface->devnode, buf, 256)) {
printf("Unable to find sub-device path\n"); printf("Unable to find sub-device path\n");
return 1; return 1;
} }
subdev_fd = open(buf, O_RDWR); subdev_fd = open(buf, O_RDWR);
if (subdev_fd == -1) { if (subdev_fd == -1) {
printf("Unable to open sub-device\n"); printf("Unable to open sub-device\n");
return 1; return 1;
} }
} }
double open_end = get_time(); double open_end = get_time();
printf("Opening the device took %fms\n", (open_end - find_end) * 1000); printf("Opening the device took %fms\n", (open_end - find_end) * 1000);
MPCamera *camera = mp_camera_new(video_fd, subdev_fd); MPCamera *camera = mp_camera_new(video_fd, subdev_fd);
MPControlList *controls = mp_camera_list_controls(camera); MPControlList *controls = mp_camera_list_controls(camera);
double control_list_end = get_time(); double control_list_end = get_time();
printf("Available controls: (took %fms)\n", printf("Available controls: (took %fms)\n",
(control_list_end - open_end) * 1000); (control_list_end - open_end) * 1000);
for (MPControlList *list = controls; list; for (MPControlList *list = controls; list;
list = mp_control_list_next(list)) { list = mp_control_list_next(list)) {
MPControl *c = mp_control_list_get(list); MPControl *c = mp_control_list_get(list);
printf(" %32s id:%s type:%s default:%d\n", c->name, printf(" %32s id:%s type:%s default:%d\n",
mp_control_id_to_str(c->id), mp_control_type_to_str(c->type), c->name,
c->default_value); mp_control_id_to_str(c->id),
} mp_control_type_to_str(c->type),
c->default_value);
}
double mode_list_begin = get_time(); double mode_list_begin = get_time();
MPCameraModeList *modes = mp_camera_list_available_modes(camera); MPCameraModeList *modes = mp_camera_list_available_modes(camera);
double mode_list_end = get_time(); double mode_list_end = get_time();
printf("Available modes: (took %fms)\n", printf("Available modes: (took %fms)\n",
(mode_list_end - mode_list_begin) * 1000); (mode_list_end - mode_list_begin) * 1000);
for (MPCameraModeList *list = modes; list; for (MPCameraModeList *list = modes; list;
list = mp_camera_mode_list_next(list)) { list = mp_camera_mode_list_next(list)) {
MPCameraMode *m = mp_camera_mode_list_get(list); MPCameraMode *m = mp_camera_mode_list_get(list);
printf(" %dx%d interval:%d/%d fmt:%s\n", m->width, m->height, printf(" %dx%d interval:%d/%d fmt:%s\n",
m->frame_interval.numerator, m->frame_interval.denominator, m->width,
mp_pixel_format_to_str(m->pixel_format)); m->height,
m->frame_interval.numerator,
m->frame_interval.denominator,
mp_pixel_format_to_str(m->pixel_format));
// Skip really slow framerates // Skip really slow framerates
if (m->frame_interval.denominator < 15) { if (m->frame_interval.denominator < 15) {
printf(" Skipping…\n"); printf(" Skipping…\n");
continue; continue;
} }
double start_capture = get_time(); double start_capture = get_time();
mp_camera_set_mode(camera, m); mp_camera_set_mode(camera, m);
mp_camera_start_capture(camera); mp_camera_start_capture(camera);
double last = get_time(); double last = get_time();
printf(" Testing 10 captures, starting took %fms\n", printf(" Testing 10 captures, starting took %fms\n",
(last - start_capture) * 1000); (last - start_capture) * 1000);
for (int i = 0; i < 10; ++i) { for (int i = 0; i < 10; ++i) {
MPBuffer buffer; MPBuffer buffer;
if (!mp_camera_capture_buffer(camera, &buffer)) { if (!mp_camera_capture_buffer(camera, &buffer)) {
printf(" Failed to capture buffer\n"); printf(" Failed to capture buffer\n");
} }
size_t num_bytes = mp_pixel_format_width_to_bytes( size_t num_bytes = mp_pixel_format_width_to_bytes(
m->pixel_format, m->width) * m->pixel_format, m->width) *
m->height; m->height;
uint8_t *data = malloc(num_bytes); uint8_t *data = malloc(num_bytes);
memcpy(data, buffer.data, num_bytes); memcpy(data, buffer.data, num_bytes);
printf(" first byte: %d.", data[0]); printf(" first byte: %d.", data[0]);
free(data); free(data);
mp_camera_release_buffer(camera, buffer.index); mp_camera_release_buffer(camera, buffer.index);
double now = get_time(); double now = get_time();
printf(" capture took %fms\n", (now - last) * 1000); printf(" capture took %fms\n", (now - last) * 1000);
last = now; last = now;
} }
mp_camera_stop_capture(camera); mp_camera_stop_capture(camera);
} }
double cleanup_start = get_time(); double cleanup_start = get_time();
mp_camera_free(camera); mp_camera_free(camera);
close(video_fd); close(video_fd);
if (subdev_fd != -1) if (subdev_fd != -1)
close(subdev_fd); close(subdev_fd);
mp_device_close(device); mp_device_close(device);
double cleanup_end = get_time(); double cleanup_end = get_time();
printf("Cleanup took %fms\n", (cleanup_end - cleanup_start) * 1000); printf("Cleanup took %fms\n", (cleanup_end - cleanup_start) * 1000);
} }

View File

@@ -5,56 +5,65 @@
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
MPDeviceList *list = mp_device_list_new(); MPDeviceList *list = mp_device_list_new();
while (list) { while (list) {
MPDevice *device = mp_device_list_get(list); MPDevice *device = mp_device_list_get(list);
const struct media_device_info *info = mp_device_get_info(device); const struct media_device_info *info = mp_device_get_info(device);
printf("%s (%s) %s\n", info->model, info->driver, info->serial); printf("%s (%s) %s\n", info->model, info->driver, info->serial);
printf(" Bus Info: %s\n", info->bus_info); printf(" Bus Info: %s\n", info->bus_info);
printf(" Media Version: %d\n", info->media_version); printf(" Media Version: %d\n", info->media_version);
printf(" HW Revision: %d\n", info->hw_revision); printf(" HW Revision: %d\n", info->hw_revision);
printf(" Driver Version: %d\n", info->driver_version); printf(" Driver Version: %d\n", info->driver_version);
const struct media_v2_entity *entities = const struct media_v2_entity *entities =
mp_device_get_entities(device); mp_device_get_entities(device);
size_t num = mp_device_get_num_entities(device); size_t num = mp_device_get_num_entities(device);
printf(" Entities (%ld):\n", num); printf(" Entities (%ld):\n", num);
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
printf(" %d %s (%d)\n", entities[i].id, entities[i].name, printf(" %d %s (%d)\n",
entities[i].function); entities[i].id,
} entities[i].name,
entities[i].function);
}
const struct media_v2_interface *interfaces = const struct media_v2_interface *interfaces =
mp_device_get_interfaces(device); mp_device_get_interfaces(device);
num = mp_device_get_num_interfaces(device); num = mp_device_get_num_interfaces(device);
printf(" Interfaces (%ld):\n", num); printf(" Interfaces (%ld):\n", num);
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
printf(" %d (%d - %d) devnode %d:%d\n", interfaces[i].id, printf(" %d (%d - %d) devnode %d:%d\n",
interfaces[i].intf_type, interfaces[i].flags, interfaces[i].id,
interfaces[i].devnode.major, interfaces[i].intf_type,
interfaces[i].devnode.minor); interfaces[i].flags,
} interfaces[i].devnode.major,
interfaces[i].devnode.minor);
}
const struct media_v2_pad *pads = mp_device_get_pads(device); const struct media_v2_pad *pads = mp_device_get_pads(device);
num = mp_device_get_num_pads(device); num = mp_device_get_num_pads(device);
printf(" Pads (%ld):\n", num); printf(" Pads (%ld):\n", num);
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
printf(" %d for device:%d (%d)\n", pads[i].id, printf(" %d for device:%d (%d)\n",
pads[i].entity_id, pads[i].flags); pads[i].id,
} pads[i].entity_id,
pads[i].flags);
}
const struct media_v2_link *links = mp_device_get_links(device); const struct media_v2_link *links = mp_device_get_links(device);
num = mp_device_get_num_links(device); num = mp_device_get_num_links(device);
printf(" Links (%ld):\n", num); printf(" Links (%ld):\n", num);
for (int i = 0; i < num; ++i) { for (int i = 0; i < num; ++i) {
printf(" %d from:%d to:%d (%d)\n", links[i].id, printf(" %d from:%d to:%d (%d)\n",
links[i].source_id, links[i].sink_id, links[i].flags); links[i].id,
} links[i].source_id,
links[i].sink_id,
links[i].flags);
}
list = mp_device_list_next(list); list = mp_device_list_next(list);
} }
mp_device_list_free(list); mp_device_list_free(list);
} }