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.

444 lines
14KB

  1. /*
  2. * DVD subtitle encoding
  3. * Copyright (c) 2005 Wolfram Gloger
  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. #include "bytestream.h"
  23. #include "internal.h"
  24. #include "libavutil/avassert.h"
  25. #include "libavutil/bprint.h"
  26. #include "libavutil/imgutils.h"
  27. typedef struct {
  28. uint32_t global_palette[16];
  29. } DVDSubtitleContext;
  30. // ncnt is the nibble counter
  31. #define PUTNIBBLE(val)\
  32. do {\
  33. if (ncnt++ & 1)\
  34. *q++ = bitbuf | ((val) & 0x0f);\
  35. else\
  36. bitbuf = (val) << 4;\
  37. } while(0)
  38. static void dvd_encode_rle(uint8_t **pq,
  39. const uint8_t *bitmap, int linesize,
  40. int w, int h,
  41. const int cmap[256])
  42. {
  43. uint8_t *q;
  44. unsigned int bitbuf = 0;
  45. int ncnt;
  46. int x, y, len, color;
  47. q = *pq;
  48. for (y = 0; y < h; ++y) {
  49. ncnt = 0;
  50. for(x = 0; x < w; x += len) {
  51. color = bitmap[x];
  52. for (len=1; x+len < w; ++len)
  53. if (bitmap[x+len] != color)
  54. break;
  55. color = cmap[color];
  56. av_assert0(color < 4);
  57. if (len < 0x04) {
  58. PUTNIBBLE((len << 2)|color);
  59. } else if (len < 0x10) {
  60. PUTNIBBLE(len >> 2);
  61. PUTNIBBLE((len << 2)|color);
  62. } else if (len < 0x40) {
  63. PUTNIBBLE(0);
  64. PUTNIBBLE(len >> 2);
  65. PUTNIBBLE((len << 2)|color);
  66. } else if (x+len == w) {
  67. PUTNIBBLE(0);
  68. PUTNIBBLE(0);
  69. PUTNIBBLE(0);
  70. PUTNIBBLE(color);
  71. } else {
  72. if (len > 0xff)
  73. len = 0xff;
  74. PUTNIBBLE(0);
  75. PUTNIBBLE(len >> 6);
  76. PUTNIBBLE(len >> 2);
  77. PUTNIBBLE((len << 2)|color);
  78. }
  79. }
  80. /* end of line */
  81. if (ncnt & 1)
  82. PUTNIBBLE(0);
  83. bitmap += linesize;
  84. }
  85. *pq = q;
  86. }
  87. static int color_distance(uint32_t a, uint32_t b)
  88. {
  89. int r = 0, d, i;
  90. int alpha_a = 8, alpha_b = 8;
  91. for (i = 24; i >= 0; i -= 8) {
  92. d = alpha_a * (int)((a >> i) & 0xFF) -
  93. alpha_b * (int)((b >> i) & 0xFF);
  94. r += d * d;
  95. alpha_a = a >> 28;
  96. alpha_b = b >> 28;
  97. }
  98. return r;
  99. }
  100. /**
  101. * Count colors used in a rectangle, quantizing alpha and grouping by
  102. * nearest global palette entry.
  103. */
  104. static void count_colors(AVCodecContext *avctx, unsigned hits[33],
  105. const AVSubtitleRect *r)
  106. {
  107. DVDSubtitleContext *dvdc = avctx->priv_data;
  108. unsigned count[256] = { 0 };
  109. uint32_t *palette = (uint32_t *)r->pict.data[1];
  110. uint32_t color;
  111. int x, y, i, j, match, d, best_d, av_uninit(best_j);
  112. uint8_t *p = r->pict.data[0];
  113. for (y = 0; y < r->h; y++) {
  114. for (x = 0; x < r->w; x++)
  115. count[*(p++)]++;
  116. p += r->pict.linesize[0] - r->w;
  117. }
  118. for (i = 0; i < 256; i++) {
  119. if (!count[i]) /* avoid useless search */
  120. continue;
  121. color = palette[i];
  122. /* 0: transparent, 1-16: semi-transparent, 17-33 opaque */
  123. match = color < 0x33000000 ? 0 : color < 0xCC000000 ? 1 : 17;
  124. if (match) {
  125. best_d = INT_MAX;
  126. for (j = 0; j < 16; j++) {
  127. d = color_distance(0xFF000000 | color,
  128. 0xFF000000 | dvdc->global_palette[j]);
  129. if (d < best_d) {
  130. best_d = d;
  131. best_j = j;
  132. }
  133. }
  134. match += best_j;
  135. }
  136. hits[match] += count[i];
  137. }
  138. }
  139. static void select_palette(AVCodecContext *avctx, int out_palette[4],
  140. int out_alpha[4], unsigned hits[33])
  141. {
  142. DVDSubtitleContext *dvdc = avctx->priv_data;
  143. int i, j, bright, mult;
  144. uint32_t color;
  145. int selected[4] = { 0 };
  146. uint32_t pseudopal[33] = { 0 };
  147. uint32_t refcolor[3] = { 0x00000000, 0xFFFFFFFF, 0xFF000000 };
  148. /* Bonus for transparent: if the rectangle fits tightly the text, the
  149. background color can be quite rare, but it would be ugly without it */
  150. hits[0] *= 16;
  151. /* Bonus for bright colors */
  152. for (i = 0; i < 16; i++) {
  153. if (!(hits[1 + i] + hits[17 + i]))
  154. continue; /* skip unused colors to gain time */
  155. color = dvdc->global_palette[i];
  156. bright = 0;
  157. for (j = 0; j < 3; j++, color >>= 8)
  158. bright += (color & 0xFF) < 0x40 || (color & 0xFF) >= 0xC0;
  159. mult = 2 + FFMIN(bright, 2);
  160. hits[ 1 + i] *= mult;
  161. hits[17 + i] *= mult;
  162. }
  163. /* Select four most frequent colors */
  164. for (i = 0; i < 4; i++) {
  165. for (j = 0; j < 33; j++)
  166. if (hits[j] > hits[selected[i]])
  167. selected[i] = j;
  168. hits[selected[i]] = 0;
  169. }
  170. /* Order the colors like in most DVDs:
  171. 0: background, 1: foreground, 2: outline */
  172. for (i = 0; i < 16; i++) {
  173. pseudopal[ 1 + i] = 0x80000000 | dvdc->global_palette[i];
  174. pseudopal[17 + i] = 0xFF000000 | dvdc->global_palette[i];
  175. }
  176. for (i = 0; i < 3; i++) {
  177. int best_d = color_distance(refcolor[i], pseudopal[selected[i]]);
  178. for (j = i + 1; j < 4; j++) {
  179. int d = color_distance(refcolor[i], pseudopal[selected[j]]);
  180. if (d < best_d) {
  181. FFSWAP(int, selected[i], selected[j]);
  182. best_d = d;
  183. }
  184. }
  185. }
  186. /* Output */
  187. for (i = 0; i < 4; i++) {
  188. out_palette[i] = selected[i] ? (selected[i] - 1) & 0xF : 0;
  189. out_alpha [i] = !selected[i] ? 0 : selected[i] < 17 ? 0x80 : 0xFF;
  190. }
  191. }
  192. static void build_color_map(AVCodecContext *avctx, int cmap[],
  193. const uint32_t palette[],
  194. const int out_palette[], unsigned int const out_alpha[])
  195. {
  196. DVDSubtitleContext *dvdc = avctx->priv_data;
  197. int i, j, d, best_d;
  198. uint32_t pseudopal[4];
  199. for (i = 0; i < 4; i++)
  200. pseudopal[i] = (out_alpha[i] << 24) |
  201. dvdc->global_palette[out_palette[i]];
  202. for (i = 0; i < 256; i++) {
  203. best_d = INT_MAX;
  204. for (j = 0; j < 4; j++) {
  205. d = color_distance(pseudopal[j], palette[i]);
  206. if (d < best_d) {
  207. cmap[i] = j;
  208. best_d = d;
  209. }
  210. }
  211. }
  212. }
  213. static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[])
  214. {
  215. int x, y;
  216. uint8_t *p, *q;
  217. p = src->pict.data[0];
  218. q = dst->pict.data[0] + (src->x - dst->x) +
  219. (src->y - dst->y) * dst->pict.linesize[0];
  220. for (y = 0; y < src->h; y++) {
  221. for (x = 0; x < src->w; x++)
  222. *(q++) = cmap[*(p++)];
  223. p += src->pict.linesize[0] - src->w;
  224. q += dst->pict.linesize[0] - src->w;
  225. }
  226. }
  227. static int encode_dvd_subtitles(AVCodecContext *avctx,
  228. uint8_t *outbuf, int outbuf_size,
  229. const AVSubtitle *h)
  230. {
  231. DVDSubtitleContext *dvdc = avctx->priv_data;
  232. uint8_t *q, *qq;
  233. int offset1, offset2;
  234. int i, rects = h->num_rects, ret;
  235. unsigned global_palette_hits[33] = { 0 };
  236. int cmap[256];
  237. int out_palette[4];
  238. int out_alpha[4];
  239. AVSubtitleRect vrect;
  240. uint8_t *vrect_data = NULL;
  241. int x2, y2;
  242. if (rects == 0 || h->rects == NULL)
  243. return AVERROR(EINVAL);
  244. for (i = 0; i < rects; i++)
  245. if (h->rects[i]->type != SUBTITLE_BITMAP) {
  246. av_log(avctx, AV_LOG_ERROR, "Bitmap subtitle required\n");
  247. return AVERROR(EINVAL);
  248. }
  249. vrect = *h->rects[0];
  250. if (rects > 1) {
  251. /* DVD subtitles can have only one rectangle: build a virtual
  252. rectangle containing all actual rectangles.
  253. The data of the rectangles will be copied later, when the palette
  254. is decided, because the rectangles may have different palettes. */
  255. int xmin = h->rects[0]->x, xmax = xmin + h->rects[0]->w;
  256. int ymin = h->rects[0]->y, ymax = ymin + h->rects[0]->h;
  257. for (i = 1; i < rects; i++) {
  258. xmin = FFMIN(xmin, h->rects[i]->x);
  259. ymin = FFMIN(ymin, h->rects[i]->y);
  260. xmax = FFMAX(xmax, h->rects[i]->x + h->rects[i]->w);
  261. ymax = FFMAX(ymax, h->rects[i]->y + h->rects[i]->h);
  262. }
  263. vrect.x = xmin;
  264. vrect.y = ymin;
  265. vrect.w = xmax - xmin;
  266. vrect.h = ymax - ymin;
  267. if ((ret = av_image_check_size(vrect.w, vrect.h, 0, avctx)) < 0)
  268. return ret;
  269. /* Count pixels outside the virtual rectangle as transparent */
  270. global_palette_hits[0] = vrect.w * vrect.h;
  271. for (i = 0; i < rects; i++)
  272. global_palette_hits[0] -= h->rects[i]->w * h->rects[i]->h;
  273. }
  274. for (i = 0; i < rects; i++)
  275. count_colors(avctx, global_palette_hits, h->rects[i]);
  276. select_palette(avctx, out_palette, out_alpha, global_palette_hits);
  277. if (rects > 1) {
  278. if (!(vrect_data = av_calloc(vrect.w, vrect.h)))
  279. return AVERROR(ENOMEM);
  280. vrect.pict.data [0] = vrect_data;
  281. vrect.pict.linesize[0] = vrect.w;
  282. for (i = 0; i < rects; i++) {
  283. build_color_map(avctx, cmap, (uint32_t *)h->rects[i]->pict.data[1],
  284. out_palette, out_alpha);
  285. copy_rectangle(&vrect, h->rects[i], cmap);
  286. }
  287. for (i = 0; i < 4; i++)
  288. cmap[i] = i;
  289. } else {
  290. build_color_map(avctx, cmap, (uint32_t *)h->rects[0]->pict.data[1],
  291. out_palette, out_alpha);
  292. }
  293. av_log(avctx, AV_LOG_DEBUG, "Selected palette:");
  294. for (i = 0; i < 4; i++)
  295. av_log(avctx, AV_LOG_DEBUG, " 0x%06x@@%02x (0x%x,0x%x)",
  296. dvdc->global_palette[out_palette[i]], out_alpha[i],
  297. out_palette[i], out_alpha[i] >> 4);
  298. av_log(avctx, AV_LOG_DEBUG, "\n");
  299. // encode data block
  300. q = outbuf + 4;
  301. offset1 = q - outbuf;
  302. // worst case memory requirement: 1 nibble per pixel..
  303. if ((q - outbuf) + vrect.w * vrect.h / 2 + 17 + 21 > outbuf_size) {
  304. av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n");
  305. ret = AVERROR_BUFFER_TOO_SMALL;
  306. goto fail;
  307. }
  308. dvd_encode_rle(&q, vrect.pict.data[0], vrect.w * 2,
  309. vrect.w, (vrect.h + 1) >> 1, cmap);
  310. offset2 = q - outbuf;
  311. dvd_encode_rle(&q, vrect.pict.data[0] + vrect.w, vrect.w * 2,
  312. vrect.w, vrect.h >> 1, cmap);
  313. // set data packet size
  314. qq = outbuf + 2;
  315. bytestream_put_be16(&qq, q - outbuf);
  316. // send start display command
  317. bytestream_put_be16(&q, (h->start_display_time*90) >> 10);
  318. bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12 + 2);
  319. *q++ = 0x03; // palette - 4 nibbles
  320. *q++ = (out_palette[3] << 4) | out_palette[2];
  321. *q++ = (out_palette[1] << 4) | out_palette[0];
  322. *q++ = 0x04; // alpha - 4 nibbles
  323. *q++ = (out_alpha[3] & 0xF0) | (out_alpha[2] >> 4);
  324. *q++ = (out_alpha[1] & 0xF0) | (out_alpha[0] >> 4);
  325. // 12 bytes per rect
  326. x2 = vrect.x + vrect.w - 1;
  327. y2 = vrect.y + vrect.h - 1;
  328. *q++ = 0x05;
  329. // x1 x2 -> 6 nibbles
  330. *q++ = vrect.x >> 4;
  331. *q++ = (vrect.x << 4) | ((x2 >> 8) & 0xf);
  332. *q++ = x2;
  333. // y1 y2 -> 6 nibbles
  334. *q++ = vrect.y >> 4;
  335. *q++ = (vrect.y << 4) | ((y2 >> 8) & 0xf);
  336. *q++ = y2;
  337. *q++ = 0x06;
  338. // offset1, offset2
  339. bytestream_put_be16(&q, offset1);
  340. bytestream_put_be16(&q, offset2);
  341. *q++ = 0x01; // start command
  342. *q++ = 0xff; // terminating command
  343. // send stop display command last
  344. bytestream_put_be16(&q, (h->end_display_time*90) >> 10);
  345. bytestream_put_be16(&q, (q - outbuf) - 2 /*+ 4*/);
  346. *q++ = 0x02; // set end
  347. *q++ = 0xff; // terminating command
  348. qq = outbuf;
  349. bytestream_put_be16(&qq, q - outbuf);
  350. av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%"PTRDIFF_SPECIFIER"\n", q - outbuf);
  351. ret = q - outbuf;
  352. fail:
  353. av_free(vrect_data);
  354. return ret;
  355. }
  356. static int dvdsub_init(AVCodecContext *avctx)
  357. {
  358. DVDSubtitleContext *dvdc = avctx->priv_data;
  359. static const uint32_t default_palette[16] = {
  360. 0x000000, 0x0000FF, 0x00FF00, 0xFF0000,
  361. 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF,
  362. 0x808000, 0x8080FF, 0x800080, 0x80FF80,
  363. 0x008080, 0xFF8080, 0x555555, 0xAAAAAA,
  364. };
  365. AVBPrint extradata;
  366. int i, ret;
  367. av_assert0(sizeof(dvdc->global_palette) == sizeof(default_palette));
  368. memcpy(dvdc->global_palette, default_palette, sizeof(dvdc->global_palette));
  369. av_bprint_init(&extradata, 0, 1);
  370. if (avctx->width && avctx->height)
  371. av_bprintf(&extradata, "size: %dx%d\n", avctx->width, avctx->height);
  372. av_bprintf(&extradata, "palette:");
  373. for (i = 0; i < 16; i++)
  374. av_bprintf(&extradata, " %06"PRIx32"%c",
  375. dvdc->global_palette[i] & 0xFFFFFF, i < 15 ? ',' : '\n');
  376. ret = avpriv_bprint_to_extradata(avctx, &extradata);
  377. if (ret < 0)
  378. return ret;
  379. return 0;
  380. }
  381. static int dvdsub_encode(AVCodecContext *avctx,
  382. unsigned char *buf, int buf_size,
  383. const AVSubtitle *sub)
  384. {
  385. //DVDSubtitleContext *s = avctx->priv_data;
  386. int ret;
  387. ret = encode_dvd_subtitles(avctx, buf, buf_size, sub);
  388. return ret;
  389. }
  390. AVCodec ff_dvdsub_encoder = {
  391. .name = "dvdsub",
  392. .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
  393. .type = AVMEDIA_TYPE_SUBTITLE,
  394. .id = AV_CODEC_ID_DVD_SUBTITLE,
  395. .init = dvdsub_init,
  396. .encode_sub = dvdsub_encode,
  397. .priv_data_size = sizeof(DVDSubtitleContext),
  398. };