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