improve ffmpeg format selection popup menu, more ffmpeg audio fixes
[goodguy/history.git] / cinelerra-5.0 / quicktime / qtpng.c
1 #include "colormodels.h"
2 #include "funcprotos.h"
3 #include <png.h>
4 #include <string.h>
5 #include "quicktime.h"
6 #include "qtpng.h"
7
8 typedef struct
9 {
10         int compression_level;
11         unsigned char *buffer;
12 // Read position
13         long buffer_position;
14 // Frame size
15         long buffer_size;
16 // Buffer allocation
17         long buffer_allocated;
18         int quality;
19         unsigned char *temp_frame;
20 } quicktime_png_codec_t;
21
22 static void delete_codec(quicktime_video_map_t *vtrack)
23 {
24         quicktime_png_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
25         if(codec->buffer) free(codec->buffer);
26         if(codec->temp_frame) free(codec->temp_frame);
27         free(codec);
28 }
29
30 static int source_cmodel(quicktime_t *file, int track)
31 {
32         int depth = quicktime_video_depth(file, track);
33         if(depth == 24) 
34                 return BC_RGB888;
35         else
36                 return BC_RGBA8888;
37 }
38
39 void quicktime_set_png(quicktime_t *file, int compression_level)
40 {
41         int i;
42
43         for(i = 0; i < file->total_vtracks; i++)
44         {
45                 if(quicktime_match_32(quicktime_video_compressor(file, i), QUICKTIME_PNG))
46                 {
47                         quicktime_png_codec_t *codec = ((quicktime_codec_t*)file->vtracks[i].codec)->priv;
48                         codec->compression_level = compression_level;
49                 }
50         }
51 }
52
53 static void read_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
54 {
55         quicktime_png_codec_t *codec = png_get_io_ptr(png_ptr);
56         
57         if(length + codec->buffer_position <= codec->buffer_size)
58         {
59                 memcpy(data, codec->buffer + codec->buffer_position, length);
60                 codec->buffer_position += length;
61         }
62 }
63
64 static void write_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
65 {
66         quicktime_png_codec_t *codec = png_get_io_ptr(png_ptr);
67
68         if(length + codec->buffer_size > codec->buffer_allocated)
69         {
70                 codec->buffer_allocated += length;
71                 codec->buffer = realloc(codec->buffer, codec->buffer_allocated);
72         }
73         memcpy(codec->buffer + codec->buffer_size, data, length);
74         codec->buffer_size += length;
75 }
76
77 static void flush_function(png_structp png_ptr)
78 {
79         ;
80 }
81
82 static int decode(quicktime_t *file, unsigned char **row_pointers, int track)
83 {
84         int result = 0;
85         int64_t i;
86         quicktime_video_map_t *vtrack = &(file->vtracks[track]);
87         quicktime_trak_t *trak = vtrack->track;
88         png_structp png_ptr;
89         png_infop info_ptr;
90         png_infop end_info = 0; 
91         int height = trak->tkhd.track_height;
92         int width = trak->tkhd.track_width;
93         quicktime_png_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
94         int cmodel = source_cmodel(file, track);
95         int use_temp = (cmodel != file->color_model ||
96                 file->in_x != 0 ||
97                 file->in_y != 0 ||
98                 file->in_w != width ||
99                 file->in_h != height ||
100                 file->out_w != width ||
101                 file->out_h != height);
102         unsigned char **temp_rows = malloc(sizeof(unsigned char*) * height);
103
104         if(use_temp)
105         {
106                 if(!codec->temp_frame)
107                 {
108                         codec->temp_frame = malloc(cmodel_calculate_datasize(width, 
109                                         height, 
110                                         -1, 
111                                         cmodel));
112                 }
113                 for(i = 0; i < height; i++)
114                         temp_rows[i] = codec->temp_frame + 
115                                 cmodel_calculate_pixelsize(cmodel) * width * i;
116         }
117         else
118         {
119                 for(i = 0; i < height; i++)
120                         temp_rows[i] = row_pointers[i];
121         }
122
123         quicktime_set_video_position(file, vtrack->current_position, track);
124         codec->buffer_size = quicktime_frame_size(file, vtrack->current_position, track);
125         codec->buffer_position = 0;
126         if(codec->buffer_size > codec->buffer_allocated)
127         {
128                 codec->buffer_allocated = codec->buffer_size;
129                 codec->buffer = realloc(codec->buffer, codec->buffer_allocated);
130         }
131
132         result = !quicktime_read_data(file, (char*)codec->buffer, codec->buffer_size);
133
134         if(!result)
135         {
136                 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
137                 info_ptr = png_create_info_struct(png_ptr);
138                 png_set_read_fn(png_ptr, codec, (png_rw_ptr)read_function);
139                 png_read_info(png_ptr, info_ptr);
140
141 /* read the image */
142                 png_read_image(png_ptr, temp_rows);
143                 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
144         }
145
146         if(use_temp)
147         {
148                 cmodel_transfer(row_pointers, 
149                         temp_rows,
150                         row_pointers[0],
151                         row_pointers[1],
152                         row_pointers[2],
153                         0,
154                         0,
155                         0,
156                         file->in_x, 
157                         file->in_y, 
158                         file->in_w, 
159                         file->in_h,
160                         0, 
161                         0, 
162                         file->out_w, 
163                         file->out_h,
164                         cmodel, 
165                         file->color_model,
166                         0,
167                         width,
168                         file->out_w);
169         }
170
171
172         free(temp_rows);
173
174         return result;
175 }
176
177
178
179
180 static int encode(quicktime_t *file, unsigned char **row_pointers, int track)
181 {
182         //int64_t offset = quicktime_position(file);
183         int result = 0;
184         quicktime_video_map_t *vtrack = &(file->vtracks[track]);
185         quicktime_trak_t *trak = vtrack->track;
186         quicktime_png_codec_t *codec = ((quicktime_codec_t*)vtrack->codec)->priv;
187         int height = trak->tkhd.track_height;
188         int width = trak->tkhd.track_width;
189         png_structp png_ptr;
190         png_infop info_ptr;
191         int cmodel = source_cmodel(file, track);
192         quicktime_atom_t chunk_atom;
193
194         codec->buffer_size = 0;
195         codec->buffer_position = 0;
196
197         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
198         info_ptr = png_create_info_struct(png_ptr);
199         png_set_write_fn(png_ptr,
200                codec, 
201                            (png_rw_ptr)write_function,
202                (png_flush_ptr)flush_function);
203         png_set_compression_level(png_ptr, codec->compression_level);
204         png_set_IHDR(png_ptr, 
205                 info_ptr, 
206                 width, height,
207         8, 
208                 cmodel == BC_RGB888 ? 
209                   PNG_COLOR_TYPE_RGB : 
210                   PNG_COLOR_TYPE_RGB_ALPHA, 
211                 PNG_INTERLACE_NONE, 
212                 PNG_COMPRESSION_TYPE_DEFAULT, 
213                 PNG_FILTER_TYPE_DEFAULT);
214         png_write_info(png_ptr, info_ptr);
215         png_write_image(png_ptr, row_pointers);
216         png_write_end(png_ptr, info_ptr);
217         png_destroy_write_struct(&png_ptr, &info_ptr);
218
219         quicktime_write_chunk_header(file, trak, &chunk_atom);
220         result = !quicktime_write_data(file, (char*) codec->buffer, codec->buffer_size);
221         quicktime_write_chunk_footer(file, trak, vtrack->current_chunk, &chunk_atom, 1);
222
223         vtrack->current_chunk++;
224         return result;
225 }
226
227 static int set_parameter(quicktime_t *file, 
228                 int track, 
229                 char *key, 
230                 void *value)
231 {
232         quicktime_video_map_t *vtrack = &(file->vtracks[track]);
233         quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec;
234         quicktime_png_codec_t *codec = codec_base->priv;
235
236         if(!strcasecmp(key, "compression_level"))
237                 codec->compression_level = *(int*)value;
238         return 0;
239 }
240
241 static int reads_colormodel(quicktime_t *file, 
242                 int colormodel, 
243                 int track)
244 {
245         return (colormodel == BC_RGB888 ||
246                 colormodel == BC_BGR8888);
247 }
248
249 void quicktime_init_codec_png(quicktime_video_map_t *vtrack)
250 {
251         quicktime_codec_t *codec_base = (quicktime_codec_t*)vtrack->codec;
252         quicktime_png_codec_t *codec;
253
254 /* Init public items */
255         codec_base->priv = calloc(1, sizeof(quicktime_png_codec_t));
256         codec_base->delete_vcodec = delete_codec;
257         codec_base->decode_video = decode;
258         codec_base->encode_video = encode;
259         codec_base->decode_audio = 0;
260         codec_base->encode_audio = 0;
261         codec_base->reads_colormodel = reads_colormodel;
262         codec_base->set_parameter = set_parameter;
263         codec_base->fourcc = QUICKTIME_PNG;
264         codec_base->title = "PNG";
265         codec_base->desc = "Lossless RGB compression";
266
267 /* Init private items */
268         codec = codec_base->priv;
269         codec->compression_level = 9;
270 }