process_pipeline.c 36 KB

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