r827: Fix a crash when no audio output device can be opened.
[cinelerra_cv.git] / cinelerra / filepng.C
blobb6e955d87008855c732ae6a6ba994e96c7b0092c
1 #include "asset.h"
2 #include "edit.h"
3 #include "file.h"
4 #include "filepng.h"
5 #include "interlacemodes.h"
6 #include "language.h"
7 #include "mwindow.inc"
8 #include "quicktime.h"
9 #include "vframe.h"
10 #include "videodevice.inc"
12 #include <png.h>
14 FilePNG::FilePNG(Asset *asset, File *file)
15  : FileList(asset, file, "PNGLIST", ".png", FILE_PNG, FILE_PNG_LIST)
19 FilePNG::~FilePNG()
25 int FilePNG::check_sig(Asset *asset)
27         FILE *stream = fopen(asset->path, "rb");
29         if(stream)
30         {
32 //printf("FilePNG::check_sig 1\n");
33                 char test[16];
34                 fread(test, 16, 1, stream);
35                 fclose(stream);
37                 if(png_check_sig((unsigned char*)test, 8))
38                 {
39 //printf("FilePNG::check_sig 1\n");
40                         return 1;
41                 }
42                 else
43                 if(test[0] == 'P' && test[1] == 'N' && test[2] == 'G' && 
44                         test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
45                 {
46 //printf("FilePNG::check_sig 1\n");
47                         return 1;
48                 }
49         }
50         return 0;
55 void FilePNG::get_parameters(BC_WindowBase *parent_window, 
56         Asset *asset, 
57         BC_WindowBase* &format_window,
58         int audio_options,
59         int video_options)
61         if(video_options)
62         {
63                 PNGConfigVideo *window = new PNGConfigVideo(parent_window, asset);
64                 format_window = window;
65                 window->create_objects();
66                 window->run_window();
67                 delete window;
68         }
74 int FilePNG::can_copy_from(Edit *edit, int64_t position)
76         if(edit->asset->format == FILE_MOV)
77         {
78                 if(match4(edit->asset->vcodec, QUICKTIME_PNG)) return 1;
79         }
80         else
81         if(edit->asset->format == FILE_PNG || 
82                 edit->asset->format == FILE_PNG_LIST)
83                 return 1;
85         return 0;
89 int FilePNG::colormodel_supported(int colormodel)
91         if (((colormodel == BC_RGBA8888) && (native_cmodel == BC_RGBA16161616))
92             || ((colormodel == BC_RGB161616) && (native_cmodel == BC_RGBA16161616))
93             || (colormodel == BC_RGB888))
94         {
95             return colormodel;
96         }
97         else if ((colormodel == BC_RGB161616) && (native_cmodel == BC_RGBA8888))
98         {
99             return BC_RGB888;
100         }
101         else
102         {
103             return native_cmodel;
104         }
108 int FilePNG::get_best_colormodel(Asset *asset, int driver)
110         if(asset->png_use_alpha)
111                 return BC_RGBA8888;
112         else
113                 return BC_RGB888;
119 int FilePNG::read_frame_header(char *path)
121         int result = 0;
122         int color_type;
123         int color_depth;
124         int num_trans = 0;
125         
126         FILE *stream;
128         if(!(stream = fopen(path, "rb")))
129         {
130                 perror("FilePNG::read_frame_header");
131                 return 1;
132         }
134         png_structp png_ptr;
135         png_infop info_ptr;
136         png_infop end_info = 0; 
137         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
138         info_ptr = png_create_info_struct(png_ptr);
139         png_init_io(png_ptr, stream);
142         png_read_info(png_ptr, info_ptr);
144         asset->width = png_get_image_width(png_ptr, info_ptr);
145         asset->height = png_get_image_height(png_ptr, info_ptr);
146         
147         asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
149         color_type = png_get_color_type(png_ptr, info_ptr);
150         color_depth = png_get_bit_depth(png_ptr,info_ptr);
151         
152         png_get_tRNS(png_ptr, info_ptr, NULL, &num_trans, NULL);
153         
154         if (color_depth == 16)
155         {
156             if (color_type & PNG_COLOR_MASK_ALPHA)
157             {
158                 native_cmodel = BC_RGBA16161616;
159             }
160             else
161             {
162                 native_cmodel = BC_RGB161616;
163             }
164         }
165         else 
166         if ((color_type & PNG_COLOR_MASK_ALPHA)
167             || (num_trans > 0))
168         {
169             native_cmodel = BC_RGBA8888;
170         }
171         else
172         {
173             native_cmodel = BC_RGB888;
174         }
177         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
178         fclose(stream);
179         
180         
181         
182         return result;
188 static void read_function(png_structp png_ptr, 
189         png_bytep data, 
190         png_uint_32 length)
192         VFrame *input = (VFrame*)png_get_io_ptr(png_ptr);
194         memcpy(data, input->get_data() + input->get_compressed_size(), length);
195         input->set_compressed_size(input->get_compressed_size() + length);
198 static void write_function(png_structp png_ptr, png_bytep data, png_uint_32 length)
200         VFrame *output = (VFrame*)png_get_io_ptr(png_ptr);
202         if(output->get_compressed_allocated() < output->get_compressed_size() + length)
203                 output->allocate_compressed_data((output->get_compressed_allocated() + length) * 2);
204         memcpy(output->get_data() + output->get_compressed_size(), data, length);
205         output->set_compressed_size(output->get_compressed_size() + length);
208 static void flush_function(png_structp png_ptr)
210         ;
215 int FilePNG::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
217         PNGUnit *png_unit = (PNGUnit*)unit;
218         int result = 0;
219         png_structp png_ptr;
220         png_infop info_ptr;
221         png_infop end_info = 0; 
222         VFrame *output_frame;
223         data->set_compressed_size(0);
225 //printf("FilePNG::write_frame 1\n");
226         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
227         info_ptr = png_create_info_struct(png_ptr);
228         png_set_write_fn(png_ptr,
229                data, 
230                            (png_rw_ptr)write_function,
231                (png_flush_ptr)flush_function);
232         png_set_compression_level(png_ptr, 9);
234         png_set_IHDR(png_ptr, 
235                 info_ptr, 
236                 asset->width, 
237                 asset->height,
238         8, 
239                 asset->png_use_alpha ? 
240                   PNG_COLOR_TYPE_RGB_ALPHA : 
241                   PNG_COLOR_TYPE_RGB, 
242                 PNG_INTERLACE_NONE, 
243                 PNG_COMPRESSION_TYPE_DEFAULT, 
244                 PNG_FILTER_TYPE_DEFAULT);
245         png_write_info(png_ptr, info_ptr);
247 //printf("FilePNG::write_frame 1\n");
248         native_cmodel = asset->png_use_alpha ? BC_RGBA8888 : BC_RGB888;
249         if(frame->get_color_model() != native_cmodel)
250         {
251                 if(!png_unit->temp_frame) png_unit->temp_frame = new VFrame(0, 
252                         asset->width, 
253                         asset->height, 
254                         native_cmodel);
256                 cmodel_transfer(png_unit->temp_frame->get_rows(), /* Leave NULL if non existent */
257                         frame->get_rows(),
258                         png_unit->temp_frame->get_y(), /* Leave NULL if non existent */
259                         png_unit->temp_frame->get_u(),
260                         png_unit->temp_frame->get_v(),
261                         frame->get_y(), /* Leave NULL if non existent */
262                         frame->get_u(),
263                         frame->get_v(),
264                         0,        /* Dimensions to capture from input frame */
265                         0, 
266                         asset->width, 
267                         asset->height,
268                         0,       /* Dimensions to project on output frame */
269                         0, 
270                         asset->width, 
271                         asset->height,
272                         frame->get_color_model(), 
273                         png_unit->temp_frame->get_color_model(),
274                         0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
275                         asset->width,       /* For planar use the luma rowspan */
276                         asset->height);
277                 
278                 output_frame = png_unit->temp_frame;
279         }
280         else
281                 output_frame = frame;
284 //printf("FilePNG::write_frame 2\n");
285         png_write_image(png_ptr, output_frame->get_rows());
286         png_write_end(png_ptr, info_ptr);
287         png_destroy_write_struct(&png_ptr, &info_ptr);
288 //printf("FilePNG::write_frame 3 %d\n", data->get_compressed_size());
290         return result;
293 int FilePNG::read_frame(VFrame *output, VFrame *input)
295         png_structp png_ptr;
296         png_infop info_ptr;
297         png_infop end_info = 0; 
298         int result = 0;
299         int color_type;
300         int color_depth;
301         int colormodel;
302         int size = input->get_compressed_size();
303         input->set_compressed_size(0);
304         
305         
306         //printf("FilePNG::read_frame 1 %d %d\n", native_cmodel, output->get_color_model());
307         png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
308         info_ptr = png_create_info_struct(png_ptr);
309         png_set_read_fn(png_ptr, input, (png_rw_ptr)read_function);
310         png_read_info(png_ptr, info_ptr);
312         int png_color_type = png_get_color_type(png_ptr, info_ptr);
313         if (png_color_type == PNG_COLOR_TYPE_GRAY ||
314                 png_color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
315         {
316                 png_set_gray_to_rgb(png_ptr);
317         }
319         colormodel = output->get_color_model();
320         color_type = png_get_color_type(png_ptr, info_ptr);
321         color_depth = png_get_bit_depth(png_ptr,info_ptr);
322         
323         if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGB161616))
324             && ((colormodel == BC_RGBA8888)||(colormodel == BC_RGB888)))
325         {
326             png_set_strip_16(png_ptr);
327         }
329         /* If we're dropping the alpha channel, use the background color of the image
330            otherwise, use black */
331         if (((native_cmodel == BC_RGBA16161616)||(native_cmodel == BC_RGBA8888))
332             && ((colormodel == BC_RGB161616)||(colormodel == BC_RGB888)))
333         {
334             png_color_16 my_background;
335             png_color_16p image_background;
336             
337             memset(&my_background,0,sizeof(png_color_16));
338             
339             if (png_get_bKGD(png_ptr, info_ptr, &image_background))
340             {
341                 png_set_background(png_ptr, image_background, PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
342             }
343             else
344             {
345                 png_set_background(png_ptr, &my_background, PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
346             }
347         }
348         
349         /* Little endian */
350         if ((color_depth == 16)
351             &&((colormodel == BC_RGBA16161616)||(colormodel == BC_RGB161616)))
352         {
353             png_set_swap(png_ptr);
354         }
355         
356         if (!(color_type & PNG_COLOR_MASK_COLOR))
357         {
358             png_set_gray_to_rgb(png_ptr);
359         }
360         
361         if (color_type & PNG_COLOR_MASK_PALETTE)
362         {
363             png_set_palette_to_rgb(png_ptr);
364         }
365         
366         if (color_depth <= 8)
367         {
368             png_set_expand(png_ptr);
369         }
371 /* read the image */
372         png_read_image(png_ptr, output->get_rows());
373 //printf("FilePNG::read_frame 3\n");
374         png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
376         input->set_compressed_size(size);
378 //printf("FilePNG::read_frame 4\n");
379         return result;
382 FrameWriterUnit* FilePNG::new_writer_unit(FrameWriter *writer)
384         return new PNGUnit(this, writer);
398 PNGUnit::PNGUnit(FilePNG *file, FrameWriter *writer)
399  : FrameWriterUnit(writer)
401         this->file = file;
402         temp_frame = 0;
404 PNGUnit::~PNGUnit()
406         if(temp_frame) delete temp_frame;
417 PNGConfigVideo::PNGConfigVideo(BC_WindowBase *parent_window, Asset *asset)
418  : BC_Window(PROGRAM_NAME ": Video Compression",
419         parent_window->get_abs_cursor_x(1),
420         parent_window->get_abs_cursor_y(1),
421         200,
422         100)
424         this->parent_window = parent_window;
425         this->asset = asset;
428 PNGConfigVideo::~PNGConfigVideo()
432 int PNGConfigVideo::create_objects()
434         int x = 10, y = 10;
435         add_subwindow(new PNGUseAlpha(this, x, y));
436         add_subwindow(new BC_OKButton(this));
437         return 0;
440 int PNGConfigVideo::close_event()
442         set_done(0);
443         return 1;
447 PNGUseAlpha::PNGUseAlpha(PNGConfigVideo *gui, int x, int y)
448  : BC_CheckBox(x, y, gui->asset->png_use_alpha, _("Use alpha"))
450         this->gui = gui;
453 int PNGUseAlpha::handle_event()
455         gui->asset->png_use_alpha = get_value();
456         return 1;