asademux.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:14k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * asademux.c: asa demuxer VM
  3.  *****************************************************************************
  4.  * Copyright (C) 2007 the VideoLAN team
  5.  *
  6.  * Originated from asa: portable digital subtitle renderer
  7.  *
  8.  * Authors: David Lamparter <equinox at diac24 dot net>
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  23.  ****************************************************************************/
  24. /****************************************************************************
  25.  * Changes from asa version:
  26.  *  - headers adapted
  27.  *  - external definition file support dropped
  28.  *  - integer timestamps
  29.  ****************************************************************************
  30.  * Please retain Linux kernel CodingStyle for sync.
  31.  * base commit d8c269b0fae9a8f8904e16e92313da165d664c74
  32.  ****************************************************************************/
  33. #include "config.h"
  34. #include <vlc_common.h>
  35. #include <vlc_input.h>
  36. #include <vlc_demux.h>
  37. #include <limits.h>
  38. #include <string.h>
  39. #include "asademux.h"
  40. #define MAXDELTA 4 /**< nr of times kept for delta backref */
  41. #define MAXGROUP 24 /**< maximum number of regex match groups */
  42. #define xmalloc malloc
  43. #define xrealloc realloc
  44. #define xfree free
  45. #define xstrdup strdup
  46. /** state of a running import */
  47. struct asa_import_state {
  48. demux_t *demux; /**< demuxer for msg* funcs */
  49. const char *line; /**< beginning of current line */
  50. size_t remain; /**< remaining data at line */
  51. char **matches; /**< active matchgroups */
  52. unsigned nmatches; /**< number of matchgroups */
  53. char *selstr; /**< buffer for currently selected */
  54. size_t sellen; /**< strlen of selstr */
  55. char *out; /**< output buffer (NULL if empty) */
  56. size_t outlen; /**< length of output string w/o  */
  57. int64_t usecperf, /**< microseconds per frame, active */
  58. origusecperf, /**< microseconds per frame, from app */
  59. start, /**< start time */
  60. end; /**< end time */
  61. int64_t delta[MAXDELTA]; /**< hist of last times for delta */
  62. asa_import_callback *cb; /**< commit callback */
  63. void *cb_arg; /**< callback argument */
  64. };
  65. #define iargs struct asa_import_state *state, struct asa_import_insn *insn
  66. /** asa instruction function.
  67.  * @param state import state
  68.  * @param insn instruction to execute
  69.  * @return status code.n
  70.  *   0: continue
  71.  *   -1: restart from beginning
  72.  *   >0: break level
  73.  */
  74. typedef int (*asa_import_func)(iargs);
  75. static int asai_commit (iargs);
  76. static int asai_discard(iargs);
  77. static int asai_break  (iargs);
  78. static int asai_select (iargs);
  79. static int asai_sg     (iargs);
  80. static int asai_sgu    (iargs);
  81. static int asai_append (iargs);
  82. static int asai_fps    (iargs);
  83. static int asai_show   (iargs);
  84. static int asai_hide   (iargs);
  85. static int asai_child  (iargs);
  86. #undef iargs
  87. /** vm functions. KEEP IN SYNC WITH imports.h! */
  88. static const asa_import_func importfuncs[] = {
  89. asai_commit,
  90. asai_discard,
  91. asai_break,
  92. asai_select,
  93. asai_sg,
  94. asai_sgu,
  95. asai_append,
  96. asai_fps,
  97. asai_show,
  98. asai_hide,
  99. asai_child
  100. };
  101. #define ASAI_MAX (unsigned)(sizeof(importfuncs) / sizeof(importfuncs[0]))
  102. struct asa_import_detect *asa_det_first = NULL,
  103. **asa_det_last = &asa_det_first;
  104. struct asa_import_format *asa_fmt_first = NULL,
  105. **asa_fmt_last = &asa_fmt_first;
  106. /** asa_imports_crosslink - resolve references in imports file.
  107.  * updates asa_import_format.prevtgt, asa_import_format.nexttgt,
  108.  * asa_import_detect.fmt
  109.  */
  110. static void asa_imports_crosslink(void)
  111. {
  112. struct asa_import_format *fmt, *fmt2;
  113. struct asa_import_detect *det;
  114. for (fmt = asa_fmt_first; fmt; fmt = fmt->next) {
  115. for (fmt2 = fmt->next; fmt2; fmt2 = fmt2->next)
  116. if (!strcmp(fmt->name, fmt2->name)) {
  117. fmt->nexttgt = fmt2;
  118. fmt2->prevtgt = fmt;
  119. break;
  120. }
  121. }
  122. for (det = asa_det_first; det; det = det->next) {
  123. det->fmt = NULL;
  124. for (fmt = asa_fmt_first; fmt; fmt = fmt->next)
  125. if (!strcmp(det->name, fmt->name)) {
  126. det->fmt = fmt;
  127. break;
  128. }
  129. }
  130. }
  131. /** asa_imports_detect - autodetect subtitle format.
  132.  * @param data pointer to subtitle byte data
  133.  * @param datalen byte length of data
  134.  * @return the detect structure that hit or NULL if detection failed
  135.  */
  136. struct asa_import_detect *asa_imports_detect(const void *data, size_t dlen)
  137. {
  138. struct asa_import_detect *det;
  139. const char *d = (const char *)data;
  140. int v[64];
  141. if (dlen > 2048)
  142. dlen = 2048;
  143. for (det = asa_det_first; det; det = det->next)
  144. if (pcre_exec(det->re.pcre, NULL, d, dlen, 0, 0, v, 64) >= 0)
  145. return det;
  146. return NULL;
  147. }
  148. /** asai_run_insns - execute a list of instructions.
  149.  * @see asa_import_func */
  150. static int asai_run_insns(struct asa_import_state *state,
  151. struct asa_import_insn *insn)
  152. {
  153. struct asa_import_insn *inow = insn, preload;
  154. int rv, repeating = 0;
  155. preload.next = insn;
  156. for (; inow; inow = inow->next) {
  157. if (repeating && inow->insn != ASAI_CHILD)
  158. continue;
  159. if (inow->insn >= ASAI_MAX)
  160. continue;
  161. rv = importfuncs[inow->insn](state, inow);
  162. if (rv == -1) {
  163. inow = &preload;
  164. continue;
  165. }
  166. if (rv > 0)
  167. return rv - 1;
  168. }
  169. /* ran through everything, let's try another round */
  170. return -1;
  171. }
  172. /** asai_commit - commit a block to the user.
  173.  * @see asa_import_func */
  174. static int asai_commit(struct asa_import_state *state,
  175. struct asa_import_insn *insn)
  176. {
  177. int rv = 0;
  178. if (!state->out)
  179. return 0;
  180. if (state->outlen > 0)
  181. rv = state->cb(state->demux, state->cb_arg,
  182. state->start, state->end,
  183. state->out, state->outlen);
  184. xfree(state->out);
  185. state->out = NULL;
  186. state->outlen = 0;
  187. if (rv)
  188. return INT_MAX;
  189. return 0;
  190. }
  191. /** asai_discard - clear the buffer without committing.
  192.  * @see asa_import_func */
  193. static int asai_discard(struct asa_import_state *state,
  194. struct asa_import_insn *insn)
  195. {
  196. if (!state->out)
  197. return 0;
  198. xfree(state->out);
  199. state->out = NULL;
  200. state->outlen = 0;
  201. return 0;
  202. }
  203. /** asai_break - jump out of child.
  204.  * @see asa_import_func */
  205. static int asai_break(struct asa_import_state *state,
  206. struct asa_import_insn *insn)
  207. {
  208. return insn->v.break_depth;
  209. }
  210. /** asai_select - choose a match group to be the active one.
  211.  * @see asa_import_func */
  212. static int asai_select (struct asa_import_state *state,
  213. struct asa_import_insn *insn)
  214. {
  215. if (insn->v.select < 0
  216. || (unsigned)insn->v.select >= state->nmatches) {
  217. msg_Err(state->demux, "import script trying to "
  218. "reference group %d, maximum is %d",
  219. insn->v.select, state->nmatches);
  220. return 0;
  221. }
  222. if (state->selstr)
  223. xfree(state->selstr);
  224. state->selstr = xstrdup(state->matches[insn->v.select]);
  225. state->sellen = strlen(state->selstr);
  226. return 0;
  227. }
  228. #include <stddef.h>
  229. static ptrdiff_t asai_process_replace(struct asa_import_state *state,
  230. struct asa_import_insn *insn, int *v, int rv)
  231. {
  232. struct asa_repl *r;
  233. char *newstr;
  234. ptrdiff_t newpos, firstold;
  235. size_t newstr_size;
  236. newstr_size = v[0] * 2;
  237. newstr = (char *)xmalloc(newstr_size);
  238. memcpy(newstr, state->selstr, v[0]);
  239. newpos = v[0];
  240. for (r = insn->v.sg.repl; r; r = r->next) {
  241. size_t avail = newstr_size - newpos, need;
  242. const char *src;
  243. if (r->group >= rv) {
  244. msg_Err(state->demux,
  245. "import script trying to replace by "
  246. "reference group %d, maximum is %d",
  247. r->group, rv);
  248. continue;
  249. }
  250. if (r->group >= 0) {
  251. need = v[r->group * 2 + 1] - v[r->group * 2];
  252. src = state->selstr + v[r->group * 2];
  253. } else {
  254. need = strlen(r->text);
  255. src = r->text;
  256. }
  257. if (need > avail) {
  258. newstr_size += need - avail + 256;
  259. newstr = (char *)xrealloc(newstr, newstr_size);
  260. }
  261. memcpy(newstr + newpos, src, need);
  262. newpos += need;
  263. }
  264. firstold = newpos;
  265. newstr_size = newpos + state->sellen - v[1];
  266. newstr = (char *)xrealloc(newstr, newstr_size + 1);
  267. memcpy(newstr + newpos, state->selstr + v[1],
  268. state->sellen - v[1] + 1);
  269. state->selstr = newstr;
  270. state->sellen = newstr_size;
  271. return firstold;
  272. }
  273. /** asai_sg - search and replace.
  274.  * @see asa_import_func */
  275. static int asai_sg(struct asa_import_state *state,
  276. struct asa_import_insn *insn)
  277. {
  278. int rv, v[MAXGROUP * 2];
  279. char *oldstr;
  280. ptrdiff_t s = 0;
  281. if (!state->selstr)
  282. return 0;
  283. while ((unsigned)s < state->sellen &&
  284. (rv = pcre_exec(insn->v.sg.regex.pcre, NULL, state->selstr,
  285. state->sellen, s, 0, v, MAXGROUP * 2)) >= 0) {
  286. oldstr = state->selstr;
  287. s = asai_process_replace(state, insn, v, rv);
  288. xfree(oldstr);
  289. }
  290. return 0;
  291. }
  292. /** asai_chunk_alloc - allocate composite chunk.
  293.  * @see asa_import_func */
  294. static inline char **asai_chunk_alloc(char **old, int *v, int rv)
  295. {
  296. size_t s = rv * sizeof(char *);
  297. int i;
  298. for (i = 0; i < rv; i++)
  299. s += v[i * 2 + 1] - v[i * 2] + 1;
  300. return (char **)xrealloc(old, s);
  301. }
  302. /** asai_set_matches - load result from pcre_exec into matches */
  303. static void asai_set_matches(struct asa_import_state *state,
  304. const char *src, int *v, int rv)
  305. {
  306. unsigned i;
  307. char *dst;
  308. state->matches = asai_chunk_alloc(state->matches, v, rv);
  309. state->nmatches = rv;
  310. dst = (char *)(state->matches + rv);
  311. for (i = 0; i < state->nmatches; i++) {
  312. size_t len = v[2 * i + 1] - v[2 * i];
  313. state->matches[i] = dst;
  314. memcpy(dst, src + v[2 * i], len);
  315. dst[len] = '';
  316. dst += len + 1;
  317. }
  318. if (state->selstr)
  319. xfree(state->selstr);
  320. state->selstr = xstrdup(state->matches[0]);
  321. state->sellen = strlen(state->selstr);
  322. }
  323. /** asai_sgu - replace one time and update matches.
  324.  * @see asa_import_func */
  325. static int asai_sgu(struct asa_import_state *state,
  326. struct asa_import_insn *insn)
  327. {
  328. int rv, v[MAXGROUP * 2];
  329. char *oldstr;
  330. if (!state->selstr)
  331. return 0;
  332. if ((rv = pcre_exec(insn->v.sg.regex.pcre, NULL, state->selstr,
  333. state->sellen, 0, 0, v, MAXGROUP * 2)) >= 0) {
  334. oldstr = state->selstr;
  335. asai_process_replace(state, insn, v, rv);
  336. asai_set_matches(state, oldstr, v, rv);
  337. xfree(oldstr);
  338. }
  339. return 0;
  340. }
  341. /** asai_append - append selected string to output buffer.
  342.  * @see asa_import_func */
  343. static int asai_append (struct asa_import_state *state,
  344. struct asa_import_insn *insn)
  345. {
  346. state->out = (char *)xrealloc(state->out,
  347. state->outlen + state->sellen + 1);
  348. memcpy(state->out + state->outlen, state->selstr, state->sellen);
  349. state->outlen += state->sellen;
  350. state->out[state->outlen] = '';
  351. return 0;
  352. }
  353. /** asai_fps - override fps.
  354.  * @see asa_import_func */
  355. static int asai_fps(struct asa_import_state *state,
  356. struct asa_import_insn *insn)
  357. {
  358. if (insn->v.fps_value == 0)
  359. state->usecperf = state->origusecperf;
  360. else
  361. state->usecperf = (int64_t)(1000000. / insn->v.fps_value);
  362. return 0;
  363. }
  364. /** asai_gettime - walk asa_tspec and sum up the time.
  365.  * @see asa_import_func
  366.  * @return the calculated time, delta[0] on error
  367.  * also updates the delta history.
  368.  */
  369. static int64_t asai_gettime(struct asa_import_state *state,
  370. struct asa_import_insn *insn)
  371. {
  372. struct asa_tspec *tsp;
  373. int64_t t = 0;
  374. if (insn->v.tspec.delta_select != -1) {
  375. if (insn->v.tspec.delta_select < MAXDELTA)
  376. t += state->delta[insn->v.tspec.delta_select];
  377. else
  378. msg_Err(state->demux, "imports: tspec "
  379. "delta %d exceeds compiled-in maximum of %d",
  380. insn->v.tspec.delta_select, MAXDELTA);
  381. }
  382. for (tsp = insn->v.tspec.tsp; tsp; tsp = tsp->next) {
  383. char *errptr;
  384. double src;
  385. if ((unsigned)tsp->group >= state->nmatches) {
  386. msg_Err(state->demux, "imports: tspec "
  387. "tries to access group %d, but only "
  388. "%d groups exist",
  389. tsp->group, state->nmatches);
  390. continue;
  391. }
  392. if (!*state->matches[tsp->group])
  393. continue;
  394. src = strtod(state->matches[tsp->group], &errptr);
  395. if (*errptr)
  396. msg_Warn(state->demux, "imports: invalid tspec '%s'",
  397. state->matches[tsp->group]);
  398. t += (src * tsp->mult * 1000000)
  399. + src * tsp->fps_mult * state->usecperf;
  400. }
  401. memmove(state->delta + 1, state->delta,
  402. sizeof(state->delta[0]) * (MAXDELTA - 1));
  403. state->delta[0] = t;
  404. return t;
  405. }
  406. /** asai_show - set start time.
  407.  * @see asa_import_func */
  408. static int asai_show(struct asa_import_state *state,
  409. struct asa_import_insn *insn)
  410. {
  411. state->start = asai_gettime(state, insn);
  412. return 0;
  413. }
  414. /** asai_hide - set end time.
  415.  * @see asa_import_func */
  416. static int asai_hide(struct asa_import_state *state,
  417. struct asa_import_insn *insn)
  418. {
  419. state->end = asai_gettime(state, insn);
  420. return 0;
  421. }
  422. /** asai_child - execute childs if we match.
  423.  * @see asa_import_func */
  424. static int asai_child(struct asa_import_state *state,
  425. struct asa_import_insn *insn)
  426. {
  427. int rv, v[MAXGROUP * 2];
  428. if ((rv = pcre_exec(insn->v.child.regex.pcre, NULL, state->line,
  429. state->remain, 0, 0, v, MAXGROUP * 2)) >= 0) {
  430. asai_set_matches(state, state->line, v, rv);
  431. state->line += v[1];
  432. state->remain -= v[1];
  433. rv = asai_run_insns(state, insn->v.child.insns);
  434. return rv;
  435. }
  436. return 0;
  437. }
  438. int asa_import(demux_t *d, const void *data, size_t dlen,
  439. int64_t usecperframe, struct asa_import_detect *det,
  440. asa_import_callback *callback, void *arg)
  441. {
  442. struct asa_import_format *fmt = det->fmt;
  443. struct asa_import_state state;
  444. int rv;
  445. memset(&state, 0, sizeof(state));
  446. state.demux = d;
  447. state.usecperf = state.origusecperf = usecperframe;
  448. state.line = (const char *)data;
  449. state.remain = dlen;
  450. state.cb = callback;
  451. state.cb_arg = arg;
  452. rv = asai_run_insns(&state, fmt->insns);
  453. if (state.matches)
  454. xfree(state.matches);
  455. if (state.out) {
  456. callback(d, arg, state.start, state.end,
  457. state.out, state.outlen);
  458. xfree(state.out);
  459. }
  460. if (state.selstr)
  461. xfree(state.selstr);
  462. return rv;
  463. }
  464. int asa_pcre_compile(asa_pcre *out, const char *str)
  465. {
  466. const char *err;
  467. int ec, eo;
  468. out->pcre = pcre_compile2(str, 0, &ec, &err, &eo, NULL);
  469. if (out->pcre)
  470. return 0;
  471. return 1;
  472. }
  473. #include "asademux_defs.h"
  474. void asa_init_import()
  475. {
  476. static int setup = 0;
  477. if (setup)
  478. return;
  479. preparse_add();
  480. asa_imports_crosslink();
  481. setup = 1;
  482. }