1/* 2 * DVB subtitle encoding 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#include "bytestream.h" 23#include "colorspace.h" 24 25typedef struct DVBSubtitleContext { 26 int hide_state; 27 int object_version; 28} DVBSubtitleContext; 29 30#define PUTBITS2(val)\ 31{\ 32 bitbuf |= (val) << bitcnt;\ 33 bitcnt -= 2;\ 34 if (bitcnt < 0) {\ 35 bitcnt = 6;\ 36 *q++ = bitbuf;\ 37 bitbuf = 0;\ 38 }\ 39} 40 41static void dvb_encode_rle2(uint8_t **pq, 42 const uint8_t *bitmap, int linesize, 43 int w, int h) 44{ 45 uint8_t *q; 46 unsigned int bitbuf; 47 int bitcnt; 48 int x, y, len, x1, v, color; 49 50 q = *pq; 51 52 for(y = 0; y < h; y++) { 53 *q++ = 0x10; 54 bitbuf = 0; 55 bitcnt = 6; 56 57 x = 0; 58 while (x < w) { 59 x1 = x; 60 color = bitmap[x1++]; 61 while (x1 < w && bitmap[x1] == color) 62 x1++; 63 len = x1 - x; 64 if (color == 0 && len == 2) { 65 PUTBITS2(0); 66 PUTBITS2(0); 67 PUTBITS2(1); 68 } else if (len >= 3 && len <= 10) { 69 v = len - 3; 70 PUTBITS2(0); 71 PUTBITS2((v >> 2) | 2); 72 PUTBITS2(v & 3); 73 PUTBITS2(color); 74 } else if (len >= 12 && len <= 27) { 75 v = len - 12; 76 PUTBITS2(0); 77 PUTBITS2(0); 78 PUTBITS2(2); 79 PUTBITS2(v >> 2); 80 PUTBITS2(v & 3); 81 PUTBITS2(color); 82 } else if (len >= 29) { 83 /* length = 29 ... 284 */ 84 if (len > 284) 85 len = 284; 86 v = len - 29; 87 PUTBITS2(0); 88 PUTBITS2(0); 89 PUTBITS2(3); 90 PUTBITS2((v >> 6)); 91 PUTBITS2((v >> 4) & 3); 92 PUTBITS2((v >> 2) & 3); 93 PUTBITS2(v & 3); 94 PUTBITS2(color); 95 } else { 96 PUTBITS2(color); 97 if (color == 0) { 98 PUTBITS2(1); 99 } 100 len = 1; 101 } 102 x += len; 103 } 104 /* end of line */ 105 PUTBITS2(0); 106 PUTBITS2(0); 107 PUTBITS2(0); 108 if (bitcnt != 6) { 109 *q++ = bitbuf; 110 } 111 *q++ = 0xf0; 112 bitmap += linesize; 113 } 114 *pq = q; 115} 116 117#define PUTBITS4(val)\ 118{\ 119 bitbuf |= (val) << bitcnt;\ 120 bitcnt -= 4;\ 121 if (bitcnt < 0) {\ 122 bitcnt = 4;\ 123 *q++ = bitbuf;\ 124 bitbuf = 0;\ 125 }\ 126} 127 128/* some DVB decoders only implement 4 bits/pixel */ 129static void dvb_encode_rle4(uint8_t **pq, 130 const uint8_t *bitmap, int linesize, 131 int w, int h) 132{ 133 uint8_t *q; 134 unsigned int bitbuf; 135 int bitcnt; 136 int x, y, len, x1, v, color; 137 138 q = *pq; 139 140 for(y = 0; y < h; y++) { 141 *q++ = 0x11; 142 bitbuf = 0; 143 bitcnt = 4; 144 145 x = 0; 146 while (x < w) { 147 x1 = x; 148 color = bitmap[x1++]; 149 while (x1 < w && bitmap[x1] == color) 150 x1++; 151 len = x1 - x; 152 if (color == 0 && len == 2) { 153 PUTBITS4(0); 154 PUTBITS4(0xd); 155 } else if (color == 0 && (len >= 3 && len <= 9)) { 156 PUTBITS4(0); 157 PUTBITS4(len - 2); 158 } else if (len >= 4 && len <= 7) { 159 PUTBITS4(0); 160 PUTBITS4(8 + len - 4); 161 PUTBITS4(color); 162 } else if (len >= 9 && len <= 24) { 163 PUTBITS4(0); 164 PUTBITS4(0xe); 165 PUTBITS4(len - 9); 166 PUTBITS4(color); 167 } else if (len >= 25) { 168 if (len > 280) 169 len = 280; 170 v = len - 25; 171 PUTBITS4(0); 172 PUTBITS4(0xf); 173 PUTBITS4(v >> 4); 174 PUTBITS4(v & 0xf); 175 PUTBITS4(color); 176 } else { 177 PUTBITS4(color); 178 if (color == 0) { 179 PUTBITS4(0xc); 180 } 181 len = 1; 182 } 183 x += len; 184 } 185 /* end of line */ 186 PUTBITS4(0); 187 PUTBITS4(0); 188 if (bitcnt != 4) { 189 *q++ = bitbuf; 190 } 191 *q++ = 0xf0; 192 bitmap += linesize; 193 } 194 *pq = q; 195} 196 197static int encode_dvb_subtitles(DVBSubtitleContext *s, 198 uint8_t *outbuf, AVSubtitle *h) 199{ 200 uint8_t *q, *pseg_len; 201 int page_id, region_id, clut_id, object_id, i, bpp_index, page_state; 202 203 204 q = outbuf; 205 206 page_id = 1; 207 208 if (h->num_rects == 0 || h->rects == NULL) 209 return -1; 210 211 *q++ = 0x00; /* subtitle_stream_id */ 212 213 /* page composition segment */ 214 215 *q++ = 0x0f; /* sync_byte */ 216 *q++ = 0x10; /* segment_type */ 217 bytestream_put_be16(&q, page_id); 218 pseg_len = q; 219 q += 2; /* segment length */ 220 *q++ = 30; /* page_timeout (seconds) */ 221 if (s->hide_state) 222 page_state = 0; /* normal case */ 223 else 224 page_state = 2; /* mode change */ 225 /* page_version = 0 + page_state */ 226 *q++ = s->object_version | (page_state << 2) | 3; 227 228 for (region_id = 0; region_id < h->num_rects; region_id++) { 229 *q++ = region_id; 230 *q++ = 0xff; /* reserved */ 231 bytestream_put_be16(&q, h->rects[region_id]->x); /* left pos */ 232 bytestream_put_be16(&q, h->rects[region_id]->y); /* top pos */ 233 } 234 235 bytestream_put_be16(&pseg_len, q - pseg_len - 2); 236 237 if (!s->hide_state) { 238 for (clut_id = 0; clut_id < h->num_rects; clut_id++) { 239 240 /* CLUT segment */ 241 242 if (h->rects[clut_id]->nb_colors <= 4) { 243 /* 2 bpp, some decoders do not support it correctly */ 244 bpp_index = 0; 245 } else if (h->rects[clut_id]->nb_colors <= 16) { 246 /* 4 bpp, standard encoding */ 247 bpp_index = 1; 248 } else { 249 return -1; 250 } 251 252 *q++ = 0x0f; /* sync byte */ 253 *q++ = 0x12; /* CLUT definition segment */ 254 bytestream_put_be16(&q, page_id); 255 pseg_len = q; 256 q += 2; /* segment length */ 257 *q++ = clut_id; 258 *q++ = (0 << 4) | 0xf; /* version = 0 */ 259 260 for(i = 0; i < h->rects[clut_id]->nb_colors; i++) { 261 *q++ = i; /* clut_entry_id */ 262 *q++ = (1 << (7 - bpp_index)) | (0xf << 1) | 1; /* 2 bits/pixel full range */ 263 { 264 int a, r, g, b; 265 uint32_t x= ((uint32_t*)h->rects[clut_id]->pict.data[1])[i]; 266 a = (x >> 24) & 0xff; 267 r = (x >> 16) & 0xff; 268 g = (x >> 8) & 0xff; 269 b = (x >> 0) & 0xff; 270 271 *q++ = RGB_TO_Y_CCIR(r, g, b); 272 *q++ = RGB_TO_V_CCIR(r, g, b, 0); 273 *q++ = RGB_TO_U_CCIR(r, g, b, 0); 274 *q++ = 255 - a; 275 } 276 } 277 278 bytestream_put_be16(&pseg_len, q - pseg_len - 2); 279 } 280 } 281 282 for (region_id = 0; region_id < h->num_rects; region_id++) { 283 284 /* region composition segment */ 285 286 if (h->rects[region_id]->nb_colors <= 4) { 287 /* 2 bpp, some decoders do not support it correctly */ 288 bpp_index = 0; 289 } else if (h->rects[region_id]->nb_colors <= 16) { 290 /* 4 bpp, standard encoding */ 291 bpp_index = 1; 292 } else { 293 return -1; 294 } 295 296 *q++ = 0x0f; /* sync_byte */ 297 *q++ = 0x11; /* segment_type */ 298 bytestream_put_be16(&q, page_id); 299 pseg_len = q; 300 q += 2; /* segment length */ 301 *q++ = region_id; 302 *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */ 303 bytestream_put_be16(&q, h->rects[region_id]->w); /* region width */ 304 bytestream_put_be16(&q, h->rects[region_id]->h); /* region height */ 305 *q++ = ((1 + bpp_index) << 5) | ((1 + bpp_index) << 2) | 0x03; 306 *q++ = region_id; /* clut_id == region_id */ 307 *q++ = 0; /* 8 bit fill colors */ 308 *q++ = 0x03; /* 4 bit and 2 bit fill colors */ 309 310 if (!s->hide_state) { 311 bytestream_put_be16(&q, region_id); /* object_id == region_id */ 312 *q++ = (0 << 6) | (0 << 4); 313 *q++ = 0; 314 *q++ = 0xf0; 315 *q++ = 0; 316 } 317 318 bytestream_put_be16(&pseg_len, q - pseg_len - 2); 319 } 320 321 if (!s->hide_state) { 322 323 for (object_id = 0; object_id < h->num_rects; object_id++) { 324 /* Object Data segment */ 325 326 if (h->rects[object_id]->nb_colors <= 4) { 327 /* 2 bpp, some decoders do not support it correctly */ 328 bpp_index = 0; 329 } else if (h->rects[object_id]->nb_colors <= 16) { 330 /* 4 bpp, standard encoding */ 331 bpp_index = 1; 332 } else { 333 return -1; 334 } 335 336 *q++ = 0x0f; /* sync byte */ 337 *q++ = 0x13; 338 bytestream_put_be16(&q, page_id); 339 pseg_len = q; 340 q += 2; /* segment length */ 341 342 bytestream_put_be16(&q, object_id); 343 *q++ = (s->object_version << 4) | (0 << 2) | (0 << 1) | 1; /* version = 0, 344 onject_coding_method, 345 non_modifying_color_flag */ 346 { 347 uint8_t *ptop_field_len, *pbottom_field_len, *top_ptr, *bottom_ptr; 348 void (*dvb_encode_rle)(uint8_t **pq, 349 const uint8_t *bitmap, int linesize, 350 int w, int h); 351 ptop_field_len = q; 352 q += 2; 353 pbottom_field_len = q; 354 q += 2; 355 356 if (bpp_index == 0) 357 dvb_encode_rle = dvb_encode_rle2; 358 else 359 dvb_encode_rle = dvb_encode_rle4; 360 361 top_ptr = q; 362 dvb_encode_rle(&q, h->rects[object_id]->pict.data[0], h->rects[object_id]->w * 2, 363 h->rects[object_id]->w, h->rects[object_id]->h >> 1); 364 bottom_ptr = q; 365 dvb_encode_rle(&q, h->rects[object_id]->pict.data[0] + h->rects[object_id]->w, 366 h->rects[object_id]->w * 2, h->rects[object_id]->w, 367 h->rects[object_id]->h >> 1); 368 369 bytestream_put_be16(&ptop_field_len, bottom_ptr - top_ptr); 370 bytestream_put_be16(&pbottom_field_len, q - bottom_ptr); 371 } 372 373 bytestream_put_be16(&pseg_len, q - pseg_len - 2); 374 } 375 } 376 377 /* end of display set segment */ 378 379 *q++ = 0x0f; /* sync_byte */ 380 *q++ = 0x80; /* segment_type */ 381 bytestream_put_be16(&q, page_id); 382 pseg_len = q; 383 q += 2; /* segment length */ 384 385 bytestream_put_be16(&pseg_len, q - pseg_len - 2); 386 387 *q++ = 0xff; /* end of PES data */ 388 389 s->object_version = (s->object_version + 1) & 0xf; 390 s->hide_state = !s->hide_state; 391 return q - outbuf; 392} 393 394static int dvbsub_encode(AVCodecContext *avctx, 395 unsigned char *buf, int buf_size, void *data) 396{ 397 DVBSubtitleContext *s = avctx->priv_data; 398 AVSubtitle *sub = data; 399 int ret; 400 401 ret = encode_dvb_subtitles(s, buf, sub); 402 return ret; 403} 404 405AVCodec dvbsub_encoder = { 406 "dvbsub", 407 CODEC_TYPE_SUBTITLE, 408 CODEC_ID_DVB_SUBTITLE, 409 sizeof(DVBSubtitleContext), 410 NULL, 411 dvbsub_encode, 412 .long_name = NULL_IF_CONFIG_SMALL("DVB subtitles"), 413}; 414