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:
@@ -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
|
||||||
...
|
...
|
||||||
|
@@ -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:
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -7,5 +7,5 @@ uniform vec4 color;
|
|||||||
void
|
void
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
gl_FragColor = color;
|
gl_FragColor = color;
|
||||||
}
|
}
|
||||||
|
@@ -7,5 +7,5 @@ attribute vec2 vert;
|
|||||||
void
|
void
|
||||||
main()
|
main()
|
||||||
{
|
{
|
||||||
gl_Position = vec4(vert, 0, 1);
|
gl_Position = vec4(vert, 0, 1);
|
||||||
}
|
}
|
||||||
|
1903
src/camera.c
1903
src/camera.c
File diff suppressed because it is too large
Load Diff
66
src/camera.h
66
src/camera.h
@@ -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);
|
||||||
|
@@ -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];
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
493
src/device.c
493
src/device.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
28
src/device.h
28
src/device.h
@@ -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);
|
||||||
|
240
src/flash.c
240
src/flash.c
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
358
src/gl_util.c
358
src/gl_util.c
@@ -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();
|
||||||
}
|
}
|
||||||
|
@@ -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();
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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));
|
||||||
}
|
}
|
||||||
|
@@ -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
1287
src/main.c
File diff suppressed because it is too large
Load Diff
26
src/main.h
26
src/main.h
@@ -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);
|
||||||
|
28
src/matrix.c
28
src/matrix.c
@@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
149
src/pipeline.c
149
src/pipeline.c
@@ -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;
|
||||||
}
|
}
|
||||||
|
@@ -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
@@ -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();
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
@@ -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);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user