Guest User

Raw Rec

a guest
May 22nd, 2013
642
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2. * RAW recording. Similar to lv_rec, with some different internals:
  3. *
  4. * - buffering: group the frames in 32GB contiguous chunks, to maximize writing speed
  5. * - edmac_copy_rectangle: we can crop the image and trim the black borders!
  6. * - edmac operation done outside the LV task
  7. * - on buffer overflow, it stops or skips frames (user-selected)
  8. * - using generic raw routines, no hardcoded stuff (should be easier to port)
  9. * - only for RAW in a single file (do one thing and do it well)
  10. * - goal: 1920x1080 on 1000x cards
  11. *
  12. * Usage:
  13. * - enable modules in Makefile.user (CONFIG_MODULES = y, CONFIG_TCC = y, CONFIG_PICOC = n, CONFIG_CONSOLE = y)
  14. * - run "make" from modules/raw_rec to compile this module and the DNG converter
  15. * - run "make install" from platform dir to copy the modules on the card
  16. * - from Module menu: Load modules now
  17. * - look in Movie menu
  18. */
  19.  
  20. #include <module.h>
  21. #include <dryos.h>
  22. #include <property.h>
  23. #include <bmp.h>
  24. #include <menu.h>
  25. #include <config.h>
  26. #include "../lv_rec/lv_rec.h"
  27. #include "edmac.h"
  28.  
  29. static int resolution_presets_x[] = { 640, 720, 960, 1120, 1136, 1152, 1200, 1280, 1320, 1360, 1440, 1504, 1536, 1600, 1880, 1920, 2048, 2560, 2880, 3592 };
  30. #define RESOLUTION_CHOICES_X CHOICES("640","720","960","1120","1136","1152","1200","1280","1320","1360","1440","1504","1536","1600","1880","1920","2048","2560","2880","3592")
  31. static int resolution_presets_y[] = { 320, 360, 400, 434, 480, 500, 540, 544, 580, 600, 620, 640, 680, 700, 720, 740, 768, 840, 900, 960, 1024, 1080, 1152, 1180, 1280, 1320 };
  32. #define RESOLUTION_CHOICES_Y CHOICES("320","360","400","434", "480","500", "540","544","580","600","620","640","680","700","720","740","768","840","900","960","1024","1080","1152","1180","1280","1320")
  33.  
  34. extern void raw14_to_raw12(void *buffer, int size);
  35. extern void raw14_to_raw10(void *buffer, int size);
  36.  
  37. static int buffer_size_compressed = 0;
  38.  
  39. /* when enabled, it hooks shortcut keys */
  40. static int raw_video_enabled = 0;
  41.  
  42. //~ static CONFIG_INT("raw.res.x", resolution_index_x, 2);
  43. //~ static CONFIG_INT("raw.res.y", resolution_index_y, 4);
  44. //~ static CONFIG_INT("raw.write.spd", measured_write_speed, 0);
  45.  
  46. /* no config options yet */
  47. static int resolution_index_x = 9;
  48. static int resolution_index_y = 7;
  49. static int measured_write_speed = 0;
  50. static int stop_on_buffer_overflow = 1;
  51. static int sound_rec = 2;
  52. static int panning_enabled = 0;
  53. static int hacked_mode = 0;
  54.  
  55. #define RAW_IDLE 0
  56. #define RAW_PREPARING 1
  57. #define RAW_RECORDING 2
  58. #define RAW_FINISHING 3
  59.  
  60. static int raw_recording_state = RAW_IDLE;
  61.  
  62. #define RAW_IS_IDLE (raw_recording_state == RAW_IDLE)
  63. #define RAW_IS_PREPARING (raw_recording_state == RAW_PREPARING)
  64. #define RAW_IS_RECORDING (raw_recording_state == RAW_RECORDING)
  65. #define RAW_IS_FINISHING (raw_recording_state == RAW_FINISHING)
  66.  
  67. struct buff
  68. {
  69. void* ptr;
  70. int size;
  71. int used;
  72. };
  73.  
  74. static struct memSuite * mem_suite = 0; /* memory suite for our buffers */
  75. static void * fullsize_buffers[2]; /* original image, before cropping, double-buffered */
  76. static struct buff buffers[10]; /* our recording buffers */
  77. static int buffer_count = 0; /* how many buffers we could allocate */
  78. static int capturing_buffer_index = 0; /* in which buffer we are capturing */
  79. static int saving_buffer_index = 0; /* from which buffer we are saving to card */
  80. static int capture_offset = 0; /* position of capture pointer inside the buffer (0-32MB) */
  81. static int frame_count = 0; /* how many frames we have processed */
  82. static int frame_skips = 0; /* how many frames were dropped/skipped */
  83. static char* movie_filename = 0; /* file name for current (or last) movie */
  84.  
  85. static int get_res_x()
  86. {
  87. return MIN(resolution_presets_x[resolution_index_x], raw_info.jpeg.width);
  88. }
  89.  
  90. static int get_res_y()
  91. {
  92. return MIN(resolution_presets_y[resolution_index_y], raw_info.jpeg.height);
  93. }
  94.  
  95. static MENU_UPDATE_FUNC(write_speed_update)
  96. {
  97. int res_x = get_res_x();
  98. int res_y = get_res_y();
  99. int fps = fps_get_current_x1000();
  100. int speed = (res_x * res_y * 14/8 / 1024) * fps / 100 / 1024;
  101. int ok = speed < measured_write_speed;
  102. MENU_SET_WARNING(ok ? MENU_WARN_INFO : MENU_WARN_ADVICE,
  103. "Write speed needed: %d.%d MB/s at %d.%03d fps.",
  104. speed/10, speed%10, fps/1000, fps%1000
  105. );
  106. char msg[70];
  107. int best_num = 0;
  108. int best_den = 0;
  109. float ratio = (float)res_x / res_y;
  110. float minerr = 100;
  111. for (int num = 0; num < 20; num++)
  112. {
  113. for (int den = 0; den < 20; den++)
  114. {
  115. float err = ABS((float)num / den - ratio);
  116. if (err < minerr)
  117. {
  118. minerr = err;
  119. best_num = num;
  120. best_den = den;
  121. }
  122. }
  123. }
  124. snprintf(msg, sizeof(msg), "Aspect ratio: %d:%d", best_num, best_den);
  125. if (ratio > 1)
  126. {
  127. int r = ratio * 100;
  128. if (r%100) STR_APPEND(msg, " (%d.%02d:1)", r/100, r%100);
  129. }
  130. else
  131. {
  132. int r = (1/ratio) * 100;
  133. if (r%100) STR_APPEND(msg, " (1:%d.%02d)", r/100, r%100);
  134. }
  135.  
  136. MENU_SET_HELP(msg);
  137. }
  138.  
  139. static void refresh_raw_settings()
  140. {
  141. if (RAW_IS_IDLE)
  142. {
  143. /* autodetect the resolution (update every second) */
  144. static int aux = INT_MIN;
  145. if (should_run_polling_action(1000, &aux))
  146. {
  147. raw_update_params();
  148. }
  149. }
  150. }
  151. static MENU_UPDATE_FUNC(raw_main_update)
  152. {
  153. if (!raw_video_enabled) return;
  154.  
  155. refresh_raw_settings();
  156.  
  157. if (!RAW_IS_IDLE)
  158. {
  159. MENU_SET_VALUE(RAW_IS_RECORDING ? "Recording..." : RAW_IS_PREPARING ? "Starting..." : RAW_IS_FINISHING ? "Stopping..." : "err");
  160. MENU_SET_ICON(MNI_RECORD, 0);
  161. }
  162. else
  163. {
  164. MENU_SET_VALUE("ON, %dx%d", get_res_x(), get_res_y());
  165. }
  166.  
  167. write_speed_update(entry, info);
  168. }
  169.  
  170. static MENU_UPDATE_FUNC(resolution_update)
  171. {
  172. if (!raw_video_enabled)
  173. {
  174. MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Enable RAW video first.");
  175. MENU_SET_VALUE("N/A");
  176. return;
  177. }
  178.  
  179. refresh_raw_settings();
  180.  
  181. int is_x = (entry->priv == &resolution_index_x);
  182. int selected = is_x ? resolution_presets_x[resolution_index_x] : resolution_presets_y[resolution_index_y];
  183. int possible = is_x ? get_res_x() : get_res_y();
  184. MENU_SET_VALUE("%d", possible);
  185.  
  186. if(lv)
  187. {
  188. if (selected != possible)
  189. MENU_SET_RINFO(" can't %d", selected);
  190. else
  191. MENU_SET_RINFO("max %d", is_x ? raw_info.jpeg.width : raw_info.jpeg.height);
  192. }
  193. else
  194. {
  195. MENU_SET_RINFO("");
  196. }
  197.  
  198. write_speed_update(entry, info);
  199. }
  200.  
  201. /* add a footer to given file handle to */
  202. static unsigned int lv_rec_save_footer(FILE *save_file)
  203. {
  204. lv_rec_file_footer_t footer;
  205.  
  206. strcpy((char*)footer.magic, "RAWM");
  207. footer.xRes = get_res_x();
  208. footer.yRes = get_res_y();
  209. footer.frameSize = footer.xRes * footer.yRes * 14/8;
  210. footer.frameCount = frame_count - 1; /* last frame is usually gibberish */
  211. footer.frameSkip = 1;
  212.  
  213. footer.sourceFpsx1000 = fps_get_current_x1000();
  214. footer.raw_info = raw_info;
  215.  
  216. int written = FIO_WriteFile(save_file, &footer, sizeof(lv_rec_file_footer_t));
  217.  
  218. return written == sizeof(lv_rec_file_footer_t);
  219. }
  220.  
  221. static int setup_buffers()
  222. {
  223. /* allocate the entire memory, but only use large chunks */
  224. /* yes, this may be a bit wasteful, but at least it works */
  225. mem_suite = shoot_malloc_suite(0);
  226. if (!mem_suite) return 0;
  227.  
  228. /* allocate memory for double buffering */
  229. int buf_size = raw_info.frame_size * 33/32; /* leave some margin, just in case */
  230.  
  231. /* find the smallest chunk that we can use for buf_size */
  232. fullsize_buffers[0] = 0;
  233. struct memChunk * chunk = GetFirstChunkFromSuite(mem_suite);
  234. int waste = INT_MAX;
  235. while(chunk)
  236. {
  237. int size = GetSizeOfMemoryChunk(chunk);
  238. if (size >= buf_size)
  239. {
  240. if (size - buf_size < waste)
  241. {
  242. waste = size - buf_size;
  243. fullsize_buffers[0] = GetMemoryAddressOfMemoryChunk(chunk);
  244. }
  245. }
  246. chunk = GetNextMemoryChunk(mem_suite, chunk);
  247. }
  248. if (fullsize_buffers[0] == 0) return 0;
  249.  
  250. /* reuse Canon's buffer */
  251. fullsize_buffers[1] = raw_info.buffer;
  252. if (fullsize_buffers[1] == 0) return 0;
  253.  
  254. /* use all chunks larger than 16MB for recording */
  255. chunk = GetFirstChunkFromSuite(mem_suite);
  256. buffer_count = 0;
  257. int total = 0;
  258. while(chunk && buffer_count < COUNT(buffers))
  259. {
  260. int size = GetSizeOfMemoryChunk(chunk);
  261. if (size >= 16*1024*1024)
  262. {
  263.  
  264. void* ptr = GetMemoryAddressOfMemoryChunk(chunk);
  265. if (ptr != fullsize_buffers[0])
  266. {
  267. /* make sure our buffers are aligned at 4K */
  268. buffers[buffer_count].ptr = (void*)(((intptr_t)ptr + 4095) & ~4095);
  269. buffers[buffer_count].size = size - 8192;
  270. buffers[buffer_count].used = 0;
  271. buffer_count++;
  272. total += size;
  273. }
  274.  
  275. }
  276. chunk = GetNextMemoryChunk(mem_suite, chunk);
  277. }
  278.  
  279. /* try to recycle the waste */
  280. if (waste >= 16*1024*1024 + 8192)
  281. {
  282. buffers[buffer_count].ptr = (void*)(((intptr_t)(fullsize_buffers[0] + buf_size) + 4095) & ~4095);
  283. buffers[buffer_count].size = waste - 8192;
  284. buffers[buffer_count].used = 0;
  285. buffer_count++;
  286. total += waste;
  287. }
  288.  
  289. /* Sort Buffers */
  290. static struct buff temp[10];
  291. for (int i = 0; i < buffer_count; i++)
  292. for(int j = 0; j < buffer_count- i - 1; j++)
  293. if(buffers[j].size < buffers[j + 1].size)
  294. {
  295. temp[j] = buffers[j];
  296. buffers[j] = buffers[j + 1];
  297. buffers[j + 1] = temp[j];
  298. }
  299.  
  300. char msg[100];
  301. snprintf(msg, sizeof(msg), "Alloc: ");
  302. for (int i = 0; i < buffer_count; i++)
  303. {
  304. STR_APPEND(msg, "%dM", (buffers[i].size / 1024 + 512) / 1024);
  305. if (i < buffer_count-1) STR_APPEND(msg, "+");
  306. }
  307. bmp_printf(FONT_MED, 30, 90, msg);
  308.  
  309. /* we need at least two buffers */
  310. if (buffer_count < 2) return 0;
  311.  
  312. return 1;
  313. }
  314.  
  315. static void free_buffers()
  316. {
  317. if (mem_suite) shoot_free_suite(mem_suite);
  318. mem_suite = 0;
  319. }
  320.  
  321. static void show_buffer_status(int adj)
  322. {
  323. if (!liveview_display_idle()) return;
  324.  
  325. int free_buffers = mod(saving_buffer_index - capturing_buffer_index, buffer_count); /* how many free slots do we have? */
  326. if (free_buffers == 0) free_buffers = 4; /* saving task waiting for capturing task */
  327. free_buffers += adj; /* when skipping frames, adj is -1, because capturing_buffer_index was not incremented yet */
  328.  
  329. /* could use a nicer display, but stars should be fine too */
  330. char buffer_status[10];
  331. for (int i = 0; i < (buffer_count-free_buffers); i++)
  332. buffer_status[i] = '*';
  333. for (int i = (buffer_count-free_buffers); i < buffer_count; i++)
  334. buffer_status[i] = '.';
  335. buffer_status[buffer_count] = 0;
  336.  
  337. if(frame_skips > 0)
  338. {
  339. bmp_printf(FONT(FONT_MED, COLOR_RED, COLOR_BLACK), 30, 50, "Buffer usage: <%s>, %d skipped frames", buffer_status, frame_skips);
  340. }
  341. else
  342. {
  343. bmp_printf(FONT_MED, 30, 50, "Buffer usage: <%s>", buffer_status);
  344. }
  345. }
  346.  
  347. static int frame_offset_x = 0;
  348. static int frame_offset_y = 0;
  349. static int frame_offset_delta_x = 0;
  350. static int frame_offset_delta_y = 0;
  351.  
  352. static unsigned int raw_rec_should_preview(unsigned int ctx);
  353.  
  354. static void cropmark_draw()
  355. {
  356. if (raw_rec_should_preview(0))
  357. raw_force_aspect_ratio_1to1();
  358.  
  359. int res_x = get_res_x();
  360. int res_y = get_res_y();
  361. int skip_x = raw_info.active_area.x1 + (raw_info.jpeg.width - res_x) / 2;
  362. int skip_y = raw_info.active_area.y1 + (raw_info.jpeg.height - res_y) / 2;
  363.  
  364. if (panning_enabled)
  365. {
  366. skip_x += frame_offset_x;
  367. skip_y += frame_offset_y;
  368. }
  369.  
  370. int x = RAW2BM_X(skip_x);
  371. int y = RAW2BM_Y(skip_y);
  372. int w = RAW2BM_DX(res_x);
  373. int h = RAW2BM_DY(res_y);
  374. static int prev_x = 0;
  375. static int prev_y = 0;
  376. static int prev_w = 0;
  377. static int prev_h = 0;
  378.  
  379. /* window changed? erase the old cropmark */
  380. if (prev_x != x || prev_y != y || prev_w != w || prev_h != h)
  381. {
  382. bmp_draw_rect(0, prev_x, prev_y, prev_w, prev_h);
  383. bmp_draw_rect(0, prev_x-1, prev_y-1, prev_w+2, prev_h+2);
  384. }
  385.  
  386. prev_x = x;
  387. prev_y = y;
  388. prev_w = w;
  389. prev_h = h;
  390.  
  391. /* display a simple cropmark */
  392. bmp_draw_rect(COLOR_WHITE, x, y, w, h);
  393. bmp_draw_rect(COLOR_BLACK, x-1, y-1, w+2, h+2);
  394. }
  395.  
  396. static void panning_update()
  397. {
  398. if (!panning_enabled) return;
  399.  
  400. int res_x = get_res_x();
  401. int res_y = get_res_y();
  402. int skip_x = raw_info.active_area.x1 + (raw_info.jpeg.width - res_x) / 2;
  403. int skip_y = raw_info.active_area.y1 + (raw_info.jpeg.height - res_y) / 2;
  404.  
  405. frame_offset_x = COERCE(
  406. frame_offset_x + frame_offset_delta_x,
  407. raw_info.active_area.x1 - skip_x,
  408. raw_info.active_area.x2 - res_x - skip_x
  409. );
  410.  
  411. frame_offset_y = COERCE(
  412. frame_offset_y + frame_offset_delta_y,
  413. raw_info.active_area.y1 - skip_y,
  414. raw_info.active_area.y2 - res_y - skip_y
  415. );
  416. }
  417.  
  418. static unsigned int raw_rec_polling_cbr(unsigned int unused)
  419. {
  420. if (!raw_video_enabled)
  421. return 0;
  422.  
  423. /* refresh cropmark (faster when panning, slower when idle) */
  424. static int aux = INT_MIN;
  425. if (frame_offset_delta_x || frame_offset_delta_y || should_run_polling_action(500, &aux))
  426. {
  427. if (liveview_display_idle())
  428. {
  429. BMP_LOCK( cropmark_draw(); )
  430. }
  431. }
  432.  
  433. /* update settings when changing video modes (outside menu) */
  434. if (RAW_IS_IDLE && !gui_menu_shown())
  435. {
  436. refresh_raw_settings();
  437. }
  438.  
  439. return 0;
  440. }
  441.  
  442. static void lv_unhack(int unused)
  443. {
  444. call("aewb_enableaewb", 1);
  445. idle_globaldraw_en();
  446. PauseLiveView();
  447. ResumeLiveView();
  448. }
  449.  
  450. static void hack_liveview()
  451. {
  452. if (!hacked_mode) return;
  453.  
  454. int rec = RAW_IS_RECORDING;
  455. static int prev_rec = 0;
  456. int should_hack = 0;
  457. int should_unhack = 0;
  458.  
  459. if (rec)
  460. {
  461. if (frame_count == 0)
  462. should_hack = 1;
  463. /*
  464. if (frame_count % 10 == 0)
  465. should_hack = 1;
  466. else if (frame_count % 10 == 9)
  467. should_unhack = 1;
  468. */
  469. }
  470. else if (prev_rec)
  471. {
  472. should_unhack = 1;
  473. }
  474. prev_rec = rec;
  475.  
  476. if (should_hack)
  477. {
  478. call("aewb_enableaewb", 0);
  479. idle_globaldraw_dis();
  480. int y = 100;
  481. for (int channel = 0; channel < 32; channel++)
  482. {
  483. /* silence out the EDMACs used for HD and LV buffers */
  484. int pitch = edmac_get_length(channel) & 0xFFFF;
  485. if (pitch == vram_lv.pitch || pitch == vram_hd.pitch)
  486. {
  487. uint32_t reg = edmac_get_base(channel);
  488. bmp_printf(FONT_SMALL, 30, y += font_small.height, "Hack %x %dx%d ", reg, shamem_read(reg + 0x10) & 0xFFFF, shamem_read(reg + 0x10) >> 16);
  489. *(volatile uint32_t *)(reg + 0x10) = shamem_read(reg + 0x10) & 0xFFFF;
  490. }
  491. }
  492. }
  493. else if (should_unhack)
  494. {
  495. task_create("lv_unhack", 0x1e, 0x1000, lv_unhack, (void*)0);
  496. }
  497. }
  498.  
  499. static int process_frame()
  500. {
  501. if (!lv) return 0;
  502.  
  503. /* skip the first frame, it will be gibberish */
  504. if (frame_count == 0) { frame_count++; return 0; }
  505.  
  506. /* copy current frame to our buffer and crop it to its final size */
  507. int res_x = get_res_x();
  508. int res_y = get_res_y();
  509.  
  510. /* center crop */
  511. int skip_x = raw_info.active_area.x1 + (raw_info.jpeg.width - res_x) / 2;
  512. int skip_y = raw_info.active_area.y1 + (raw_info.jpeg.height - res_y) / 2;
  513. if (panning_enabled)
  514. {
  515. skip_x += frame_offset_x;
  516. skip_y += frame_offset_y;
  517. }
  518.  
  519. /* start copying frame to our buffer */
  520. void* ptr = buffers[capturing_buffer_index].ptr + capture_offset;
  521. int ans = edmac_copy_rectangle_start(ptr, fullsize_buffers[(frame_count+1) % 2], raw_info.pitch, skip_x/8*14, skip_y/2*2, res_x*14/8, res_y);
  522.  
  523. /* advance to next frame */
  524. frame_count++;
  525. capture_offset += res_x * res_y * 14/8;
  526.  
  527. if (liveview_display_idle())
  528. {
  529. bmp_printf( FONT_MED, 30, 70,
  530. "Capturing frame %d...",
  531. frame_count
  532. );
  533. }
  534.  
  535. return ans;
  536. }
  537.  
  538. static unsigned int raw_rec_vsync_cbr(unsigned int unused)
  539. {
  540. static int dma_transfer_in_progress = 0;
  541. /* there may be DMA transfers started in process_frame, finish them */
  542. /* let's assume they are faster than LiveView refresh rate (well, they HAVE to be) */
  543. if (dma_transfer_in_progress)
  544. {
  545. edmac_copy_rectangle_finish();
  546. dma_transfer_in_progress = 0;
  547. }
  548.  
  549. if (!raw_video_enabled) return 0;
  550.  
  551. hack_liveview();
  552.  
  553. /* panning window is updated when recording, but also when not recording */
  554. panning_update();
  555.  
  556. if (!RAW_IS_RECORDING) return 0;
  557. if (!raw_lv_settings_still_valid()) { raw_recording_state = RAW_FINISHING; return 0; }
  558. if (stop_on_buffer_overflow && frame_skips) return 0;
  559.  
  560. /* double-buffering */
  561. raw_lv_redirect_edmac(fullsize_buffers[frame_count % 2]);
  562.  
  563. if (capture_offset + raw_info.frame_size >= buffers[capturing_buffer_index].size)
  564. {
  565. /* this buffer is full, try next one */
  566. int next_buffer = mod(capturing_buffer_index + 1, buffer_count);
  567. if (next_buffer != saving_buffer_index)
  568. {
  569. buffers[capturing_buffer_index].used = capture_offset;
  570. capturing_buffer_index = next_buffer;
  571. capture_offset = 0;
  572. }
  573. else
  574. {
  575. /* card too slow */
  576. frame_skips++;
  577. if (!stop_on_buffer_overflow)
  578. {
  579. bmp_printf( FONT_MED, 30, 70,
  580. "Skipping frames... "
  581. );
  582. }
  583. show_buffer_status(-1);
  584. return 0;
  585. }
  586. }
  587. else
  588. {
  589. show_buffer_status(0);
  590. }
  591.  
  592. dma_transfer_in_progress = process_frame();
  593.  
  594. /* try a sync beep */
  595. if (sound_rec == 2 && frame_count == 1)
  596. beep();
  597.  
  598. return 0;
  599. }
  600.  
  601. static char* get_next_raw_movie_file_name()
  602. {
  603. static char filename[100];
  604.  
  605. for (int number = 0 ; number < 10000000; number++)
  606. {
  607. snprintf(filename, sizeof(filename), "%s/M%07d.RAW", get_dcim_dir(), number);
  608. uint32_t size;
  609. if( FIO_GetFileSize( filename, &size ) != 0 ) break;
  610. if (size == 0) break;
  611. }
  612.  
  613. return filename;
  614. }
  615.  
  616. static char* get_wav_file_name(char* movie_filename)
  617. {
  618. /* same name as movie, but with wav extension */
  619. static char wavfile[100];
  620. snprintf(wavfile, sizeof(wavfile), movie_filename);
  621. int len = strlen(wavfile);
  622. wavfile[len-4] = '.';
  623. wavfile[len-3] = 'W';
  624. wavfile[len-2] = 'A';
  625. wavfile[len-1] = 'V';
  626. /* prefer SD card for saving WAVs (should be faster on 5D3) */
  627. if (is_dir("B:/")) wavfile[0] = 'B';
  628. return wavfile;
  629. }
  630.  
  631. static void raw_video_rec_task()
  632. {
  633. /* init stuff */
  634. raw_recording_state = RAW_PREPARING;
  635. buffer_count = 0;
  636. capturing_buffer_index = 0;
  637. saving_buffer_index = 0;
  638. capture_offset = 0;
  639. frame_count = 0;
  640. frame_skips = 0;
  641. frame_offset_delta_x = 0;
  642. frame_offset_delta_y = 0;
  643.  
  644. /* create output file */
  645. movie_filename = get_next_raw_movie_file_name();
  646. FILE* f = FIO_CreateFileEx(movie_filename);
  647. if (f == INVALID_PTR)
  648. {
  649. bmp_printf( FONT_MED, 30, 50, "File create error");
  650. goto cleanup;
  651. }
  652.  
  653. /* detect raw parameters (geometry, black level etc) */
  654. if (!raw_update_params())
  655. {
  656. bmp_printf( FONT_MED, 30, 50, "Raw detect error");
  657. goto cleanup;
  658. }
  659.  
  660. /* allocate memory */
  661. if (!setup_buffers())
  662. {
  663. bmp_printf( FONT_MED, 30, 50, "Memory error");
  664. goto cleanup;
  665. }
  666.  
  667. if (sound_rec == 1)
  668. {
  669. char* wavfile = get_wav_file_name(movie_filename);
  670. bmp_printf( FONT_MED, 30, 90, "Sound: %s%s", wavfile + 17, wavfile[0] == 'B' && movie_filename[0] == 'A' ? " on SD card" : "");
  671. bmp_printf( FONT_MED, 30, 90, "%s", wavfile);
  672. WAV_StartRecord(wavfile);
  673. }
  674.  
  675. /* this will enable the vsync CBR and the other task(s) */
  676. raw_recording_state = RAW_RECORDING;
  677.  
  678. int t0 = 0;
  679. //~ uint32_t written = 0;
  680. uint64_t written = 0;
  681. //~ uint32_t writtenL = 0;
  682. /* fake recording status, to integrate with other ml stuff (e.g. hdr video */
  683. recording = -1;
  684.  
  685. /* main recording loop */
  686. while (RAW_IS_RECORDING && lv)
  687. {
  688. if (stop_on_buffer_overflow && frame_skips)
  689. goto abort;
  690.  
  691. /* do we have any buffers completely filled with data, that we can save? */
  692. if (saving_buffer_index != capturing_buffer_index)
  693. {
  694. if (!t0) t0 = get_ms_clock_value();
  695. void* ptr = buffers[saving_buffer_index].ptr;
  696. int size_used = buffers[saving_buffer_index].used;
  697. buffer_size_compressed = (size_used * 12) / 14;
  698. raw14_to_raw12(ptr, size_used);
  699. int r = FIO_WriteFile(f, ptr, buffer_size_compressed);
  700. if (r != buffer_size_compressed) goto abort;
  701. written += buffer_size_compressed;
  702. saving_buffer_index = mod(saving_buffer_index + 1, buffer_count);
  703. }
  704.  
  705. /* how fast are we writing? does this speed match our benchmarks? */
  706. if (t0)
  707. {
  708. int t1 = get_ms_clock_value();
  709. int speed = (written / 1024) * 10 / (t1 - t0) * 1000 / 1024; // MB/s x10
  710. measured_write_speed = speed;
  711. if (liveview_display_idle()) bmp_printf( FONT_MED, 30, 90,
  712. "%s: %d MB, %d.%d MB/s ",
  713. movie_filename + 17, /* skip A:/DCIM/100CANON/ */
  714. ((uint32_t)(written / 1024 / 1024)),
  715. speed/10, speed%10
  716. );
  717. }
  718.  
  719. msleep(20);
  720.  
  721. /* 4GB limit? not yet handled */
  722. /* leave some margin to be able to flush everything, just in case */
  723. //~ if (written > 0xFFFFFFFFu - ((uint32_t)buffer_count + 1) * 32*1024*1024)
  724. //~ if (written > 0x3FFFFFFFFu - ((uint32_t)buffer_count + 1) * 32*1024*1024)
  725. if(0)
  726. {
  727. abort:
  728. bmp_printf( FONT_MED, 30, 90,
  729. "Movie recording stopped automagically"
  730. );
  731. break;
  732. }
  733.  
  734. }
  735.  
  736. /* done, this will stop the vsync CBR and the copying task */
  737. raw_recording_state = RAW_FINISHING;
  738.  
  739. /* wait until the other tasks calm down */
  740. msleep(1000);
  741.  
  742. recording = 0;
  743.  
  744. if (sound_rec == 1)
  745. {
  746. WAV_StopRecord();
  747. }
  748.  
  749. bmp_printf( FONT_MED, 30, 70,
  750. "Frames captured: %d ",
  751. frame_count - 1
  752. );
  753.  
  754. /* write remaining frames */
  755. while (saving_buffer_index != capturing_buffer_index)
  756. {
  757. if (!t0) t0 = get_ms_clock_value();
  758. written += FIO_WriteFile(f, buffers[saving_buffer_index].ptr, buffers[saving_buffer_index].used);
  759. saving_buffer_index = mod(saving_buffer_index + 1, buffer_count);
  760. }
  761. written += FIO_WriteFile(f, buffers[capturing_buffer_index].ptr, capture_offset);
  762.  
  763. /* write metadata */
  764. int footer_ok = lv_rec_save_footer(f);
  765. if (!footer_ok)
  766. {
  767. bmp_printf( FONT_MED, 30, 110,
  768. "Footer save error"
  769. );
  770. beep();
  771. msleep(2000);
  772. }
  773.  
  774. cleanup:
  775. if (f) FIO_CloseFile(f);
  776. free_buffers();
  777. redraw();
  778. raw_recording_state = RAW_IDLE;
  779. }
  780.  
  781. static MENU_SELECT_FUNC(raw_start_stop)
  782. {
  783. if (!RAW_IS_IDLE)
  784. {
  785. raw_recording_state = RAW_FINISHING;
  786. }
  787. else
  788. {
  789. raw_recording_state = RAW_PREPARING;
  790. gui_stop_menu();
  791. task_create("raw_rec_task", 0x19, 0x1000, raw_video_rec_task, (void*)0);
  792. }
  793. }
  794.  
  795. static MENU_SELECT_FUNC(raw_video_toggle)
  796. {
  797. if (!RAW_IS_IDLE) return;
  798.  
  799. raw_video_enabled = !raw_video_enabled;
  800.  
  801. /* toggle the lv_save_raw flag from raw.c */
  802. if (raw_video_enabled)
  803. raw_lv_request();
  804. else
  805. raw_lv_release();
  806. msleep(50);
  807. }
  808.  
  809. static int raw_playing = 0;
  810. static void raw_video_playback_task()
  811. {
  812. set_lv_zoom(1);
  813. PauseLiveView();
  814.  
  815. int resx = get_res_x();
  816. int resy = get_res_y();
  817. raw_set_geometry(resx, resy, 0, 0, 0, 0);
  818.  
  819. FILE* f = INVALID_PTR;
  820. void* buf = shoot_malloc(raw_info.frame_size);
  821. if (!buf)
  822. goto cleanup;
  823.  
  824. bmp_printf(FONT_MED, 0, 0, "file '%s' ", movie_filename);
  825. msleep(100);
  826.  
  827. if (!movie_filename)
  828. goto cleanup;
  829.  
  830. f = FIO_Open( movie_filename, O_RDONLY | O_SYNC );
  831. if( f == INVALID_PTR )
  832. goto cleanup;
  833.  
  834. clrscr();
  835. struct vram_info * lv_vram = get_yuv422_vram();
  836. memset(lv_vram->vram, 0, lv_vram->width * lv_vram->pitch);
  837. for (int i = 0; i < frame_count-1; i++)
  838. {
  839. bmp_printf(FONT_MED, 0, os.y_max - 20, "%d/%d", i+1, frame_count-1);
  840. bmp_printf(FONT_MED, os.x_max - font_med.width*9, os.y_max - font_med.height, "%dx%d", resx, resy);
  841. int r = FIO_ReadFile(f, buf, raw_info.frame_size);
  842. if (r != raw_info.frame_size)
  843. break;
  844.  
  845. if (get_halfshutter_pressed())
  846. break;
  847.  
  848. raw_info.buffer = buf;
  849. raw_set_geometry(resx, resy, 0, 0, 0, 0);
  850. raw_force_aspect_ratio_1to1();
  851. raw_preview_fast();
  852. }
  853.  
  854. cleanup:
  855. if (f != INVALID_PTR) FIO_CloseFile(f);
  856. if (buf) shoot_free(buf);
  857. raw_playing = 0;
  858. ResumeLiveView();
  859. }
  860.  
  861. static MENU_SELECT_FUNC(raw_playback_start)
  862. {
  863. if (!raw_playing && RAW_IS_IDLE)
  864. {
  865. if (!movie_filename)
  866. {
  867. bmp_printf(FONT_MED, 20, 50, "Please record a movie first.");
  868. return;
  869. }
  870. raw_playing = 1;
  871. gui_stop_menu();
  872. task_create("raw_rec_task", 0x1e, 0x1000, raw_video_playback_task, (void*)0);
  873. }
  874. }
  875.  
  876. static MENU_UPDATE_FUNC(raw_playback_update)
  877. {
  878. if (movie_filename)
  879. MENU_SET_VALUE(movie_filename + 17);
  880. else
  881. MENU_SET_WARNING(MENU_WARN_NOT_WORKING, "Record a video clip first.");
  882. }
  883.  
  884. static struct menu_entry raw_video_menu[] =
  885. {
  886. {
  887. .name = "RAW video",
  888. .priv = &raw_video_enabled,
  889. .select = raw_video_toggle,
  890. .max = 1,
  891. .update = raw_main_update,
  892. .submenu_width = 710,
  893. .depends_on = DEP_LIVEVIEW,
  894. .help = "Record 14-bit RAW video. Press LiveView to start.",
  895. .children = (struct menu_entry[]) {
  896. {
  897. .name = "Width",
  898. .priv = &resolution_index_x,
  899. .max = COUNT(resolution_presets_x) - 1,
  900. .update = resolution_update,
  901. .choices = RESOLUTION_CHOICES_X,
  902. },
  903. {
  904. .name = "Height",
  905. .priv = &resolution_index_y,
  906. .max = COUNT(resolution_presets_y) - 1,
  907. .update = resolution_update,
  908. .choices = RESOLUTION_CHOICES_Y,
  909. },
  910. {
  911. .name = "Sound",
  912. .priv = &sound_rec,
  913. .max = 2,
  914. .choices = CHOICES("OFF", "Separate WAV", "Sync beep"),
  915. .help = "Sound recording options.",
  916. },
  917. {
  918. .name = "Frame skipping",
  919. .priv = &stop_on_buffer_overflow,
  920. .max = 1,
  921. .choices = CHOICES("Allow", "OFF"),
  922. .icon_type = IT_BOOL_NEG,
  923. .help = "Enable if you don't mind skipping frames (for slow cards).",
  924. },
  925. {
  926. .name = "Panning mode",
  927. .priv = &panning_enabled,
  928. .max = 1,
  929. .help = "Smooth panning of the recording window (software dolly).",
  930. .help2 = "Use direction keys to move the window.",
  931. },
  932. {
  933. .name = "HaCKeD mode",
  934. .priv = &hacked_mode,
  935. .max = 1,
  936. .help = "Some extreme hacks for squeezing a little more speed.",
  937. .help2 = "Your camera will explode.",
  938. },
  939. {
  940. .name = "Playback",
  941. .select = raw_playback_start,
  942. .update = raw_playback_update,
  943. .icon_type = IT_ACTION,
  944. .help = "Play back the last raw video clip.",
  945. },
  946. MENU_EOL,
  947. },
  948. }
  949. };
  950.  
  951.  
  952. static unsigned int raw_rec_keypress_cbr(unsigned int key)
  953. {
  954. if (!raw_video_enabled)
  955. return 1;
  956.  
  957. /* keys are only hooked in LiveView */
  958. if (!liveview_display_idle())
  959. return 1;
  960.  
  961. /* start/stop recording with the LiveView key */
  962. if(key == MODULE_KEY_LV || key == MODULE_KEY_REC)
  963. {
  964. switch(raw_recording_state)
  965. {
  966. case RAW_IDLE:
  967. case RAW_RECORDING:
  968. raw_start_stop(0,0);
  969. break;
  970. }
  971. return 0;
  972. }
  973.  
  974. /* panning (with arrow keys) */
  975. if (panning_enabled)
  976. {
  977. switch (key)
  978. {
  979. case MODULE_KEY_PRESS_LEFT:
  980. frame_offset_delta_x -= 8;
  981. return 0;
  982. case MODULE_KEY_PRESS_RIGHT:
  983. frame_offset_delta_x += 8;
  984. return 0;
  985. case MODULE_KEY_PRESS_UP:
  986. frame_offset_delta_y -= 2;
  987. return 0;
  988. case MODULE_KEY_PRESS_DOWN:
  989. frame_offset_delta_y += 2;
  990. return 0;
  991. case MODULE_KEY_PRESS_DOWN_LEFT:
  992. frame_offset_delta_y += 2;
  993. frame_offset_delta_x -= 8;
  994. return 0;
  995. case MODULE_KEY_PRESS_DOWN_RIGHT:
  996. frame_offset_delta_y += 2;
  997. frame_offset_delta_x += 8;
  998. return 0;
  999. case MODULE_KEY_PRESS_UP_LEFT:
  1000. frame_offset_delta_y -= 2;
  1001. frame_offset_delta_x -= 8;
  1002. return 0;
  1003. case MODULE_KEY_PRESS_UP_RIGHT:
  1004. frame_offset_delta_y -= 2;
  1005. frame_offset_delta_x += 8;
  1006. return 0;
  1007. case MODULE_KEY_JOY_CENTER:
  1008. /* first click stop the motion, second click center the window */
  1009. if (frame_offset_delta_x || frame_offset_delta_y)
  1010. {
  1011. frame_offset_delta_y = 0;
  1012. frame_offset_delta_x = 0;
  1013. }
  1014. else
  1015. {
  1016. frame_offset_y = 0;
  1017. frame_offset_x = 0;
  1018. }
  1019. }
  1020. }
  1021.  
  1022. return 1;
  1023. }
  1024.  
  1025. static unsigned int raw_rec_should_preview(unsigned int ctx)
  1026. {
  1027. /* enable preview in x5 mode, since framing doesn't match */
  1028. /* keep x10 mode unaltered, for focusing */
  1029. return raw_video_enabled && lv_dispsize == 5;
  1030. }
  1031.  
  1032. static unsigned int raw_rec_update_preview(unsigned int ctx)
  1033. {
  1034. if (!raw_rec_should_preview(0))
  1035. return 0;
  1036. struct display_filter_buffers * buffers = (struct display_filter_buffers *) ctx;
  1037. raw_force_aspect_ratio_1to1();
  1038. raw_preview_fast_ex(raw_info.buffer, buffers->dst_buf, BM2LV_Y(os.y0), BM2LV_Y(os.y_max), !get_halfshutter_pressed());
  1039. if (!RAW_IS_IDLE) msleep(500); /* be gentle with the CPU, save it for recording */
  1040. return 1;
  1041. }
  1042.  
  1043. static unsigned int raw_rec_init()
  1044. {
  1045. menu_add("Movie", raw_video_menu, COUNT(raw_video_menu));
  1046. return 0;
  1047. }
  1048.  
  1049. static unsigned int raw_rec_deinit()
  1050. {
  1051. return 0;
  1052. }
  1053.  
  1054. MODULE_INFO_START()
  1055. MODULE_INIT(raw_rec_init)
  1056. MODULE_DEINIT(raw_rec_deinit)
  1057. MODULE_INFO_END()
  1058.  
  1059. MODULE_STRINGS_START()
  1060. MODULE_STRING("Description", "14-bit RAW video")
  1061. MODULE_STRING("License", "GPL")
  1062. MODULE_STRING("Author", "a1ex")
  1063. MODULE_STRING("Credits", "g3gg0 (lv_rec)")
  1064. MODULE_STRINGS_END()
  1065.  
  1066. MODULE_CBRS_START()
  1067. MODULE_CBR(CBR_VSYNC, raw_rec_vsync_cbr, 0)
  1068. MODULE_CBR(CBR_KEYPRESS, raw_rec_keypress_cbr, 0)
  1069. MODULE_CBR(CBR_SHOOT_TASK, raw_rec_polling_cbr, 0)
  1070. MODULE_CBR(CBR_DISPLAY_FILTER_ENABLED, raw_rec_should_preview, 0)
  1071. MODULE_CBR(CBR_DISPLAY_FILTER_UPDATE, raw_rec_update_preview, 0)
  1072. MODULE_CBRS_END()
RAW Paste Data