1 /*****************************************************************
2 * gmerlin - a general purpose multimedia framework and applications
3 *
4 * Copyright (c) 2001 - 2011 Members of the Gmerlin project
5 * gmerlin-general@lists.sourceforge.net
6 * http://gmerlin.sourceforge.net
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 * *****************************************************************/
21
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #include <config.h>
28 #include <gmerlin/translation.h>
29 #include <gmerlin/plugin.h>
30 #include <gmerlin/pluginfuncs.h>
31 #include <gmerlin/utils.h>
32
33 #include <targa.h>
34
35 #include <gmerlin/log.h>
36 #define LOG_DOMAIN "iw_tga"
37
38 #define PADD(i, size) i = ((i + size - 1) / size) * size
39
40 /* TGA writer */
41
42 typedef struct
43 {
44 gavl_video_format_t format;
45 int rle;
46
47 bg_iw_callbacks_t * cb;
48 char * filename;
49 } tga_t;
50
create_tga()51 static void * create_tga()
52 {
53 tga_t * ret;
54 ret = calloc(1, sizeof(*ret));
55 return ret;
56 }
57
destroy_tga(void * priv)58 static void destroy_tga(void * priv)
59 {
60 tga_t * tga = priv;
61 free(tga);
62 }
63
set_callbacks_tga(void * data,bg_iw_callbacks_t * cb)64 static void set_callbacks_tga(void * data, bg_iw_callbacks_t * cb)
65 {
66 tga_t * e = data;
67 e->cb = cb;
68 }
69
write_header_tga(void * priv,const char * filename,gavl_video_format_t * format,const gavl_metadata_t * m)70 static int write_header_tga(void * priv, const char * filename,
71 gavl_video_format_t * format,
72 const gavl_metadata_t * m)
73 {
74 tga_t * tga = priv;
75
76 if(gavl_pixelformat_has_alpha(format->pixelformat))
77 format->pixelformat = GAVL_RGBA_32;
78 else
79 format->pixelformat = GAVL_BGR_24;
80
81 gavl_video_format_copy(&tga->format, format);
82
83 tga->filename = bg_filename_ensure_extension(filename, "tga");
84
85 if(!bg_iw_cb_create_output_file(tga->cb, tga->filename))
86 return 0;
87
88 return 1;
89 }
90
write_image_tga(void * priv,gavl_video_frame_t * frame)91 static int write_image_tga(void * priv, gavl_video_frame_t * frame)
92 {
93 tga_t * tga = priv;
94 gavl_video_frame_t * tmp_frame;
95 int result, ret = 1;
96
97 errno = 0;
98
99 if(tga->format.pixelformat == GAVL_RGBA_32)
100 {
101 tmp_frame = gavl_video_frame_create(&tga->format);
102 gavl_video_frame_copy(&tga->format, tmp_frame, frame);
103 if(tga->rle)
104 {
105 result = tga_write_rgb(tga->filename, tmp_frame->planes[0],
106 tga->format.image_width,
107 tga->format.image_height, 32,
108 frame->strides[0]);
109 }
110 else
111 {
112 result =tga_write_rgb_rle(tga->filename, tmp_frame->planes[0],
113 tga->format.image_width,
114 tga->format.image_height, 32,
115 frame->strides[0]);
116 }
117 gavl_video_frame_destroy(tmp_frame);
118 }
119 else
120 {
121 if(tga->rle)
122 {
123 result = tga_write_bgr(tga->filename, frame->planes[0],
124 tga->format.image_width,
125 tga->format.image_height, 24,
126 frame->strides[0]);
127 }
128 else
129 {
130 result = tga_write_bgr_rle(tga->filename, frame->planes[0],
131 tga->format.image_width,
132 tga->format.image_height, 24,
133 frame->strides[0]);
134 }
135 }
136
137 if(result != TGA_NOERR)
138 {
139 if(errno)
140 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Cannot save %s: %s",
141 tga->filename, strerror(errno));
142 else
143 bg_log(BG_LOG_ERROR, LOG_DOMAIN, "Cannot save %s: %s",
144 tga->filename, tga_error(result));
145 ret = 0;
146 }
147
148 free(tga->filename);
149 tga->filename = NULL;
150
151 return ret;
152 }
153
154 /* Configuration stuff */
155
156 static const bg_parameter_info_t parameters[] =
157 {
158 {
159 .name = "rle",
160 .long_name = TRS("Do RLE compression"),
161 .type = BG_PARAMETER_CHECKBUTTON,
162 .val_default = { .val_i = 0 },
163 },
164 { /* End of parameters */ }
165 };
166
get_parameters_tga(void * p)167 static const bg_parameter_info_t * get_parameters_tga(void * p)
168 {
169 return parameters;
170 }
171
set_parameter_tga(void * p,const char * name,const bg_parameter_value_t * val)172 static void set_parameter_tga(void * p, const char * name,
173 const bg_parameter_value_t * val)
174 {
175 tga_t * tga;
176 tga = p;
177
178 if(!name)
179 return;
180
181 if(!strcmp(name, "rle"))
182 tga->rle = val->val_i;
183 }
184
185
186 const bg_image_writer_plugin_t the_plugin =
187 {
188 .common =
189 {
190 BG_LOCALE,
191 .name = "iw_tga",
192 .long_name = TRS("TGA writer"),
193 .description = TRS("Writer for TGA images"),
194 .type = BG_PLUGIN_IMAGE_WRITER,
195 .flags = BG_PLUGIN_FILE,
196 .priority = 5,
197 .create = create_tga,
198 .destroy = destroy_tga,
199 .get_parameters = get_parameters_tga,
200 .set_parameter = set_parameter_tga
201 },
202 .extensions = "tga",
203 .set_callbacks = set_callbacks_tga,
204 .write_header = write_header_tga,
205 .write_image = write_image_tga,
206 };
207
208 /* Include this into all plugin modules exactly once
209 to let the plugin loader obtain the API version */
210 BG_GET_PLUGIN_API_VERSION;
211