Libav
dvdsubenc.c
Go to the documentation of this file.
1 /*
2  * DVD subtitle encoding
3  * Copyright (c) 2005 Wolfram Gloger
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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 
24 #undef NDEBUG
25 #include <assert.h>
26 
27 // ncnt is the nibble counter
28 #define PUTNIBBLE(val)\
29 do {\
30  if (ncnt++ & 1)\
31  *q++ = bitbuf | ((val) & 0x0f);\
32  else\
33  bitbuf = (val) << 4;\
34 } while(0)
35 
36 static void dvd_encode_rle(uint8_t **pq,
37  const uint8_t *bitmap, int linesize,
38  int w, int h,
39  const int cmap[256])
40 {
41  uint8_t *q;
42  unsigned int bitbuf = 0;
43  int ncnt;
44  int x, y, len, color;
45 
46  q = *pq;
47 
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  assert(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 
86  *pq = q;
87 }
88 
89 static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,
90  const AVSubtitle *h)
91 {
92  uint8_t *q, *qq;
93  int object_id;
94  int offset1[20], offset2[20];
95  int i, imax, color, alpha, rects = h->num_rects;
96  unsigned long hmax;
97  unsigned long hist[256];
98  int cmap[256];
99 
100  if (rects == 0 || !h->rects)
101  return -1;
102  if (rects > 20)
103  rects = 20;
104 
105  // analyze bitmaps, compress to 4 colors
106  for (i=0; i<256; ++i) {
107  hist[i] = 0;
108  cmap[i] = 0;
109  }
110  for (object_id = 0; object_id < rects; object_id++) {
111 #if FF_API_AVPICTURE
113  if (!h->rects[object_id]->data[0]) {
114  AVSubtitleRect *rect = h->rects[object_id];
115  int j;
116  for (j = 0; j < 4; j++) {
117  rect->data[j] = rect->pict.data[j];
118  rect->linesize[j] = rect->pict.linesize[j];
119  }
120  }
122 #endif
123 
124  for (i=0; i<h->rects[object_id]->w*h->rects[object_id]->h; ++i) {
125  color = h->rects[object_id]->data[0][i];
126  // only count non-transparent pixels
127  alpha = ((uint32_t *)h->rects[object_id]->data[1])[color] >> 24;
128  hist[color] += alpha;
129  }
130  }
131  for (color=3;; --color) {
132  hmax = 0;
133  imax = 0;
134  for (i=0; i<256; ++i)
135  if (hist[i] > hmax) {
136  imax = i;
137  hmax = hist[i];
138  }
139  if (hmax == 0)
140  break;
141  if (color == 0)
142  color = 3;
143  av_log(NULL, AV_LOG_DEBUG, "dvd_subtitle hist[%d]=%ld -> col %d\n",
144  imax, hist[imax], color);
145  cmap[imax] = color;
146  hist[imax] = 0;
147  }
148 
149 
150  // encode data block
151  q = outbuf + 4;
152  for (object_id = 0; object_id < rects; object_id++) {
153  offset1[object_id] = q - outbuf;
154  // worst case memory requirement: 1 nibble per pixel..
155  if ((q - outbuf) + h->rects[object_id]->w*h->rects[object_id]->h/2
156  + 17*rects + 21 > outbuf_size) {
157  av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n");
158  return -1;
159  }
160  dvd_encode_rle(&q, h->rects[object_id]->data[0],
161  h->rects[object_id]->w*2,
162  h->rects[object_id]->w, h->rects[object_id]->h >> 1,
163  cmap);
164  offset2[object_id] = q - outbuf;
165  dvd_encode_rle(&q, h->rects[object_id]->data[0] + h->rects[object_id]->w,
166  h->rects[object_id]->w*2,
167  h->rects[object_id]->w, h->rects[object_id]->h >> 1,
168  cmap);
169  }
170 
171  // set data packet size
172  qq = outbuf + 2;
173  bytestream_put_be16(&qq, q - outbuf);
174 
175  // send start display command
176  bytestream_put_be16(&q, (h->start_display_time*90) >> 10);
177  bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12*rects + 2);
178  *q++ = 0x03; // palette - 4 nibbles
179  *q++ = 0x03; *q++ = 0x7f;
180  *q++ = 0x04; // alpha - 4 nibbles
181  *q++ = 0xf0; *q++ = 0x00;
182  //*q++ = 0x0f; *q++ = 0xff;
183 
184  // XXX not sure if more than one rect can really be encoded..
185  // 12 bytes per rect
186  for (object_id = 0; object_id < rects; object_id++) {
187  int x2 = h->rects[object_id]->x + h->rects[object_id]->w - 1;
188  int y2 = h->rects[object_id]->y + h->rects[object_id]->h - 1;
189 
190  *q++ = 0x05;
191  // x1 x2 -> 6 nibbles
192  *q++ = h->rects[object_id]->x >> 4;
193  *q++ = (h->rects[object_id]->x << 4) | ((x2 >> 8) & 0xf);
194  *q++ = x2;
195  // y1 y2 -> 6 nibbles
196  *q++ = h->rects[object_id]->y >> 4;
197  *q++ = (h->rects[object_id]->y << 4) | ((y2 >> 8) & 0xf);
198  *q++ = y2;
199 
200  *q++ = 0x06;
201  // offset1, offset2
202  bytestream_put_be16(&q, offset1[object_id]);
203  bytestream_put_be16(&q, offset2[object_id]);
204  }
205  *q++ = 0x01; // start command
206  *q++ = 0xff; // terminating command
207 
208  // send stop display command last
209  bytestream_put_be16(&q, (h->end_display_time*90) >> 10);
210  bytestream_put_be16(&q, (q - outbuf) - 2 /*+ 4*/);
211  *q++ = 0x02; // set end
212  *q++ = 0xff; // terminating command
213 
214  qq = outbuf;
215  bytestream_put_be16(&qq, q - outbuf);
216 
217  av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%td\n", q - outbuf);
218  return q - outbuf;
219 }
220 
221 static int dvdsub_encode(AVCodecContext *avctx,
222  unsigned char *buf, int buf_size,
223  const AVSubtitle *sub)
224 {
225  //DVDSubtitleContext *s = avctx->priv_data;
226  int ret;
227 
228  ret = encode_dvd_subtitles(buf, buf_size, sub);
229  return ret;
230 }
231 
233  .name = "dvdsub",
234  .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
235  .type = AVMEDIA_TYPE_SUBTITLE,
237  .encode_sub = dvdsub_encode,
238 };
int x
top left corner of pict, undefined when pict is not set
Definition: avcodec.h:3426
av_log(ac->avr, AV_LOG_TRACE, "%d samples - audio_convert: %s to %s (%s)\, len, av_get_sample_fmt_name(ac->in_fmt), av_get_sample_fmt_name(ac->out_fmt), use_generic ? ac->func_descr_generic :ac->func_descr)
unsigned num_rects
Definition: avcodec.h:3463
AVCodec.
Definition: avcodec.h:3120
static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size, const AVSubtitle *h)
Definition: dvdsubenc.c:89
attribute_deprecated AVPicture pict
Definition: avcodec.h:3437
AVSubtitleRect ** rects
Definition: avcodec.h:3464
int w
width of pict, undefined when pict is not set
Definition: avcodec.h:3428
uint8_t
static void dvd_encode_rle(uint8_t **pq, const uint8_t *bitmap, int linesize, int w, int h, const int cmap[256])
Definition: dvdsubenc.c:36
attribute_deprecated int linesize[AV_NUM_DATA_POINTERS]
number of bytes per line
Definition: avcodec.h:3394
int h
height of pict, undefined when pict is not set
Definition: avcodec.h:3429
static int dvdsub_encode(AVCodecContext *avctx, unsigned char *buf, int buf_size, const AVSubtitle *sub)
Definition: dvdsubenc.c:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:124
int y
top left corner of pict, undefined when pict is not set
Definition: avcodec.h:3427
AVCodec ff_dvdsub_encoder
Definition: dvdsubenc.c:232
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:148
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:145
const char * name
Name of the codec implementation.
Definition: avcodec.h:3127
uint32_t end_display_time
Definition: avcodec.h:3462
int linesize[4]
Definition: avcodec.h:3444
attribute_deprecated uint8_t * data[AV_NUM_DATA_POINTERS]
Definition: avcodec.h:3392
uint8_t * data[4]
data+linesize for the bitmap of this subtitle.
Definition: avcodec.h:3443
NULL
Definition: eval.c:55
Libavcodec external API header.
main external API structure.
Definition: avcodec.h:1409
static const uint8_t color[NB_LEVELS]
Definition: log.c:62
#define PUTNIBBLE(val)
Definition: dvdsubenc.c:28
#define FF_DISABLE_DEPRECATION_WARNINGS
Definition: internal.h:77
uint32_t start_display_time
Definition: avcodec.h:3461
#define FF_ENABLE_DEPRECATION_WARNINGS
Definition: internal.h:78
int len