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.

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