targaenc.c

Go to the documentation of this file.
00001 /*
00002  * Targa (.tga) image encoder
00003  * Copyright (c) 2007 Bobby Bingham
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 #include "avcodec.h"
00022 #include "rle.h"
00023 
00024 typedef struct TargaContext {
00025     AVFrame picture;
00026 } TargaContext;
00027 
00028 /**
00029  * RLE compress the image, with maximum size of out_size
00030  * @param outbuf Output buffer
00031  * @param out_size Maximum output size
00032  * @param pic Image to compress
00033  * @param bpp Bytes per pixel
00034  * @param w Image width
00035  * @param h Image height
00036  * @return Size of output in bytes, or -1 if larger than out_size
00037  */
00038 static int targa_encode_rle(uint8_t *outbuf, int out_size, AVFrame *pic,
00039                             int bpp, int w, int h)
00040 {
00041     int y,ret;
00042     uint8_t *out;
00043 
00044     out = outbuf;
00045 
00046     for(y = 0; y < h; y ++) {
00047         ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0);
00048         if(ret == -1){
00049             return -1;
00050         }
00051         out+= ret;
00052         out_size -= ret;
00053     }
00054 
00055     return out - outbuf;
00056 }
00057 
00058 static int targa_encode_normal(uint8_t *outbuf, AVFrame *pic, int bpp, int w, int h)
00059 {
00060     int i, n = bpp * w;
00061     uint8_t *out = outbuf;
00062     uint8_t *ptr = pic->data[0];
00063 
00064     for(i=0; i < h; i++) {
00065         memcpy(out, ptr, n);
00066         out += n;
00067         ptr += pic->linesize[0];
00068     }
00069 
00070     return out - outbuf;
00071 }
00072 
00073 static int targa_encode_frame(AVCodecContext *avctx,
00074                               unsigned char *outbuf,
00075                               int buf_size, void *data){
00076     AVFrame *p = data;
00077     int bpp, picsize, datasize;
00078     uint8_t *out;
00079 
00080     if(avctx->width > 0xffff || avctx->height > 0xffff) {
00081         av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n");
00082         return -1;
00083     }
00084     picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
00085     if(buf_size < picsize + 45) {
00086         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
00087         return -1;
00088     }
00089 
00090     p->pict_type= FF_I_TYPE;
00091     p->key_frame= 1;
00092 
00093     /* zero out the header and only set applicable fields */
00094     memset(outbuf, 0, 12);
00095     AV_WL16(outbuf+12, avctx->width);
00096     AV_WL16(outbuf+14, avctx->height);
00097     outbuf[17] = 0x20;           /* origin is top-left. no alpha */
00098 
00099     /* TODO: support alpha channel */
00100     switch(avctx->pix_fmt) {
00101     case PIX_FMT_GRAY8:
00102         outbuf[2] = 3;           /* uncompressed grayscale image */
00103         outbuf[16] = 8;          /* bpp */
00104         break;
00105     case PIX_FMT_RGB555:
00106         outbuf[2] = 2;           /* uncompresses true-color image */
00107         outbuf[16] = 16;         /* bpp */
00108         break;
00109     case PIX_FMT_BGR24:
00110         outbuf[2] = 2;           /* uncompressed true-color image */
00111         outbuf[16] = 24;         /* bpp */
00112         break;
00113     default:
00114         return -1;
00115     }
00116     bpp = outbuf[16] >> 3;
00117 
00118     out = outbuf + 18;  /* skip past the header we just output */
00119 
00120     /* try RLE compression */
00121     datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height);
00122 
00123     /* if that worked well, mark the picture as RLE compressed */
00124     if(datasize >= 0)
00125         outbuf[2] |= 8;
00126 
00127     /* if RLE didn't make it smaller, go back to no compression */
00128     else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height);
00129 
00130     out += datasize;
00131 
00132     /* The standard recommends including this section, even if we don't use
00133      * any of the features it affords. TODO: take advantage of the pixel
00134      * aspect ratio and encoder ID fields available? */
00135     memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26);
00136 
00137     return out + 26 - outbuf;
00138 }
00139 
00140 static av_cold int targa_encode_init(AVCodecContext *avctx)
00141 {
00142     TargaContext *s = avctx->priv_data;
00143 
00144     avcodec_get_frame_defaults(&s->picture);
00145     s->picture.key_frame= 1;
00146     avctx->coded_frame= &s->picture;
00147 
00148     return 0;
00149 }
00150 
00151 AVCodec targa_encoder = {
00152     .name = "targa",
00153     .type = CODEC_TYPE_VIDEO,
00154     .id = CODEC_ID_TARGA,
00155     .priv_data_size = sizeof(TargaContext),
00156     .init = targa_encode_init,
00157     .encode = targa_encode_frame,
00158     .pix_fmts= (enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_RGB555, PIX_FMT_GRAY8, PIX_FMT_NONE},
00159     .long_name= NULL_IF_CONFIG_SMALL("Truevision Targa image"),
00160 };

Generated on Thu Nov 20 22:44:57 2008 for libextractor by  doxygen 1.5.1