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 } else {
00058 s->font_height = 8;
00059 s->flags = 0;
00060 }
00061
00062 if ((s->flags & BINTEXT_PALETTE)) {
00063 for (i = 0; i < 16; i++) {
00064 s->palette[i] = 0xFF000000 | (AV_RB24(p) << 2) | ((AV_RB24(p) >> 4) & 0x30303);
00065 p += 3;
00066 }
00067 } else {
00068 for (i = 0; i < 16; i++)
00069 s->palette[i] = 0xFF000000 | ff_cga_palette[i];
00070 }
00071
00072 if ((s->flags & BINTEXT_FONT)) {
00073 s->font = p;
00074 } else {
00075 switch(s->font_height) {
00076 default:
00077 av_log(avctx, AV_LOG_WARNING, "font height %i not supported\n", s->font_height);
00078 s->font_height = 8;
00079 case 8:
00080 s->font = ff_cga_font;
00081 break;
00082 case 16:
00083 s->font = ff_vga16_font;
00084 break;
00085 }
00086 }
00087
00088 return 0;
00089 }
00090
00091 #define DEFAULT_BG_COLOR 0
00092 static void hscroll(AVCodecContext *avctx)
00093 {
00094 XbinContext *s = avctx->priv_data;
00095 if (s->y < avctx->height - s->font_height) {
00096 s->y += s->font_height;
00097 } else {
00098 memmove(s->frame.data[0], s->frame.data[0] + s->font_height*s->frame.linesize[0],
00099 (avctx->height - s->font_height)*s->frame.linesize[0]);
00100 memset(s->frame.data[0] + (avctx->height - s->font_height)*s->frame.linesize[0],
00101 DEFAULT_BG_COLOR, s->font_height * s->frame.linesize[0]);
00102 }
00103 }
00104
00105 #define FONT_WIDTH 8
00106
00110 static void draw_char(AVCodecContext *avctx, int c, int a)
00111 {
00112 XbinContext *s = avctx->priv_data;
00113 if (s->y > avctx->height - s->font_height)
00114 return;
00115 ff_draw_pc_font(s->frame.data[0] + s->y * s->frame.linesize[0] + s->x,
00116 s->frame.linesize[0], s->font, s->font_height, c,
00117 a & 0x0F, a >> 4);
00118 s->x += FONT_WIDTH;
00119 if (s->x > avctx->width - FONT_WIDTH) {
00120 s->x = 0;
00121 s->y += s->font_height;
00122 }
00123 }
00124
00125 static int decode_frame(AVCodecContext *avctx,
00126 void *data, int *data_size,
00127 AVPacket *avpkt)
00128 {
00129 XbinContext *s = avctx->priv_data;
00130 const uint8_t *buf = avpkt->data;
00131 int buf_size = avpkt->size;
00132 const uint8_t *buf_end = buf+buf_size;
00133
00134 s->x = s->y = 0;
00135 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID |
00136 FF_BUFFER_HINTS_PRESERVE |
00137 FF_BUFFER_HINTS_REUSABLE;
00138 if (avctx->reget_buffer(avctx, &s->frame)) {
00139 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00140 return -1;
00141 }
00142 s->frame.pict_type = AV_PICTURE_TYPE_I;
00143 s->frame.palette_has_changed = 1;
00144 memcpy(s->frame.data[1], s->palette, 16 * 4);
00145
00146 if (avctx->codec_id == CODEC_ID_XBIN) {
00147 while (buf + 2 < buf_end) {
00148 int i,c,a;
00149 int type = *buf >> 6;
00150 int count = (*buf & 0x3F) + 1;
00151 buf++;
00152 switch (type) {
00153 case 0:
00154 for (i = 0; i < count && buf + 1 < buf_end; i++) {
00155 draw_char(avctx, buf[0], buf[1]);
00156 buf += 2;
00157 }
00158 break;
00159 case 1:
00160 c = *buf++;
00161 for (i = 0; i < count && buf < buf_end; i++)
00162 draw_char(avctx, c, *buf++);
00163 break;
00164 case 2:
00165 a = *buf++;
00166 for (i = 0; i < count && buf < buf_end; i++)
00167 draw_char(avctx, *buf++, a);
00168 break;
00169 case 3:
00170 c = *buf++;
00171 a = *buf++;
00172 for (i = 0; i < count && buf < buf_end; i++)
00173 draw_char(avctx, c, a);
00174 break;
00175 }
00176 }
00177 } else if (avctx->codec_id == CODEC_ID_IDF) {
00178 while (buf + 2 < buf_end) {
00179 if (AV_RL16(buf) == 1) {
00180 int i;
00181 if (buf + 6 > buf_end)
00182 break;
00183 for (i = 0; i < buf[2]; i++)
00184 draw_char(avctx, buf[4], buf[5]);
00185 buf += 6;
00186 } else {
00187 draw_char(avctx, buf[0], buf[1]);
00188 buf += 2;
00189 }
00190 }
00191 } else {
00192 while (buf + 1 < buf_end) {
00193 draw_char(avctx, buf[0], buf[1]);
00194 buf += 2;
00195 }
00196 }
00197
00198 *data_size = sizeof(AVFrame);
00199 *(AVFrame*)data = s->frame;
00200 return buf_size;
00201 }
00202
00203 static av_cold int decode_end(AVCodecContext *avctx)
00204 {
00205 XbinContext *s = avctx->priv_data;
00206
00207 if (s->frame.data[0])
00208 avctx->release_buffer(avctx, &s->frame);
00209
00210 return 0;
00211 }
00212
00213 AVCodec ff_bintext_decoder = {
00214 .name = "bintext",
00215 .type = AVMEDIA_TYPE_VIDEO,
00216 .id = CODEC_ID_BINTEXT,
00217 .priv_data_size = sizeof(XbinContext),
00218 .init = decode_init,
00219 .close = decode_end,
00220 .decode = decode_frame,
00221 .capabilities = CODEC_CAP_DR1,
00222 .long_name = NULL_IF_CONFIG_SMALL("Binary text"),
00223 };
00224
00225 AVCodec ff_xbin_decoder = {
00226 .name = "xbin",
00227 .type = AVMEDIA_TYPE_VIDEO,
00228 .id = CODEC_ID_XBIN,
00229 .priv_data_size = sizeof(XbinContext),
00230 .init = decode_init,
00231 .close = decode_end,
00232 .decode = decode_frame,
00233 .capabilities = CODEC_CAP_DR1,
00234 .long_name = NULL_IF_CONFIG_SMALL("eXtended BINary text"),
00235 };
00236
00237 AVCodec ff_idf_decoder = {
00238 .name = "idf",
00239 .type = AVMEDIA_TYPE_VIDEO,
00240 .id = CODEC_ID_IDF,
00241 .priv_data_size = sizeof(XbinContext),
00242 .init = decode_init,
00243 .close = decode_end,
00244 .decode = decode_frame,
00245 .capabilities = CODEC_CAP_DR1,
00246 .long_name = NULL_IF_CONFIG_SMALL("iCEDraw text"),
00247 };