1/* 2 * Chronomaster DFA Video Decoder 3 * Copyright (c) 2011 Konstantin Shishkov 4 * based on work by Vladimir "VAG" Gneushev 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23#include <inttypes.h> 24 25#include "avcodec.h" 26#include "bytestream.h" 27#include "codec_internal.h" 28#include "internal.h" 29 30#include "libavutil/avassert.h" 31#include "libavutil/imgutils.h" 32#include "libavutil/mem.h" 33 34typedef struct DfaContext { 35 uint32_t pal[256]; 36 uint8_t *frame_buf; 37} DfaContext; 38 39static av_cold int dfa_decode_init(AVCodecContext *avctx) 40{ 41 DfaContext *s = avctx->priv_data; 42 43 avctx->pix_fmt = AV_PIX_FMT_PAL8; 44 45 if (!avctx->width || !avctx->height || FFMAX(avctx->width, avctx->height) >= (1<<16)) 46 return AVERROR_INVALIDDATA; 47 48 av_assert0(av_image_check_size(avctx->width, avctx->height, 0, avctx) >= 0); 49 50 s->frame_buf = av_mallocz(avctx->width * avctx->height); 51 if (!s->frame_buf) 52 return AVERROR(ENOMEM); 53 54 return 0; 55} 56 57static int decode_copy(GetByteContext *gb, uint8_t *frame, int width, int height) 58{ 59 const int size = width * height; 60 61 if (bytestream2_get_buffer(gb, frame, size) != size) 62 return AVERROR_INVALIDDATA; 63 return 0; 64} 65 66static int decode_tsw1(GetByteContext *gb, uint8_t *frame, int width, int height) 67{ 68 const uint8_t *frame_start = frame; 69 const uint8_t *frame_end = frame + width * height; 70 int mask = 0x10000, bitbuf = 0; 71 int v, count; 72 unsigned segments; 73 unsigned offset; 74 75 segments = bytestream2_get_le32(gb); 76 offset = bytestream2_get_le32(gb); 77 if (segments == 0 && offset == frame_end - frame) 78 return 0; // skip frame 79 if (frame_end - frame <= offset) 80 return AVERROR_INVALIDDATA; 81 frame += offset; 82 while (segments--) { 83 if (bytestream2_get_bytes_left(gb) < 2) 84 return AVERROR_INVALIDDATA; 85 if (mask == 0x10000) { 86 bitbuf = bytestream2_get_le16u(gb); 87 mask = 1; 88 } 89 if (frame_end - frame < 2) 90 return AVERROR_INVALIDDATA; 91 if (bitbuf & mask) { 92 v = bytestream2_get_le16(gb); 93 offset = (v & 0x1FFF) << 1; 94 count = ((v >> 13) + 2) << 1; 95 if (frame - frame_start < offset || frame_end - frame < count) 96 return AVERROR_INVALIDDATA; 97 av_memcpy_backptr(frame, offset, count); 98 frame += count; 99 } else { 100 *frame++ = bytestream2_get_byte(gb); 101 *frame++ = bytestream2_get_byte(gb); 102 } 103 mask <<= 1; 104 } 105 106 return 0; 107} 108 109static int decode_dsw1(GetByteContext *gb, uint8_t *frame, int width, int height) 110{ 111 const uint8_t *frame_start = frame; 112 const uint8_t *frame_end = frame + width * height; 113 int mask = 0x10000, bitbuf = 0; 114 int v, offset, count, segments; 115 116 segments = bytestream2_get_le16(gb); 117 while (segments--) { 118 if (bytestream2_get_bytes_left(gb) < 2) 119 return AVERROR_INVALIDDATA; 120 if (mask == 0x10000) { 121 bitbuf = bytestream2_get_le16u(gb); 122 mask = 1; 123 } 124 if (frame_end - frame < 2) 125 return AVERROR_INVALIDDATA; 126 if (bitbuf & mask) { 127 v = bytestream2_get_le16(gb); 128 offset = (v & 0x1FFF) << 1; 129 count = ((v >> 13) + 2) << 1; 130 if (frame - frame_start < offset || frame_end - frame < count) 131 return AVERROR_INVALIDDATA; 132 av_memcpy_backptr(frame, offset, count); 133 frame += count; 134 } else if (bitbuf & (mask << 1)) { 135 frame += bytestream2_get_le16(gb); 136 } else { 137 *frame++ = bytestream2_get_byte(gb); 138 *frame++ = bytestream2_get_byte(gb); 139 } 140 mask <<= 2; 141 } 142 143 return 0; 144} 145 146static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height) 147{ 148 const uint8_t *frame_start = frame; 149 const uint8_t *frame_end = frame + width * height; 150 int mask = 0x10000, bitbuf = 0; 151 int i, v, offset, count, segments; 152 153 if ((width | height) & 1) 154 return AVERROR_INVALIDDATA; 155 segments = bytestream2_get_le16(gb); 156 while (segments--) { 157 if (bytestream2_get_bytes_left(gb) < 2) 158 return AVERROR_INVALIDDATA; 159 if (mask == 0x10000) { 160 bitbuf = bytestream2_get_le16u(gb); 161 mask = 1; 162 } 163 164 if (bitbuf & mask) { 165 v = bytestream2_get_le16(gb); 166 offset = (v & 0x1FFF) << 2; 167 count = ((v >> 13) + 2) << 1; 168 if (frame - frame_start < offset || frame_end - frame < count*2 + width) 169 return AVERROR_INVALIDDATA; 170 for (i = 0; i < count; i++) { 171 frame[0] = frame[1] = 172 frame[width] = frame[width + 1] = frame[-offset]; 173 174 frame += 2; 175 } 176 } else if (bitbuf & (mask << 1)) { 177 v = bytestream2_get_le16(gb)*2; 178 if (frame - frame_end < v) 179 return AVERROR_INVALIDDATA; 180 frame += v; 181 } else { 182 if (width < 4 || frame_end - frame < width + 4) 183 return AVERROR_INVALIDDATA; 184 frame[0] = frame[1] = 185 frame[width] = frame[width + 1] = bytestream2_get_byte(gb); 186 frame += 2; 187 frame[0] = frame[1] = 188 frame[width] = frame[width + 1] = bytestream2_get_byte(gb); 189 frame += 2; 190 } 191 mask <<= 2; 192 } 193 194 return 0; 195} 196 197static int decode_bdlt(GetByteContext *gb, uint8_t *frame, int width, int height) 198{ 199 uint8_t *line_ptr; 200 int count, lines, segments; 201 202 count = bytestream2_get_le16(gb); 203 if (count >= height) 204 return AVERROR_INVALIDDATA; 205 frame += width * count; 206 lines = bytestream2_get_le16(gb); 207 if (count + lines > height) 208 return AVERROR_INVALIDDATA; 209 210 while (lines--) { 211 if (bytestream2_get_bytes_left(gb) < 1) 212 return AVERROR_INVALIDDATA; 213 line_ptr = frame; 214 frame += width; 215 segments = bytestream2_get_byteu(gb); 216 while (segments--) { 217 if (frame - line_ptr <= bytestream2_peek_byte(gb)) 218 return AVERROR_INVALIDDATA; 219 line_ptr += bytestream2_get_byte(gb); 220 count = (int8_t)bytestream2_get_byte(gb); 221 if (count >= 0) { 222 if (frame - line_ptr < count) 223 return AVERROR_INVALIDDATA; 224 if (bytestream2_get_buffer(gb, line_ptr, count) != count) 225 return AVERROR_INVALIDDATA; 226 } else { 227 count = -count; 228 if (frame - line_ptr < count) 229 return AVERROR_INVALIDDATA; 230 memset(line_ptr, bytestream2_get_byte(gb), count); 231 } 232 line_ptr += count; 233 } 234 } 235 236 return 0; 237} 238 239static int decode_wdlt(GetByteContext *gb, uint8_t *frame, int width, int height) 240{ 241 const uint8_t *frame_end = frame + width * height; 242 uint8_t *line_ptr; 243 int count, i, v, lines, segments; 244 int y = 0; 245 246 lines = bytestream2_get_le16(gb); 247 if (lines > height) 248 return AVERROR_INVALIDDATA; 249 250 while (lines--) { 251 if (bytestream2_get_bytes_left(gb) < 2) 252 return AVERROR_INVALIDDATA; 253 segments = bytestream2_get_le16u(gb); 254 while ((segments & 0xC000) == 0xC000) { 255 unsigned skip_lines = -(int16_t)segments; 256 int64_t delta = -((int16_t)segments * (int64_t)width); 257 if (frame_end - frame <= delta || y + lines + skip_lines > height) 258 return AVERROR_INVALIDDATA; 259 frame += delta; 260 y += skip_lines; 261 segments = bytestream2_get_le16(gb); 262 } 263 264 if (frame_end <= frame) 265 return AVERROR_INVALIDDATA; 266 if (segments & 0x8000) { 267 frame[width - 1] = segments & 0xFF; 268 segments = bytestream2_get_le16(gb); 269 } 270 line_ptr = frame; 271 if (frame_end - frame < width) 272 return AVERROR_INVALIDDATA; 273 frame += width; 274 y++; 275 while (segments--) { 276 if (frame - line_ptr <= bytestream2_peek_byte(gb)) 277 return AVERROR_INVALIDDATA; 278 line_ptr += bytestream2_get_byte(gb); 279 count = (int8_t)bytestream2_get_byte(gb); 280 if (count >= 0) { 281 if (frame - line_ptr < count * 2) 282 return AVERROR_INVALIDDATA; 283 if (bytestream2_get_buffer(gb, line_ptr, count * 2) != count * 2) 284 return AVERROR_INVALIDDATA; 285 line_ptr += count * 2; 286 } else { 287 count = -count; 288 if (frame - line_ptr < count * 2) 289 return AVERROR_INVALIDDATA; 290 v = bytestream2_get_le16(gb); 291 for (i = 0; i < count; i++) 292 bytestream_put_le16(&line_ptr, v); 293 } 294 } 295 } 296 297 return 0; 298} 299 300static int decode_tdlt(GetByteContext *gb, uint8_t *frame, int width, int height) 301{ 302 const uint8_t *frame_end = frame + width * height; 303 uint32_t segments = bytestream2_get_le32(gb); 304 int skip, copy; 305 306 while (segments--) { 307 if (bytestream2_get_bytes_left(gb) < 2) 308 return AVERROR_INVALIDDATA; 309 copy = bytestream2_get_byteu(gb) * 2; 310 skip = bytestream2_get_byteu(gb) * 2; 311 if (frame_end - frame < copy + skip || 312 bytestream2_get_bytes_left(gb) < copy) 313 return AVERROR_INVALIDDATA; 314 frame += skip; 315 bytestream2_get_buffer(gb, frame, copy); 316 frame += copy; 317 } 318 319 return 0; 320} 321 322static int decode_blck(GetByteContext *gb, uint8_t *frame, int width, int height) 323{ 324 memset(frame, 0, width * height); 325 return 0; 326} 327 328 329typedef int (*chunk_decoder)(GetByteContext *gb, uint8_t *frame, int width, int height); 330 331static const chunk_decoder decoder[8] = { 332 decode_copy, decode_tsw1, decode_bdlt, decode_wdlt, 333 decode_tdlt, decode_dsw1, decode_blck, decode_dds1, 334}; 335 336static const char chunk_name[8][5] = { 337 "COPY", "TSW1", "BDLT", "WDLT", "TDLT", "DSW1", "BLCK", "DDS1" 338}; 339 340static int dfa_decode_frame(AVCodecContext *avctx, AVFrame *frame, 341 int *got_frame, AVPacket *avpkt) 342{ 343 DfaContext *s = avctx->priv_data; 344 GetByteContext gb; 345 const uint8_t *buf = avpkt->data; 346 uint32_t chunk_type, chunk_size; 347 uint8_t *dst; 348 int ret; 349 int i, pal_elems; 350 int version = avctx->extradata_size==2 ? AV_RL16(avctx->extradata) : 0; 351 352 if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 353 return ret; 354 355 bytestream2_init(&gb, avpkt->data, avpkt->size); 356 while (bytestream2_get_bytes_left(&gb) > 0) { 357 if (bytestream2_get_bytes_left(&gb) < 12) 358 return AVERROR_INVALIDDATA; 359 bytestream2_skip(&gb, 4); 360 chunk_size = bytestream2_get_le32(&gb); 361 chunk_type = bytestream2_get_le32(&gb); 362 if (!chunk_type) 363 break; 364 if (chunk_type == 1) { 365 pal_elems = FFMIN(chunk_size / 3, 256); 366 for (i = 0; i < pal_elems; i++) { 367 s->pal[i] = bytestream2_get_be24(&gb) << 2; 368 s->pal[i] |= 0xFFU << 24 | (s->pal[i] >> 6) & 0x30303; 369 } 370 frame->palette_has_changed = 1; 371 } else if (chunk_type <= 9) { 372 if (decoder[chunk_type - 2](&gb, s->frame_buf, avctx->width, avctx->height)) { 373 av_log(avctx, AV_LOG_ERROR, "Error decoding %s chunk\n", 374 chunk_name[chunk_type - 2]); 375 return AVERROR_INVALIDDATA; 376 } 377 } else { 378 av_log(avctx, AV_LOG_WARNING, 379 "Ignoring unknown chunk type %"PRIu32"\n", 380 chunk_type); 381 } 382 buf += chunk_size; 383 } 384 385 buf = s->frame_buf; 386 dst = frame->data[0]; 387 if (version == 0x100) { 388 for (i = 0; i < avctx->height; i++) { 389 int j; 390 const uint8_t *buf1 = buf + (i&3)*(avctx->width/4) + (i/4)*avctx->width; 391 int stride = (avctx->height/4)*avctx->width; 392 for(j = 0; j < avctx->width/4; j++) { 393 dst[4*j+0] = buf1[j + 0*stride]; 394 dst[4*j+1] = buf1[j + 1*stride]; 395 dst[4*j+2] = buf1[j + 2*stride]; 396 dst[4*j+3] = buf1[j + 3*stride]; 397 } 398 j *= 4; 399 for(; j < avctx->width; j++) { 400 dst[j] = buf1[(j/4) + (j&3)*stride]; 401 } 402 dst += frame->linesize[0]; 403 } 404 } else 405 av_image_copy_plane(dst, frame->linesize[0], buf, avctx->width, 406 avctx->width, avctx->height); 407 408 memcpy(frame->data[1], s->pal, sizeof(s->pal)); 409 410 *got_frame = 1; 411 412 return avpkt->size; 413} 414 415static av_cold int dfa_decode_end(AVCodecContext *avctx) 416{ 417 DfaContext *s = avctx->priv_data; 418 419 av_freep(&s->frame_buf); 420 421 return 0; 422} 423 424const FFCodec ff_dfa_decoder = { 425 .p.name = "dfa", 426 .p.long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), 427 .p.type = AVMEDIA_TYPE_VIDEO, 428 .p.id = AV_CODEC_ID_DFA, 429 .priv_data_size = sizeof(DfaContext), 430 .init = dfa_decode_init, 431 .close = dfa_decode_end, 432 FF_CODEC_DECODE_CB(dfa_decode_frame), 433 .p.capabilities = AV_CODEC_CAP_DR1, 434 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 435}; 436