PageRenderTime 27ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ripping.c

http://sacd-ripper.googlecode.com/
C | 347 lines | 274 code | 49 blank | 24 comment | 45 complexity | c1ebb248a250e438e45a069fb514f8f5 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, GPL-3.0
  1. /**
  2. * SACD Ripper - http://code.google.com/p/sacd-ripper/
  3. *
  4. * Copyright (c) 2010-2011 by respective authors.
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. *
  20. */
  21. #include <stdio.h>
  22. #include <string.h>
  23. #include <sysutil/sysutil.h>
  24. #include <sysutil/msg.h>
  25. #include <sys/systime.h>
  26. #include <sys/file.h>
  27. #include <sys/atomic.h>
  28. #include <sys/stat.h>
  29. #include <errno.h>
  30. #include <utils.h>
  31. #include <fileutils.h>
  32. #include <logging.h>
  33. #include <sacd_reader.h>
  34. #include <scarletbook_read.h>
  35. #include <scarletbook_output.h>
  36. #include <scarletbook_helpers.h>
  37. #include <sac_accessor.h>
  38. #include "ripping.h"
  39. #include "output_device.h"
  40. #include "exit_handler.h"
  41. #include "rsxutil.h"
  42. static int dialog_action = 0;
  43. static atomic_t stats_total_sectors;
  44. static atomic_t stats_total_sectors_processed;
  45. static atomic_t stats_current_file_total_sectors; // total amount of block to process
  46. static atomic_t stats_current_file_sectors_processed;
  47. static atomic_t stats_current_track;
  48. static atomic_t stats_total_tracks;
  49. static void dialog_handler(msgButton button, void *user_data)
  50. {
  51. switch (button)
  52. {
  53. case MSG_DIALOG_BTN_OK:
  54. dialog_action = 1;
  55. break;
  56. case MSG_DIALOG_BTN_NO:
  57. case MSG_DIALOG_BTN_ESCAPE:
  58. dialog_action = 2;
  59. break;
  60. case MSG_DIALOG_BTN_NONE:
  61. dialog_action = -1;
  62. break;
  63. default:
  64. break;
  65. }
  66. }
  67. static int check_disc_space(sacd_reader_t *sacd_reader, scarletbook_handle_t *handle, int ripping_flags)
  68. {
  69. uint64_t needed_sectors = 0;
  70. if (ripping_flags & RIP_ISO)
  71. {
  72. needed_sectors = sacd_get_total_sectors(sacd_reader);
  73. }
  74. else if (has_two_channel(handle) && ripping_flags & RIP_2CH)
  75. {
  76. needed_sectors = get_two_channel(handle)->track_end - get_two_channel(handle)->track_start;
  77. }
  78. else if (has_both_channels(handle) && ripping_flags & RIP_MCH)
  79. {
  80. needed_sectors = get_multi_channel(handle)->track_end - get_multi_channel(handle)->track_start;
  81. }
  82. if (needed_sectors > output_device_sectors)
  83. {
  84. msgType dialog_type;
  85. char *message = (char *) malloc(512);
  86. LOG(lm_main, LOG_ERROR, ("no enough disc space on %s (%llu), needs: %llu", output_device, output_device_sectors, needed_sectors));
  87. snprintf(message, 512, "Ripping aborted.\nYou do not have enough disc space on [%s (%.2fGB available)].", output_device, output_device_space);
  88. dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON);
  89. dialog_action = 0;
  90. msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL);
  91. while (!user_requested_exit() && !dialog_action)
  92. {
  93. sysUtilCheckCallback();
  94. flip();
  95. }
  96. msgDialogAbort();
  97. free(message);
  98. return 0;
  99. }
  100. return 1;
  101. }
  102. static void handle_status_update_track_callback(char *filename, int current_track, int total_tracks)
  103. {
  104. sysAtomicSet(&stats_current_track, current_track);
  105. sysAtomicSet(&stats_total_tracks, total_tracks);
  106. }
  107. static void handle_status_update_progress_callback(uint32_t total_sectors, uint32_t total_sectors_processed,
  108. uint32_t current_file_total_sectors, uint32_t current_file_sectors_processed)
  109. {
  110. sysAtomicSet(&stats_total_sectors, total_sectors);
  111. sysAtomicSet(&stats_total_sectors_processed, total_sectors_processed);
  112. sysAtomicSet(&stats_current_file_total_sectors, current_file_total_sectors);
  113. sysAtomicSet(&stats_current_file_sectors_processed, current_file_sectors_processed);
  114. }
  115. static int safe_fwprintf(FILE *stream, const wchar_t *format, ...)
  116. {
  117. return 0;
  118. }
  119. int start_ripping_gui(int ripping_flags)
  120. {
  121. char *albumdir, *musicfilename, *file_path = 0;
  122. sacd_reader_t *sacd_reader;
  123. scarletbook_handle_t *handle;
  124. scarletbook_output_t *output;
  125. msgType dialog_type;
  126. int area_idx, i, ret;
  127. uint32_t prev_upper_progress = 0;
  128. uint32_t prev_lower_progress = 0;
  129. uint32_t delta;
  130. int prev_current_track = 0;
  131. uint32_t prev_stats_total_sectors_processed = 0;
  132. uint32_t prev_stats_current_file_sectors_processed = 0;
  133. uint64_t tb_start, tb_freq;
  134. uint64_t tmp_total_ripping_sectors = 0;
  135. char progress_message[64];
  136. sysAtomicSet(&stats_total_sectors, 0);
  137. sysAtomicSet(&stats_total_sectors_processed, 0);
  138. sysAtomicSet(&stats_current_file_total_sectors, 0);
  139. sysAtomicSet(&stats_current_file_sectors_processed, 0);
  140. sysAtomicSet(&stats_current_track, 0);
  141. sysAtomicSet(&stats_total_tracks, 0);
  142. sacd_reader = sacd_open("/dev_bdvd");
  143. if (sacd_reader)
  144. {
  145. handle = scarletbook_open(sacd_reader, 0);
  146. if (check_disc_space(sacd_reader, handle, ripping_flags))
  147. {
  148. ret = sacd_authenticate(sacd_reader);
  149. if (ret != 0)
  150. {
  151. LOG(lm_main, LOG_ERROR, ("authentication failed: %x", ret));
  152. }
  153. // select the channel area
  154. area_idx = ((has_multi_channel(handle) && ripping_flags & RIP_MCH) || !has_two_channel(handle)) ? handle->mulch_area_idx : handle->twoch_area_idx;
  155. albumdir = get_album_dir(handle);
  156. output = scarletbook_output_create(handle, handle_status_update_track_callback, handle_status_update_progress_callback, safe_fwprintf);
  157. if (ripping_flags & RIP_ISO)
  158. {
  159. #define FAT32_SECTOR_LIMIT 2090000
  160. uint32_t total_sectors = sacd_get_total_sectors(sacd_reader);
  161. uint32_t sector_size = FAT32_SECTOR_LIMIT;
  162. uint32_t sector_offset = 0;
  163. if (total_sectors > FAT32_SECTOR_LIMIT)
  164. {
  165. musicfilename = (char *) malloc(512);
  166. file_path = make_filename(output_device, 0, albumdir, "iso");
  167. for (i = 1; total_sectors != 0; i++)
  168. {
  169. sector_size = min(total_sectors, FAT32_SECTOR_LIMIT);
  170. snprintf(musicfilename, 512, "%s.%03d", file_path, i);
  171. scarletbook_output_enqueue_raw_sectors(output, sector_offset, sector_size, musicfilename, "iso");
  172. sector_offset += sector_size;
  173. total_sectors -= sector_size;
  174. }
  175. free(file_path);
  176. free(musicfilename);
  177. }
  178. else
  179. {
  180. file_path = make_filename(output_device, 0, albumdir, "iso");
  181. scarletbook_output_enqueue_raw_sectors(output, 0, total_sectors, file_path, "iso");
  182. free(file_path);
  183. }
  184. tmp_total_ripping_sectors = sacd_get_total_sectors(sacd_reader);
  185. }
  186. else
  187. {
  188. // do not overwrite previous dump
  189. get_unique_dir(output_device, &albumdir);
  190. // fill the queue with items to rip
  191. for (i = 0; i < handle->area[area_idx].area_toc->track_count; i++)
  192. {
  193. musicfilename = get_music_filename(handle, area_idx, i);
  194. if (ripping_flags & RIP_DSF)
  195. {
  196. file_path = make_filename(output_device, albumdir, musicfilename, "dsf");
  197. scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsf",
  198. 1 /* always decode to DSD */);
  199. }
  200. else if (ripping_flags & RIP_DSDIFF)
  201. {
  202. file_path = make_filename(output_device, albumdir, musicfilename, "dff");
  203. scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsdiff",
  204. ((ripping_flags & RIP_2CH_DST || ripping_flags & RIP_MCH_DST) ? 0 : 1));
  205. }
  206. tmp_total_ripping_sectors += handle->area[area_idx].area_tracklist_offset->track_length_lsn[i];
  207. free(musicfilename);
  208. free(file_path);
  209. }
  210. file_path = make_filename(output_device, albumdir, 0, 0);
  211. LOG(lm_main, LOG_NOTICE, ("setting output folder to: %s", file_path));
  212. recursive_mkdir(file_path, 0777);
  213. free(file_path);
  214. }
  215. scarletbook_output_start(output);
  216. tb_freq = sysGetTimebaseFrequency();
  217. tb_start = __gettime();
  218. {
  219. char *message = (char *) malloc(512);
  220. file_path = make_filename(output_device, albumdir, 0, 0);
  221. snprintf(message, 512, "Title: %s\nOutput: %s\nFormat: %s\nSize: %.2fGB\nArea: %s\nEncoding: %s",
  222. substr(albumdir, 0, 100),
  223. file_path,
  224. (ripping_flags & RIP_DSDIFF ? "DSDIFF" : (ripping_flags & RIP_DSF ? "DSF" : "ISO")),
  225. ((double) ((tmp_total_ripping_sectors * SACD_LSN_SIZE) / 1073741824.00)),
  226. (ripping_flags & RIP_2CH ? "2ch" : "mch"),
  227. (ripping_flags & RIP_2CH_DST || ripping_flags & RIP_MCH_DST ? "DST" : (ripping_flags & RIP_ISO ? "DECRYPTED" : "DSD"))
  228. );
  229. free(file_path);
  230. dialog_action = 0;
  231. dialog_type = MSG_DIALOG_MUTE_ON | MSG_DIALOG_DOUBLE_PROGRESSBAR;
  232. msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL);
  233. while (!user_requested_exit() && dialog_action == 0 && scarletbook_output_is_busy(output))
  234. {
  235. uint32_t tmp_stats_total_sectors_processed = sysAtomicRead(&stats_total_sectors_processed);
  236. uint32_t tmp_stats_total_sectors = sysAtomicRead(&stats_total_sectors);
  237. uint32_t tmp_stats_current_file_sectors_processed = sysAtomicRead(&stats_current_file_sectors_processed);
  238. uint32_t tmp_stats_current_file_total_sectors = sysAtomicRead(&stats_current_file_total_sectors);
  239. int tmp_current_track = sysAtomicRead(&stats_current_track);
  240. if (tmp_current_track != 0 && tmp_current_track != prev_current_track)
  241. {
  242. memset(progress_message, 0, 64);
  243. musicfilename = get_music_filename(handle, area_idx, tmp_current_track - 1);
  244. // HACK: substr is not thread safe, but it's only used in this thread..
  245. snprintf(progress_message, 63, "Track (%d/%d): [%s...]", tmp_current_track, sysAtomicRead(&stats_total_tracks), substr(musicfilename, 0, 40));
  246. free(musicfilename);
  247. msgDialogProgressBarReset(MSG_PROGRESSBAR_INDEX0);
  248. msgDialogProgressBarSetMsg(MSG_PROGRESSBAR_INDEX1, progress_message);
  249. prev_upper_progress = 0;
  250. prev_stats_current_file_sectors_processed = 0;
  251. prev_current_track = tmp_current_track;
  252. }
  253. if (tmp_stats_total_sectors != 0 && prev_stats_total_sectors_processed != tmp_stats_total_sectors_processed)
  254. {
  255. delta = (tmp_stats_current_file_sectors_processed + (tmp_stats_current_file_sectors_processed - prev_stats_current_file_sectors_processed)) * 100 / tmp_stats_current_file_total_sectors - prev_upper_progress;
  256. prev_upper_progress += delta;
  257. msgDialogProgressBarInc(MSG_PROGRESSBAR_INDEX0, delta);
  258. delta = (tmp_stats_total_sectors_processed + (tmp_stats_total_sectors_processed - prev_stats_total_sectors_processed)) * 100 / tmp_stats_total_sectors - prev_lower_progress;
  259. prev_lower_progress += delta;
  260. msgDialogProgressBarInc(MSG_PROGRESSBAR_INDEX1, delta);
  261. snprintf(progress_message, 64, "Ripping %.1fMB/%.1fMB at %.2fMB/sec",
  262. ((float)(tmp_stats_current_file_sectors_processed * SACD_LSN_SIZE) / 1048576.00),
  263. ((float)(tmp_stats_current_file_total_sectors * SACD_LSN_SIZE) / 1048576.00),
  264. (float)((float) tmp_stats_total_sectors_processed * SACD_LSN_SIZE / 1048576.00) / (float)((__gettime() - tb_start) / (float)(tb_freq)));
  265. msgDialogProgressBarSetMsg(MSG_PROGRESSBAR_INDEX0, progress_message);
  266. prev_stats_total_sectors_processed = tmp_stats_total_sectors_processed;
  267. prev_stats_current_file_sectors_processed = tmp_stats_current_file_sectors_processed;
  268. }
  269. sysUtilCheckCallback();
  270. flip();
  271. }
  272. msgDialogAbort();
  273. free(message);
  274. }
  275. free(albumdir);
  276. scarletbook_output_destroy(output);
  277. }
  278. scarletbook_close(handle);
  279. }
  280. sacd_close(sacd_reader);
  281. if (user_requested_exit())
  282. {
  283. return 0;
  284. }
  285. else if (1)
  286. {
  287. dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON);
  288. msgDialogOpen2(dialog_type, "ripping process completed.", dialog_handler, NULL, NULL);
  289. dialog_action = 0;
  290. while (!dialog_action && !user_requested_exit())
  291. {
  292. sysUtilCheckCallback();
  293. flip();
  294. }
  295. msgDialogAbort();
  296. }
  297. return 0;
  298. }