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