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.

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