• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavcodec/pictordec.c

Go to the documentation of this file.
00001 /*
00002  * Pictor/PC Paint decoder
00003  * Copyright (c) 2010 Peter Ross <pross@xvid.org>
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 
00027 #include "libavutil/imgutils.h"
00028 #include "avcodec.h"
00029 #include "bytestream.h"
00030 #include "cga_data.h"
00031 
00032 typedef struct PicContext {
00033     AVFrame frame;
00034     int width, height;
00035     int nb_planes;
00036 } PicContext;
00037 
00038 static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y)
00039 {
00040     while (run > 0) {
00041         uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0];
00042         if (*x + run >= s->width) {
00043             int n = s->width - *x;
00044             memset(d + *x, value, n);
00045             run -= n;
00046             *x = 0;
00047             *y -= 1;
00048             if (*y < 0)
00049                 break;
00050         } else {
00051             memset(d + *x, value, run);
00052             *x += run;
00053             break;
00054         }
00055     }
00056 }
00057 
00058 static void picmemset(PicContext *s, int value, int run, int *x, int *y, int *plane, int bits_per_plane)
00059 {
00060     uint8_t *d;
00061     int shift = *plane * bits_per_plane;
00062     int mask  = ((1 << bits_per_plane) - 1) << shift;
00063     value   <<= shift;
00064 
00065     while (run > 0) {
00066         int j;
00067         for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
00068             d = s->frame.data[0] + *y * s->frame.linesize[0];
00069             d[*x] |= (value >> j) & mask;
00070             *x += 1;
00071             if (*x == s->width) {
00072                 *y -= 1;
00073                 *x = 0;
00074                 if (*y < 0) {
00075                    *y = s->height - 1;
00076                    *plane += 1;
00077                    value <<= bits_per_plane;
00078                    mask  <<= bits_per_plane;
00079                    if (*plane >= s->nb_planes)
00080                        break;
00081                 }
00082             }
00083         }
00084         run--;
00085     }
00086 }
00087 
00088 static const uint8_t cga_mode45_index[6][4] = {
00089     [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
00090     [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
00091     [2] = { 0, 3,  4,   7 }, // mode5, low intensity
00092     [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
00093     [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
00094     [5] = { 0, 11, 12, 15 }, // mode5, high intensity
00095 };
00096 
00097 static av_cold int decode_init(AVCodecContext *avctx)
00098 {
00099     PicContext *s = avctx->priv_data;
00100 
00101     avcodec_get_frame_defaults(&s->frame);
00102     return 0;
00103 }
00104 
00105 static int decode_frame(AVCodecContext *avctx,
00106                         void *data, int *data_size,
00107                         AVPacket *avpkt)
00108 {
00109     PicContext *s = avctx->priv_data;
00110     int buf_size = avpkt->size;
00111     const uint8_t *buf = avpkt->data;
00112     const uint8_t *buf_end = avpkt->data + buf_size;
00113     uint32_t *palette;
00114     int bits_per_plane, bpp, etype, esize, npal;
00115     int i, x, y, plane;
00116 
00117     if (buf_size < 11)
00118         return AVERROR_INVALIDDATA;
00119 
00120     if (bytestream_get_le16(&buf) != 0x1234)
00121         return AVERROR_INVALIDDATA;
00122     s->width  = bytestream_get_le16(&buf);
00123     s->height = bytestream_get_le16(&buf);
00124     buf += 4;
00125     bits_per_plane    = *buf & 0xF;
00126     s->nb_planes      = (*buf++ >> 4) + 1;
00127     bpp               = s->nb_planes ? bits_per_plane*s->nb_planes : bits_per_plane;
00128     if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
00129         av_log_ask_for_sample(s, "unsupported bit depth\n");
00130         return AVERROR_INVALIDDATA;
00131     }
00132 
00133     if (*buf == 0xFF) {
00134         buf += 2;
00135         etype  = bytestream_get_le16(&buf);
00136         esize  = bytestream_get_le16(&buf);
00137         if (buf_end - buf < esize)
00138             return AVERROR_INVALIDDATA;
00139     } else {
00140         etype = -1;
00141         esize = 0;
00142     }
00143 
00144     avctx->pix_fmt = PIX_FMT_PAL8;
00145 
00146     if (s->width != avctx->width && s->height != avctx->height) {
00147         if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
00148             return -1;
00149         avcodec_set_dimensions(avctx, s->width, s->height);
00150         if (s->frame.data[0])
00151             avctx->release_buffer(avctx, &s->frame);
00152     }
00153 
00154     if (avctx->get_buffer(avctx, &s->frame) < 0){
00155         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00156         return -1;
00157     }
00158     memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]);
00159     s->frame.pict_type           = AV_PICTURE_TYPE_I;
00160     s->frame.palette_has_changed = 1;
00161 
00162     palette = (uint32_t*)s->frame.data[1];
00163     if (etype == 1 && esize > 1 && *buf < 6) {
00164         int idx = *buf;
00165         npal = 4;
00166         for (i = 0; i < npal; i++)
00167             palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
00168     } else if (etype == 2) {
00169         npal = FFMIN(esize, 16);
00170         for (i = 0; i < npal; i++)
00171             palette[i] = ff_cga_palette[ FFMIN(buf[i], 16)];
00172     } else if (etype == 3) {
00173         npal = FFMIN(esize, 16);
00174         for (i = 0; i < npal; i++)
00175             palette[i] = ff_ega_palette[ FFMIN(buf[i], 63)];
00176     } else if (etype == 4 || etype == 5) {
00177         npal = FFMIN(esize / 3, 256);
00178         for (i = 0; i < npal; i++)
00179             palette[i] = AV_RB24(buf + i*3) << 2;
00180     } else {
00181         if (bpp == 1) {
00182             npal = 2;
00183             palette[0] = 0x000000;
00184             palette[1] = 0xFFFFFF;
00185         } else if (bpp == 2) {
00186             npal = 4;
00187             for (i = 0; i < npal; i++)
00188                 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
00189         } else {
00190             npal = 16;
00191             memcpy(palette, ff_cga_palette, npal * 4);
00192         }
00193     }
00194     // fill remaining palette entries
00195     memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
00196     buf += esize;
00197 
00198 
00199     x = 0;
00200     y = s->height - 1;
00201     plane = 0;
00202     if (bytestream_get_le16(&buf)) {
00203         while (buf_end - buf >= 6) {
00204             const uint8_t *buf_pend = buf + FFMIN(AV_RL16(buf), buf_end - buf);
00205             //ignore uncompressed block size reported at buf[2]
00206             int marker = buf[4];
00207             buf += 5;
00208 
00209             while (plane < s->nb_planes && buf_pend - buf >= 1) {
00210                 int run = 1;
00211                 int val = *buf++;
00212                 if (val == marker) {
00213                     run = *buf++;
00214                     if (run == 0)
00215                         run = bytestream_get_le16(&buf);
00216                     val = *buf++;
00217                 }
00218                 if (buf > buf_end)
00219                     break;
00220 
00221                 if (bits_per_plane == 8) {
00222                     picmemset_8bpp(s, val, run, &x, &y);
00223                     if (y < 0)
00224                         break;
00225                 } else {
00226                     picmemset(s, val, run, &x, &y, &plane, bits_per_plane);
00227                 }
00228             }
00229         }
00230     } else {
00231         av_log_ask_for_sample(s, "uncompressed image\n");
00232         return buf_size;
00233     }
00234 
00235     *data_size = sizeof(AVFrame);
00236     *(AVFrame*)data = s->frame;
00237     return buf_size;
00238 }
00239 
00240 static av_cold int decode_end(AVCodecContext *avctx)
00241 {
00242     PicContext *s = avctx->priv_data;
00243     if (s->frame.data[0])
00244         avctx->release_buffer(avctx, &s->frame);
00245     return 0;
00246 }
00247 
00248 AVCodec ff_pictor_decoder = {
00249     "pictor",
00250     AVMEDIA_TYPE_VIDEO,
00251     CODEC_ID_PICTOR,
00252     sizeof(PicContext),
00253     decode_init,
00254     NULL,
00255     decode_end,
00256     decode_frame,
00257     CODEC_CAP_DR1,
00258     .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
00259 };

Generated on Fri Feb 22 2013 07:24:28 for FFmpeg by  doxygen 1.7.1