00001 #include "asset.h"
00002 #include "bcsignals.h"
00003 #include "clip.h"
00004 #include "fileexr.h"
00005 #include "filesystem.h"
00006 #include "interlacemodes.h"
00007
00008 #include <ImathBox.h>
00009 #include <ImfChannelList.h>
00010 #include <ImfChromaticities.h>
00011 #include <ImfCompression.h>
00012 #include <ImfIO.h>
00013 #include <ImfInputFile.h>
00014 #include <ImfOutputFile.h>
00015 #include <ImfPixelType.h>
00016 #include <ImfRgbaFile.h>
00017 #include <ImfRgbaYca.h>
00018 #include <ImfVersion.h>
00019 #include "mwindow.inc"
00020 #include "vframe.h"
00021
00022
00023 class EXRIStream : public Imf::IStream
00024 {
00025 public:
00026 EXRIStream(char *data, int size);
00027 ~EXRIStream();
00028
00029 bool read (char c[], int n);
00030 Imf::Int64 tellg ();
00031 void seekg (Imf::Int64 pos);
00032 void clear ();
00033
00034 private:
00035 char *data;
00036 int size;
00037 int position;
00038 };
00039
00040 class EXROStream : public Imf::OStream
00041 {
00042 public:
00043 EXROStream(VFrame *data);
00044 ~EXROStream();
00045
00046 virtual void write(const char c[], int n);
00047 virtual Imf::Int64 tellp();
00048 virtual void seekp(Imf::Int64 pos);
00049
00050 private:
00051 VFrame *data;
00052 int position;
00053 };
00054
00055
00056
00057 EXRIStream::EXRIStream(char *data, int size)
00058 : Imf::IStream("mypath")
00059 {
00060 this->data = data;
00061 this->size = size;
00062 position = 0;
00063 }
00064
00065 EXRIStream::~EXRIStream()
00066 {
00067 }
00068
00069 bool EXRIStream::read(char c[], int n)
00070 {
00071 int fragment = n;
00072 if(position + fragment > size)
00073 {
00074 fragment = size - position;
00075 }
00076 memcpy(c, data + position, fragment);
00077 position += fragment;
00078
00079 if(n != fragment)
00080 {
00081 throw Iex::InputExc ("EXRIStream::read: Unexpected end of file.");
00082 }
00083 return position >= size;
00084 }
00085
00086 Imf::Int64 EXRIStream::tellg ()
00087 {
00088 return position;
00089 }
00090
00091 void EXRIStream::seekg(Imf::Int64 pos)
00092 {
00093 position = pos;
00094 }
00095
00096 void EXRIStream::clear()
00097 {
00098 }
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 EXROStream::EXROStream(VFrame *data)
00111 : Imf::OStream("mypath")
00112 {
00113 this->data = data;
00114 position = 0;
00115 }
00116 EXROStream::~EXROStream()
00117 {
00118 }
00119
00120 void EXROStream::write(const char c[], int n)
00121 {
00122 if(position + n > data->get_compressed_allocated())
00123 data->allocate_compressed_data(MAX(position + n, data->get_compressed_allocated() * 2));
00124
00125 memcpy(data->get_data() + position, c, n);
00126 position += n;
00127 data->set_compressed_size(MAX(position, data->get_compressed_size()));
00128 }
00129
00130 Imf::Int64 EXROStream::tellp()
00131 {
00132 return position;
00133 }
00134
00135 void EXROStream::seekp(Imf::Int64 pos)
00136 {
00137 position = pos;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150 FileEXR::FileEXR(Asset *asset, File *file)
00151 : FileList(asset, file, "EXRLIST", ".exr", FILE_EXR, FILE_EXR_LIST)
00152 {
00153 native_cmodel = BC_RGB_FLOAT;
00154 is_yuv = 0;
00155 temp_y = 0;
00156 temp_u = 0;
00157 temp_v = 0;
00158 }
00159
00160 FileEXR::~FileEXR()
00161 {
00162 if(temp_y) delete [] temp_y;
00163 if(temp_u) delete [] temp_u;
00164 if(temp_v) delete [] temp_v;
00165 }
00166
00167 char* FileEXR::compression_to_str(int compression)
00168 {
00169 switch(compression)
00170 {
00171 case FileEXR::NONE: return "None"; break;
00172 case FileEXR::PIZ: return "PIZ"; break;
00173 case FileEXR::ZIP: return "ZIP"; break;
00174 case FileEXR::ZIPS: return "ZIPS"; break;
00175 case FileEXR::RLE: return "RLE"; break;
00176 case FileEXR::PXR24: return "PXR24"; break;
00177 }
00178 return "None";
00179 }
00180
00181 int FileEXR::compression_to_exr(int compression)
00182 {
00183 switch(compression)
00184 {
00185 case FileEXR::NONE: return (int)Imf::NO_COMPRESSION; break;
00186 case FileEXR::PIZ: return (int)Imf::PIZ_COMPRESSION; break;
00187 case FileEXR::ZIP: return (int)Imf::ZIP_COMPRESSION; break;
00188 case FileEXR::ZIPS: return (int)Imf::ZIPS_COMPRESSION; break;
00189 case FileEXR::RLE: return (int)Imf::RLE_COMPRESSION; break;
00190 case FileEXR::PXR24: return (int)Imf::PXR24_COMPRESSION; break;
00191 }
00192 return Imf::NO_COMPRESSION;
00193 }
00194
00195 int FileEXR::str_to_compression(char *string)
00196 {
00197 if(!strcmp(compression_to_str(FileEXR::NONE), string))
00198 return FileEXR::NONE;
00199 if(!strcmp(compression_to_str(FileEXR::PIZ), string))
00200 return FileEXR::PIZ;
00201 if(!strcmp(compression_to_str(FileEXR::ZIP), string))
00202 return FileEXR::ZIP;
00203 if(!strcmp(compression_to_str(FileEXR::ZIPS), string))
00204 return FileEXR::ZIPS;
00205 if(!strcmp(compression_to_str(FileEXR::RLE), string))
00206 return FileEXR::RLE;
00207 if(!strcmp(compression_to_str(FileEXR::PXR24), string))
00208 return PXR24;
00209 return FileEXR::NONE;
00210 }
00211
00212 int FileEXR::check_sig(Asset *asset, char *test)
00213 {
00214 if(Imf::isImfMagic(test)) return 1;
00215 if(test[0] == 'E' && test[1] == 'X' && test[2] == 'R' &&
00216 test[3] == 'L' && test[4] == 'I' && test[5] == 'S' && test[6] == 'T')
00217 {
00218 return 1;
00219 }
00220
00221 return 0;
00222 }
00223
00224 void FileEXR::get_parameters(BC_WindowBase *parent_window,
00225 Asset *asset,
00226 BC_WindowBase* &format_window,
00227 int audio_options,
00228 int video_options)
00229 {
00230 if(video_options)
00231 {
00232 EXRConfigVideo *window = new EXRConfigVideo(parent_window, asset);
00233 format_window = window;
00234 window->create_objects();
00235 window->run_window();
00236 delete window;
00237 }
00238 }
00239
00240 int FileEXR::colormodel_supported(int colormodel)
00241 {
00242 return native_cmodel;
00243 }
00244
00245 int FileEXR::get_best_colormodel(Asset *asset, int driver)
00246 {
00247 if(asset->exr_use_alpha)
00248 return BC_RGBA_FLOAT;
00249 else
00250 return BC_RGB_FLOAT;
00251 }
00252
00253 int FileEXR::get_memory_usage()
00254 {
00255 int result = FileList::get_memory_usage();
00256 if(temp_y) result += asset->width * asset->height * 3 / 2;
00257 return result;
00258 }
00259
00260
00261 int FileEXR::read_frame_header(char *path)
00262 {
00263 int result = 0;
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 Imf::InputFile file(path);
00283
00284 Imath::Box2i dw = file.header().dataWindow();
00285
00286 asset->width = dw.max.x - dw.min.x + 1;
00287 asset->height = dw.max.y - dw.min.y + 1;
00288 asset->interlace_mode = BC_ILACE_MODE_NOTINTERLACED;
00289
00290 const Imf::ChannelList &channels = file.header().channels();
00291
00292 if(channels.findChannel("A"))
00293 native_cmodel = BC_RGBA_FLOAT;
00294 else
00295 native_cmodel = BC_RGB_FLOAT;
00296
00297 if(channels.findChannel("Y"))
00298 is_yuv = 1;
00299
00300
00301
00302
00303
00304
00305 return result;
00306 }
00307
00308 int FileEXR::read_frame(VFrame *frame, VFrame *data)
00309 {
00310 EXRIStream exr_stream((char*)data->get_data(), data->get_compressed_size());
00311 Imf::InputFile file(exr_stream);
00312 Imath::Box2i dw = file.header().dataWindow();
00313 int dx = dw.min.x;
00314 int dy = dw.min.y;
00315 Imf::FrameBuffer framebuffer;
00316 float **rows = (float**)frame->get_rows();
00317 int components = cmodel_components(frame->get_color_model());
00318
00319 if(is_yuv)
00320 {
00321 if(!temp_y) temp_y = new float[asset->width * asset->height];
00322 if(!temp_u) temp_u = new float[asset->width * asset->height / 4];
00323 if(!temp_v) temp_v = new float[asset->width * asset->height / 4];
00324 framebuffer.insert("Y", Imf::Slice(Imf::FLOAT,
00325 (char*)(temp_y - dy * asset->width - dx),
00326 sizeof(float),
00327 sizeof(float) * frame->get_w()));
00328 framebuffer.insert("BY", Imf::Slice(Imf::FLOAT,
00329 (char*)(temp_u - dy * asset->width / 4 - dx / 2),
00330 sizeof(float),
00331 sizeof(float) * frame->get_w() / 2,
00332 2,
00333 2));
00334 framebuffer.insert("RY", Imf::Slice(Imf::FLOAT,
00335 (char*)(temp_v - dy * asset->width / 4 - dx / 2),
00336 sizeof(float),
00337 sizeof(float) * frame->get_w() / 2,
00338 2,
00339 2));
00340 }
00341 else
00342 {
00343 framebuffer.insert("R", Imf::Slice(Imf::FLOAT,
00344 (char*)(&rows[-dy][-dx * components]),
00345 sizeof(float) * components,
00346 sizeof(float) * components * frame->get_w()));
00347 framebuffer.insert("G", Imf::Slice(Imf::FLOAT,
00348 (char*)(&rows[-dy][-dx * components + 1]),
00349 sizeof(float) * components,
00350 sizeof(float) * components * frame->get_w()));
00351 framebuffer.insert("B", Imf::Slice(Imf::FLOAT,
00352 (char*)(&rows[-dy][-dx * components + 2]),
00353 sizeof(float) * components,
00354 sizeof(float) * components * frame->get_w()));
00355 }
00356
00357
00358 if(components == 4)
00359 {
00360 framebuffer.insert("A", Imf::Slice(Imf::FLOAT,
00361 (char*)(&rows[-dy][-dx * components + 3]),
00362 sizeof(float) * components,
00363 sizeof(float) * components * frame->get_w()));
00364 }
00365
00366 file.setFrameBuffer(framebuffer);
00367 file.readPixels (dw.min.y, dw.max.y);
00368
00369
00370
00371 if(is_yuv)
00372 {
00373
00374 Imath::V3f yw;
00375 Imf::Chromaticities cr;
00376 yw = Imf::RgbaYca::computeYw(cr);
00377
00378 for(int i = 0; i < asset->height - 1; i += 2)
00379 {
00380 float *y_row1 = temp_y + i * asset->width;
00381 float *y_row2 = temp_y + (i + 1) * asset->width;
00382 float *u_row = temp_u + (i * asset->width / 4);
00383 float *v_row = temp_v + (i * asset->width / 4);
00384 float *out_row1 = rows[i];
00385 float *out_row2 = rows[i + 1];
00386 for(int j = 0; j < asset->width - 1; j += 2)
00387 {
00388 float v = *u_row++;
00389 float u = *v_row++;
00390 float y;
00391
00392 float r, g, b;
00393 y = *y_row1++;
00394 r = (u + 1) * y;
00395 b = (v + 1) * y;
00396 g = (y - r * yw.x - b * yw.z) / yw.y;
00397 *out_row1++ = r;
00398 *out_row1++ = g;
00399 *out_row1++ = b;
00400 if(components == 4) out_row1++;
00401
00402 y = *y_row1++;
00403 r = (u + 1) * y;
00404 b = (v + 1) * y;
00405 g = (y - r * yw.x - b * yw.z) / yw.y;
00406 *out_row1++ = r;
00407 *out_row1++ = g;
00408 *out_row1++ = b;
00409 if(components == 4) out_row1++;
00410
00411 y = *y_row2++;
00412 r = (u + 1) * y;
00413 b = (v + 1) * y;
00414 g = (y - r * yw.x - b * yw.z) / yw.y;
00415 *out_row2++ = r;
00416 *out_row2++ = g;
00417 *out_row2++ = b;
00418 if(components == 4) out_row1++;
00419
00420 y = *y_row2++;
00421 r = (u + 1) * y;
00422 b = (v + 1) * y;
00423 g = (y - r * yw.x - b * yw.z) / yw.y;
00424 *out_row2++ = r;
00425 *out_row2++ = g;
00426 *out_row2++ = b;
00427 if(components == 4) out_row1++;
00428 }
00429 }
00430 }
00431 }
00432
00433
00434
00435
00436 int FileEXR::write_frame(VFrame *frame, VFrame *data, FrameWriterUnit *unit)
00437 {
00438
00439 EXRUnit *exr_unit = (EXRUnit*)unit;
00440 int result = 0;
00441
00442 VFrame *output_frame;
00443 data->set_compressed_size(0);
00444
00445
00446 int native_cmodel = asset->exr_use_alpha ? BC_RGBA_FLOAT : BC_RGB_FLOAT;
00447 int components = cmodel_components(native_cmodel);
00448
00449 if(frame->get_color_model() != native_cmodel)
00450 {
00451 if(!exr_unit->temp_frame) exr_unit->temp_frame = new VFrame(0,
00452 asset->width,
00453 asset->height,
00454 native_cmodel);
00455 cmodel_transfer(exr_unit->temp_frame->get_rows(),
00456 frame->get_rows(),
00457 exr_unit->temp_frame->get_y(),
00458 exr_unit->temp_frame->get_u(),
00459 exr_unit->temp_frame->get_v(),
00460 frame->get_y(),
00461 frame->get_u(),
00462 frame->get_v(),
00463 0,
00464 0,
00465 asset->width,
00466 asset->height,
00467 0,
00468 0,
00469 asset->width,
00470 asset->height,
00471 frame->get_color_model(),
00472 native_cmodel,
00473 0,
00474 asset->width,
00475 asset->height);
00476 output_frame = exr_unit->temp_frame;
00477 }
00478 else
00479 output_frame = frame;
00480
00481 Imf::Header header(output_frame->get_w(), output_frame->get_h());
00482 header.compression() = (Imf::Compression)compression_to_exr(
00483 asset->exr_compression);
00484 header.channels().insert("R", Imf::Channel(Imf::FLOAT));
00485 header.channels().insert("G", Imf::Channel(Imf::FLOAT));
00486 header.channels().insert("B", Imf::Channel(Imf::FLOAT));
00487 if(asset->exr_use_alpha) header.channels().insert("A", Imf::Channel(Imf::FLOAT));
00488
00489 EXROStream exr_stream(data);
00490 Imf::OutputFile file(exr_stream, header);
00491 Imf::FrameBuffer framebuffer;
00492 float **rows = (float**)output_frame->get_rows();
00493 framebuffer.insert("R",
00494 Imf::Slice(Imf::FLOAT,
00495 (char*)(rows[0]),
00496 sizeof(float) * components,
00497 sizeof(float) * components * output_frame->get_w()));
00498 framebuffer.insert("G",
00499 Imf::Slice(Imf::FLOAT,
00500 (char*)(rows[0] + 1),
00501 sizeof(float) * components,
00502 sizeof(float) * components * output_frame->get_w()));
00503 framebuffer.insert("B",
00504 Imf::Slice(Imf::FLOAT,
00505 (char*)(rows[0] + 2),
00506 sizeof(float) * components,
00507 sizeof(float) * components * output_frame->get_w()));
00508 if(asset->exr_use_alpha)
00509 framebuffer.insert("A",
00510 Imf::Slice(Imf::FLOAT,
00511 (char*)(rows[0] + 3),
00512 sizeof(float) * components,
00513 sizeof(float) * components * output_frame->get_w()));
00514 file.setFrameBuffer(framebuffer);
00515 file.writePixels(asset->height);
00516
00517 }
00518
00519 FrameWriterUnit* FileEXR::new_writer_unit(FrameWriter *writer)
00520 {
00521 return new EXRUnit(this, writer);
00522 }
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 EXRUnit::EXRUnit(FileEXR *file, FrameWriter *writer)
00536 : FrameWriterUnit(writer)
00537 {
00538 this->file = file;
00539 temp_frame = 0;
00540 }
00541
00542 EXRUnit::~EXRUnit()
00543 {
00544 if(temp_frame) delete temp_frame;
00545 }
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 EXRConfigVideo::EXRConfigVideo(BC_WindowBase *parent_window, Asset *asset)
00558 : BC_Window(PROGRAM_NAME ": Video Compression",
00559 parent_window->get_abs_cursor_x(1),
00560 parent_window->get_abs_cursor_y(1),
00561 300,
00562 BC_OKButton::calculate_h() + 100)
00563 {
00564 this->parent_window = parent_window;
00565 this->asset = asset;
00566 }
00567
00568 EXRConfigVideo::~EXRConfigVideo()
00569 {
00570 }
00571
00572 int EXRConfigVideo::create_objects()
00573 {
00574 int x = 10, y = 10;
00575 add_subwindow(new EXRUseAlpha(this, x, y));
00576 y += 30;
00577 EXRCompression *menu;
00578 add_subwindow(new BC_Title(x, y, "Compression:"));
00579 x += 110;
00580 add_subwindow(menu = new EXRCompression(this, x, y, 100));
00581 menu->create_objects();
00582 add_subwindow(new BC_OKButton(this));
00583 return 0;
00584 }
00585
00586 int EXRConfigVideo::close_event()
00587 {
00588 set_done(0);
00589 return 1;
00590 }
00591
00592
00593 EXRUseAlpha::EXRUseAlpha(EXRConfigVideo *gui, int x, int y)
00594 : BC_CheckBox(x, y, gui->asset->exr_use_alpha, _("Use alpha"))
00595 {
00596 this->gui = gui;
00597 }
00598
00599 int EXRUseAlpha::handle_event()
00600 {
00601 gui->asset->exr_use_alpha = get_value();
00602 return 1;
00603 }
00604
00605
00606
00607 EXRCompression::EXRCompression(EXRConfigVideo *gui, int x, int y, int w)
00608 : BC_PopupMenu(x,
00609 y,
00610 w,
00611 FileEXR::compression_to_str(gui->asset->exr_compression))
00612 {
00613 this->gui = gui;
00614 }
00615 void EXRCompression::create_objects()
00616 {
00617 add_item(new EXRCompressionItem(gui, FileEXR::NONE));
00618 add_item(new EXRCompressionItem(gui, FileEXR::PIZ));
00619 add_item(new EXRCompressionItem(gui, FileEXR::ZIP));
00620 add_item(new EXRCompressionItem(gui, FileEXR::ZIPS));
00621 add_item(new EXRCompressionItem(gui, FileEXR::RLE));
00622 add_item(new EXRCompressionItem(gui, FileEXR::PXR24));
00623 }
00624
00625 int EXRCompression::handle_event()
00626 {
00627 return 1;
00628 }
00629
00630 EXRCompressionItem::EXRCompressionItem(EXRConfigVideo *gui, int value)
00631 : BC_MenuItem(FileEXR::compression_to_str(value))
00632 {
00633 this->gui = gui;
00634 this->value = value;
00635 }
00636
00637 int EXRCompressionItem::handle_event()
00638 {
00639 gui->asset->exr_compression = value;
00640 return 0;
00641 }
00642