#include "DDImage/DeepReader.h" #include "DDImage/plugins.h" #include "DDImage/Knobs.h" #include "DDImage/DeepPixel.h" #include "DDImage/DeepPlane.h" #include #include #include #include #include #include "DeepRead.h" using namespace DD::Image; static Op* build(Node* node) { return new DeepRead(node); } const Op::Description DeepRead::d("DeepRead", "Image/DeepRead", build); DeepRead::DeepRead(Node* node) : DeepOnlyOp(node) , _reader(NULL) , _fileformat(NULL) , _filename("") , _readerType(NULL) , _filetype(NULL) , _formatHint(NULL) , _outputType(IMAGE) , _first(1) , _last(1) { inputs(0); } const char* DeepRead::node_help() const { return "Read deep data from files."; } void DeepRead::knobs(Knob_Callback f) { Knob* rfk = Read_File_knob(this, f, &_filename, "file"); if (f.makeKnobs() && rfk) rfk->set_flag(Knob::KNOB_CHANGED_ALWAYS | Knob::EARLY_STORE); Obsolete_knob(f, "File", "knob file $value"); Obsolete_knob(f, "Format", "knob format $value"); Reload_Button(f); Tooltip(f, "Re-read the deep image from the disk"); if (!f.makeKnobs()) makeFormat(); replaceable_knobs(f); } void DeepRead::append(Hash& hash) { outputContext().appendProxy(hash); } void DeepRead::_validate(bool forReal) { makeReader(_filename); ReadGuard guard(_readerLock); if (_reader) { _deepInfo = _reader->deepInfo(); _deepInfo.setFirstFrame(_first); _deepInfo.setLastFrame(_last); } else { if ( (_outputType & IGNORE_MISSING_CLIP) != 0 ){ _deepInfo = DeepInfo( FormatPair(_formatHint,_formatHint), DD::Image::Box(0, 0, _formatHint->width(), _formatHint->height()), Mask_RGB | Mask_Alpha | Mask_Deep); } } } void DeepRead::makeFormat() { if (firstRead() && firstRead() != this) { firstRead()->makeFormat(); return; } const char* fname = _filename.c_str(); if (!fname || !*fname) { fname = knob("file")->get_text(); } std::string extension; std::string realname; if (!fname) { delete _fileformat; _fileformat = 0; return; } const DeepReader::Description* r = NULL; if (GetFormatAndName(fname, extension, realname)) { r = DeepReader::Description::find(extension.c_str()); if (!r) { internalError("%s", plugin_error()); } } else { internalError("no reader"); } if (_readerType == r) return; if (_fileformat) { delete _fileformat; _fileformat = 0; } if (r && r->formatConstructor) { _fileformat = (*r->formatConstructor)(this); } _readerType = r; // save file type _filetype = r ? r->names : 0; FileOp::replace_knobs(_readerType, _filetype); } int DeepRead::knob_changed(Knob* k) { if (k && k->is("file")) { makeFormat(); return 1; } return DeepOnlyOp::knob_changed(k); } bool DeepRead::doDeepEngine(DD::Image::Box box, const DD::Image::ChannelSet& channels, DeepOutputPlane& plane) { if ( _readerError ) { error("%s", _readerErrorString.c_str()); return true; } if ((_outputType & TYPE_MASK) == BLACK) { DD::Image::DeepInPlaceOutputPlane outPlane(channels, box, DeepPixel::eZAscending); for (Box::iterator it = box.begin(); it != box.end(); it++) { outPlane.setSampleCount(it, 0); } plane = outPlane; return true; } if ((_outputType & TYPE_MASK) == CHECKERBOARD) { DD::Image::DeepInPlaceOutputPlane outPlane(channels, box, DeepPixel::eZAscending); outPlane.reserveSamples(box.area()); for (Box::iterator it = box.begin(); it != box.end(); it++) { outPlane.setSampleCount(it, 1); DeepOutputPixel out = outPlane.getPixel(it); float* output = out.writable(); foreach (z, channels) { if (z == Chan_DeepFront || z == Chan_DeepBack) { *output++ = 1; } else { int m = 16 + z; const int masked = ( it.y + m ) & 63; if ( masked > 31) m += 32; const int modified = ( it.x + m ) & 63; *output++ = modified > 31 ? 1.0f : 0.0f; } } } mFnAssert(outPlane.isComplete()); plane = outPlane; return true; } ReadGuard guard(_readerLock); bool success = false; if (_reader == NULL) error("missing reader for %s", _filename.c_str()); else success = _reader->doDeepEngine(box, channels, plane); return success; } void DeepRead::makeReader(const std::string& filename) { WriteGuard guard(_readerLock); if (_reader && _readerFilename == filename) { DD::Image::Hash hash; outputContext().appendProxy(hash); formatHint()->append(hash); hash.append( version() ); if ( _fileformat ) _fileformat->append( hash ); if (hash == _readerHash) { return; } } if (_reader) { delete _reader; _reader = NULL; } _readerError = false; _readerErrorString = ""; std::string extension; std::string realname; if (!GetFormatAndName(filename.c_str(), extension, realname)) { error("no format"); return; } const DeepReader::Description* r = extension.length() ? DeepReader::Description::find(extension.c_str()) : NULL; _readerFilename = realname; _readerContext = outputContext(); float sx = 1, sy = 1; const bool formatHintValid = _formatHint && (_formatHint->width() != 0) && (_formatHint->height() != 0); if (formatHintValid && _formatPair.fullSizeFormat()) { sx = float(_formatPair.fullSizeFormat()->width()) / _formatHint->width(); sy = float(_formatPair.fullSizeFormat()->height()) / _formatHint->height(); } _readerContext.scale(sx, sy); if (!r) { error("Cannot open deep reader: %s.", plugin_error()); _readerHash.reset(); return; } if ( (_outputType & IGNORE_MISSING_CLIP) != 0){ return; } _reader = r->constructor(this, _readerFilename); _readerHash.reset(); outputContext().appendProxy(_readerHash); if (formatHintValid) { formatHint()->append(_readerHash); } _readerHash.append( version() ); } const MetaData::Bundle& DeepRead::_fetchMetaData(const char* keyname) { makeReader(_filename); ReadGuard guard(_readerLock); if ( _reader ) { _meta = _reader->metaData(); /// We can't return this directly, because the Reader might get deleted /// (thus invalidating the reference) when the Read is closed. /// /// So, let us make a local copy to store it in, which is guaranteed /// to be around for as long as we need it. We can put some non-reader /// specific things in this, also. // If it starts with "type:" then we force use of that type of reader. // This also is how you can pass strings to non-file Reader classes const char* fname = StripPrefix(_readerFilename.c_str() ); struct stat buf; int err = stat(fname, &buf); if (err != -1) { char sbuf[30]; strftime(sbuf, 30, "%Y-%m-%d %H:%M:%S", localtime(&buf.st_mtime)); _meta.setData(MetaData::MODIFIED_TIME, sbuf); strftime(sbuf, 30, "%Y-%m-%d %H:%M:%S", localtime(&buf.st_ctime)); _meta.setData(MetaData::CREATED_TIME, sbuf); _meta.setData(MetaData::FILESIZE, (unsigned)buf.st_size); } _meta.setData(MetaData::FILENAME, _readerFilename ); _meta.setData(MetaData::WIDTH, _reader->deepInfo().box().w() ); _meta.setData(MetaData::HEIGHT, _reader->deepInfo().box().h() ); const DeepReader::Description* readerdesc = static_cast(_readerType); if ( readerdesc ) _meta.setData(MetaData::FILEREADER, readerdesc->label); } return _meta; } void DeepRead::_open() { makeReader(_filename); } void DeepRead::close() { WriteGuard guard(_readerLock); delete _reader; _reader = NULL; } const char* DeepRead::getFilename() const { return _filename.c_str(); } const char* DeepRead::Class() const { return "DeepRead"; } void DeepRead::expectedFrameRange(int first, int last) { _first = first; _last = last; } void DeepRead::setReadFormat(const DD::Image::Format* format) { _formatHint = format; } const Format* DeepRead::formatHint() const { return _formatHint; } void DeepRead::output_type(int i) { _outputType = i; } void DeepRead::setFullSizeFormat(const DD::Image::Format* f) { _formatPair.fullSizeFormat(f); } void DeepRead::setFormat(const DD::Image::Format* f) { _formatPair.format(f); } FormatPair& DeepRead::getFormats() { return _formatPair; } bool DeepRead::videosequence() const { return false; } void DeepRead::force_near_frame(bool) { } void DeepRead::frame_for_reader(int) { }