libavcodec/sgidec.c
Go to the documentation of this file.
00001 /*
00002  * SGI image decoder
00003  * Todd Kirby <doubleshot@pacbell.net>
00004  *
00005  * This file is part of Libav.
00006  *
00007  * Libav 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  * Libav 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 Libav; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00020  */
00021 
00022 #include "libavutil/imgutils.h"
00023 #include "avcodec.h"
00024 #include "bytestream.h"
00025 #include "sgi.h"
00026 
00027 typedef struct SgiState {
00028     AVCodecContext *avctx;
00029     AVFrame picture;
00030     unsigned int width;
00031     unsigned int height;
00032     unsigned int depth;
00033     unsigned int bytes_per_channel;
00034     int linesize;
00035     GetByteContext g;
00036 } SgiState;
00037 
00046 static int expand_rle_row(SgiState *s, uint8_t *out_buf,
00047                           int len, int pixelstride)
00048 {
00049     unsigned char pixel, count;
00050     unsigned char *orig = out_buf;
00051 
00052     while (1) {
00053         if (bytestream2_get_bytes_left(&s->g) < 1)
00054             return AVERROR_INVALIDDATA;
00055         pixel = bytestream2_get_byteu(&s->g);
00056         if (!(count = (pixel & 0x7f))) {
00057             return (out_buf - orig) / pixelstride;
00058         }
00059 
00060         /* Check for buffer overflow. */
00061         if (pixelstride * (count - 1) >= len) {
00062             av_log(s->avctx, AV_LOG_ERROR, "Invalid pixel count.\n");
00063             return AVERROR_INVALIDDATA;
00064         }
00065 
00066         if (pixel & 0x80) {
00067             while (count--) {
00068                 *out_buf = bytestream2_get_byte(&s->g);
00069                 out_buf += pixelstride;
00070             }
00071         } else {
00072             pixel = bytestream2_get_byte(&s->g);
00073 
00074             while (count--) {
00075                 *out_buf = pixel;
00076                 out_buf += pixelstride;
00077             }
00078         }
00079     }
00080 }
00081 
00088 static int read_rle_sgi(uint8_t *out_buf, SgiState *s)
00089 {
00090     uint8_t *dest_row;
00091     unsigned int len = s->height * s->depth * 4;
00092     GetByteContext g_table = s->g;
00093     unsigned int y, z;
00094     unsigned int start_offset;
00095 
00096     /* size of  RLE offset and length tables */
00097     if (len * 2  > bytestream2_get_bytes_left(&s->g)) {
00098         return AVERROR_INVALIDDATA;
00099     }
00100 
00101     for (z = 0; z < s->depth; z++) {
00102         dest_row = out_buf;
00103         for (y = 0; y < s->height; y++) {
00104             dest_row -= s->linesize;
00105             start_offset = bytestream2_get_be32(&g_table);
00106             bytestream2_seek(&s->g, start_offset, SEEK_SET);
00107             if (expand_rle_row(s, dest_row + z, FFABS(s->linesize) - z,
00108                                s->depth) != s->width) {
00109                 return AVERROR_INVALIDDATA;
00110             }
00111         }
00112     }
00113     return 0;
00114 }
00115 
00123 static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end,
00124                                  SgiState *s)
00125 {
00126     int x, y, z;
00127     unsigned int offset = s->height * s->width * s->bytes_per_channel;
00128     GetByteContext gp[4];
00129 
00130     /* Test buffer size. */
00131     if (offset * s->depth > bytestream2_get_bytes_left(&s->g))
00132         return AVERROR_INVALIDDATA;
00133 
00134     /* Create a reader for each plane */
00135     for (z = 0; z < s->depth; z++) {
00136         gp[z] = s->g;
00137         bytestream2_skip(&gp[z], z * offset);
00138     }
00139 
00140     for (y = s->height - 1; y >= 0; y--) {
00141         out_end = out_buf + (y * s->linesize);
00142         if (s->bytes_per_channel == 1) {
00143             for (x = s->width; x > 0; x--)
00144                 for (z = 0; z < s->depth; z++)
00145                     *out_end++ = bytestream2_get_byteu(&gp[z]);
00146         } else {
00147             uint16_t *out16 = (uint16_t *)out_end;
00148             for (x = s->width; x > 0; x--)
00149                 for (z = 0; z < s->depth; z++)
00150                     *out16++ = bytestream2_get_ne16u(&gp[z]);
00151         }
00152     }
00153     return 0;
00154 }
00155 
00156 static int decode_frame(AVCodecContext *avctx,
00157                         void *data, int *data_size,
00158                         AVPacket *avpkt)
00159 {
00160     SgiState *s = avctx->priv_data;
00161     AVFrame *picture = data;
00162     AVFrame *p = &s->picture;
00163     unsigned int dimension, rle;
00164     int ret = 0;
00165     uint8_t *out_buf, *out_end;
00166 
00167     bytestream2_init(&s->g, avpkt->data, avpkt->size);
00168     if (bytestream2_get_bytes_left(&s->g) < SGI_HEADER_SIZE) {
00169         av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", avpkt->size);
00170         return AVERROR_INVALIDDATA;
00171     }
00172 
00173     /* Test for SGI magic. */
00174     if (bytestream2_get_be16(&s->g) != SGI_MAGIC) {
00175         av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
00176         return AVERROR_INVALIDDATA;
00177     }
00178 
00179     rle                  = bytestream2_get_byte(&s->g);
00180     s->bytes_per_channel = bytestream2_get_byte(&s->g);
00181     dimension            = bytestream2_get_be16(&s->g);
00182     s->width             = bytestream2_get_be16(&s->g);
00183     s->height            = bytestream2_get_be16(&s->g);
00184     s->depth             = bytestream2_get_be16(&s->g);
00185 
00186     if (s->bytes_per_channel != 1 && (s->bytes_per_channel != 2 || rle)) {
00187         av_log(avctx, AV_LOG_ERROR, "wrong channel number\n");
00188         return -1;
00189     }
00190 
00191     /* Check for supported image dimensions. */
00192     if (dimension != 2 && dimension != 3) {
00193         av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n");
00194         return -1;
00195     }
00196 
00197     if (s->depth == SGI_GRAYSCALE) {
00198         avctx->pix_fmt = s->bytes_per_channel == 2 ? PIX_FMT_GRAY16BE : PIX_FMT_GRAY8;
00199     } else if (s->depth == SGI_RGB) {
00200         avctx->pix_fmt = s->bytes_per_channel == 2 ? PIX_FMT_RGB48BE : PIX_FMT_RGB24;
00201     } else if (s->depth == SGI_RGBA && s->bytes_per_channel == 1) {
00202         avctx->pix_fmt = PIX_FMT_RGBA;
00203     } else {
00204         av_log(avctx, AV_LOG_ERROR, "wrong picture format\n");
00205         return -1;
00206     }
00207 
00208     if (av_image_check_size(s->width, s->height, 0, avctx))
00209         return -1;
00210     avcodec_set_dimensions(avctx, s->width, s->height);
00211 
00212     if (p->data[0])
00213         avctx->release_buffer(avctx, p);
00214 
00215     p->reference = 0;
00216     if (avctx->get_buffer(avctx, p) < 0) {
00217         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n");
00218         return -1;
00219     }
00220 
00221     p->pict_type = AV_PICTURE_TYPE_I;
00222     p->key_frame = 1;
00223     out_buf = p->data[0];
00224 
00225     out_end = out_buf + p->linesize[0] * s->height;
00226 
00227     s->linesize = p->linesize[0];
00228 
00229     /* Skip header. */
00230     bytestream2_seek(&s->g, SGI_HEADER_SIZE, SEEK_SET);
00231     if (rle) {
00232         ret = read_rle_sgi(out_end, s);
00233     } else {
00234         ret = read_uncompressed_sgi(out_buf, out_end, s);
00235     }
00236 
00237     if (ret == 0) {
00238         *picture   = s->picture;
00239         *data_size = sizeof(AVPicture);
00240         return avpkt->size;
00241     } else {
00242         return ret;
00243     }
00244 }
00245 
00246 static av_cold int sgi_init(AVCodecContext *avctx){
00247     SgiState *s = avctx->priv_data;
00248 
00249     avcodec_get_frame_defaults(&s->picture);
00250     avctx->coded_frame = &s->picture;
00251 
00252     return 0;
00253 }
00254 
00255 static av_cold int sgi_end(AVCodecContext *avctx)
00256 {
00257     SgiState * const s = avctx->priv_data;
00258 
00259     if (s->picture.data[0])
00260         avctx->release_buffer(avctx, &s->picture);
00261 
00262     return 0;
00263 }
00264 
00265 static av_cold int sgi_decode_init(AVCodecContext *avctx)
00266 {
00267     SgiState *s = avctx->priv_data;
00268 
00269     s->avctx = avctx;
00270 
00271     return 0;
00272 }
00273 
00274 AVCodec ff_sgi_decoder = {
00275     .name           = "sgi",
00276     .type           = AVMEDIA_TYPE_VIDEO,
00277     .id             = CODEC_ID_SGI,
00278     .priv_data_size = sizeof(SgiState),
00279     .init           = sgi_init,
00280     .close          = sgi_end,
00281     .decode         = decode_frame,
00282     .init           = sgi_decode_init,
00283     .long_name = NULL_IF_CONFIG_SMALL("SGI image"),
00284 };
00285