00001 /* 00002 * Interplay C93 video decoder 00003 * Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com> 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 00022 #include "avcodec.h" 00023 #include "bytestream.h" 00024 00025 typedef struct { 00026 AVFrame pictures[2]; 00027 int currentpic; 00028 } C93DecoderContext; 00029 00030 typedef enum { 00031 C93_8X8_FROM_PREV = 0x02, 00032 C93_4X4_FROM_PREV = 0x06, 00033 C93_4X4_FROM_CURR = 0x07, 00034 C93_8X8_2COLOR = 0x08, 00035 C93_4X4_2COLOR = 0x0A, 00036 C93_4X4_4COLOR_GRP = 0x0B, 00037 C93_4X4_4COLOR = 0x0D, 00038 C93_NOOP = 0x0E, 00039 C93_8X8_INTRA = 0x0F, 00040 } C93BlockType; 00041 00042 #define WIDTH 320 00043 #define HEIGHT 192 00044 00045 #define C93_HAS_PALETTE 0x01 00046 #define C93_FIRST_FRAME 0x02 00047 00048 static av_cold int decode_init(AVCodecContext *avctx) 00049 { 00050 avctx->pix_fmt = PIX_FMT_PAL8; 00051 return 0; 00052 } 00053 00054 static av_cold int decode_end(AVCodecContext *avctx) 00055 { 00056 C93DecoderContext * const c93 = avctx->priv_data; 00057 00058 if (c93->pictures[0].data[0]) 00059 avctx->release_buffer(avctx, &c93->pictures[0]); 00060 if (c93->pictures[1].data[0]) 00061 avctx->release_buffer(avctx, &c93->pictures[1]); 00062 return 0; 00063 } 00064 00065 static inline int copy_block(AVCodecContext *avctx, uint8_t *to, 00066 uint8_t *from, int offset, int height, int stride) 00067 { 00068 int i; 00069 int width = height; 00070 int from_x = offset % WIDTH; 00071 int from_y = offset / WIDTH; 00072 int overflow = from_x + width - WIDTH; 00073 00074 if (!from) { 00075 /* silently ignoring predictive blocks in first frame */ 00076 return 0; 00077 } 00078 00079 if (from_y + height > HEIGHT) { 00080 av_log(avctx, AV_LOG_ERROR, "invalid offset %d during C93 decoding\n", 00081 offset); 00082 return -1; 00083 } 00084 00085 if (overflow > 0) { 00086 width -= overflow; 00087 for (i = 0; i < height; i++) { 00088 memcpy(&to[i*stride+width], &from[(from_y+i)*stride], overflow); 00089 } 00090 } 00091 00092 for (i = 0; i < height; i++) { 00093 memcpy(&to[i*stride], &from[(from_y+i)*stride+from_x], width); 00094 } 00095 00096 return 0; 00097 } 00098 00099 static inline void draw_n_color(uint8_t *out, int stride, int width, 00100 int height, int bpp, uint8_t cols[4], uint8_t grps[4], uint32_t col) 00101 { 00102 int x, y; 00103 for (y = 0; y < height; y++) { 00104 if (grps) 00105 cols[0] = grps[3 * (y >> 1)]; 00106 for (x = 0; x < width; x++) { 00107 if (grps) 00108 cols[1]= grps[(x >> 1) + 1]; 00109 out[x + y*stride] = cols[col & ((1 << bpp) - 1)]; 00110 col >>= bpp; 00111 } 00112 } 00113 } 00114 00115 static int decode_frame(AVCodecContext *avctx, void *data, 00116 int *data_size, const uint8_t * buf, int buf_size) 00117 { 00118 C93DecoderContext * const c93 = avctx->priv_data; 00119 AVFrame * const newpic = &c93->pictures[c93->currentpic]; 00120 AVFrame * const oldpic = &c93->pictures[c93->currentpic^1]; 00121 AVFrame *picture = data; 00122 uint8_t *out; 00123 int stride, i, x, y, bt = 0; 00124 00125 c93->currentpic ^= 1; 00126 00127 newpic->reference = 1; 00128 newpic->buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 00129 FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; 00130 if (avctx->reget_buffer(avctx, newpic)) { 00131 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00132 return -1; 00133 } 00134 00135 stride = newpic->linesize[0]; 00136 00137 if (buf[0] & C93_FIRST_FRAME) { 00138 newpic->pict_type = FF_I_TYPE; 00139 newpic->key_frame = 1; 00140 } else { 00141 newpic->pict_type = FF_P_TYPE; 00142 newpic->key_frame = 0; 00143 } 00144 00145 if (*buf++ & C93_HAS_PALETTE) { 00146 uint32_t *palette = (uint32_t *) newpic->data[1]; 00147 const uint8_t *palbuf = buf + buf_size - 768 - 1; 00148 for (i = 0; i < 256; i++) { 00149 palette[i] = bytestream_get_be24(&palbuf); 00150 } 00151 } else { 00152 if (oldpic->data[1]) 00153 memcpy(newpic->data[1], oldpic->data[1], 256 * 4); 00154 } 00155 00156 for (y = 0; y < HEIGHT; y += 8) { 00157 out = newpic->data[0] + y * stride; 00158 for (x = 0; x < WIDTH; x += 8) { 00159 uint8_t *copy_from = oldpic->data[0]; 00160 unsigned int offset, j; 00161 uint8_t cols[4], grps[4]; 00162 C93BlockType block_type; 00163 00164 if (!bt) 00165 bt = *buf++; 00166 00167 block_type= bt & 0x0F; 00168 switch (block_type) { 00169 case C93_8X8_FROM_PREV: 00170 offset = bytestream_get_le16(&buf); 00171 if (copy_block(avctx, out, copy_from, offset, 8, stride)) 00172 return -1; 00173 break; 00174 00175 case C93_4X4_FROM_CURR: 00176 copy_from = newpic->data[0]; 00177 case C93_4X4_FROM_PREV: 00178 for (j = 0; j < 8; j += 4) { 00179 for (i = 0; i < 8; i += 4) { 00180 offset = bytestream_get_le16(&buf); 00181 if (copy_block(avctx, &out[j*stride+i], 00182 copy_from, offset, 4, stride)) 00183 return -1; 00184 } 00185 } 00186 break; 00187 00188 case C93_8X8_2COLOR: 00189 bytestream_get_buffer(&buf, cols, 2); 00190 for (i = 0; i < 8; i++) { 00191 draw_n_color(out + i*stride, stride, 8, 1, 1, cols, 00192 NULL, *buf++); 00193 } 00194 00195 break; 00196 00197 case C93_4X4_2COLOR: 00198 case C93_4X4_4COLOR: 00199 case C93_4X4_4COLOR_GRP: 00200 for (j = 0; j < 8; j += 4) { 00201 for (i = 0; i < 8; i += 4) { 00202 if (block_type == C93_4X4_2COLOR) { 00203 bytestream_get_buffer(&buf, cols, 2); 00204 draw_n_color(out + i + j*stride, stride, 4, 4, 00205 1, cols, NULL, bytestream_get_le16(&buf)); 00206 } else if (block_type == C93_4X4_4COLOR) { 00207 bytestream_get_buffer(&buf, cols, 4); 00208 draw_n_color(out + i + j*stride, stride, 4, 4, 00209 2, cols, NULL, bytestream_get_le32(&buf)); 00210 } else { 00211 bytestream_get_buffer(&buf, grps, 4); 00212 draw_n_color(out + i + j*stride, stride, 4, 4, 00213 1, cols, grps, bytestream_get_le16(&buf)); 00214 } 00215 } 00216 } 00217 break; 00218 00219 case C93_NOOP: 00220 break; 00221 00222 case C93_8X8_INTRA: 00223 for (j = 0; j < 8; j++) 00224 bytestream_get_buffer(&buf, out + j*stride, 8); 00225 break; 00226 00227 default: 00228 av_log(avctx, AV_LOG_ERROR, "unexpected type %x at %dx%d\n", 00229 block_type, x, y); 00230 return -1; 00231 } 00232 bt >>= 4; 00233 out += 8; 00234 } 00235 } 00236 00237 *picture = *newpic; 00238 *data_size = sizeof(AVFrame); 00239 00240 return buf_size; 00241 } 00242 00243 AVCodec c93_decoder = { 00244 "c93", 00245 CODEC_TYPE_VIDEO, 00246 CODEC_ID_C93, 00247 sizeof(C93DecoderContext), 00248 decode_init, 00249 NULL, 00250 decode_end, 00251 decode_frame, 00252 CODEC_CAP_DR1, 00253 .long_name = NULL_IF_CONFIG_SMALL("Interplay C93"), 00254 };