process_pipeline.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066
  1. #include "process_pipeline.h"
  2. #include "gles2_debayer.h"
  3. #include "io_pipeline.h"
  4. #include "main.h"
  5. #include "pipeline.h"
  6. #include "state.h"
  7. #include "zbar_pipeline.h"
  8. #include <assert.h>
  9. #include <gtk/gtk.h>
  10. #include <math.h>
  11. #include <tiffio.h>
  12. #ifndef SYSCONFDIR
  13. #include "config.h"
  14. #endif
  15. #include "dcp.h"
  16. #include "gl_util.h"
  17. #include <sys/mman.h>
  18. #define TIFFTAG_FORWARDMATRIX1 50964
  19. #define TIFFTAG_FORWARDMATRIX2 50965
  20. static const float colormatrix_srgb[] = { 3.2409f, -1.5373f, -0.4986f,
  21. -0.9692f, 1.8759f, 0.0415f,
  22. 0.0556f, -0.2039f, 1.0569f };
  23. static MPPipeline *pipeline;
  24. mp_state_proc state_proc;
  25. static char burst_dir[23];
  26. static volatile bool is_capturing = false;
  27. static volatile int frames_processed = 0;
  28. static volatile int frames_received = 0;
  29. libmegapixels_camera *pr_camera;
  30. static int output_buffer_width = -1;
  31. static int output_buffer_height = -1;
  32. static bool flash_enabled;
  33. static char capture_fname[255];
  34. static GSettings *settings;
  35. static void
  36. register_custom_tiff_tags(TIFF *tif)
  37. {
  38. static const TIFFFieldInfo custom_fields[] = {
  39. { TIFFTAG_FORWARDMATRIX1,
  40. -1,
  41. -1,
  42. TIFF_SRATIONAL,
  43. FIELD_CUSTOM,
  44. 1,
  45. 1,
  46. "ForwardMatrix1" },
  47. { TIFFTAG_FORWARDMATRIX2,
  48. -1,
  49. -1,
  50. TIFF_SRATIONAL,
  51. FIELD_CUSTOM,
  52. 1,
  53. 1,
  54. "ForwardMatrix2" },
  55. { DCPTAG_PROFILE_TONE_CURVE,
  56. -1,
  57. -1,
  58. TIFF_FLOAT,
  59. FIELD_CUSTOM,
  60. 1,
  61. 1,
  62. "ProfileToneCurve" },
  63. { DCPTAG_PROFILE_HUE_SAT_MAP_DIMS,
  64. -1,
  65. -1,
  66. TIFF_FLOAT,
  67. FIELD_CUSTOM,
  68. 1,
  69. 1,
  70. "ProfileHueSatMapDims" },
  71. { DCPTAG_PROFILE_HUE_SAT_MAP_DATA_1,
  72. -1,
  73. -1,
  74. TIFF_FLOAT,
  75. FIELD_CUSTOM,
  76. 1,
  77. 1,
  78. "ProfileHueSatMapData1" },
  79. { DCPTAG_PROFILE_HUE_SAT_MAP_DATA_2,
  80. -1,
  81. -1,
  82. TIFF_FLOAT,
  83. FIELD_CUSTOM,
  84. 1,
  85. 1,
  86. "ProfileHueSatMapData2" },
  87. };
  88. // Add missing dng fields
  89. TIFFMergeFieldInfo(tif,
  90. custom_fields,
  91. sizeof(custom_fields) / sizeof(custom_fields[0]));
  92. }
  93. void
  94. mp_process_find_all_processors(GtkListStore *store)
  95. {
  96. GtkTreeIter iter;
  97. char buffer[512];
  98. // Find all the original postprocess.sh locations
  99. // Check postprocess.sh in the current working directory
  100. if (access("./data/postprocess.sh", F_OK) != -1) {
  101. gtk_list_store_insert(store, &iter, -1);
  102. gtk_list_store_set(store,
  103. &iter,
  104. 0,
  105. "./data/postprocess.sh",
  106. 1,
  107. "(cwd) postprocess.sh",
  108. -1);
  109. }
  110. // Check for a script in XDG_CONFIG_HOME
  111. sprintf(buffer, "%s/megapixels/postprocess.sh", g_get_user_config_dir());
  112. if (access(buffer, F_OK) != -1) {
  113. gtk_list_store_insert(store, &iter, -1);
  114. gtk_list_store_set(
  115. store, &iter, 0, buffer, 1, "(user) postprocess.sh", -1);
  116. }
  117. // Check user overridden /etc/megapixels/postprocessor.sh
  118. sprintf(buffer, "%s/megapixels/postprocess.sh", SYSCONFDIR);
  119. if (access(buffer, F_OK) != -1) {
  120. gtk_list_store_insert(store, &iter, -1);
  121. gtk_list_store_set(
  122. store, &iter, 0, buffer, 1, "(system) postprocess.sh", -1);
  123. }
  124. // Check user overridden /usr/share/megapixels/postprocessor.sh
  125. sprintf(buffer, "%s/megapixels/postprocess.sh", DATADIR);
  126. if (access(buffer, F_OK) != -1) {
  127. gtk_list_store_insert(store, &iter, -1);
  128. gtk_list_store_set(
  129. store, &iter, 0, buffer, 1, "(built-in) postprocess.sh", -1);
  130. }
  131. // Find extra packaged postprocessor scripts
  132. // These should be packaged in
  133. // /usr/share/megapixels/postprocessor.d/executable
  134. sprintf(buffer, "%s/megapixels/postprocessor.d", DATADIR);
  135. DIR *d;
  136. struct dirent *dir;
  137. d = opendir(buffer);
  138. if (d) {
  139. while ((dir = readdir(d)) != NULL) {
  140. if (dir->d_name[0] == '.') {
  141. continue;
  142. }
  143. sprintf(buffer,
  144. "%s/megapixels/postprocessor.d/%s",
  145. DATADIR,
  146. dir->d_name);
  147. gtk_list_store_insert(store, &iter, -1);
  148. gtk_list_store_set(
  149. store, &iter, 0, buffer, 1, dir->d_name, -1);
  150. }
  151. closedir(d);
  152. }
  153. }
  154. bool
  155. mp_process_find_processor(char *script)
  156. {
  157. char filename[] = "postprocess.sh";
  158. // Check postprocess.sh in the current working directory
  159. sprintf(script, "./data/%s", filename);
  160. if (access(script, F_OK) != -1) {
  161. sprintf(script, "./data/%s", filename);
  162. printf("Found postprocessor script at %s\n", script);
  163. return true;
  164. }
  165. // Check for a script in XDG_CONFIG_HOME
  166. sprintf(script, "%s/megapixels/%s", g_get_user_config_dir(), filename);
  167. if (access(script, F_OK) != -1) {
  168. printf("Found postprocessor script at %s\n", script);
  169. return true;
  170. }
  171. // Check user overridden /etc/megapixels/postprocessor.sh
  172. sprintf(script, "%s/megapixels/%s", SYSCONFDIR, filename);
  173. if (access(script, F_OK) != -1) {
  174. printf("Found postprocessor script at %s\n", script);
  175. return true;
  176. }
  177. // Check packaged /usr/share/megapixels/postprocessor.sh
  178. sprintf(script, "%s/megapixels/%s", DATADIR, filename);
  179. if (access(script, F_OK) != -1) {
  180. printf("Found postprocessor script at %s\n", script);
  181. return true;
  182. }
  183. return false;
  184. }
  185. static void
  186. setup(MPPipeline *pipeline, const void *data)
  187. {
  188. TIFFSetTagExtender(register_custom_tiff_tags);
  189. settings = g_settings_new("org.postmarketos.Megapixels");
  190. }
  191. void
  192. mp_process_pipeline_start()
  193. {
  194. pipeline = mp_pipeline_new();
  195. mp_pipeline_invoke(pipeline, setup, NULL, 0);
  196. mp_zbar_pipeline_start();
  197. }
  198. void
  199. mp_process_pipeline_stop()
  200. {
  201. mp_pipeline_free(pipeline);
  202. mp_zbar_pipeline_stop();
  203. }
  204. void
  205. mp_process_pipeline_sync()
  206. {
  207. mp_pipeline_sync(pipeline);
  208. }
  209. #define NUM_BUFFERS 4
  210. struct _MPProcessPipelineBuffer {
  211. GLuint texture_id;
  212. _Atomic(int) refcount;
  213. };
  214. static MPProcessPipelineBuffer output_buffers[NUM_BUFFERS];
  215. void
  216. mp_process_pipeline_buffer_ref(MPProcessPipelineBuffer *buf)
  217. {
  218. ++buf->refcount;
  219. }
  220. void
  221. mp_process_pipeline_buffer_unref(MPProcessPipelineBuffer *buf)
  222. {
  223. --buf->refcount;
  224. }
  225. uint32_t
  226. mp_process_pipeline_buffer_get_texture_id(MPProcessPipelineBuffer *buf)
  227. {
  228. return buf->texture_id;
  229. }
  230. static void
  231. repack_image_sequencial(const uint8_t *src_buf,
  232. uint8_t *dst_buf,
  233. libmegapixels_mode *mode)
  234. {
  235. uint16_t pixels[4];
  236. uint32_t row_length =
  237. libmegapixels_mode_width_to_bytes(mode->format, mode->width);
  238. uint32_t padding_bytes =
  239. libmegapixels_mode_width_to_padding(mode->format, mode->width);
  240. size_t si = 0;
  241. // Image data must be 10-bit packed
  242. assert(libmegapixels_format_bits_per_pixel(mode->format) == 10);
  243. /*
  244. * Repack 40 bits stored in sensor format into sequencial format
  245. *
  246. * src_buf: 11111111 22222222 33333333 44444444 11223344 ...
  247. * dst_buf: 11111111 11222222 22223333 33333344 44444444 ...
  248. */
  249. for (size_t i = 0; i < row_length * mode->height; i += 5) {
  250. // Skip padding bytes in source buffer
  251. if (i && i % row_length == 0)
  252. si += padding_bytes;
  253. /* Extract pixels from packed sensor format */
  254. pixels[0] = (src_buf[si] << 2) | (src_buf[si + 4] >> 6);
  255. pixels[1] = (src_buf[si + 1] << 2) | (src_buf[si + 4] >> 4 & 0x03);
  256. pixels[2] = (src_buf[si + 2] << 2) | (src_buf[si + 4] >> 2 & 0x03);
  257. pixels[3] = (src_buf[si + 3] << 2) | (src_buf[si + 4] & 0x03);
  258. /* Pack pixels into sequencial format */
  259. dst_buf[i] = (pixels[0] >> 2 & 0xff);
  260. dst_buf[i + 1] = (pixels[0] << 6 & 0xff) | (pixels[1] >> 4 & 0x3f);
  261. dst_buf[i + 2] = (pixels[1] << 4 & 0xff) | (pixels[2] >> 6 & 0x0f);
  262. dst_buf[i + 3] = (pixels[2] << 2 & 0xff) | (pixels[3] >> 8 & 0x03);
  263. dst_buf[i + 4] = (pixels[3] & 0xff);
  264. si += 5;
  265. }
  266. }
  267. static GLES2Debayer *gles2_debayer = NULL;
  268. static GdkGLContext *context;
  269. // #define RENDERDOC
  270. #ifdef RENDERDOC
  271. #include <renderdoc/app.h>
  272. extern RENDERDOC_API_1_1_2 *rdoc_api;
  273. #endif
  274. static void
  275. init_gl(MPPipeline *pipeline, GdkSurface **surface)
  276. {
  277. GError *error = NULL;
  278. context = gdk_surface_create_gl_context(*surface, &error);
  279. if (context == NULL) {
  280. printf("Failed to initialize OpenGL context: %s\n", error->message);
  281. g_clear_error(&error);
  282. return;
  283. }
  284. gdk_gl_context_set_use_es(context, true);
  285. gdk_gl_context_set_required_version(context, 2, 0);
  286. gdk_gl_context_set_forward_compatible(context, false);
  287. #ifdef DEBUG
  288. gdk_gl_context_set_debug_enabled(context, true);
  289. #else
  290. gdk_gl_context_set_debug_enabled(context, false);
  291. #endif
  292. gdk_gl_context_realize(context, &error);
  293. if (error != NULL) {
  294. printf("Failed to create OpenGL context: %s\n", error->message);
  295. g_clear_object(&context);
  296. g_clear_error(&error);
  297. return;
  298. }
  299. gdk_gl_context_make_current(context);
  300. check_gl();
  301. // Make a VAO for OpenGL
  302. if (!gdk_gl_context_get_use_es(context)) {
  303. GLuint vao;
  304. glGenVertexArrays(1, &vao);
  305. glBindVertexArray(vao);
  306. check_gl();
  307. }
  308. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  309. check_gl();
  310. for (size_t i = 0; i < NUM_BUFFERS; ++i) {
  311. glGenTextures(1, &output_buffers[i].texture_id);
  312. glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
  313. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  314. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  315. }
  316. glBindTexture(GL_TEXTURE_2D, 0);
  317. gboolean is_es = gdk_gl_context_get_use_es(context);
  318. int major, minor;
  319. gdk_gl_context_get_version(context, &major, &minor);
  320. printf("Initialized %s %d.%d\n",
  321. is_es ? "OpenGL ES" : "OpenGL",
  322. major,
  323. minor);
  324. }
  325. void
  326. mp_process_pipeline_init_gl(GdkSurface *surface)
  327. {
  328. mp_pipeline_invoke(pipeline,
  329. (MPPipelineCallback)init_gl,
  330. &surface,
  331. sizeof(GdkSurface *));
  332. }
  333. static GdkTexture *
  334. process_image_for_preview(const uint8_t *image)
  335. {
  336. #ifdef PROFILE_DEBAYER
  337. clock_t t1 = clock();
  338. #endif
  339. // Pick an available buffer
  340. MPProcessPipelineBuffer *output_buffer = NULL;
  341. for (size_t i = 0; i < NUM_BUFFERS; ++i) {
  342. if (output_buffers[i].refcount == 0) {
  343. output_buffer = &output_buffers[i];
  344. }
  345. }
  346. if (output_buffer == NULL) {
  347. return NULL;
  348. }
  349. assert(output_buffer != NULL);
  350. #ifdef RENDERDOC
  351. if (rdoc_api) {
  352. rdoc_api->StartFrameCapture(NULL, NULL);
  353. }
  354. #endif
  355. // Copy image to a GL texture. TODO: This can be avoided
  356. GLuint input_texture;
  357. glGenTextures(1, &input_texture);
  358. glBindTexture(GL_TEXTURE_2D, input_texture);
  359. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  360. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  361. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  362. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  363. glTexImage2D(
  364. GL_TEXTURE_2D,
  365. 0,
  366. GL_LUMINANCE,
  367. libmegapixels_mode_width_to_bytes(state_proc.mode->format,
  368. state_proc.mode->width) +
  369. libmegapixels_mode_width_to_padding(state_proc.mode->format,
  370. state_proc.mode->width),
  371. state_proc.mode->height,
  372. 0,
  373. GL_LUMINANCE,
  374. GL_UNSIGNED_BYTE,
  375. image);
  376. check_gl();
  377. gles2_debayer_process(
  378. gles2_debayer, output_buffer->texture_id, input_texture);
  379. check_gl();
  380. glFinish();
  381. glDeleteTextures(1, &input_texture);
  382. #ifdef PROFILE_DEBAYER
  383. clock_t t2 = clock();
  384. printf("process_image_for_preview %fms\n",
  385. (float)(t2 - t1) / CLOCKS_PER_SEC * 1000);
  386. #endif
  387. #ifdef RENDERDOC
  388. if (rdoc_api) {
  389. rdoc_api->EndFrameCapture(NULL, NULL);
  390. }
  391. #endif
  392. mp_process_pipeline_buffer_ref(output_buffer);
  393. mp_main_set_preview(output_buffer);
  394. if (!state_proc.exposure.manual && state_proc.exposure.auto_control == 0) {
  395. int width = output_buffer_width / 3;
  396. int height = output_buffer_height / 3;
  397. uint32_t *center = g_malloc_n(width * height * sizeof(uint32_t), 1);
  398. glReadPixels(width,
  399. height,
  400. width,
  401. height,
  402. GL_RGBA,
  403. GL_UNSIGNED_BYTE,
  404. center);
  405. libmegapixels_aaa_software_statistics(
  406. center, width, height, &state_proc.stats);
  407. }
  408. // Create a thumbnail from the preview for the last capture
  409. GdkTexture *thumb = NULL;
  410. if (state_proc.captures_remaining == 1) {
  411. printf("Making thumbnail\n");
  412. size_t size = output_buffer_width * output_buffer_height *
  413. sizeof(uint32_t);
  414. uint32_t *data = g_malloc_n(size, 1);
  415. glReadPixels(0,
  416. 0,
  417. output_buffer_width,
  418. output_buffer_height,
  419. GL_RGBA,
  420. GL_UNSIGNED_BYTE,
  421. data);
  422. check_gl();
  423. // Flip vertically
  424. for (size_t y = 0; y < output_buffer_height / 2; ++y) {
  425. for (size_t x = 0; x < output_buffer_width; ++x) {
  426. uint32_t tmp = data[(output_buffer_height - y - 1) *
  427. output_buffer_width +
  428. x];
  429. data[(output_buffer_height - y - 1) *
  430. output_buffer_width +
  431. x] = data[y * output_buffer_width + x];
  432. data[y * output_buffer_width + x] = tmp;
  433. }
  434. }
  435. thumb = gdk_memory_texture_new(output_buffer_width,
  436. output_buffer_height,
  437. GDK_MEMORY_R8G8B8A8,
  438. g_bytes_new_take(data, size),
  439. output_buffer_width *
  440. sizeof(uint32_t));
  441. }
  442. return thumb;
  443. }
  444. static void
  445. process_image_for_capture(const uint8_t *image, int count)
  446. {
  447. time_t rawtime;
  448. time(&rawtime);
  449. struct tm tim = *(localtime(&rawtime));
  450. char datetime[20] = { 0 };
  451. strftime(datetime, 20, "%Y:%m:%d %H:%M:%S", &tim);
  452. char fname[255];
  453. sprintf(fname, "%s/%d.dng", burst_dir, count);
  454. TIFF *tif = TIFFOpen(fname, "w");
  455. if (!tif) {
  456. printf("Could not open tiff\n");
  457. }
  458. // Define TIFF thumbnail
  459. TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
  460. TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, state_proc.mode->width >> 4);
  461. TIFFSetField(tif, TIFFTAG_IMAGELENGTH, state_proc.mode->height >> 4);
  462. TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
  463. TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
  464. TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
  465. TIFFSetField(tif, TIFFTAG_MAKE, state_proc.configuration->make);
  466. TIFFSetField(tif, TIFFTAG_MODEL, state_proc.configuration->model);
  467. uint16_t orientation;
  468. if (state_proc.device_rotation == 0) {
  469. orientation = state_proc.mode->mirrored ? ORIENTATION_TOPRIGHT :
  470. ORIENTATION_TOPLEFT;
  471. } else if (state_proc.device_rotation == 90) {
  472. orientation = state_proc.mode->mirrored ? ORIENTATION_RIGHTBOT :
  473. ORIENTATION_LEFTBOT;
  474. } else if (state_proc.device_rotation == 180) {
  475. orientation = state_proc.mode->mirrored ? ORIENTATION_BOTLEFT :
  476. ORIENTATION_BOTRIGHT;
  477. } else {
  478. orientation = state_proc.mode->mirrored ? ORIENTATION_LEFTTOP :
  479. ORIENTATION_RIGHTTOP;
  480. }
  481. TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation);
  482. TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
  483. TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
  484. TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  485. TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels");
  486. long sub_offset = 0;
  487. TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
  488. TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0");
  489. TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0");
  490. char uniquecameramodel[255];
  491. sprintf(uniquecameramodel,
  492. "%s %s",
  493. state_proc.configuration->make,
  494. state_proc.configuration->model);
  495. TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, uniquecameramodel);
  496. static const float neutral[] = { 1.0, 1.0, 1.0 };
  497. TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral);
  498. TIFFSetField(tif, TIFFTAG_ANALOGBALANCE, 3, state_proc.balance);
  499. // Write black thumbnail, only windows uses this
  500. {
  501. unsigned char *buf = (unsigned char *)calloc(
  502. 1, (state_proc.mode->width >> 4) * 3);
  503. for (int row = 0; row < (state_proc.mode->height >> 4); row++) {
  504. TIFFWriteScanline(tif, buf, row, 0);
  505. }
  506. free(buf);
  507. }
  508. TIFFWriteDirectory(tif);
  509. // Define main photo
  510. TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
  511. TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, state_proc.mode->width);
  512. TIFFSetField(tif, TIFFTAG_IMAGELENGTH, state_proc.mode->height);
  513. TIFFSetField(tif,
  514. TIFFTAG_BITSPERSAMPLE,
  515. libmegapixels_format_bits_per_pixel(state_proc.mode->format));
  516. TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
  517. TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
  518. TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  519. static const short cfapatterndim[] = { 2, 2 };
  520. TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfapatterndim);
  521. #if (TIFFLIB_VERSION < 20201219) && !LIBTIFF_CFA_PATTERN
  522. TIFFSetField(tif,
  523. TIFFTAG_CFAPATTERN,
  524. mp_pixel_format_cfa_pattern(mode.pixel_format));
  525. #else
  526. TIFFSetField(tif,
  527. TIFFTAG_CFAPATTERN,
  528. 4,
  529. libmegapixels_format_cfa_pattern(state_proc.mode->format));
  530. #endif
  531. printf("TIFF version %d\n", TIFFLIB_VERSION);
  532. int whitelevel =
  533. (1 << libmegapixels_format_bits_per_pixel(state_proc.mode->format)) -
  534. 1;
  535. TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &whitelevel);
  536. TIFFCheckpointDirectory(tif);
  537. printf("Writing frame to %s\n", fname);
  538. uint8_t *output_image = (uint8_t *)image;
  539. // Repack 10-bit image from sensor format into a sequencial format
  540. if (libmegapixels_format_bits_per_pixel(state_proc.mode->format) == 10) {
  541. output_image = malloc(
  542. libmegapixels_mode_width_to_bytes(state_proc.mode->format,
  543. state_proc.mode->width) *
  544. state_proc.mode->height);
  545. repack_image_sequencial(image, output_image, state_proc.mode);
  546. }
  547. for (int row = 0; row < state_proc.mode->height; row++) {
  548. TIFFWriteScanline(tif,
  549. (void *)output_image +
  550. (row * libmegapixels_mode_width_to_bytes(
  551. state_proc.mode->format,
  552. state_proc.mode->width)),
  553. row,
  554. 0);
  555. }
  556. TIFFWriteDirectory(tif);
  557. if (output_image != image)
  558. free(output_image);
  559. // Add an EXIF block to the tiff
  560. TIFFCreateEXIFDirectory(tif);
  561. // 1 = manual, 2 = full auto, 3 = aperture priority, 4 = shutter priority
  562. if (!state_proc.exposure.manual) {
  563. TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 2);
  564. } else {
  565. TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 1);
  566. }
  567. /*
  568. TIFFSetField(tif,
  569. EXIFTAG_EXPOSURETIME,
  570. (mode.frame_interval.numerator /
  571. (float)mode.frame_interval.denominator) /
  572. ((float)mode.height / (float)exposure));
  573. if (pr_camera->iso_min && pr_camera->iso_max) {
  574. uint16_t isospeed = remap(
  575. gain - 1, 0, gain_max, pr_camera->iso_min,
  576. pr_camera->iso_max); TIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1,
  577. &isospeed);
  578. }
  579. if (!pr_camera->has_flash) {
  580. // No flash function
  581. TIFFSetField(tif, EXIFTAG_FLASH, 0x20);
  582. } else if (flash_enabled) {
  583. // Flash present and fired
  584. TIFFSetField(tif, EXIFTAG_FLASH, 0x1);
  585. } else {
  586. // Flash present but not fired
  587. TIFFSetField(tif, EXIFTAG_FLASH, 0x0);
  588. }
  589. */
  590. TIFFSetField(tif, EXIFTAG_DATETIMEORIGINAL, datetime);
  591. TIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, datetime);
  592. /*
  593. if (pr_camera->fnumber) {
  594. TIFFSetField(tif, EXIFTAG_FNUMBER, pr_camera->fnumber);
  595. }
  596. if (pr_camera->focallength) {
  597. TIFFSetField(tif, EXIFTAG_FOCALLENGTH, pr_camera->focallength);
  598. }
  599. if (pr_camera->focallength && pr_camera->cropfactor) {
  600. TIFFSetField(tif,
  601. EXIFTAG_FOCALLENGTHIN35MMFILM,
  602. (short)(pr_camera->focallength *
  603. pr_camera->cropfactor));
  604. }
  605. */
  606. uint64_t exif_offset = 0;
  607. TIFFWriteCustomDirectory(tif, &exif_offset);
  608. TIFFFreeDirectory(tif);
  609. // Update exif pointer
  610. TIFFSetDirectory(tif, 0);
  611. TIFFSetField(tif, TIFFTAG_EXIFIFD, exif_offset);
  612. TIFFRewriteDirectory(tif);
  613. TIFFClose(tif);
  614. }
  615. static void
  616. post_process_finished(GSubprocess *proc, GAsyncResult *res, GdkTexture *thumb)
  617. {
  618. char *stdout;
  619. g_subprocess_communicate_utf8_finish(proc, res, &stdout, NULL, NULL);
  620. // The last line contains the file name
  621. int end = strlen(stdout);
  622. // Skip the newline at the end
  623. stdout[--end] = '\0';
  624. char *path = path = stdout + end - 1;
  625. do {
  626. if (*path == '\n') {
  627. path++;
  628. break;
  629. }
  630. --path;
  631. } while (path > stdout);
  632. mp_main_capture_completed(thumb, path);
  633. }
  634. static void
  635. process_capture_burst(GdkTexture *thumb)
  636. {
  637. time_t rawtime;
  638. time(&rawtime);
  639. struct tm tim = *(localtime(&rawtime));
  640. char timestamp[30];
  641. strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim);
  642. if (g_get_user_special_dir(G_USER_DIRECTORY_PICTURES) != NULL) {
  643. sprintf(capture_fname,
  644. "%s/IMG%s",
  645. g_get_user_special_dir(G_USER_DIRECTORY_PICTURES),
  646. timestamp);
  647. } else if (getenv("XDG_PICTURES_DIR") != NULL) {
  648. sprintf(capture_fname,
  649. "%s/IMG%s",
  650. getenv("XDG_PICTURES_DIR"),
  651. timestamp);
  652. } else {
  653. sprintf(capture_fname,
  654. "%s/Pictures/IMG%s",
  655. getenv("HOME"),
  656. timestamp);
  657. }
  658. bool save_dng = g_settings_get_boolean(settings, "save-raw");
  659. char *postprocessor = g_settings_get_string(settings, "postprocessor");
  660. char save_dng_s[2] = "0";
  661. if (save_dng) {
  662. save_dng_s[0] = '1';
  663. }
  664. // Start post-processing the captured burst
  665. g_print("Post process %s to %s.ext (save-dng %s)\n",
  666. burst_dir,
  667. capture_fname,
  668. save_dng_s);
  669. g_autoptr(GError) error = NULL;
  670. GSubprocess *proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE,
  671. &error,
  672. postprocessor,
  673. burst_dir,
  674. capture_fname,
  675. save_dng_s,
  676. NULL);
  677. if (!proc) {
  678. g_printerr("Failed to spawn postprocess process: %s\n",
  679. error->message);
  680. return;
  681. }
  682. g_subprocess_communicate_utf8_async(
  683. proc, NULL, NULL, (GAsyncReadyCallback)post_process_finished, thumb);
  684. }
  685. static void
  686. process_image(MPPipeline *pipeline, const MPBuffer *buffer)
  687. {
  688. #ifdef PROFILE_PROCESS
  689. clock_t t1 = clock();
  690. #endif
  691. size_t size = (libmegapixels_mode_width_to_bytes(state_proc.mode->format,
  692. state_proc.mode->width) +
  693. libmegapixels_mode_width_to_padding(state_proc.mode->format,
  694. state_proc.mode->width)) *
  695. state_proc.mode->height;
  696. uint8_t *image = malloc(size);
  697. memcpy(image, buffer->data, size);
  698. mp_io_pipeline_release_buffer(buffer->index);
  699. MPZBarImage *zbar_image = mp_zbar_image_new(image,
  700. state_proc.mode->format,
  701. state_proc.mode->width,
  702. state_proc.mode->height,
  703. state_proc.device_rotation,
  704. state_proc.mode->mirrored);
  705. mp_zbar_pipeline_process_image(mp_zbar_image_ref(zbar_image));
  706. #ifdef PROFILE_PROCESS
  707. clock_t t2 = clock();
  708. #endif
  709. GdkTexture *thumb = process_image_for_preview(image);
  710. if (state_proc.captures_remaining > 0) {
  711. --state_proc.captures_remaining;
  712. process_image_for_capture(image, state_proc.counter++);
  713. if (state_proc.captures_remaining == 0) {
  714. assert(thumb);
  715. process_capture_burst(thumb);
  716. } else {
  717. assert(!thumb);
  718. }
  719. } else {
  720. assert(!thumb);
  721. }
  722. mp_zbar_image_unref(zbar_image);
  723. ++frames_processed;
  724. if (state_proc.captures_remaining == 0) {
  725. is_capturing = false;
  726. }
  727. #ifdef PROFILE_PROCESS
  728. clock_t t3 = clock();
  729. printf("process_image %fms, step 1:%fms, step 2:%fms\n",
  730. (float)(t3 - t1) / CLOCKS_PER_SEC * 1000,
  731. (float)(t2 - t1) / CLOCKS_PER_SEC * 1000,
  732. (float)(t3 - t2) / CLOCKS_PER_SEC * 1000);
  733. #endif
  734. }
  735. void
  736. mp_process_pipeline_process_image(MPBuffer buffer)
  737. {
  738. // If we haven't processed the previous frame yet, drop this one
  739. if (frames_received != frames_processed && !is_capturing) {
  740. mp_io_pipeline_release_buffer(buffer.index);
  741. return;
  742. }
  743. ++frames_received;
  744. mp_pipeline_invoke(pipeline,
  745. (MPPipelineCallback)process_image,
  746. &buffer,
  747. sizeof(MPBuffer));
  748. }
  749. static void
  750. capture()
  751. {
  752. char template[] = "/tmp/megapixels.XXXXXX";
  753. char *tempdir;
  754. tempdir = mkdtemp(template);
  755. if (tempdir == NULL) {
  756. g_printerr("Could not make capture directory %s\n", template);
  757. exit(EXIT_FAILURE);
  758. }
  759. strcpy(burst_dir, tempdir);
  760. state_proc.captures_remaining = state_proc.burst_length;
  761. state_proc.counter = 0;
  762. }
  763. void
  764. mp_process_pipeline_capture()
  765. {
  766. is_capturing = true;
  767. mp_pipeline_invoke(pipeline, capture, NULL, 0);
  768. }
  769. static void
  770. on_output_changed(bool format_changed)
  771. {
  772. output_buffer_width = state_proc.mode->width / 2;
  773. output_buffer_height = state_proc.mode->height / 2;
  774. if (state_proc.mode->rotation != 0 && state_proc.mode->rotation != 180) {
  775. int tmp = output_buffer_width;
  776. output_buffer_width = output_buffer_height;
  777. output_buffer_height = tmp;
  778. }
  779. for (size_t i = 0; i < NUM_BUFFERS; ++i) {
  780. glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
  781. glTexImage2D(GL_TEXTURE_2D,
  782. 0,
  783. GL_RGBA,
  784. output_buffer_width,
  785. output_buffer_height,
  786. 0,
  787. GL_RGBA,
  788. GL_UNSIGNED_BYTE,
  789. NULL);
  790. }
  791. glBindTexture(GL_TEXTURE_2D, 0);
  792. // Create new gles2_debayer on format change
  793. if (format_changed) {
  794. if (gles2_debayer)
  795. gles2_debayer_free(gles2_debayer);
  796. gles2_debayer = gles2_debayer_new(state_proc.mode->format);
  797. check_gl();
  798. gles2_debayer_use(gles2_debayer);
  799. }
  800. gles2_debayer_configure(gles2_debayer,
  801. output_buffer_width,
  802. output_buffer_height,
  803. state_proc.mode->width,
  804. state_proc.mode->height,
  805. state_proc.mode->rotation,
  806. 0,
  807. state_proc.calibration);
  808. }
  809. static int
  810. mod(int a, int b)
  811. {
  812. int r = a % b;
  813. return r < 0 ? r + b : r;
  814. }
  815. static void
  816. update_state(MPPipeline *pipeline, const mp_state_proc *new_state)
  817. {
  818. bool camera_changed = state_proc.camera != new_state->camera;
  819. state_proc.configuration = new_state->configuration;
  820. state_proc.camera = new_state->camera;
  821. state_proc.gain.control = new_state->gain.control;
  822. state_proc.gain.auto_control = new_state->gain.auto_control;
  823. state_proc.gain.value = new_state->gain.value;
  824. state_proc.gain.max = new_state->gain.max;
  825. state_proc.gain.manual = new_state->gain.manual;
  826. state_proc.exposure.control = new_state->exposure.control;
  827. state_proc.exposure.auto_control = new_state->exposure.auto_control;
  828. state_proc.exposure.value = new_state->exposure.value;
  829. state_proc.exposure.max = new_state->exposure.max;
  830. state_proc.exposure.manual = new_state->exposure.manual;
  831. state_proc.focus.control = new_state->focus.control;
  832. state_proc.focus.auto_control = new_state->focus.auto_control;
  833. state_proc.focus.value = new_state->focus.value;
  834. state_proc.focus.max = new_state->focus.max;
  835. state_proc.focus.manual = new_state->focus.manual;
  836. const bool output_changed =
  837. !libmegapixels_mode_equals(state_proc.mode,
  838. new_state->camera->current_mode) ||
  839. state_proc.preview_width != new_state->preview_width ||
  840. state_proc.preview_height != new_state->preview_height ||
  841. state_proc.device_rotation != new_state->device_rotation;
  842. bool format_changed = state_proc.mode == NULL;
  843. if (!format_changed && state_proc.mode->v4l_pixfmt !=
  844. new_state->camera->current_mode->v4l_pixfmt) {
  845. format_changed = true;
  846. }
  847. state_proc.mode = new_state->camera->current_mode;
  848. state_proc.preview_width = new_state->preview_width;
  849. state_proc.preview_height = new_state->preview_height;
  850. state_proc.device_rotation = new_state->device_rotation;
  851. state_proc.burst_length = new_state->burst_length;
  852. state_proc.balance[0] = new_state->balance[0];
  853. state_proc.balance[1] = new_state->balance[1];
  854. state_proc.balance[2] = new_state->balance[2];
  855. if (output_changed) {
  856. state_proc.camera_rotation = mod(
  857. state_proc.mode->rotation - state_proc.device_rotation, 360);
  858. on_output_changed(format_changed);
  859. }
  860. if (camera_changed) {
  861. char cf[PATH_MAX];
  862. if (find_calibration(cf, state_proc.camera->name)) {
  863. state_proc.calibration = parse_calibration_file(cf);
  864. } else {
  865. printf("No calibration for %s\n", state_proc.camera->name);
  866. }
  867. }
  868. mp_state_main new_main = {
  869. .camera = pr_camera,
  870. .has_auto_focus_continuous = false,
  871. .has_auto_focus_start = false,
  872. .preview_buffer_width = output_buffer_width,
  873. .preview_buffer_height = output_buffer_height,
  874. .control_flash = false,
  875. .gain.control = state_proc.gain.control,
  876. .gain.auto_control = state_proc.gain.auto_control,
  877. .gain.value = state_proc.gain.value,
  878. .gain.max = state_proc.gain.max,
  879. .gain.manual = state_proc.gain.manual,
  880. .exposure.control = state_proc.exposure.control,
  881. .exposure.auto_control = state_proc.exposure.auto_control,
  882. .exposure.value = state_proc.exposure.value,
  883. .exposure.max = state_proc.exposure.max,
  884. .exposure.manual = state_proc.exposure.manual,
  885. .focus.control = state_proc.focus.control,
  886. .focus.auto_control = state_proc.focus.auto_control,
  887. .focus.value = state_proc.focus.value,
  888. .focus.max = state_proc.focus.max,
  889. .focus.manual = state_proc.focus.manual,
  890. .stats.exposure = state_proc.stats.exposure,
  891. .stats.whitebalance = state_proc.stats.whitebalance,
  892. .stats.focus = state_proc.stats.focus,
  893. };
  894. mp_main_update_state(&new_main);
  895. }
  896. void
  897. mp_process_pipeline_update_state(const mp_state_proc *new_state)
  898. {
  899. mp_pipeline_invoke(pipeline,
  900. (MPPipelineCallback)update_state,
  901. new_state,
  902. sizeof(mp_state_proc));
  903. }
  904. // GTK4 seems to require this
  905. void
  906. pango_fc_font_get_languages()
  907. {
  908. }