PageRenderTime 62ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/amplayer/player/player_sub.c

https://github.com/J1nx-Hackable-Gadgets/libamplayer-m3
C | 1893 lines | 1566 code | 227 blank | 100 comment | 588 complexity | a63399465d200142c4affc0aa021c982 MD5 | raw file
Possible License(s): LGPL-3.0, CC-BY-SA-3.0, GPL-2.0, GPL-3.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. /*******************************************************************
  2. *
  3. * Copyright C 2005 by Amlogic, Inc. All Rights Reserved.
  4. *
  5. * Description:
  6. *
  7. * Author: Amlogic Software
  8. * Created: 12/22/2005 9:13PM
  9. *
  10. *******************************************************************/
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <ctype.h>
  15. #include <fcntl.h>
  16. #include <sys/types.h>
  17. #include <dirent.h>
  18. #include <sys/stat.h>
  19. #include "list.h"
  20. #include "player_sub.h"
  21. #include "player_priv.h"
  22. #define DUMP_SUB
  23. static float mpsub_position = 0;
  24. static int sub_slacktime = 20000; //20 sec
  25. static int sub_no_text_pp = 0; // 1 => do not apply text post-processing
  26. // like {\...} elimination in SSA format.
  27. /* read one line of string from data source */
  28. static char *subfile_buffer = NULL;
  29. static int buffer_size;
  30. static unsigned subfile_read;
  31. static char *internal_subf_gets(char *s, int fd)
  32. {
  33. int offset = subfile_read;
  34. int copied;
  35. if (!subfile_buffer) {
  36. subfile_buffer = (char *)MALLOC(LINE_LEN);
  37. if (subfile_buffer) {
  38. subfile_read = 0;
  39. offset = 0;
  40. buffer_size = read(fd, subfile_buffer, LINE_LEN);
  41. if (buffer_size <= 0) {
  42. return NULL;
  43. }
  44. } else {
  45. log_error("no enough memory!\n");
  46. return NULL;
  47. }
  48. }
  49. while ((offset < buffer_size) && (subfile_buffer[offset] != '\n')) {
  50. offset++;
  51. }
  52. if (offset < buffer_size) {
  53. MEMCPY(s, subfile_buffer + subfile_read, offset - subfile_read);
  54. s[offset - subfile_read ] = '\0';
  55. subfile_read = offset + 1;
  56. if (subfile_read == LINE_LEN) {
  57. subfile_read = 0;
  58. buffer_size = read(fd, subfile_buffer, LINE_LEN);
  59. }
  60. } else {
  61. if (buffer_size < LINE_LEN) {
  62. /* end of file w/o terminator "\n" */
  63. return NULL;
  64. }
  65. copied = LINE_LEN - subfile_read;
  66. MEMCPY(s, subfile_buffer + subfile_read, copied);
  67. if (buffer_size == LINE_LEN) {
  68. /* refill */
  69. buffer_size = read(fd, subfile_buffer, LINE_LEN);
  70. if (buffer_size < 0) {
  71. return NULL;
  72. }
  73. }
  74. offset = 0;
  75. while ((offset < MIN(LINE_LEN - copied, buffer_size)) && (subfile_buffer[offset] != '\n')) {
  76. offset++;
  77. }
  78. if (subfile_buffer[offset] == '\n') {
  79. subfile_read = offset + 1;
  80. if (offset) {
  81. memcpy(s + copied, subfile_buffer, offset);
  82. }
  83. s[copied + offset + 1] = '\0';
  84. } else if (buffer_size < LINE_LEN) {
  85. /* end of file w/o terminator "\n" */
  86. return NULL;
  87. } else {
  88. s[LINE_LEN + 1] = '\0';
  89. }
  90. }
  91. return s;
  92. }
  93. /* internal string manipulation functions */
  94. static int internal_eol(char p)
  95. {
  96. return (p == '\r' || p == '\n' || p == '\0');
  97. }
  98. static void internal_trail_space(char *s)
  99. {
  100. int i = 0;
  101. while (isspace(s[i])) {
  102. ++i;
  103. }
  104. if (i) {
  105. strcpy(s, s + i);
  106. }
  107. i = strlen(s) - 1;
  108. while (i > 0 && isspace(s[i])) {
  109. s[i--] = '\0';
  110. }
  111. }
  112. static char *internal_stristr(const char *haystack, const char *needle)
  113. {
  114. int len = 0;
  115. const char *p = haystack;
  116. if (!(haystack && needle)) {
  117. return NULL;
  118. }
  119. len = strlen(needle);
  120. while (*p != '\0') {
  121. if (strncasecmp(p, needle, len) == 0) {
  122. return (char*)p;
  123. }
  124. p++;
  125. }
  126. return NULL;
  127. }
  128. static char *internal_sub_readtext(char *source, char **dest)
  129. {
  130. int len = 0;
  131. char *p = source;
  132. while (!internal_eol(*p) && *p != '|') {
  133. p++, len++;
  134. }
  135. if (*dest == NULL) {
  136. *dest = (char *)MALLOC(len + 1);
  137. }
  138. if (*dest) {
  139. return ERR;
  140. }
  141. strncpy(*dest, source, len);
  142. (*dest)[len] = 0;
  143. while (*p == '\r' || *p == '\n' || *p == '|') {
  144. p++;
  145. }
  146. if (*p) {
  147. /* not-last text field */
  148. return p;
  149. } else {
  150. /* last text field */
  151. return NULL;
  152. }
  153. }
  154. static char *internal_sub_strdup(char *src)
  155. {
  156. char *ret;
  157. int len;
  158. len = strlen(src);
  159. ret = (char *)MALLOC(len + 1);
  160. if (ret) {
  161. strcpy(ret, src);
  162. }
  163. return ret;
  164. }
  165. /* subtitle file read line functions */
  166. static subtitle_t *internal_sub_read_line_sami(int fd, subtitle_t *current)
  167. {
  168. static char line[LINE_LEN + 1];
  169. static char *s = NULL, *slacktime_s;
  170. char text[LINE_LEN + 1], *p = NULL, *q;
  171. int state;
  172. current->text.lines = current->start = current->end = 0;
  173. current->text.alignment = SUB_ALIGNMENT_BOTTOMCENTER;
  174. state = 0;
  175. /* read the first line */
  176. if (!s) {
  177. s = internal_subf_gets(line, fd);
  178. if (!s) {
  179. return 0;
  180. }
  181. }
  182. do {
  183. switch (state) {
  184. case 0: /* find "START=" or "Slacktime:" */
  185. slacktime_s = internal_stristr(s, "Slacktime:");
  186. if (slacktime_s) {
  187. sub_slacktime = strtol(slacktime_s + 10, NULL, 0) / 10;
  188. }
  189. s = internal_stristr(s, "Start=");
  190. if (s) {
  191. current->start = strtol(s + 6, &s, 0) / 10;
  192. /* eat '>' */
  193. for (; *s != '>' && *s != '\0'; s++) {
  194. ;
  195. }
  196. s++;
  197. state = 1;
  198. continue;
  199. }
  200. break;
  201. case 1: /* find (optionnal) "<P", skip other TAGs */
  202. for (; *s == ' ' || *s == '\t'; s++) {
  203. ; /* strip blanks, if any */
  204. }
  205. if (*s == '\0') {
  206. break;
  207. }
  208. if (*s != '<') {
  209. state = 3;
  210. p = text;
  211. continue;
  212. } /* not a TAG */
  213. s++;
  214. if (*s == 'P' || *s == 'p') {
  215. s++;
  216. state = 2;
  217. continue;
  218. } /* found '<P' */
  219. for (; *s != '>' && *s != '\0'; s++) {
  220. ; /* skip remains of non-<P> TAG */
  221. }
  222. if (s == '\0') {
  223. break;
  224. }
  225. s++;
  226. continue;
  227. case 2: /* find ">" */
  228. s = strchr(s, '>');
  229. if (s) {
  230. s++;
  231. state = 3;
  232. p = text;
  233. continue;
  234. }
  235. break;
  236. case 3: /* get all text until '<' appears */
  237. if (*s == '\0') {
  238. break;
  239. } else if (!strncasecmp(s, "<br>", 4)) {
  240. *p = '\0';
  241. p = text;
  242. internal_trail_space(text);
  243. if (text[0] != '\0') {
  244. current->text.text[current->text.lines++] = internal_sub_strdup(text);
  245. }
  246. s += 4;
  247. } else if ((*s == '{') && !sub_no_text_pp) {
  248. state = 5;
  249. ++s;
  250. continue;
  251. } else if (*s == '<') {
  252. state = 4;
  253. } else if (!strncasecmp(s, "&nbsp;", 6)) {
  254. *p++ = ' ';
  255. s += 6;
  256. } else if (*s == '\t') {
  257. *p++ = ' ';
  258. s++;
  259. } else if (*s == '\r' || *s == '\n') {
  260. s++;
  261. } else {
  262. *p++ = *s++;
  263. }
  264. /* skip duplicated space */
  265. if (p > text + 2) if (*(p - 1) == ' ' && *(p - 2) == ' ') {
  266. p--;
  267. }
  268. continue;
  269. case 4: /* get current->end or skip <TAG> */
  270. q = internal_stristr(s, "Start=");
  271. if (q) {
  272. current->end = strtol(q + 6, &q, 0) / 10 - 1;
  273. *p = '\0';
  274. internal_trail_space(text);
  275. if (text[0] != '\0') {
  276. current->text.text[current->text.lines++] = internal_sub_strdup(text);
  277. }
  278. if (current->text.lines > 0) {
  279. state = 99;
  280. break;
  281. }
  282. state = 0;
  283. continue;
  284. }
  285. s = strchr(s, '>');
  286. if (s) {
  287. s++;
  288. state = 3;
  289. continue;
  290. }
  291. break;
  292. case 5: /* get rid of {...} text, but read the alignment code */
  293. if ((*s == '\\') && (*(s + 1) == 'a') && !sub_no_text_pp) {
  294. if (internal_stristr(s, "\\a1") != NULL) {
  295. current->text.alignment = SUB_ALIGNMENT_BOTTOMLEFT;
  296. s = s + 3;
  297. }
  298. if (internal_stristr(s, "\\a2") != NULL) {
  299. current->text.alignment = SUB_ALIGNMENT_BOTTOMCENTER;
  300. s = s + 3;
  301. } else if (internal_stristr(s, "\\a3") != NULL) {
  302. current->text.alignment = SUB_ALIGNMENT_BOTTOMRIGHT;
  303. s = s + 3;
  304. } else if ((internal_stristr(s, "\\a4") != NULL) || (internal_stristr(s, "\\a5") != NULL) || (internal_stristr(s, "\\a8") != NULL)) {
  305. current->text.alignment = SUB_ALIGNMENT_TOPLEFT;
  306. s = s + 3;
  307. } else if (internal_stristr(s, "\\a6") != NULL) {
  308. current->text.alignment = SUB_ALIGNMENT_TOPCENTER;
  309. s = s + 3;
  310. } else if (internal_stristr(s, "\\a7") != NULL) {
  311. current->text.alignment = SUB_ALIGNMENT_TOPRIGHT;
  312. s = s + 3;
  313. } else if (internal_stristr(s, "\\a9") != NULL) {
  314. current->text.alignment = SUB_ALIGNMENT_MIDDLELEFT;
  315. s = s + 3;
  316. } else if (internal_stristr(s, "\\a10") != NULL) {
  317. current->text.alignment = SUB_ALIGNMENT_MIDDLECENTER;
  318. s = s + 4;
  319. } else if (internal_stristr(s, "\\a11") != NULL) {
  320. current->text.alignment = SUB_ALIGNMENT_MIDDLERIGHT;
  321. s = s + 4;
  322. }
  323. }
  324. if (*s == '}') {
  325. state = 3;
  326. }
  327. ++s;
  328. continue;
  329. }
  330. /* read next line */
  331. s = internal_subf_gets(line, fd);
  332. if (state != 99 && !s) {
  333. if (current->start > 0) {
  334. break; // if it is the last subtitle
  335. } else {
  336. return 0;
  337. }
  338. }
  339. } while (state != 99);
  340. /* For the last subtitle */
  341. if (current->end <= 0) {
  342. current->end = current->start + sub_slacktime;
  343. *p = '\0';
  344. internal_trail_space(text);
  345. if (text[0] != '\0') {
  346. current->text.text[current->text.lines++] = internal_sub_strdup(text);
  347. }
  348. }
  349. return current;
  350. }
  351. subtitle_t *internal_sub_read_line_microdvd(int fd, subtitle_t *current)
  352. {
  353. char line[LINE_LEN + 1];
  354. char line2[LINE_LEN + 1];
  355. char *p, *next;
  356. int i;
  357. float ptsrate = (float)current->end / 960;
  358. current->end = 0;
  359. do {
  360. if (!internal_subf_gets(line, fd)) {
  361. return NULL;
  362. }
  363. } while ((sscanf(line, "{%ld}{}%[^\r\n]", &(current->start), line2) < 2) &&
  364. (sscanf(line, "{%ld}{%ld}%[^\r\n]", &(current->start), &(current->end), line2) < 3));
  365. p = line2;
  366. next = p, i = 0;
  367. while (1) {
  368. next = internal_sub_readtext(next, &(current->text.text[i]));
  369. if (!next) {
  370. break;
  371. }
  372. if (current->text.text[i] == ERR) {
  373. return ERR;
  374. }
  375. i++;
  376. if (i >= SUB_MAX_TEXT) {
  377. log_print(("Too many lines in a subtitle\n"));
  378. current->text.lines = i;
  379. return current;
  380. }
  381. }
  382. current->text.lines = ++i;
  383. current->start = current->start * ptsrate;
  384. current->end = current->end * ptsrate;
  385. return current;
  386. }
  387. subtitle_t *internal_sub_read_line_mpl2(int fd, subtitle_t *current)
  388. {
  389. char line[LINE_LEN + 1];
  390. char line2[LINE_LEN + 1];
  391. char *p, *next;
  392. int i;
  393. do {
  394. if (!internal_subf_gets(line, fd)) {
  395. return NULL;
  396. }
  397. } while ((sscanf(line, "[%ld][%ld]%[^\r\n]", &(current->start), &(current->end), line2) < 3));
  398. current->start *= 10;
  399. current->end *= 10;
  400. p = line2;
  401. next = p, i = 0;
  402. while (1) {
  403. next = internal_sub_readtext(next, &(current->text.text[i]));
  404. if (!next) {
  405. break;
  406. }
  407. if (current->text.text[i] == ERR) {
  408. return ERR;
  409. }
  410. i++;
  411. if (i >= SUB_MAX_TEXT) {
  412. log_print(("Too many lines in a subtitle\n"));
  413. current->text.lines = i;
  414. return current;
  415. }
  416. }
  417. current->text.lines = ++i;
  418. return current;
  419. }
  420. subtitle_t *internal_sub_read_line_subrip(int fd, subtitle_t *current)
  421. {
  422. char line[LINE_LEN + 1];
  423. int a1, a2, a3, a4, b1, b2, b3, b4;
  424. char *p = NULL, *q = NULL;
  425. int len;
  426. while (1) {
  427. if (!internal_subf_gets(line, fd)) {
  428. return NULL;
  429. }
  430. if (sscanf(line, "%d:%d:%d.%d,%d:%d:%d.%d",
  431. &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4) < 8) {
  432. continue;
  433. }
  434. current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4;
  435. current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4;
  436. if (!internal_subf_gets(line, fd)) {
  437. return NULL;
  438. }
  439. p = q = line;
  440. for (current->text.lines = 1; current->text.lines < SUB_MAX_TEXT; current->text.lines++) {
  441. for (q = p, len = 0; *p && *p != '\r' && *p != '\n' && *p != '|' && strncmp(p, "[br]", 4); p++, len++) {
  442. ;
  443. }
  444. current->text.text[current->text.lines - 1] = (char *)MALLOC(len + 1);
  445. if (!current->text.text[current->text.lines - 1]) {
  446. return ERR;
  447. }
  448. strncpy(current->text.text[current->text.lines - 1], q, len);
  449. current->text.text[current->text.lines - 1][len] = '\0';
  450. if (!*p || *p == '\r' || *p == '\n') {
  451. break;
  452. }
  453. if (*p == '|') {
  454. p++;
  455. } else {
  456. while (*p++ != ']') {
  457. ;
  458. }
  459. }
  460. }
  461. break;
  462. }
  463. return current;
  464. }
  465. subtitle_t *internal_sub_read_line_subviewer(int fd, subtitle_t *current)
  466. {
  467. char line[LINE_LEN + 1];
  468. int a1, a2, a3, a4, b1, b2, b3, b4;
  469. char *p = NULL;
  470. int i, len;
  471. while (!current->text.text[0]) {
  472. if (!internal_subf_gets(line, fd)) {
  473. return NULL;
  474. }
  475. if ((len = sscanf(line,
  476. "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",
  477. &a1, &a2, &a3, (char *)&i, &a4, &b1, &b2, &b3,
  478. (char *)&i, &b4)) < 10) {
  479. continue;
  480. }
  481. current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
  482. current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
  483. for (i = 0; i < SUB_MAX_TEXT;) {
  484. if (!internal_subf_gets(line, fd)) {
  485. break;
  486. }
  487. len = 0;
  488. for (p = line; *p != '\n' && *p != '\r' && *p; p++, len++) {
  489. ;
  490. }
  491. if (len) {
  492. int j = 0, skip = 0;
  493. char *curptr = current->text.text[i] = (char *)MALLOC(len + 1);
  494. if (!current->text.text[i]) {
  495. return ERR;
  496. }
  497. for (; j < len; j++) {
  498. /* let's filter html tags ::atmos */
  499. if (line[j] == '>') {
  500. skip = 0;
  501. continue;
  502. }
  503. if (line[j] == '<') {
  504. skip = 1;
  505. continue;
  506. }
  507. if (skip) {
  508. continue;
  509. }
  510. *curptr = line[j];
  511. curptr++;
  512. }
  513. *curptr = '\0';
  514. i++;
  515. } else {
  516. break;
  517. }
  518. }
  519. current->text.lines = i;
  520. }
  521. return current;
  522. }
  523. subtitle_t *internal_sub_read_line_subviewer2(int fd, subtitle_t *current)
  524. {
  525. char line[LINE_LEN + 1];
  526. int a1, a2, a3, a4;
  527. char *p = NULL;
  528. int i, len;
  529. while (!current->text.text[0]) {
  530. if (!internal_subf_gets(line, fd)) {
  531. return NULL;
  532. }
  533. if (line[0] != '{') {
  534. continue;
  535. }
  536. if ((len = sscanf(line, "{T %d:%d:%d:%d", &a1, &a2, &a3, &a4)) < 4) {
  537. continue;
  538. }
  539. current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
  540. for (i = 0; i < SUB_MAX_TEXT;) {
  541. if (!internal_subf_gets(line, fd)) {
  542. break;
  543. }
  544. if (line[0] == '}') {
  545. break;
  546. }
  547. len = 0;
  548. for (p = line; *p != '\n' && *p != '\r' && *p; ++p, ++len) {
  549. ;
  550. }
  551. if (len) {
  552. current->text.text[i] = (char *)MALLOC(len + 1);
  553. if (!current->text.text[i]) {
  554. return ERR;
  555. }
  556. strncpy(current->text.text[i], line, len);
  557. current->text.text[i][len] = '\0';
  558. ++i;
  559. } else {
  560. break;
  561. }
  562. }
  563. current->text.lines = i;
  564. }
  565. return current;
  566. }
  567. subtitle_t *internal_sub_read_line_vplayer(int fd, subtitle_t *current)
  568. {
  569. char line[LINE_LEN + 1];
  570. int a1, a2, a3;
  571. char *p = NULL, *next, separator;
  572. int i, len, plen;
  573. while (!current->text.text[0]) {
  574. if (!internal_subf_gets(line, fd)) {
  575. return NULL;
  576. }
  577. if ((len = sscanf(line, "%d:%d:%d%c%n", &a1, &a2, &a3, &separator, &plen)) < 4) {
  578. continue;
  579. }
  580. current->start = a1 * 360000 + a2 * 6000 + a3 * 100;
  581. if (!current->start) {
  582. continue;
  583. }
  584. p = &line[plen];
  585. //log_print("plen %d, p %s\n", plen, p);
  586. i = 0;
  587. if (*p != '|') {
  588. next = p;
  589. while (1) {
  590. next = internal_sub_readtext(next, &(current->text.text[i]));
  591. if (!next) {
  592. break;
  593. }
  594. if (current->text.text[i] == ERR) {
  595. return ERR;
  596. }
  597. i++;
  598. if (i >= SUB_MAX_TEXT) {
  599. log_print(("Too many lines in a subtitle\n"));
  600. current->text.lines = i;
  601. while (1) {
  602. if (!internal_subf_gets(line, fd)) {
  603. return NULL;
  604. }
  605. if ((len = sscanf(line, "%d:%d:%d%c%n", &a1, &a2, &a3, &separator, &plen)) < 4) {
  606. continue;
  607. } else {
  608. current->end = a1 * 360000 + a2 * 6000 + a3 * 100;
  609. return current;
  610. }
  611. }
  612. return current;
  613. }
  614. }
  615. current->text.lines = i;
  616. }
  617. }
  618. while (1) {
  619. if (!internal_subf_gets(line, fd)) {
  620. return NULL;
  621. }
  622. if ((len = sscanf(line, "%d:%d:%d%c%n", &a1, &a2, &a3, &separator, &plen)) < 4) {
  623. continue;
  624. } else {
  625. current->end = a1 * 360000 + a2 * 6000 + a3 * 100;
  626. return current;
  627. }
  628. }
  629. return current;
  630. }
  631. subtitle_t *internal_sub_read_line_rt(int fd, subtitle_t *current)
  632. {
  633. //TODO: This format uses quite rich (sub/super)set of xhtml
  634. // I couldn't check it since DTD is not included.
  635. // WARNING: full XML parses can be required for proper parsing
  636. char line[LINE_LEN + 1];
  637. int a1, a2, a3, a4, b1, b2, b3, b4;
  638. char *p = NULL, *next = NULL;
  639. int i, len, plen;
  640. while (!current->text.text[0]) {
  641. if (!internal_subf_gets(line, fd)) {
  642. return NULL;
  643. }
  644. //TODO: it seems that format of time is not easily determined, it may be 1:12, 1:12.0 or 0:1:12.0
  645. //to describe the same moment in time. Maybe there are even more formats in use.
  646. //if ((len=sscanf (line, "<Time Begin=\"%d:%d:%d.%d\" End=\"%d:%d:%d.%d\"",&a1,&a2,&a3,&a4,&b1,&b2,&b3,&b4)) < 8)
  647. plen = a1 = a2 = a3 = a4 = b1 = b2 = b3 = b4 = 0;
  648. if (
  649. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d.%d\" %*[Ee]nd=\"%d.%d\"%*[^<]<clear/>%n", &a3, &a4, &b3, &b4, &plen)) < 4) &&
  650. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n", &a3, &a4, &b2, &b3, &b4, &plen)) < 5) &&
  651. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n", &a2, &a3, &b2, &b3, &plen)) < 4) &&
  652. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n", &a2, &a3, &b2, &b3, &b4, &plen)) < 5) &&
  653. // ((len=sscanf (line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d\"%*[^<]<clear/>%n",&a2,&a3,&a4,&b2,&b3,&plen)) < 5) &&
  654. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\" %*[Ee]nd=\"%d:%d.%d\"%*[^<]<clear/>%n", &a2, &a3, &a4, &b2, &b3, &b4, &plen)) < 6) &&
  655. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\" %*[Ee]nd=\"%d:%d:%d.%d\"%*[^<]<clear/>%n", &a1, &a2, &a3, &a4, &b1, &b2, &b3, &b4, &plen)) < 8) &&
  656. //now try it without end time
  657. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d.%d\"%*[^<]<clear/>%n", &a3, &a4, &plen)) < 2) &&
  658. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d\"%*[^<]<clear/>%n", &a2, &a3, &plen)) < 2) &&
  659. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d.%d\"%*[^<]<clear/>%n", &a2, &a3, &a4, &plen)) < 3) &&
  660. ((len = sscanf(line, "<%*[tT]ime %*[bB]egin=\"%d:%d:%d.%d\"%*[^<]<clear/>%n", &a1, &a2, &a3, &a4, &plen)) < 4)
  661. ) {
  662. continue;
  663. }
  664. current->start = a1 * 360000 + a2 * 6000 + a3 * 100 + a4 / 10;
  665. current->end = b1 * 360000 + b2 * 6000 + b3 * 100 + b4 / 10;
  666. if (b1 == 0 && b2 == 0 && b3 == 0 && b4 == 0) {
  667. current->end = current->start + 200;
  668. }
  669. p = line;
  670. p += plen;
  671. i = 0;
  672. // TODO: I don't know what kind of convention is here for marking multiline subs, maybe <br/> like in xml?
  673. next = strstr(line, "<clear/>");
  674. if (next && strlen(next) > 8) {
  675. next += 8;
  676. i = 0;
  677. while (1) {
  678. next = internal_sub_readtext(next, &(current->text.text[i]));
  679. if (!next) {
  680. break;
  681. }
  682. if (current->text.text[i] == ERR) {
  683. return ERR;
  684. }
  685. i++;
  686. if (i >= SUB_MAX_TEXT) {
  687. log_print(("Too many lines in a subtitle\n"));
  688. current->text.lines = i;
  689. return current;
  690. }
  691. }
  692. }
  693. current->text.lines = i + 1;
  694. }
  695. return current;
  696. }
  697. subtitle_t *internal_sub_read_line_ssa(int fd, subtitle_t *current)
  698. {
  699. /*
  700. * Sub Station Alpha v4 (and v2?) scripts have 9 commas before subtitle
  701. * other Sub Station Alpha scripts have only 8 commas before subtitle
  702. * Reading the "ScriptType:" field is not reliable since many scripts appear
  703. * w/o it
  704. *
  705. * http://www.scriptclub.org is a good place to find more examples
  706. * http://www.eswat.demon.co.uk is where the SSA specs can be found
  707. */
  708. int comma;
  709. static int max_comma = 32;/* let's use 32 for the case that the */
  710. /* amount of commas increase with newer SSA versions */
  711. int hour1, min1, sec1, hunsec1,
  712. hour2, min2, sec2, hunsec2, nothing;
  713. int num;
  714. char line[LINE_LEN + 1], line3[LINE_LEN + 1], *line2;
  715. char *tmp;
  716. do {
  717. if (!internal_subf_gets(line, fd)) {
  718. return NULL;
  719. }
  720. } while ((sscanf(line, "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d,"
  721. "%[^\n\r]", &nothing,
  722. &hour1, &min1, &sec1, &hunsec1,
  723. &hour2, &min2, &sec2, &hunsec2,
  724. line3) < 9) &&
  725. (sscanf(line, "Dialogue: %d,%d:%d:%d.%d,%d:%d:%d.%d,"
  726. "%[^\n\r]", &nothing,
  727. &hour1, &min1, &sec1, &hunsec1,
  728. &hour2, &min2, &sec2, &hunsec2,
  729. line3) < 9));
  730. line2 = strchr(line3, ',');
  731. for (comma = 4; comma < max_comma; comma ++) {
  732. tmp = strchr(line2 + 1, ',');
  733. if (!tmp) {
  734. break;
  735. }
  736. if (*(++tmp) == ' ') {
  737. break;
  738. }
  739. /* a space after a comma means we're already in a sentence */
  740. line2 = tmp;
  741. }
  742. if (comma < max_comma) {
  743. max_comma = comma;
  744. }
  745. /* eliminate the trailing comma */
  746. if (*line2 == ',') {
  747. line2++;
  748. }
  749. current->text.lines = 0;
  750. num = 0;
  751. current->start = 360000 * hour1 + 6000 * min1 + 100 * sec1 + hunsec1;
  752. current->end = 360000 * hour2 + 6000 * min2 + 100 * sec2 + hunsec2;
  753. while (((tmp = strstr(line2, "\\n")) != NULL) || ((tmp = strstr(line2, "\\N")) != NULL)) {
  754. current->text.text[num] = (char *)MALLOC(tmp - line2 + 1);
  755. strncpy(current->text.text[num], line2, tmp - line2);
  756. current->text.text[num][tmp - line2] = '\0';
  757. line2 = tmp + 2;
  758. num++;
  759. current->text.lines++;
  760. if (current->text.lines >= SUB_MAX_TEXT) {
  761. return current;
  762. }
  763. }
  764. current->text.text[num] = internal_sub_strdup(line2);
  765. current->text.lines++;
  766. return current;
  767. }
  768. static void internal_sub_pp_ssa(subtitle_t *sub)
  769. {
  770. int l = sub->text.lines;
  771. char *so, *de, *start;
  772. while (l) {
  773. /* eliminate any text enclosed with {}, they are font and color settings */
  774. so = de = sub->text.text[--l];
  775. while (*so) {
  776. if (*so == '{' && so[1] == '\\') {
  777. for (start = so; *so && *so != '}'; so++) {
  778. ;
  779. }
  780. if (*so) {
  781. so++;
  782. } else {
  783. so = start;
  784. }
  785. }
  786. if (*so) {
  787. *de = *so;
  788. so++;
  789. de++;
  790. }
  791. }
  792. *de = *so;
  793. }
  794. }
  795. /*
  796. * PJS subtitles reader.
  797. * That's the "Phoenix Japanimation Society" format.
  798. * I found some of them in http://www.scriptsclub.org/ (used for anime).
  799. * The time is in tenths of second.
  800. */
  801. subtitle_t *internal_sub_read_line_pjs(int fd, subtitle_t *current)
  802. {
  803. char line[LINE_LEN + 1];
  804. char text[LINE_LEN + 1], *s, *d;
  805. if (!internal_subf_gets(line, fd)) {
  806. return NULL;
  807. }
  808. /* skip spaces */
  809. for (s = line; *s && isspace(*s); s++) {
  810. ;
  811. }
  812. /* allow empty lines at the end of the file */
  813. if (*s == 0) {
  814. return NULL;
  815. }
  816. /* get the time */
  817. if (sscanf(s, "%ld,%ld,", &(current->start), &(current->end)) < 2) {
  818. return ERR;
  819. }
  820. /* the files I have are in tenths of second */
  821. current->start *= 10;
  822. current->end *= 10;
  823. /* walk to the beggining of the string */
  824. for (; *s; s++) {
  825. if (*s == ',') {
  826. break;
  827. }
  828. }
  829. if (*s) {
  830. for (s++; *s; s++) if (*s == ',') {
  831. break;
  832. }
  833. if (*s) {
  834. s++;
  835. }
  836. }
  837. if (*s != '"') {
  838. return ERR;
  839. }
  840. /* copy the string to the text buffer */
  841. for (s++, d = text; *s && *s != '"'; s++, d++) {
  842. *d = *s;
  843. }
  844. *d = 0;
  845. current->text.text[0] = internal_sub_strdup(text);
  846. current->text.lines = 1;
  847. return current;
  848. }
  849. subtitle_t *internal_sub_read_line_mpsub(int fd, subtitle_t *current)
  850. {
  851. char line[LINE_LEN + 1];
  852. float a, b;
  853. int num = 0;
  854. char *p, *q;
  855. do {
  856. if (!internal_subf_gets(line, fd)) {
  857. return NULL;
  858. }
  859. } while (sscanf(line, "%f %f", &a, &b) != 2);
  860. mpsub_position += a * 100;
  861. current->start = (int) mpsub_position;
  862. mpsub_position += b * 100;
  863. current->end = (int) mpsub_position;
  864. while (num < SUB_MAX_TEXT) {
  865. if (!internal_subf_gets(line, fd)) {
  866. return (num == 0) ? NULL : current;
  867. }
  868. p = line;
  869. while (isspace(*p)) {
  870. p++;
  871. }
  872. if (internal_eol(*p) && num > 0) {
  873. return current;
  874. }
  875. if (internal_eol(*p)) {
  876. return NULL;
  877. }
  878. for (q = p; !internal_eol(*q); q++) {
  879. ;
  880. }
  881. *q = '\0';
  882. if (strlen(p)) {
  883. current->text.text[num] = internal_sub_strdup(p);
  884. current->text.lines = ++num;
  885. } else {
  886. return (num == 0) ? NULL : current;
  887. }
  888. }
  889. return NULL; /* we should have returned before if it's OK */
  890. }
  891. #define str2ms(s) (((s[1]-0x30)*3600*10+(s[2]-0x30)*3600+(s[4]-0x30)*60*10+(s[5]-0x30)*60+(s[7]-0x30)*10+(s[8]-0x30))*1000+(s[10]-0x30)*100+(s[11]-0x30)*10+(s[12]-0x30))
  892. SUBAPI subtitle_t *internal_divx_sub_add(subdata_t *subdata, unsigned char *data)
  893. {
  894. unsigned char *s;
  895. subtitle_t *sub = (subtitle_t *)calloc(1, sizeof(subtitle_t));
  896. if (!sub) {
  897. return NULL;
  898. }
  899. s = &data[0];
  900. sub->start = str2ms(s) * 90;
  901. s = &data[13];
  902. sub->end = str2ms(s) * 90;
  903. sub->subdata = data;
  904. //AVSchedLock();
  905. list_add_tail(&sub->list, &subdata->list);
  906. subdata->sub_num++;
  907. //AVSchedUnlock();
  908. return sub;
  909. }
  910. SUBAPI void internal_divx_sub_delete(subdata_t *subdata, int pts)
  911. {
  912. list_t *entry;
  913. entry = subdata->list.next;
  914. while (entry != &subdata->list) {
  915. subtitle_t *subp = list_entry(entry, subtitle_t, list);
  916. if (subp->start < pts) {
  917. if (subp->subdata) {
  918. FREE(subp->subdata);
  919. }
  920. //AVSchedLock();
  921. list_del(&subp->list);
  922. subdata->sub_num--;
  923. //AVSchedUnlock();
  924. entry = entry->next;
  925. FREE(subp);
  926. } else {
  927. break;
  928. }
  929. }
  930. }
  931. SUBAPI void internal_divx_sub_flush(subdata_t *subdata)
  932. {
  933. list_t *entry;
  934. if (subdata->sub_format != SUB_DIVX) {
  935. return;
  936. }
  937. entry = subdata->list.next;
  938. while (entry != &subdata->list) {
  939. subtitle_t *subp = list_entry(entry, subtitle_t, list);
  940. if (subp->subdata) {
  941. FREE(subp->subdata);
  942. }
  943. list_del(&subp->list);
  944. entry = entry->next;
  945. FREE(subp);
  946. }
  947. subdata->sub_num = 0;
  948. }
  949. static subtitle_t *previous_aqt_sub;
  950. subtitle_t *internal_sub_read_line_aqt(int fd, subtitle_t *current)
  951. {
  952. char line[LINE_LEN + 1];
  953. char *next;
  954. int i;
  955. while (1) {
  956. // try to locate next subtitle
  957. if (!internal_subf_gets(line, fd)) {
  958. return NULL;
  959. }
  960. if (!(sscanf(line, "-->> %ld", &(current->start)) < 1)) {
  961. break;
  962. }
  963. }
  964. if (previous_aqt_sub != NULL) {
  965. previous_aqt_sub->end = current->start - 1;
  966. }
  967. previous_aqt_sub = current;
  968. if (!internal_subf_gets(line, fd)) {
  969. return NULL;
  970. }
  971. internal_sub_readtext((char *)&line, &current->text.text[0]);
  972. current->text.lines = 1;
  973. current->end = current->start; // will be corrected by next subtitle
  974. if (!internal_subf_gets(line, fd)) {
  975. return current;
  976. }
  977. next = line, i = 1;
  978. while (1) {
  979. next = internal_sub_readtext(next, &(current->text.text[i]));
  980. if (!next) {
  981. break;
  982. }
  983. if (current->text.text[i] == ERR) {
  984. return ERR;
  985. }
  986. i++;
  987. if (i >= SUB_MAX_TEXT) {
  988. log_print(("Too many lines in a subtitle\n"));
  989. current->text.lines = i;
  990. return current;
  991. }
  992. }
  993. current->text.lines = i + 1;
  994. if ((current->text.text[0] == '\0') && (current->text.text[1] == '\0')) {
  995. // void subtitle -> end of previous marked and exit
  996. previous_aqt_sub = NULL;
  997. return NULL;
  998. }
  999. return current;
  1000. }
  1001. subtitle_t *internal_previous_subrip09_sub = NULL;
  1002. subtitle_t *internal_sub_read_line_subrip09(int fd, subtitle_t *current)
  1003. {
  1004. char line[LINE_LEN + 1];
  1005. int a1, a2, a3;
  1006. char * next = NULL;
  1007. int i, len;
  1008. while (1) {
  1009. // try to locate next subtitle
  1010. if (!internal_subf_gets(line, fd)) {
  1011. return NULL;
  1012. }
  1013. if (!((len = sscanf(line, "[%d:%d:%d]", &a1, &a2, &a3)) < 3)) {
  1014. break;
  1015. }
  1016. }
  1017. current->start = a1 * 360000 + a2 * 6000 + a3 * 100;
  1018. if (internal_previous_subrip09_sub != NULL) {
  1019. internal_previous_subrip09_sub->end = current->start - 1;
  1020. }
  1021. internal_previous_subrip09_sub = current;
  1022. if (!internal_subf_gets(line, fd)) {
  1023. return NULL;
  1024. }
  1025. next = line, i = 0;
  1026. current->text.text[0] = '\0'; // just to be sure that string is clear
  1027. while (1) {
  1028. next = internal_sub_readtext(next, &(current->text.text[i]));
  1029. if (!next) {
  1030. break;
  1031. }
  1032. if (current->text.text[i] == ERR) {
  1033. return ERR;
  1034. }
  1035. i++;
  1036. if (i >= SUB_MAX_TEXT) {
  1037. log_print(("Too many lines in a subtitle\n"));
  1038. current->text.lines = i;
  1039. return current;
  1040. }
  1041. }
  1042. current->text.lines = i + 1;
  1043. if ((current->text.text[0] == '\0') && (i == 0)) {
  1044. // void subtitle -> end of previous marked and exit
  1045. internal_previous_subrip09_sub = NULL;
  1046. return NULL;
  1047. }
  1048. return current;
  1049. }
  1050. subtitle_t *internal_sub_read_line_jacosub(int fd, subtitle_t * current)
  1051. {
  1052. char line1[LINE_LEN], line2[LINE_LEN], directive[LINE_LEN], *p, *q;
  1053. unsigned a1, a2, a3, a4, b1, b2, b3, b4, comment = 0;
  1054. static unsigned jacoTimeres = 30;
  1055. static int jacoShift = 0;
  1056. memset(current, 0, sizeof(subtitle_t));
  1057. memset(line1, 0, LINE_LEN);
  1058. memset(line2, 0, LINE_LEN);
  1059. memset(directive, 0, LINE_LEN);
  1060. while (!current->text.text[0]) {
  1061. if (!internal_subf_gets(line1, fd)) {
  1062. return NULL;
  1063. }
  1064. if (sscanf(line1, "%u:%u:%u.%u %u:%u:%u.%u %[^\n\r]",
  1065. &a1, &a2, &a3, &a4,
  1066. &b1, &b2, &b3, &b4, line2) < 9) {
  1067. if (sscanf(line1, "@%u @%u %[^\n\r]", &a4, &b4, line2) < 3) {
  1068. if (line1[0] == '#') {
  1069. int hours = 0, minutes = 0, seconds, delta, inverter = 1;
  1070. unsigned units = jacoShift;
  1071. switch (toupper(line1[1])) {
  1072. case 'S':
  1073. if (isalpha(line1[2])) {
  1074. delta = 6;
  1075. } else {
  1076. delta = 2;
  1077. }
  1078. if (sscanf(&line1[delta], "%d", &hours)) {
  1079. if (hours < 0) {
  1080. hours *= -1;
  1081. inverter = -1;
  1082. }
  1083. if (sscanf(&line1[delta], "%*d:%d", &minutes)) {
  1084. if (sscanf(&line1[delta], "%*d:%*d:%d", &seconds)) {
  1085. sscanf(&line1[delta], "%*d:%*d:%*d.%d", &units);
  1086. } else {
  1087. hours = 0;
  1088. sscanf(&line1[delta], "%d:%d.%d", &minutes, &seconds, &units);
  1089. minutes *= inverter;
  1090. }
  1091. } else {
  1092. hours = minutes = 0;
  1093. sscanf(&line1[delta], "%d.%d", &seconds, &units);
  1094. seconds *= inverter;
  1095. }
  1096. jacoShift = ((hours * 3600 + minutes * 60 + seconds) * jacoTimeres + units)
  1097. * inverter;
  1098. }
  1099. break;
  1100. case 'T':
  1101. if (isalpha(line1[2])) {
  1102. delta = 8;
  1103. } else {
  1104. delta = 2;
  1105. }
  1106. sscanf(&line1[delta], "%u", &jacoTimeres);
  1107. break;
  1108. }
  1109. }
  1110. continue;
  1111. } else {
  1112. current->start = (unsigned long)((a4 + jacoShift) * 100.0 / jacoTimeres);
  1113. current->end = (unsigned long)((b4 + jacoShift) * 100.0 / jacoTimeres);
  1114. }
  1115. } else {
  1116. current->start = (unsigned long)(((a1 * 3600 + a2 * 60 + a3) * jacoTimeres + a4 +
  1117. jacoShift) * 100.0 / jacoTimeres);
  1118. current->end = (unsigned long)(((b1 * 3600 + b2 * 60 + b3) * jacoTimeres + b4 +
  1119. jacoShift) * 100.0 / jacoTimeres);
  1120. }
  1121. current->text.lines = 0;
  1122. p = line2;
  1123. while ((*p == ' ') || (*p == '\t')) {
  1124. ++p;
  1125. }
  1126. if (isalpha(*p) || *p == '[') {
  1127. int cont, jLength;
  1128. if (sscanf(p, "%s %[^\n\r]", directive, line1) < 2) {
  1129. return (subtitle_t *) ERR;
  1130. }
  1131. jLength = strlen(directive);
  1132. for (cont = 0; cont < jLength; ++cont) {
  1133. if (isalpha(*(directive + cont))) {
  1134. *(directive + cont) = toupper(*(directive + cont));
  1135. }
  1136. }
  1137. if ((strstr(directive, "RDB") != NULL)
  1138. || (strstr(directive, "RDC") != NULL)
  1139. || (strstr(directive, "RLB") != NULL)
  1140. || (strstr(directive, "RLG") != NULL)) {
  1141. continue;
  1142. }
  1143. if (strstr(directive, "JL") != NULL) {
  1144. current->text.alignment = SUB_ALIGNMENT_BOTTOMLEFT;
  1145. } else if (strstr(directive, "JR") != NULL) {
  1146. current->text.alignment = SUB_ALIGNMENT_BOTTOMRIGHT;
  1147. } else {
  1148. current->text.alignment = SUB_ALIGNMENT_BOTTOMCENTER;
  1149. }
  1150. strcpy(line2, line1);
  1151. p = line2;
  1152. }
  1153. for (q = line1; (!internal_eol(*p)) && (current->text.lines < SUB_MAX_TEXT); ++p) {
  1154. switch (*p) {
  1155. case '{':
  1156. comment++;
  1157. break;
  1158. case '}':
  1159. if (comment) {
  1160. --comment;
  1161. //the next line to get rid of a blank after the comment
  1162. if ((*(p + 1)) == ' ') {
  1163. p++;
  1164. }
  1165. }
  1166. break;
  1167. case '~':
  1168. if (!comment) {
  1169. *q = ' ';
  1170. ++q;
  1171. }
  1172. break;
  1173. case ' ':
  1174. case '\t':
  1175. if ((*(p + 1) == ' ') || (*(p + 1) == '\t')) {
  1176. break;
  1177. }
  1178. if (!comment) {
  1179. *q = ' ';
  1180. ++q;
  1181. }
  1182. break;
  1183. case '\\':
  1184. if (*(p + 1) == 'n') {
  1185. *q = '\0';
  1186. q = line1;
  1187. current->text.text[current->text.lines++] = internal_sub_strdup(line1);
  1188. ++p;
  1189. break;
  1190. }
  1191. if ((toupper(*(p + 1)) == 'C')
  1192. || (toupper(*(p + 1)) == 'F')) {
  1193. ++p, ++p;
  1194. break;
  1195. }
  1196. if ((*(p + 1) == 'B') || (*(p + 1) == 'b') || (*(p + 1) == 'D') || //actually this means "insert current date here"
  1197. (*(p + 1) == 'I') || (*(p + 1) == 'i') || (*(p + 1) == 'N') || (*(p + 1) == 'T') || //actually this means "insert current time here"
  1198. (*(p + 1) == 'U') || (*(p + 1) == 'u')) {
  1199. ++p;
  1200. break;
  1201. }
  1202. if ((*(p + 1) == '\\') ||
  1203. (*(p + 1) == '~') || (*(p + 1) == '{')) {
  1204. ++p;
  1205. } else if (internal_eol(*(p + 1))) {
  1206. if (!internal_subf_gets(directive, fd)) {
  1207. return NULL;
  1208. }
  1209. internal_trail_space(directive);
  1210. strncat(line2, directive,
  1211. (LINE_LEN > 511) ? LINE_LEN : 511);
  1212. break;
  1213. }
  1214. default:
  1215. if (!comment) {
  1216. *q = *p;
  1217. ++q;
  1218. }
  1219. break;
  1220. } //-- switch
  1221. } //-- for
  1222. *q = '\0';
  1223. current->text.text[current->text.lines] = internal_sub_strdup(line1);
  1224. } //-- while
  1225. current->text.lines++;
  1226. return current;
  1227. }
  1228. static int internal_sub_autodetect(int fd)
  1229. {
  1230. char line[LINE_LEN + 1];
  1231. int i, j = 0;
  1232. char p;
  1233. j = sscanf("00:02:21,606 --> 00:02:23,073",
  1234. "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d",
  1235. &i, &i, &i, (char *)&i, &i, &i, &i, &i, (char *)&i, &i);
  1236. j = sscanf("abc",
  1237. "[aef]bc",
  1238. (char *)&i);
  1239. while (j < 100) {
  1240. j++;
  1241. if (!internal_subf_gets(line, fd)) {
  1242. return SUB_INVALID;
  1243. }
  1244. if (sscanf(line, "{%d}{%d}", &i, &i) == 2) {
  1245. return SUB_MICRODVD;
  1246. }
  1247. if (sscanf(line, "{%d}{}", &i) == 1) {
  1248. return SUB_MICRODVD;
  1249. }
  1250. if (sscanf(line, "[%d][%d]", &i, &i) == 2) {
  1251. return SUB_MPL2;
  1252. }
  1253. if (sscanf(line, "%d:%d:%d.%d,%d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
  1254. return SUB_SUBRIP;
  1255. }
  1256. if (sscanf(line, "%d:%d:%d%[,.:]%d --> %d:%d:%d%[,.:]%d", &i, &i, &i, (char *)&i, &i, &i, &i, &i, (char *)&i, &i) == 10) {
  1257. return SUB_SUBVIEWER;
  1258. }
  1259. if (sscanf(line, "{T %d:%d:%d:%d", &i, &i, &i, &i) == 4) {
  1260. return SUB_SUBVIEWER2;
  1261. }
  1262. if (strstr(line, "<SAMI>")) {
  1263. return SUB_SAMI;
  1264. }
  1265. if (sscanf(line, "%d:%d:%d.%d %d:%d:%d.%d", &i, &i, &i, &i, &i, &i, &i, &i) == 8) {
  1266. return SUB_JACOSUB;
  1267. }
  1268. if (sscanf(line, "@%d @%d", &i, &i) == 2) {
  1269. return SUB_JACOSUB;
  1270. }
  1271. if (sscanf(line, "%d:%d:%d:", &i, &i, &i) == 3) {
  1272. return SUB_VPLAYER;
  1273. }
  1274. if (sscanf(line, "%d:%d:%d ", &i, &i, &i) == 3) {
  1275. return SUB_VPLAYER;
  1276. }
  1277. //TODO: just checking if first line of sub starts with "<" is WAY
  1278. // too weak test for RT
  1279. // Please someone who knows the format of RT... FIX IT!!!
  1280. // It may conflict with other sub formats in the future (actually it doesn't)
  1281. if (*line == '<') {
  1282. return SUB_RT;
  1283. }
  1284. if (!memcmp(line, "Dialogue: Marked", 16)) {
  1285. return SUB_SSA;
  1286. }
  1287. if (!memcmp(line, "Dialogue: ", 10)) {
  1288. return SUB_SSA;
  1289. }
  1290. if (sscanf(line, "%d,%d,\"%c", &i, &i, (char *) &i) == 3) {
  1291. return SUB_PJS;
  1292. }
  1293. if (sscanf(line, "FORMAT=%d", &i) == 1) {
  1294. return SUB_MPSUB;
  1295. }
  1296. if (sscanf(line, "FORMAT=TIM%c", &p) == 1 && p == 'E') {
  1297. return SUB_MPSUB;
  1298. }
  1299. if (strstr(line, "-->>")) {
  1300. return SUB_AQTITLE;
  1301. }
  1302. if (sscanf(line, "[%d:%d:%d]", &i, &i, &i) == 3) {
  1303. return SUB_SUBRIP09;
  1304. }
  1305. }
  1306. return SUB_INVALID; // too many bad lines
  1307. }
  1308. SUBAPI void internal_sub_close(subdata_t *subdata)
  1309. {
  1310. int i;
  1311. list_t *entry;
  1312. entry = subdata->list.next;
  1313. while (entry != &subdata->list) {
  1314. subtitle_t *subt = list_entry(entry, subtitle_t, list);
  1315. if (subdata->sub_format == SUB_DIVX) {
  1316. if (subt->subdata) {
  1317. FREE(subt->subdata);
  1318. }
  1319. } else {
  1320. for (i = 0; i < subt->text.lines; i++) {
  1321. FREE(subt->text.text[i]);
  1322. }
  1323. }
  1324. entry = entry->next;
  1325. FREE(subt);
  1326. }
  1327. FREE(subdata);
  1328. }
  1329. SUBAPI subdata_t *internal_sub_open(char *filename, unsigned int rate)
  1330. {
  1331. int fd = 0;
  1332. subtitle_t *sub, *sub_read;
  1333. subdata_t *subdata;
  1334. int sub_format = SUB_INVALID;
  1335. subreader_t sr[] = {
  1336. { internal_sub_read_line_microdvd, NULL, "microdvd" },
  1337. { internal_sub_read_line_subrip, NULL, "subrip" },
  1338. { internal_sub_read_line_subviewer, NULL, "subviewer" },
  1339. { internal_sub_read_line_sami, NULL, "sami" },
  1340. { internal_sub_read_line_vplayer, NULL, "vplayer" },
  1341. { internal_sub_read_line_rt, NULL, "rt" },
  1342. { internal_sub_read_line_ssa, internal_sub_pp_ssa, "ssa" },
  1343. { internal_sub_read_line_pjs, NULL, "pjs" },
  1344. { internal_sub_read_line_mpsub, NULL, "mpsub" },
  1345. { internal_sub_read_line_aqt, NULL, "aqt" },
  1346. { internal_sub_read_line_subviewer2, NULL, "subviewer 2.0" },
  1347. { internal_sub_read_line_subrip09, NULL, "subrip 0.9" },
  1348. { internal_sub_read_line_jacosub, NULL, "jacosub" },
  1349. { internal_sub_read_line_mpl2, NULL, "mpl2" }
  1350. };
  1351. subreader_t *srp;
  1352. if (filename == NULL) {
  1353. return NULL;
  1354. } else if (0 == strcmp(filename, "subdivx")) {
  1355. sub_format = SUB_DIVX;
  1356. } else {
  1357. fd = open(filename, O_RDONLY);
  1358. if (fd < 0) {
  1359. return NULL;
  1360. }
  1361. }
  1362. subdata = (subdata_t *)MALLOC(sizeof(subdata_t));
  1363. if (!subdata) {
  1364. close(fd);
  1365. return NULL;
  1366. }
  1367. memset(subdata, 0, sizeof(subdata_t));
  1368. INIT_LIST_HEAD(&subdata->list);
  1369. if (sub_format == SUB_DIVX) {
  1370. subdata->sub_format = sub_format;
  1371. subdata->sub_num = 0;
  1372. return subdata;
  1373. } else {
  1374. subdata->sub_format = internal_sub_autodetect(fd);
  1375. }
  1376. if (subdata->sub_format == SUB_INVALID) {
  1377. log_print(("SUB: Could not determine file format\n"));
  1378. internal_sub_close(subdata);
  1379. close(fd);
  1380. return NULL;
  1381. }
  1382. srp = sr + subdata->sub_format;
  1383. //log_print(("SUB: Detected subtitle file format: %s\n", srp->name));
  1384. lseek(fd, 0, SEEK_SET);
  1385. if (subfile_buffer) {
  1386. FREE(subfile_buffer);
  1387. subfile_buffer = NULL;
  1388. }
  1389. while (1) {
  1390. sub = (subtitle_t *)MALLOC(sizeof(subtitle_t));
  1391. if (!sub) {
  1392. break;
  1393. }
  1394. memset(sub, 0, sizeof(subtitle_t));
  1395. sub->end = rate;
  1396. sub_read = srp->read(fd, sub);
  1397. if (!sub_read) {
  1398. FREE(sub);
  1399. break; // EOF
  1400. }
  1401. if (sub_read == ERR) {
  1402. FREE(sub);
  1403. subdata->sub_error++;
  1404. } else {
  1405. // Apply any post processing that needs recoding first
  1406. if (!sub_no_text_pp && srp->post) {
  1407. srp->post(sub_read);
  1408. }
  1409. /* 10ms to pts conversion */
  1410. sub->start = sub_ms2pts(sub->start);
  1411. sub->end = sub_ms2pts(sub->end);
  1412. //log_print("return: %s\n", sub->text.text[0]);
  1413. list_add_tail(&sub->list, &subdata->list);
  1414. subdata->sub_num++;
  1415. }
  1416. }
  1417. if (subfile_buffer) {
  1418. FREE(subfile_buffer);
  1419. subfile_buffer = NULL;
  1420. }
  1421. close(fd);
  1422. if (subdata->sub_num <= 0) {
  1423. internal_sub_close(subdata);
  1424. return NULL;
  1425. }
  1426. log_print("SUB: Read %d subtitles", subdata->sub_num);
  1427. if (subdata->sub_error) {
  1428. log_print(", %d bad line(s).\n", subdata->sub_error);
  1429. } else {
  1430. log_print((".\n"));
  1431. }
  1432. return subdata;
  1433. }
  1434. SUBAPI char *internal_sub_filenames(char *filename, unsigned perfect_match)
  1435. {
  1436. char *dir;
  1437. char *sub_exts[] = {"utf", "sub", "srt", "smi",
  1438. "rt", "txt", "ssa", "aqt", "jss", "js", "ass", NULL
  1439. };
  1440. char *p = NULL, *p2 = NULL;
  1441. char *ext, *fn, *long_fn;
  1442. DIR *pDir;
  1443. int i, looking;
  1444. struct dirent *pDirEntry;
  1445. char *subname = NULL;
  1446. unsigned videofile_lnamlen = 0;
  1447. /* get directory name first */
  1448. fn = p;
  1449. p = strrchr(filename, '/');
  1450. p2 = strrchr(filename, '\\');
  1451. if (p2 > p) {
  1452. p = p2;
  1453. }
  1454. if (p) {
  1455. dir = (char *)MALLOC(p - filename + 2);
  1456. if (!dir) {
  1457. return NULL;
  1458. }
  1459. memcpy(dir, filename, p - filename + 1); /* including final '/' or '\\' */
  1460. dir[p - filename + 1] = '\0';
  1461. fn = p + 1;
  1462. } else {
  1463. dir = (char *)MALLOC(3);
  1464. if (!dir) {
  1465. return NULL;
  1466. }
  1467. strcpy(dir, "./");
  1468. }
  1469. /* get long file name of input file */
  1470. pDir = opendir(dir);
  1471. if (!pDir) {
  1472. FREE(dir);
  1473. return NULL;
  1474. }
  1475. looking = 1;
  1476. while (looking) {
  1477. pDirEntry = readdir(pDir);
  1478. if (!pDirEntry) {
  1479. break;
  1480. }
  1481. if (pDirEntry->d_type & S_IFDIR) {
  1482. continue;
  1483. }
  1484. /*
  1485. if(pDirEntry->d_reclen){
  1486. if(strncasecmp(fn,pDirEntry->d_name,pDirEntry->d_reclen) == 0){
  1487. looking = 0;
  1488. }
  1489. }
  1490. else{
  1491. if(strncasecmp(fn, pDirEntry->d_name, pDirEntry->d_namlen) == 0){
  1492. looking = 0;
  1493. }
  1494. }*/
  1495. if (strncasecmp(fn, pDirEntry->d_name, pDirEntry->d_reclen) == 0) {
  1496. looking = 0;
  1497. }
  1498. }
  1499. if (looking == 1) {
  1500. closedir(pDir);
  1501. FREE(dir);
  1502. return NULL;
  1503. } else {
  1504. /* sometimes long file name is not available, just use short name */
  1505. #if 0
  1506. if (p

Large files files are truncated, but you can click here to view the full file