Libav
|
00001 /* 00002 * DVD subtitle encoding for ffmpeg 00003 * Copyright (c) 2005 Wolfram Gloger 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * FFmpeg is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 #include "avcodec.h" 00022 #include "bytestream.h" 00023 00024 #undef NDEBUG 00025 #include <assert.h> 00026 00027 // ncnt is the nibble counter 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 /* end of line */ 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 // analyze bitmaps, compress to 4 colors 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 // only count non-transparent pixels 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 // encode data block 00137 q = outbuf + 4; 00138 for (object_id = 0; object_id < rects; object_id++) { 00139 offset1[object_id] = q - outbuf; 00140 // worst case memory requirement: 1 nibble per pixel.. 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 // set data packet size 00158 qq = outbuf + 2; 00159 bytestream_put_be16(&qq, q - outbuf); 00160 00161 // send start display command 00162 bytestream_put_be16(&q, (h->start_display_time*90) >> 10); 00163 bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12*rects + 2); 00164 *q++ = 0x03; // palette - 4 nibbles 00165 *q++ = 0x03; *q++ = 0x7f; 00166 *q++ = 0x04; // alpha - 4 nibbles 00167 *q++ = 0xf0; *q++ = 0x00; 00168 //*q++ = 0x0f; *q++ = 0xff; 00169 00170 // XXX not sure if more than one rect can really be encoded.. 00171 // 12 bytes per rect 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 // x1 x2 -> 6 nibbles 00178 *q++ = h->rects[object_id]->x >> 4; 00179 *q++ = (h->rects[object_id]->x << 4) | ((x2 >> 8) & 0xf); 00180 *q++ = x2; 00181 // y1 y2 -> 6 nibbles 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 // offset1, offset2 00188 bytestream_put_be16(&q, offset1[object_id]); 00189 bytestream_put_be16(&q, offset2[object_id]); 00190 } 00191 *q++ = 0x01; // start command 00192 *q++ = 0xff; // terminating command 00193 00194 // send stop display command last 00195 bytestream_put_be16(&q, (h->end_display_time*90) >> 10); 00196 bytestream_put_be16(&q, (q - outbuf) - 2 /*+ 4*/); 00197 *q++ = 0x02; // set end 00198 *q++ = 0xff; // terminating command 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 //DVDSubtitleContext *s = avctx->priv_data; 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 };