• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • 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     GetByteContext g;
00037 } PicContext;
00038 
00039 static void picmemset_8bpp(PicContext *s, int value, int run, int *x, int *y)
00040 {
00041     while (run > 0) {
00042         uint8_t *d = s->frame.data[0] + *y * s->frame.linesize[0];
00043         if (*x + run >= s->width) {
00044             int n = s->width - *x;
00045             memset(d + *x, value, n);
00046             run -= n;
00047             *x = 0;
00048             *y -= 1;
00049             if (*y < 0)
00050                 break;
00051         } else {
00052             memset(d + *x, value, run);
00053             *x += run;
00054             break;
00055         }
00056     }
00057 }
00058 
00059 static void picmemset(PicContext *s, int value, int run,
00060                       int *x, int *y, int *plane, int bits_per_plane)
00061 {
00062     uint8_t *d;
00063     int shift = *plane * bits_per_plane;
00064     int mask  = ((1 << bits_per_plane) - 1) << shift;
00065     value   <<= shift;
00066 
00067     while (run > 0) {
00068         int j;
00069         for (j = 8-bits_per_plane; j >= 0; j -= bits_per_plane) {
00070             d = s->frame.data[0] + *y * s->frame.linesize[0];
00071             d[*x] |= (value >> j) & mask;
00072             *x += 1;
00073             if (*x == s->width) {
00074                 *y -= 1;
00075                 *x = 0;
00076                 if (*y < 0) {
00077                    *y = s->height - 1;
00078                    *plane += 1;
00079                    value <<= bits_per_plane;
00080                    mask  <<= bits_per_plane;
00081                    if (*plane >= s->nb_planes)
00082                        break;
00083                 }
00084             }
00085         }
00086         run--;
00087     }
00088 }
00089 
00090 static const uint8_t cga_mode45_index[6][4] = {
00091     [0] = { 0, 3,  5,   7 }, // mode4, palette#1, low intensity
00092     [1] = { 0, 2,  4,   6 }, // mode4, palette#2, low intensity
00093     [2] = { 0, 3,  4,   7 }, // mode5, low intensity
00094     [3] = { 0, 11, 13, 15 }, // mode4, palette#1, high intensity
00095     [4] = { 0, 10, 12, 14 }, // mode4, palette#2, high intensity
00096     [5] = { 0, 11, 12, 15 }, // mode5, high intensity
00097 };
00098 
00099 static av_cold int decode_init(AVCodecContext *avctx)
00100 {
00101     PicContext *s = avctx->priv_data;
00102 
00103     avcodec_get_frame_defaults(&s->frame);
00104     return 0;
00105 }
00106 
00107 static int decode_frame(AVCodecContext *avctx,
00108                         void *data, int *data_size,
00109                         AVPacket *avpkt)
00110 {
00111     PicContext *s = avctx->priv_data;
00112     uint32_t *palette;
00113     int bits_per_plane, bpp, etype, esize, npal, pos_after_pal;
00114     int i, x, y, plane, tmp;
00115 
00116     bytestream2_init(&s->g, avpkt->data, avpkt->size);
00117 
00118     if (bytestream2_get_bytes_left(&s->g) < 11)
00119         return AVERROR_INVALIDDATA;
00120 
00121     if (bytestream2_get_le16u(&s->g) != 0x1234)
00122         return AVERROR_INVALIDDATA;
00123 
00124     s->width       = bytestream2_get_le16u(&s->g);
00125     s->height      = bytestream2_get_le16u(&s->g);
00126     bytestream2_skip(&s->g, 4);
00127     tmp            = bytestream2_get_byteu(&s->g);
00128     bits_per_plane = tmp & 0xF;
00129     s->nb_planes   = (tmp >> 4) + 1;
00130     bpp            = bits_per_plane * s->nb_planes;
00131     if (bits_per_plane > 8 || bpp < 1 || bpp > 32) {
00132         av_log_ask_for_sample(avctx, "unsupported bit depth\n");
00133         return AVERROR_INVALIDDATA;
00134     }
00135 
00136     if (bytestream2_peek_byte(&s->g) == 0xFF || bpp == 8) {
00137         bytestream2_skip(&s->g, 2);
00138         etype = bytestream2_get_le16(&s->g);
00139         esize = bytestream2_get_le16(&s->g);
00140         if (bytestream2_get_bytes_left(&s->g) < esize)
00141             return AVERROR_INVALIDDATA;
00142     } else {
00143         etype = -1;
00144         esize = 0;
00145     }
00146 
00147     avctx->pix_fmt = PIX_FMT_PAL8;
00148 
00149     if (s->width != avctx->width && s->height != avctx->height) {
00150         if (av_image_check_size(s->width, s->height, 0, avctx) < 0)
00151             return -1;
00152         avcodec_set_dimensions(avctx, s->width, s->height);
00153         if (s->frame.data[0])
00154             avctx->release_buffer(avctx, &s->frame);
00155     }
00156 
00157     if (avctx->get_buffer(avctx, &s->frame) < 0){
00158         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00159         return -1;
00160     }
00161     memset(s->frame.data[0], 0, s->height * s->frame.linesize[0]);
00162     s->frame.pict_type           = AV_PICTURE_TYPE_I;
00163     s->frame.palette_has_changed = 1;
00164 
00165     pos_after_pal = bytestream2_tell(&s->g) + esize;
00166     palette = (uint32_t*)s->frame.data[1];
00167     if (etype == 1 && esize > 1 && bytestream2_peek_byte(&s->g) < 6) {
00168         int idx = bytestream2_get_byte(&s->g);
00169         npal = 4;
00170         for (i = 0; i < npal; i++)
00171             palette[i] = ff_cga_palette[ cga_mode45_index[idx][i] ];
00172     } else if (etype == 2) {
00173         npal = FFMIN(esize, 16);
00174         for (i = 0; i < npal; i++) {
00175             int pal_idx = bytestream2_get_byte(&s->g);
00176             palette[i]  = ff_cga_palette[FFMIN(pal_idx, 16)];
00177         }
00178     } else if (etype == 3) {
00179         npal = FFMIN(esize, 16);
00180         for (i = 0; i < npal; i++) {
00181             int pal_idx = bytestream2_get_byte(&s->g);
00182             palette[i]  = ff_ega_palette[FFMIN(pal_idx, 63)];
00183         }
00184     } else if (etype == 4 || etype == 5) {
00185         npal = FFMIN(esize / 3, 256);
00186         for (i = 0; i < npal; i++) {
00187             palette[i] = bytestream2_get_be24(&s->g) << 2;
00188             palette[i] |= 0xFFU << 24 | palette[i] >> 6 & 0x30303;
00189         }
00190     } else {
00191         if (bpp == 1) {
00192             npal = 2;
00193             palette[0] = 0xFF000000;
00194             palette[1] = 0xFFFFFFFF;
00195         } else if (bpp == 2) {
00196             npal = 4;
00197             for (i = 0; i < npal; i++)
00198                 palette[i] = ff_cga_palette[ cga_mode45_index[0][i] ];
00199         } else {
00200             npal = 16;
00201             memcpy(palette, ff_cga_palette, npal * 4);
00202         }
00203     }
00204     // fill remaining palette entries
00205     memset(palette + npal, 0, AVPALETTE_SIZE - npal * 4);
00206     // skip remaining palette bytes
00207     bytestream2_seek(&s->g, pos_after_pal, SEEK_SET);
00208 
00209     y = s->height - 1;
00210     if (bytestream2_get_le16(&s->g)) {
00211         x = 0;
00212         plane = 0;
00213         while (y >= 0 && bytestream2_get_bytes_left(&s->g) >= 6) {
00214             int stop_size, marker, t1, t2;
00215 
00216             t1        = bytestream2_get_bytes_left(&s->g);
00217             t2        = bytestream2_get_le16(&s->g);
00218             stop_size = t1 - FFMIN(t1, t2);
00219             // ignore uncompressed block size
00220             bytestream2_skip(&s->g, 2);
00221             marker    = bytestream2_get_byte(&s->g);
00222 
00223             while (plane < s->nb_planes && y >= 0 &&
00224                    bytestream2_get_bytes_left(&s->g) > stop_size) {
00225                 int run = 1;
00226                 int val = bytestream2_get_byte(&s->g);
00227                 if (val == marker) {
00228                     run = bytestream2_get_byte(&s->g);
00229                     if (run == 0)
00230                         run = bytestream2_get_le16(&s->g);
00231                     val = bytestream2_get_byte(&s->g);
00232                 }
00233                 if (!bytestream2_get_bytes_left(&s->g))
00234                     break;
00235 
00236                 if (bits_per_plane == 8) {
00237                     picmemset_8bpp(s, val, run, &x, &y);
00238                 } else {
00239                     picmemset(s, val, run, &x, &y, &plane, bits_per_plane);
00240                 }
00241             }
00242         }
00243     } else {
00244         while (y >= 0 && bytestream2_get_bytes_left(&s->g) > 0) {
00245             memcpy(s->frame.data[0] + y * s->frame.linesize[0], s->g.buffer, FFMIN(avctx->width, bytestream2_get_bytes_left(&s->g)));
00246             bytestream2_skip(&s->g, avctx->width);
00247             y--;
00248         }
00249     }
00250 
00251     *data_size = sizeof(AVFrame);
00252     *(AVFrame*)data = s->frame;
00253     return avpkt->size;
00254 }
00255 
00256 static av_cold int decode_end(AVCodecContext *avctx)
00257 {
00258     PicContext *s = avctx->priv_data;
00259     if (s->frame.data[0])
00260         avctx->release_buffer(avctx, &s->frame);
00261     return 0;
00262 }
00263 
00264 AVCodec ff_pictor_decoder = {
00265     .name           = "pictor",
00266     .type           = AVMEDIA_TYPE_VIDEO,
00267     .id             = CODEC_ID_PICTOR,
00268     .priv_data_size = sizeof(PicContext),
00269     .init           = decode_init,
00270     .close          = decode_end,
00271     .decode         = decode_frame,
00272     .capabilities   = CODEC_CAP_DR1,
00273     .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"),
00274 };
Generated on Fri Feb 1 2013 14:34:41 for FFmpeg by doxygen 1.7.1