Implement DNG raw burst capture

This commit is contained in:
Martijn Braam 2020-09-26 23:30:15 +02:00
parent e713540974
commit e70eebe34b
8 changed files with 270 additions and 2462 deletions

2187
bayer.c

File diff suppressed because it is too large Load Diff

87
bayer.h
View File

@ -1,87 +0,0 @@
#include <stdint.h>
typedef enum {
DC1394_BAYER_METHOD_NEAREST=0,
DC1394_BAYER_METHOD_SIMPLE,
DC1394_BAYER_METHOD_BILINEAR,
DC1394_BAYER_METHOD_HQLINEAR,
DC1394_BAYER_METHOD_DOWNSAMPLE,
DC1394_BAYER_METHOD_EDGESENSE,
DC1394_BAYER_METHOD_VNG,
DC1394_BAYER_METHOD_AHD
} dc1394bayer_method_t;
typedef enum {
DC1394_COLOR_FILTER_RGGB = 512,
DC1394_COLOR_FILTER_GBRG,
DC1394_COLOR_FILTER_GRBG,
DC1394_COLOR_FILTER_BGGR
} dc1394color_filter_t ;
#define DC1394_COLOR_FILTER_MIN DC1394_COLOR_FILTER_RGGB
#define DC1394_COLOR_FILTER_MAX DC1394_COLOR_FILTER_BGGR
#define DC1394_COLOR_FILTER_NUM (DC1394_COLOR_FILTER_MAX - DC1394_COLOR_FILTER_MIN + 1)
/**
* Error codes returned by most libdc1394 functions.
*
* General rule: 0 is success, negative denotes a problem.
*/
typedef enum {
DC1394_SUCCESS = 0,
DC1394_FAILURE = -1,
DC1394_NOT_A_CAMERA = -2,
DC1394_FUNCTION_NOT_SUPPORTED = -3,
DC1394_CAMERA_NOT_INITIALIZED = -4,
DC1394_MEMORY_ALLOCATION_FAILURE = -5,
DC1394_TAGGED_REGISTER_NOT_FOUND = -6,
DC1394_NO_ISO_CHANNEL = -7,
DC1394_NO_BANDWIDTH = -8,
DC1394_IOCTL_FAILURE = -9,
DC1394_CAPTURE_IS_NOT_SET = -10,
DC1394_CAPTURE_IS_RUNNING = -11,
DC1394_RAW1394_FAILURE = -12,
DC1394_FORMAT7_ERROR_FLAG_1 = -13,
DC1394_FORMAT7_ERROR_FLAG_2 = -14,
DC1394_INVALID_ARGUMENT_VALUE = -15,
DC1394_REQ_VALUE_OUTSIDE_RANGE = -16,
DC1394_INVALID_FEATURE = -17,
DC1394_INVALID_VIDEO_FORMAT = -18,
DC1394_INVALID_VIDEO_MODE = -19,
DC1394_INVALID_FRAMERATE = -20,
DC1394_INVALID_TRIGGER_MODE = -21,
DC1394_INVALID_TRIGGER_SOURCE = -22,
DC1394_INVALID_ISO_SPEED = -23,
DC1394_INVALID_IIDC_VERSION = -24,
DC1394_INVALID_COLOR_CODING = -25,
DC1394_INVALID_COLOR_FILTER = -26,
DC1394_INVALID_CAPTURE_POLICY = -27,
DC1394_INVALID_ERROR_CODE = -28,
DC1394_INVALID_BAYER_METHOD = -29,
DC1394_INVALID_VIDEO1394_DEVICE = -30,
DC1394_INVALID_OPERATION_MODE = -31,
DC1394_INVALID_TRIGGER_POLARITY = -32,
DC1394_INVALID_FEATURE_MODE = -33,
DC1394_INVALID_LOG_TYPE = -34,
DC1394_INVALID_BYTE_ORDER = -35,
DC1394_INVALID_STEREO_METHOD = -36,
DC1394_BASLER_NO_MORE_SFF_CHUNKS = -37,
DC1394_BASLER_CORRUPTED_SFF_CHUNK = -38,
DC1394_BASLER_UNKNOWN_SFF_CHUNK = -39
} dc1394error_t;
#define DC1394_ERROR_MIN DC1394_BASLER_UNKNOWN_SFF_CHUNK
#define DC1394_ERROR_MAX DC1394_SUCCESS
#define DC1394_ERROR_NUM (DC1394_ERROR_MAX-DC1394_ERROR_MIN+1)
typedef enum {
DC1394_FALSE= 0,
DC1394_TRUE
} dc1394bool_t;
dc1394error_t
dc1394_bayer_decoding_8bit(const uint8_t * bayer, uint8_t * rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method);
dc1394error_t
dc1394_bayer_decoding_16bit(const uint16_t * bayer, uint16_t * rgb, uint32_t sx, uint32_t sy, dc1394color_filter_t tile, dc1394bayer_method_t method, uint32_t bits);

View File

@ -1,4 +1,6 @@
[device]
make=PINE64
model=PinePhone
csi=sun6i-csi
[rear]
@ -8,6 +10,10 @@ height=1944
rate=15
fmt=BGGR8
rotate=270
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693
blacklevel=32
whitelevel=255
[front]
driver=gc2145

View File

@ -1,4 +1,6 @@
[device]
make=PINE64
model=PinePhone
csi=sun6i-csi
[rear]
@ -8,6 +10,10 @@ height=1944
rate=15
fmt=BGGR8
rotate=270
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693
blacklevel=32
whitelevel=255
[front]
driver=gc2145

View File

@ -1,4 +1,6 @@
[device]
make=PINE64
model=PinePhone
csi=sun6i-csi
[rear]
@ -8,6 +10,10 @@ height=1944
rate=15
fmt=BGGR8
rotate=270
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693
blacklevel=32
whitelevel=255
[front]
driver=gc2145

View File

@ -1,4 +1,6 @@
[device]
make=PINE64
model=PinePhone
csi=sun6i-csi
[rear]
@ -8,6 +10,10 @@ height=1944
rate=15
fmt=BGGR8
rotate=270
colormatrix=1.384,-0.3203,-0.0124,-0.2728,1.049,0.1556,-0.0506,0.2577,0.8050
forwardmatrix=0.7331,0.1294,0.1018,0.3039,0.6698,0.0263,0.0002,0.0556,0.7693
blacklevel=32
whitelevel=255
[front]
driver=gc2145

431
main.c
View File

@ -14,9 +14,9 @@
#include <asm/errno.h>
#include <wordexp.h>
#include <gtk/gtk.h>
#include <tiffio.h>
#include "config.h"
#include "ini.h"
#include "bayer.h"
#include "quickdebayer.h"
enum io_method {
@ -25,35 +25,43 @@ enum io_method {
IO_METHOD_USERPTR,
};
#define TIFFTAG_FORWARDMATRIX1 50964
struct buffer {
void *start;
size_t length;
};
struct camerainfo {
char dev_name[260];
unsigned int entity_id;
char dev[260];
int width;
int height;
int rate;
int rotate;
int fmt;
int mbus;
int fd;
float colormatrix[9];
float forwardmatrix[9];
int blacklevel;
int whitelevel;
};
static float colormatrix_srgb[] = {
3.2409, -1.5373, -0.4986,
-0.9692, 1.8759, 0.0415,
0.0556, -0.2039, 1.0569
};
struct buffer *buffers;
static unsigned int n_buffers;
// Rear camera
static char *rear_dev_name;
static unsigned int rear_entity_id;
static char rear_dev[260];
static int rear_width = -1;
static int rear_height = -1;
static int rear_rate = 30;
static int rear_rotate = 0;
static int rear_fmt = V4L2_PIX_FMT_RGB24;
static int rear_mbus = MEDIA_BUS_FMT_RGB888_1X24;
// Front camera
static char *front_dev_name;
static unsigned int front_entity_id;
static char front_dev[260];
static int front_width = -1;
static int front_height = -1;
static int front_rate = 30;
static int front_rotate = 0;
static int front_fmt = V4L2_PIX_FMT_RGB24;
static int front_mbus = MEDIA_BUS_FMT_RGB888_1X24;
struct camerainfo rear_cam;
struct camerainfo front_cam;
struct camerainfo current;
// Camera interface
static char *media_drv_name;
@ -61,14 +69,11 @@ static unsigned int interface_entity_id;
static char dev_name[260];
static int media_fd;
static int video_fd;
static char *exif_make;
static char *exif_model;
// State
static int ready = 0;
static int current_width = -1;
static int current_height = -1;
static int current_fmt = 0;
static int current_rotate = 0;
static int current_fd;
static int capture = 0;
static int current_is_rear = 1;
static cairo_surface_t *surface = NULL;
@ -257,9 +262,12 @@ init_sensor(char *fn, int width, int height, int mbus, int rate)
fmt.format.code);
// Placeholder, default is also 1
//v4l2_ctrl_set(fd, V4L2_CID_AUTOGAIN, 1);
close(current_fd);
current_fd = fd;
//v4l2_ctrl_set(fd, V4L2_CID_AUTOGAIN, 0);
//v4l2_ctrl_set(fd, V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL);
//v4l2_ctrl_set(fd, V4L2_CID_EXPOSURE, height/24);
//v4l2_ctrl_set(fd, V4L2_CID_GAIN, 0);
close(current.fd);
current.fd = fd;
}
static int
@ -316,12 +324,12 @@ init_device(int fd)
struct v4l2_format fmt = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
};
if (current_width > 0) {
if (current.width > 0) {
g_printerr("Setting camera to %dx%d fmt %d\n",
current_width, current_height, current_fmt);
fmt.fmt.pix.width = current_width;
fmt.fmt.pix.height = current_height;
fmt.fmt.pix.pixelformat = current_fmt;
current.width, current.height, current.fmt);
fmt.fmt.pix.width = current.width;
fmt.fmt.pix.height = current.height;
fmt.fmt.pix.pixelformat = current.fmt;
fmt.fmt.pix.field = V4L2_FIELD_ANY;
if (xioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
@ -345,10 +353,10 @@ init_device(int fd)
g_printerr("Driver returned %dx%d fmt %d\n",
fmt.fmt.pix.width, fmt.fmt.pix.height,
fmt.fmt.pix.pixelformat);
current_width = fmt.fmt.pix.width;
current_height = fmt.fmt.pix.height;
current.width = fmt.fmt.pix.width;
current.height = fmt.fmt.pix.height;
}
current_fmt = fmt.fmt.pix.pixelformat;
current.fmt = fmt.fmt.pix.pixelformat;
/* Buggy driver paranoia. */
unsigned int min = fmt.fmt.pix.width * 2;
@ -367,11 +375,9 @@ init_device(int fd)
static void
process_image(const int *p, int size)
{
clock_t t;
time_t rawtime;
struct tm tim;
uint8_t *pixels;
double time_taken;
char fname[255];
char timestamp[30];
GdkPixbuf *pixbuf;
@ -380,51 +386,34 @@ process_image(const int *p, int size)
GError *error = NULL;
double scale;
cairo_t *cr;
t = clock();
TIFF *tif;
int skip = 2;
long sub_offset = 0;
static const short cfapatterndim[] = {2, 2};
static const float neutral[] = {1.0, 1.0, 1.0};
static const TIFFFieldInfo custom_fields[] = {
{TIFFTAG_FORWARDMATRIX1, -1, -1, TIFF_SRATIONAL, FIELD_CUSTOM, 1, 1, "ForwardMatrix1"},
};
dc1394bayer_method_t method = DC1394_BAYER_METHOD_DOWNSAMPLE;
dc1394color_filter_t filter = DC1394_COLOR_FILTER_BGGR;
if (capture) {
method = DC1394_BAYER_METHOD_SIMPLE;
// method = DC1394_BAYER_METHOD_VNG is slightly sharper but takes 10 seconds;
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current_width, current_height);
pixels = gdk_pixbuf_get_pixels(pixbuf);
dc1394_bayer_decoding_8bit((const uint8_t *) p, pixels, current_width, current_height, filter, method);
} else {
if(current_width > 1280) {
// Only process preview frames when not capturing
if (capture == 0) {
if(current.width > 1280) {
skip = 3;
}
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current_width / (skip*2), current_height / (skip*2));
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current.width / (skip*2), current.height / (skip*2));
pixels = gdk_pixbuf_get_pixels(pixbuf);
quick_debayer_bggr8((const uint8_t *)p, pixels, current_width, current_height, skip);
}
quick_debayer_bggr8((const uint8_t *)p, pixels, current.width, current.height, skip);
if (current_rotate == 0) {
pixbufrot = pixbuf;
} else if (current_rotate == 90) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
} else if (current_rotate == 180) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
} else if (current_rotate == 270) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
}
if (capture) {
time(&rawtime);
tim = *(localtime(&rawtime));
strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim);
sprintf(fname, "%s/Pictures/IMG%s.jpg", getenv("HOME"), timestamp);
printf("Saving image\n");
thumb = gdk_pixbuf_scale_simple(pixbufrot, 24, 24, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(thumb_last), thumb);
gdk_pixbuf_save(pixbufrot, fname, "jpeg", &error, "quality", "95", NULL);
last_path = strdup(fname);
if (error != NULL) {
g_printerr("%s\n", error->message);
g_clear_error(&error);
if (current.rotate == 0) {
pixbufrot = pixbuf;
} else if (current.rotate == 90) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
} else if (current.rotate == 180) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
} else if (current.rotate == 270) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
}
} else {
scale = (double) preview_width / gdk_pixbuf_get_width(pixbufrot);
cr = cairo_create(surface);
cairo_set_source_rgb(cr, 0, 0, 0);
@ -434,11 +423,108 @@ process_image(const int *p, int size)
cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_NONE);
cairo_paint(cr);
gtk_widget_queue_draw_area(preview, 0, 0, preview_width, preview_height);
}
capture = 0;
t = clock() - t;
time_taken = ((double) t) / CLOCKS_PER_SEC;
//printf("%f fps\n", 1.0 / time_taken);
} else {
capture--;
time(&rawtime);
tim = *(localtime(&rawtime));
strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim);
sprintf(fname, "%s/Pictures/IMG%s-%d.dng", getenv("HOME"), timestamp, capture);
if(!(tif = TIFFOpen(fname, "w"))) {
printf("Could not open tiff\n");
}
// Add missing dng fields
TIFFMergeFieldInfo(tif, custom_fields, sizeof(custom_fields) / sizeof(custom_fields[0]));
// Define TIFF thumbnail
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, current.width >> 4);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, current.height >> 4);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
TIFFSetField(tif, TIFFTAG_MAKE, "PINE64");
TIFFSetField(tif, TIFFTAG_MODEL, "PinePhone");
TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels");
TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0");
TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0");
TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, "PINE64 PinePhone");
if(current.colormatrix[0]) {
TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, current.colormatrix);
} else {
TIFFSetField(tif, TIFFTAG_COLORMATRIX1, 9, colormatrix_srgb);
}
if(current.forwardmatrix[0]) {
TIFFSetField(tif, TIFFTAG_FORWARDMATRIX1, 9, current.forwardmatrix);
}
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, (int)current.width >> 4);
for (int row = 0; row < current.height>>4; row++) {
TIFFWriteScanline(tif, buf, row, 0);
}
free(buf);
}
TIFFWriteDirectory(tif);
// Define main photo
TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, current.width);
TIFFSetField(tif, TIFFTAG_IMAGELENGTH, current.height);
TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfapatterndim);
TIFFSetField(tif, TIFFTAG_CFAPATTERN, "\002\001\001\000"); // BGGR
if(current.whitelevel) {
TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &current.whitelevel);
}
if(current.blacklevel) {
TIFFSetField(tif, TIFFTAG_BLACKLEVEL, 1, &current.blacklevel);
}
printf("Writing frame\n");
unsigned char *pLine = (unsigned char*)malloc(current.width);
for(int row = 0; row < current.height; row++){
TIFFWriteScanline(tif, ((uint8_t *)p)+(row*current.width), row, 0);
}
free(pLine);
TIFFClose(tif);
// Update the thumbnail if this is the last frame
if (capture == 0) {
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, current.width / (skip*2), current.height / (skip*2));
pixels = gdk_pixbuf_get_pixels(pixbuf);
quick_debayer_bggr8((const uint8_t *)p, pixels, current.width, current.height, skip);
if (current.rotate == 0) {
pixbufrot = pixbuf;
} else if (current.rotate == 90) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
} else if (current.rotate == 180) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
} else if (current.rotate == 270) {
pixbufrot = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
}
thumb = gdk_pixbuf_scale_simple(pixbufrot, 24, 24, GDK_INTERP_BILINEAR);
gtk_image_set_from_pixbuf(GTK_IMAGE(thumb_last), thumb);
gdk_pixbuf_save(pixbufrot, fname, "jpeg", &error, "quality", "95", NULL);
last_path = strdup(fname);
if (error != NULL) {
g_printerr("%s\n", error->message);
g_clear_error(&error);
}
}
}
}
static gboolean
@ -552,101 +638,76 @@ static int
config_ini_handler(void *user, const char *section, const char *name,
const char *value)
{
if (strcmp(section, "rear") == 0) {
if (strcmp(name, "width") == 0) {
rear_width = strtoint(value, NULL, 10);
} else if (strcmp(name, "height") == 0) {
rear_height = strtoint(value, NULL, 10);
} else if (strcmp(name, "rate") == 0) {
rear_rate = strtoint(value, NULL, 10);
} else if (strcmp(name, "rotate") == 0) {
rear_rotate = strtoint(value, NULL, 10);
} else if (strcmp(name, "fmt") == 0) {
if (strcmp(value, "RGB") == 0) {
rear_fmt = V4L2_PIX_FMT_RGB24;
} else if (strcmp(value, "UYVY") == 0) {
rear_fmt = V4L2_PIX_FMT_UYVY;
} else if (strcmp(value, "YUYV") == 0) {
rear_fmt = V4L2_PIX_FMT_YUYV;
} else if (strcmp(value, "JPEG") == 0) {
rear_fmt = V4L2_PIX_FMT_JPEG;
} else if (strcmp(value, "NV12") == 0) {
rear_fmt = V4L2_PIX_FMT_NV12;
} else if (strcmp(value, "YUV420") == 0
|| strcmp(value, "I420") == 0
|| strcmp(value, "YU12") == 0) {
rear_fmt = V4L2_PIX_FMT_YUV420;
} else if (strcmp(value, "YVU420") == 0
|| strcmp(value, "YV12") == 0) {
rear_fmt = V4L2_PIX_FMT_YVU420;
} else if (strcmp(value, "RGGB8") == 0) {
rear_fmt = V4L2_PIX_FMT_SRGGB8;
} else if (strcmp(value, "BGGR8") == 0) {
rear_fmt = V4L2_PIX_FMT_SBGGR8;
rear_mbus = MEDIA_BUS_FMT_SBGGR8_1X8;
} else if (strcmp(value, "GRBG8") == 0) {
rear_fmt = V4L2_PIX_FMT_SGRBG8;
} else if (strcmp(value, "GBRG8") == 0) {
rear_fmt = V4L2_PIX_FMT_SGBRG8;
} else {
g_printerr("Unsupported pixelformat %s\n", value);
exit(1);
}
} else if (strcmp(name, "driver") == 0) {
rear_dev_name = strdup(value);
struct camerainfo *cc;
if (strcmp(section, "rear") == 0 || strcmp(section, "front") == 0) {
if (strcmp(section, "rear") == 0) {
cc = &rear_cam;
} else {
g_printerr("Unknown key '%s' in [rear]\n", name);
exit(1);
cc = &front_cam;
}
} else if (strcmp(section, "front") == 0) {
if (strcmp(name, "width") == 0) {
front_width = strtoint(value, NULL, 10);
cc->width = strtoint(value, NULL, 10);
} else if (strcmp(name, "height") == 0) {
front_height = strtoint(value, NULL, 10);
cc->height = strtoint(value, NULL, 10);
} else if (strcmp(name, "rate") == 0) {
front_rate = strtoint(value, NULL, 10);
cc->rate = strtoint(value, NULL, 10);
} else if (strcmp(name, "rotate") == 0) {
front_rotate = strtoint(value, NULL, 10);
cc->rotate = strtoint(value, NULL, 10);
} else if (strcmp(name, "fmt") == 0) {
if (strcmp(value, "RGB") == 0) {
front_fmt = V4L2_PIX_FMT_RGB24;
} else if (strcmp(value, "UYVY") == 0) {
front_fmt = V4L2_PIX_FMT_UYVY;
} else if (strcmp(value, "YUYV") == 0) {
front_fmt = V4L2_PIX_FMT_YUYV;
} else if (strcmp(value, "JPEG") == 0) {
front_fmt = V4L2_PIX_FMT_JPEG;
} else if (strcmp(value, "NV12") == 0) {
front_fmt = V4L2_PIX_FMT_NV12;
} else if (strcmp(value, "YUV420") == 0
|| strcmp(value, "I420") == 0
|| strcmp(value, "YU12") == 0) {
front_fmt = V4L2_PIX_FMT_YUV420;
} else if (strcmp(value, "YVU420") == 0
|| strcmp(value, "YV12") == 0) {
front_fmt = V4L2_PIX_FMT_YVU420;
} else if (strcmp(value, "RGGB8") == 0) {
front_fmt = V4L2_PIX_FMT_SRGGB8;
if (strcmp(value, "RGGB8") == 0) {
cc->fmt = V4L2_PIX_FMT_SRGGB8;
} else if (strcmp(value, "BGGR8") == 0) {
front_fmt = V4L2_PIX_FMT_SBGGR8;
front_mbus = MEDIA_BUS_FMT_SBGGR8_1X8;
cc->fmt = V4L2_PIX_FMT_SBGGR8;
cc->mbus = MEDIA_BUS_FMT_SBGGR8_1X8;
} else if (strcmp(value, "GRBG8") == 0) {
front_fmt = V4L2_PIX_FMT_SGRBG8;
cc->fmt = V4L2_PIX_FMT_SGRBG8;
} else if (strcmp(value, "GBRG8") == 0) {
front_fmt = V4L2_PIX_FMT_SGBRG8;
cc->fmt = V4L2_PIX_FMT_SGBRG8;
} else {
g_printerr("Unsupported pixelformat %s\n", value);
exit(1);
}
} else if (strcmp(name, "driver") == 0) {
front_dev_name = strdup(value);
strcpy(cc->dev_name, value);
} 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 {
g_printerr("Unknown key '%s' in [front]\n", name);
g_printerr("Unknown key '%s' in [%s]\n", name, section);
exit(1);
}
} else if (strcmp(section, "device") == 0) {
if (strcmp(name, "csi") == 0) {
media_drv_name = strdup(value);
} else 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);
@ -685,7 +746,7 @@ setup_rear()
// Disable the interface<->front link
link.flags = 0;
link.source.entity = front_entity_id;
link.source.entity = front_cam.entity_id;
link.source.index = 0;
link.sink.entity = interface_entity_id;
link.sink.index = 0;
@ -697,7 +758,7 @@ setup_rear()
// Enable the interface<->rear link
link.flags = MEDIA_LNK_FL_ENABLED;
link.source.entity = rear_entity_id;
link.source.entity = rear_cam.entity_id;
link.source.index = 0;
link.sink.entity = interface_entity_id;
link.sink.index = 0;
@ -707,12 +768,10 @@ setup_rear()
return -1;
}
current_width = rear_width;
current_height = rear_height;
current_fmt = rear_fmt;
current_rotate = rear_rotate;
current = rear_cam;
// Find camera node
init_sensor(rear_dev, rear_width, rear_height, rear_mbus, rear_rate);
init_sensor(current.dev, current.width, current.height, current.mbus, current.rate);
return 0;
}
@ -723,7 +782,7 @@ setup_front()
// Disable the interface<->rear link
link.flags = 0;
link.source.entity = rear_entity_id;
link.source.entity = rear_cam.entity_id;
link.source.index = 0;
link.sink.entity = interface_entity_id;
link.sink.index = 0;
@ -735,7 +794,7 @@ setup_front()
// Enable the interface<->rear link
link.flags = MEDIA_LNK_FL_ENABLED;
link.source.entity = front_entity_id;
link.source.entity = front_cam.entity_id;
link.source.index = 0;
link.sink.entity = interface_entity_id;
link.sink.index = 0;
@ -744,12 +803,9 @@ setup_front()
g_printerr("Could not enable front camera link\n");
return -1;
}
current_width = front_width;
current_height = front_height;
current_fmt = front_fmt;
current_rotate = front_rotate;
current = front_cam;
// Find camera node
init_sensor(front_dev, front_width, front_height, front_mbus, front_rate);
init_sensor(current.dev, current.width, current.height, current.mbus, current.rate);
return 0;
}
@ -767,16 +823,16 @@ find_cameras()
break;
}
printf("At node %s, (0x%x)\n", entity.name, entity.type);
if (strncmp(entity.name, front_dev_name, strlen(front_dev_name)) == 0) {
front_entity_id = entity.id;
find_dev_node(entity.dev.major, entity.dev.minor, front_dev);
printf("Found front cam, is %s at %s\n", entity.name, front_dev);
if (strncmp(entity.name, front_cam.dev_name, strlen(front_cam.dev_name)) == 0) {
front_cam.entity_id = entity.id;
find_dev_node(entity.dev.major, entity.dev.minor, front_cam.dev);
printf("Found front cam, is %s at %s\n", entity.name, front_cam.dev);
found++;
}
if (strncmp(entity.name, rear_dev_name, strlen(rear_dev_name)) == 0) {
rear_entity_id = entity.id;
find_dev_node(entity.dev.major, entity.dev.minor, rear_dev);
printf("Found rear cam, is %s at %s\n", entity.name, rear_dev);
if (strncmp(entity.name, rear_cam.dev_name, strlen(rear_cam.dev_name)) == 0) {
rear_cam.entity_id = entity.id;
find_dev_node(entity.dev.major, entity.dev.minor, rear_cam.dev);
printf("Found rear cam, is %s at %s\n", entity.name, rear_cam.dev);
found++;
}
if (entity.type == MEDIA_ENT_F_IO_V4L) {
@ -847,7 +903,7 @@ on_open_directory_clicked(GtkWidget *widget, gpointer user_data)
void
on_shutter_clicked(GtkWidget *widget, gpointer user_data)
{
capture = 1;
capture = 5;
}
void
@ -860,7 +916,7 @@ void
on_camera_switch_clicked(GtkWidget *widget, gpointer user_data)
{
stop_capturing(video_fd);
close(current_fd);
close(current.fd);
if (current_is_rear == 1) {
setup_front();
current_is_rear = 0;
@ -913,6 +969,13 @@ find_config(char *conffile)
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 0;
}
// Check for a config file in XDG_CONFIG_HOME
sprintf(conffile, "%s/megapixels/config/%s.ini", xdg_config_home, buf);
if(access(conffile, F_OK) != -1) {
@ -932,12 +995,6 @@ find_config(char *conffile)
printf("Found config file at %s\n", conffile);
return 0;
}
// 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 0;
}
printf("%s not found\n", conffile);
} else {
printf("Could not read device name from device tree\n");

View File

@ -1,6 +1,7 @@
project('megapixels', 'c')
gnome = import('gnome')
gtkdep = dependency('gtk+-3.0')
tiff = dependency('libtiff-4')
cc = meson.get_compiler('c')
libm = cc.find_library('m', required: false)
@ -14,7 +15,7 @@ configure_file(
output: 'config.h',
configuration: conf )
executable('megapixels', 'main.c', 'ini.c', 'bayer.c', 'quickdebayer.c', resources, dependencies : [gtkdep, libm], install : true)
executable('megapixels', 'main.c', 'ini.c', 'quickdebayer.c', resources, dependencies : [gtkdep, libm, tiff], install : true)
install_data(['org.postmarketos.Megapixels.desktop'],
install_dir : get_option('datadir') / 'applications')