r602: Fix baver's code... don't insert timecode when show_tc is not set
[cinelerra_cv/mob.git] / cinelerra / fileexr.C
blob496e1ae99115779293c7168ee925813410e28270
1 #include "asset.h"
2 #include "bcsignals.h"
3 #include "clip.h"
4 #include "fileexr.h"
5 #include "filesystem.h"
6 #include "interlacemodes.h"
8 #include <ImathBox.h>
9 #include <ImfChannelList.h>
10 #include <ImfChromaticities.h>
11 #include <ImfCompression.h>
12 #include <ImfIO.h>
13 #include <ImfInputFile.h>
14 #include <ImfOutputFile.h>
15 #include <ImfPixelType.h>
16 #include <ImfRgbaFile.h>
17 #include <ImfRgbaYca.h>
18 #include <ImfVersion.h>
19 #include "mwindow.inc"
20 #include "vframe.h"
23 class EXRIStream : public Imf::IStream
25 public:
26         EXRIStream(char *data, int size);
27         ~EXRIStream();
29         bool read (char c[], int n);
30         Imf::Int64 tellg ();
31         void seekg (Imf::Int64 pos);
32         void clear ();
34 private:
35         char *data;
36         int size;
37         int position;
40 class EXROStream : public Imf::OStream
42 public:
43         EXROStream(VFrame *data);
44         ~EXROStream();
46     virtual void write(const char c[], int n);
47     virtual Imf::Int64 tellp();
48     virtual void seekp(Imf::Int64 pos);
50 private:
51         VFrame *data;
52         int position;
57 EXRIStream::EXRIStream(char *data, int size)
58  : Imf::IStream("mypath")
60         this->data = data;
61         this->size = size;
62         position = 0;
65 EXRIStream::~EXRIStream()
69 bool EXRIStream::read(char c[], int n)
71         int fragment = n;
72         if(position + fragment > size)
73         {
74                 fragment = size - position;
75         }
76         memcpy(c, data + position, fragment);
77         position += fragment;
79         if(n != fragment)
80         {
81                 throw Iex::InputExc ("EXRIStream::read: Unexpected end of file.");
82         }
83         return position >= size;
86 Imf::Int64 EXRIStream::tellg ()
88         return position;
91 void EXRIStream::seekg(Imf::Int64 pos)
93         position = pos;
96 void EXRIStream::clear()
110 EXROStream::EXROStream(VFrame *data)
111  : Imf::OStream("mypath")
113         this->data = data;
114         position = 0;
116 EXROStream::~EXROStream()
120 void EXROStream::write(const char c[], int n)
122         if(position + n > data->get_compressed_allocated())
123                 data->allocate_compressed_data(MAX(position + n, data->get_compressed_allocated() * 2));
125         memcpy(data->get_data() + position, c, n);
126         position += n;
127         data->set_compressed_size(MAX(position, data->get_compressed_size()));
130 Imf::Int64 EXROStream::tellp()
132         return position;
135 void EXROStream::seekp(Imf::Int64 pos)
137         position = pos;
150 FileEXR::FileEXR(Asset *asset, File *file)
151  : FileList(asset, file, "EXRLIST", ".exr", FILE_EXR, FILE_EXR_LIST)
153         native_cmodel = BC_RGB_FLOAT;
154         is_yuv = 0;
155         temp_y = 0;
156         temp_u = 0;
157         temp_v = 0;
160 FileEXR::~FileEXR()
162         if(temp_y) delete [] temp_y;
163         if(temp_u) delete [] temp_u;
164         if(temp_v) delete [] temp_v;
167 char* FileEXR::compression_to_str(int compression)
169         switch(compression)
170         {
171                 case FileEXR::NONE: return "None"; break;
172                 case FileEXR::PIZ: return "PIZ"; break;
173                 case FileEXR::ZIP: return "ZIP"; break;
174                 case FileEXR::ZIPS: return "ZIPS"; break;
175                 case FileEXR::RLE: return "RLE"; break;
176                 case FileEXR::PXR24: return "PXR24"; break;
177         }
178         return "None";
181 int FileEXR::compression_to_exr(int compression)
183         switch(compression)
184         {
185                 case FileEXR::NONE: return (int)Imf::NO_COMPRESSION; break;
186                 case FileEXR::PIZ: return (int)Imf::PIZ_COMPRESSION; break;
187                 case FileEXR::ZIP: return (int)Imf::ZIP_COMPRESSION; break;
188                 case FileEXR::ZIPS: return (int)Imf::ZIPS_COMPRESSION; break;
189                 case FileEXR::RLE: return (int)Imf::RLE_COMPRESSION; break;
190                 case FileEXR::PXR24: return (int)Imf::PXR24_COMPRESSION; break;
191         }
192         return Imf::NO_COMPRESSION;
195 int FileEXR::str_to_compression(char *string)
197         if(!strcmp(compression_to_str(FileEXR::NONE), string))  
198                 return FileEXR::NONE;
199         if(!strcmp(compression_to_str(FileEXR::PIZ), string))   
200                 return FileEXR::PIZ;
201         if(!strcmp(compression_to_str(FileEXR::ZIP), string))   
202                 return FileEXR::ZIP;
203         if(!strcmp(compression_to_str(FileEXR::ZIPS), string))  
204                 return FileEXR::ZIPS;
205         if(!strcmp(compression_to_str(FileEXR::RLE), string))   
206                 return FileEXR::RLE;
207         if(!strcmp(compression_to_str(FileEXR::PXR24), string))         
208                 return PXR24;
209         return FileEXR::NONE;
212 int FileEXR::check_sig(Asset *asset, char *test)
214         if(Imf::isImfMagic(test)) return 1;
215         if(test[0] == 'E' && test[1] == 'X' && test[2] == 'R' && 
216                 test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
217         {
218                 return 1;
219         }
221         return 0;
224 void FileEXR::get_parameters(BC_WindowBase *parent_window, 
225         Asset *asset, 
226         BC_WindowBase* &format_window,
227         int audio_options,
228         int video_options)
230         if(video_options)
231         {
232                 EXRConfigVideo *window = new EXRConfigVideo(parent_window, asset);
233                 format_window = window;
234                 window->create_objects();
235                 window->run_window();
236                 delete window;
237         }
240 int FileEXR::colormodel_supported(int colormodel)
242         return native_cmodel;
245 int FileEXR::get_best_colormodel(Asset *asset, int driver)
247         if(asset->exr_use_alpha)
248                 return BC_RGBA_FLOAT;
249         else
250                 return BC_RGB_FLOAT;
253 int FileEXR::get_memory_usage()
255         int result = FileBase::get_memory_usage();
256         if(temp_y) result += asset->width * asset->height * 3 / 2;
257         return result;
261 int FileEXR::read_frame_header(char *path)
263         int result = 0;
264         FILE *stream;
266         if(!(stream = fopen(path, "rb")))
267         {
268                 perror("FileEXR::read_frame_header");
269                 return 1;
270         }
271         int size = FileSystem::get_size(path);
272         char *buffer = new char[size];
273         fread(buffer, size, 1, stream);
274         fclose(stream);
276         EXRIStream exr_stream(buffer, size);
277         Imf::InputFile file(exr_stream);
278         Imath::Box2i dw = file.header().dataWindow();
279         
280         asset->width = dw.max.x - dw.min.x + 1;
281         asset->height = dw.max.y - dw.min.y + 1;
282         asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
284         const Imf::ChannelList &channels = file.header().channels();
286         if(channels.findChannel("A"))
287                 native_cmodel = BC_RGBA_FLOAT;
288         else
289                 native_cmodel = BC_RGB_FLOAT;
291         if(channels.findChannel("Y"))
292                 is_yuv = 1;
293 // for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i)
294 // {
295 // printf("%s\n", i.name());
296 // }
298         delete [] buffer;
299         return result;
302 int FileEXR::read_frame(VFrame *frame, VFrame *data)
304         EXRIStream exr_stream((char*)data->get_data(), data->get_compressed_size());
305         Imf::InputFile file(exr_stream);
306         Imath::Box2i dw = file.header().dataWindow();
307     int dx = dw.min.x;
308     int dy = dw.min.y;
309         Imf::FrameBuffer framebuffer;
310         float **rows = (float**)frame->get_rows();
311         int components = cmodel_components(frame->get_color_model());
313         if(is_yuv)
314         {
315                 if(!temp_y) temp_y = new float[asset->width * asset->height];
316                 if(!temp_u) temp_u = new float[asset->width * asset->height / 4];
317                 if(!temp_v) temp_v = new float[asset->width * asset->height / 4];
318                 framebuffer.insert("Y", Imf::Slice(Imf::FLOAT, 
319                         (char*)(temp_y - dy * asset->width - dx),
320                         sizeof(float),
321                         sizeof(float) * frame->get_w()));
322                 framebuffer.insert("BY", Imf::Slice(Imf::FLOAT, 
323                         (char*)(temp_u - dy * asset->width / 4 - dx / 2),
324                         sizeof(float),
325                         sizeof(float) * frame->get_w() / 2,
326                         2, 
327                         2));
328                 framebuffer.insert("RY", Imf::Slice(Imf::FLOAT, 
329                         (char*)(temp_v - dy * asset->width / 4 - dx / 2),
330                         sizeof(float),
331                         sizeof(float) * frame->get_w() / 2,
332                         2, 
333                         2));
334         }
335         else
336         {
337                 framebuffer.insert("R", Imf::Slice(Imf::FLOAT, 
338                         (char*)(&rows[-dy][-dx * components]),
339                         sizeof(float) * components,
340                         sizeof(float) * components * frame->get_w()));
341                 framebuffer.insert("G", Imf::Slice(Imf::FLOAT, 
342                         (char*)(&rows[-dy][-dx * components + 1]),
343                         sizeof(float) * components,
344                         sizeof(float) * components * frame->get_w()));
345                 framebuffer.insert("B", Imf::Slice(Imf::FLOAT, 
346                         (char*)(&rows[-dy][-dx * components + 2]),
347                         sizeof(float) * components,
348                         sizeof(float) * components * frame->get_w()));
349         }
351 // Alpha always goes directly to the output frame
352         if(components == 4)
353         {
354                 framebuffer.insert("A", Imf::Slice(Imf::FLOAT, 
355                         (char*)(&rows[-dy][-dx * components + 3]),
356                         sizeof(float) * components,
357                         sizeof(float) * components * frame->get_w()));
358         }
360         file.setFrameBuffer(framebuffer);
361         file.readPixels (dw.min.y, dw.max.y);
365         if(is_yuv)
366         {
367 // Convert to RGB using crazy ILM equations
368                 Imath::V3f yw;
369                 Imf::Chromaticities cr;
370                 yw = Imf::RgbaYca::computeYw(cr);
372                 for(int i = 0; i < asset->height - 1; i += 2)
373                 {
374                         float *y_row1 = temp_y + i * asset->width;
375                         float *y_row2 = temp_y + (i + 1) * asset->width;
376                         float *u_row = temp_u + (i * asset->width / 4);
377                         float *v_row = temp_v + (i * asset->width / 4);
378                         float *out_row1 = rows[i];
379                         float *out_row2 = rows[i + 1];
380                         for(int j = 0; j < asset->width - 1; j += 2)
381                         {
382                                 float v = *u_row++;
383                                 float u = *v_row++;
384                                 float y;
386                                 float r, g, b;
387                                 y = *y_row1++;
388                                 r = (u + 1) * y;
389                                 b = (v + 1) * y;
390                                 g = (y - r * yw.x - b * yw.z) / yw.y;
391                                 *out_row1++ = r;
392                                 *out_row1++ = g;
393                                 *out_row1++ = b;
394                                 if(components == 4) out_row1++;
396                                 y = *y_row1++;
397                                 r = (u + 1) * y;
398                                 b = (v + 1) * y;
399                                 g = (y - r * yw.x - b * yw.z) / yw.y;
400                                 *out_row1++ = r;
401                                 *out_row1++ = g;
402                                 *out_row1++ = b;
403                                 if(components == 4) out_row1++;
405                                 y = *y_row2++;
406                                 r = (u + 1) * y;
407                                 b = (v + 1) * y;
408                                 g = (y - r * yw.x - b * yw.z) / yw.y;
409                                 *out_row2++ = r;
410                                 *out_row2++ = g;
411                                 *out_row2++ = b;
412                                 if(components == 4) out_row1++;
414                                 y = *y_row2++;
415                                 r = (u + 1) * y;
416                                 b = (v + 1) * y;
417                                 g = (y - r * yw.x - b * yw.z) / yw.y;
418                                 *out_row2++ = r;
419                                 *out_row2++ = g;
420                                 *out_row2++ = b;
421                                 if(components == 4) out_row1++;
422                         }
423                 }
424         }
430 int FileEXR::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
432 //printf("FileEXR::write_frame 1\n");
433         EXRUnit *exr_unit = (EXRUnit*)unit;
434         int result = 0;
436         VFrame *output_frame;
437         data->set_compressed_size(0);
440         int native_cmodel = asset->exr_use_alpha ? BC_RGBA_FLOAT : BC_RGB_FLOAT;
441         int components = cmodel_components(native_cmodel);
443         if(frame->get_color_model() != native_cmodel)
444         {
445                 if(!exr_unit->temp_frame) exr_unit->temp_frame = new VFrame(0,
446                         asset->width,
447                         asset->height,
448                         native_cmodel);
449                 cmodel_transfer(exr_unit->temp_frame->get_rows(), /* Leave NULL if non existent */
450                         frame->get_rows(),
451                         exr_unit->temp_frame->get_y(), /* Leave NULL if non existent */
452                         exr_unit->temp_frame->get_u(),
453                         exr_unit->temp_frame->get_v(),
454                         frame->get_y(), /* Leave NULL if non existent */
455                         frame->get_u(),
456                         frame->get_v(),
457                         0,        /* Dimensions to capture from input frame */
458                         0, 
459                         asset->width, 
460                         asset->height,
461                         0,       /* Dimensions to project on output frame */
462                         0, 
463                         asset->width, 
464                         asset->height,
465                         frame->get_color_model(), 
466                         native_cmodel,
467                         0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
468                         asset->width,       /* For planar use the luma rowspan */
469                         asset->height);
470                 output_frame = exr_unit->temp_frame;
471         }
472         else
473                 output_frame = frame;
475         Imf::Header header(output_frame->get_w(), output_frame->get_h());
476         header.compression() = (Imf::Compression)compression_to_exr(
477                 asset->exr_compression);
478         header.channels().insert("R", Imf::Channel(Imf::FLOAT));
479         header.channels().insert("G", Imf::Channel(Imf::FLOAT));
480         header.channels().insert("B", Imf::Channel(Imf::FLOAT));
481         if(asset->exr_use_alpha) header.channels().insert("A", Imf::Channel(Imf::FLOAT));
483         EXROStream exr_stream(data);
484         Imf::OutputFile file(exr_stream, header);
485         Imf::FrameBuffer framebuffer;
486         float **rows = (float**)output_frame->get_rows();
487         framebuffer.insert("R",
488                 Imf::Slice(Imf::FLOAT,
489                         (char*)(rows[0]),
490                         sizeof(float) * components,
491                         sizeof(float) * components * output_frame->get_w()));
492         framebuffer.insert("G",
493                 Imf::Slice(Imf::FLOAT,
494                         (char*)(rows[0] + 1),
495                         sizeof(float) * components,
496                         sizeof(float) * components * output_frame->get_w()));
497         framebuffer.insert("B",
498                 Imf::Slice(Imf::FLOAT,
499                         (char*)(rows[0] + 2),
500                         sizeof(float) * components,
501                         sizeof(float) * components * output_frame->get_w()));
502         if(asset->exr_use_alpha)
503                 framebuffer.insert("A",
504                         Imf::Slice(Imf::FLOAT,
505                                 (char*)(rows[0] + 3),
506                                 sizeof(float) * components,
507                                 sizeof(float) * components * output_frame->get_w()));
508         file.setFrameBuffer(framebuffer);
509         file.writePixels(asset->height);
510 //printf("FileEXR::write_frame 10\n");
513 FrameWriterUnit* FileEXR::new_writer_unit(FrameWriter *writer)
515         return new EXRUnit(this, writer);
529 EXRUnit::EXRUnit(FileEXR *file, FrameWriter *writer)
530  : FrameWriterUnit(writer)
532         this->file = file;
533         temp_frame = 0;
536 EXRUnit::~EXRUnit()
538         if(temp_frame) delete temp_frame;
551 EXRConfigVideo::EXRConfigVideo(BC_WindowBase *parent_window, Asset *asset)
552  : BC_Window(PROGRAM_NAME ": Video Compression",
553         parent_window->get_abs_cursor_x(1),
554         parent_window->get_abs_cursor_y(1),
555         300,
556         100)
558         this->parent_window = parent_window;
559         this->asset = asset;
562 EXRConfigVideo::~EXRConfigVideo()
566 int EXRConfigVideo::create_objects()
568         int x = 10, y = 10;
569         add_subwindow(new EXRUseAlpha(this, x, y));
570         y += 30;
571         EXRCompression *menu;
572         add_subwindow(new BC_Title(x, y, "Compression:"));
573         x += 110;
574         add_subwindow(menu = new EXRCompression(this, x, y, 100));
575         menu->create_objects();
576         add_subwindow(new BC_OKButton(this));
577         return 0;
580 int EXRConfigVideo::close_event()
582         set_done(0);
583         return 1;
587 EXRUseAlpha::EXRUseAlpha(EXRConfigVideo *gui, int x, int y)
588  : BC_CheckBox(x, y, gui->asset->exr_use_alpha, _("Use alpha"))
590         this->gui = gui;
593 int EXRUseAlpha::handle_event()
595         gui->asset->exr_use_alpha = get_value();
596         return 1;
601 EXRCompression::EXRCompression(EXRConfigVideo *gui, int x, int y, int w)
602  : BC_PopupMenu(x, 
603         y, 
604         w, 
605         FileEXR::compression_to_str(gui->asset->exr_compression))
607         this->gui = gui;
609 void EXRCompression::create_objects()
611         add_item(new EXRCompressionItem(gui, FileEXR::NONE));
612         add_item(new EXRCompressionItem(gui, FileEXR::PIZ));
613         add_item(new EXRCompressionItem(gui, FileEXR::ZIP));
614         add_item(new EXRCompressionItem(gui, FileEXR::ZIPS));
615         add_item(new EXRCompressionItem(gui, FileEXR::RLE));
616         add_item(new EXRCompressionItem(gui, FileEXR::PXR24));
619 int EXRCompression::handle_event()
621         return 1;
624 EXRCompressionItem::EXRCompressionItem(EXRConfigVideo *gui, int value)
625  : BC_MenuItem(FileEXR::compression_to_str(value))
627         this->gui = gui;
628         this->value = value;
631 int EXRCompressionItem::handle_event()
633         gui->asset->exr_compression = value;
634         return 0;