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