ffmpeg / libavcodec / targaenc.c @ ce5e49b0
History | View | Annotate | Download (5.24 KB)
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 "libavutil/intreadwrite.h" |
23 |
#include "avcodec.h" |
24 |
#include "rle.h" |
25 |
#include "targa.h" |
26 |
|
27 |
typedef struct TargaContext { |
28 |
AVFrame picture; |
29 |
} TargaContext; |
30 |
|
31 |
/**
|
32 |
* RLE compress the image, with maximum size of out_size
|
33 |
* @param outbuf Output buffer
|
34 |
* @param out_size Maximum output size
|
35 |
* @param pic Image to compress
|
36 |
* @param bpp Bytes per pixel
|
37 |
* @param w Image width
|
38 |
* @param h Image height
|
39 |
* @return Size of output in bytes, or -1 if larger than out_size
|
40 |
*/
|
41 |
static int targa_encode_rle(uint8_t *outbuf, int out_size, AVFrame *pic, |
42 |
int bpp, int w, int h) |
43 |
{ |
44 |
int y,ret;
|
45 |
uint8_t *out; |
46 |
|
47 |
out = outbuf; |
48 |
|
49 |
for(y = 0; y < h; y ++) { |
50 |
ret = ff_rle_encode(out, out_size, pic->data[0] + pic->linesize[0] * y, bpp, w, 0x7f, 0, -1, 0); |
51 |
if(ret == -1){ |
52 |
return -1; |
53 |
} |
54 |
out+= ret; |
55 |
out_size -= ret; |
56 |
} |
57 |
|
58 |
return out - outbuf;
|
59 |
} |
60 |
|
61 |
static int targa_encode_normal(uint8_t *outbuf, AVFrame *pic, int bpp, int w, int h) |
62 |
{ |
63 |
int i, n = bpp * w;
|
64 |
uint8_t *out = outbuf; |
65 |
uint8_t *ptr = pic->data[0];
|
66 |
|
67 |
for(i=0; i < h; i++) { |
68 |
memcpy(out, ptr, n); |
69 |
out += n; |
70 |
ptr += pic->linesize[0];
|
71 |
} |
72 |
|
73 |
return out - outbuf;
|
74 |
} |
75 |
|
76 |
static int targa_encode_frame(AVCodecContext *avctx, |
77 |
unsigned char *outbuf, |
78 |
int buf_size, void *data){ |
79 |
AVFrame *p = data; |
80 |
int bpp, picsize, datasize = -1; |
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(buf_size < picsize + 45) { |
89 |
av_log(avctx, AV_LOG_ERROR, "encoded frame too large\n");
|
90 |
return AVERROR(EINVAL);
|
91 |
} |
92 |
|
93 |
p->pict_type= AV_PICTURE_TYPE_I; |
94 |
p->key_frame= 1;
|
95 |
|
96 |
/* zero out the header and only set applicable fields */
|
97 |
memset(outbuf, 0, 12); |
98 |
AV_WL16(outbuf+12, avctx->width);
|
99 |
AV_WL16(outbuf+14, avctx->height);
|
100 |
/* image descriptor byte: origin is always top-left, bits 0-3 specify alpha */
|
101 |
outbuf[17] = 0x20 | (avctx->pix_fmt == PIX_FMT_BGRA ? 8 : 0); |
102 |
|
103 |
switch(avctx->pix_fmt) {
|
104 |
case PIX_FMT_GRAY8:
|
105 |
outbuf[2] = TGA_BW; /* uncompressed grayscale image */ |
106 |
outbuf[16] = 8; /* bpp */ |
107 |
break;
|
108 |
case PIX_FMT_RGB555LE:
|
109 |
outbuf[2] = TGA_RGB; /* uncompresses true-color image */ |
110 |
outbuf[16] = 16; /* bpp */ |
111 |
break;
|
112 |
case PIX_FMT_BGR24:
|
113 |
outbuf[2] = TGA_RGB; /* uncompressed true-color image */ |
114 |
outbuf[16] = 24; /* bpp */ |
115 |
break;
|
116 |
case PIX_FMT_BGRA:
|
117 |
outbuf[2] = TGA_RGB; /* uncompressed true-color image */ |
118 |
outbuf[16] = 32; /* bpp */ |
119 |
break;
|
120 |
default:
|
121 |
av_log(avctx, AV_LOG_ERROR, "Pixel format '%s' not supported.\n",
|
122 |
avcodec_get_pix_fmt_name(avctx->pix_fmt)); |
123 |
return AVERROR(EINVAL);
|
124 |
} |
125 |
bpp = outbuf[16] >> 3; |
126 |
|
127 |
out = outbuf + 18; /* skip past the header we just output */ |
128 |
|
129 |
/* try RLE compression */
|
130 |
if (avctx->coder_type != FF_CODER_TYPE_RAW)
|
131 |
datasize = targa_encode_rle(out, picsize, p, bpp, avctx->width, avctx->height); |
132 |
|
133 |
/* if that worked well, mark the picture as RLE compressed */
|
134 |
if(datasize >= 0) |
135 |
outbuf[2] |= 8; |
136 |
|
137 |
/* if RLE didn't make it smaller, go back to no compression */
|
138 |
else datasize = targa_encode_normal(out, p, bpp, avctx->width, avctx->height);
|
139 |
|
140 |
out += datasize; |
141 |
|
142 |
/* The standard recommends including this section, even if we don't use
|
143 |
* any of the features it affords. TODO: take advantage of the pixel
|
144 |
* aspect ratio and encoder ID fields available? */
|
145 |
memcpy(out, "\0\0\0\0\0\0\0\0TRUEVISION-XFILE.", 26); |
146 |
|
147 |
return out + 26 - outbuf; |
148 |
} |
149 |
|
150 |
static av_cold int targa_encode_init(AVCodecContext *avctx) |
151 |
{ |
152 |
TargaContext *s = avctx->priv_data; |
153 |
|
154 |
avcodec_get_frame_defaults(&s->picture); |
155 |
s->picture.key_frame= 1;
|
156 |
avctx->coded_frame= &s->picture; |
157 |
|
158 |
return 0; |
159 |
} |
160 |
|
161 |
AVCodec ff_targa_encoder = { |
162 |
.name = "targa",
|
163 |
.type = AVMEDIA_TYPE_VIDEO, |
164 |
.id = CODEC_ID_TARGA, |
165 |
.priv_data_size = sizeof(TargaContext),
|
166 |
.init = targa_encode_init, |
167 |
.encode = targa_encode_frame, |
168 |
.pix_fmts= (const enum PixelFormat[]){PIX_FMT_BGR24, PIX_FMT_BGRA, PIX_FMT_RGB555LE, PIX_FMT_GRAY8, PIX_FMT_NONE}, |
169 |
.long_name= NULL_IF_CONFIG_SMALL("Truevision Targa image"),
|
170 |
}; |