00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00031 #include "libavutil/intreadwrite.h"
00032 #include "avcodec.h"
00033 #include "cga_data.h"
00034 #include "bintext.h"
00035
00036 typedef struct XbinContext {
00037 AVFrame frame;
00038 int palette[16];
00039 int flags;
00040 int font_height;
00041 const uint8_t *font;
00042 int x, y;
00043 } XbinContext;
00044
00045 static av_cold int decode_init(AVCodecContext *avctx)
00046 {
00047 XbinContext *s = avctx->priv_data;
00048 uint8_t *p;
00049 int i;
00050
00051 avctx->pix_fmt = PIX_FMT_PAL8;
00052 p = avctx->extradata;
00053 if (p) {
00054 s->font_height = p[0];
00055 s->flags = p[1];
00056 p += 2;
00057 if(avctx->extradata_size < 2 + (!!(s->flags & BINTEXT_PALETTE))*3*16
00058 + (!!(s->flags & BINTEXT_FONT))*s->font_height*256) {
00059 av_log(avctx, AV_LOG_ERROR, "not enough extradata\n");
00060 return AVERROR_INVALIDDATA;
00061 }
00062 } else {
00063 s->font_height = 8;
00064 s->flags = 0;
00065 }
00066
00067 if ((s->flags & BINTEXT_PALETTE)) {
00068 for (i = 0; i < 16; i++) {
00069 s->palette[i] = 0xFF000000 | (AV_RB24(p) << 2) | ((AV_RB24(p) >> 4) & 0x30303);
00070 p += 3;
00071 }
00072 } else {
00073 for (i = 0; i < 16; i++)
00074 s->palette[i] = 0xFF000000 | ff_cga_palette[i];
00075 }
00076
00077 if ((s->flags & BINTEXT_FONT)) {
00078 s->font = p;
00079 } else {
00080 switch(s->font_height) {
00081 default:
00082 av_log(avctx, AV_LOG_WARNING, "font height %i not supported\n", s->font_height);
00083 s->font_height = 8;
00084 case 8:
00085 s->font = ff_cga_font;
00086 break;
00087 case 16:
00088 s->font = ff_vga16_font;
00089 break;
00090 }
00091 }
00092
00093 return 0;
00094 }
00095
00096 #define DEFAULT_BG_COLOR 0
00097 av_unused static void hscroll(AVCodecContext *avctx)
00098 {
00099 XbinContext *s = avctx->priv_data;
00100 if (s->y < avctx->height - s->font_height) {
00101 s->y += s->font_height;
00102 } else {
00103 memmove(s->frame.data[0], s->frame.data[0] + s->font_height*s->frame.linesize[0],
00104 (avctx->height - s->font_height)*s->frame.linesize[0]);
00105 memset(s->frame.data[0] + (avctx->height - s->font_height)*s->frame.linesize[0],
00106 DEFAULT_BG_COLOR, s->font_height * s->frame.linesize[0]);
00107 }
00108 }
00109
00110 #define FONT_WIDTH 8
00111
00115 static void draw_char(AVCodecContext *avctx, int c, int a)
00116 {
00117 XbinContext *s = avctx->priv_data;
00118 if (s->y > avctx->height - s->font_height)
00119 return;
00120 ff_draw_pc_font(s->frame.data[0] + s->y * s->frame.linesize[0] + s->x,
00121 s->frame.linesize[0], s->font, s->font_height, c,
00122 a & 0x0F, a >> 4);
00123 s->x += FONT_WIDTH;
00124 if (s->x > avctx->width - FONT_WIDTH) {
00125 s->x = 0;
00126 s->y += s->font_height;
00127 }
00128 }
00129
00130 static int decode_frame(AVCodecContext *avctx,
00131 void *data, int *data_size,
00132 AVPacket *avpkt)
00133 {
00134 XbinContext *s = avctx->priv_data;
00135 const uint8_t *buf = avpkt->data;
00136 int buf_size = avpkt->size;
00137 const uint8_t *buf_end = buf+buf_size;
00138
00139 s->x = s->y = 0;
00140 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID |
00141 FF_BUFFER_HINTS_PRESERVE |
00142 FF_BUFFER_HINTS_REUSABLE;
00143 if (avctx->reget_buffer(avctx, &s->frame)) {
00144 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00145 return -1;
00146 }
00147 s->frame.pict_type = AV_PICTURE_TYPE_I;
00148 s->frame.palette_has_changed = 1;
00149 memcpy(s->frame.data[1], s->palette, 16 * 4);
00150
00151 if (avctx->codec_id == AV_CODEC_ID_XBIN) {
00152 while (buf + 2 < buf_end) {
00153 int i,c,a;
00154 int type = *buf >> 6;
00155 int count = (*buf & 0x3F) + 1;
00156 buf++;
00157 switch (type) {
00158 case 0:
00159 for (i = 0; i < count && buf + 1 < buf_end; i++) {
00160 draw_char(avctx, buf[0], buf[1]);
00161 buf += 2;
00162 }
00163 break;
00164 case 1:
00165 c = *buf++;
00166 for (i = 0; i < count && buf < buf_end; i++)
00167 draw_char(avctx, c, *buf++);
00168 break;
00169 case 2:
00170 a = *buf++;
00171 for (i = 0; i < count && buf < buf_end; i++)
00172 draw_char(avctx, *buf++, a);
00173 break;
00174 case 3:
00175 c = *buf++;
00176 a = *buf++;
00177 for (i = 0; i < count && buf < buf_end; i++)
00178 draw_char(avctx, c, a);
00179 break;
00180 }
00181 }
00182 } else if (avctx->codec_id == AV_CODEC_ID_IDF) {
00183 while (buf + 2 < buf_end) {
00184 if (AV_RL16(buf) == 1) {
00185 int i;
00186 if (buf + 6 > buf_end)
00187 break;
00188 for (i = 0; i < buf[2]; i++)
00189 draw_char(avctx, buf[4], buf[5]);
00190 buf += 6;
00191 } else {
00192 draw_char(avctx, buf[0], buf[1]);
00193 buf += 2;
00194 }
00195 }
00196 } else {
00197 while (buf + 1 < buf_end) {
00198 draw_char(avctx, buf[0], buf[1]);
00199 buf += 2;
00200 }
00201 }
00202
00203 *data_size = sizeof(AVFrame);
00204 *(AVFrame*)data = s->frame;
00205 return buf_size;
00206 }
00207
00208 static av_cold int decode_end(AVCodecContext *avctx)
00209 {
00210 XbinContext *s = avctx->priv_data;
00211
00212 if (s->frame.data[0])
00213 avctx->release_buffer(avctx, &s->frame);
00214
00215 return 0;
00216 }
00217
00218 #if CONFIG_BINTEXT_DECODER
00219 AVCodec ff_bintext_decoder = {
00220 .name = "bintext",
00221 .type = AVMEDIA_TYPE_VIDEO,
00222 .id = AV_CODEC_ID_BINTEXT,
00223 .priv_data_size = sizeof(XbinContext),
00224 .init = decode_init,
00225 .close = decode_end,
00226 .decode = decode_frame,
00227 .capabilities = CODEC_CAP_DR1,
00228 .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
00229 };
00230 #endif
00231 #if CONFIG_XBIN_DECODER
00232 AVCodec ff_xbin_decoder = {
00233 .name = "xbin",
00234 .type = AVMEDIA_TYPE_VIDEO,
00235 .id = AV_CODEC_ID_XBIN,
00236 .priv_data_size = sizeof(XbinContext),
00237 .init = decode_init,
00238 .close = decode_end,
00239 .decode = decode_frame,
00240 .capabilities = CODEC_CAP_DR1,
00241 .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text"),
00242 };
00243 #endif
00244 #if CONFIG_IDF_DECODER
00245 AVCodec ff_idf_decoder = {
00246 .name = "idf",
00247 .type = AVMEDIA_TYPE_VIDEO,
00248 .id = AV_CODEC_ID_IDF,
00249 .priv_data_size = sizeof(XbinContext),
00250 .init = decode_init,
00251 .close = decode_end,
00252 .decode = decode_frame,
00253 .capabilities = CODEC_CAP_DR1,
00254 .long_name = NULL_IF_CONFIG_SMALL("iCEDraw text"),
00255 };
00256 #endif