process_pipeline.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  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. state_proc.red += (state_proc.stats.whitebalance * -0.02f) + (state_proc.stats.tint * 0.01f);
  408. state_proc.blue += (state_proc.stats.whitebalance * +0.02f) + (state_proc.stats.tint * 0.01f);
  409. state_proc.blacklevel += state_proc.stats.blacklevel * 0.01f;
  410. gles2_debayer_set_shading(gles2_debayer, state_proc.red, state_proc.blue, state_proc.blacklevel);
  411. }
  412. // Create a thumbnail from the preview for the last capture
  413. GdkTexture *thumb = NULL;
  414. if (state_proc.captures_remaining == 1) {
  415. printf("Making thumbnail\n");
  416. size_t size = output_buffer_width * output_buffer_height *
  417. sizeof(uint32_t);
  418. uint32_t *data = g_malloc_n(size, 1);
  419. glReadPixels(0,
  420. 0,
  421. output_buffer_width,
  422. output_buffer_height,
  423. GL_RGBA,
  424. GL_UNSIGNED_BYTE,
  425. data);
  426. check_gl();
  427. // Flip vertically
  428. for (size_t y = 0; y < output_buffer_height / 2; ++y) {
  429. for (size_t x = 0; x < output_buffer_width; ++x) {
  430. uint32_t tmp = data[(output_buffer_height - y - 1) *
  431. output_buffer_width +
  432. x];
  433. data[(output_buffer_height - y - 1) *
  434. output_buffer_width +
  435. x] = data[y * output_buffer_width + x];
  436. data[y * output_buffer_width + x] = tmp;
  437. }
  438. }
  439. thumb = gdk_memory_texture_new(output_buffer_width,
  440. output_buffer_height,
  441. GDK_MEMORY_R8G8B8A8,
  442. g_bytes_new_take(data, size),
  443. output_buffer_width *
  444. sizeof(uint32_t));
  445. }
  446. return thumb;
  447. }
  448. static void
  449. process_image_for_capture(const uint8_t *image, int count)
  450. {
  451. time_t rawtime;
  452. time(&rawtime);
  453. struct tm tim = *(localtime(&rawtime));
  454. char datetime[20] = { 0 };
  455. strftime(datetime, 20, "%Y:%m:%d %H:%M:%S", &tim);
  456. char fname[255];
  457. sprintf(fname, "%s/%d.dng", burst_dir, count);
  458. TIFF *tif = TIFFOpen(fname, "w");
  459. if (!tif) {
  460. printf("Could not open tiff\n");
  461. }
  462. // Define TIFF thumbnail
  463. TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 1);
  464. TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, state_proc.mode->width >> 4);
  465. TIFFSetField(tif, TIFFTAG_IMAGELENGTH, state_proc.mode->height >> 4);
  466. TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
  467. TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
  468. TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB);
  469. TIFFSetField(tif, TIFFTAG_MAKE, state_proc.configuration->make);
  470. TIFFSetField(tif, TIFFTAG_MODEL, state_proc.configuration->model);
  471. uint16_t orientation;
  472. if (state_proc.device_rotation == 0) {
  473. orientation = state_proc.mode->mirrored ? ORIENTATION_TOPRIGHT :
  474. ORIENTATION_TOPLEFT;
  475. } else if (state_proc.device_rotation == 90) {
  476. orientation = state_proc.mode->mirrored ? ORIENTATION_RIGHTBOT :
  477. ORIENTATION_LEFTBOT;
  478. } else if (state_proc.device_rotation == 180) {
  479. orientation = state_proc.mode->mirrored ? ORIENTATION_BOTLEFT :
  480. ORIENTATION_BOTRIGHT;
  481. } else {
  482. orientation = state_proc.mode->mirrored ? ORIENTATION_LEFTTOP :
  483. ORIENTATION_RIGHTTOP;
  484. }
  485. TIFFSetField(tif, TIFFTAG_ORIENTATION, orientation);
  486. TIFFSetField(tif, TIFFTAG_DATETIME, datetime);
  487. TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3);
  488. TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  489. TIFFSetField(tif, TIFFTAG_SOFTWARE, "Megapixels");
  490. long sub_offset = 0;
  491. TIFFSetField(tif, TIFFTAG_SUBIFD, 1, &sub_offset);
  492. TIFFSetField(tif, TIFFTAG_DNGVERSION, "\001\001\0\0");
  493. TIFFSetField(tif, TIFFTAG_DNGBACKWARDVERSION, "\001\0\0\0");
  494. char uniquecameramodel[255];
  495. sprintf(uniquecameramodel,
  496. "%s %s",
  497. state_proc.configuration->make,
  498. state_proc.configuration->model);
  499. TIFFSetField(tif, TIFFTAG_UNIQUECAMERAMODEL, uniquecameramodel);
  500. static const float neutral[] = { 1.0, 1.0, 1.0 };
  501. TIFFSetField(tif, TIFFTAG_ASSHOTNEUTRAL, 3, neutral);
  502. TIFFSetField(tif, TIFFTAG_ANALOGBALANCE, 3, state_proc.balance);
  503. // Write black thumbnail, only windows uses this
  504. {
  505. unsigned char *buf = (unsigned char *)calloc(
  506. 1, (state_proc.mode->width >> 4) * 3);
  507. for (int row = 0; row < (state_proc.mode->height >> 4); row++) {
  508. TIFFWriteScanline(tif, buf, row, 0);
  509. }
  510. free(buf);
  511. }
  512. TIFFWriteDirectory(tif);
  513. // Define main photo
  514. TIFFSetField(tif, TIFFTAG_SUBFILETYPE, 0);
  515. TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, state_proc.mode->width);
  516. TIFFSetField(tif, TIFFTAG_IMAGELENGTH, state_proc.mode->height);
  517. TIFFSetField(tif,
  518. TIFFTAG_BITSPERSAMPLE,
  519. libmegapixels_format_bits_per_pixel(state_proc.mode->format));
  520. TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_CFA);
  521. TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 1);
  522. TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
  523. static const short cfapatterndim[] = { 2, 2 };
  524. TIFFSetField(tif, TIFFTAG_CFAREPEATPATTERNDIM, cfapatterndim);
  525. #if (TIFFLIB_VERSION < 20201219) && !LIBTIFF_CFA_PATTERN
  526. TIFFSetField(tif,
  527. TIFFTAG_CFAPATTERN,
  528. mp_pixel_format_cfa_pattern(mode.pixel_format));
  529. #else
  530. TIFFSetField(tif,
  531. TIFFTAG_CFAPATTERN,
  532. 4,
  533. libmegapixels_format_cfa_pattern(state_proc.mode->format));
  534. #endif
  535. printf("TIFF version %d\n", TIFFLIB_VERSION);
  536. int whitelevel =
  537. (1 << libmegapixels_format_bits_per_pixel(state_proc.mode->format)) -
  538. 1;
  539. TIFFSetField(tif, TIFFTAG_WHITELEVEL, 1, &whitelevel);
  540. TIFFCheckpointDirectory(tif);
  541. printf("Writing frame to %s\n", fname);
  542. uint8_t *output_image = (uint8_t *)image;
  543. // Repack 10-bit image from sensor format into a sequencial format
  544. if (libmegapixels_format_bits_per_pixel(state_proc.mode->format) == 10) {
  545. output_image = malloc(
  546. libmegapixels_mode_width_to_bytes(state_proc.mode->format,
  547. state_proc.mode->width) *
  548. state_proc.mode->height);
  549. repack_image_sequencial(image, output_image, state_proc.mode);
  550. }
  551. for (int row = 0; row < state_proc.mode->height; row++) {
  552. TIFFWriteScanline(tif,
  553. (void *)output_image +
  554. (row * libmegapixels_mode_width_to_bytes(
  555. state_proc.mode->format,
  556. state_proc.mode->width)),
  557. row,
  558. 0);
  559. }
  560. TIFFWriteDirectory(tif);
  561. if (output_image != image)
  562. free(output_image);
  563. // Add an EXIF block to the tiff
  564. TIFFCreateEXIFDirectory(tif);
  565. // 1 = manual, 2 = full auto, 3 = aperture priority, 4 = shutter priority
  566. if (!state_proc.exposure.manual) {
  567. TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 2);
  568. } else {
  569. TIFFSetField(tif, EXIFTAG_EXPOSUREPROGRAM, 1);
  570. }
  571. /*
  572. TIFFSetField(tif,
  573. EXIFTAG_EXPOSURETIME,
  574. (mode.frame_interval.numerator /
  575. (float)mode.frame_interval.denominator) /
  576. ((float)mode.height / (float)exposure));
  577. if (pr_camera->iso_min && pr_camera->iso_max) {
  578. uint16_t isospeed = remap(
  579. gain - 1, 0, gain_max, pr_camera->iso_min,
  580. pr_camera->iso_max); TIFFSetField(tif, EXIFTAG_ISOSPEEDRATINGS, 1,
  581. &isospeed);
  582. }
  583. if (!pr_camera->has_flash) {
  584. // No flash function
  585. TIFFSetField(tif, EXIFTAG_FLASH, 0x20);
  586. } else if (flash_enabled) {
  587. // Flash present and fired
  588. TIFFSetField(tif, EXIFTAG_FLASH, 0x1);
  589. } else {
  590. // Flash present but not fired
  591. TIFFSetField(tif, EXIFTAG_FLASH, 0x0);
  592. }
  593. */
  594. TIFFSetField(tif, EXIFTAG_DATETIMEORIGINAL, datetime);
  595. TIFFSetField(tif, EXIFTAG_DATETIMEDIGITIZED, datetime);
  596. /*
  597. if (pr_camera->fnumber) {
  598. TIFFSetField(tif, EXIFTAG_FNUMBER, pr_camera->fnumber);
  599. }
  600. if (pr_camera->focallength) {
  601. TIFFSetField(tif, EXIFTAG_FOCALLENGTH, pr_camera->focallength);
  602. }
  603. if (pr_camera->focallength && pr_camera->cropfactor) {
  604. TIFFSetField(tif,
  605. EXIFTAG_FOCALLENGTHIN35MMFILM,
  606. (short)(pr_camera->focallength *
  607. pr_camera->cropfactor));
  608. }
  609. */
  610. uint64_t exif_offset = 0;
  611. TIFFWriteCustomDirectory(tif, &exif_offset);
  612. TIFFFreeDirectory(tif);
  613. // Update exif pointer
  614. TIFFSetDirectory(tif, 0);
  615. TIFFSetField(tif, TIFFTAG_EXIFIFD, exif_offset);
  616. TIFFRewriteDirectory(tif);
  617. TIFFClose(tif);
  618. }
  619. static void
  620. post_process_finished(GSubprocess *proc, GAsyncResult *res, GdkTexture *thumb)
  621. {
  622. char *stdout;
  623. g_subprocess_communicate_utf8_finish(proc, res, &stdout, NULL, NULL);
  624. // The last line contains the file name
  625. int end = strlen(stdout);
  626. // Skip the newline at the end
  627. stdout[--end] = '\0';
  628. char *path = path = stdout + end - 1;
  629. do {
  630. if (*path == '\n') {
  631. path++;
  632. break;
  633. }
  634. --path;
  635. } while (path > stdout);
  636. mp_main_capture_completed(thumb, path);
  637. }
  638. static void
  639. process_capture_burst(GdkTexture *thumb)
  640. {
  641. time_t rawtime;
  642. time(&rawtime);
  643. struct tm tim = *(localtime(&rawtime));
  644. char timestamp[30];
  645. strftime(timestamp, 30, "%Y%m%d%H%M%S", &tim);
  646. if (g_get_user_special_dir(G_USER_DIRECTORY_PICTURES) != NULL) {
  647. sprintf(capture_fname,
  648. "%s/IMG%s",
  649. g_get_user_special_dir(G_USER_DIRECTORY_PICTURES),
  650. timestamp);
  651. } else if (getenv("XDG_PICTURES_DIR") != NULL) {
  652. sprintf(capture_fname,
  653. "%s/IMG%s",
  654. getenv("XDG_PICTURES_DIR"),
  655. timestamp);
  656. } else {
  657. sprintf(capture_fname,
  658. "%s/Pictures/IMG%s",
  659. getenv("HOME"),
  660. timestamp);
  661. }
  662. bool save_dng = g_settings_get_boolean(settings, "save-raw");
  663. char *postprocessor = g_settings_get_string(settings, "postprocessor");
  664. char save_dng_s[2] = "0";
  665. if (save_dng) {
  666. save_dng_s[0] = '1';
  667. }
  668. // Start post-processing the captured burst
  669. g_print("Post process %s to %s.ext (save-dng %s)\n",
  670. burst_dir,
  671. capture_fname,
  672. save_dng_s);
  673. g_autoptr(GError) error = NULL;
  674. GSubprocess *proc = g_subprocess_new(G_SUBPROCESS_FLAGS_STDOUT_PIPE,
  675. &error,
  676. postprocessor,
  677. burst_dir,
  678. capture_fname,
  679. save_dng_s,
  680. NULL);
  681. if (!proc) {
  682. g_printerr("Failed to spawn postprocess process: %s\n",
  683. error->message);
  684. return;
  685. }
  686. g_subprocess_communicate_utf8_async(
  687. proc, NULL, NULL, (GAsyncReadyCallback)post_process_finished, thumb);
  688. }
  689. static void
  690. process_image(MPPipeline *pipeline, const MPBuffer *buffer)
  691. {
  692. #ifdef PROFILE_PROCESS
  693. clock_t t1 = clock();
  694. #endif
  695. size_t size = (libmegapixels_mode_width_to_bytes(state_proc.mode->format,
  696. state_proc.mode->width) +
  697. libmegapixels_mode_width_to_padding(state_proc.mode->format,
  698. state_proc.mode->width)) *
  699. state_proc.mode->height;
  700. uint8_t *image = malloc(size);
  701. memcpy(image, buffer->data, size);
  702. mp_io_pipeline_release_buffer(buffer->index);
  703. MPZBarImage *zbar_image = mp_zbar_image_new(image,
  704. state_proc.mode->format,
  705. state_proc.mode->width,
  706. state_proc.mode->height,
  707. state_proc.device_rotation,
  708. state_proc.mode->mirrored);
  709. mp_zbar_pipeline_process_image(mp_zbar_image_ref(zbar_image));
  710. #ifdef PROFILE_PROCESS
  711. clock_t t2 = clock();
  712. #endif
  713. GdkTexture *thumb = process_image_for_preview(image);
  714. if (state_proc.captures_remaining > 0) {
  715. --state_proc.captures_remaining;
  716. process_image_for_capture(image, state_proc.counter++);
  717. if (state_proc.captures_remaining == 0) {
  718. assert(thumb);
  719. process_capture_burst(thumb);
  720. } else {
  721. assert(!thumb);
  722. }
  723. } else {
  724. assert(!thumb);
  725. }
  726. mp_zbar_image_unref(zbar_image);
  727. ++frames_processed;
  728. if (state_proc.captures_remaining == 0) {
  729. is_capturing = false;
  730. }
  731. #ifdef PROFILE_PROCESS
  732. clock_t t3 = clock();
  733. printf("process_image %fms, step 1:%fms, step 2:%fms\n",
  734. (float)(t3 - t1) / CLOCKS_PER_SEC * 1000,
  735. (float)(t2 - t1) / CLOCKS_PER_SEC * 1000,
  736. (float)(t3 - t2) / CLOCKS_PER_SEC * 1000);
  737. #endif
  738. }
  739. void
  740. mp_process_pipeline_process_image(MPBuffer buffer)
  741. {
  742. // If we haven't processed the previous frame yet, drop this one
  743. if (frames_received != frames_processed && !is_capturing) {
  744. mp_io_pipeline_release_buffer(buffer.index);
  745. return;
  746. }
  747. ++frames_received;
  748. mp_pipeline_invoke(pipeline,
  749. (MPPipelineCallback)process_image,
  750. &buffer,
  751. sizeof(MPBuffer));
  752. }
  753. static void
  754. capture()
  755. {
  756. char template[] = "/tmp/megapixels.XXXXXX";
  757. char *tempdir;
  758. tempdir = mkdtemp(template);
  759. if (tempdir == NULL) {
  760. g_printerr("Could not make capture directory %s\n", template);
  761. exit(EXIT_FAILURE);
  762. }
  763. strcpy(burst_dir, tempdir);
  764. state_proc.captures_remaining = state_proc.burst_length;
  765. state_proc.counter = 0;
  766. }
  767. void
  768. mp_process_pipeline_capture()
  769. {
  770. is_capturing = true;
  771. mp_pipeline_invoke(pipeline, capture, NULL, 0);
  772. }
  773. static void
  774. on_output_changed(bool format_changed)
  775. {
  776. output_buffer_width = state_proc.mode->width / 2;
  777. output_buffer_height = state_proc.mode->height / 2;
  778. if (state_proc.mode->rotation != 0 && state_proc.mode->rotation != 180) {
  779. int tmp = output_buffer_width;
  780. output_buffer_width = output_buffer_height;
  781. output_buffer_height = tmp;
  782. }
  783. for (size_t i = 0; i < NUM_BUFFERS; ++i) {
  784. glBindTexture(GL_TEXTURE_2D, output_buffers[i].texture_id);
  785. glTexImage2D(GL_TEXTURE_2D,
  786. 0,
  787. GL_RGBA,
  788. output_buffer_width,
  789. output_buffer_height,
  790. 0,
  791. GL_RGBA,
  792. GL_UNSIGNED_BYTE,
  793. NULL);
  794. }
  795. glBindTexture(GL_TEXTURE_2D, 0);
  796. // Create new gles2_debayer on format change
  797. if (format_changed) {
  798. if (gles2_debayer)
  799. gles2_debayer_free(gles2_debayer);
  800. gles2_debayer = gles2_debayer_new(state_proc.mode->format);
  801. check_gl();
  802. gles2_debayer_use(gles2_debayer);
  803. }
  804. state_proc.blacklevel = 0.0f;
  805. state_proc.red = 1.0f;
  806. state_proc.blue = 1.0f;
  807. gles2_debayer_configure(gles2_debayer,
  808. output_buffer_width,
  809. output_buffer_height,
  810. state_proc.mode->width,
  811. state_proc.mode->height,
  812. state_proc.mode->rotation,
  813. 0,
  814. state_proc.calibration);
  815. }
  816. static int
  817. mod(int a, int b)
  818. {
  819. int r = a % b;
  820. return r < 0 ? r + b : r;
  821. }
  822. static void
  823. update_state(MPPipeline *pipeline, const mp_state_proc *new_state)
  824. {
  825. bool camera_changed = state_proc.camera != new_state->camera;
  826. state_proc.configuration = new_state->configuration;
  827. state_proc.camera = new_state->camera;
  828. state_proc.gain.control = new_state->gain.control;
  829. state_proc.gain.auto_control = new_state->gain.auto_control;
  830. state_proc.gain.value = new_state->gain.value;
  831. state_proc.gain.max = new_state->gain.max;
  832. state_proc.gain.manual = new_state->gain.manual;
  833. state_proc.exposure.control = new_state->exposure.control;
  834. state_proc.exposure.auto_control = new_state->exposure.auto_control;
  835. state_proc.exposure.value = new_state->exposure.value;
  836. state_proc.exposure.max = new_state->exposure.max;
  837. state_proc.exposure.manual = new_state->exposure.manual;
  838. state_proc.focus.control = new_state->focus.control;
  839. state_proc.focus.auto_control = new_state->focus.auto_control;
  840. state_proc.focus.value = new_state->focus.value;
  841. state_proc.focus.max = new_state->focus.max;
  842. state_proc.focus.manual = new_state->focus.manual;
  843. const bool output_changed =
  844. !libmegapixels_mode_equals(state_proc.mode,
  845. new_state->camera->current_mode) ||
  846. state_proc.preview_width != new_state->preview_width ||
  847. state_proc.preview_height != new_state->preview_height ||
  848. state_proc.device_rotation != new_state->device_rotation;
  849. bool format_changed = state_proc.mode == NULL;
  850. if (!format_changed && state_proc.mode->v4l_pixfmt !=
  851. new_state->camera->current_mode->v4l_pixfmt) {
  852. format_changed = true;
  853. }
  854. state_proc.mode = new_state->camera->current_mode;
  855. state_proc.preview_width = new_state->preview_width;
  856. state_proc.preview_height = new_state->preview_height;
  857. state_proc.device_rotation = new_state->device_rotation;
  858. state_proc.burst_length = new_state->burst_length;
  859. state_proc.balance[0] = new_state->balance[0];
  860. state_proc.balance[1] = new_state->balance[1];
  861. state_proc.balance[2] = new_state->balance[2];
  862. if (output_changed) {
  863. state_proc.camera_rotation = mod(
  864. state_proc.mode->rotation - state_proc.device_rotation, 360);
  865. on_output_changed(format_changed);
  866. }
  867. if (camera_changed) {
  868. char cf[PATH_MAX];
  869. if (find_calibration(cf, state_proc.camera->name)) {
  870. state_proc.calibration = parse_calibration_file(cf);
  871. } else {
  872. printf("No calibration for %s\n", state_proc.camera->name);
  873. }
  874. }
  875. mp_state_main new_main = {
  876. .camera = pr_camera,
  877. .has_auto_focus_continuous = false,
  878. .has_auto_focus_start = false,
  879. .preview_buffer_width = output_buffer_width,
  880. .preview_buffer_height = output_buffer_height,
  881. .control_flash = false,
  882. .gain.control = state_proc.gain.control,
  883. .gain.auto_control = state_proc.gain.auto_control,
  884. .gain.value = state_proc.gain.value,
  885. .gain.max = state_proc.gain.max,
  886. .gain.manual = state_proc.gain.manual,
  887. .exposure.control = state_proc.exposure.control,
  888. .exposure.auto_control = state_proc.exposure.auto_control,
  889. .exposure.value = state_proc.exposure.value,
  890. .exposure.max = state_proc.exposure.max,
  891. .exposure.manual = state_proc.exposure.manual,
  892. .focus.control = state_proc.focus.control,
  893. .focus.auto_control = state_proc.focus.auto_control,
  894. .focus.value = state_proc.focus.value,
  895. .focus.max = state_proc.focus.max,
  896. .focus.manual = state_proc.focus.manual,
  897. .stats.exposure = state_proc.stats.exposure,
  898. .stats.whitebalance = state_proc.stats.whitebalance,
  899. .stats.focus = state_proc.stats.focus,
  900. };
  901. mp_main_update_state(&new_main);
  902. }
  903. void
  904. mp_process_pipeline_update_state(const mp_state_proc *new_state)
  905. {
  906. mp_pipeline_invoke(pipeline,
  907. (MPPipelineCallback)update_state,
  908. new_state,
  909. sizeof(mp_state_proc));
  910. }
  911. // GTK4 seems to require this
  912. void
  913. pango_fc_font_get_languages()
  914. {
  915. }