00001 /* 00002 * Chronomaster DFA Video Decoder 00003 * Copyright (c) 2011 Konstantin Shishkov 00004 * based on work by Vladimir "VAG" Gneushev 00005 * 00006 * This file is part of FFmpeg. 00007 * 00008 * FFmpeg is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * FFmpeg is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with FFmpeg; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 #include "avcodec.h" 00024 #include "bytestream.h" 00025 00026 #include "libavutil/imgutils.h" 00027 #include "libavutil/lzo.h" // for av_memcpy_backptr 00028 00029 typedef struct DfaContext { 00030 AVFrame pic; 00031 00032 uint32_t pal[256]; 00033 uint8_t *frame_buf; 00034 } DfaContext; 00035 00036 static av_cold int dfa_decode_init(AVCodecContext *avctx) 00037 { 00038 DfaContext *s = avctx->priv_data; 00039 int ret; 00040 00041 avctx->pix_fmt = PIX_FMT_PAL8; 00042 00043 if ((ret = av_image_check_size(avctx->width, avctx->height, 0, avctx)) < 0) 00044 return ret; 00045 00046 s->frame_buf = av_mallocz(avctx->width * avctx->height + AV_LZO_OUTPUT_PADDING); 00047 if (!s->frame_buf) 00048 return AVERROR(ENOMEM); 00049 00050 return 0; 00051 } 00052 00053 static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height) 00054 { 00055 const int size = width * height; 00056 00057 if (bytestream2_get_buffer(gb, frame, size) != size) 00058 return AVERROR_INVALIDDATA; 00059 return 0; 00060 } 00061 00062 static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height) 00063 { 00064 const uint8_t *frame_start = frame; 00065 const uint8_t *frame_end = frame + width * height; 00066 int mask = 0x10000, bitbuf = 0; 00067 int v, count, segments; 00068 unsigned offset; 00069 00070 segments = bytestream2_get_le32(gb); 00071 offset = bytestream2_get_le32(gb); 00072 if (frame_end - frame <= offset) 00073 return AVERROR_INVALIDDATA; 00074 frame += offset; 00075 while (segments--) { 00076 if (bytestream2_get_bytes_left(gb) < 2) 00077 return AVERROR_INVALIDDATA; 00078 if (mask == 0x10000) { 00079 bitbuf = bytestream2_get_le16u(gb); 00080 mask = 1; 00081 } 00082 if (frame_end - frame < 2) 00083 return AVERROR_INVALIDDATA; 00084 if (bitbuf & mask) { 00085 v = bytestream2_get_le16(gb); 00086 offset = (v & 0x1FFF) << 1; 00087 count = ((v >> 13) + 2) << 1; 00088 if (frame - frame_start < offset || frame_end - frame < count) 00089 return AVERROR_INVALIDDATA; 00090 av_memcpy_backptr(frame, offset, count); 00091 frame += count; 00092 } else { 00093 *frame++ = bytestream2_get_byte(gb); 00094 *frame++ = bytestream2_get_byte(gb); 00095 } 00096 mask <<= 1; 00097 } 00098 00099 return 0; 00100 } 00101 00102 static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height) 00103 { 00104 const uint8_t *frame_start = frame; 00105 const uint8_t *frame_end = frame + width * height; 00106 int mask = 0x10000, bitbuf = 0; 00107 int v, offset, count, segments; 00108 00109 segments = bytestream2_get_le16(gb); 00110 while (segments--) { 00111 if (bytestream2_get_bytes_left(gb) < 2) 00112 return AVERROR_INVALIDDATA; 00113 if (mask == 0x10000) { 00114 bitbuf = bytestream2_get_le16u(gb); 00115 mask = 1; 00116 } 00117 if (frame_end - frame < 2) 00118 return AVERROR_INVALIDDATA; 00119 if (bitbuf & mask) { 00120 v = bytestream2_get_le16(gb); 00121 offset = (v & 0x1FFF) << 1; 00122 count = ((v >> 13) + 2) << 1; 00123 if (frame - frame_start < offset || frame_end - frame < count) 00124 return AVERROR_INVALIDDATA; 00125 // can't use av_memcpy_backptr() since it can overwrite following pixels 00126 for (v = 0; v < count; v++) 00127 frame[v] = frame[v - offset]; 00128 frame += count; 00129 } else if (bitbuf & (mask << 1)) { 00130 frame += bytestream2_get_le16(gb); 00131 } else { 00132 *frame++ = bytestream2_get_byte(gb); 00133 *frame++ = bytestream2_get_byte(gb); 00134 } 00135 mask <<= 2; 00136 } 00137 00138 return 0; 00139 } 00140 00141 static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height) 00142 { 00143 const uint8_t *frame_start = frame; 00144 const uint8_t *frame_end = frame + width * height; 00145 int mask = 0x10000, bitbuf = 0; 00146 int i, v, offset, count, segments; 00147 00148 segments = bytestream2_get_le16(gb); 00149 while (segments--) { 00150 if (bytestream2_get_bytes_left(gb) < 2) 00151 return AVERROR_INVALIDDATA; 00152 if (mask == 0x10000) { 00153 bitbuf = bytestream2_get_le16u(gb); 00154 mask = 1; 00155 } 00156 00157 if (bitbuf & mask) { 00158 v = bytestream2_get_le16(gb); 00159 offset = (v & 0x1FFF) << 2; 00160 count = ((v >> 13) + 2) << 1; 00161 if (frame - frame_start < offset || frame_end - frame < count*2 + width) 00162 return AVERROR_INVALIDDATA; 00163 for (i = 0; i < count; i++) { 00164 frame[0] = frame[1] = 00165 frame[width] = frame[width + 1] = frame[-offset]; 00166 00167 frame += 2; 00168 } 00169 } else if (bitbuf & (mask << 1)) { 00170 v = bytestream2_get_le16(gb)*2; 00171 if (frame - frame_end < v) 00172 return AVERROR_INVALIDDATA; 00173 frame += v; 00174 } else { 00175 if (frame_end - frame < width + 3) 00176 return AVERROR_INVALIDDATA; 00177 frame[0] = frame[1] = 00178 frame[width] = frame[width + 1] = bytestream2_get_byte(gb); 00179 frame += 2; 00180 frame[0] = frame[1] = 00181 frame[width] = frame[width + 1] = bytestream2_get_byte(gb); 00182 frame += 2; 00183 } 00184 mask <<= 2; 00185 } 00186 00187 return 0; 00188 } 00189 00190 static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height) 00191 { 00192 uint8_t *line_ptr; 00193 int count, lines, segments; 00194 00195 count = bytestream2_get_le16(gb); 00196 if (count >= height) 00197 return AVERROR_INVALIDDATA; 00198 frame += width * count; 00199 lines = bytestream2_get_le16(gb); 00200 if (count + lines > height) 00201 return AVERROR_INVALIDDATA; 00202 00203 while (lines--) { 00204 if (bytestream2_get_bytes_left(gb) < 1) 00205 return AVERROR_INVALIDDATA; 00206 line_ptr = frame; 00207 frame += width; 00208 segments = bytestream2_get_byteu(gb); 00209 while (segments--) { 00210 if (frame - line_ptr <= bytestream2_peek_byte(gb)) 00211 return AVERROR_INVALIDDATA; 00212 line_ptr += bytestream2_get_byte(gb); 00213 count = (int8_t)bytestream2_get_byte(gb); 00214 if (count >= 0) { 00215 if (frame - line_ptr < count) 00216 return AVERROR_INVALIDDATA; 00217 if (bytestream2_get_buffer(gb, line_ptr, count) != count) 00218 return AVERROR_INVALIDDATA; 00219 } else { 00220 count = -count; 00221 if (frame - line_ptr < count) 00222 return AVERROR_INVALIDDATA; 00223 memset(line_ptr, bytestream2_get_byte(gb), count); 00224 } 00225 line_ptr += count; 00226 } 00227 } 00228 00229 return 0; 00230 } 00231 00232 static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height) 00233 { 00234 const uint8_t *frame_end = frame + width * height; 00235 uint8_t *line_ptr; 00236 int count, i, v, lines, segments; 00237 int y = 0; 00238 00239 lines = bytestream2_get_le16(gb); 00240 if (lines > height) 00241 return AVERROR_INVALIDDATA; 00242 00243 while (lines--) { 00244 if (bytestream2_get_bytes_left(gb) < 2) 00245 return AVERROR_INVALIDDATA; 00246 segments = bytestream2_get_le16u(gb); 00247 while ((segments & 0xC000) == 0xC000) { 00248 unsigned skip_lines = -(int16_t)segments; 00249 unsigned delta = -((int16_t)segments * width); 00250 if (frame_end - frame <= delta || y + lines + skip_lines > height) 00251 return AVERROR_INVALIDDATA; 00252 frame += delta; 00253 y += skip_lines; 00254 segments = bytestream2_get_le16(gb); 00255 } 00256 if (segments & 0x8000) { 00257 frame[width - 1] = segments & 0xFF; 00258 segments = bytestream2_get_le16(gb); 00259 } 00260 line_ptr = frame; 00261 frame += width; 00262 y++; 00263 while (segments--) { 00264 if (frame - line_ptr <= bytestream2_peek_byte(gb)) 00265 return AVERROR_INVALIDDATA; 00266 line_ptr += bytestream2_get_byte(gb); 00267 count = (int8_t)bytestream2_get_byte(gb); 00268 if (count >= 0) { 00269 if (frame - line_ptr < count * 2) 00270 return AVERROR_INVALIDDATA; 00271 if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2) 00272 return AVERROR_INVALIDDATA; 00273 line_ptr += count * 2; 00274 } else { 00275 count = -count; 00276 if (frame - line_ptr < count * 2) 00277 return AVERROR_INVALIDDATA; 00278 v = bytestream2_get_le16(gb); 00279 for (i = 0; i < count; i++) 00280 bytestream_put_le16(&line_ptr, v); 00281 } 00282 } 00283 } 00284 00285 return 0; 00286 } 00287 00288 static int decode_unk6(GetByteContext *gb, uint8_t *frame, int width, int height) 00289 { 00290 return AVERROR_PATCHWELCOME; 00291 } 00292 00293 static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height) 00294 { 00295 memset(frame, 0, width * height); 00296 return 0; 00297 } 00298 00299 00300 typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height); 00301 00302 static const chunk_decoder decoder[8] = { 00303 decode_copy, decode_tsw1, decode_bdlt, decode_wdlt, 00304 decode_unk6, decode_dsw1, decode_blck, decode_dds1, 00305 }; 00306 00307 static const char* chunk_name[8] = { 00308 "COPY", "TSW1", "BDLT", "WDLT", "????", "DSW1", "BLCK", "DDS1" 00309 }; 00310 00311 static int dfa_decode_frame(AVCodecContext *avctx, 00312 void *data, int *data_size, 00313 AVPacket *avpkt) 00314 { 00315 DfaContext *s = avctx->priv_data; 00316 GetByteContext gb; 00317 const uint8_t *buf = avpkt->data; 00318 uint32_t chunk_type, chunk_size; 00319 uint8_t *dst; 00320 int ret; 00321 int i, pal_elems; 00322 00323 if (s->pic.data[0]) 00324 avctx->release_buffer(avctx, &s->pic); 00325 00326 if ((ret = avctx->get_buffer(avctx, &s->pic))) { 00327 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00328 return ret; 00329 } 00330 00331 bytestream2_init(&gb, avpkt->data, avpkt->size); 00332 while (bytestream2_get_bytes_left(&gb) > 0) { 00333 bytestream2_skip(&gb, 4); 00334 chunk_size = bytestream2_get_le32(&gb); 00335 chunk_type = bytestream2_get_le32(&gb); 00336 if (!chunk_type) 00337 break; 00338 if (chunk_type == 1) { 00339 pal_elems = FFMIN(chunk_size / 3, 256); 00340 for (i = 0; i < pal_elems; i++) { 00341 s->pal[i] = bytestream2_get_be24(&gb) << 2; 00342 s->pal[i] |= 0xFF << 24 | (s->pal[i] >> 6) & 0x30303; 00343 } 00344 s->pic.palette_has_changed = 1; 00345 } else if (chunk_type <= 9) { 00346 if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) { 00347 av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n", 00348 chunk_name[chunk_type - 2]); 00349 return AVERROR_INVALIDDATA; 00350 } 00351 } else { 00352 av_log(avctx, AV_LOG_WARNING, "Ignoring unknown chunk type %d\n", 00353 chunk_type); 00354 } 00355 buf += chunk_size; 00356 } 00357 00358 buf = s->frame_buf; 00359 dst = s->pic.data[0]; 00360 for (i = 0; i < avctx->height; i++) { 00361 memcpy(dst, buf, avctx->width); 00362 dst += s->pic.linesize[0]; 00363 buf += avctx->width; 00364 } 00365 memcpy(s->pic.data[1], s->pal, sizeof(s->pal)); 00366 00367 *data_size = sizeof(AVFrame); 00368 *(AVFrame*)data = s->pic; 00369 00370 return avpkt->size; 00371 } 00372 00373 static av_cold int dfa_decode_end(AVCodecContext *avctx) 00374 { 00375 DfaContext *s = avctx->priv_data; 00376 00377 if (s->pic.data[0]) 00378 avctx->release_buffer(avctx, &s->pic); 00379 00380 av_freep(&s->frame_buf); 00381 00382 return 0; 00383 } 00384 00385 AVCodec ff_dfa_decoder = { 00386 .name = "dfa", 00387 .type = AVMEDIA_TYPE_VIDEO, 00388 .id = CODEC_ID_DFA, 00389 .priv_data_size = sizeof(DfaContext), 00390 .init = dfa_decode_init, 00391 .close = dfa_decode_end, 00392 .decode = dfa_decode_frame, 00393 .capabilities = CODEC_CAP_DR1, 00394 .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), 00395 };