00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "avcodec.h"
00022 #include "bytestream.h"
00023
00024 #undef NDEBUG
00025 #include <assert.h>
00026
00027
00028 #define PUTNIBBLE(val)\
00029 do {\
00030 if (ncnt++ & 1)\
00031 *q++ = bitbuf | ((val) & 0x0f);\
00032 else\
00033 bitbuf = (val) << 4;\
00034 } while(0)
00035
00036 static void dvd_encode_rle(uint8_t **pq,
00037 const uint8_t *bitmap, int linesize,
00038 int w, int h,
00039 const int cmap[256])
00040 {
00041 uint8_t *q;
00042 unsigned int bitbuf = 0;
00043 int ncnt;
00044 int x, y, len, color;
00045
00046 q = *pq;
00047
00048 for (y = 0; y < h; ++y) {
00049 ncnt = 0;
00050 for(x = 0; x < w; x += len) {
00051 color = bitmap[x];
00052 for (len=1; x+len < w; ++len)
00053 if (bitmap[x+len] != color)
00054 break;
00055 color = cmap[color];
00056 assert(color < 4);
00057 if (len < 0x04) {
00058 PUTNIBBLE((len << 2)|color);
00059 } else if (len < 0x10) {
00060 PUTNIBBLE(len >> 2);
00061 PUTNIBBLE((len << 2)|color);
00062 } else if (len < 0x40) {
00063 PUTNIBBLE(0);
00064 PUTNIBBLE(len >> 2);
00065 PUTNIBBLE((len << 2)|color);
00066 } else if (x+len == w) {
00067 PUTNIBBLE(0);
00068 PUTNIBBLE(0);
00069 PUTNIBBLE(0);
00070 PUTNIBBLE(color);
00071 } else {
00072 if (len > 0xff)
00073 len = 0xff;
00074 PUTNIBBLE(0);
00075 PUTNIBBLE(len >> 6);
00076 PUTNIBBLE(len >> 2);
00077 PUTNIBBLE((len << 2)|color);
00078 }
00079 }
00080
00081 if (ncnt & 1)
00082 PUTNIBBLE(0);
00083 bitmap += linesize;
00084 }
00085
00086 *pq = q;
00087 }
00088
00089 static int encode_dvd_subtitles(uint8_t *outbuf, int outbuf_size,
00090 const AVSubtitle *h)
00091 {
00092 uint8_t *q, *qq;
00093 int object_id;
00094 int offset1[20], offset2[20];
00095 int i, imax, color, alpha, rects = h->num_rects;
00096 unsigned long hmax;
00097 unsigned long hist[256];
00098 int cmap[256];
00099
00100 if (rects == 0 || h->rects == NULL)
00101 return -1;
00102 if (rects > 20)
00103 rects = 20;
00104
00105
00106 for (i=0; i<256; ++i) {
00107 hist[i] = 0;
00108 cmap[i] = 0;
00109 }
00110 for (object_id = 0; object_id < rects; object_id++)
00111 for (i=0; i<h->rects[object_id]->w*h->rects[object_id]->h; ++i) {
00112 color = h->rects[object_id]->pict.data[0][i];
00113
00114 alpha = ((uint32_t*)h->rects[object_id]->pict.data[1])[color] >> 24;
00115 hist[color] += alpha;
00116 }
00117 for (color=3;; --color) {
00118 hmax = 0;
00119 imax = 0;
00120 for (i=0; i<256; ++i)
00121 if (hist[i] > hmax) {
00122 imax = i;
00123 hmax = hist[i];
00124 }
00125 if (hmax == 0)
00126 break;
00127 if (color == 0)
00128 color = 3;
00129 av_log(NULL, AV_LOG_DEBUG, "dvd_subtitle hist[%d]=%ld -> col %d\n",
00130 imax, hist[imax], color);
00131 cmap[imax] = color;
00132 hist[imax] = 0;
00133 }
00134
00135
00136
00137 q = outbuf + 4;
00138 for (object_id = 0; object_id < rects; object_id++) {
00139 offset1[object_id] = q - outbuf;
00140
00141 if ((q - outbuf) + h->rects[object_id]->w*h->rects[object_id]->h/2
00142 + 17*rects + 21 > outbuf_size) {
00143 av_log(NULL, AV_LOG_ERROR, "dvd_subtitle too big\n");
00144 return -1;
00145 }
00146 dvd_encode_rle(&q, h->rects[object_id]->pict.data[0],
00147 h->rects[object_id]->w*2,
00148 h->rects[object_id]->w, h->rects[object_id]->h >> 1,
00149 cmap);
00150 offset2[object_id] = q - outbuf;
00151 dvd_encode_rle(&q, h->rects[object_id]->pict.data[0] + h->rects[object_id]->w,
00152 h->rects[object_id]->w*2,
00153 h->rects[object_id]->w, h->rects[object_id]->h >> 1,
00154 cmap);
00155 }
00156
00157
00158 qq = outbuf + 2;
00159 bytestream_put_be16(&qq, q - outbuf);
00160
00161
00162 bytestream_put_be16(&q, (h->start_display_time*90) >> 10);
00163 bytestream_put_be16(&q, (q - outbuf) + 8 + 12*rects + 2);
00164 *q++ = 0x03;
00165 *q++ = 0x03; *q++ = 0x7f;
00166 *q++ = 0x04;
00167 *q++ = 0xf0; *q++ = 0x00;
00168
00169
00170
00171
00172 for (object_id = 0; object_id < rects; object_id++) {
00173 int x2 = h->rects[object_id]->x + h->rects[object_id]->w - 1;
00174 int y2 = h->rects[object_id]->y + h->rects[object_id]->h - 1;
00175
00176 *q++ = 0x05;
00177
00178 *q++ = h->rects[object_id]->x >> 4;
00179 *q++ = (h->rects[object_id]->x << 4) | ((x2 >> 8) & 0xf);
00180 *q++ = x2;
00181
00182 *q++ = h->rects[object_id]->y >> 4;
00183 *q++ = (h->rects[object_id]->y << 4) | ((y2 >> 8) & 0xf);
00184 *q++ = y2;
00185
00186 *q++ = 0x06;
00187
00188 bytestream_put_be16(&q, offset1[object_id]);
00189 bytestream_put_be16(&q, offset2[object_id]);
00190 }
00191 *q++ = 0x01;
00192 *q++ = 0xff;
00193
00194
00195 bytestream_put_be16(&q, (h->end_display_time*90) >> 10);
00196 bytestream_put_be16(&q, (q - outbuf) - 2 );
00197 *q++ = 0x02;
00198 *q++ = 0xff;
00199
00200 qq = outbuf;
00201 bytestream_put_be16(&qq, q - outbuf);
00202
00203 av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%td\n", q - outbuf);
00204 return q - outbuf;
00205 }
00206
00207 static int dvdsub_encode(AVCodecContext *avctx,
00208 unsigned char *buf, int buf_size, void *data)
00209 {
00210
00211 AVSubtitle *sub = data;
00212 int ret;
00213
00214 ret = encode_dvd_subtitles(buf, buf_size, sub);
00215 return ret;
00216 }
00217
00218 AVCodec dvdsub_encoder = {
00219 "dvdsub",
00220 AVMEDIA_TYPE_SUBTITLE,
00221 CODEC_ID_DVD_SUBTITLE,
00222 0,
00223 NULL,
00224 dvdsub_encode,
00225 .long_name = NULL_IF_CONFIG_SMALL("DVD subtitles"),
00226 };