You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

481 lines
14KB

  1. /*
  2. * DVD subtitle decoding for ffmpeg
  3. * Copyright (c) 2005 Fabrice Bellard.
  4. *
  5. * This file is part of FFmpeg.
  6. *
  7. * FFmpeg is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU Lesser General Public
  9. * License as published by the Free Software Foundation; either
  10. * version 2.1 of the License, or (at your option) any later version.
  11. *
  12. * FFmpeg is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with FFmpeg; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. */
  21. #include "avcodec.h"
  22. //#define DEBUG
  23. typedef struct DVDSubContext {
  24. } DVDSubContext;
  25. static int dvdsub_init_decoder(AVCodecContext *avctx)
  26. {
  27. return 0;
  28. }
  29. static uint16_t getbe16(const uint8_t *p)
  30. {
  31. return (p[0] << 8) | p[1];
  32. }
  33. static int get_nibble(const uint8_t *buf, int nibble_offset)
  34. {
  35. return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf;
  36. }
  37. static int decode_rle(uint8_t *bitmap, int linesize, int w, int h,
  38. const uint8_t *buf, int nibble_offset, int buf_size)
  39. {
  40. unsigned int v;
  41. int x, y, len, color, nibble_end;
  42. uint8_t *d;
  43. nibble_end = buf_size * 2;
  44. x = 0;
  45. y = 0;
  46. d = bitmap;
  47. for(;;) {
  48. if (nibble_offset >= nibble_end)
  49. return -1;
  50. v = get_nibble(buf, nibble_offset++);
  51. if (v < 0x4) {
  52. v = (v << 4) | get_nibble(buf, nibble_offset++);
  53. if (v < 0x10) {
  54. v = (v << 4) | get_nibble(buf, nibble_offset++);
  55. if (v < 0x040) {
  56. v = (v << 4) | get_nibble(buf, nibble_offset++);
  57. if (v < 4) {
  58. v |= (w - x) << 2;
  59. }
  60. }
  61. }
  62. }
  63. len = v >> 2;
  64. if (len > (w - x))
  65. len = (w - x);
  66. color = v & 0x03;
  67. memset(d + x, color, len);
  68. x += len;
  69. if (x >= w) {
  70. y++;
  71. if (y >= h)
  72. break;
  73. d += linesize;
  74. x = 0;
  75. /* byte align */
  76. nibble_offset += (nibble_offset & 1);
  77. }
  78. }
  79. return 0;
  80. }
  81. static void guess_palette(uint32_t *rgba_palette,
  82. uint8_t *palette,
  83. uint8_t *alpha,
  84. uint32_t subtitle_color)
  85. {
  86. uint8_t color_used[16];
  87. int nb_opaque_colors, i, level, j, r, g, b;
  88. for(i = 0; i < 4; i++)
  89. rgba_palette[i] = 0;
  90. memset(color_used, 0, 16);
  91. nb_opaque_colors = 0;
  92. for(i = 0; i < 4; i++) {
  93. if (alpha[i] != 0 && !color_used[palette[i]]) {
  94. color_used[palette[i]] = 1;
  95. nb_opaque_colors++;
  96. }
  97. }
  98. if (nb_opaque_colors == 0)
  99. return;
  100. j = nb_opaque_colors;
  101. memset(color_used, 0, 16);
  102. for(i = 0; i < 4; i++) {
  103. if (alpha[i] != 0) {
  104. if (!color_used[palette[i]]) {
  105. level = (0xff * j) / nb_opaque_colors;
  106. r = (((subtitle_color >> 16) & 0xff) * level) >> 8;
  107. g = (((subtitle_color >> 8) & 0xff) * level) >> 8;
  108. b = (((subtitle_color >> 0) & 0xff) * level) >> 8;
  109. rgba_palette[i] = b | (g << 8) | (r << 16) | ((alpha[i] * 17) << 24);
  110. color_used[palette[i]] = (i + 1);
  111. j--;
  112. } else {
  113. rgba_palette[i] = (rgba_palette[color_used[palette[i]] - 1] & 0x00ffffff) |
  114. ((alpha[i] * 17) << 24);
  115. }
  116. }
  117. }
  118. }
  119. static int decode_dvd_subtitles(AVSubtitle *sub_header,
  120. const uint8_t *buf, int buf_size)
  121. {
  122. int cmd_pos, pos, cmd, x1, y1, x2, y2, offset1, offset2, next_cmd_pos;
  123. uint8_t palette[4], alpha[4];
  124. int date;
  125. int i;
  126. int is_menu = 0;
  127. if (buf_size < 4)
  128. return -1;
  129. sub_header->rects = NULL;
  130. sub_header->num_rects = 0;
  131. sub_header->start_display_time = 0;
  132. sub_header->end_display_time = 0;
  133. cmd_pos = getbe16(buf + 2);
  134. while ((cmd_pos + 4) < buf_size) {
  135. date = getbe16(buf + cmd_pos);
  136. next_cmd_pos = getbe16(buf + cmd_pos + 2);
  137. #ifdef DEBUG
  138. av_log(NULL, AV_LOG_INFO, "cmd_pos=0x%04x next=0x%04x date=%d\n",
  139. cmd_pos, next_cmd_pos, date);
  140. #endif
  141. pos = cmd_pos + 4;
  142. offset1 = -1;
  143. offset2 = -1;
  144. x1 = y1 = x2 = y2 = 0;
  145. while (pos < buf_size) {
  146. cmd = buf[pos++];
  147. #ifdef DEBUG
  148. av_log(NULL, AV_LOG_INFO, "cmd=%02x\n", cmd);
  149. #endif
  150. switch(cmd) {
  151. case 0x00:
  152. /* menu subpicture */
  153. is_menu = 1;
  154. break;
  155. case 0x01:
  156. /* set start date */
  157. sub_header->start_display_time = (date << 10) / 90;
  158. break;
  159. case 0x02:
  160. /* set end date */
  161. sub_header->end_display_time = (date << 10) / 90;
  162. break;
  163. case 0x03:
  164. /* set palette */
  165. if ((buf_size - pos) < 2)
  166. goto fail;
  167. palette[3] = buf[pos] >> 4;
  168. palette[2] = buf[pos] & 0x0f;
  169. palette[1] = buf[pos + 1] >> 4;
  170. palette[0] = buf[pos + 1] & 0x0f;
  171. pos += 2;
  172. break;
  173. case 0x04:
  174. /* set alpha */
  175. if ((buf_size - pos) < 2)
  176. goto fail;
  177. alpha[3] = buf[pos] >> 4;
  178. alpha[2] = buf[pos] & 0x0f;
  179. alpha[1] = buf[pos + 1] >> 4;
  180. alpha[0] = buf[pos + 1] & 0x0f;
  181. pos += 2;
  182. #ifdef DEBUG
  183. av_log(NULL, AV_LOG_INFO, "alpha=%x%x%x%x\n", alpha[0],alpha[1],alpha[2],alpha[3]);
  184. #endif
  185. break;
  186. case 0x05:
  187. if ((buf_size - pos) < 6)
  188. goto fail;
  189. x1 = (buf[pos] << 4) | (buf[pos + 1] >> 4);
  190. x2 = ((buf[pos + 1] & 0x0f) << 8) | buf[pos + 2];
  191. y1 = (buf[pos + 3] << 4) | (buf[pos + 4] >> 4);
  192. y2 = ((buf[pos + 4] & 0x0f) << 8) | buf[pos + 5];
  193. #ifdef DEBUG
  194. av_log(NULL, AV_LOG_INFO, "x1=%d x2=%d y1=%d y2=%d\n",
  195. x1, x2, y1, y2);
  196. #endif
  197. pos += 6;
  198. break;
  199. case 0x06:
  200. if ((buf_size - pos) < 4)
  201. goto fail;
  202. offset1 = getbe16(buf + pos);
  203. offset2 = getbe16(buf + pos + 2);
  204. #ifdef DEBUG
  205. av_log(NULL, AV_LOG_INFO, "offset1=0x%04x offset2=0x%04x\n", offset1, offset2);
  206. #endif
  207. pos += 4;
  208. break;
  209. case 0xff:
  210. default:
  211. goto the_end;
  212. }
  213. }
  214. the_end:
  215. if (offset1 >= 0) {
  216. int w, h;
  217. uint8_t *bitmap;
  218. /* decode the bitmap */
  219. w = x2 - x1 + 1;
  220. if (w < 0)
  221. w = 0;
  222. h = y2 - y1;
  223. if (h < 0)
  224. h = 0;
  225. if (w > 0 && h > 0) {
  226. if (sub_header->rects != NULL) {
  227. for (i = 0; i < sub_header->num_rects; i++) {
  228. av_free(sub_header->rects[i].bitmap);
  229. av_free(sub_header->rects[i].rgba_palette);
  230. }
  231. av_freep(&sub_header->rects);
  232. sub_header->num_rects = 0;
  233. }
  234. bitmap = av_malloc(w * h);
  235. sub_header->rects = av_mallocz(sizeof(AVSubtitleRect));
  236. sub_header->num_rects = 1;
  237. sub_header->rects[0].rgba_palette = av_malloc(4 * 4);
  238. decode_rle(bitmap, w * 2, w, h / 2,
  239. buf, offset1 * 2, buf_size);
  240. decode_rle(bitmap + w, w * 2, w, h / 2,
  241. buf, offset2 * 2, buf_size);
  242. guess_palette(sub_header->rects[0].rgba_palette,
  243. palette, alpha, 0xffff00);
  244. sub_header->rects[0].x = x1;
  245. sub_header->rects[0].y = y1;
  246. sub_header->rects[0].w = w;
  247. sub_header->rects[0].h = h;
  248. sub_header->rects[0].nb_colors = 4;
  249. sub_header->rects[0].linesize = w;
  250. sub_header->rects[0].bitmap = bitmap;
  251. }
  252. }
  253. if (next_cmd_pos == cmd_pos)
  254. break;
  255. cmd_pos = next_cmd_pos;
  256. }
  257. if (sub_header->num_rects > 0)
  258. return is_menu;
  259. fail:
  260. return -1;
  261. }
  262. static int is_transp(const uint8_t *buf, int pitch, int n,
  263. const uint8_t *transp_color)
  264. {
  265. int i;
  266. for(i = 0; i < n; i++) {
  267. if (!transp_color[*buf])
  268. return 0;
  269. buf += pitch;
  270. }
  271. return 1;
  272. }
  273. /* return 0 if empty rectangle, 1 if non empty */
  274. static int find_smallest_bounding_rectangle(AVSubtitle *s)
  275. {
  276. uint8_t transp_color[256];
  277. int y1, y2, x1, x2, y, w, h, i;
  278. uint8_t *bitmap;
  279. if (s->num_rects == 0 || s->rects == NULL || s->rects[0].w <= 0 || s->rects[0].h <= 0)
  280. return 0;
  281. memset(transp_color, 0, 256);
  282. for(i = 0; i < s->rects[0].nb_colors; i++) {
  283. if ((s->rects[0].rgba_palette[i] >> 24) == 0)
  284. transp_color[i] = 1;
  285. }
  286. y1 = 0;
  287. while (y1 < s->rects[0].h && is_transp(s->rects[0].bitmap + y1 * s->rects[0].linesize,
  288. 1, s->rects[0].w, transp_color))
  289. y1++;
  290. if (y1 == s->rects[0].h) {
  291. av_freep(&s->rects[0].bitmap);
  292. s->rects[0].w = s->rects[0].h = 0;
  293. return 0;
  294. }
  295. y2 = s->rects[0].h - 1;
  296. while (y2 > 0 && is_transp(s->rects[0].bitmap + y2 * s->rects[0].linesize, 1,
  297. s->rects[0].w, transp_color))
  298. y2--;
  299. x1 = 0;
  300. while (x1 < (s->rects[0].w - 1) && is_transp(s->rects[0].bitmap + x1, s->rects[0].linesize,
  301. s->rects[0].h, transp_color))
  302. x1++;
  303. x2 = s->rects[0].w - 1;
  304. while (x2 > 0 && is_transp(s->rects[0].bitmap + x2, s->rects[0].linesize, s->rects[0].h,
  305. transp_color))
  306. x2--;
  307. w = x2 - x1 + 1;
  308. h = y2 - y1 + 1;
  309. bitmap = av_malloc(w * h);
  310. if (!bitmap)
  311. return 1;
  312. for(y = 0; y < h; y++) {
  313. memcpy(bitmap + w * y, s->rects[0].bitmap + x1 + (y1 + y) * s->rects[0].linesize, w);
  314. }
  315. av_freep(&s->rects[0].bitmap);
  316. s->rects[0].bitmap = bitmap;
  317. s->rects[0].linesize = w;
  318. s->rects[0].w = w;
  319. s->rects[0].h = h;
  320. s->rects[0].x += x1;
  321. s->rects[0].y += y1;
  322. return 1;
  323. }
  324. static int dvdsub_close_decoder(AVCodecContext *avctx)
  325. {
  326. return 0;
  327. }
  328. #ifdef DEBUG
  329. #undef fprintf
  330. static void ppm_save(const char *filename, uint8_t *bitmap, int w, int h,
  331. uint32_t *rgba_palette)
  332. {
  333. int x, y, v;
  334. FILE *f;
  335. f = fopen(filename, "w");
  336. if (!f) {
  337. perror(filename);
  338. exit(1);
  339. }
  340. fprintf(f, "P6\n"
  341. "%d %d\n"
  342. "%d\n",
  343. w, h, 255);
  344. for(y = 0; y < h; y++) {
  345. for(x = 0; x < w; x++) {
  346. v = rgba_palette[bitmap[y * w + x]];
  347. putc((v >> 16) & 0xff, f);
  348. putc((v >> 8) & 0xff, f);
  349. putc((v >> 0) & 0xff, f);
  350. }
  351. }
  352. fclose(f);
  353. }
  354. #endif
  355. static int dvdsub_decode(AVCodecContext *avctx,
  356. void *data, int *data_size,
  357. uint8_t *buf, int buf_size)
  358. {
  359. AVSubtitle *sub = (void *)data;
  360. int is_menu;
  361. is_menu = decode_dvd_subtitles(sub, buf, buf_size);
  362. if (is_menu < 0) {
  363. no_subtitle:
  364. *data_size = 0;
  365. return buf_size;
  366. }
  367. if (!is_menu && find_smallest_bounding_rectangle(sub) == 0)
  368. goto no_subtitle;
  369. #if defined(DEBUG)
  370. av_log(NULL, AV_LOG_INFO, "start=%d ms end =%d ms\n",
  371. sub->start_display_time,
  372. sub->end_display_time);
  373. ppm_save("/tmp/a.ppm", sub->rects[0].bitmap,
  374. sub->rects[0].w, sub->rects[0].h, sub->rects[0].rgba_palette);
  375. #endif
  376. *data_size = 1;
  377. return buf_size;
  378. }
  379. AVCodec dvdsub_decoder = {
  380. "dvdsub",
  381. CODEC_TYPE_SUBTITLE,
  382. CODEC_ID_DVD_SUBTITLE,
  383. sizeof(DVDSubContext),
  384. dvdsub_init_decoder,
  385. NULL,
  386. dvdsub_close_decoder,
  387. dvdsub_decode,
  388. };
  389. /* parser definition */
  390. typedef struct DVDSubParseContext {
  391. uint8_t *packet;
  392. int packet_len;
  393. int packet_index;
  394. } DVDSubParseContext;
  395. static int dvdsub_parse_init(AVCodecParserContext *s)
  396. {
  397. return 0;
  398. }
  399. static int dvdsub_parse(AVCodecParserContext *s,
  400. AVCodecContext *avctx,
  401. uint8_t **poutbuf, int *poutbuf_size,
  402. const uint8_t *buf, int buf_size)
  403. {
  404. DVDSubParseContext *pc = s->priv_data;
  405. if (pc->packet_index == 0) {
  406. if (buf_size < 2)
  407. return 0;
  408. pc->packet_len = (buf[0] << 8) | buf[1];
  409. av_freep(&pc->packet);
  410. pc->packet = av_malloc(pc->packet_len);
  411. }
  412. if (pc->packet) {
  413. if (pc->packet_index + buf_size <= pc->packet_len) {
  414. memcpy(pc->packet + pc->packet_index, buf, buf_size);
  415. pc->packet_index += buf_size;
  416. if (pc->packet_index >= pc->packet_len) {
  417. *poutbuf = pc->packet;
  418. *poutbuf_size = pc->packet_len;
  419. pc->packet_index = 0;
  420. return buf_size;
  421. }
  422. } else {
  423. /* erroneous size */
  424. pc->packet_index = 0;
  425. }
  426. }
  427. *poutbuf = NULL;
  428. *poutbuf_size = 0;
  429. return buf_size;
  430. }
  431. static void dvdsub_parse_close(AVCodecParserContext *s)
  432. {
  433. DVDSubParseContext *pc = s->priv_data;
  434. av_freep(&pc->packet);
  435. }
  436. AVCodecParser dvdsub_parser = {
  437. { CODEC_ID_DVD_SUBTITLE },
  438. sizeof(DVDSubParseContext),
  439. dvdsub_parse_init,
  440. dvdsub_parse,
  441. dvdsub_parse_close,
  442. };