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

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 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 
00022 #include "avcodec.h"
00023 #include "bytestream.h"
00024 #include "sgi.h"
00025 
00026 typedef struct SgiState {
00027     AVFrame picture;
00028     unsigned int width;
00029     unsigned int height;
00030     unsigned int depth;
00031     int linesize;
00032 } SgiState;
00033 
00043 static int expand_rle_row(const uint8_t *in_buf, const uint8_t* in_end,
00044             unsigned char *out_buf, uint8_t* out_end, int pixelstride)
00045 {
00046     unsigned char pixel, count;
00047     unsigned char *orig = out_buf;
00048 
00049     while (1) {
00050         if(in_buf + 1 > in_end) return -1;
00051         pixel = bytestream_get_byte(&in_buf);
00052         if (!(count = (pixel & 0x7f))) {
00053             return (out_buf - orig) / pixelstride;
00054         }
00055 
00056         /* Check for buffer overflow. */
00057         if(out_buf + pixelstride * count >= out_end) return -1;
00058 
00059         if (pixel & 0x80) {
00060             while (count--) {
00061                 *out_buf = bytestream_get_byte(&in_buf);
00062                 out_buf += pixelstride;
00063             }
00064         } else {
00065             pixel = bytestream_get_byte(&in_buf);
00066 
00067             while (count--) {
00068                 *out_buf = pixel;
00069                 out_buf += pixelstride;
00070             }
00071         }
00072     }
00073 }
00074 
00083 static int read_rle_sgi(unsigned char* out_buf, const uint8_t *in_buf,
00084                         const uint8_t *in_end, SgiState* s)
00085 {
00086     uint8_t *dest_row;
00087     unsigned int len = s->height * s->depth * 4;
00088     const uint8_t *start_table = in_buf;
00089     unsigned int y, z;
00090     unsigned int start_offset;
00091 
00092     /* size of  RLE offset and length tables */
00093     if(len * 2  > in_end - in_buf) {
00094         return AVERROR_INVALIDDATA;
00095     }
00096 
00097     in_buf -= SGI_HEADER_SIZE;
00098     for (z = 0; z < s->depth; z++) {
00099         dest_row = out_buf;
00100         for (y = 0; y < s->height; y++) {
00101             dest_row -= s->linesize;
00102             start_offset = bytestream_get_be32(&start_table);
00103             if(start_offset > in_end - in_buf) {
00104                 return AVERROR_INVALIDDATA;
00105             }
00106             if (expand_rle_row(in_buf + start_offset, in_end, dest_row + z,
00107                 dest_row + FFABS(s->linesize), s->depth) != s->width)
00108                 return AVERROR_INVALIDDATA;
00109         }
00110     }
00111     return 0;
00112 }
00113 
00123 static int read_uncompressed_sgi(unsigned char* out_buf, uint8_t* out_end,
00124                 const uint8_t *in_buf, const uint8_t *in_end, SgiState* s)
00125 {
00126     int x, y, z;
00127     const uint8_t *ptr;
00128     unsigned int offset = s->height * s->width;
00129 
00130     /* Test buffer size. */
00131     if (offset * s->depth > in_end - in_buf) {
00132        return -1;
00133     }
00134 
00135     for (y = s->height - 1; y >= 0; y--) {
00136         out_end = out_buf + (y * s->linesize);
00137         for (x = s->width; x > 0; x--) {
00138             ptr = in_buf++;
00139             for(z = 0; z < s->depth; z ++) {
00140                 bytestream_put_byte(&out_end, *ptr);
00141                 ptr += offset;
00142             }
00143         }
00144     }
00145     return 0;
00146 }
00147 
00148 static int decode_frame(AVCodecContext *avctx,
00149                         void *data, int *data_size,
00150                         const uint8_t *in_buf, int buf_size)
00151 {
00152     SgiState *s = avctx->priv_data;
00153     AVFrame *picture = data;
00154     AVFrame *p = &s->picture;
00155     const uint8_t *in_end = in_buf + buf_size;
00156     unsigned int dimension, bytes_per_channel, rle;
00157     int ret = 0;
00158     uint8_t *out_buf, *out_end;
00159 
00160     if (buf_size < SGI_HEADER_SIZE){
00161         av_log(avctx, AV_LOG_ERROR, "buf_size too small (%d)\n", buf_size);
00162         return -1;
00163     }
00164 
00165     /* Test for SGI magic. */
00166     if (bytestream_get_be16(&in_buf) != SGI_MAGIC) {
00167         av_log(avctx, AV_LOG_ERROR, "bad magic number\n");
00168         return -1;
00169     }
00170 
00171     rle = bytestream_get_byte(&in_buf);
00172     bytes_per_channel = bytestream_get_byte(&in_buf);
00173     dimension = bytestream_get_be16(&in_buf);
00174     s->width  = bytestream_get_be16(&in_buf);
00175     s->height = bytestream_get_be16(&in_buf);
00176     s->depth  = bytestream_get_be16(&in_buf);
00177 
00178     if (bytes_per_channel != 1) {
00179         av_log(avctx, AV_LOG_ERROR, "wrong channel number\n");
00180         return -1;
00181     }
00182 
00183     /* Check for supported image dimensions. */
00184     if (dimension != 2 && dimension != 3) {
00185         av_log(avctx, AV_LOG_ERROR, "wrong dimension number\n");
00186         return -1;
00187     }
00188 
00189     if (s->depth == SGI_GRAYSCALE) {
00190         avctx->pix_fmt = PIX_FMT_GRAY8;
00191     } else if (s->depth == SGI_RGB) {
00192         avctx->pix_fmt = PIX_FMT_RGB24;
00193     } else if (s->depth == SGI_RGBA) {
00194         avctx->pix_fmt = PIX_FMT_RGBA;
00195     } else {
00196         av_log(avctx, AV_LOG_ERROR, "wrong picture format\n");
00197         return -1;
00198     }
00199 
00200     if (avcodec_check_dimensions(avctx, s->width, s->height))
00201         return -1;
00202     avcodec_set_dimensions(avctx, s->width, s->height);
00203 
00204     if (p->data[0])
00205         avctx->release_buffer(avctx, p);
00206 
00207     p->reference = 0;
00208     if (avctx->get_buffer(avctx, p) < 0) {
00209         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed.\n");
00210         return -1;
00211     }
00212 
00213     p->pict_type = FF_I_TYPE;
00214     p->key_frame = 1;
00215     out_buf = p->data[0];
00216 
00217     out_end = out_buf + p->linesize[0] * s->height;
00218 
00219     s->linesize = p->linesize[0];
00220 
00221     /* Skip header. */
00222     in_buf += SGI_HEADER_SIZE - 12;
00223     if (rle) {
00224         ret = read_rle_sgi(out_end, in_buf, in_end, s);
00225     } else {
00226         ret = read_uncompressed_sgi(out_buf, out_end, in_buf, in_end, s);
00227     }
00228 
00229     if (ret == 0) {
00230         *picture   = s->picture;
00231         *data_size = sizeof(AVPicture);
00232         return buf_size;
00233     } else {
00234         return -1;
00235     }
00236 }
00237 
00238 static av_cold int sgi_init(AVCodecContext *avctx){
00239     SgiState *s = avctx->priv_data;
00240 
00241     avcodec_get_frame_defaults(&s->picture);
00242     avctx->coded_frame = &s->picture;
00243 
00244     return 0;
00245 }
00246 
00247 static av_cold int sgi_end(AVCodecContext *avctx)
00248 {
00249     SgiState * const s = avctx->priv_data;
00250 
00251     if (s->picture.data[0])
00252         avctx->release_buffer(avctx, &s->picture);
00253 
00254     return 0;
00255 }
00256 
00257 AVCodec sgi_decoder = {
00258     "sgi",
00259     CODEC_TYPE_VIDEO,
00260     CODEC_ID_SGI,
00261     sizeof(SgiState),
00262     sgi_init,
00263     NULL,
00264     sgi_end,
00265     decode_frame,
00266     .long_name = NULL_IF_CONFIG_SMALL("SGI image"),
00267 };
00268 

Generated on Tue Nov 4 2014 12:59:22 for ffmpeg by  doxygen 1.7.1