main.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. Copyright (C) 2014 Olivier Marty <olivier.marty.m at gmail.com>
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. */
  15. #include "parser.h"
  16. #include "time.h"
  17. #include "printer.h"
  18. #include "rich_text.h"
  19. #include "events.h"
  20. #include <stdlib.h>
  21. #include <unistd.h>
  22. #include <string.h>
  23. enum _t_state { S_RUNNING, S_PAUSED, S_STOP };
  24. typedef enum _t_state t_state;
  25. void displayUsage(char *name)
  26. {
  27. printf("Usage : %s file.srt or .sub .sub2 .vtt\n", name);
  28. printf("Options :\n");
  29. printf(" -s sec\t: skip the first x seconds\n");
  30. printf(" -d sec\t: wait x seconds before starting (default : 5)\n");
  31. printf(" -t x\t\t: time factor x1000\n");
  32. printf(" -e x\t\t: input format (srt, sub, sub2 (MicroDVD), vtt)\n");
  33. printf(" -m px\t\t: margin with the bottom of the screen\n");
  34. printf(" -p px\t\t: padding of the box\n");
  35. printf(" -g px\t\t: gap between two lines\n");
  36. printf(" -k px\t\t: gap between two subtitles\n");
  37. printf(" -f fontname\t: name of the font to use\n");
  38. printf(" -i fontname\t: name of the italic font to use\n");
  39. printf(" -b fontname\t: name of the bold font to use\n");
  40. printf(" -j fontname\t: name of the bold and italic font to use\n");
  41. printf(" -h\t\t: display this help and exit\n");
  42. }
  43. // display a message and program its end (and free) (one at a time)
  44. void display(struct printerEnv *env, struct richText *rt, int time, t_events *events)
  45. {
  46. static int id = -1;
  47. t_event e;
  48. printerHide(env, id);
  49. id--;
  50. e.type = T_HIDE;
  51. e.hide.time = timeGetRelative();
  52. e.hide.time.tv_sec += time;
  53. e.hide.id = id;
  54. e.hide.rt = rt;
  55. printerShow(env, rt, id);
  56. eventsPush(events, e);
  57. }
  58. int extension(const char *str, const char *suffix)
  59. {
  60. if(!str || !suffix)
  61. return 0;
  62. size_t lenstr = strlen(str);
  63. size_t lensuffix = strlen(suffix);
  64. if(lensuffix > lenstr)
  65. return 0;
  66. return strncmp(str + lenstr - lensuffix, suffix, lensuffix) == 0;
  67. }
  68. int main(int argc, char **argv)
  69. {
  70. int i, delay = 5, margin_bottom = 50, padding = 5, gap = 5, gap2 = 20;
  71. double factor = 1.0, shift = 0.;
  72. char *font = NULL, *font_i = NULL, *font_b = NULL, *font_bi = NULL,
  73. *format = NULL;
  74. FILE *f = NULL;
  75. t_state state = S_RUNNING;
  76. // parse arguments
  77. int c;
  78. while((c = getopt (argc, argv, "s:d:t:e:m:p:g:k:f:i:b:j:h")) != -1)
  79. switch(c)
  80. {
  81. case 's':
  82. shift = atof(optarg);
  83. break;
  84. case 'd':
  85. delay = atoi(optarg);
  86. break;
  87. case 't':
  88. factor = atoi(optarg)/1000.;
  89. break;
  90. case 'e':
  91. format = malloc(strlen(optarg)+1);
  92. strcpy(format, optarg);
  93. break;
  94. case 'm':
  95. margin_bottom = atoi(optarg);
  96. break;
  97. case 'p':
  98. padding = atoi(optarg);
  99. break;
  100. case 'g':
  101. gap = atoi(optarg);
  102. break;
  103. case 'k':
  104. gap2 = atoi(optarg);
  105. break;
  106. case 'f':
  107. font = malloc(strlen(optarg)+1);
  108. strcpy(font, optarg);
  109. break;
  110. case 'i':
  111. font_i = malloc(strlen(optarg)+1);
  112. strcpy(font_i, optarg);
  113. break;
  114. case 'b':
  115. font_b = malloc(strlen(optarg)+1);
  116. strcpy(font_b, optarg);
  117. break;
  118. case 'j':
  119. font_bi = malloc(strlen(optarg)+1);
  120. strcpy(font_bi, optarg);
  121. break;
  122. case 'h':
  123. displayUsage(argv[0]);
  124. return 0;
  125. //case '?':
  126. default:
  127. return 1;
  128. }
  129. if(optind >= argc)
  130. {
  131. fprintf(stderr, "Missing filename.\n");
  132. displayUsage(argv[0]);
  133. return 1;
  134. }
  135. f = fopen(argv[optind], "r");
  136. if(f == NULL)
  137. {
  138. perror("fopen()");
  139. exit(1);
  140. }
  141. int (*start_f)(FILE*);
  142. int (*next_f)(FILE *f, int expected, struct SubtitleLine *r);
  143. if((format == NULL && extension(argv[optind], ".srt"))
  144. || (format != NULL && !strcmp(format, "srt")))
  145. {
  146. printf("Type : srt\n");
  147. start_f = start_srt;
  148. next_f = next_srt;
  149. }
  150. else if((format == NULL && extension(argv[optind], ".sub"))
  151. || (format != NULL && !strcmp(format, "sub")))
  152. {
  153. printf("Type : sub\n");
  154. start_f = start_sub;
  155. next_f = next_sub;
  156. }
  157. else if((format == NULL && extension(argv[optind], ".sub2"))
  158. || (format != NULL && !strcmp(format, "sub2")))
  159. {
  160. printf("Type : sub2\n");
  161. start_f = start_sub2;
  162. next_f = next_sub2;
  163. }
  164. else if((format == NULL && extension(argv[optind], ".vtt"))
  165. || (format != NULL && !strcmp(format, "vtt")))
  166. {
  167. printf("Type : vtt\n");
  168. start_f = start_vtt;
  169. next_f = next_vtt;
  170. }
  171. else
  172. {
  173. fprintf(stderr, "Unknow format !\n");
  174. displayUsage(argv[0]);
  175. exit(1);
  176. }
  177. if(!start_f(f))
  178. {
  179. fprintf(stderr, "Bad header !\n");
  180. exit(1);
  181. }
  182. // open the window
  183. struct printerEnv penv = printerOpenWindow(font, font_i, font_b, font_bi);
  184. // set attributes
  185. penv.margin_bottom = margin_bottom;
  186. penv.padding = padding;
  187. penv.gap = gap;
  188. penv.gap2 = gap2;
  189. // show a counter before start the clock
  190. for(i = delay; i > 0; i--)
  191. {
  192. struct richText *rt;
  193. char t[16];
  194. sprintf(t, "<i>%d...</i>\n", i);
  195. printf("%s\n", t);
  196. rt = richTextParse(t);
  197. printerShow(&penv, rt, 0);
  198. sleep(1);
  199. printerHide(&penv, 0);
  200. richTextFree(rt);
  201. }
  202. printerRender(&penv);
  203. printf("0 !\n");
  204. timeInitialize();
  205. timeShift(-factor*shift);
  206. int id = 0;
  207. struct richText *pausert = richTextParse("<i>paused...</i>\n");
  208. t_events events = eventsInit(8);
  209. t_event event;
  210. event.type = T_SHOW;
  211. event.show.id = -1; // first
  212. while(1)
  213. {
  214. switch(state)
  215. {
  216. case S_RUNNING:
  217. switch(event.type)
  218. {
  219. case T_KEYPRESSED:
  220. switch(event.keyPressed.key)
  221. {
  222. case ' ':
  223. state = S_PAUSED;
  224. printf("paused...\n");
  225. printerShow(&penv, pausert, 0);
  226. timePause(1);
  227. break;
  228. case 65363: // right shift
  229. shift += 0.05;
  230. printf("shift : +0.05s (total : %.2fs)\n", shift);
  231. timeShift(-0.05);
  232. {
  233. char *msg = malloc(64);
  234. sprintf(msg, "<i>shift %.2fs</i>\n", shift);
  235. display(&penv, richTextParse(msg), 1, &events);
  236. }
  237. break;
  238. case 65361: // left shift
  239. shift -= 0.05;
  240. printf("shift : -0.05s (total : %.2fs)\n", shift);
  241. timeShift(-0.05);
  242. {
  243. char *msg = malloc(64);
  244. sprintf(msg, "<i>shift %.2fs</i>\n", shift);
  245. display(&penv, richTextParse(msg), 1, &events);
  246. }
  247. break;
  248. }
  249. break;
  250. case T_HIDE:
  251. printerHide(&penv, event.hide.id);
  252. printerRender(&penv);
  253. free(event.hide.rt->raw);
  254. richTextFree(event.hide.rt);
  255. printf("\n");
  256. break;
  257. case T_SHOW:
  258. if(event.hide.id >= 0)
  259. {
  260. printf("%ds\n", event.show.time.tv_sec);
  261. printf("%s", event.show.rt->raw);
  262. printerShow(&penv, event.show.rt, event.show.id);
  263. }
  264. // grab next subtitles
  265. while(1)
  266. {
  267. struct SubtitleLine sline;
  268. if(feof(f))
  269. break;
  270. id = next_f(f, id+1, &sline);
  271. sline.begin = timeFactor(sline.begin, factor);
  272. sline.end = timeFactor(sline.end, factor);
  273. if(timeInFuture(sline.end))
  274. {
  275. char *copy = NULL;
  276. struct richText *rt;
  277. copy = malloc(sizeof(char[strlen(sline.text)+1]));
  278. if(copy == NULL)
  279. {
  280. perror("malloc()");
  281. exit(1);
  282. }
  283. strcpy(copy, sline.text);
  284. rt = richTextParse(copy);
  285. // show event
  286. t_event show, hide;
  287. show.type = T_SHOW;
  288. show.show.id = id;
  289. show.show.rt = rt;
  290. show.show.time = sline.begin;
  291. // hide event
  292. hide.type = T_HIDE;
  293. hide.hide.id = id;
  294. hide.hide.rt = rt;
  295. hide.hide.time = sline.end;
  296. eventsPush(&events, show);
  297. eventsPush(&events, hide);
  298. break;
  299. }
  300. else
  301. {
  302. printf("skipped :\n");
  303. printf("%s\n", sline.text);
  304. }
  305. }
  306. break;
  307. }
  308. break;
  309. case S_PAUSED:
  310. switch(event.type)
  311. {
  312. case T_KEYPRESSED:
  313. if(event.keyPressed.key == ' ')
  314. {
  315. state = S_RUNNING;
  316. printf("end\n");
  317. printerHide(&penv, 0);
  318. printerRender(&penv);
  319. timePause(0);
  320. }
  321. break;
  322. }
  323. break;
  324. }
  325. if(eventsEmpty(events))
  326. state = S_STOP;
  327. if(state == S_STOP)
  328. break;
  329. // sleep until next event
  330. mytime next_event = eventsNextTime(events);
  331. while(1)
  332. {
  333. int value;
  334. fd_set in_fds;
  335. FD_ZERO(&in_fds);
  336. FD_SET(penv.d_fd, &in_fds);
  337. if(XPending(penv.d)) // event waiting (pselect does no see events that come
  338. // during the beginning of the program
  339. value = 1;
  340. else if(state == S_PAUSED) // blocking select
  341. value = pselect(penv.d_fd+1, &in_fds, NULL, NULL, NULL, NULL);
  342. else // timeout
  343. {
  344. struct timespec to_wait = timeDiff(next_event, timeGetRelative());
  345. if(to_wait.tv_sec < 0)
  346. {
  347. to_wait.tv_sec = 0;
  348. to_wait.tv_nsec = 0;
  349. }
  350. value = pselect(penv.d_fd+1, &in_fds, NULL, NULL, &to_wait, NULL);
  351. }
  352. if(value == -1) // TODO tester interruption par un signal : return 0 ou -1
  353. // dans les deux cas c'est foireux
  354. {
  355. perror("pselect()");
  356. exit(1);
  357. }
  358. else if(value > 0) // x event
  359. {
  360. while(XPending(penv.d))
  361. {
  362. event = manageEvent(&penv);
  363. if(event.type == T_KEYPRESSED)
  364. break;
  365. }
  366. if(event.type == T_KEYPRESSED)
  367. break;
  368. }
  369. else // deadline
  370. {
  371. event = eventsPop(&events);
  372. break;
  373. }
  374. }
  375. }
  376. richTextFree(pausert);
  377. printerCloseWindow(penv);
  378. fclose(f);
  379. return 0;
  380. }