prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / fileexr.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  * 
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * 
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  * 
20  */
21
22 #include "asset.h"
23 #include "bcsignals.h"
24 #include "clip.h"
25 #include "fileexr.h"
26 #include "filesystem.h"
27 #include "mwindow.inc"
28 #include "vframe.h"
29
30 #include "ImathBox.h"
31 #include "ImfChannelList.h"
32 #include "ImfChromaticities.h"
33 #include "ImfCompression.h"
34 #include "ImfIO.h"
35 #include "ImfInputFile.h"
36 #include "ImfOutputFile.h"
37 #include "ImfPixelType.h"
38 #include "ImfRgbaFile.h"
39 #include "ImfRgbaYca.h"
40 #include "ImfVersion.h"
41
42 class EXRIStream : public Imf::IStream
43 {
44 public:
45         EXRIStream(char *data, int size);
46         ~EXRIStream();
47
48         bool read (char c[], int n);
49         Imf::Int64 tellg ();
50         void seekg (Imf::Int64 pos);
51         void clear ();
52
53 private:
54         char *data;
55         int size;
56         int position;
57 };
58
59 class EXROStream : public Imf::OStream
60 {
61 public:
62         EXROStream(VFrame *data);
63         ~EXROStream();
64
65     virtual void write(const char c[], int n);
66     virtual Imf::Int64 tellp();
67     virtual void seekp(Imf::Int64 pos);
68
69 private:
70         VFrame *data;
71         int position;
72 };
73
74
75
76 EXRIStream::EXRIStream(char *data, int size)
77  : Imf::IStream("mypath")
78 {
79         this->data = data;
80         this->size = size;
81         position = 0;
82 }
83
84 EXRIStream::~EXRIStream()
85 {
86 }
87
88 bool EXRIStream::read(char c[], int n)
89 {
90         int fragment = n;
91         if(position + fragment > size)
92         {
93                 fragment = size - position;
94         }
95         memcpy(c, data + position, fragment);
96         position += fragment;
97
98         if(n != fragment)
99         {
100                 throw Iex::InputExc ("EXRIStream::read: Unexpected end of file.");
101         }
102         return position >= size;
103 }
104
105 Imf::Int64 EXRIStream::tellg ()
106 {
107         return position;
108 }
109
110 void EXRIStream::seekg(Imf::Int64 pos)
111 {
112         position = pos;
113 }
114
115 void EXRIStream::clear()
116 {
117 }
118
119
120
121
122
123
124
125
126
127
128
129 EXROStream::EXROStream(VFrame *data)
130  : Imf::OStream("mypath")
131 {
132         this->data = data;
133         position = 0;
134 }
135 EXROStream::~EXROStream()
136 {
137 }
138
139 void EXROStream::write(const char c[], int n)
140 {
141         if(position + n > data->get_compressed_allocated())
142                 data->allocate_compressed_data(MAX(position + n, data->get_compressed_allocated() * 2));
143
144         memcpy(data->get_data() + position, c, n);
145         position += n;
146         data->set_compressed_size(MAX(position, data->get_compressed_size()));
147 }
148
149 Imf::Int64 EXROStream::tellp()
150 {
151         return position;
152 }
153
154 void EXROStream::seekp(Imf::Int64 pos)
155 {
156         position = pos;
157 }
158
159
160
161
162
163
164
165
166
167
168
169 FileEXR::FileEXR(Asset *asset, File *file)
170  : FileList(asset, file, "EXRLIST", ".exr", FILE_EXR, FILE_EXR_LIST)
171 {
172         native_cmodel = BC_RGB_FLOAT;
173         is_yuv = 0;
174         temp_y = 0;
175         temp_u = 0;
176         temp_v = 0;
177 }
178
179 FileEXR::~FileEXR()
180 {
181         if(temp_y) delete [] temp_y;
182         if(temp_u) delete [] temp_u;
183         if(temp_v) delete [] temp_v;
184 }
185
186 const char* FileEXR::compression_to_str(int compression)
187 {
188         switch(compression)
189         {
190                 case FileEXR::NONE: return "None"; break;
191                 case FileEXR::PIZ: return "PIZ"; break;
192                 case FileEXR::ZIP: return "ZIP"; break;
193                 case FileEXR::ZIPS: return "ZIPS"; break;
194                 case FileEXR::RLE: return "RLE"; break;
195                 case FileEXR::PXR24: return "PXR24"; break;
196         }
197         return _("None");
198 }
199
200 int FileEXR::compression_to_exr(int compression)
201 {
202         switch(compression)
203         {
204                 case FileEXR::NONE: return (int)Imf::NO_COMPRESSION; break;
205                 case FileEXR::PIZ: return (int)Imf::PIZ_COMPRESSION; break;
206                 case FileEXR::ZIP: return (int)Imf::ZIP_COMPRESSION; break;
207                 case FileEXR::ZIPS: return (int)Imf::ZIPS_COMPRESSION; break;
208                 case FileEXR::RLE: return (int)Imf::RLE_COMPRESSION; break;
209                 case FileEXR::PXR24: return (int)Imf::PXR24_COMPRESSION; break;
210         }
211         return Imf::NO_COMPRESSION;
212 }
213
214 int FileEXR::str_to_compression(char *string)
215 {
216         if(!strcmp(compression_to_str(FileEXR::NONE), string))  
217                 return FileEXR::NONE;
218         if(!strcmp(compression_to_str(FileEXR::PIZ), string))   
219                 return FileEXR::PIZ;
220         if(!strcmp(compression_to_str(FileEXR::ZIP), string))   
221                 return FileEXR::ZIP;
222         if(!strcmp(compression_to_str(FileEXR::ZIPS), string))  
223                 return FileEXR::ZIPS;
224         if(!strcmp(compression_to_str(FileEXR::RLE), string))   
225                 return FileEXR::RLE;
226         if(!strcmp(compression_to_str(FileEXR::PXR24), string))         
227                 return PXR24;
228         return FileEXR::NONE;
229 }
230
231 int FileEXR::check_sig(Asset *asset, char *test)
232 {
233         if(Imf::isImfMagic(test)) return 1;
234         if(test[0] == 'E' && test[1] == 'X' && test[2] == 'R' && 
235                 test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
236         {
237                 return 1;
238         }
239
240         return 0;
241 }
242
243 void FileEXR::get_parameters(BC_WindowBase *parent_window, 
244         Asset *asset, 
245         BC_WindowBase* &format_window,
246         int audio_options,
247         int video_options)
248 {
249         if(video_options)
250         {
251                 EXRConfigVideo *window = new EXRConfigVideo(parent_window, asset);
252                 format_window = window;
253                 window->create_objects();
254                 window->run_window();
255                 delete window;
256         }
257 }
258
259 int FileEXR::colormodel_supported(int colormodel)
260 {
261         return native_cmodel;
262 }
263
264 int FileEXR::get_best_colormodel(Asset *asset, int driver)
265 {
266         if(asset->exr_use_alpha)
267                 return BC_RGBA_FLOAT;
268         else
269                 return BC_RGB_FLOAT;
270 }
271
272 int64_t FileEXR::get_memory_usage()
273 {
274         int64_t result = FileList::get_memory_usage();
275         if(temp_y) result += (int64_t)asset->width * asset->height * 3 / 2;
276         return result;
277 }
278
279
280 int FileEXR::read_frame_header(char *path)
281 {
282         int result = 0;
283
284 // This may have been used by VFS
285 //      FILE *stream;
286 // 
287 //      if(!(stream = fopen(path, "rb")))
288 //      {
289 //              perror("FileEXR::read_frame_header");
290 //              return 1;
291 //      }
292 //      int size = FileSystem::get_size(path);
293 //      char *buffer = new char[size];
294 //      fread(buffer, size, 1, stream);
295 //      fclose(stream);
296 // 
297 //      EXRIStream exr_stream(buffer, size);
298 //      Imf::InputFile file(exr_stream);
299
300
301         Imf::InputFile file(path);
302
303         Imath::Box2i dw = file.header().dataWindow();
304         
305         asset->width = dw.max.x - dw.min.x + 1;
306         asset->height = dw.max.y - dw.min.y + 1;
307
308         const Imf::ChannelList &channels = file.header().channels();
309
310         if(channels.findChannel("A"))
311                 native_cmodel = BC_RGBA_FLOAT;
312         else
313                 native_cmodel = BC_RGB_FLOAT;
314
315         if(channels.findChannel("Y"))
316                 is_yuv = 1;
317 // for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
318 // {
319 // printf("%s\n", i.name());
320 // }
321
322 //      delete [] buffer;
323         return result;
324 }
325
326 int FileEXR::read_frame(VFrame *frame, VFrame *data)
327 {
328         EXRIStream exr_stream((char*)data->get_data(), data->get_compressed_size());
329         Imf::InputFile file(exr_stream);
330         Imath::Box2i dw = file.header().dataWindow();
331     int dx = dw.min.x;
332     int dy = dw.min.y;
333         Imf::FrameBuffer framebuffer;
334         float **rows = (float**)frame->get_rows();
335         int components = BC_CModels::components(frame->get_color_model());
336
337         if(is_yuv)
338         {
339                 if(!temp_y) temp_y = new float[asset->width * asset->height];
340                 if(!temp_u) temp_u = new float[asset->width * asset->height / 4];
341                 if(!temp_v) temp_v = new float[asset->width * asset->height / 4];
342                 framebuffer.insert("Y", Imf::Slice(Imf::FLOAT, 
343                         (char*)(temp_y - dy * asset->width - dx),
344                         sizeof(float),
345                         sizeof(float) * frame->get_w()));
346                 framebuffer.insert("BY", Imf::Slice(Imf::FLOAT, 
347                         (char*)(temp_u - dy * asset->width / 4 - dx / 2),
348                         sizeof(float),
349                         sizeof(float) * frame->get_w() / 2,
350                         2, 
351                         2));
352                 framebuffer.insert("RY", Imf::Slice(Imf::FLOAT, 
353                         (char*)(temp_v - dy * asset->width / 4 - dx / 2),
354                         sizeof(float),
355                         sizeof(float) * frame->get_w() / 2,
356                         2, 
357                         2));
358         }
359         else
360         {
361                 framebuffer.insert("R", Imf::Slice(Imf::FLOAT, 
362                         (char*)(&rows[-dy][-dx * components]),
363                         sizeof(float) * components,
364                         sizeof(float) * components * frame->get_w()));
365                 framebuffer.insert("G", Imf::Slice(Imf::FLOAT, 
366                         (char*)(&rows[-dy][-dx * components + 1]),
367                         sizeof(float) * components,
368                         sizeof(float) * components * frame->get_w()));
369                 framebuffer.insert("B", Imf::Slice(Imf::FLOAT, 
370                         (char*)(&rows[-dy][-dx * components + 2]),
371                         sizeof(float) * components,
372                         sizeof(float) * components * frame->get_w()));
373         }
374
375 // Alpha always goes directly to the output frame
376         if(components == 4)
377         {
378                 framebuffer.insert("A", Imf::Slice(Imf::FLOAT, 
379                         (char*)(&rows[-dy][-dx * components + 3]),
380                         sizeof(float) * components,
381                         sizeof(float) * components * frame->get_w()));
382         }
383
384         file.setFrameBuffer(framebuffer);
385         file.readPixels (dw.min.y, dw.max.y);
386
387         if(is_yuv)
388         {
389 // Convert to RGB using crazy ILM equations
390                 Imath::V3f yw;
391                 Imf::Chromaticities cr;
392                 yw = Imf::RgbaYca::computeYw(cr);
393
394                 for(int i = 0; i < asset->height - 1; i += 2)
395                 {
396                         float *y_row1 = temp_y + i * asset->width;
397                         float *y_row2 = temp_y + (i + 1) * asset->width;
398                         float *u_row = temp_u + (i * asset->width / 4);
399                         float *v_row = temp_v + (i * asset->width / 4);
400                         float *out_row1 = rows[i];
401                         float *out_row2 = rows[i + 1];
402                         for(int j = 0; j < asset->width - 1; j += 2)
403                         {
404                                 float v = *u_row++;
405                                 float u = *v_row++;
406                                 float y;
407
408                                 float r, g, b;
409                                 y = *y_row1++;
410                                 r = (u + 1) * y;
411                                 b = (v + 1) * y;
412                                 g = (y - r * yw.x - b * yw.z) / yw.y;
413                                 *out_row1++ = r;
414                                 *out_row1++ = g;
415                                 *out_row1++ = b;
416                                 if(components == 4) out_row1++;
417
418                                 y = *y_row1++;
419                                 r = (u + 1) * y;
420                                 b = (v + 1) * y;
421                                 g = (y - r * yw.x - b * yw.z) / yw.y;
422                                 *out_row1++ = r;
423                                 *out_row1++ = g;
424                                 *out_row1++ = b;
425                                 if(components == 4) out_row1++;
426
427                                 y = *y_row2++;
428                                 r = (u + 1) * y;
429                                 b = (v + 1) * y;
430                                 g = (y - r * yw.x - b * yw.z) / yw.y;
431                                 *out_row2++ = r;
432                                 *out_row2++ = g;
433                                 *out_row2++ = b;
434                                 if(components == 4) out_row1++;
435
436                                 y = *y_row2++;
437                                 r = (u + 1) * y;
438                                 b = (v + 1) * y;
439                                 g = (y - r * yw.x - b * yw.z) / yw.y;
440                                 *out_row2++ = r;
441                                 *out_row2++ = g;
442                                 *out_row2++ = b;
443                                 if(components == 4) out_row1++;
444                         }
445                 }
446         }
447         return 0;
448 }
449
450
451
452
453 int FileEXR::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
454 {
455         EXRUnit *exr_unit = (EXRUnit*)unit;
456
457         VFrame *output_frame;
458         data->set_compressed_size(0);
459
460
461         int native_cmodel = asset->exr_use_alpha ? BC_RGBA_FLOAT : BC_RGB_FLOAT;
462         int components = BC_CModels::components(native_cmodel);
463
464         if(frame->get_color_model() != native_cmodel)
465         {
466                 if(!exr_unit->temp_frame) exr_unit->temp_frame = new VFrame(0,
467                         -1,
468                         asset->width,
469                         asset->height,
470                         native_cmodel,
471                         -1);
472                 BC_CModels::transfer(exr_unit->temp_frame->get_rows(), /* Leave NULL if non existent */
473                         frame->get_rows(),
474                         exr_unit->temp_frame->get_y(), /* Leave NULL if non existent */
475                         exr_unit->temp_frame->get_u(),
476                         exr_unit->temp_frame->get_v(),
477                         frame->get_y(), /* Leave NULL if non existent */
478                         frame->get_u(),
479                         frame->get_v(),
480                         0,        /* Dimensions to capture from input frame */
481                         0,
482                         asset->width,
483                         asset->height,
484                         0,       /* Dimensions to project on output frame */
485                         0,
486                         asset->width,
487                         asset->height,
488                         frame->get_color_model(),
489                         native_cmodel,
490                         0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
491                         asset->width,       /* For planar use the luma rowspan */
492                         asset->height);
493                 output_frame = exr_unit->temp_frame;
494         }
495         else
496                 output_frame = frame;
497
498         Imf::Header header(output_frame->get_w(), output_frame->get_h());
499         header.compression() = (Imf::Compression)compression_to_exr(
500                 asset->exr_compression);
501         header.channels().insert("R", Imf::Channel(Imf::FLOAT));
502         header.channels().insert("G", Imf::Channel(Imf::FLOAT));
503         header.channels().insert("B", Imf::Channel(Imf::FLOAT));
504         if(asset->exr_use_alpha) header.channels().insert("A", Imf::Channel(Imf::FLOAT));
505
506         EXROStream exr_stream(data);
507         Imf::OutputFile file(exr_stream, header);
508         Imf::FrameBuffer framebuffer;
509         float **rows = (float**)output_frame->get_rows();
510         framebuffer.insert("R",
511                 Imf::Slice(Imf::FLOAT,
512                         (char*)(rows[0]),
513                         sizeof(float) * components,
514                         sizeof(float) * components * output_frame->get_w()));
515         framebuffer.insert("G",
516                 Imf::Slice(Imf::FLOAT,
517                         (char*)(rows[0] + 1),
518                         sizeof(float) * components,
519                         sizeof(float) * components * output_frame->get_w()));
520         framebuffer.insert("B",
521                 Imf::Slice(Imf::FLOAT,
522                         (char*)(rows[0] + 2),
523                         sizeof(float) * components,
524                         sizeof(float) * components * output_frame->get_w()));
525         if(asset->exr_use_alpha)
526                 framebuffer.insert("A",
527                         Imf::Slice(Imf::FLOAT,
528                                 (char*)(rows[0] + 3),
529                                 sizeof(float) * components,
530                                 sizeof(float) * components * output_frame->get_w()));
531         file.setFrameBuffer(framebuffer);
532         file.writePixels(asset->height);
533         return 0;
534 }
535
536 FrameWriterUnit* FileEXR::new_writer_unit(FrameWriter *writer)
537 {
538         return new EXRUnit(this, writer);
539 }
540
541
542
543
544
545
546
547
548
549
550
551
552 EXRUnit::EXRUnit(FileEXR *file, FrameWriter *writer)
553  : FrameWriterUnit(writer)
554 {
555         this->file = file;
556         temp_frame = 0;
557 }
558
559 EXRUnit::~EXRUnit()
560 {
561         if(temp_frame) delete temp_frame;
562 }
563
564
565
566
567
568
569
570
571
572
573
574 EXRConfigVideo::EXRConfigVideo(BC_WindowBase *parent_window, Asset *asset)
575  : BC_Window(_(PROGRAM_NAME ": Video Compression"),
576         parent_window->get_abs_cursor_x(1),
577         parent_window->get_abs_cursor_y(1),
578         300,
579         BC_OKButton::calculate_h() + 100)
580 {
581         this->parent_window = parent_window;
582         this->asset = asset;
583 }
584
585 EXRConfigVideo::~EXRConfigVideo()
586 {
587 }
588
589 void EXRConfigVideo::create_objects()
590 {
591         lock_window("EXRConfigVideo::create_objects");
592         int x = 10, y = 10;
593         add_subwindow(new EXRUseAlpha(this, x, y));
594         y += 30;
595         EXRCompression *menu;
596         add_subwindow(new BC_Title(x, y, _("Compression:")));
597         x += 110;
598         add_subwindow(menu = new EXRCompression(this, x, y, 100));
599         menu->create_objects();
600         add_subwindow(new BC_OKButton(this));
601         show_window(1);
602         unlock_window();
603 }
604
605 int EXRConfigVideo::close_event()
606 {
607         set_done(0);
608         return 1;
609 }
610
611
612 EXRUseAlpha::EXRUseAlpha(EXRConfigVideo *gui, int x, int y)
613  : BC_CheckBox(x, y, gui->asset->exr_use_alpha, _("Use alpha"))
614 {
615         this->gui = gui;
616 }
617
618 int EXRUseAlpha::handle_event()
619 {
620         gui->asset->exr_use_alpha = get_value();
621         return 1;
622 }
623
624
625
626 EXRCompression::EXRCompression(EXRConfigVideo *gui, int x, int y, int w)
627  : BC_PopupMenu(x,
628         y,
629         w,
630         FileEXR::compression_to_str(gui->asset->exr_compression))
631 {
632         this->gui = gui;
633 }
634 void EXRCompression::create_objects()
635 {
636         add_item(new EXRCompressionItem(gui, FileEXR::NONE));
637         add_item(new EXRCompressionItem(gui, FileEXR::PIZ));
638         add_item(new EXRCompressionItem(gui, FileEXR::ZIP));
639         add_item(new EXRCompressionItem(gui, FileEXR::ZIPS));
640         add_item(new EXRCompressionItem(gui, FileEXR::RLE));
641         add_item(new EXRCompressionItem(gui, FileEXR::PXR24));
642 }
643
644 int EXRCompression::handle_event()
645 {
646         return 1;
647 }
648
649 EXRCompressionItem::EXRCompressionItem(EXRConfigVideo *gui, int value)
650  : BC_MenuItem(FileEXR::compression_to_str(value))
651 {
652         this->gui = gui;
653         this->value = value;
654 }
655
656 int EXRCompressionItem::handle_event()
657 {
658         gui->asset->exr_compression = value;
659         return 0;
660 }
661