Libav 0.7.1
libavcodec/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 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/intreadwrite.h"
00023 #include "libavutil/pixdesc.h"
00024 #include "avcodec.h"
00025 #include "rle.h"
00026 #include "targa.h"
00027 
00028 typedef struct TargaContext {
00029     AVFrame picture;
00030 } TargaContext;
00031 
00042 static int targa_encode_rle(uint8_t *outbuf, int out_size, AVFrame *pic,
00043                             int bpp, int w, int h)
00044 {
00045     int y,ret;
00046     uint8_t *out;
00047 
00048     out = outbuf;
00049 
00050     for(y = 0; y < h; y ++) {
00051         ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0);
00052         if(ret == -1){
00053             return -1;
00054         }
00055         out+= ret;
00056         out_size -= ret;
00057     }
00058 
00059     return out - outbuf;
00060 }
00061 
00062 static int targa_encode_normal(uint8_t *outbuf, AVFrame *pic, int bpp, int w, int h)
00063 {
00064     int i, n = bpp * w;
00065     uint8_t *out = outbuf;
00066     uint8_t *ptr = pic->data[0];
00067 
00068     for(i=0; i < h; i++) {
00069         memcpy(out, ptr, n);
00070         out += n;
00071         ptr += pic->linesize[0];
00072     }
00073 
00074     return out - outbuf;
00075 }
00076 
00077 static int targa_encode_frame(AVCodecContext *avctx,
00078                               unsigned char *outbuf,
00079                               int buf_size, void *data){
00080     AVFrame *p = data;
00081     int bpp, picsize, datasize = -1;
00082     uint8_t *out;
00083 
00084     if(avctx->width > 0xffff || avctx->height > 0xffff) {
00085         av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n");
00086         return AVERROR(EINVAL);
00087     }
00088     picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
00089     if(buf_size < picsize + 45) {
00090         av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
00091         return AVERROR(EINVAL);
00092     }
00093 
00094     p->pict_type= AV_PICTURE_TYPE_I;
00095     p->key_frame= 1;
00096 
00097     /* zero out the header and only set applicable fields */
00098     memset(outbuf, 0, 12);
00099     AV_WL16(outbuf+12, avctx->width);
00100     AV_WL16(outbuf+14, avctx->height);
00101     /* image descriptor byte: origin is always top-left, bits 0-3 specify alpha */
00102     outbuf[17] = 0x20 | (avctx->pix_fmt == PIX_FMT_BGRA ? 8 : 0);
00103 
00104     switch(avctx->pix_fmt) {
00105     case PIX_FMT_GRAY8:
00106         outbuf[2] = TGA_BW;      /* uncompressed grayscale image */
00107         outbuf[16] = 8;          /* bpp */
00108         break;
00109     case PIX_FMT_RGB555LE:
00110         outbuf[2] = TGA_RGB;     /* uncompresses true-color image */
00111         outbuf[16] = 16;         /* bpp */
00112         break;
00113     case PIX_FMT_BGR24:
00114         outbuf[2] = TGA_RGB;     /* uncompressed true-color image */
00115         outbuf[16] = 24;         /* bpp */
00116         break;
00117     case PIX_FMT_BGRA:
00118         outbuf[2] = TGA_RGB;     /* uncompressed true-color image */
00119         outbuf[16] = 32;         /* bpp */
00120         break;
00121     default:
00122         av_log(avctx, AV_LOG_ERROR, "Pixel format '%s' not supported.\n",
00123                av_get_pix_fmt_name(avctx->pix_fmt));
00124         return AVERROR(EINVAL);
00125     }
00126     bpp = outbuf[16] >> 3;
00127 
00128     out = outbuf + 18;  /* skip past the header we just output */
00129 
00130     /* try RLE compression */
00131     if (avctx->coder_type != FF_CODER_TYPE_RAW)
00132         datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height);
00133 
00134     /* if that worked well, mark the picture as RLE compressed */
00135     if(datasize >= 0)
00136         outbuf[2] |= 8;
00137 
00138     /* if RLE didn't make it smaller, go back to no compression */
00139     else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height);
00140 
00141     out += datasize;
00142 
00143     /* The standard recommends including this section, even if we don't use
00144      * any of the features it affords. TODO: take advantage of the pixel
00145      * aspect ratio and encoder ID fields available? */
00146     memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26);
00147 
00148     return out + 26 - outbuf;
00149 }
00150 
00151 static av_cold int targa_encode_init(AVCodecContext *avctx)
00152 {
00153     TargaContext *s = avctx->priv_data;
00154 
00155     avcodec_get_frame_defaults(&s->picture);
00156     s->picture.key_frame= 1;
00157     avctx->coded_frame= &s->picture;
00158 
00159     return 0;
00160 }
00161 
00162 AVCodec ff_targa_encoder = {
00163     .name = "targa",
00164     .type = AVMEDIA_TYPE_VIDEO,
00165     .id = CODEC_ID_TARGA,
00166     .priv_data_size = sizeof(TargaContext),
00167     .init = targa_encode_init,
00168     .encode = targa_encode_frame,
00169     .pix_fmts= (const enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_BGRA, PIX_FMT_RGB555LE, PIX_FMT_GRAY8, PIX_FMT_NONE},
00170     .long_name= NULL_IF_CONFIG_SMALL("Truevision Targa image"),
00171 };