00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <string.h>
00023
00024 #include "libavutil/internal.h"
00025 #include "libavutil/intreadwrite.h"
00026 #include "libavutil/pixdesc.h"
00027 #include "avcodec.h"
00028 #include "internal.h"
00029 #include "rle.h"
00030 #include "targa.h"
00031
00032 typedef struct TargaContext {
00033 AVFrame picture;
00034 } TargaContext;
00035
00046 static int targa_encode_rle(uint8_t *outbuf, int out_size, const AVFrame *pic,
00047 int bpp, int w, int h)
00048 {
00049 int y,ret;
00050 uint8_t *out;
00051
00052 out = outbuf;
00053
00054 for(y = 0; y < h; y ++) {
00055 ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0);
00056 if(ret == -1){
00057 return -1;
00058 }
00059 out+= ret;
00060 out_size -= ret;
00061 }
00062
00063 return out - outbuf;
00064 }
00065
00066 static int targa_encode_normal(uint8_t *outbuf, const AVFrame *pic, int bpp, int w, int h)
00067 {
00068 int i, n = bpp * w;
00069 uint8_t *out = outbuf;
00070 uint8_t *ptr = pic->data[0];
00071
00072 for(i=0; i < h; i++) {
00073 memcpy(out, ptr, n);
00074 out += n;
00075 ptr += pic->linesize[0];
00076 }
00077
00078 return out - outbuf;
00079 }
00080
00081 static int targa_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
00082 const AVFrame *p, int *got_packet)
00083 {
00084 int bpp, picsize, datasize = -1, ret, i;
00085 uint8_t *out;
00086
00087 if(avctx->width > 0xffff || avctx->height > 0xffff) {
00088 av_log(avctx, AV_LOG_ERROR, "image dimensions too large\n");
00089 return AVERROR(EINVAL);
00090 }
00091 picsize = avpicture_get_size(avctx->pix_fmt, avctx->width, avctx->height);
00092 if ((ret = ff_alloc_packet2(avctx, pkt, picsize + 45)) < 0)
00093 return ret;
00094
00095
00096 memset(pkt->data, 0, 12);
00097 AV_WL16(pkt->data+12, avctx->width);
00098 AV_WL16(pkt->data+14, avctx->height);
00099
00100 pkt->data[17] = 0x20 | (avctx->pix_fmt == AV_PIX_FMT_BGRA ? 8 : 0);
00101
00102 out = pkt->data + 18;
00103
00104 avctx->bits_per_coded_sample = av_get_bits_per_pixel(av_pix_fmt_desc_get(avctx->pix_fmt));
00105 switch(avctx->pix_fmt) {
00106 case AV_PIX_FMT_PAL8: {
00107 int pal_bpp = 24;
00108 for (i = 0; i < 256; i++)
00109 if (AV_RN32(p->data[1] + 4 * i) >> 24 != 0xFF) {
00110 pal_bpp = 32;
00111 break;
00112 }
00113 pkt->data[1] = 1;
00114 pkt->data[2] = TGA_PAL;
00115 pkt->data[6] = 1;
00116 pkt->data[7] = pal_bpp;
00117 pkt->data[16] = 8;
00118 for (i = 0; i < 256; i++)
00119 if (pal_bpp == 32) {
00120 AV_WL32(pkt->data + 18 + 4 * i, *(uint32_t *)(p->data[1] + i * 4));
00121 } else {
00122 AV_WL24(pkt->data + 18 + 3 * i, *(uint32_t *)(p->data[1] + i * 4));
00123 }
00124 out += 32 * pal_bpp;
00125 break;
00126 }
00127 case AV_PIX_FMT_GRAY8:
00128 pkt->data[2] = TGA_BW;
00129 avctx->bits_per_coded_sample = 0x28;
00130 pkt->data[16] = 8;
00131 break;
00132 case AV_PIX_FMT_RGB555LE:
00133 pkt->data[2] = TGA_RGB;
00134 avctx->bits_per_coded_sample =
00135 pkt->data[16] = 16;
00136 break;
00137 case AV_PIX_FMT_BGR24:
00138 pkt->data[2] = TGA_RGB;
00139 pkt->data[16] = 24;
00140 break;
00141 case AV_PIX_FMT_BGRA:
00142 pkt->data[2] = TGA_RGB;
00143 pkt->data[16] = 32;
00144 break;
00145 default:
00146 av_log(avctx, AV_LOG_ERROR, "Pixel format '%s' not supported.\n",
00147 av_get_pix_fmt_name(avctx->pix_fmt));
00148 return AVERROR(EINVAL);
00149 }
00150 bpp = pkt->data[16] >> 3;
00151
00152
00153 if (avctx->coder_type != FF_CODER_TYPE_RAW)
00154 datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height);
00155
00156
00157 if(datasize >= 0)
00158 pkt->data[2] |= TGA_RLE;
00159
00160
00161 else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height);
00162
00163 out += datasize;
00164
00165
00166
00167
00168 memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26);
00169
00170 pkt->size = out + 26 - pkt->data;
00171 pkt->flags |= AV_PKT_FLAG_KEY;
00172 *got_packet = 1;
00173
00174 return 0;
00175 }
00176
00177 static av_cold int targa_encode_init(AVCodecContext *avctx)
00178 {
00179 TargaContext *s = avctx->priv_data;
00180
00181 avcodec_get_frame_defaults(&s->picture);
00182 s->picture.key_frame= 1;
00183 s->picture.pict_type = AV_PICTURE_TYPE_I;
00184 avctx->coded_frame= &s->picture;
00185
00186 return 0;
00187 }
00188
00189 AVCodec ff_targa_encoder = {
00190 .name = "targa",
00191 .type = AVMEDIA_TYPE_VIDEO,
00192 .id = AV_CODEC_ID_TARGA,
00193 .priv_data_size = sizeof(TargaContext),
00194 .init = targa_encode_init,
00195 .encode2 = targa_encode_frame,
00196 .pix_fmts = (const enum AVPixelFormat[]){
00197 AV_PIX_FMT_BGR24, AV_PIX_FMT_BGRA, AV_PIX_FMT_RGB555LE, AV_PIX_FMT_GRAY8, AV_PIX_FMT_PAL8,
00198 AV_PIX_FMT_NONE
00199 },
00200 .long_name= NULL_IF_CONFIG_SMALL("Truevision Targa image"),
00201 };