SHARE
TWEET

Raw Rec

a guest May 22nd, 2013 244 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
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top