Selaa lähdekoodia

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.
Benjamin Schaaf 2 vuotta sitten
vanhempi
commit
772db36877
32 muutettua tiedostoa jossa 4563 lisäystä ja 4269 poistoa
  1. 28 28
      .clang-format
  2. 0 6
      .gitlab-ci.yml
  3. 1 1
      data/blit.frag
  4. 2 2
      data/blit.vert
  5. 21 20
      data/debayer.frag
  6. 5 5
      data/debayer.vert
  7. 1 1
      data/solid.frag
  8. 1 1
      data/solid.vert
  9. 1045 1030
      src/camera.c
  10. 34 34
      src/camera.h
  11. 244 228
      src/camera_config.c
  12. 33 33
      src/camera_config.h
  13. 255 250
      src/device.c
  14. 15 13
      src/device.h
  15. 131 117
      src/flash.c
  16. 213 197
      src/gl_util.c
  17. 4 2
      src/gl_util.h
  18. 108 100
      src/gles2_debayer.c
  19. 9 5
      src/gles2_debayer.h
  20. 460 444
      src/io_pipeline.c
  21. 11 11
      src/io_pipeline.h
  22. 745 648
      src/main.c
  23. 13 13
      src/main.h
  24. 14 14
      src/matrix.c
  25. 85 76
      src/pipeline.c
  26. 8 5
      src/pipeline.h
  27. 594 534
      src/process_pipeline.c
  28. 14 14
      src/process_pipeline.h
  29. 209 195
      src/zbar_pipeline.c
  30. 12 8
      src/zbar_pipeline.h
  31. 187 182
      tools/camera_test.c
  32. 61 52
      tools/list_devices.c

+ 28 - 28
.clang-format

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

+ 0 - 6
.gitlab-ci.yml

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

+ 1 - 1
data/blit.frag

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

+ 2 - 2
data/blit.vert

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

+ 21 - 20
data/debayer.frag

@@ -13,30 +13,31 @@ varying vec2 bottom_right_uv;
 void
 main()
 {
-	// 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
-	// they end up as 16-bit floats and that's not accurate enough.
-	vec4 samples = vec4(texture2D(texture, top_left_uv).r,
-			    texture2D(texture, top_right_uv).r,
-			    texture2D(texture, bottom_left_uv).r,
-			    texture2D(texture, bottom_right_uv).r);
+        // 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
+        // they end up as 16-bit floats and that's not accurate enough.
+        vec4 samples = vec4(texture2D(texture, top_left_uv).r,
+                            texture2D(texture, top_right_uv).r,
+                            texture2D(texture, bottom_left_uv).r,
+                            texture2D(texture, bottom_right_uv).r);
 
-	// 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.
-	vec3 color = vec3(samples.w, (samples.y + samples.z) / 2.0, samples.x);
+        // 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.
+        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
-	vec3 corrected = color - 0.02;
+        // Some crude blacklevel correction to make the preview a bit nicer, this
+        // should be an uniform
+        vec3 corrected = color - 0.02;
 
-	// Apply the color matrices
-	//vec3 corrected = color_matrix * color2;
+        // Apply the color matrices
+        // vec3 corrected = color_matrix * color2;
 
-	// Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/
-	vec3 srgb_color =
-		(vec3(1.138) * inversesqrt(corrected) - vec3(0.138)) * corrected;
+        // Fast SRGB estimate. See https://mimosa-pudica.net/fast-gamma/
+        vec3 srgb_color =
+                (vec3(1.138) * inversesqrt(corrected) - vec3(0.138)) * corrected;
 
-	// Slow SRGB estimate
-	// vec3 srgb_color = pow(color, vec3(1.0 / 2.2));
+        // Slow SRGB estimate
+        // vec3 srgb_color = pow(color, vec3(1.0 / 2.2));
 
-	gl_FragColor = vec4(srgb_color, 1);
+        gl_FragColor = vec4(srgb_color, 1);
 }

+ 5 - 5
data/debayer.vert

@@ -16,10 +16,10 @@ varying vec2 bottom_right_uv;
 void
 main()
 {
-	top_left_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);
-	bottom_left_uv = vec2(bottom_right_uv.x, top_left_uv.y);
+        top_left_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);
+        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);
 }

+ 1 - 1
data/solid.frag

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

+ 1 - 1
data/solid.vert

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

+ 1045 - 1030
src/camera.c

@@ -13,1360 +13,1375 @@
 #define MAX_BG_TASKS 8
 
 static const char *pixel_format_names[MP_PIXEL_FMT_MAX] = {
-	"unsupported", "BGGR8",	  "GBRG8",   "GRBG8", "RGGB8", "BGGR10P",
-	"GBRG10P",     "GRBG10P", "RGGB10P", "UYVY",  "YUYV",
+        "unsupported", "BGGR8",   "GBRG8",   "GRBG8", "RGGB8", "BGGR10P",
+        "GBRG10P",     "GRBG10P", "RGGB10P", "UYVY",  "YUYV",
 };
 
 const char *
 mp_pixel_format_to_str(uint32_t pixel_format)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, "INVALID");
-	return pixel_format_names[pixel_format];
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, "INVALID");
+        return pixel_format_names[pixel_format];
 }
 
 MPPixelFormat
 mp_pixel_format_from_str(const char *name)
 {
-	for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
-		if (strcasecmp(pixel_format_names[i], name) == 0) {
-			return i;
-		}
-	}
-	g_return_val_if_reached(MP_PIXEL_FMT_UNSUPPORTED);
+        for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
+                if (strcasecmp(pixel_format_names[i], name) == 0) {
+                        return i;
+                }
+        }
+        g_return_val_if_reached(MP_PIXEL_FMT_UNSUPPORTED);
 }
 
 static const uint32_t pixel_format_v4l_pixel_formats[MP_PIXEL_FMT_MAX] = {
-	0,
-	V4L2_PIX_FMT_SBGGR8,
-	V4L2_PIX_FMT_SGBRG8,
-	V4L2_PIX_FMT_SGRBG8,
-	V4L2_PIX_FMT_SRGGB8,
-	V4L2_PIX_FMT_SBGGR10P,
-	V4L2_PIX_FMT_SGBRG10P,
-	V4L2_PIX_FMT_SGRBG10P,
-	V4L2_PIX_FMT_SRGGB10P,
-	V4L2_PIX_FMT_UYVY,
-	V4L2_PIX_FMT_YUYV,
+        0,
+        V4L2_PIX_FMT_SBGGR8,
+        V4L2_PIX_FMT_SGBRG8,
+        V4L2_PIX_FMT_SGRBG8,
+        V4L2_PIX_FMT_SRGGB8,
+        V4L2_PIX_FMT_SBGGR10P,
+        V4L2_PIX_FMT_SGBRG10P,
+        V4L2_PIX_FMT_SGRBG10P,
+        V4L2_PIX_FMT_SRGGB10P,
+        V4L2_PIX_FMT_UYVY,
+        V4L2_PIX_FMT_YUYV,
 };
 
 uint32_t
 mp_pixel_format_to_v4l_pixel_format(MPPixelFormat pixel_format)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
-	return pixel_format_v4l_pixel_formats[pixel_format];
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
+        return pixel_format_v4l_pixel_formats[pixel_format];
 }
 
 MPPixelFormat
 mp_pixel_format_from_v4l_pixel_format(uint32_t v4l_pixel_format)
 {
-	for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
-		if (pixel_format_v4l_pixel_formats[i] == v4l_pixel_format) {
-			return i;
-		}
-	}
-	return MP_PIXEL_FMT_UNSUPPORTED;
+        for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
+                if (pixel_format_v4l_pixel_formats[i] == v4l_pixel_format) {
+                        return i;
+                }
+        }
+        return MP_PIXEL_FMT_UNSUPPORTED;
 }
 
 static const uint32_t pixel_format_v4l_bus_codes[MP_PIXEL_FMT_MAX] = {
-	0,
-	MEDIA_BUS_FMT_SBGGR8_1X8,
-	MEDIA_BUS_FMT_SGBRG8_1X8,
-	MEDIA_BUS_FMT_SGRBG8_1X8,
-	MEDIA_BUS_FMT_SRGGB8_1X8,
-	MEDIA_BUS_FMT_SBGGR10_1X10,
-	MEDIA_BUS_FMT_SGBRG10_1X10,
-	MEDIA_BUS_FMT_SGRBG10_1X10,
-	MEDIA_BUS_FMT_SRGGB10_1X10,
-	MEDIA_BUS_FMT_UYVY8_2X8,
-	MEDIA_BUS_FMT_YUYV8_2X8,
+        0,
+        MEDIA_BUS_FMT_SBGGR8_1X8,
+        MEDIA_BUS_FMT_SGBRG8_1X8,
+        MEDIA_BUS_FMT_SGRBG8_1X8,
+        MEDIA_BUS_FMT_SRGGB8_1X8,
+        MEDIA_BUS_FMT_SBGGR10_1X10,
+        MEDIA_BUS_FMT_SGBRG10_1X10,
+        MEDIA_BUS_FMT_SGRBG10_1X10,
+        MEDIA_BUS_FMT_SRGGB10_1X10,
+        MEDIA_BUS_FMT_UYVY8_2X8,
+        MEDIA_BUS_FMT_YUYV8_2X8,
 };
 
 uint32_t
 mp_pixel_format_to_v4l_bus_code(MPPixelFormat pixel_format)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
-	return pixel_format_v4l_bus_codes[pixel_format];
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
+        return pixel_format_v4l_bus_codes[pixel_format];
 }
 
 MPPixelFormat
 mp_pixel_format_from_v4l_bus_code(uint32_t v4l_bus_code)
 {
-	for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
-		if (pixel_format_v4l_bus_codes[i] == v4l_bus_code) {
-			return i;
-		}
-	}
-	return MP_PIXEL_FMT_UNSUPPORTED;
+        for (MPPixelFormat i = 0; i < MP_PIXEL_FMT_MAX; ++i) {
+                if (pixel_format_v4l_bus_codes[i] == v4l_bus_code) {
+                        return i;
+                }
+        }
+        return MP_PIXEL_FMT_UNSUPPORTED;
 }
 
 uint32_t
 mp_pixel_format_bits_per_pixel(MPPixelFormat pixel_format)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
-	switch (pixel_format) {
-	case MP_PIXEL_FMT_BGGR8:
-	case MP_PIXEL_FMT_GBRG8:
-	case MP_PIXEL_FMT_GRBG8:
-	case MP_PIXEL_FMT_RGGB8:
-		return 8;
-	case MP_PIXEL_FMT_BGGR10P:
-	case MP_PIXEL_FMT_GBRG10P:
-	case MP_PIXEL_FMT_GRBG10P:
-	case MP_PIXEL_FMT_RGGB10P:
-		return 10;
-	case MP_PIXEL_FMT_UYVY:
-	case MP_PIXEL_FMT_YUYV:
-		return 16;
-	default:
-		return 0;
-	}
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
+        switch (pixel_format) {
+        case MP_PIXEL_FMT_BGGR8:
+        case MP_PIXEL_FMT_GBRG8:
+        case MP_PIXEL_FMT_GRBG8:
+        case MP_PIXEL_FMT_RGGB8:
+                return 8;
+        case MP_PIXEL_FMT_BGGR10P:
+        case MP_PIXEL_FMT_GBRG10P:
+        case MP_PIXEL_FMT_GRBG10P:
+        case MP_PIXEL_FMT_RGGB10P:
+                return 10;
+        case MP_PIXEL_FMT_UYVY:
+        case MP_PIXEL_FMT_YUYV:
+                return 16;
+        default:
+                return 0;
+        }
 }
 
 uint32_t
 mp_pixel_format_pixel_depth(MPPixelFormat pixel_format)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
-	switch (pixel_format) {
-	case MP_PIXEL_FMT_BGGR8:
-	case MP_PIXEL_FMT_GBRG8:
-	case MP_PIXEL_FMT_GRBG8:
-	case MP_PIXEL_FMT_RGGB8:
-	case MP_PIXEL_FMT_UYVY:
-	case MP_PIXEL_FMT_YUYV:
-		return 8;
-	case MP_PIXEL_FMT_GBRG10P:
-	case MP_PIXEL_FMT_GRBG10P:
-	case MP_PIXEL_FMT_RGGB10P:
-	case MP_PIXEL_FMT_BGGR10P:
-		return 10;
-	default:
-		return 0;
-	}
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
+        switch (pixel_format) {
+        case MP_PIXEL_FMT_BGGR8:
+        case MP_PIXEL_FMT_GBRG8:
+        case MP_PIXEL_FMT_GRBG8:
+        case MP_PIXEL_FMT_RGGB8:
+        case MP_PIXEL_FMT_UYVY:
+        case MP_PIXEL_FMT_YUYV:
+                return 8;
+        case MP_PIXEL_FMT_GBRG10P:
+        case MP_PIXEL_FMT_GRBG10P:
+        case MP_PIXEL_FMT_RGGB10P:
+        case MP_PIXEL_FMT_BGGR10P:
+                return 10;
+        default:
+                return 0;
+        }
 }
 
 uint32_t
 mp_pixel_format_width_to_bytes(MPPixelFormat pixel_format, uint32_t width)
 {
-	uint32_t bits_per_pixel = mp_pixel_format_bits_per_pixel(pixel_format);
-	uint64_t bits_per_width = width * (uint64_t)bits_per_pixel;
+        uint32_t bits_per_pixel = mp_pixel_format_bits_per_pixel(pixel_format);
+        uint64_t bits_per_width = width * (uint64_t)bits_per_pixel;
 
-	uint64_t remainder = bits_per_width % 8;
-	if (remainder == 0)
-		return bits_per_width / 8;
+        uint64_t remainder = bits_per_width % 8;
+        if (remainder == 0)
+                return bits_per_width / 8;
 
-	return (bits_per_width + 8 - remainder) / 8;
+        return (bits_per_width + 8 - remainder) / 8;
 }
 
 uint32_t
 mp_pixel_format_width_to_colors(MPPixelFormat pixel_format, uint32_t width)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
-	switch (pixel_format) {
-	case MP_PIXEL_FMT_BGGR8:
-	case MP_PIXEL_FMT_GBRG8:
-	case MP_PIXEL_FMT_GRBG8:
-	case MP_PIXEL_FMT_RGGB8:
-		return width / 2;
-	case MP_PIXEL_FMT_BGGR10P:
-	case MP_PIXEL_FMT_GBRG10P:
-	case MP_PIXEL_FMT_GRBG10P:
-	case MP_PIXEL_FMT_RGGB10P:
-		return width / 2 * 5;
-	case MP_PIXEL_FMT_UYVY:
-	case MP_PIXEL_FMT_YUYV:
-		return width;
-	default:
-		return 0;
-	}
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
+        switch (pixel_format) {
+        case MP_PIXEL_FMT_BGGR8:
+        case MP_PIXEL_FMT_GBRG8:
+        case MP_PIXEL_FMT_GRBG8:
+        case MP_PIXEL_FMT_RGGB8:
+                return width / 2;
+        case MP_PIXEL_FMT_BGGR10P:
+        case MP_PIXEL_FMT_GBRG10P:
+        case MP_PIXEL_FMT_GRBG10P:
+        case MP_PIXEL_FMT_RGGB10P:
+                return width / 2 * 5;
+        case MP_PIXEL_FMT_UYVY:
+        case MP_PIXEL_FMT_YUYV:
+                return width;
+        default:
+                return 0;
+        }
 }
 
 uint32_t
 mp_pixel_format_height_to_colors(MPPixelFormat pixel_format, uint32_t height)
 {
-	g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
-	switch (pixel_format) {
-	case MP_PIXEL_FMT_BGGR8:
-	case MP_PIXEL_FMT_GBRG8:
-	case MP_PIXEL_FMT_GRBG8:
-	case MP_PIXEL_FMT_RGGB8:
-	case MP_PIXEL_FMT_BGGR10P:
-	case MP_PIXEL_FMT_GBRG10P:
-	case MP_PIXEL_FMT_GRBG10P:
-	case MP_PIXEL_FMT_RGGB10P:
-		return height / 2;
-	case MP_PIXEL_FMT_UYVY:
-	case MP_PIXEL_FMT_YUYV:
-		return height;
-	default:
-		return 0;
-	}
+        g_return_val_if_fail(pixel_format < MP_PIXEL_FMT_MAX, 0);
+        switch (pixel_format) {
+        case MP_PIXEL_FMT_BGGR8:
+        case MP_PIXEL_FMT_GBRG8:
+        case MP_PIXEL_FMT_GRBG8:
+        case MP_PIXEL_FMT_RGGB8:
+        case MP_PIXEL_FMT_BGGR10P:
+        case MP_PIXEL_FMT_GBRG10P:
+        case MP_PIXEL_FMT_GRBG10P:
+        case MP_PIXEL_FMT_RGGB10P:
+                return height / 2;
+        case MP_PIXEL_FMT_UYVY:
+        case MP_PIXEL_FMT_YUYV:
+                return height;
+        default:
+                return 0;
+        }
 }
 
 bool
 mp_camera_mode_is_equivalent(const MPCameraMode *m1, const MPCameraMode *m2)
 {
-	return m1->pixel_format == m2->pixel_format &&
-	       m1->frame_interval.numerator == m2->frame_interval.numerator &&
-	       m1->frame_interval.denominator == m2->frame_interval.denominator &&
-	       m1->width == m2->width && m1->height == m2->height;
+        return m1->pixel_format == m2->pixel_format &&
+               m1->frame_interval.numerator == m2->frame_interval.numerator &&
+               m1->frame_interval.denominator == m2->frame_interval.denominator &&
+               m1->width == m2->width && m1->height == m2->height;
 }
 
 static void
 errno_printerr(const char *s)
 {
-	g_printerr("MPCamera: %s error %d, %s\n", s, errno, strerror(errno));
+        g_printerr("MPCamera: %s error %d, %s\n", s, errno, strerror(errno));
 }
 
 static int
 xioctl(int fd, int request, void *arg)
 {
-	int r;
-	do {
-		r = ioctl(fd, request, arg);
-	} while (r == -1 && errno == EINTR);
-	return r;
+        int r;
+        do {
+                r = ioctl(fd, request, arg);
+        } while (r == -1 && errno == EINTR);
+        return r;
 }
 
 struct video_buffer {
-	uint32_t length;
-	uint8_t *data;
-	int fd;
+        uint32_t length;
+        uint8_t *data;
+        int fd;
 };
 
 struct _MPCamera {
-	int video_fd;
-	int subdev_fd;
+        int video_fd;
+        int subdev_fd;
 
-	bool has_set_mode;
-	MPCameraMode current_mode;
+        bool has_set_mode;
+        MPCameraMode current_mode;
 
-	struct video_buffer buffers[MAX_VIDEO_BUFFERS];
-	uint32_t num_buffers;
+        struct video_buffer buffers[MAX_VIDEO_BUFFERS];
+        uint32_t num_buffers;
 
-	// keeping track of background task child-PIDs for cleanup code
-	int child_bg_pids[MAX_BG_TASKS];
+        // keeping track of background task child-PIDs for cleanup code
+        int child_bg_pids[MAX_BG_TASKS];
 
-	bool use_mplane;
+        bool use_mplane;
 };
 
 MPCamera *
 mp_camera_new(int video_fd, int subdev_fd)
 {
-	g_return_val_if_fail(video_fd != -1, NULL);
-
-	// Query capabilities
-	struct v4l2_capability cap;
-	if (xioctl(video_fd, VIDIOC_QUERYCAP, &cap) == -1) {
-		return NULL;
-	}
-
-	// Check whether this is a video capture device
-	bool use_mplane;
-	if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
-		use_mplane = true;
-		printf("!!\n");
-	} else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
-		use_mplane = false;
-	} else {
-		return NULL;
-	}
-
-	MPCamera *camera = malloc(sizeof(MPCamera));
-	camera->video_fd = video_fd;
-	camera->subdev_fd = subdev_fd;
-	camera->has_set_mode = false;
-	camera->num_buffers = 0;
-	camera->use_mplane = use_mplane;
-	memset(camera->child_bg_pids, 0,
-	       sizeof(camera->child_bg_pids[0]) * MAX_BG_TASKS);
-	return camera;
+        g_return_val_if_fail(video_fd != -1, NULL);
+
+        // Query capabilities
+        struct v4l2_capability cap;
+        if (xioctl(video_fd, VIDIOC_QUERYCAP, &cap) == -1) {
+                return NULL;
+        }
+
+        // Check whether this is a video capture device
+        bool use_mplane;
+        if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) {
+                use_mplane = true;
+                printf("!!\n");
+        } else if (cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) {
+                use_mplane = false;
+        } else {
+                return NULL;
+        }
+
+        MPCamera *camera = malloc(sizeof(MPCamera));
+        camera->video_fd = video_fd;
+        camera->subdev_fd = subdev_fd;
+        camera->has_set_mode = false;
+        camera->num_buffers = 0;
+        camera->use_mplane = use_mplane;
+        memset(camera->child_bg_pids,
+               0,
+               sizeof(camera->child_bg_pids[0]) * MAX_BG_TASKS);
+        return camera;
 }
 
 void
 mp_camera_free(MPCamera *camera)
 {
-	mp_camera_wait_bg_tasks(camera);
+        mp_camera_wait_bg_tasks(camera);
 
-	g_warn_if_fail(camera->num_buffers == 0);
-	if (camera->num_buffers != 0) {
-		mp_camera_stop_capture(camera);
-	}
+        g_warn_if_fail(camera->num_buffers == 0);
+        if (camera->num_buffers != 0) {
+                mp_camera_stop_capture(camera);
+        }
 
-	free(camera);
+        free(camera);
 }
 
 void
 mp_camera_add_bg_task(MPCamera *camera, pid_t pid)
 {
-	int status;
-	while (true) {
-		for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
-			if (camera->child_bg_pids[i] == 0) {
-				camera->child_bg_pids[i] = pid;
-				return;
-			} else {
-				// error == -1, still running == 0
-				if (waitpid(camera->child_bg_pids[i], &status,
-					    WNOHANG) <= 0)
-					continue; // consider errored wait still running
-
-				if (WIFEXITED(status)) {
-					// replace exited
-					camera->child_bg_pids[i] = pid;
-					return;
-				}
-			}
-		}
-
-		// wait for any status change on child processes
-		pid_t changed = waitpid(-1, &status, 0);
-		if (WIFEXITED(status)) {
-			// some child exited
-			for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
-				if (camera->child_bg_pids[i] == changed) {
-					camera->child_bg_pids[i] = pid;
-					return;
-				}
-			}
-		}
-
-		// no luck, repeat and check if something exited maybe
-	}
+        int status;
+        while (true) {
+                for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
+                        if (camera->child_bg_pids[i] == 0) {
+                                camera->child_bg_pids[i] = pid;
+                                return;
+                        } else {
+                                // error == -1, still running == 0
+                                if (waitpid(camera->child_bg_pids[i],
+                                            &status,
+                                            WNOHANG) <= 0)
+                                        continue; // consider errored wait still
+                                                  // running
+
+                                if (WIFEXITED(status)) {
+                                        // replace exited
+                                        camera->child_bg_pids[i] = pid;
+                                        return;
+                                }
+                        }
+                }
+
+                // wait for any status change on child processes
+                pid_t changed = waitpid(-1, &status, 0);
+                if (WIFEXITED(status)) {
+                        // some child exited
+                        for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
+                                if (camera->child_bg_pids[i] == changed) {
+                                        camera->child_bg_pids[i] = pid;
+                                        return;
+                                }
+                        }
+                }
+
+                // no luck, repeat and check if something exited maybe
+        }
 }
 
 void
 mp_camera_wait_bg_tasks(MPCamera *camera)
 {
-	for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
-		if (camera->child_bg_pids[i] != 0) {
-			// ignore errors
-			waitpid(camera->child_bg_pids[i], NULL, 0);
-		}
-	}
+        for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
+                if (camera->child_bg_pids[i] != 0) {
+                        // ignore errors
+                        waitpid(camera->child_bg_pids[i], NULL, 0);
+                }
+        }
 }
 
 bool
 mp_camera_check_task_complete(MPCamera *camera, pid_t pid)
 {
-	// this method is potentially unsafe because pid could already be reused at
-	// this point, but extremely unlikely so we won't implement this.
-	int status;
-
-	if (pid == 0)
-		return true;
-
-	// ignore errors (-1), no exit == 0
-	int pidchange = waitpid(pid, &status, WNOHANG);
-	if (pidchange == -1) // error or exists and runs
-		return false;
-
-	if (WIFEXITED(status)) {
-		for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
-			if (camera->child_bg_pids[i] == pid) {
-				camera->child_bg_pids[i] = 0;
-				break;
-			}
-		}
-		return true;
-	} else {
-		return false;
-	}
+        // this method is potentially unsafe because pid could already be reused at
+        // this point, but extremely unlikely so we won't implement this.
+        int status;
+
+        if (pid == 0)
+                return true;
+
+        // ignore errors (-1), no exit == 0
+        int pidchange = waitpid(pid, &status, WNOHANG);
+        if (pidchange == -1) // error or exists and runs
+                return false;
+
+        if (WIFEXITED(status)) {
+                for (size_t i = 0; i < MAX_BG_TASKS; ++i) {
+                        if (camera->child_bg_pids[i] == pid) {
+                                camera->child_bg_pids[i] = 0;
+                                break;
+                        }
+                }
+                return true;
+        } else {
+                return false;
+        }
 }
 
 bool
 mp_camera_is_subdev(MPCamera *camera)
 {
-	return camera->subdev_fd != -1;
+        return camera->subdev_fd != -1;
 }
 
 int
 mp_camera_get_video_fd(MPCamera *camera)
 {
-	return camera->video_fd;
+        return camera->video_fd;
 }
 
 int
 mp_camera_get_subdev_fd(MPCamera *camera)
 {
-	return camera->subdev_fd;
+        return camera->subdev_fd;
 }
 
 static bool
 camera_mode_impl(MPCamera *camera, int request, MPCameraMode *mode)
 {
-	uint32_t pixfmt = mp_pixel_format_from_v4l_pixel_format(mode->pixel_format);
-	struct v4l2_format fmt = {};
-	if (camera->use_mplane) {
-		fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-		fmt.fmt.pix_mp.width = mode->width;
-		fmt.fmt.pix_mp.height = mode->height;
-		fmt.fmt.pix_mp.pixelformat = pixfmt;
-		fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
-	} else {
-		fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		fmt.fmt.pix.width = mode->width;
-		fmt.fmt.pix.height = mode->height;
-		fmt.fmt.pix.pixelformat = pixfmt;
-		fmt.fmt.pix.field = V4L2_FIELD_ANY;
-	}
-
-	if (xioctl(camera->video_fd, request, &fmt) == -1) {
-		return false;
-	}
-
-	if (camera->use_mplane) {
-		mode->width = fmt.fmt.pix_mp.width;
-		mode->height = fmt.fmt.pix_mp.height;
-		mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
-			fmt.fmt.pix_mp.pixelformat);
-	} else {
-		mode->width = fmt.fmt.pix.width;
-		mode->height = fmt.fmt.pix.height;
-		mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
-			fmt.fmt.pix.pixelformat);
-	}
-
-	return true;
+        uint32_t pixfmt = mp_pixel_format_from_v4l_pixel_format(mode->pixel_format);
+        struct v4l2_format fmt = {};
+        if (camera->use_mplane) {
+                fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+                fmt.fmt.pix_mp.width = mode->width;
+                fmt.fmt.pix_mp.height = mode->height;
+                fmt.fmt.pix_mp.pixelformat = pixfmt;
+                fmt.fmt.pix_mp.field = V4L2_FIELD_ANY;
+        } else {
+                fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                fmt.fmt.pix.width = mode->width;
+                fmt.fmt.pix.height = mode->height;
+                fmt.fmt.pix.pixelformat = pixfmt;
+                fmt.fmt.pix.field = V4L2_FIELD_ANY;
+        }
+
+        if (xioctl(camera->video_fd, request, &fmt) == -1) {
+                return false;
+        }
+
+        if (camera->use_mplane) {
+                mode->width = fmt.fmt.pix_mp.width;
+                mode->height = fmt.fmt.pix_mp.height;
+                mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
+                        fmt.fmt.pix_mp.pixelformat);
+        } else {
+                mode->width = fmt.fmt.pix.width;
+                mode->height = fmt.fmt.pix.height;
+                mode->pixel_format = mp_pixel_format_from_v4l_pixel_format(
+                        fmt.fmt.pix.pixelformat);
+        }
+
+        return true;
 }
 
 bool
 mp_camera_try_mode(MPCamera *camera, MPCameraMode *mode)
 {
-	if (!camera_mode_impl(camera, VIDIOC_TRY_FMT, mode)) {
-		errno_printerr("VIDIOC_S_FMT");
-		return false;
-	}
-	return true;
+        if (!camera_mode_impl(camera, VIDIOC_TRY_FMT, mode)) {
+                errno_printerr("VIDIOC_S_FMT");
+                return false;
+        }
+        return true;
 }
 
 const MPCameraMode *
 mp_camera_get_mode(const MPCamera *camera)
 {
-	return &camera->current_mode;
+        return &camera->current_mode;
 }
 
 bool
 mp_camera_set_mode(MPCamera *camera, MPCameraMode *mode)
 {
-	// Set the mode in the subdev the camera is one
-	if (mp_camera_is_subdev(camera)) {
-		struct v4l2_subdev_frame_interval interval = {};
-		interval.pad = 0;
-		interval.interval = mode->frame_interval;
-		if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL,
-			   &interval) == -1) {
-			errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
-			return false;
-		}
-
-		bool did_set_frame_rate = interval.interval.numerator ==
-						  mode->frame_interval.numerator &&
-					  interval.interval.denominator ==
-						  mode->frame_interval.denominator;
-
-		struct v4l2_subdev_format fmt = {};
-		fmt.pad = 0;
-		fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
-		fmt.format.width = mode->width;
-		fmt.format.height = mode->height;
-		fmt.format.code =
-			mp_pixel_format_to_v4l_bus_code(mode->pixel_format);
-		fmt.format.field = V4L2_FIELD_ANY;
-		if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) {
-			errno_printerr("VIDIOC_SUBDEV_S_FMT");
-			return false;
-		}
-
-		// Some drivers like ov5640 don't allow you to set the frame format with
-		// too high a frame-rate, but that means the frame-rate won't be set
-		// after the format change. So we need to try again here if we didn't
-		// succeed before. Ideally we'd be able to set both at once.
-		if (!did_set_frame_rate) {
-			interval.interval = mode->frame_interval;
-			if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FRAME_INTERVAL,
-				   &interval) == -1) {
-				errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
-			}
-		}
-
-		// Update the mode
-		mode->pixel_format =
-			mp_pixel_format_from_v4l_bus_code(fmt.format.code);
-		mode->frame_interval = interval.interval;
-		mode->width = fmt.format.width;
-		mode->height = fmt.format.height;
-	}
-
-	// Set the mode for the video device
-	{
-		if (!camera_mode_impl(camera, VIDIOC_S_FMT, mode)) {
-			errno_printerr("VIDIOC_S_FMT");
-			return false;
-		}
-	}
-
-	camera->has_set_mode = true;
-	camera->current_mode = *mode;
-
-	return true;
+        // Set the mode in the subdev the camera is one
+        if (mp_camera_is_subdev(camera)) {
+                struct v4l2_subdev_frame_interval interval = {};
+                interval.pad = 0;
+                interval.interval = mode->frame_interval;
+                if (xioctl(camera->subdev_fd,
+                           VIDIOC_SUBDEV_S_FRAME_INTERVAL,
+                           &interval) == -1) {
+                        errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
+                        return false;
+                }
+
+                bool did_set_frame_rate = interval.interval.numerator ==
+                                                  mode->frame_interval.numerator &&
+                                          interval.interval.denominator ==
+                                                  mode->frame_interval.denominator;
+
+                struct v4l2_subdev_format fmt = {};
+                fmt.pad = 0;
+                fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+                fmt.format.width = mode->width;
+                fmt.format.height = mode->height;
+                fmt.format.code =
+                        mp_pixel_format_to_v4l_bus_code(mode->pixel_format);
+                fmt.format.field = V4L2_FIELD_ANY;
+                if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_S_FMT, &fmt) == -1) {
+                        errno_printerr("VIDIOC_SUBDEV_S_FMT");
+                        return false;
+                }
+
+                // Some drivers like ov5640 don't allow you to set the frame format
+                // with too high a frame-rate, but that means the frame-rate won't be
+                // set after the format change. So we need to try again here if we
+                // didn't succeed before. Ideally we'd be able to set both at once.
+                if (!did_set_frame_rate) {
+                        interval.interval = mode->frame_interval;
+                        if (xioctl(camera->subdev_fd,
+                                   VIDIOC_SUBDEV_S_FRAME_INTERVAL,
+                                   &interval) == -1) {
+                                errno_printerr("VIDIOC_SUBDEV_S_FRAME_INTERVAL");
+                        }
+                }
+
+                // Update the mode
+                mode->pixel_format =
+                        mp_pixel_format_from_v4l_bus_code(fmt.format.code);
+                mode->frame_interval = interval.interval;
+                mode->width = fmt.format.width;
+                mode->height = fmt.format.height;
+        }
+
+        // Set the mode for the video device
+        {
+                if (!camera_mode_impl(camera, VIDIOC_S_FMT, mode)) {
+                        errno_printerr("VIDIOC_S_FMT");
+                        return false;
+                }
+        }
+
+        camera->has_set_mode = true;
+        camera->current_mode = *mode;
+
+        return true;
 }
 
 bool
 mp_camera_start_capture(MPCamera *camera)
 {
-	g_return_val_if_fail(camera->has_set_mode, false);
-	g_return_val_if_fail(camera->num_buffers == 0, false);
-
-	enum v4l2_buf_type buftype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	if (camera->use_mplane) {
-		buftype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
-	}
-
-	// Start by requesting buffers
-	struct v4l2_requestbuffers req = {};
-	req.count = MAX_VIDEO_BUFFERS;
-	req.type = buftype;
-	req.memory = V4L2_MEMORY_MMAP;
-
-	if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
-		errno_printerr("VIDIOC_REQBUFS");
-		return false;
-	}
-
-	if (req.count < 2) {
-		g_printerr(
-			"Insufficient buffer memory. Only %d buffers available.\n",
-			req.count);
-		goto error;
-	}
-
-	for (uint32_t i = 0; i < req.count; ++i) {
-		// Query each buffer and mmap it
-		struct v4l2_buffer buf = {
-			.type = buftype,
-			.memory = V4L2_MEMORY_MMAP,
-			.index = i,
-		};
-
-		struct v4l2_plane planes[1];
-		if (camera->use_mplane) {
-			buf.m.planes = planes;
-			buf.length = 1;
-		}
-
-		if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
-			errno_printerr("VIDIOC_QUERYBUF");
-			break;
-		}
-
-		if (camera->use_mplane) {
-			camera->buffers[i].length = planes[0].length;
-			camera->buffers[i].data =
-				mmap(NULL, planes[0].length, PROT_READ, MAP_SHARED,
-				     camera->video_fd, planes[0].m.mem_offset);
-		} else {
-			camera->buffers[i].length = buf.length;
-			camera->buffers[i].data =
-				mmap(NULL, buf.length, PROT_READ, MAP_SHARED,
-				     camera->video_fd, buf.m.offset);
-		}
-
-		if (camera->buffers[i].data == MAP_FAILED) {
-			errno_printerr("mmap");
-			break;
-		}
-
-		struct v4l2_exportbuffer expbuf = {
-			.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
-			.index = i,
-		};
-		if (xioctl(camera->video_fd, VIDIOC_EXPBUF, &expbuf) == -1) {
-			errno_printerr("VIDIOC_EXPBUF");
-			break;
-		}
-
-		camera->buffers[i].fd = expbuf.fd;
-
-		++camera->num_buffers;
-	}
-
-	if (camera->num_buffers != req.count) {
-		g_printerr("Unable to map all buffers\n");
-		goto error;
-	}
-
-	for (uint32_t i = 0; i < camera->num_buffers; ++i) {
-		struct v4l2_buffer buf = {
-			.type = buftype,
-			.memory = V4L2_MEMORY_MMAP,
-			.index = i,
-		};
-
-		struct v4l2_plane planes[1];
-		if (camera->use_mplane) {
-			buf.m.planes = planes;
-			buf.length = 1;
-		}
-
-		// Queue the buffer for capture
-		if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
-			errno_printerr("VIDIOC_QBUF");
-			goto error;
-		}
-	}
-
-	// Start capture
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
-		errno_printerr("VIDIOC_STREAMON");
-		goto error;
-	}
-
-	return true;
+        g_return_val_if_fail(camera->has_set_mode, false);
+        g_return_val_if_fail(camera->num_buffers == 0, false);
+
+        enum v4l2_buf_type buftype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        if (camera->use_mplane) {
+                buftype = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+        }
+
+        // Start by requesting buffers
+        struct v4l2_requestbuffers req = {};
+        req.count = MAX_VIDEO_BUFFERS;
+        req.type = buftype;
+        req.memory = V4L2_MEMORY_MMAP;
+
+        if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
+                errno_printerr("VIDIOC_REQBUFS");
+                return false;
+        }
+
+        if (req.count < 2) {
+                g_printerr(
+                        "Insufficient buffer memory. Only %d buffers available.\n",
+                        req.count);
+                goto error;
+        }
+
+        for (uint32_t i = 0; i < req.count; ++i) {
+                // Query each buffer and mmap it
+                struct v4l2_buffer buf = {
+                        .type = buftype,
+                        .memory = V4L2_MEMORY_MMAP,
+                        .index = i,
+                };
+
+                struct v4l2_plane planes[1];
+                if (camera->use_mplane) {
+                        buf.m.planes = planes;
+                        buf.length = 1;
+                }
+
+                if (xioctl(camera->video_fd, VIDIOC_QUERYBUF, &buf) == -1) {
+                        errno_printerr("VIDIOC_QUERYBUF");
+                        break;
+                }
+
+                if (camera->use_mplane) {
+                        camera->buffers[i].length = planes[0].length;
+                        camera->buffers[i].data = mmap(NULL,
+                                                       planes[0].length,
+                                                       PROT_READ,
+                                                       MAP_SHARED,
+                                                       camera->video_fd,
+                                                       planes[0].m.mem_offset);
+                } else {
+                        camera->buffers[i].length = buf.length;
+                        camera->buffers[i].data = mmap(NULL,
+                                                       buf.length,
+                                                       PROT_READ,
+                                                       MAP_SHARED,
+                                                       camera->video_fd,
+                                                       buf.m.offset);
+                }
+
+                if (camera->buffers[i].data == MAP_FAILED) {
+                        errno_printerr("mmap");
+                        break;
+                }
+
+                struct v4l2_exportbuffer expbuf = {
+                        .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                        .index = i,
+                };
+                if (xioctl(camera->video_fd, VIDIOC_EXPBUF, &expbuf) == -1) {
+                        errno_printerr("VIDIOC_EXPBUF");
+                        break;
+                }
+
+                camera->buffers[i].fd = expbuf.fd;
+
+                ++camera->num_buffers;
+        }
+
+        if (camera->num_buffers != req.count) {
+                g_printerr("Unable to map all buffers\n");
+                goto error;
+        }
+
+        for (uint32_t i = 0; i < camera->num_buffers; ++i) {
+                struct v4l2_buffer buf = {
+                        .type = buftype,
+                        .memory = V4L2_MEMORY_MMAP,
+                        .index = i,
+                };
+
+                struct v4l2_plane planes[1];
+                if (camera->use_mplane) {
+                        buf.m.planes = planes;
+                        buf.length = 1;
+                }
+
+                // Queue the buffer for capture
+                if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
+                        errno_printerr("VIDIOC_QBUF");
+                        goto error;
+                }
+        }
+
+        // Start capture
+        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        if (xioctl(camera->video_fd, VIDIOC_STREAMON, &type) == -1) {
+                errno_printerr("VIDIOC_STREAMON");
+                goto error;
+        }
+
+        return true;
 
 error:
-	// Unmap any mapped buffers
-	assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
-	for (uint32_t i = 0; i < camera->num_buffers; ++i) {
-		if (munmap(camera->buffers[i].data, camera->buffers[i].length) ==
-		    -1) {
-			errno_printerr("munmap");
-		}
-
-		if (close(camera->buffers[i].fd) == -1) {
-			errno_printerr("close");
-		}
-	}
-
-	// Reset allocated buffers
-	{
-		struct v4l2_requestbuffers req = {};
-		req.count = 0;
-		req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		req.memory = V4L2_MEMORY_MMAP;
-
-		if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
-			errno_printerr("VIDIOC_REQBUFS");
-		}
-	}
-
-	return false;
+        // Unmap any mapped buffers
+        assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
+        for (uint32_t i = 0; i < camera->num_buffers; ++i) {
+                if (munmap(camera->buffers[i].data, camera->buffers[i].length) ==
+                    -1) {
+                        errno_printerr("munmap");
+                }
+
+                if (close(camera->buffers[i].fd) == -1) {
+                        errno_printerr("close");
+                }
+        }
+
+        // Reset allocated buffers
+        {
+                struct v4l2_requestbuffers req = {};
+                req.count = 0;
+                req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                req.memory = V4L2_MEMORY_MMAP;
+
+                if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
+                        errno_printerr("VIDIOC_REQBUFS");
+                }
+        }
+
+        return false;
 }
 
 bool
 mp_camera_stop_capture(MPCamera *camera)
 {
-	g_return_val_if_fail(camera->num_buffers > 0, false);
-
-	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	if (xioctl(camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) {
-		errno_printerr("VIDIOC_STREAMOFF");
-	}
-
-	assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
-	for (int i = 0; i < camera->num_buffers; ++i) {
-		if (munmap(camera->buffers[i].data, camera->buffers[i].length) ==
-		    -1) {
-			errno_printerr("munmap");
-		}
-
-		if (close(camera->buffers[i].fd) == -1) {
-			errno_printerr("close");
-		}
-	}
-
-	camera->num_buffers = 0;
-
-	struct v4l2_requestbuffers req = {};
-	req.count = 0;
-	req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	req.memory = V4L2_MEMORY_MMAP;
-	if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
-		errno_printerr("VIDIOC_REQBUFS");
-	}
-
-	return true;
+        g_return_val_if_fail(camera->num_buffers > 0, false);
+
+        enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        if (xioctl(camera->video_fd, VIDIOC_STREAMOFF, &type) == -1) {
+                errno_printerr("VIDIOC_STREAMOFF");
+        }
+
+        assert(camera->num_buffers <= MAX_VIDEO_BUFFERS);
+        for (int i = 0; i < camera->num_buffers; ++i) {
+                if (munmap(camera->buffers[i].data, camera->buffers[i].length) ==
+                    -1) {
+                        errno_printerr("munmap");
+                }
+
+                if (close(camera->buffers[i].fd) == -1) {
+                        errno_printerr("close");
+                }
+        }
+
+        camera->num_buffers = 0;
+
+        struct v4l2_requestbuffers req = {};
+        req.count = 0;
+        req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        req.memory = V4L2_MEMORY_MMAP;
+        if (xioctl(camera->video_fd, VIDIOC_REQBUFS, &req) == -1) {
+                errno_printerr("VIDIOC_REQBUFS");
+        }
+
+        return true;
 }
 
 bool
 mp_camera_is_capturing(MPCamera *camera)
 {
-	return camera->num_buffers > 0;
+        return camera->num_buffers > 0;
 }
 
 bool
 mp_camera_capture_buffer(MPCamera *camera, MPBuffer *buffer)
 {
-	struct v4l2_buffer buf = {};
-	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	buf.memory = V4L2_MEMORY_MMAP;
-
-	struct v4l2_plane planes[1];
-	if (camera->use_mplane) {
-		buf.m.planes = planes;
-		buf.length = 1;
-	}
-
-	if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
-		switch (errno) {
-		case EAGAIN:
-			return true;
-		case EIO:
-			/* Could ignore EIO, see spec. */
-			/* fallthrough */
-		default:
-			errno_printerr("VIDIOC_DQBUF");
-			exit(1);
-			return false;
-		}
-	}
-
-	uint32_t pixel_format = camera->current_mode.pixel_format;
-	uint32_t width = camera->current_mode.width;
-	uint32_t height = camera->current_mode.height;
-
-	uint32_t bytesused;
-	if (camera->use_mplane) {
-		bytesused = planes[0].bytesused;
-	} else {
-		bytesused = buf.bytesused;
-	}
-
-	assert(bytesused ==
-	       mp_pixel_format_width_to_bytes(pixel_format, width) * height);
-	assert(bytesused == camera->buffers[buf.index].length);
-
-	buffer->index = buf.index;
-	buffer->data = camera->buffers[buf.index].data;
-	buffer->fd = camera->buffers[buf.index].fd;
-
-	return true;
+        struct v4l2_buffer buf = {};
+        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        buf.memory = V4L2_MEMORY_MMAP;
+
+        struct v4l2_plane planes[1];
+        if (camera->use_mplane) {
+                buf.m.planes = planes;
+                buf.length = 1;
+        }
+
+        if (xioctl(camera->video_fd, VIDIOC_DQBUF, &buf) == -1) {
+                switch (errno) {
+                case EAGAIN:
+                        return true;
+                case EIO:
+                        /* Could ignore EIO, see spec. */
+                        /* fallthrough */
+                default:
+                        errno_printerr("VIDIOC_DQBUF");
+                        exit(1);
+                        return false;
+                }
+        }
+
+        uint32_t pixel_format = camera->current_mode.pixel_format;
+        uint32_t width = camera->current_mode.width;
+        uint32_t height = camera->current_mode.height;
+
+        uint32_t bytesused;
+        if (camera->use_mplane) {
+                bytesused = planes[0].bytesused;
+        } else {
+                bytesused = buf.bytesused;
+        }
+
+        assert(bytesused ==
+               mp_pixel_format_width_to_bytes(pixel_format, width) * height);
+        assert(bytesused == camera->buffers[buf.index].length);
+
+        buffer->index = buf.index;
+        buffer->data = camera->buffers[buf.index].data;
+        buffer->fd = camera->buffers[buf.index].fd;
+
+        return true;
 }
 
 bool
 mp_camera_release_buffer(MPCamera *camera, uint32_t buffer_index)
 {
-	struct v4l2_buffer buf = {};
-	buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-	buf.memory = V4L2_MEMORY_MMAP;
-	buf.index = buffer_index;
-	if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
-		errno_printerr("VIDIOC_QBUF");
-		return false;
-	}
-	return true;
+        struct v4l2_buffer buf = {};
+        buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+        buf.memory = V4L2_MEMORY_MMAP;
+        buf.index = buffer_index;
+        if (xioctl(camera->video_fd, VIDIOC_QBUF, &buf) == -1) {
+                errno_printerr("VIDIOC_QBUF");
+                return false;
+        }
+        return true;
 }
 
 struct _MPCameraModeList {
-	MPCameraMode mode;
-	MPCameraModeList *next;
+        MPCameraMode mode;
+        MPCameraModeList *next;
 };
 
 static MPCameraModeList *
 get_subdev_modes(MPCamera *camera, bool (*check)(MPCamera *, MPCameraMode *))
 {
-	MPCameraModeList *item = NULL;
-
-	for (uint32_t fmt_index = 0;; ++fmt_index) {
-		struct v4l2_subdev_mbus_code_enum fmt = {};
-		fmt.index = fmt_index;
-		fmt.pad = 0;
-		fmt.which = V4L2_SUBDEV_FORMAT_TRY;
-		if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &fmt) ==
-		    -1) {
-			if (errno != EINVAL) {
-				errno_printerr("VIDIOC_SUBDEV_ENUM_MBUS_CODE");
-			}
-			break;
-		}
-
-		// Skip unsupported formats
-		uint32_t format = mp_pixel_format_from_v4l_bus_code(fmt.code);
-		if (format == MP_PIXEL_FMT_UNSUPPORTED) {
-			continue;
-		}
-
-		for (uint32_t frame_index = 0;; ++frame_index) {
-			struct v4l2_subdev_frame_size_enum frame = {};
-			frame.index = frame_index;
-			frame.pad = 0;
-			frame.code = fmt.code;
-			frame.which = V4L2_SUBDEV_FORMAT_TRY;
-			if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_FRAME_SIZE,
-				   &frame) == -1) {
-				if (errno != EINVAL) {
-					errno_printerr(
-						"VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
-				}
-				break;
-			}
-
-			// TODO: Handle other types
-			if (frame.min_width != frame.max_width ||
-			    frame.min_height != frame.max_height) {
-				break;
-			}
-
-			for (uint32_t interval_index = 0;; ++interval_index) {
-				struct v4l2_subdev_frame_interval_enum interval = {};
-				interval.index = interval_index;
-				interval.pad = 0;
-				interval.code = fmt.code;
-				interval.width = frame.max_width;
-				interval.height = frame.max_height;
-				interval.which = V4L2_SUBDEV_FORMAT_TRY;
-				if (xioctl(camera->subdev_fd,
-					   VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL,
-					   &interval) == -1) {
-					if (errno != EINVAL) {
-						errno_printerr(
-							"VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
-					}
-					break;
-				}
-
-				MPCameraMode mode = {
-					.pixel_format = format,
-					.frame_interval = interval.interval,
-					.width = frame.max_width,
-					.height = frame.max_height,
-				};
-
-				if (!check(camera, &mode)) {
-					continue;
-				}
-
-				MPCameraModeList *new_item =
-					malloc(sizeof(MPCameraModeList));
-				new_item->mode = mode;
-				new_item->next = item;
-				item = new_item;
-			}
-		}
-	}
-
-	return item;
+        MPCameraModeList *item = NULL;
+
+        for (uint32_t fmt_index = 0;; ++fmt_index) {
+                struct v4l2_subdev_mbus_code_enum fmt = {};
+                fmt.index = fmt_index;
+                fmt.pad = 0;
+                fmt.which = V4L2_SUBDEV_FORMAT_TRY;
+                if (xioctl(camera->subdev_fd, VIDIOC_SUBDEV_ENUM_MBUS_CODE, &fmt) ==
+                    -1) {
+                        if (errno != EINVAL) {
+                                errno_printerr("VIDIOC_SUBDEV_ENUM_MBUS_CODE");
+                        }
+                        break;
+                }
+
+                // Skip unsupported formats
+                uint32_t format = mp_pixel_format_from_v4l_bus_code(fmt.code);
+                if (format == MP_PIXEL_FMT_UNSUPPORTED) {
+                        continue;
+                }
+
+                for (uint32_t frame_index = 0;; ++frame_index) {
+                        struct v4l2_subdev_frame_size_enum frame = {};
+                        frame.index = frame_index;
+                        frame.pad = 0;
+                        frame.code = fmt.code;
+                        frame.which = V4L2_SUBDEV_FORMAT_TRY;
+                        if (xioctl(camera->subdev_fd,
+                                   VIDIOC_SUBDEV_ENUM_FRAME_SIZE,
+                                   &frame) == -1) {
+                                if (errno != EINVAL) {
+                                        errno_printerr(
+                                                "VIDIOC_SUBDEV_ENUM_FRAME_SIZE");
+                                }
+                                break;
+                        }
+
+                        // TODO: Handle other types
+                        if (frame.min_width != frame.max_width ||
+                            frame.min_height != frame.max_height) {
+                                break;
+                        }
+
+                        for (uint32_t interval_index = 0;; ++interval_index) {
+                                struct v4l2_subdev_frame_interval_enum interval = {};
+                                interval.index = interval_index;
+                                interval.pad = 0;
+                                interval.code = fmt.code;
+                                interval.width = frame.max_width;
+                                interval.height = frame.max_height;
+                                interval.which = V4L2_SUBDEV_FORMAT_TRY;
+                                if (xioctl(camera->subdev_fd,
+                                           VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL,
+                                           &interval) == -1) {
+                                        if (errno != EINVAL) {
+                                                errno_printerr(
+                                                        "VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL");
+                                        }
+                                        break;
+                                }
+
+                                MPCameraMode mode = {
+                                        .pixel_format = format,
+                                        .frame_interval = interval.interval,
+                                        .width = frame.max_width,
+                                        .height = frame.max_height,
+                                };
+
+                                if (!check(camera, &mode)) {
+                                        continue;
+                                }
+
+                                MPCameraModeList *new_item =
+                                        malloc(sizeof(MPCameraModeList));
+                                new_item->mode = mode;
+                                new_item->next = item;
+                                item = new_item;
+                        }
+                }
+        }
+
+        return item;
 }
 
 static MPCameraModeList *
 get_video_modes(MPCamera *camera, bool (*check)(MPCamera *, MPCameraMode *))
 {
-	MPCameraModeList *item = NULL;
-
-	for (uint32_t fmt_index = 0;; ++fmt_index) {
-		struct v4l2_fmtdesc fmt = {};
-		fmt.index = fmt_index;
-		fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		if (xioctl(camera->video_fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
-			if (errno != EINVAL) {
-				errno_printerr("VIDIOC_ENUM_FMT");
-			}
-			break;
-		}
-
-		// Skip unsupported formats
-		uint32_t format =
-			mp_pixel_format_from_v4l_pixel_format(fmt.pixelformat);
-		if (format == MP_PIXEL_FMT_UNSUPPORTED) {
-			continue;
-		}
-
-		for (uint32_t frame_index = 0;; ++frame_index) {
-			struct v4l2_frmsizeenum frame = {};
-			frame.index = frame_index;
-			frame.pixel_format = fmt.pixelformat;
-			if (xioctl(camera->video_fd, VIDIOC_ENUM_FRAMESIZES,
-				   &frame) == -1) {
-				if (errno != EINVAL) {
-					errno_printerr("VIDIOC_ENUM_FRAMESIZES");
-				}
-				break;
-			}
-
-			// TODO: Handle other types
-			if (frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
-				break;
-			}
-
-			for (uint32_t interval_index = 0;; ++interval_index) {
-				struct v4l2_frmivalenum interval = {};
-				interval.index = interval_index;
-				interval.pixel_format = fmt.pixelformat;
-				interval.width = frame.discrete.width;
-				interval.height = frame.discrete.height;
-				if (xioctl(camera->video_fd,
-					   VIDIOC_ENUM_FRAMEINTERVALS,
-					   &interval) == -1) {
-					if (errno != EINVAL) {
-						errno_printerr(
-							"VIDIOC_ENUM_FRAMESIZES");
-					}
-					break;
-				}
-
-				// TODO: Handle other types
-				if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
-					break;
-				}
-
-				MPCameraMode mode = {
-					.pixel_format = format,
-					.frame_interval = interval.discrete,
-					.width = frame.discrete.width,
-					.height = frame.discrete.height,
-				};
-
-				if (!check(camera, &mode)) {
-					continue;
-				}
-
-				MPCameraModeList *new_item =
-					malloc(sizeof(MPCameraModeList));
-				new_item->mode = mode;
-				new_item->next = item;
-				item = new_item;
-			}
-		}
-	}
-
-	return item;
+        MPCameraModeList *item = NULL;
+
+        for (uint32_t fmt_index = 0;; ++fmt_index) {
+                struct v4l2_fmtdesc fmt = {};
+                fmt.index = fmt_index;
+                fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                if (xioctl(camera->video_fd, VIDIOC_ENUM_FMT, &fmt) == -1) {
+                        if (errno != EINVAL) {
+                                errno_printerr("VIDIOC_ENUM_FMT");
+                        }
+                        break;
+                }
+
+                // Skip unsupported formats
+                uint32_t format =
+                        mp_pixel_format_from_v4l_pixel_format(fmt.pixelformat);
+                if (format == MP_PIXEL_FMT_UNSUPPORTED) {
+                        continue;
+                }
+
+                for (uint32_t frame_index = 0;; ++frame_index) {
+                        struct v4l2_frmsizeenum frame = {};
+                        frame.index = frame_index;
+                        frame.pixel_format = fmt.pixelformat;
+                        if (xioctl(camera->video_fd,
+                                   VIDIOC_ENUM_FRAMESIZES,
+                                   &frame) == -1) {
+                                if (errno != EINVAL) {
+                                        errno_printerr("VIDIOC_ENUM_FRAMESIZES");
+                                }
+                                break;
+                        }
+
+                        // TODO: Handle other types
+                        if (frame.type != V4L2_FRMSIZE_TYPE_DISCRETE) {
+                                break;
+                        }
+
+                        for (uint32_t interval_index = 0;; ++interval_index) {
+                                struct v4l2_frmivalenum interval = {};
+                                interval.index = interval_index;
+                                interval.pixel_format = fmt.pixelformat;
+                                interval.width = frame.discrete.width;
+                                interval.height = frame.discrete.height;
+                                if (xioctl(camera->video_fd,
+                                           VIDIOC_ENUM_FRAMEINTERVALS,
+                                           &interval) == -1) {
+                                        if (errno != EINVAL) {
+                                                errno_printerr(
+                                                        "VIDIOC_ENUM_FRAMESIZES");
+                                        }
+                                        break;
+                                }
+
+                                // TODO: Handle other types
+                                if (interval.type != V4L2_FRMIVAL_TYPE_DISCRETE) {
+                                        break;
+                                }
+
+                                MPCameraMode mode = {
+                                        .pixel_format = format,
+                                        .frame_interval = interval.discrete,
+                                        .width = frame.discrete.width,
+                                        .height = frame.discrete.height,
+                                };
+
+                                if (!check(camera, &mode)) {
+                                        continue;
+                                }
+
+                                MPCameraModeList *new_item =
+                                        malloc(sizeof(MPCameraModeList));
+                                new_item->mode = mode;
+                                new_item->next = item;
+                                item = new_item;
+                        }
+                }
+        }
+
+        return item;
 }
 
 static bool
 all_modes(MPCamera *camera, MPCameraMode *mode)
 {
-	return true;
+        return true;
 }
 
 static bool
 available_modes(MPCamera *camera, MPCameraMode *mode)
 {
-	MPCameraMode attempt = *mode;
-	return mp_camera_try_mode(camera, &attempt) &&
-	       mp_camera_mode_is_equivalent(mode, &attempt);
+        MPCameraMode attempt = *mode;
+        return mp_camera_try_mode(camera, &attempt) &&
+               mp_camera_mode_is_equivalent(mode, &attempt);
 }
 
 MPCameraModeList *
 mp_camera_list_supported_modes(MPCamera *camera)
 {
-	if (mp_camera_is_subdev(camera)) {
-		return get_subdev_modes(camera, all_modes);
-	} else {
-		return get_video_modes(camera, all_modes);
-	}
+        if (mp_camera_is_subdev(camera)) {
+                return get_subdev_modes(camera, all_modes);
+        } else {
+                return get_video_modes(camera, all_modes);
+        }
 }
 
 MPCameraModeList *
 mp_camera_list_available_modes(MPCamera *camera)
 {
-	if (mp_camera_is_subdev(camera)) {
-		return get_subdev_modes(camera, available_modes);
-	} else {
-		return get_video_modes(camera, available_modes);
-	}
+        if (mp_camera_is_subdev(camera)) {
+                return get_subdev_modes(camera, available_modes);
+        } else {
+                return get_video_modes(camera, available_modes);
+        }
 }
 
 MPCameraMode *
 mp_camera_mode_list_get(MPCameraModeList *list)
 {
-	g_return_val_if_fail(list, NULL);
-	return &list->mode;
+        g_return_val_if_fail(list, NULL);
+        return &list->mode;
 }
 
 MPCameraModeList *
 mp_camera_mode_list_next(MPCameraModeList *list)
 {
-	g_return_val_if_fail(list, NULL);
-	return list->next;
+        g_return_val_if_fail(list, NULL);
+        return list->next;
 }
 
 void
 mp_camera_mode_list_free(MPCameraModeList *list)
 {
-	while (list) {
-		MPCameraModeList *tmp = list;
-		list = tmp->next;
-		free(tmp);
-	}
+        while (list) {
+                MPCameraModeList *tmp = list;
+                list = tmp->next;
+                free(tmp);
+        }
 }
 
 struct int_str_pair {
-	uint32_t value;
-	const char *str;
+        uint32_t value;
+        const char *str;
 };
 
 struct int_str_pair control_id_names[] = {
-	{ V4L2_CID_BRIGHTNESS, "BRIGHTNESS" },
-	{ V4L2_CID_CONTRAST, "CONTRAST" },
-	{ V4L2_CID_SATURATION, "SATURATION" },
-	{ V4L2_CID_HUE, "HUE" },
-	{ V4L2_CID_AUDIO_VOLUME, "AUDIO_VOLUME" },
-	{ V4L2_CID_AUDIO_BALANCE, "AUDIO_BALANCE" },
-	{ V4L2_CID_AUDIO_BASS, "AUDIO_BASS" },
-	{ V4L2_CID_AUDIO_TREBLE, "AUDIO_TREBLE" },
-	{ V4L2_CID_AUDIO_MUTE, "AUDIO_MUTE" },
-	{ V4L2_CID_AUDIO_LOUDNESS, "AUDIO_LOUDNESS" },
-	{ V4L2_CID_BLACK_LEVEL, "BLACK_LEVEL" },
-	{ V4L2_CID_AUTO_WHITE_BALANCE, "AUTO_WHITE_BALANCE" },
-	{ V4L2_CID_DO_WHITE_BALANCE, "DO_WHITE_BALANCE" },
-	{ V4L2_CID_RED_BALANCE, "RED_BALANCE" },
-	{ V4L2_CID_BLUE_BALANCE, "BLUE_BALANCE" },
-	{ V4L2_CID_GAMMA, "GAMMA" },
-	{ V4L2_CID_WHITENESS, "WHITENESS" },
-	{ V4L2_CID_EXPOSURE, "EXPOSURE" },
-	{ V4L2_CID_AUTOGAIN, "AUTOGAIN" },
-	{ V4L2_CID_GAIN, "GAIN" },
-	{ V4L2_CID_HFLIP, "HFLIP" },
-	{ V4L2_CID_VFLIP, "VFLIP" },
-	{ V4L2_CID_POWER_LINE_FREQUENCY, "POWER_LINE_FREQUENCY" },
-	{ V4L2_CID_HUE_AUTO, "HUE_AUTO" },
-	{ V4L2_CID_WHITE_BALANCE_TEMPERATURE, "WHITE_BALANCE_TEMPERATURE" },
-	{ V4L2_CID_SHARPNESS, "SHARPNESS" },
-	{ V4L2_CID_BACKLIGHT_COMPENSATION, "BACKLIGHT_COMPENSATION" },
-	{ V4L2_CID_CHROMA_AGC, "CHROMA_AGC" },
-	{ V4L2_CID_COLOR_KILLER, "COLOR_KILLER" },
-	{ V4L2_CID_COLORFX, "COLORFX" },
-	{ V4L2_CID_AUTOBRIGHTNESS, "AUTOBRIGHTNESS" },
-	{ V4L2_CID_BAND_STOP_FILTER, "BAND_STOP_FILTER" },
-	{ V4L2_CID_ROTATE, "ROTATE" },
-	{ V4L2_CID_BG_COLOR, "BG_COLOR" },
-	{ V4L2_CID_CHROMA_GAIN, "CHROMA_GAIN" },
-	{ V4L2_CID_ILLUMINATORS_1, "ILLUMINATORS_1" },
-	{ V4L2_CID_ILLUMINATORS_2, "ILLUMINATORS_2" },
-	{ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, "MIN_BUFFERS_FOR_CAPTURE" },
-	{ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, "MIN_BUFFERS_FOR_OUTPUT" },
-	{ V4L2_CID_ALPHA_COMPONENT, "ALPHA_COMPONENT" },
-	{ V4L2_CID_COLORFX_CBCR, "COLORFX_CBCR" },
-	{ V4L2_CID_LASTP1, "LASTP1" },
-	{ V4L2_CID_USER_MEYE_BASE, "USER_MEYE_BASE" },
-	{ V4L2_CID_USER_BTTV_BASE, "USER_BTTV_BASE" },
-	{ V4L2_CID_USER_S2255_BASE, "USER_S2255_BASE" },
-	{ V4L2_CID_USER_SI476X_BASE, "USER_SI476X_BASE" },
-	{ V4L2_CID_USER_TI_VPE_BASE, "USER_TI_VPE_BASE" },
-	{ V4L2_CID_USER_SAA7134_BASE, "USER_SAA7134_BASE" },
-	{ V4L2_CID_USER_ADV7180_BASE, "USER_ADV7180_BASE" },
-	{ V4L2_CID_USER_TC358743_BASE, "USER_TC358743_BASE" },
-	{ V4L2_CID_USER_MAX217X_BASE, "USER_MAX217X_BASE" },
-	{ V4L2_CID_USER_IMX_BASE, "USER_IMX_BASE" },
-	// { V4L2_CID_USER_ATMEL_ISC_BASE, "USER_ATMEL_ISC_BASE" },
-	{ V4L2_CID_CAMERA_CLASS_BASE, "CAMERA_CLASS_BASE" },
-	{ V4L2_CID_CAMERA_CLASS, "CAMERA_CLASS" },
-	{ V4L2_CID_EXPOSURE_AUTO, "EXPOSURE_AUTO" },
-	{ V4L2_CID_EXPOSURE_ABSOLUTE, "EXPOSURE_ABSOLUTE" },
-	{ V4L2_CID_EXPOSURE_AUTO_PRIORITY, "EXPOSURE_AUTO_PRIORITY" },
-	{ V4L2_CID_PAN_RELATIVE, "PAN_RELATIVE" },
-	{ V4L2_CID_TILT_RELATIVE, "TILT_RELATIVE" },
-	{ V4L2_CID_PAN_RESET, "PAN_RESET" },
-	{ V4L2_CID_TILT_RESET, "TILT_RESET" },
-	{ V4L2_CID_PAN_ABSOLUTE, "PAN_ABSOLUTE" },
-	{ V4L2_CID_TILT_ABSOLUTE, "TILT_ABSOLUTE" },
-	{ V4L2_CID_FOCUS_ABSOLUTE, "FOCUS_ABSOLUTE" },
-	{ V4L2_CID_FOCUS_RELATIVE, "FOCUS_RELATIVE" },
-	{ V4L2_CID_FOCUS_AUTO, "FOCUS_AUTO" },
-	{ V4L2_CID_ZOOM_ABSOLUTE, "ZOOM_ABSOLUTE" },
-	{ V4L2_CID_ZOOM_RELATIVE, "ZOOM_RELATIVE" },
-	{ V4L2_CID_ZOOM_CONTINUOUS, "ZOOM_CONTINUOUS" },
-	{ V4L2_CID_PRIVACY, "PRIVACY" },
-	{ V4L2_CID_IRIS_ABSOLUTE, "IRIS_ABSOLUTE" },
-	{ V4L2_CID_IRIS_RELATIVE, "IRIS_RELATIVE" },
-	{ V4L2_CID_AUTO_EXPOSURE_BIAS, "AUTO_EXPOSURE_BIAS" },
-	{ V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, "AUTO_N_PRESET_WHITE_BALANCE" },
-	{ V4L2_CID_WIDE_DYNAMIC_RANGE, "WIDE_DYNAMIC_RANGE" },
-	{ V4L2_CID_IMAGE_STABILIZATION, "IMAGE_STABILIZATION" },
-	{ V4L2_CID_ISO_SENSITIVITY, "ISO_SENSITIVITY" },
-	{ V4L2_CID_ISO_SENSITIVITY_AUTO, "ISO_SENSITIVITY_AUTO" },
-	{ V4L2_CID_EXPOSURE_METERING, "EXPOSURE_METERING" },
-	{ V4L2_CID_SCENE_MODE, "SCENE_MODE" },
-	{ V4L2_CID_3A_LOCK, "3A_LOCK" },
-	{ V4L2_CID_AUTO_FOCUS_START, "AUTO_FOCUS_START" },
-	{ V4L2_CID_AUTO_FOCUS_STOP, "AUTO_FOCUS_STOP" },
-	{ V4L2_CID_AUTO_FOCUS_STATUS, "AUTO_FOCUS_STATUS" },
-	{ V4L2_CID_AUTO_FOCUS_RANGE, "AUTO_FOCUS_RANGE" },
-	{ V4L2_CID_PAN_SPEED, "PAN_SPEED" },
-	{ V4L2_CID_TILT_SPEED, "TILT_SPEED" },
-	// { V4L2_CID_CAMERA_ORIENTATION, "CAMERA_ORIENTATION" },
-	// { V4L2_CID_CAMERA_SENSOR_ROTATION, "CAMERA_SENSOR_ROTATION" },
-	{ V4L2_CID_FLASH_LED_MODE, "FLASH_LED_MODE" },
-	{ V4L2_CID_FLASH_STROBE_SOURCE, "FLASH_STROBE_SOURCE" },
-	{ V4L2_CID_FLASH_STROBE, "FLASH_STROBE" },
-	{ V4L2_CID_FLASH_STROBE_STOP, "FLASH_STROBE_STOP" },
-	{ V4L2_CID_FLASH_STROBE_STATUS, "FLASH_STROBE_STATUS" },
-	{ V4L2_CID_FLASH_TIMEOUT, "FLASH_TIMEOUT" },
-	{ V4L2_CID_FLASH_INTENSITY, "FLASH_INTENSITY" },
-	{ V4L2_CID_FLASH_TORCH_INTENSITY, "FLASH_TORCH_INTENSITY" },
-	{ V4L2_CID_FLASH_INDICATOR_INTENSITY, "FLASH_INDICATOR_INTENSITY" },
-	{ V4L2_CID_FLASH_FAULT, "FLASH_FAULT" },
-	{ V4L2_CID_FLASH_CHARGE, "FLASH_CHARGE" },
-	{ V4L2_CID_FLASH_READY, "FLASH_READY" },
+        { V4L2_CID_BRIGHTNESS, "BRIGHTNESS" },
+        { V4L2_CID_CONTRAST, "CONTRAST" },
+        { V4L2_CID_SATURATION, "SATURATION" },
+        { V4L2_CID_HUE, "HUE" },
+        { V4L2_CID_AUDIO_VOLUME, "AUDIO_VOLUME" },
+        { V4L2_CID_AUDIO_BALANCE, "AUDIO_BALANCE" },
+        { V4L2_CID_AUDIO_BASS, "AUDIO_BASS" },
+        { V4L2_CID_AUDIO_TREBLE, "AUDIO_TREBLE" },
+        { V4L2_CID_AUDIO_MUTE, "AUDIO_MUTE" },
+        { V4L2_CID_AUDIO_LOUDNESS, "AUDIO_LOUDNESS" },
+        { V4L2_CID_BLACK_LEVEL, "BLACK_LEVEL" },
+        { V4L2_CID_AUTO_WHITE_BALANCE, "AUTO_WHITE_BALANCE" },
+        { V4L2_CID_DO_WHITE_BALANCE, "DO_WHITE_BALANCE" },
+        { V4L2_CID_RED_BALANCE, "RED_BALANCE" },
+        { V4L2_CID_BLUE_BALANCE, "BLUE_BALANCE" },
+        { V4L2_CID_GAMMA, "GAMMA" },
+        { V4L2_CID_WHITENESS, "WHITENESS" },
+        { V4L2_CID_EXPOSURE, "EXPOSURE" },
+        { V4L2_CID_AUTOGAIN, "AUTOGAIN" },
+        { V4L2_CID_GAIN, "GAIN" },
+        { V4L2_CID_HFLIP, "HFLIP" },
+        { V4L2_CID_VFLIP, "VFLIP" },
+        { V4L2_CID_POWER_LINE_FREQUENCY, "POWER_LINE_FREQUENCY" },
+        { V4L2_CID_HUE_AUTO, "HUE_AUTO" },
+        { V4L2_CID_WHITE_BALANCE_TEMPERATURE, "WHITE_BALANCE_TEMPERATURE" },
+        { V4L2_CID_SHARPNESS, "SHARPNESS" },
+        { V4L2_CID_BACKLIGHT_COMPENSATION, "BACKLIGHT_COMPENSATION" },
+        { V4L2_CID_CHROMA_AGC, "CHROMA_AGC" },
+        { V4L2_CID_COLOR_KILLER, "COLOR_KILLER" },
+        { V4L2_CID_COLORFX, "COLORFX" },
+        { V4L2_CID_AUTOBRIGHTNESS, "AUTOBRIGHTNESS" },
+        { V4L2_CID_BAND_STOP_FILTER, "BAND_STOP_FILTER" },
+        { V4L2_CID_ROTATE, "ROTATE" },
+        { V4L2_CID_BG_COLOR, "BG_COLOR" },
+        { V4L2_CID_CHROMA_GAIN, "CHROMA_GAIN" },
+        { V4L2_CID_ILLUMINATORS_1, "ILLUMINATORS_1" },
+        { V4L2_CID_ILLUMINATORS_2, "ILLUMINATORS_2" },
+        { V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, "MIN_BUFFERS_FOR_CAPTURE" },
+        { V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, "MIN_BUFFERS_FOR_OUTPUT" },
+        { V4L2_CID_ALPHA_COMPONENT, "ALPHA_COMPONENT" },
+        { V4L2_CID_COLORFX_CBCR, "COLORFX_CBCR" },
+        { V4L2_CID_LASTP1, "LASTP1" },
+        { V4L2_CID_USER_MEYE_BASE, "USER_MEYE_BASE" },
+        { V4L2_CID_USER_BTTV_BASE, "USER_BTTV_BASE" },
+        { V4L2_CID_USER_S2255_BASE, "USER_S2255_BASE" },
+        { V4L2_CID_USER_SI476X_BASE, "USER_SI476X_BASE" },
+        { V4L2_CID_USER_TI_VPE_BASE, "USER_TI_VPE_BASE" },
+        { V4L2_CID_USER_SAA7134_BASE, "USER_SAA7134_BASE" },
+        { V4L2_CID_USER_ADV7180_BASE, "USER_ADV7180_BASE" },
+        { V4L2_CID_USER_TC358743_BASE, "USER_TC358743_BASE" },
+        { V4L2_CID_USER_MAX217X_BASE, "USER_MAX217X_BASE" },
+        { V4L2_CID_USER_IMX_BASE, "USER_IMX_BASE" },
+        // { V4L2_CID_USER_ATMEL_ISC_BASE, "USER_ATMEL_ISC_BASE" },
+        { V4L2_CID_CAMERA_CLASS_BASE, "CAMERA_CLASS_BASE" },
+        { V4L2_CID_CAMERA_CLASS, "CAMERA_CLASS" },
+        { V4L2_CID_EXPOSURE_AUTO, "EXPOSURE_AUTO" },
+        { V4L2_CID_EXPOSURE_ABSOLUTE, "EXPOSURE_ABSOLUTE" },
+        { V4L2_CID_EXPOSURE_AUTO_PRIORITY, "EXPOSURE_AUTO_PRIORITY" },
+        { V4L2_CID_PAN_RELATIVE, "PAN_RELATIVE" },
+        { V4L2_CID_TILT_RELATIVE, "TILT_RELATIVE" },
+        { V4L2_CID_PAN_RESET, "PAN_RESET" },
+        { V4L2_CID_TILT_RESET, "TILT_RESET" },
+        { V4L2_CID_PAN_ABSOLUTE, "PAN_ABSOLUTE" },
+        { V4L2_CID_TILT_ABSOLUTE, "TILT_ABSOLUTE" },
+        { V4L2_CID_FOCUS_ABSOLUTE, "FOCUS_ABSOLUTE" },
+        { V4L2_CID_FOCUS_RELATIVE, "FOCUS_RELATIVE" },
+        { V4L2_CID_FOCUS_AUTO, "FOCUS_AUTO" },
+        { V4L2_CID_ZOOM_ABSOLUTE, "ZOOM_ABSOLUTE" },
+        { V4L2_CID_ZOOM_RELATIVE, "ZOOM_RELATIVE" },
+        { V4L2_CID_ZOOM_CONTINUOUS, "ZOOM_CONTINUOUS" },
+        { V4L2_CID_PRIVACY, "PRIVACY" },
+        { V4L2_CID_IRIS_ABSOLUTE, "IRIS_ABSOLUTE" },
+        { V4L2_CID_IRIS_RELATIVE, "IRIS_RELATIVE" },
+        { V4L2_CID_AUTO_EXPOSURE_BIAS, "AUTO_EXPOSURE_BIAS" },
+        { V4L2_CID_AUTO_N_PRESET_WHITE_BALANCE, "AUTO_N_PRESET_WHITE_BALANCE" },
+        { V4L2_CID_WIDE_DYNAMIC_RANGE, "WIDE_DYNAMIC_RANGE" },
+        { V4L2_CID_IMAGE_STABILIZATION, "IMAGE_STABILIZATION" },
+        { V4L2_CID_ISO_SENSITIVITY, "ISO_SENSITIVITY" },
+        { V4L2_CID_ISO_SENSITIVITY_AUTO, "ISO_SENSITIVITY_AUTO" },
+        { V4L2_CID_EXPOSURE_METERING, "EXPOSURE_METERING" },
+        { V4L2_CID_SCENE_MODE, "SCENE_MODE" },
+        { V4L2_CID_3A_LOCK, "3A_LOCK" },
+        { V4L2_CID_AUTO_FOCUS_START, "AUTO_FOCUS_START" },
+        { V4L2_CID_AUTO_FOCUS_STOP, "AUTO_FOCUS_STOP" },
+        { V4L2_CID_AUTO_FOCUS_STATUS, "AUTO_FOCUS_STATUS" },
+        { V4L2_CID_AUTO_FOCUS_RANGE, "AUTO_FOCUS_RANGE" },
+        { V4L2_CID_PAN_SPEED, "PAN_SPEED" },
+        { V4L2_CID_TILT_SPEED, "TILT_SPEED" },
+        // { V4L2_CID_CAMERA_ORIENTATION, "CAMERA_ORIENTATION" },
+        // { V4L2_CID_CAMERA_SENSOR_ROTATION, "CAMERA_SENSOR_ROTATION" },
+        { V4L2_CID_FLASH_LED_MODE, "FLASH_LED_MODE" },
+        { V4L2_CID_FLASH_STROBE_SOURCE, "FLASH_STROBE_SOURCE" },
+        { V4L2_CID_FLASH_STROBE, "FLASH_STROBE" },
+        { V4L2_CID_FLASH_STROBE_STOP, "FLASH_STROBE_STOP" },
+        { V4L2_CID_FLASH_STROBE_STATUS, "FLASH_STROBE_STATUS" },
+        { V4L2_CID_FLASH_TIMEOUT, "FLASH_TIMEOUT" },
+        { V4L2_CID_FLASH_INTENSITY, "FLASH_INTENSITY" },
+        { V4L2_CID_FLASH_TORCH_INTENSITY, "FLASH_TORCH_INTENSITY" },
+        { V4L2_CID_FLASH_INDICATOR_INTENSITY, "FLASH_INDICATOR_INTENSITY" },
+        { V4L2_CID_FLASH_FAULT, "FLASH_FAULT" },
+        { V4L2_CID_FLASH_CHARGE, "FLASH_CHARGE" },
+        { V4L2_CID_FLASH_READY, "FLASH_READY" },
 };
 
 const char *
 mp_control_id_to_str(uint32_t id)
 {
-	size_t size = sizeof(control_id_names) / sizeof(*control_id_names);
+        size_t size = sizeof(control_id_names) / sizeof(*control_id_names);
 
-	for (size_t i = 0; i < size; ++i) {
-		if (control_id_names[i].value == id) {
-			return control_id_names[i].str;
-		}
-	}
+        for (size_t i = 0; i < size; ++i) {
+                if (control_id_names[i].value == id) {
+                        return control_id_names[i].str;
+                }
+        }
 
-	return "UNKNOWN";
+        return "UNKNOWN";
 }
 
 struct int_str_pair control_type_names[] = {
-	{ V4L2_CTRL_TYPE_INTEGER, "INTEGER" },
-	{ V4L2_CTRL_TYPE_BOOLEAN, "BOOLEAN" },
-	{ V4L2_CTRL_TYPE_MENU, "MENU" },
-	{ V4L2_CTRL_TYPE_INTEGER_MENU, "INTEGER_MENU" },
-	{ V4L2_CTRL_TYPE_BITMASK, "BITMASK" },
-	{ V4L2_CTRL_TYPE_BUTTON, "BUTTON" },
-	{ V4L2_CTRL_TYPE_INTEGER64, "INTEGER64" },
-	{ V4L2_CTRL_TYPE_STRING, "STRING" },
-	{ V4L2_CTRL_TYPE_CTRL_CLASS, "CTRL_CLASS" },
-	{ V4L2_CTRL_TYPE_U8, "U8" },
-	{ V4L2_CTRL_TYPE_U16, "U16" },
-	{ V4L2_CTRL_TYPE_U32, "U32" },
-	// { V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS, "MPEG2_SLICE_PARAMS" },
-	// { V4L2_CTRL_TYPE_MPEG2_QUANTIZATION, "MPEG2_QUANTIZATION" },
-	// { V4L2_CTRL_TYPE_AREA, "AREA" },
-	// { V4L2_CTRL_TYPE_H264_SPS, "H264_SPS" },
-	// { V4L2_CTRL_TYPE_H264_PPS, "H264_PPS" },
-	// { V4L2_CTRL_TYPE_H264_SCALING_MATRIX, "H264_SCALING_MATRIX" },
-	// { V4L2_CTRL_TYPE_H264_SLICE_PARAMS, "H264_SLICE_PARAMS" },
-	// { V4L2_CTRL_TYPE_H264_DECODE_PARAMS, "H264_DECODE_PARAMS" },
-	// { V4L2_CTRL_TYPE_HEVC_SPS, "HEVC_SPS" },
-	// { V4L2_CTRL_TYPE_HEVC_PPS, "HEVC_PPS" },
-	// { V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, "HEVC_SLICE_PARAMS" },
+        { V4L2_CTRL_TYPE_INTEGER, "INTEGER" },
+        { V4L2_CTRL_TYPE_BOOLEAN, "BOOLEAN" },
+        { V4L2_CTRL_TYPE_MENU, "MENU" },
+        { V4L2_CTRL_TYPE_INTEGER_MENU, "INTEGER_MENU" },
+        { V4L2_CTRL_TYPE_BITMASK, "BITMASK" },
+        { V4L2_CTRL_TYPE_BUTTON, "BUTTON" },
+        { V4L2_CTRL_TYPE_INTEGER64, "INTEGER64" },
+        { V4L2_CTRL_TYPE_STRING, "STRING" },
+        { V4L2_CTRL_TYPE_CTRL_CLASS, "CTRL_CLASS" },
+        { V4L2_CTRL_TYPE_U8, "U8" },
+        { V4L2_CTRL_TYPE_U16, "U16" },
+        { V4L2_CTRL_TYPE_U32, "U32" },
+        // { V4L2_CTRL_TYPE_MPEG2_SLICE_PARAMS, "MPEG2_SLICE_PARAMS" },
+        // { V4L2_CTRL_TYPE_MPEG2_QUANTIZATION, "MPEG2_QUANTIZATION" },
+        // { V4L2_CTRL_TYPE_AREA, "AREA" },
+        // { V4L2_CTRL_TYPE_H264_SPS, "H264_SPS" },
+        // { V4L2_CTRL_TYPE_H264_PPS, "H264_PPS" },
+        // { V4L2_CTRL_TYPE_H264_SCALING_MATRIX, "H264_SCALING_MATRIX" },
+        // { V4L2_CTRL_TYPE_H264_SLICE_PARAMS, "H264_SLICE_PARAMS" },
+        // { V4L2_CTRL_TYPE_H264_DECODE_PARAMS, "H264_DECODE_PARAMS" },
+        // { V4L2_CTRL_TYPE_HEVC_SPS, "HEVC_SPS" },
+        // { V4L2_CTRL_TYPE_HEVC_PPS, "HEVC_PPS" },
+        // { V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS, "HEVC_SLICE_PARAMS" },
 };
 
 const char *
 mp_control_type_to_str(uint32_t type)
 {
-	size_t size = sizeof(control_type_names) / sizeof(*control_type_names);
+        size_t size = sizeof(control_type_names) / sizeof(*control_type_names);
 
-	for (size_t i = 0; i < size; ++i) {
-		if (control_type_names[i].value == type) {
-			return control_type_names[i].str;
-		}
-	}
+        for (size_t i = 0; i < size; ++i) {
+                if (control_type_names[i].value == type) {
+                        return control_type_names[i].str;
+                }
+        }
 
-	return "UNKNOWN";
+        return "UNKNOWN";
 }
 
 struct _MPControlList {
-	MPControl control;
-	MPControlList *next;
+        MPControl control;
+        MPControlList *next;
 };
 
 static int
 control_fd(MPCamera *camera)
 {
-	if (camera->subdev_fd != -1) {
-		return camera->subdev_fd;
-	}
-	return camera->video_fd;
+        if (camera->subdev_fd != -1) {
+                return camera->subdev_fd;
+        }
+        return camera->video_fd;
 }
 
 MPControlList *
 mp_camera_list_controls(MPCamera *camera)
 {
-	MPControlList *item = NULL;
-
-	struct v4l2_query_ext_ctrl ctrl = {};
-	ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
-	while (true) {
-		if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
-			if (errno != EINVAL) {
-				errno_printerr("VIDIOC_QUERY_EXT_CTRL");
-			}
-			break;
-		}
-
-		MPControl control = {
-			.id = ctrl.id,
-			.type = ctrl.type,
-			.name = {},
-			.min = ctrl.minimum,
-			.max = ctrl.maximum,
-			.step = ctrl.step,
-			.default_value = ctrl.default_value,
-			.flags = ctrl.flags,
-			.element_size = ctrl.elem_size,
-			.element_count = ctrl.elems,
-			.dimensions_count = ctrl.nr_of_dims,
-			.dimensions = {},
-		};
-
-		strcpy(control.name, ctrl.name);
-		memcpy(control.dimensions, ctrl.dims,
-		       sizeof(uint32_t) * V4L2_CTRL_MAX_DIMS);
-
-		MPControlList *new_item = malloc(sizeof(MPControlList));
-		new_item->control = control;
-		new_item->next = item;
-		item = new_item;
-
-		ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
-	}
-
-	return item;
+        MPControlList *item = NULL;
+
+        struct v4l2_query_ext_ctrl ctrl = {};
+        ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
+        while (true) {
+                if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
+                        if (errno != EINVAL) {
+                                errno_printerr("VIDIOC_QUERY_EXT_CTRL");
+                        }
+                        break;
+                }
+
+                MPControl control = {
+                        .id = ctrl.id,
+                        .type = ctrl.type,
+                        .name = {},
+                        .min = ctrl.minimum,
+                        .max = ctrl.maximum,
+                        .step = ctrl.step,
+                        .default_value = ctrl.default_value,
+                        .flags = ctrl.flags,
+                        .element_size = ctrl.elem_size,
+                        .element_count = ctrl.elems,
+                        .dimensions_count = ctrl.nr_of_dims,
+                        .dimensions = {},
+                };
+
+                strcpy(control.name, ctrl.name);
+                memcpy(control.dimensions,
+                       ctrl.dims,
+                       sizeof(uint32_t) * V4L2_CTRL_MAX_DIMS);
+
+                MPControlList *new_item = malloc(sizeof(MPControlList));
+                new_item->control = control;
+                new_item->next = item;
+                item = new_item;
+
+                ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND;
+        }
+
+        return item;
 }
 
 MPControl *
 mp_control_list_get(MPControlList *list)
 {
-	g_return_val_if_fail(list, NULL);
-	return &list->control;
+        g_return_val_if_fail(list, NULL);
+        return &list->control;
 }
 
 MPControlList *
 mp_control_list_next(MPControlList *list)
 {
-	g_return_val_if_fail(list, NULL);
-	return list->next;
+        g_return_val_if_fail(list, NULL);
+        return list->next;
 }
 
 void
 mp_control_list_free(MPControlList *list)
 {
-	while (list) {
-		MPControlList *tmp = list;
-		list = tmp->next;
-		free(tmp);
-	}
+        while (list) {
+                MPControlList *tmp = list;
+                list = tmp->next;
+                free(tmp);
+        }
 }
 
 bool
 mp_camera_query_control(MPCamera *camera, uint32_t id, MPControl *control)
 {
-	struct v4l2_query_ext_ctrl ctrl = {};
-	ctrl.id = id;
-	if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
-		if (errno != EINVAL) {
-			errno_printerr("VIDIOC_QUERY_EXT_CTRL");
-		}
-		return false;
-	}
-
-	if (control) {
-		control->id = ctrl.id;
-		control->type = ctrl.type;
-		strcpy(control->name, ctrl.name);
-		control->min = ctrl.minimum;
-		control->max = ctrl.maximum;
-		control->step = ctrl.step;
-		control->default_value = ctrl.default_value;
-		control->flags = ctrl.flags;
-		control->element_size = ctrl.elem_size;
-		control->element_count = ctrl.elems;
-		control->dimensions_count = ctrl.nr_of_dims;
-		memcpy(control->dimensions, ctrl.dims,
-		       sizeof(uint32_t) * V4L2_CTRL_MAX_DIMS);
-	}
-	return true;
+        struct v4l2_query_ext_ctrl ctrl = {};
+        ctrl.id = id;
+        if (xioctl(control_fd(camera), VIDIOC_QUERY_EXT_CTRL, &ctrl) == -1) {
+                if (errno != EINVAL) {
+                        errno_printerr("VIDIOC_QUERY_EXT_CTRL");
+                }
+                return false;
+        }
+
+        if (control) {
+                control->id = ctrl.id;
+                control->type = ctrl.type;
+                strcpy(control->name, ctrl.name);
+                control->min = ctrl.minimum;
+                control->max = ctrl.maximum;
+                control->step = ctrl.step;
+                control->default_value = ctrl.default_value;
+                control->flags = ctrl.flags;
+                control->element_size = ctrl.elem_size;
+                control->element_count = ctrl.elems;
+                control->dimensions_count = ctrl.nr_of_dims;
+                memcpy(control->dimensions,
+                       ctrl.dims,
+                       sizeof(uint32_t) * V4L2_CTRL_MAX_DIMS);
+        }
+        return true;
 }
 
 static bool
 control_impl_int32(MPCamera *camera, uint32_t id, int request, int32_t *value)
 {
-	struct v4l2_ext_control ctrl = {};
-	ctrl.id = id;
-	ctrl.value = *value;
-
-	struct v4l2_ext_controls ctrls = {
-		.ctrl_class = 0,
-		.which = V4L2_CTRL_WHICH_CUR_VAL,
-		.count = 1,
-		.controls = &ctrl,
-	};
-	if (xioctl(control_fd(camera), request, &ctrls) == -1) {
-		return false;
-	}
-
-	*value = ctrl.value;
-	return true;
+        struct v4l2_ext_control ctrl = {};
+        ctrl.id = id;
+        ctrl.value = *value;
+
+        struct v4l2_ext_controls ctrls = {
+                .ctrl_class = 0,
+                .which = V4L2_CTRL_WHICH_CUR_VAL,
+                .count = 1,
+                .controls = &ctrl,
+        };
+        if (xioctl(control_fd(camera), request, &ctrls) == -1) {
+                return false;
+        }
+
+        *value = ctrl.value;
+        return true;
 }
 
 pid_t
 mp_camera_control_set_int32_bg(MPCamera *camera, uint32_t id, int32_t v)
 {
-	struct v4l2_ext_control ctrl = {};
-	ctrl.id = id;
-	ctrl.value = v;
-
-	struct v4l2_ext_controls ctrls = {
-		.ctrl_class = 0,
-		.which = V4L2_CTRL_WHICH_CUR_VAL,
-		.count = 1,
-		.controls = &ctrl,
-	};
-
-	int fd = control_fd(camera);
-
-	// fork only after all the memory has been read
-	pid_t pid = fork();
-	if (pid == -1) {
-		return 0; // discard errors, nothing to do in parent process
-	} else if (pid != 0) {
-		// parent process adding pid to wait list (to clear zombie processes)
-		mp_camera_add_bg_task(camera, pid);
-		return pid;
-	}
-
-	// ignore errors
-	xioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
-	// exit without calling exit handlers
-	_exit(0);
+        struct v4l2_ext_control ctrl = {};
+        ctrl.id = id;
+        ctrl.value = v;
+
+        struct v4l2_ext_controls ctrls = {
+                .ctrl_class = 0,
+                .which = V4L2_CTRL_WHICH_CUR_VAL,
+                .count = 1,
+                .controls = &ctrl,
+        };
+
+        int fd = control_fd(camera);
+
+        // fork only after all the memory has been read
+        pid_t pid = fork();
+        if (pid == -1) {
+                return 0; // discard errors, nothing to do in parent process
+        } else if (pid != 0) {
+                // parent process adding pid to wait list (to clear zombie processes)
+                mp_camera_add_bg_task(camera, pid);
+                return pid;
+        }
+
+        // ignore errors
+        xioctl(fd, VIDIOC_S_EXT_CTRLS, &ctrls);
+        // exit without calling exit handlers
+        _exit(0);
 }
 
 bool
 mp_camera_control_try_int32(MPCamera *camera, uint32_t id, int32_t *v)
 {
-	return control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, v);
+        return control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, v);
 }
 
 bool
 mp_camera_control_set_int32(MPCamera *camera, uint32_t id, int32_t v)
 {
-	return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &v);
+        return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &v);
 }
 
 int32_t
 mp_camera_control_get_int32(MPCamera *camera, uint32_t id)
 {
-	int32_t v = 0;
-	control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
-	return v;
+        int32_t v = 0;
+        control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
+        return v;
 }
 
 bool
 mp_camera_control_try_boolean(MPCamera *camera, uint32_t id, bool *v)
 {
-	int32_t value = *v;
-	bool s = control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, &value);
-	*v = value;
-	return s;
+        int32_t value = *v;
+        bool s = control_impl_int32(camera, id, VIDIOC_TRY_EXT_CTRLS, &value);
+        *v = value;
+        return s;
 }
 
 bool
 mp_camera_control_set_bool(MPCamera *camera, uint32_t id, bool v)
 {
-	int32_t value = v;
-	return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &value);
+        int32_t value = v;
+        return control_impl_int32(camera, id, VIDIOC_S_EXT_CTRLS, &value);
 }
 
 bool
 mp_camera_control_get_bool(MPCamera *camera, uint32_t id)
 {
-	int32_t v = false;
-	control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
-	return v;
+        int32_t v = false;
+        control_impl_int32(camera, id, VIDIOC_G_EXT_CTRLS, &v);
+        return v;
 }
 
 pid_t
 mp_camera_control_set_bool_bg(MPCamera *camera, uint32_t id, bool v)
 {
-	int32_t value = v;
-	return mp_camera_control_set_int32_bg(camera, id, value);
+        int32_t value = v;
+        return mp_camera_control_set_int32_bg(camera, id, value);
 }

+ 34 - 34
src/camera.h

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

+ 244 - 228
src/camera_config.c

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

+ 33 - 33
src/camera_config.h

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

+ 255 - 250
src/device.c

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

+ 15 - 13
src/device.h

@@ -5,8 +5,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
-bool mp_find_device_path(struct media_v2_intf_devnode devnode, char *path,
-			 int length);
+bool
+mp_find_device_path(struct media_v2_intf_devnode devnode, char *path, int length);
 
 typedef struct _MPDevice MPDevice;
 
@@ -15,35 +15,37 @@ MPDevice *mp_device_open(const char *path);
 MPDevice *mp_device_new(int fd);
 void mp_device_close(MPDevice *device);
 
-bool mp_device_setup_link(MPDevice *device, uint32_t source_pad_id,
-			  uint32_t sink_pad_id, bool enabled);
+bool mp_device_setup_link(MPDevice *device,
+                          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_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 uint32_t type);
+                                                         const uint32_t type);
 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);
 size_t mp_device_get_num_entities(const MPDevice *device);
 const struct media_v2_interface *
 mp_device_find_entity_interface(const MPDevice *device, uint32_t entity_id);
 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);
 size_t mp_device_get_num_interfaces(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_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,
-						       uint32_t entity_id);
+                                                       uint32_t entity_id);
 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,
-						   uint32_t sink);
+                                                   uint32_t sink);
 const struct media_v2_link *
 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);
@@ -56,7 +58,7 @@ MPDeviceList *mp_device_list_new();
 void mp_device_list_free(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_get(const MPDeviceList *device_list);

+ 131 - 117
src/flash.c

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

+ 213 - 197
src/gl_util.c

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

+ 4 - 2
src/gl_util.h

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

+ 108 - 100
src/gles2_debayer.c

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

+ 9 - 5
src/gles2_debayer.h

@@ -10,10 +10,14 @@ void gles2_debayer_free(GLES2Debayer *self);
 
 void gles2_debayer_use(GLES2Debayer *self);
 
-void gles2_debayer_configure(GLES2Debayer *self, const uint32_t dst_width,
-			     const uint32_t dst_height, const uint32_t src_width,
-			     const uint32_t src_height, const uint32_t rotation,
-			     const bool mirrored, const float *colormatrix,
-			     const uint8_t blacklevel);
+void gles2_debayer_configure(GLES2Debayer *self,
+                             const uint32_t dst_width,
+                             const uint32_t dst_height,
+                             const uint32_t src_width,
+                             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);

+ 460 - 444
src/io_pipeline.c

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

+ 11 - 11
src/io_pipeline.h

@@ -3,23 +3,23 @@
 #include "camera_config.h"
 
 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_height;
+        int preview_width;
+        int preview_height;
 
-	int device_rotation;
+        int device_rotation;
 
-	bool gain_is_manual;
-	int gain;
+        bool gain_is_manual;
+        int gain;
 
-	bool exposure_is_manual;
-	int exposure;
+        bool exposure_is_manual;
+        int exposure;
 
-	bool save_dng;
-	bool flash_enabled;
+        bool save_dng;
+        bool flash_enabled;
 };
 
 void mp_io_pipeline_start();

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 745 - 648
src/main.c


+ 13 - 13
src/main.h

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

+ 14 - 14
src/matrix.c

@@ -3,24 +3,24 @@
 void
 print_matrix(float m[9])
 {
-	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\n", m[6], m[7], m[8]);
+        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\n", m[6], m[7], m[8]);
 }
 
 void
 multiply_matrices(float a[9], float b[9], float out[9])
 {
-	// zero out target matrix
-	for (int i = 0; i < 9; i++) {
-		out[i] = 0;
-	}
+        // zero out target matrix
+        for (int i = 0; i < 9; i++) {
+                out[i] = 0;
+        }
 
-	for (int i = 0; i < 3; i++) {
-		for (int j = 0; j < 3; j++) {
-			for (int k = 0; k < 3; k++) {
-				out[i * 3 + j] += a[i * 3 + k] * b[k * 3 + j];
-			}
-		}
-	}
+        for (int i = 0; i < 3; i++) {
+                for (int j = 0; j < 3; j++) {
+                        for (int k = 0; k < 3; k++) {
+                                out[i * 3 + j] += a[i * 3 + k] * b[k * 3 + j];
+                        }
+                }
+        }
 }

+ 85 - 76
src/pipeline.c

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

+ 8 - 5
src/pipeline.h

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

+ 594 - 534
src/process_pipeline.c

@@ -1,15 +1,15 @@
 #include "process_pipeline.h"
 
-#include "pipeline.h"
-#include "zbar_pipeline.h"
-#include "io_pipeline.h"
-#include "main.h"
 #include "config.h"
 #include "gles2_debayer.h"
-#include <tiffio.h>
+#include "io_pipeline.h"
+#include "main.h"
+#include "pipeline.h"
+#include "zbar_pipeline.h"
 #include <assert.h>
-#include <math.h>
 #include <gtk/gtk.h>
+#include <math.h>
+#include <tiffio.h>
 
 #include "gl_util.h"
 #include <sys/mman.h>
@@ -17,7 +17,7 @@
 #define TIFFTAG_FORWARDMATRIX1 50964
 
 static const float colormatrix_srgb[] = { 3.2409, -1.5373, -0.4986, -0.9692, 1.8759,
-					  0.0415, 0.0556,  -0.2039, 1.0569 };
+                                          0.0415, 0.0556,  -0.2039, 1.0569 };
 
 static MPPipeline *pipeline;
 
@@ -58,113 +58,120 @@ static char capture_fname[255];
 static void
 register_custom_tiff_tags(TIFF *tif)
 {
-	static const TIFFFieldInfo custom_fields[] = {
-		{ TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 1, 1,
-		  "ForwardMatrix1" },
-	};
-
-	// Add missing dng fields
-	TIFFMergeFieldInfo(tif, custom_fields,
-			   sizeof(custom_fields) / sizeof(custom_fields[0]));
+        static const TIFFFieldInfo custom_fields[] = {
+                { TIFFTAG_FORWARDMATRIX1,
+                  -1,
+                  -1,
+                  TIFF_SRATIONAL,
+                  FIELD_CUSTOM,
+                  1,
+                  1,
+                  "ForwardMatrix1" },
+        };
+
+        // Add missing dng fields
+        TIFFMergeFieldInfo(tif,
+                           custom_fields,
+                           sizeof(custom_fields) / sizeof(custom_fields[0]));
 }
 
 static bool
 find_processor(char *script)
 {
-	char filename[] = "postprocess.sh";
-
-	// Check postprocess.sh in the current working directory
-	sprintf(script, "./data/%s", filename);
-	if (access(script, F_OK) != -1) {
-		sprintf(script, "./data/%s", filename);
-		printf("Found postprocessor script at %s\n", script);
-		return true;
-	}
-
-	// Check for a script in XDG_CONFIG_HOME
-	sprintf(script, "%s/megapixels/%s", g_get_user_config_dir(), filename);
-	if (access(script, F_OK) != -1) {
-		printf("Found postprocessor script at %s\n", script);
-		return true;
-	}
-
-	// Check user overridden /etc/megapixels/postprocessor.sh
-	sprintf(script, "%s/megapixels/%s", SYSCONFDIR, filename);
-	if (access(script, F_OK) != -1) {
-		printf("Found postprocessor script at %s\n", script);
-		return true;
-	}
-
-	// Check packaged /usr/share/megapixels/postprocessor.sh
-	sprintf(script, "%s/megapixels/%s", DATADIR, filename);
-	if (access(script, F_OK) != -1) {
-		printf("Found postprocessor script at %s\n", script);
-		return true;
-	}
-
-	return false;
+        char filename[] = "postprocess.sh";
+
+        // Check postprocess.sh in the current working directory
+        sprintf(script, "./data/%s", filename);
+        if (access(script, F_OK) != -1) {
+                sprintf(script, "./data/%s", filename);
+                printf("Found postprocessor script at %s\n", script);
+                return true;
+        }
+
+        // Check for a script in XDG_CONFIG_HOME
+        sprintf(script, "%s/megapixels/%s", g_get_user_config_dir(), filename);
+        if (access(script, F_OK) != -1) {
+                printf("Found postprocessor script at %s\n", script);
+                return true;
+        }
+
+        // Check user overridden /etc/megapixels/postprocessor.sh
+        sprintf(script, "%s/megapixels/%s", SYSCONFDIR, filename);
+        if (access(script, F_OK) != -1) {
+                printf("Found postprocessor script at %s\n", script);
+                return true;
+        }
+
+        // Check packaged /usr/share/megapixels/postprocessor.sh
+        sprintf(script, "%s/megapixels/%s", DATADIR, filename);
+        if (access(script, F_OK) != -1) {
+                printf("Found postprocessor script at %s\n", script);
+                return true;
+        }
+
+        return false;
 }
 
 static void
 setup(MPPipeline *pipeline, const void *data)
 {
-	TIFFSetTagExtender(register_custom_tiff_tags);
+        TIFFSetTagExtender(register_custom_tiff_tags);
 
-	if (!find_processor(processing_script)) {
-		g_printerr("Could not find any post-process script\n");
-		exit(1);
-	}
+        if (!find_processor(processing_script)) {
+                g_printerr("Could not find any post-process script\n");
+                exit(1);
+        }
 }
 
 void
 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);
 
-	mp_zbar_pipeline_start();
+        mp_zbar_pipeline_start();
 }
 
 void
 mp_process_pipeline_stop()
 {
-	mp_pipeline_free(pipeline);
+        mp_pipeline_free(pipeline);
 
-	mp_zbar_pipeline_stop();
+        mp_zbar_pipeline_stop();
 }
 
 void
 mp_process_pipeline_sync()
 {
-	mp_pipeline_sync(pipeline);
+        mp_pipeline_sync(pipeline);
 }
 
 #define NUM_BUFFERS 4
 
 struct _MPProcessPipelineBuffer {
-	GLuint texture_id;
+        GLuint texture_id;
 
-	_Atomic(int) refcount;
+        _Atomic(int) refcount;
 };
 static MPProcessPipelineBuffer output_buffers[NUM_BUFFERS];
 
 void
 mp_process_pipeline_buffer_ref(MPProcessPipelineBuffer *buf)
 {
-	++buf->refcount;
+        ++buf->refcount;
 }
 
 void
 mp_process_pipeline_buffer_unref(MPProcessPipelineBuffer *buf)
 {
-	--buf->refcount;
+        --buf->refcount;
 }
 
 uint32_t
 mp_process_pipeline_buffer_get_texture_id(MPProcessPipelineBuffer *buf)
 {
-	return buf->texture_id;
+        return buf->texture_id;
 }
 
 static GLES2Debayer *gles2_debayer = NULL;
@@ -181,584 +188,637 @@ extern RENDERDOC_API_1_1_2 *rdoc_api;
 static void
 init_gl(MPPipeline *pipeline, GdkSurface **surface)
 {
-	GError *error = NULL;
-	context = gdk_surface_create_gl_context(*surface, &error);
-	if (context == NULL) {
-		printf("Failed to initialize OpenGL context: %s\n", error->message);
-		g_clear_error(&error);
-		return;
-	}
-
-	gdk_gl_context_set_use_es(context, true);
-	gdk_gl_context_set_required_version(context, 2, 0);
-	gdk_gl_context_set_forward_compatible(context, false);
+        GError *error = NULL;
+        context = gdk_surface_create_gl_context(*surface, &error);
+        if (context == NULL) {
+                printf("Failed to initialize OpenGL context: %s\n", error->message);
+                g_clear_error(&error);
+                return;
+        }
+
+        gdk_gl_context_set_use_es(context, true);
+        gdk_gl_context_set_required_version(context, 2, 0);
+        gdk_gl_context_set_forward_compatible(context, false);
 #ifdef DEBUG
-	gdk_gl_context_set_debug_enabled(context, true);
+        gdk_gl_context_set_debug_enabled(context, true);
 #else
-	gdk_gl_context_set_debug_enabled(context, false);
+        gdk_gl_context_set_debug_enabled(context, false);
 #endif
 
-	gdk_gl_context_realize(context, &error);
-	if (error != NULL) {
-		printf("Failed to create OpenGL context: %s\n", error->message);
-		g_clear_object(&context);
-		g_clear_error(&error);
-		return;
-	}
-
-	gdk_gl_context_make_current(context);
-	check_gl();
-
-	// Make a VAO for OpenGL
-	if (!gdk_gl_context_get_use_es(context)) {
-		GLuint vao;
-		glGenVertexArrays(1, &vao);
-		glBindVertexArray(vao);
-		check_gl();
-	}
-
-	gles2_debayer = gles2_debayer_new(MP_PIXEL_FMT_BGGR8);
-	check_gl();
-
-	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-	check_gl();
-
-	gles2_debayer_use(gles2_debayer);
-
-	for (size_t i = 0; i < NUM_BUFFERS; ++i) {
-		glGenTextures(1, &output_buffers[i].texture_id);
-		glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	}
-
-	glBindTexture(GL_TEXTURE_2D, 0);
-
-	gboolean is_es = gdk_gl_context_get_use_es(context);
-	int major, minor;
-	gdk_gl_context_get_version(context, &major, &minor);
-
-	printf("Initialized %s %d.%d\n", is_es ? "OpenGL ES" : "OpenGL", major,
-	       minor);
+        gdk_gl_context_realize(context, &error);
+        if (error != NULL) {
+                printf("Failed to create OpenGL context: %s\n", error->message);
+                g_clear_object(&context);
+                g_clear_error(&error);
+                return;
+        }
+
+        gdk_gl_context_make_current(context);
+        check_gl();
+
+        // Make a VAO for OpenGL
+        if (!gdk_gl_context_get_use_es(context)) {
+                GLuint vao;
+                glGenVertexArrays(1, &vao);
+                glBindVertexArray(vao);
+                check_gl();
+        }
+
+        gles2_debayer = gles2_debayer_new(MP_PIXEL_FMT_BGGR8);
+        check_gl();
+
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+        check_gl();
+
+        gles2_debayer_use(gles2_debayer);
+
+        for (size_t i = 0; i < NUM_BUFFERS; ++i) {
+                glGenTextures(1, &output_buffers[i].texture_id);
+                glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        }
+
+        glBindTexture(GL_TEXTURE_2D, 0);
+
+        gboolean is_es = gdk_gl_context_get_use_es(context);
+        int major, minor;
+        gdk_gl_context_get_version(context, &major, &minor);
+
+        printf("Initialized %s %d.%d\n",
+               is_es ? "OpenGL ES" : "OpenGL",
+               major,
+               minor);
 }
 
 void
 mp_process_pipeline_init_gl(GdkSurface *surface)
 {
-	mp_pipeline_invoke(pipeline, (MPPipelineCallback)init_gl, &surface,
-			   sizeof(GdkSurface *));
+        mp_pipeline_invoke(pipeline,
+                           (MPPipelineCallback)init_gl,
+                           &surface,
+                           sizeof(GdkSurface *));
 }
 
 static GdkTexture *
 process_image_for_preview(const uint8_t *image)
 {
 #ifdef PROFILE_DEBAYER
-	clock_t t1 = clock();
+        clock_t t1 = clock();
 #endif
 
-	// Pick an available buffer
-	MPProcessPipelineBuffer *output_buffer = NULL;
-	for (size_t i = 0; i < NUM_BUFFERS; ++i) {
-		if (output_buffers[i].refcount == 0) {
-			output_buffer = &output_buffers[i];
-		}
-	}
+        // Pick an available buffer
+        MPProcessPipelineBuffer *output_buffer = NULL;
+        for (size_t i = 0; i < NUM_BUFFERS; ++i) {
+                if (output_buffers[i].refcount == 0) {
+                        output_buffer = &output_buffers[i];
+                }
+        }
 
-	if (output_buffer == NULL) {
-		return NULL;
-	}
-	assert(output_buffer != NULL);
+        if (output_buffer == NULL) {
+                return NULL;
+        }
+        assert(output_buffer != NULL);
 
 #ifdef RENDERDOC
-	if (rdoc_api) {
-		rdoc_api->StartFrameCapture(NULL, NULL);
-	}
+        if (rdoc_api) {
+                rdoc_api->StartFrameCapture(NULL, NULL);
+        }
 #endif
 
-	// Copy image to a GL texture. TODO: This can be avoided
-	GLuint input_texture;
-	glGenTextures(1, &input_texture);
-	glBindTexture(GL_TEXTURE_2D, input_texture);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-	glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, mode.width, mode.height, 0,
-		     GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
-	check_gl();
-
-	gles2_debayer_process(gles2_debayer, output_buffer->texture_id,
-			      input_texture);
-	check_gl();
-
-	glFinish();
-
-	glDeleteTextures(1, &input_texture);
+        // Copy image to a GL texture. TODO: This can be avoided
+        GLuint input_texture;
+        glGenTextures(1, &input_texture);
+        glBindTexture(GL_TEXTURE_2D, input_texture);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glTexImage2D(GL_TEXTURE_2D,
+                     0,
+                     GL_LUMINANCE,
+                     mode.width,
+                     mode.height,
+                     0,
+                     GL_LUMINANCE,
+                     GL_UNSIGNED_BYTE,
+                     image);
+        check_gl();
+
+        gles2_debayer_process(
+                gles2_debayer, output_buffer->texture_id, input_texture);
+        check_gl();
+
+        glFinish();
+
+        glDeleteTextures(1, &input_texture);
 
 #ifdef PROFILE_DEBAYER
-	clock_t t2 = clock();
-	printf("process_image_for_preview %fms\n",
-	       (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
+        clock_t t2 = clock();
+        printf("process_image_for_preview %fms\n",
+               (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
 #endif
 
 #ifdef RENDERDOC
-	if (rdoc_api) {
-		rdoc_api->EndFrameCapture(NULL, NULL);
-	}
+        if (rdoc_api) {
+                rdoc_api->EndFrameCapture(NULL, NULL);
+        }
 #endif
 
-	mp_process_pipeline_buffer_ref(output_buffer);
-	mp_main_set_preview(output_buffer);
-
-	// Create a thumbnail from the preview for the last capture
-	GdkTexture *thumb = NULL;
-	if (captures_remaining == 1) {
-		printf("Making thumbnail\n");
-
-		size_t size = output_buffer_width * output_buffer_height *
-			      sizeof(uint32_t);
-
-		uint32_t *data = g_malloc_n(size, 1);
-
-		glReadPixels(0, 0, output_buffer_width, output_buffer_height,
-			     GL_RGBA, GL_UNSIGNED_BYTE, data);
-		check_gl();
-
-		// Flip vertically
-		for (size_t y = 0; y < output_buffer_height / 2; ++y) {
-			for (size_t x = 0; x < output_buffer_width; ++x) {
-				uint32_t tmp = data[(output_buffer_height - y - 1) *
-							    output_buffer_width +
-						    x];
-				data[(output_buffer_height - y - 1) *
-					     output_buffer_width +
-				     x] = data[y * output_buffer_width + x];
-				data[y * output_buffer_width + x] = tmp;
-			}
-		}
-
-		thumb = gdk_memory_texture_new(
-			output_buffer_width, output_buffer_height,
-			GDK_MEMORY_R8G8B8A8, g_bytes_new_take(data, size),
-			output_buffer_width * sizeof(uint32_t));
-	}
-
-	return thumb;
+        mp_process_pipeline_buffer_ref(output_buffer);
+        mp_main_set_preview(output_buffer);
+
+        // Create a thumbnail from the preview for the last capture
+        GdkTexture *thumb = NULL;
+        if (captures_remaining == 1) {
+                printf("Making thumbnail\n");
+
+                size_t size = output_buffer_width * output_buffer_height *
+                              sizeof(uint32_t);
+
+                uint32_t *data = g_malloc_n(size, 1);
+
+                glReadPixels(0,
+                             0,
+                             output_buffer_width,
+                             output_buffer_height,
+                             GL_RGBA,
+                             GL_UNSIGNED_BYTE,
+                             data);
+                check_gl();
+
+                // Flip vertically
+                for (size_t y = 0; y < output_buffer_height / 2; ++y) {
+                        for (size_t x = 0; x < output_buffer_width; ++x) {
+                                uint32_t tmp = data[(output_buffer_height - y - 1) *
+                                                            output_buffer_width +
+                                                    x];
+                                data[(output_buffer_height - y - 1) *
+                                             output_buffer_width +
+                                     x] = data[y * output_buffer_width + x];
+                                data[y * output_buffer_width + x] = tmp;
+                        }
+                }
+
+                thumb = gdk_memory_texture_new(output_buffer_width,
+                                               output_buffer_height,
+                                               GDK_MEMORY_R8G8B8A8,
+                                               g_bytes_new_take(data, size),
+                                               output_buffer_width *
+                                                       sizeof(uint32_t));
+        }
+
+        return thumb;
 }
 
 static void
 process_image_for_capture(const uint8_t *image, int count)
 {
-	time_t rawtime;
-	time(&rawtime);
-	struct tm tim = *(localtime(&rawtime));
-
-	char datetime[20] = { 0 };
-	strftime(datetime, 20, "%Y:%m:%d %H:%M:%S", &tim);
-
-	char fname[255];
-	sprintf(fname, "%s/%d.dng", burst_dir, count);
-
-	TIFF *tif = TIFFOpen(fname, "w");
-	if (!tif) {
-		printf("Could not open tiff\n");
-	}
-
-	// Define TIFF thumbnail
-	TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
-	TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode.width >> 4);
-	TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode.height >> 4);
-	TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
-	TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
-	TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
-	TIFFSetField(tif, TIFFTAG_MAKE, mp_get_device_make());
-	TIFFSetField(tif, TIFFTAG_MODEL, mp_get_device_model());
-	uint16_t orientation;
-	if (camera_rotation == 0) {
-		orientation = camera->mirrored ? ORIENTATION_TOPRIGHT :
-						       ORIENTATION_TOPLEFT;
-	} else if (camera_rotation == 90) {
-		orientation = camera->mirrored ? ORIENTATION_RIGHTBOT :
-						       ORIENTATION_LEFTBOT;
-	} else if (camera_rotation == 180) {
-		orientation = camera->mirrored ? ORIENTATION_BOTLEFT :
-						       ORIENTATION_BOTRIGHT;
-	} else {
-		orientation = camera->mirrored ? ORIENTATION_LEFTTOP :
-						       ORIENTATION_RIGHTTOP;
-	}
-	TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation);
-	TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
-	TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
-	TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
-	TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels");
-	long sub_offset = 0;
-	TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
-	TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0");
-	TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0");
-	char uniquecameramodel[255];
-	sprintf(uniquecameramodel, "%s %s", mp_get_device_make(),
-		mp_get_device_model());
-	TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, uniquecameramodel);
-	if (camera->colormatrix[0]) {
-		TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, camera->colormatrix);
-	} else {
-		TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, colormatrix_srgb);
-	}
-	if (camera->forwardmatrix[0]) {
-		TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, camera->forwardmatrix);
-	}
-	static const float neutral[] = { 1.0, 1.0, 1.0 };
-	TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral);
-	TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, 21);
-	// Write black thumbnail, only windows uses this
-	{
-		unsigned char *buf =
-			(unsigned char *)calloc(1, (mode.width >> 4) * 3);
-		for (int row = 0; row < (mode.height >> 4); row++) {
-			TIFFWriteScanline(tif, buf, row, 0);
-		}
-		free(buf);
-	}
-	TIFFWriteDirectory(tif);
-
-	// Define main photo
-	TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
-	TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode.width);
-	TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode.height);
-	TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE,
-		     mp_pixel_format_bits_per_pixel(mode.pixel_format));
-	TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
-	TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
-	TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
-	static const short cfapatterndim[] = { 2, 2 };
-	TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfapatterndim);
+        time_t rawtime;
+        time(&rawtime);
+        struct tm tim = *(localtime(&rawtime));
+
+        char datetime[20] = { 0 };
+        strftime(datetime, 20, "%Y:%m:%d %H:%M:%S", &tim);
+
+        char fname[255];
+        sprintf(fname, "%s/%d.dng", burst_dir, count);
+
+        TIFF *tif = TIFFOpen(fname, "w");
+        if (!tif) {
+                printf("Could not open tiff\n");
+        }
+
+        // Define TIFF thumbnail
+        TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
+        TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode.width >> 4);
+        TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode.height >> 4);
+        TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
+        TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
+        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
+        TIFFSetField(tif, TIFFTAG_MAKE, mp_get_device_make());
+        TIFFSetField(tif, TIFFTAG_MODEL, mp_get_device_model());
+        uint16_t orientation;
+        if (camera_rotation == 0) {
+                orientation = camera->mirrored ? ORIENTATION_TOPRIGHT :
+                                                 ORIENTATION_TOPLEFT;
+        } else if (camera_rotation == 90) {
+                orientation = camera->mirrored ? ORIENTATION_RIGHTBOT :
+                                                 ORIENTATION_LEFTBOT;
+        } else if (camera_rotation == 180) {
+                orientation = camera->mirrored ? ORIENTATION_BOTLEFT :
+                                                 ORIENTATION_BOTRIGHT;
+        } else {
+                orientation = camera->mirrored ? ORIENTATION_LEFTTOP :
+                                                 ORIENTATION_RIGHTTOP;
+        }
+        TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation);
+        TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
+        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
+        TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+        TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels");
+        long sub_offset = 0;
+        TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
+        TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0");
+        TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0");
+        char uniquecameramodel[255];
+        sprintf(uniquecameramodel,
+                "%s %s",
+                mp_get_device_make(),
+                mp_get_device_model());
+        TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, uniquecameramodel);
+        if (camera->colormatrix[0]) {
+                TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, camera->colormatrix);
+        } else {
+                TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, colormatrix_srgb);
+        }
+        if (camera->forwardmatrix[0]) {
+                TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, camera->forwardmatrix);
+        }
+        static const float neutral[] = { 1.0, 1.0, 1.0 };
+        TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral);
+        TIFFSetField(tif, TIFFTAG_CALIBRATIONILLUMINANT1, 21);
+        // Write black thumbnail, only windows uses this
+        {
+                unsigned char *buf =
+                        (unsigned char *)calloc(1, (mode.width >> 4) * 3);
+                for (int row = 0; row < (mode.height >> 4); row++) {
+                        TIFFWriteScanline(tif, buf, row, 0);
+                }
+                free(buf);
+        }
+        TIFFWriteDirectory(tif);
+
+        // Define main photo
+        TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
+        TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, mode.width);
+        TIFFSetField(tif, TIFFTAG_IMAGELENGTH, mode.height);
+        TIFFSetField(tif,
+                     TIFFTAG_BITSPERSAMPLE,
+                     mp_pixel_format_bits_per_pixel(mode.pixel_format));
+        TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
+        TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
+        TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
+        static const short cfapatterndim[] = { 2, 2 };
+        TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfapatterndim);
 #if (TIFFLIB_VERSION < 20201219) && !LIBTIFF_CFA_PATTERN
-	TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\002\001\001\000"); // BGGR
+        TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\002\001\001\000"); // BGGR
 #else
-	TIFFSetField(tif, TIFFTAG_CFAPATTERN, 4, "\002\001\001\000"); // BGGR
+        TIFFSetField(tif, TIFFTAG_CFAPATTERN, 4, "\002\001\001\000"); // BGGR
 #endif
-	printf("TIFF version %d\n", TIFFLIB_VERSION);
-	int whitelevel = camera->whitelevel;
-	if (!whitelevel) {
-		whitelevel =
-			(1 << mp_pixel_format_pixel_depth(mode.pixel_format)) - 1;
-	}
-	TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &whitelevel);
-	if (camera->blacklevel) {
-		const float blacklevel = camera->blacklevel;
-		TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 1, &blacklevel);
-	}
-	TIFFCheckpointDirectory(tif);
-	printf("Writing frame to %s\n", fname);
-
-	for (int row = 0; row < mode.height; row++) {
-		TIFFWriteScanline(
-			tif,
-			(void *)image +
-				(row * mp_pixel_format_width_to_bytes(
-					       mode.pixel_format, mode.width)),
-			row, 0);
-	}
-	TIFFWriteDirectory(tif);
-
-	// Add an EXIF block to the tiff
-	TIFFCreateEXIFDirectory(tif);
-	// 1 = manual, 2 = full auto, 3 = aperture priority, 4 = shutter priority
-	if (!exposure_is_manual) {
-		TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 2);
-	} else {
-		TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 1);
-	}
-
-	TIFFSetField(tif, EXIFTAG_EXPOSURETIME,
-		     (mode.frame_interval.numerator /
-		      (float)mode.frame_interval.denominator) /
-			     ((float)mode.height / (float)exposure));
-	if (camera->iso_min && camera->iso_max) {
-		uint16_t isospeed = remap(gain - 1, 0, gain_max, camera->iso_min,
-					  camera->iso_max);
-		TIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1, &isospeed);
-	}
-	TIFFSetField(tif, EXIFTAG_FLASH, 0);
-
-	TIFFSetField(tif, EXIFTAG_DATETIMEORIGINAL, datetime);
-	TIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, datetime);
-	if (camera->fnumber) {
-		TIFFSetField(tif, EXIFTAG_FNUMBER, camera->fnumber);
-	}
-	if (camera->focallength) {
-		TIFFSetField(tif, EXIFTAG_FOCALLENGTH, camera->focallength);
-	}
-	if (camera->focallength && camera->cropfactor) {
-		TIFFSetField(tif, EXIFTAG_FOCALLENGTHIN35MMFILM,
-			     (short)(camera->focallength * camera->cropfactor));
-	}
-	uint64_t exif_offset = 0;
-	TIFFWriteCustomDirectory(tif, &exif_offset);
-	TIFFFreeDirectory(tif);
-
-	// Update exif pointer
-	TIFFSetDirectory(tif, 0);
-	TIFFSetField(tif, TIFFTAG_EXIFIFD, exif_offset);
-	TIFFRewriteDirectory(tif);
-
-	TIFFClose(tif);
+        printf("TIFF version %d\n", TIFFLIB_VERSION);
+        int whitelevel = camera->whitelevel;
+        if (!whitelevel) {
+                whitelevel =
+                        (1 << mp_pixel_format_pixel_depth(mode.pixel_format)) - 1;
+        }
+        TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &whitelevel);
+        if (camera->blacklevel) {
+                const float blacklevel = camera->blacklevel;
+                TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 1, &blacklevel);
+        }
+        TIFFCheckpointDirectory(tif);
+        printf("Writing frame to %s\n", fname);
+
+        for (int row = 0; row < mode.height; row++) {
+                TIFFWriteScanline(
+                        tif,
+                        (void *)image +
+                                (row * mp_pixel_format_width_to_bytes(
+                                               mode.pixel_format, mode.width)),
+                        row,
+                        0);
+        }
+        TIFFWriteDirectory(tif);
+
+        // Add an EXIF block to the tiff
+        TIFFCreateEXIFDirectory(tif);
+        // 1 = manual, 2 = full auto, 3 = aperture priority, 4 = shutter priority
+        if (!exposure_is_manual) {
+                TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 2);
+        } else {
+                TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 1);
+        }
+
+        TIFFSetField(tif,
+                     EXIFTAG_EXPOSURETIME,
+                     (mode.frame_interval.numerator /
+                      (float)mode.frame_interval.denominator) /
+                             ((float)mode.height / (float)exposure));
+        if (camera->iso_min && camera->iso_max) {
+                uint16_t isospeed = remap(
+                        gain - 1, 0, gain_max, camera->iso_min, camera->iso_max);
+                TIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1, &isospeed);
+        }
+        TIFFSetField(tif, EXIFTAG_FLASH, 0);
+
+        TIFFSetField(tif, EXIFTAG_DATETIMEORIGINAL, datetime);
+        TIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, datetime);
+        if (camera->fnumber) {
+                TIFFSetField(tif, EXIFTAG_FNUMBER, camera->fnumber);
+        }
+        if (camera->focallength) {
+                TIFFSetField(tif, EXIFTAG_FOCALLENGTH, camera->focallength);
+        }
+        if (camera->focallength && camera->cropfactor) {
+                TIFFSetField(tif,
+                             EXIFTAG_FOCALLENGTHIN35MMFILM,
+                             (short)(camera->focallength * camera->cropfactor));
+        }
+        uint64_t exif_offset = 0;
+        TIFFWriteCustomDirectory(tif, &exif_offset);
+        TIFFFreeDirectory(tif);
+
+        // Update exif pointer
+        TIFFSetDirectory(tif, 0);
+        TIFFSetField(tif, TIFFTAG_EXIFIFD, exif_offset);
+        TIFFRewriteDirectory(tif);
+
+        TIFFClose(tif);
 }
 
 static void
 post_process_finished(GSubprocess *proc, GAsyncResult *res, GdkTexture *thumb)
 {
-	char *stdout;
-	g_subprocess_communicate_utf8_finish(proc, res, &stdout, NULL, NULL);
-
-	// The last line contains the file name
-	int end = strlen(stdout);
-	// Skip the newline at the end
-	stdout[--end] = '\0';
-
-	char *path = path = stdout + end - 1;
-	do {
-		if (*path == '\n') {
-			path++;
-			break;
-		}
-		--path;
-	} while (path > stdout);
-
-	mp_main_capture_completed(thumb, path);
+        char *stdout;
+        g_subprocess_communicate_utf8_finish(proc, res, &stdout, NULL, NULL);
+
+        // The last line contains the file name
+        int end = strlen(stdout);
+        // Skip the newline at the end
+        stdout[--end] = '\0';
+
+        char *path = path = stdout + end - 1;
+        do {
+                if (*path == '\n') {
+                        path++;
+                        break;
+                }
+                --path;
+        } while (path > stdout);
+
+        mp_main_capture_completed(thumb, path);
 }
 
 static void
 process_capture_burst(GdkTexture *thumb)
 {
-	time_t rawtime;
-	time(&rawtime);
-	struct tm tim = *(localtime(&rawtime));
-
-	char timestamp[30];
-	strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim);
-
-	if (g_get_user_special_dir(G_USER_DIRECTORY_PICTURES) != NULL) {
-		sprintf(capture_fname, "%s/IMG%s",
-			g_get_user_special_dir(G_USER_DIRECTORY_PICTURES),
-			timestamp);
-	} else if (getenv("XDG_PICTURES_DIR") != NULL) {
-		sprintf(capture_fname, "%s/IMG%s", getenv("XDG_PICTURES_DIR"),
-			timestamp);
-	} else {
-		sprintf(capture_fname, "%s/Pictures/IMG%s", getenv("HOME"),
-			timestamp);
-	}
-
-	char save_dng_s[2] = "0";
-	if (save_dng) {
-		save_dng_s[0] = '1';
-	}
-
-	// Start post-processing the captured burst
-	g_print("Post process %s to %s.ext (save-dng %s)\n", burst_dir,
-		capture_fname, save_dng_s);
-	GError *error = NULL;
-	GSubprocess *proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE, &error,
-					     processing_script, burst_dir,
-					     capture_fname, save_dng_s, NULL);
-
-	if (!proc) {
-		g_printerr("Failed to spawn postprocess process: %s\n",
-			   error->message);
-		return;
-	}
-
-	g_subprocess_communicate_utf8_async(
-		proc, NULL, NULL, (GAsyncReadyCallback)post_process_finished, thumb);
+        time_t rawtime;
+        time(&rawtime);
+        struct tm tim = *(localtime(&rawtime));
+
+        char timestamp[30];
+        strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim);
+
+        if (g_get_user_special_dir(G_USER_DIRECTORY_PICTURES) != NULL) {
+                sprintf(capture_fname,
+                        "%s/IMG%s",
+                        g_get_user_special_dir(G_USER_DIRECTORY_PICTURES),
+                        timestamp);
+        } else if (getenv("XDG_PICTURES_DIR") != NULL) {
+                sprintf(capture_fname,
+                        "%s/IMG%s",
+                        getenv("XDG_PICTURES_DIR"),
+                        timestamp);
+        } else {
+                sprintf(capture_fname,
+                        "%s/Pictures/IMG%s",
+                        getenv("HOME"),
+                        timestamp);
+        }
+
+        char save_dng_s[2] = "0";
+        if (save_dng) {
+                save_dng_s[0] = '1';
+        }
+
+        // Start post-processing the captured burst
+        g_print("Post process %s to %s.ext (save-dng %s)\n",
+                burst_dir,
+                capture_fname,
+                save_dng_s);
+        GError *error = NULL;
+        GSubprocess *proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE,
+                                             &error,
+                                             processing_script,
+                                             burst_dir,
+                                             capture_fname,
+                                             save_dng_s,
+                                             NULL);
+
+        if (!proc) {
+                g_printerr("Failed to spawn postprocess process: %s\n",
+                           error->message);
+                return;
+        }
+
+        g_subprocess_communicate_utf8_async(
+                proc, NULL, NULL, (GAsyncReadyCallback)post_process_finished, thumb);
 }
 
 static void
 process_image(MPPipeline *pipeline, const MPBuffer *buffer)
 {
 #ifdef PROFILE_PROCESS
-	clock_t t1 = clock();
+        clock_t t1 = clock();
 #endif
 
-	size_t size = mp_pixel_format_width_to_bytes(mode.pixel_format, mode.width) *
-		      mode.height;
-	uint8_t *image = malloc(size);
-	memcpy(image, buffer->data, size);
-	mp_io_pipeline_release_buffer(buffer->index);
+        size_t size = mp_pixel_format_width_to_bytes(mode.pixel_format, mode.width) *
+                      mode.height;
+        uint8_t *image = malloc(size);
+        memcpy(image, buffer->data, size);
+        mp_io_pipeline_release_buffer(buffer->index);
 
-	MPZBarImage *zbar_image =
-		mp_zbar_image_new(image, mode.pixel_format, mode.width, mode.height,
-				  camera_rotation, camera->mirrored);
-	mp_zbar_pipeline_process_image(mp_zbar_image_ref(zbar_image));
+        MPZBarImage *zbar_image = mp_zbar_image_new(image,
+                                                    mode.pixel_format,
+                                                    mode.width,
+                                                    mode.height,
+                                                    camera_rotation,
+                                                    camera->mirrored);
+        mp_zbar_pipeline_process_image(mp_zbar_image_ref(zbar_image));
 
 #ifdef PROFILE_PROCESS
-	clock_t t2 = clock();
+        clock_t t2 = clock();
 #endif
 
-	GdkTexture *thumb = process_image_for_preview(image);
+        GdkTexture *thumb = process_image_for_preview(image);
 
-	if (captures_remaining > 0) {
-		int count = burst_length - captures_remaining;
-		--captures_remaining;
+        if (captures_remaining > 0) {
+                int count = burst_length - captures_remaining;
+                --captures_remaining;
 
-		process_image_for_capture(image, count);
+                process_image_for_capture(image, count);
 
-		if (captures_remaining == 0) {
-			assert(thumb);
-			process_capture_burst(thumb);
-		} else {
-			assert(!thumb);
-		}
-	} else {
-		assert(!thumb);
-	}
+                if (captures_remaining == 0) {
+                        assert(thumb);
+                        process_capture_burst(thumb);
+                } else {
+                        assert(!thumb);
+                }
+        } else {
+                assert(!thumb);
+        }
 
-	mp_zbar_image_unref(zbar_image);
+        mp_zbar_image_unref(zbar_image);
 
-	++frames_processed;
-	if (captures_remaining == 0) {
-		is_capturing = false;
-	}
+        ++frames_processed;
+        if (captures_remaining == 0) {
+                is_capturing = false;
+        }
 
 #ifdef PROFILE_PROCESS
-	clock_t t3 = clock();
-	printf("process_image %fms, step 1:%fms, step 2:%fms\n",
-	       (float)(t3 - t1) / CLOCKS_PER_SEC * 1000,
-	       (float)(t2 - t1) / CLOCKS_PER_SEC * 1000,
-	       (float)(t3 - t2) / CLOCKS_PER_SEC * 1000);
+        clock_t t3 = clock();
+        printf("process_image %fms, step 1:%fms, step 2:%fms\n",
+               (float)(t3 - t1) / CLOCKS_PER_SEC * 1000,
+               (float)(t2 - t1) / CLOCKS_PER_SEC * 1000,
+               (float)(t3 - t2) / CLOCKS_PER_SEC * 1000);
 #endif
 }
 
 void
 mp_process_pipeline_process_image(MPBuffer buffer)
 {
-	// If we haven't processed the previous frame yet, drop this one
-	if (frames_received != frames_processed && !is_capturing) {
-		mp_io_pipeline_release_buffer(buffer.index);
-		return;
-	}
-
-	++frames_received;
-
-	mp_pipeline_invoke(pipeline, (MPPipelineCallback)process_image, &buffer,
-			   sizeof(MPBuffer));
+        // If we haven't processed the previous frame yet, drop this one
+        if (frames_received != frames_processed && !is_capturing) {
+                mp_io_pipeline_release_buffer(buffer.index);
+                return;
+        }
+
+        ++frames_received;
+
+        mp_pipeline_invoke(pipeline,
+                           (MPPipelineCallback)process_image,
+                           &buffer,
+                           sizeof(MPBuffer));
 }
 
 static void
 capture()
 {
-	char template[] = "/tmp/megapixels.XXXXXX";
-	char *tempdir;
-	tempdir = mkdtemp(template);
+        char template[] = "/tmp/megapixels.XXXXXX";
+        char *tempdir;
+        tempdir = mkdtemp(template);
 
-	if (tempdir == NULL) {
-		g_printerr("Could not make capture directory %s\n", template);
-		exit(EXIT_FAILURE);
-	}
+        if (tempdir == NULL) {
+                g_printerr("Could not make capture directory %s\n", template);
+                exit(EXIT_FAILURE);
+        }
 
-	strcpy(burst_dir, tempdir);
+        strcpy(burst_dir, tempdir);
 
-	captures_remaining = burst_length;
+        captures_remaining = burst_length;
 }
 
 void
 mp_process_pipeline_capture()
 {
-	is_capturing = true;
+        is_capturing = true;
 
-	mp_pipeline_invoke(pipeline, capture, NULL, 0);
+        mp_pipeline_invoke(pipeline, capture, NULL, 0);
 }
 
 static void
 on_output_changed()
 {
-	output_buffer_width = mode.width / 2;
-	output_buffer_height = mode.height / 2;
-
-	if (camera->rotate != 0 || camera->rotate != 180) {
-		int tmp = output_buffer_width;
-		output_buffer_width = output_buffer_height;
-		output_buffer_height = tmp;
-	}
-
-	for (size_t i = 0; i < NUM_BUFFERS; ++i) {
-		glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
-		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, output_buffer_width,
-			     output_buffer_height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
-			     NULL);
-	}
-
-	glBindTexture(GL_TEXTURE_2D, 0);
-
-	gles2_debayer_configure(
-		gles2_debayer, output_buffer_width, output_buffer_height, mode.width,
-		mode.height, camera->rotate, camera->mirrored,
-		camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
-		camera->blacklevel);
+        output_buffer_width = mode.width / 2;
+        output_buffer_height = mode.height / 2;
+
+        if (camera->rotate != 0 || camera->rotate != 180) {
+                int tmp = output_buffer_width;
+                output_buffer_width = output_buffer_height;
+                output_buffer_height = tmp;
+        }
+
+        for (size_t i = 0; i < NUM_BUFFERS; ++i) {
+                glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
+                glTexImage2D(GL_TEXTURE_2D,
+                             0,
+                             GL_RGBA,
+                             output_buffer_width,
+                             output_buffer_height,
+                             0,
+                             GL_RGBA,
+                             GL_UNSIGNED_BYTE,
+                             NULL);
+        }
+
+        glBindTexture(GL_TEXTURE_2D, 0);
+
+        gles2_debayer_configure(
+                gles2_debayer,
+                output_buffer_width,
+                output_buffer_height,
+                mode.width,
+                mode.height,
+                camera->rotate,
+                camera->mirrored,
+                camera->previewmatrix[0] == 0 ? NULL : camera->previewmatrix,
+                camera->blacklevel);
 }
 
 static int
 mod(int a, int b)
 {
-	int r = a % b;
-	return r < 0 ? r + b : r;
+        int r = a % b;
+        return r < 0 ? r + b : r;
 }
 
 static void
 update_state(MPPipeline *pipeline, const struct mp_process_pipeline_state *state)
 {
-	const bool output_changed =
-		!mp_camera_mode_is_equivalent(&mode, &state->mode) ||
-		preview_width != state->preview_width ||
-		preview_height != state->preview_height ||
-		device_rotation != state->device_rotation;
-
-	camera = state->camera;
-	mode = state->mode;
-
-	preview_width = state->preview_width;
-	preview_height = state->preview_height;
-
-	device_rotation = state->device_rotation;
-
-	burst_length = state->burst_length;
-	save_dng = state->save_dng;
-
-	// gain_is_manual = state->gain_is_manual;
-	gain = state->gain;
-	gain_max = state->gain_max;
-
-	exposure_is_manual = state->exposure_is_manual;
-	exposure = state->exposure;
-
-	if (output_changed) {
-		camera_rotation = mod(camera->rotate - device_rotation, 360);
-
-		on_output_changed();
-	}
-
-	struct mp_main_state main_state = {
-		.camera = camera,
-		.mode = mode,
-		.image_width = output_buffer_width,
-		.image_height = output_buffer_height,
-		.gain_is_manual = state->gain_is_manual,
-		.gain = gain,
-		.gain_max = gain_max,
-		.exposure_is_manual = exposure_is_manual,
-		.exposure = exposure,
-		.has_auto_focus_continuous = state->has_auto_focus_continuous,
-		.has_auto_focus_start = state->has_auto_focus_start,
-	};
-	mp_main_update_state(&main_state);
+        const bool output_changed =
+                !mp_camera_mode_is_equivalent(&mode, &state->mode) ||
+                preview_width != state->preview_width ||
+                preview_height != state->preview_height ||
+                device_rotation != state->device_rotation;
+
+        camera = state->camera;
+        mode = state->mode;
+
+        preview_width = state->preview_width;
+        preview_height = state->preview_height;
+
+        device_rotation = state->device_rotation;
+
+        burst_length = state->burst_length;
+        save_dng = state->save_dng;
+
+        // gain_is_manual = state->gain_is_manual;
+        gain = state->gain;
+        gain_max = state->gain_max;
+
+        exposure_is_manual = state->exposure_is_manual;
+        exposure = state->exposure;
+
+        if (output_changed) {
+                camera_rotation = mod(camera->rotate - device_rotation, 360);
+
+                on_output_changed();
+        }
+
+        struct mp_main_state main_state = {
+                .camera = camera,
+                .mode = mode,
+                .image_width = output_buffer_width,
+                .image_height = output_buffer_height,
+                .gain_is_manual = state->gain_is_manual,
+                .gain = gain,
+                .gain_max = gain_max,
+                .exposure_is_manual = exposure_is_manual,
+                .exposure = exposure,
+                .has_auto_focus_continuous = state->has_auto_focus_continuous,
+                .has_auto_focus_start = state->has_auto_focus_start,
+        };
+        mp_main_update_state(&main_state);
 }
 
 void
 mp_process_pipeline_update_state(const struct mp_process_pipeline_state *new_state)
 {
-	mp_pipeline_invoke(pipeline, (MPPipelineCallback)update_state, new_state,
-			   sizeof(struct mp_process_pipeline_state));
+        mp_pipeline_invoke(pipeline,
+                           (MPPipelineCallback)update_state,
+                           new_state,
+                           sizeof(struct mp_process_pipeline_state));
 }
 
 // GTK4 seems to require this

+ 14 - 14
src/process_pipeline.h

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

+ 209 - 195
src/zbar_pipeline.c

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

+ 12 - 8
src/zbar_pipeline.h

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

+ 187 - 182
tools/camera_test.c

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

+ 61 - 52
tools/list_devices.c

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

Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä