1/* 2 * Targa (.tga) image encoder 3 * Copyright (c) 2007 Bobby Bingham 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include <string.h> 23 24#include "libavutil/internal.h" 25#include "libavutil/intreadwrite.h" 26#include "libavutil/pixdesc.h" 27#include "avcodec.h" 28#include "internal.h" 29#include "rle.h" 30#include "targa.h" 31 32/** 33 * RLE compress the image, with maximum size of out_size 34 * @param outbuf Output buffer 35 * @param out_size Maximum output size 36 * @param pic Image to compress 37 * @param bpp Bytes per pixel 38 * @param w Image width 39 * @param h Image height 40 * @return Size of output in bytes, or -1 if larger than out_size 41 */ 42static int targa_encode_rle(uint8_t *outbuf, int out_size, const AVFrame *pic, 43 int bpp, int w, int h) 44{ 45 int y,ret; 46 uint8_t *out; 47 48 out = outbuf; 49 50 for(y = 0; y < h; y ++) { 51 ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0); 52 if(ret == -1){ 53 return -1; 54 } 55 out+= ret; 56 out_size -= ret; 57 } 58 59 return out - outbuf; 60} 61 62static int targa_encode_normal(uint8_t *outbuf, const AVFrame *pic, int bpp, int w, int h) 63{ 64 int i, n = bpp * w; 65 uint8_t *out = outbuf; 66 uint8_t *ptr = pic->data[0]; 67 68 for(i=0; i < h; i++) { 69 memcpy(out, ptr, n); 70 out += n; 71 ptr += pic->linesize[0]; 72 } 73 74 return out - outbuf; 75} 76 77static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 78 const AVFrame *p, int *got_packet) 79{ 80 int bpp, picsize, datasize = -1, ret, i; 81 uint8_t *out; 82 83 if(avctx->width > 0xffff || avctx->height > 0xffff) { 84 av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n"); 85 return AVERROR(EINVAL); 86 } 87 picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height); 88 if ((ret = ff_alloc_packet2(avctx, pkt, picsize + 45)) < 0) 89 return ret; 90 91 /* zero out the header and only set applicable fields */ 92 memset(pkt->data, 0, 12); 93 AV_WL16(pkt->data+12, avctx->width); 94 AV_WL16(pkt->data+14, avctx->height); 95 /* image descriptor byte: origin is always top-left, bits 0-3 specify alpha */ 96 pkt->data[17] = 0x20 | (avctx->pix_fmt == AV_PIX_FMT_BGRA ? 8 : 0); 97 98 out = pkt->data + 18; /* skip past the header we write */ 99 100 avctx->bits_per_coded_sample = av_get_bits_per_pixel(av_pix_fmt_desc_get(avctx->pix_fmt)); 101 switch(avctx->pix_fmt) { 102 case AV_PIX_FMT_PAL8: { 103 int pal_bpp = 24; /* Only write 32bit palette if there is transparency information */ 104 for (i = 0; i < 256; i++) 105 if (AV_RN32(p->data[1] + 4 * i) >> 24 != 0xFF) { 106 pal_bpp = 32; 107 break; 108 } 109 pkt->data[1] = 1; /* palette present */ 110 pkt->data[2] = TGA_PAL; /* uncompressed palettised image */ 111 pkt->data[6] = 1; /* palette contains 256 entries */ 112 pkt->data[7] = pal_bpp; /* palette contains pal_bpp bit entries */ 113 pkt->data[16] = 8; /* bpp */ 114 for (i = 0; i < 256; i++) 115 if (pal_bpp == 32) { 116 AV_WL32(pkt->data + 18 + 4 * i, *(uint32_t *)(p->data[1] + i * 4)); 117 } else { 118 AV_WL24(pkt->data + 18 + 3 * i, *(uint32_t *)(p->data[1] + i * 4)); 119 } 120 out += 32 * pal_bpp; /* skip past the palette we just output */ 121 break; 122 } 123 case AV_PIX_FMT_GRAY8: 124 pkt->data[2] = TGA_BW; /* uncompressed grayscale image */ 125 avctx->bits_per_coded_sample = 0x28; 126 pkt->data[16] = 8; /* bpp */ 127 break; 128 case AV_PIX_FMT_RGB555LE: 129 pkt->data[2] = TGA_RGB; /* uncompressed true-color image */ 130 avctx->bits_per_coded_sample = 131 pkt->data[16] = 16; /* bpp */ 132 break; 133 case AV_PIX_FMT_BGR24: 134 pkt->data[2] = TGA_RGB; /* uncompressed true-color image */ 135 pkt->data[16] = 24; /* bpp */ 136 break; 137 case AV_PIX_FMT_BGRA: 138 pkt->data[2] = TGA_RGB; /* uncompressed true-color image */ 139 pkt->data[16] = 32; /* bpp */ 140 break; 141 default: 142 av_log(avctx, AV_LOG_ERROR, "Pixel format '%s' not supported.\n", 143 av_get_pix_fmt_name(avctx->pix_fmt)); 144 return AVERROR(EINVAL); 145 } 146 bpp = pkt->data[16] >> 3; 147 148 /* try RLE compression */ 149 if (avctx->coder_type != FF_CODER_TYPE_RAW) 150 datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height); 151 152 /* if that worked well, mark the picture as RLE compressed */ 153 if(datasize >= 0) 154 pkt->data[2] |= TGA_RLE; 155 156 /* if RLE didn't make it smaller, go back to no compression */ 157 else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height); 158 159 out += datasize; 160 161 /* The standard recommends including this section, even if we don't use 162 * any of the features it affords. TODO: take advantage of the pixel 163 * aspect ratio and encoder ID fields available? */ 164 memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26); 165 166 pkt->size = out + 26 - pkt->data; 167 pkt->flags |= AV_PKT_FLAG_KEY; 168 *got_packet = 1; 169 170 return 0; 171} 172 173static av_cold int targa_encode_init(AVCodecContext *avctx) 174{ 175 avctx->coded_frame = av_frame_alloc(); 176 if (!avctx->coded_frame) 177 return AVERROR(ENOMEM); 178 179 avctx->coded_frame->key_frame = 1; 180 avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I; 181 182 return 0; 183} 184 185static av_cold int targa_encode_close(AVCodecContext *avctx) 186{ 187 av_frame_free(&avctx->coded_frame); 188 return 0; 189} 190 191AVCodec ff_targa_encoder = { 192 .name = "targa", 193 .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), 194 .type = AVMEDIA_TYPE_VIDEO, 195 .id = AV_CODEC_ID_TARGA, 196 .init = targa_encode_init, 197 .close = targa_encode_close, 198 .encode2 = targa_encode_frame, 199 .pix_fmts = (const enum AVPixelFormat[]){ 200 AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8, 201 AV_PIX_FMT_NONE 202 }, 203}; 204