Libav
|
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, AVPacket *avpkt) 00117 { 00118 const uint8_t *buf = avpkt->data; 00119 int buf_size = avpkt->size; 00120 C93DecoderContext * const c93 = avctx->priv_data; 00121 AVFrame * const newpic = &c93->pictures[c93->currentpic]; 00122 AVFrame * const oldpic = &c93->pictures[c93->currentpic^1]; 00123 AVFrame *picture = data; 00124 uint8_t *out; 00125 int stride, i, x, y, bt = 0; 00126 00127 c93->currentpic ^= 1; 00128 00129 newpic->reference = 1; 00130 newpic->buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | 00131 FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; 00132 if (avctx->reget_buffer(avctx, newpic)) { 00133 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 00134 return -1; 00135 } 00136 00137 stride = newpic->linesize[0]; 00138 00139 if (buf[0] & C93_FIRST_FRAME) { 00140 newpic->pict_type = FF_I_TYPE; 00141 newpic->key_frame = 1; 00142 } else { 00143 newpic->pict_type = FF_P_TYPE; 00144 newpic->key_frame = 0; 00145 } 00146 00147 if (*buf++ & C93_HAS_PALETTE) { 00148 uint32_t *palette = (uint32_t *) newpic->data[1]; 00149 const uint8_t *palbuf = buf + buf_size - 768 - 1; 00150 for (i = 0; i < 256; i++) { 00151 palette[i] = bytestream_get_be24(&palbuf); 00152 } 00153 } else { 00154 if (oldpic->data[1]) 00155 memcpy(newpic->data[1], oldpic->data[1], 256 * 4); 00156 } 00157 00158 for (y = 0; y < HEIGHT; y += 8) { 00159 out = newpic->data[0] + y * stride; 00160 for (x = 0; x < WIDTH; x += 8) { 00161 uint8_t *copy_from = oldpic->data[0]; 00162 unsigned int offset, j; 00163 uint8_t cols[4], grps[4]; 00164 C93BlockType block_type; 00165 00166 if (!bt) 00167 bt = *buf++; 00168 00169 block_type= bt & 0x0F; 00170 switch (block_type) { 00171 case C93_8X8_FROM_PREV: 00172 offset = bytestream_get_le16(&buf); 00173 if (copy_block(avctx, out, copy_from, offset, 8, stride)) 00174 return -1; 00175 break; 00176 00177 case C93_4X4_FROM_CURR: 00178 copy_from = newpic->data[0]; 00179 case C93_4X4_FROM_PREV: 00180 for (j = 0; j < 8; j += 4) { 00181 for (i = 0; i < 8; i += 4) { 00182 offset = bytestream_get_le16(&buf); 00183 if (copy_block(avctx, &out[j*stride+i], 00184 copy_from, offset, 4, stride)) 00185 return -1; 00186 } 00187 } 00188 break; 00189 00190 case C93_8X8_2COLOR: 00191 bytestream_get_buffer(&buf, cols, 2); 00192 for (i = 0; i < 8; i++) { 00193 draw_n_color(out + i*stride, stride, 8, 1, 1, cols, 00194 NULL, *buf++); 00195 } 00196 00197 break; 00198 00199 case C93_4X4_2COLOR: 00200 case C93_4X4_4COLOR: 00201 case C93_4X4_4COLOR_GRP: 00202 for (j = 0; j < 8; j += 4) { 00203 for (i = 0; i < 8; i += 4) { 00204 if (block_type == C93_4X4_2COLOR) { 00205 bytestream_get_buffer(&buf, cols, 2); 00206 draw_n_color(out + i + j*stride, stride, 4, 4, 00207 1, cols, NULL, bytestream_get_le16(&buf)); 00208 } else if (block_type == C93_4X4_4COLOR) { 00209 bytestream_get_buffer(&buf, cols, 4); 00210 draw_n_color(out + i + j*stride, stride, 4, 4, 00211 2, cols, NULL, bytestream_get_le32(&buf)); 00212 } else { 00213 bytestream_get_buffer(&buf, grps, 4); 00214 draw_n_color(out + i + j*stride, stride, 4, 4, 00215 1, cols, grps, bytestream_get_le16(&buf)); 00216 } 00217 } 00218 } 00219 break; 00220 00221 case C93_NOOP: 00222 break; 00223 00224 case C93_8X8_INTRA: 00225 for (j = 0; j < 8; j++) 00226 bytestream_get_buffer(&buf, out + j*stride, 8); 00227 break; 00228 00229 default: 00230 av_log(avctx, AV_LOG_ERROR, "unexpected type %x at %dx%d\n", 00231 block_type, x, y); 00232 return -1; 00233 } 00234 bt >>= 4; 00235 out += 8; 00236 } 00237 } 00238 00239 *picture = *newpic; 00240 *data_size = sizeof(AVFrame); 00241 00242 return buf_size; 00243 } 00244 00245 AVCodec c93_decoder = { 00246 "c93", 00247 AVMEDIA_TYPE_VIDEO, 00248 CODEC_ID_C93, 00249 sizeof(C93DecoderContext), 00250 decode_init, 00251 NULL, 00252 decode_end, 00253 decode_frame, 00254 CODEC_CAP_DR1, 00255 .long_name = NULL_IF_CONFIG_SMALL("Interplay C93"), 00256 };