ImfScanLineInputFile.cpp 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738
  1. ///////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2004, Industrial Light & Magic, a division of Lucas
  4. // Digital Ltd. LLC
  5. //
  6. // All rights reserved.
  7. //
  8. // Redistribution and use in source and binary forms, with or without
  9. // modification, are permitted provided that the following conditions are
  10. // met:
  11. // * Redistributions of source code must retain the above copyright
  12. // notice, this list of conditions and the following disclaimer.
  13. // * Redistributions in binary form must reproduce the above
  14. // copyright notice, this list of conditions and the following disclaimer
  15. // in the documentation and/or other materials provided with the
  16. // distribution.
  17. // * Neither the name of Industrial Light & Magic nor the names of
  18. // its contributors may be used to endorse or promote products derived
  19. // from this software without specific prior written permission.
  20. //
  21. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  25. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  26. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  27. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  28. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  29. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  30. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  31. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. //
  33. ///////////////////////////////////////////////////////////////////////////
  34. //-----------------------------------------------------------------------------
  35. //
  36. // class ScanLineInputFile
  37. //
  38. //-----------------------------------------------------------------------------
  39. #include "ImfScanLineInputFile.h"
  40. #include "ImfChannelList.h"
  41. #include "ImfMisc.h"
  42. #include "ImfStdIO.h"
  43. #include "ImfCompressor.h"
  44. #include "ImathBox.h"
  45. #include "ImathFun.h"
  46. #include <ImfXdr.h>
  47. #include <ImfConvert.h>
  48. #include <ImfThreading.h>
  49. #include <ImfPartType.h>
  50. #include "IlmThreadPool.h"
  51. #include "IlmThreadSemaphore.h"
  52. #include "IlmThreadMutex.h"
  53. #include "Iex.h"
  54. #include "ImfVersion.h"
  55. #include "ImfOptimizedPixelReading.h"
  56. #include "ImfNamespace.h"
  57. #include "ImfStandardAttributes.h"
  58. #include <algorithm>
  59. #include <string>
  60. #include <vector>
  61. #include <assert.h>
  62. #include <cstring>
  63. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
  64. using IMATH_NAMESPACE::Box2i;
  65. using IMATH_NAMESPACE::divp;
  66. using IMATH_NAMESPACE::modp;
  67. using std::string;
  68. using std::vector;
  69. using std::ifstream;
  70. using std::min;
  71. using std::max;
  72. using std::sort;
  73. using ILMTHREAD_NAMESPACE::Mutex;
  74. using ILMTHREAD_NAMESPACE::Lock;
  75. using ILMTHREAD_NAMESPACE::Semaphore;
  76. using ILMTHREAD_NAMESPACE::Task;
  77. using ILMTHREAD_NAMESPACE::TaskGroup;
  78. using ILMTHREAD_NAMESPACE::ThreadPool;
  79. namespace {
  80. struct InSliceInfo
  81. {
  82. PixelType typeInFrameBuffer;
  83. PixelType typeInFile;
  84. char * base;
  85. size_t xStride;
  86. size_t yStride;
  87. int xSampling;
  88. int ySampling;
  89. bool fill;
  90. bool skip;
  91. double fillValue;
  92. InSliceInfo (PixelType typeInFrameBuffer = HALF,
  93. PixelType typeInFile = HALF,
  94. char *base = 0,
  95. size_t xStride = 0,
  96. size_t yStride = 0,
  97. int xSampling = 1,
  98. int ySampling = 1,
  99. bool fill = false,
  100. bool skip = false,
  101. double fillValue = 0.0);
  102. };
  103. InSliceInfo::InSliceInfo (PixelType tifb,
  104. PixelType tifl,
  105. char *b,
  106. size_t xs, size_t ys,
  107. int xsm, int ysm,
  108. bool f, bool s,
  109. double fv)
  110. :
  111. typeInFrameBuffer (tifb),
  112. typeInFile (tifl),
  113. base (b),
  114. xStride (xs),
  115. yStride (ys),
  116. xSampling (xsm),
  117. ySampling (ysm),
  118. fill (f),
  119. skip (s),
  120. fillValue (fv)
  121. {
  122. // empty
  123. }
  124. struct LineBuffer
  125. {
  126. const char * uncompressedData;
  127. char * buffer;
  128. int dataSize;
  129. int minY;
  130. int maxY;
  131. Compressor * compressor;
  132. Compressor::Format format;
  133. int number;
  134. bool hasException;
  135. string exception;
  136. LineBuffer (Compressor * const comp);
  137. ~LineBuffer ();
  138. inline void wait () {_sem.wait();}
  139. inline void post () {_sem.post();}
  140. private:
  141. Semaphore _sem;
  142. };
  143. LineBuffer::LineBuffer (Compressor *comp):
  144. uncompressedData (0),
  145. buffer (0),
  146. dataSize (0),
  147. compressor (comp),
  148. format (defaultFormat(compressor)),
  149. number (-1),
  150. hasException (false),
  151. exception (),
  152. _sem (1)
  153. {
  154. // empty
  155. }
  156. LineBuffer::~LineBuffer ()
  157. {
  158. delete compressor;
  159. }
  160. /// helper struct used to detect the order that the channels are stored
  161. struct sliceOptimizationData
  162. {
  163. const char * base; ///< pointer to pixel data
  164. bool fill; ///< is this channel being filled with constant, instead of read?
  165. half fillValue; ///< if filling, the value to use
  166. size_t offset; ///< position this channel will be in the read buffer, accounting for previous channels, as well as their type
  167. PixelType type; ///< type of channel
  168. size_t xStride; ///< x-stride of channel in buffer (must be set to cause channels to interleave)
  169. size_t yStride; ///< y-stride of channel in buffer (must be same in all channels, else order will change, which is bad)
  170. int xSampling; ///< channel x sampling
  171. int ySampling; ///< channel y sampling
  172. /// we need to keep the list sorted in the order they'll be written to memory
  173. bool operator<(const sliceOptimizationData& other ) const
  174. {
  175. return base < other.base;
  176. }
  177. };
  178. } // namespace
  179. struct ScanLineInputFile::Data: public Mutex
  180. {
  181. Header header; // the image header
  182. int version; // file's version
  183. FrameBuffer frameBuffer; // framebuffer to write into
  184. LineOrder lineOrder; // order of the scanlines in file
  185. int minX; // data window's min x coord
  186. int maxX; // data window's max x coord
  187. int minY; // data window's min y coord
  188. int maxY; // data window's max x coord
  189. vector<Int64> lineOffsets; // stores offsets in file for
  190. // each line
  191. bool fileIsComplete; // True if no scanlines are missing
  192. // in the file
  193. int nextLineBufferMinY; // minimum y of the next linebuffer
  194. vector<size_t> bytesPerLine; // combined size of a line over all
  195. // channels
  196. vector<size_t> offsetInLineBuffer; // offset for each scanline in its
  197. // linebuffer
  198. vector<InSliceInfo> slices; // info about channels in file
  199. vector<LineBuffer*> lineBuffers; // each holds one line buffer
  200. int linesInBuffer; // number of scanlines each buffer
  201. // holds
  202. size_t lineBufferSize; // size of the line buffer
  203. int partNumber; // part number
  204. bool memoryMapped; // if the stream is memory mapped
  205. OptimizationMode optimizationMode; // optimizibility of the input file
  206. vector<sliceOptimizationData> optimizationData; ///< channel ordering for optimized reading
  207. Data (int numThreads);
  208. ~Data ();
  209. inline LineBuffer * getLineBuffer (int number); // hash function from line
  210. // buffer indices into our
  211. // vector of line buffers
  212. };
  213. ScanLineInputFile::Data::Data (int numThreads):
  214. partNumber(-1),
  215. memoryMapped(false)
  216. {
  217. //
  218. // We need at least one lineBuffer, but if threading is used,
  219. // to keep n threads busy we need 2*n lineBuffers
  220. //
  221. lineBuffers.resize (max (1, 2 * numThreads));
  222. }
  223. ScanLineInputFile::Data::~Data ()
  224. {
  225. for (size_t i = 0; i < lineBuffers.size(); i++)
  226. delete lineBuffers[i];
  227. }
  228. inline LineBuffer *
  229. ScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
  230. {
  231. return lineBuffers[lineBufferNumber % lineBuffers.size()];
  232. }
  233. namespace {
  234. void
  235. reconstructLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  236. LineOrder lineOrder,
  237. vector<Int64> &lineOffsets)
  238. {
  239. Int64 position = is.tellg();
  240. try
  241. {
  242. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  243. {
  244. Int64 lineOffset = is.tellg();
  245. int y;
  246. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y);
  247. int dataSize;
  248. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, dataSize);
  249. Xdr::skip <StreamIO> (is, dataSize);
  250. if (lineOrder == INCREASING_Y)
  251. lineOffsets[i] = lineOffset;
  252. else
  253. lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
  254. }
  255. }
  256. catch (...)
  257. {
  258. //
  259. // Suppress all exceptions. This functions is
  260. // called only to reconstruct the line offset
  261. // table for incomplete files, and exceptions
  262. // are likely.
  263. //
  264. }
  265. is.clear();
  266. is.seekg (position);
  267. }
  268. void
  269. readLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
  270. LineOrder lineOrder,
  271. vector<Int64> &lineOffsets,
  272. bool &complete)
  273. {
  274. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  275. {
  276. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, lineOffsets[i]);
  277. }
  278. complete = true;
  279. for (unsigned int i = 0; i < lineOffsets.size(); i++)
  280. {
  281. if (lineOffsets[i] <= 0)
  282. {
  283. //
  284. // Invalid data in the line offset table mean that
  285. // the file is probably incomplete (the table is
  286. // the last thing written to the file). Either
  287. // some process is still busy writing the file,
  288. // or writing the file was aborted.
  289. //
  290. // We should still be able to read the existing
  291. // parts of the file. In order to do this, we
  292. // have to make a sequential scan over the scan
  293. // line data to reconstruct the line offset table.
  294. //
  295. complete = false;
  296. reconstructLineOffsets (is, lineOrder, lineOffsets);
  297. break;
  298. }
  299. }
  300. }
  301. void
  302. readPixelData (InputStreamMutex *streamData,
  303. ScanLineInputFile::Data *ifd,
  304. int minY,
  305. char *&buffer,
  306. int &dataSize)
  307. {
  308. //
  309. // Read a single line buffer from the input file.
  310. //
  311. // If the input file is not memory-mapped, we copy the pixel data into
  312. // into the array pointed to by buffer. If the file is memory-mapped,
  313. // then we change where buffer points to instead of writing into the
  314. // array (hence buffer needs to be a reference to a char *).
  315. //
  316. int lineBufferNumber = (minY - ifd->minY) / ifd->linesInBuffer;
  317. if (lineBufferNumber < 0 || lineBufferNumber >= int(ifd->lineOffsets.size()))
  318. THROW (IEX_NAMESPACE::InputExc, "Invalid scan line " << minY << " requested or missing.");
  319. Int64 lineOffset = ifd->lineOffsets[lineBufferNumber];
  320. if (lineOffset == 0)
  321. THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
  322. //
  323. // Seek to the start of the scan line in the file,
  324. // if necessary.
  325. //
  326. if ( !isMultiPart(ifd->version) )
  327. {
  328. if (ifd->nextLineBufferMinY != minY)
  329. streamData->is->seekg (lineOffset);
  330. }
  331. else
  332. {
  333. //
  334. // In a multi-part file, the file pointer may have been moved by
  335. // other parts, so we have to ask tellg() where we are.
  336. //
  337. if (streamData->is->tellg() != ifd->lineOffsets[lineBufferNumber])
  338. streamData->is->seekg (lineOffset);
  339. }
  340. //
  341. // Read the data block's header.
  342. //
  343. int yInFile;
  344. //
  345. // Read the part number when we are dealing with a multi-part file.
  346. //
  347. if (isMultiPart(ifd->version))
  348. {
  349. int partNumber;
  350. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
  351. if (partNumber != ifd->partNumber)
  352. {
  353. THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
  354. << ", should be " << ifd->partNumber << ".");
  355. }
  356. }
  357. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, yInFile);
  358. OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, dataSize);
  359. if (yInFile != minY)
  360. throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
  361. if (dataSize > (int) ifd->lineBufferSize)
  362. throw IEX_NAMESPACE::InputExc ("Unexpected data block length.");
  363. //
  364. // Read the pixel data.
  365. //
  366. if (streamData->is->isMemoryMapped ())
  367. buffer = streamData->is->readMemoryMapped (dataSize);
  368. else
  369. streamData->is->read (buffer, dataSize);
  370. //
  371. // Keep track of which scan line is the next one in
  372. // the file, so that we can avoid redundant seekg()
  373. // operations (seekg() can be fairly expensive).
  374. //
  375. if (ifd->lineOrder == INCREASING_Y)
  376. ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
  377. else
  378. ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
  379. }
  380. //
  381. // A LineBufferTask encapsulates the task uncompressing a set of
  382. // scanlines (line buffer) and copying them into the frame buffer.
  383. //
  384. class LineBufferTask : public Task
  385. {
  386. public:
  387. LineBufferTask (TaskGroup *group,
  388. ScanLineInputFile::Data *ifd,
  389. LineBuffer *lineBuffer,
  390. int scanLineMin,
  391. int scanLineMax,
  392. OptimizationMode optimizationMode);
  393. virtual ~LineBufferTask ();
  394. virtual void execute ();
  395. private:
  396. ScanLineInputFile::Data * _ifd;
  397. LineBuffer * _lineBuffer;
  398. int _scanLineMin;
  399. int _scanLineMax;
  400. OptimizationMode _optimizationMode;
  401. };
  402. LineBufferTask::LineBufferTask
  403. (TaskGroup *group,
  404. ScanLineInputFile::Data *ifd,
  405. LineBuffer *lineBuffer,
  406. int scanLineMin,
  407. int scanLineMax,OptimizationMode optimizationMode)
  408. :
  409. Task (group),
  410. _ifd (ifd),
  411. _lineBuffer (lineBuffer),
  412. _scanLineMin (scanLineMin),
  413. _scanLineMax (scanLineMax),
  414. _optimizationMode(optimizationMode)
  415. {
  416. // empty
  417. }
  418. LineBufferTask::~LineBufferTask ()
  419. {
  420. //
  421. // Signal that the line buffer is now free
  422. //
  423. _lineBuffer->post ();
  424. }
  425. void
  426. LineBufferTask::execute ()
  427. {
  428. try
  429. {
  430. //
  431. // Uncompress the data, if necessary
  432. //
  433. if (_lineBuffer->uncompressedData == 0)
  434. {
  435. int uncompressedSize = 0;
  436. int maxY = min (_lineBuffer->maxY, _ifd->maxY);
  437. for (int i = _lineBuffer->minY - _ifd->minY;
  438. i <= maxY - _ifd->minY;
  439. ++i)
  440. {
  441. uncompressedSize += (int) _ifd->bytesPerLine[i];
  442. }
  443. if (_lineBuffer->compressor &&
  444. _lineBuffer->dataSize < uncompressedSize)
  445. {
  446. _lineBuffer->format = _lineBuffer->compressor->format();
  447. _lineBuffer->dataSize = _lineBuffer->compressor->uncompress
  448. (_lineBuffer->buffer,
  449. _lineBuffer->dataSize,
  450. _lineBuffer->minY,
  451. _lineBuffer->uncompressedData);
  452. }
  453. else
  454. {
  455. //
  456. // If the line is uncompressed, it's in XDR format,
  457. // regardless of the compressor's output format.
  458. //
  459. _lineBuffer->format = Compressor::XDR;
  460. _lineBuffer->uncompressedData = _lineBuffer->buffer;
  461. }
  462. }
  463. int yStart, yStop, dy;
  464. if (_ifd->lineOrder == INCREASING_Y)
  465. {
  466. yStart = _scanLineMin;
  467. yStop = _scanLineMax + 1;
  468. dy = 1;
  469. }
  470. else
  471. {
  472. yStart = _scanLineMax;
  473. yStop = _scanLineMin - 1;
  474. dy = -1;
  475. }
  476. for (int y = yStart; y != yStop; y += dy)
  477. {
  478. //
  479. // Convert one scan line's worth of pixel data back
  480. // from the machine-independent representation, and
  481. // store the result in the frame buffer.
  482. //
  483. const char *readPtr = _lineBuffer->uncompressedData +
  484. _ifd->offsetInLineBuffer[y - _ifd->minY];
  485. //
  486. // Iterate over all image channels.
  487. //
  488. for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
  489. {
  490. //
  491. // Test if scan line y of this channel contains any data
  492. // (the scan line contains data only if y % ySampling == 0).
  493. //
  494. const InSliceInfo &slice = _ifd->slices[i];
  495. if (modp (y, slice.ySampling) != 0)
  496. continue;
  497. //
  498. // Find the x coordinates of the leftmost and rightmost
  499. // sampled pixels (i.e. pixels within the data window
  500. // for which x % xSampling == 0).
  501. //
  502. int dMinX = divp (_ifd->minX, slice.xSampling);
  503. int dMaxX = divp (_ifd->maxX, slice.xSampling);
  504. //
  505. // Fill the frame buffer with pixel data.
  506. //
  507. if (slice.skip)
  508. {
  509. //
  510. // The file contains data for this channel, but
  511. // the frame buffer contains no slice for this channel.
  512. //
  513. skipChannel (readPtr, slice.typeInFile, dMaxX - dMinX + 1);
  514. }
  515. else
  516. {
  517. //
  518. // The frame buffer contains a slice for this channel.
  519. //
  520. char *linePtr = slice.base +
  521. divp (y, slice.ySampling) *
  522. slice.yStride;
  523. char *writePtr = linePtr + dMinX * slice.xStride;
  524. char *endPtr = linePtr + dMaxX * slice.xStride;
  525. copyIntoFrameBuffer (readPtr, writePtr, endPtr,
  526. slice.xStride, slice.fill,
  527. slice.fillValue, _lineBuffer->format,
  528. slice.typeInFrameBuffer,
  529. slice.typeInFile);
  530. }
  531. }
  532. }
  533. }
  534. catch (std::exception &e)
  535. {
  536. if (!_lineBuffer->hasException)
  537. {
  538. _lineBuffer->exception = e.what();
  539. _lineBuffer->hasException = true;
  540. }
  541. }
  542. catch (...)
  543. {
  544. if (!_lineBuffer->hasException)
  545. {
  546. _lineBuffer->exception = "unrecognized exception";
  547. _lineBuffer->hasException = true;
  548. }
  549. }
  550. }
  551. #ifdef IMF_HAVE_SSE2
  552. //
  553. // IIF format is more restricted than a perfectly generic one,
  554. // so it is possible to perform some optimizations.
  555. //
  556. class LineBufferTaskIIF : public Task
  557. {
  558. public:
  559. LineBufferTaskIIF (TaskGroup *group,
  560. ScanLineInputFile::Data *ifd,
  561. LineBuffer *lineBuffer,
  562. int scanLineMin,
  563. int scanLineMax,
  564. OptimizationMode optimizationMode);
  565. virtual ~LineBufferTaskIIF ();
  566. virtual void execute ();
  567. template<typename TYPE>
  568. void getWritePointer (int y,
  569. unsigned short*& pOutWritePointerRight,
  570. size_t& outPixelsToCopySSE,
  571. size_t& outPixelsToCopyNormal,int bank=0) const;
  572. template<typename TYPE>
  573. void getWritePointerStereo (int y,
  574. unsigned short*& outWritePointerRight,
  575. unsigned short*& outWritePointerLeft,
  576. size_t& outPixelsToCopySSE,
  577. size_t& outPixelsToCopyNormal) const;
  578. private:
  579. ScanLineInputFile::Data * _ifd;
  580. LineBuffer * _lineBuffer;
  581. int _scanLineMin;
  582. int _scanLineMax;
  583. OptimizationMode _optimizationMode;
  584. };
  585. LineBufferTaskIIF::LineBufferTaskIIF
  586. (TaskGroup *group,
  587. ScanLineInputFile::Data *ifd,
  588. LineBuffer *lineBuffer,
  589. int scanLineMin,
  590. int scanLineMax,
  591. OptimizationMode optimizationMode
  592. )
  593. :
  594. Task (group),
  595. _ifd (ifd),
  596. _lineBuffer (lineBuffer),
  597. _scanLineMin (scanLineMin),
  598. _scanLineMax (scanLineMax),
  599. _optimizationMode (optimizationMode)
  600. {
  601. /*
  602. //
  603. // indicates the optimised path has been taken
  604. //
  605. static bool could_optimise=false;
  606. if(could_optimise==false)
  607. {
  608. std::cerr << " optimised path\n";
  609. could_optimise=true;
  610. }
  611. */
  612. }
  613. LineBufferTaskIIF::~LineBufferTaskIIF ()
  614. {
  615. //
  616. // Signal that the line buffer is now free
  617. //
  618. _lineBuffer->post ();
  619. }
  620. // Return 0 if we are to skip because of sampling
  621. // channelBank is 0 for the first group of channels, 1 for the second
  622. template<typename TYPE>
  623. void LineBufferTaskIIF::getWritePointer
  624. (int y,
  625. unsigned short*& outWritePointerRight,
  626. size_t& outPixelsToCopySSE,
  627. size_t& outPixelsToCopyNormal,
  628. int channelBank
  629. ) const
  630. {
  631. // Channels are saved alphabetically, so the order is B G R.
  632. // The last slice (R) will give us the location of our write pointer.
  633. // The only slice that we support skipping is alpha, i.e. the first one.
  634. // This does not impact the write pointer or the pixels to copy at all.
  635. size_t nbSlicesInBank = _ifd->optimizationData.size();
  636. int sizeOfSingleValue = sizeof(TYPE);
  637. if(_ifd->optimizationData.size()>4)
  638. {
  639. // there are two banks - we only copy one at once
  640. nbSlicesInBank/=2;
  641. }
  642. size_t firstChannel = 0;
  643. if(channelBank==1)
  644. {
  645. firstChannel = _ifd->optimizationData.size()/2;
  646. }
  647. sliceOptimizationData& firstSlice = _ifd->optimizationData[firstChannel];
  648. if (modp (y, firstSlice.ySampling) != 0)
  649. {
  650. outPixelsToCopySSE = 0;
  651. outPixelsToCopyNormal = 0;
  652. outWritePointerRight = 0;
  653. }
  654. const char* linePtr1 = firstSlice.base +
  655. divp (y, firstSlice.ySampling) *
  656. firstSlice.yStride;
  657. int dMinX1 = divp (_ifd->minX, firstSlice.xSampling);
  658. int dMaxX1 = divp (_ifd->maxX, firstSlice.xSampling);
  659. // Construct the writePtr so that we start writing at
  660. // linePtr + Min offset in the line.
  661. outWritePointerRight = (unsigned short*)(linePtr1 +
  662. dMinX1 * firstSlice.xStride );
  663. size_t bytesToCopy = ((linePtr1 + dMaxX1 * firstSlice.xStride ) -
  664. (linePtr1 + dMinX1 * firstSlice.xStride )) + 2;
  665. size_t shortsToCopy = bytesToCopy / sizeOfSingleValue;
  666. size_t pixelsToCopy = (shortsToCopy / nbSlicesInBank ) + 1;
  667. // We only support writing to SSE if we have no pixels to copy normally
  668. outPixelsToCopySSE = pixelsToCopy / 8;
  669. outPixelsToCopyNormal = pixelsToCopy % 8;
  670. }
  671. template<typename TYPE>
  672. void LineBufferTaskIIF::getWritePointerStereo
  673. (int y,
  674. unsigned short*& outWritePointerRight,
  675. unsigned short*& outWritePointerLeft,
  676. size_t& outPixelsToCopySSE,
  677. size_t& outPixelsToCopyNormal) const
  678. {
  679. getWritePointer<TYPE>(y,outWritePointerRight,outPixelsToCopySSE,outPixelsToCopyNormal,0);
  680. if(outWritePointerRight)
  681. {
  682. getWritePointer<TYPE>(y,outWritePointerLeft,outPixelsToCopySSE,outPixelsToCopyNormal,1);
  683. }
  684. }
  685. void
  686. LineBufferTaskIIF::execute()
  687. {
  688. try
  689. {
  690. //
  691. // Uncompress the data, if necessary
  692. //
  693. if (_lineBuffer->uncompressedData == 0)
  694. {
  695. int uncompressedSize = 0;
  696. int maxY = min (_lineBuffer->maxY, _ifd->maxY);
  697. for (int i = _lineBuffer->minY - _ifd->minY;
  698. i <= maxY - _ifd->minY;
  699. ++i)
  700. {
  701. uncompressedSize += (int) _ifd->bytesPerLine[i];
  702. }
  703. if (_lineBuffer->compressor &&
  704. _lineBuffer->dataSize < uncompressedSize)
  705. {
  706. _lineBuffer->format = _lineBuffer->compressor->format();
  707. _lineBuffer->dataSize =
  708. _lineBuffer->compressor->uncompress (_lineBuffer->buffer,
  709. _lineBuffer->dataSize,
  710. _lineBuffer->minY,
  711. _lineBuffer->uncompressedData);
  712. }
  713. else
  714. {
  715. //
  716. // If the line is uncompressed, it's in XDR format,
  717. // regardless of the compressor's output format.
  718. //
  719. _lineBuffer->format = Compressor::XDR;
  720. _lineBuffer->uncompressedData = _lineBuffer->buffer;
  721. }
  722. }
  723. int yStart, yStop, dy;
  724. if (_ifd->lineOrder == INCREASING_Y)
  725. {
  726. yStart = _scanLineMin;
  727. yStop = _scanLineMax + 1;
  728. dy = 1;
  729. }
  730. else
  731. {
  732. yStart = _scanLineMax;
  733. yStop = _scanLineMin - 1;
  734. dy = -1;
  735. }
  736. for (int y = yStart; y != yStop; y += dy)
  737. {
  738. if (modp (y, _optimizationMode._ySampling) != 0)
  739. continue;
  740. //
  741. // Convert one scan line's worth of pixel data back
  742. // from the machine-independent representation, and
  743. // store the result in the frame buffer.
  744. //
  745. // Set the readPtr to read at the start of uncompressedData
  746. // but with an offet based on calculated array.
  747. // _ifd->offsetInLineBuffer contains offsets based on which
  748. // line we are currently processing.
  749. // Stride will be taken into consideration later.
  750. const char* readPtr = _lineBuffer->uncompressedData +
  751. _ifd->offsetInLineBuffer[y - _ifd->minY];
  752. size_t pixelsToCopySSE = 0;
  753. size_t pixelsToCopyNormal = 0;
  754. unsigned short* writePtrLeft = 0;
  755. unsigned short* writePtrRight = 0;
  756. size_t channels = _ifd->optimizationData.size();
  757. if(channels>4)
  758. {
  759. getWritePointerStereo<half>(y, writePtrRight, writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  760. }
  761. else
  762. {
  763. getWritePointer<half>(y, writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  764. }
  765. if (writePtrRight == 0 && pixelsToCopySSE == 0 && pixelsToCopyNormal == 0)
  766. {
  767. continue;
  768. }
  769. //
  770. // support reading up to eight channels
  771. //
  772. unsigned short* readPointers[8];
  773. for (size_t i = 0; i < channels ; ++i)
  774. {
  775. readPointers[i] = (unsigned short*)readPtr + (_ifd->optimizationData[i].offset * (pixelsToCopySSE * 8 + pixelsToCopyNormal));
  776. }
  777. //RGB only
  778. if(channels==3 || channels == 6 )
  779. {
  780. optimizedWriteToRGB(readPointers[0], readPointers[1], readPointers[2], writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  781. //stereo RGB
  782. if( channels == 6)
  783. {
  784. optimizedWriteToRGB(readPointers[3], readPointers[4], readPointers[5], writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  785. }
  786. //RGBA
  787. }else if(channels==4 || channels==8)
  788. {
  789. if(_ifd->optimizationData[3].fill)
  790. {
  791. optimizedWriteToRGBAFillA(readPointers[0], readPointers[1], readPointers[2], _ifd->optimizationData[3].fillValue.bits() , writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  792. }else{
  793. optimizedWriteToRGBA(readPointers[0], readPointers[1], readPointers[2], readPointers[3] , writePtrRight, pixelsToCopySSE, pixelsToCopyNormal);
  794. }
  795. //stereo RGBA
  796. if( channels == 8)
  797. {
  798. if(_ifd->optimizationData[7].fill)
  799. {
  800. optimizedWriteToRGBAFillA(readPointers[4], readPointers[5], readPointers[6], _ifd->optimizationData[7].fillValue.bits() , writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  801. }else{
  802. optimizedWriteToRGBA(readPointers[4], readPointers[5], readPointers[6], readPointers[7] , writePtrLeft, pixelsToCopySSE, pixelsToCopyNormal);
  803. }
  804. }
  805. }
  806. else {
  807. throw(IEX_NAMESPACE::LogicExc("IIF mode called with incorrect channel pattern"));
  808. }
  809. // If we are in NO_OPTIMIZATION mode, this class will never
  810. // get instantiated, so no need to check for it and duplicate
  811. // the code.
  812. }
  813. }
  814. catch (std::exception &e)
  815. {
  816. if (!_lineBuffer->hasException)
  817. {
  818. _lineBuffer->exception = e.what();
  819. _lineBuffer->hasException = true;
  820. }
  821. }
  822. catch (...)
  823. {
  824. if (!_lineBuffer->hasException)
  825. {
  826. _lineBuffer->exception = "unrecognized exception";
  827. _lineBuffer->hasException = true;
  828. }
  829. }
  830. }
  831. #endif
  832. Task *
  833. newLineBufferTask (TaskGroup *group,
  834. InputStreamMutex *streamData,
  835. ScanLineInputFile::Data *ifd,
  836. int number,
  837. int scanLineMin,
  838. int scanLineMax,
  839. OptimizationMode optimizationMode)
  840. {
  841. //
  842. // Wait for a line buffer to become available, fill the line
  843. // buffer with raw data from the file if necessary, and create
  844. // a new LineBufferTask whose execute() method will uncompress
  845. // the contents of the buffer and copy the pixels into the
  846. // frame buffer.
  847. //
  848. LineBuffer *lineBuffer = ifd->getLineBuffer (number);
  849. try
  850. {
  851. lineBuffer->wait ();
  852. if (lineBuffer->number != number)
  853. {
  854. lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
  855. lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
  856. lineBuffer->number = number;
  857. lineBuffer->uncompressedData = 0;
  858. readPixelData (streamData, ifd, lineBuffer->minY,
  859. lineBuffer->buffer,
  860. lineBuffer->dataSize);
  861. }
  862. }
  863. catch (std::exception &e)
  864. {
  865. if (!lineBuffer->hasException)
  866. {
  867. lineBuffer->exception = e.what();
  868. lineBuffer->hasException = true;
  869. }
  870. lineBuffer->number = -1;
  871. lineBuffer->post();
  872. throw;
  873. }
  874. catch (...)
  875. {
  876. //
  877. // Reading from the file caused an exception.
  878. // Signal that the line buffer is free, and
  879. // re-throw the exception.
  880. //
  881. lineBuffer->exception = "unrecognized exception";
  882. lineBuffer->hasException = true;
  883. lineBuffer->number = -1;
  884. lineBuffer->post();
  885. throw;
  886. }
  887. scanLineMin = max (lineBuffer->minY, scanLineMin);
  888. scanLineMax = min (lineBuffer->maxY, scanLineMax);
  889. Task* retTask = 0;
  890. #ifdef IMF_HAVE_SSE2
  891. if (optimizationMode._optimizable)
  892. {
  893. retTask = new LineBufferTaskIIF (group, ifd, lineBuffer,
  894. scanLineMin, scanLineMax,
  895. optimizationMode);
  896. }
  897. else
  898. #endif
  899. {
  900. retTask = new LineBufferTask (group, ifd, lineBuffer,
  901. scanLineMin, scanLineMax,
  902. optimizationMode);
  903. }
  904. return retTask;
  905. }
  906. } // namespace
  907. void ScanLineInputFile::initialize(const Header& header)
  908. {
  909. try
  910. {
  911. _data->header = header;
  912. _data->lineOrder = _data->header.lineOrder();
  913. const Box2i &dataWindow = _data->header.dataWindow();
  914. _data->minX = dataWindow.min.x;
  915. _data->maxX = dataWindow.max.x;
  916. _data->minY = dataWindow.min.y;
  917. _data->maxY = dataWindow.max.y;
  918. size_t maxBytesPerLine = bytesPerLineTable (_data->header,
  919. _data->bytesPerLine);
  920. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  921. {
  922. _data->lineBuffers[i] = new LineBuffer (newCompressor
  923. (_data->header.compression(),
  924. maxBytesPerLine,
  925. _data->header));
  926. }
  927. _data->linesInBuffer =
  928. numLinesInBuffer (_data->lineBuffers[0]->compressor);
  929. _data->lineBufferSize = maxBytesPerLine * _data->linesInBuffer;
  930. if (!_streamData->is->isMemoryMapped())
  931. {
  932. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  933. {
  934. _data->lineBuffers[i]->buffer = (char *) EXRAllocAligned(_data->lineBufferSize*sizeof(char),16);
  935. }
  936. }
  937. _data->nextLineBufferMinY = _data->minY - 1;
  938. offsetInLineBufferTable (_data->bytesPerLine,
  939. _data->linesInBuffer,
  940. _data->offsetInLineBuffer);
  941. int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
  942. _data->linesInBuffer) / _data->linesInBuffer;
  943. _data->lineOffsets.resize (lineOffsetSize);
  944. }
  945. catch (...)
  946. {
  947. delete _data;
  948. _data=NULL;
  949. throw;
  950. }
  951. }
  952. ScanLineInputFile::ScanLineInputFile(InputPartData* part)
  953. {
  954. if (part->header.type() != SCANLINEIMAGE)
  955. throw IEX_NAMESPACE::ArgExc("Can't build a ScanLineInputFile from a type-mismatched part.");
  956. _data = new Data(part->numThreads);
  957. _streamData = part->mutex;
  958. _data->memoryMapped = _streamData->is->isMemoryMapped();
  959. _data->version = part->version;
  960. initialize(part->header);
  961. _data->lineOffsets = part->chunkOffsets;
  962. _data->partNumber = part->partNumber;
  963. //
  964. // (TODO) change this code later.
  965. // The completeness of the file should be detected in MultiPartInputFile.
  966. //
  967. _data->fileIsComplete = true;
  968. }
  969. ScanLineInputFile::ScanLineInputFile
  970. (const Header &header,
  971. OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
  972. int numThreads)
  973. :
  974. _data (new Data (numThreads)),
  975. _streamData (new InputStreamMutex())
  976. {
  977. _streamData->is = is;
  978. _data->memoryMapped = is->isMemoryMapped();
  979. initialize(header);
  980. //
  981. // (TODO) this is nasty - we need a better way of working out what type of file has been used.
  982. // in any case I believe this constructor only gets used with single part files
  983. // and 'version' currently only tracks multipart state, so setting to 0 (not multipart) works for us
  984. //
  985. _data->version=0;
  986. readLineOffsets (*_streamData->is,
  987. _data->lineOrder,
  988. _data->lineOffsets,
  989. _data->fileIsComplete);
  990. }
  991. ScanLineInputFile::~ScanLineInputFile ()
  992. {
  993. if (!_data->memoryMapped)
  994. {
  995. for (size_t i = 0; i < _data->lineBuffers.size(); i++)
  996. {
  997. EXRFreeAligned(_data->lineBuffers[i]->buffer);
  998. }
  999. }
  1000. //
  1001. // ScanLineInputFile should never delete the stream,
  1002. // because it does not own the stream.
  1003. // We just delete the Mutex here.
  1004. //
  1005. if (_data->partNumber == -1)
  1006. delete _streamData;
  1007. delete _data;
  1008. }
  1009. const char *
  1010. ScanLineInputFile::fileName () const
  1011. {
  1012. return _streamData->is->fileName();
  1013. }
  1014. const Header &
  1015. ScanLineInputFile::header () const
  1016. {
  1017. return _data->header;
  1018. }
  1019. int
  1020. ScanLineInputFile::version () const
  1021. {
  1022. return _data->version;
  1023. }
  1024. namespace
  1025. {
  1026. // returns the optimization state for the given arrangement of frame bufers
  1027. // this assumes:
  1028. // both the file and framebuffer are half float data
  1029. // both the file and framebuffer have xSampling and ySampling=1
  1030. // entries in optData are sorted into their interleave order (i.e. by base address)
  1031. // These tests are done by SetFrameBuffer as it is building optData
  1032. //
  1033. OptimizationMode
  1034. detectOptimizationMode (const vector<sliceOptimizationData>& optData)
  1035. {
  1036. OptimizationMode w;
  1037. // need to be compiled with SSE optimisations: if not, just returns false
  1038. #ifdef IMF_HAVE_SSE2
  1039. // only handle reading 3,4,6 or 8 channels
  1040. switch(optData.size())
  1041. {
  1042. case 3 : break;
  1043. case 4 : break;
  1044. case 6 : break;
  1045. case 8 : break;
  1046. default :
  1047. return w;
  1048. }
  1049. //
  1050. // the point at which data switches between the primary and secondary bank
  1051. //
  1052. size_t bankSize = optData.size()>4 ? optData.size()/2 : optData.size();
  1053. for(size_t i=0;i<optData.size();i++)
  1054. {
  1055. const sliceOptimizationData& data = optData[i];
  1056. // can't fill anything other than channel 3 or channel 7
  1057. if(data.fill)
  1058. {
  1059. if(i!=3 && i!=7)
  1060. {
  1061. return w;
  1062. }
  1063. }
  1064. // cannot have gaps in the channel layout, so the stride must be (number of channels written in the bank)*2
  1065. if(data.xStride !=bankSize*2)
  1066. {
  1067. return w;
  1068. }
  1069. // each bank of channels must be channel interleaved: each channel base pointer must be (previous channel+2)
  1070. // this also means channel sampling pattern must be consistent, as must yStride
  1071. if(i!=0 && i!=bankSize)
  1072. {
  1073. if(data.base!=optData[i-1].base+2)
  1074. {
  1075. return w;
  1076. }
  1077. }
  1078. if(i!=0)
  1079. {
  1080. if(data.yStride!=optData[i-1].yStride)
  1081. {
  1082. return w;
  1083. }
  1084. }
  1085. }
  1086. w._ySampling=optData[0].ySampling;
  1087. w._optimizable=true;
  1088. #endif
  1089. return w;
  1090. }
  1091. } // Anonymous namespace
  1092. void
  1093. ScanLineInputFile::setFrameBuffer (const FrameBuffer &frameBuffer)
  1094. {
  1095. Lock lock (*_streamData);
  1096. const ChannelList &channels = _data->header.channels();
  1097. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  1098. j != frameBuffer.end();
  1099. ++j)
  1100. {
  1101. ChannelList::ConstIterator i = channels.find (j.name());
  1102. if (i == channels.end())
  1103. continue;
  1104. if (i.channel().xSampling != j.slice().xSampling ||
  1105. i.channel().ySampling != j.slice().ySampling)
  1106. THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
  1107. "of \"" << i.name() << "\" channel "
  1108. "of input file \"" << fileName() << "\" are "
  1109. "not compatible with the frame buffer's "
  1110. "subsampling factors.");
  1111. }
  1112. // optimization is possible if this is a little endian system
  1113. // and both inputs and outputs are half floats
  1114. //
  1115. bool optimizationPossible = true;
  1116. if (!GLOBAL_SYSTEM_LITTLE_ENDIAN)
  1117. {
  1118. optimizationPossible =false;
  1119. }
  1120. vector<sliceOptimizationData> optData;
  1121. //
  1122. // Initialize the slice table for readPixels().
  1123. //
  1124. vector<InSliceInfo> slices;
  1125. ChannelList::ConstIterator i = channels.begin();
  1126. // current offset of channel: pixel data starts at offset*width into the
  1127. // decompressed scanline buffer
  1128. size_t offset = 0;
  1129. for (FrameBuffer::ConstIterator j = frameBuffer.begin();
  1130. j != frameBuffer.end();
  1131. ++j)
  1132. {
  1133. while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
  1134. {
  1135. //
  1136. // Channel i is present in the file but not
  1137. // in the frame buffer; data for channel i
  1138. // will be skipped during readPixels().
  1139. //
  1140. slices.push_back (InSliceInfo (i.channel().type,
  1141. i.channel().type,
  1142. 0, // base
  1143. 0, // xStride
  1144. 0, // yStride
  1145. i.channel().xSampling,
  1146. i.channel().ySampling,
  1147. false, // fill
  1148. true, // skip
  1149. 0.0)); // fillValue
  1150. switch(i.channel().type)
  1151. {
  1152. case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
  1153. offset++;
  1154. break;
  1155. case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
  1156. offset+=2;
  1157. break;
  1158. case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
  1159. offset+=2;
  1160. break;
  1161. }
  1162. ++i;
  1163. }
  1164. bool fill = false;
  1165. if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
  1166. {
  1167. //
  1168. // Channel i is present in the frame buffer, but not in the file.
  1169. // In the frame buffer, slice j will be filled with a default value.
  1170. //
  1171. fill = true;
  1172. }
  1173. slices.push_back (InSliceInfo (j.slice().type,
  1174. fill? j.slice().type:
  1175. i.channel().type,
  1176. j.slice().base,
  1177. j.slice().xStride,
  1178. j.slice().yStride,
  1179. j.slice().xSampling,
  1180. j.slice().ySampling,
  1181. fill,
  1182. false, // skip
  1183. j.slice().fillValue));
  1184. if(!fill && i.channel().type!=OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
  1185. {
  1186. optimizationPossible = false;
  1187. }
  1188. if(j.slice().type != OPENEXR_IMF_INTERNAL_NAMESPACE::HALF)
  1189. {
  1190. optimizationPossible = false;
  1191. }
  1192. if(j.slice().xSampling!=1 || j.slice().ySampling!=1)
  1193. {
  1194. optimizationPossible = false;
  1195. }
  1196. if(optimizationPossible)
  1197. {
  1198. sliceOptimizationData dat;
  1199. dat.base = j.slice().base;
  1200. dat.fill = fill;
  1201. dat.fillValue = j.slice().fillValue;
  1202. dat.offset = offset;
  1203. dat.xStride = j.slice().xStride;
  1204. dat.yStride = j.slice().yStride;
  1205. dat.xSampling = j.slice().xSampling;
  1206. dat.ySampling = j.slice().ySampling;
  1207. optData.push_back(dat);
  1208. }
  1209. if(!fill)
  1210. {
  1211. switch(i.channel().type)
  1212. {
  1213. case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF :
  1214. offset++;
  1215. break;
  1216. case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
  1217. offset+=2;
  1218. break;
  1219. case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT :
  1220. offset+=2;
  1221. break;
  1222. }
  1223. }
  1224. if (i != channels.end() && !fill)
  1225. ++i;
  1226. }
  1227. if(optimizationPossible)
  1228. {
  1229. //
  1230. // check optimisibility
  1231. // based on channel ordering and fill channel positions
  1232. //
  1233. sort(optData.begin(),optData.end());
  1234. _data->optimizationMode = detectOptimizationMode(optData);
  1235. }
  1236. if(!optimizationPossible || _data->optimizationMode._optimizable==false)
  1237. {
  1238. optData = vector<sliceOptimizationData>();
  1239. _data->optimizationMode._optimizable=false;
  1240. }
  1241. //
  1242. // Store the new frame buffer.
  1243. //
  1244. _data->frameBuffer = frameBuffer;
  1245. _data->slices = slices;
  1246. _data->optimizationData = optData;
  1247. }
  1248. const FrameBuffer &
  1249. ScanLineInputFile::frameBuffer () const
  1250. {
  1251. Lock lock (*_streamData);
  1252. return _data->frameBuffer;
  1253. }
  1254. bool
  1255. ScanLineInputFile::isComplete () const
  1256. {
  1257. return _data->fileIsComplete;
  1258. }
  1259. bool ScanLineInputFile::isOptimizationEnabled() const
  1260. {
  1261. if (_data->slices.size() == 0)
  1262. throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
  1263. "as pixel data destination.");
  1264. return _data->optimizationMode._optimizable;
  1265. }
  1266. void
  1267. ScanLineInputFile::readPixels (int scanLine1, int scanLine2)
  1268. {
  1269. try
  1270. {
  1271. Lock lock (*_streamData);
  1272. if (_data->slices.size() == 0)
  1273. throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
  1274. "as pixel data destination.");
  1275. int scanLineMin = min (scanLine1, scanLine2);
  1276. int scanLineMax = max (scanLine1, scanLine2);
  1277. if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
  1278. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
  1279. "the image file's data window.");
  1280. //
  1281. // We impose a numbering scheme on the lineBuffers where the first
  1282. // scanline is contained in lineBuffer 1.
  1283. //
  1284. // Determine the first and last lineBuffer numbers in this scanline
  1285. // range. We always attempt to read the scanlines in the order that
  1286. // they are stored in the file.
  1287. //
  1288. int start, stop, dl;
  1289. if (_data->lineOrder == INCREASING_Y)
  1290. {
  1291. start = (scanLineMin - _data->minY) / _data->linesInBuffer;
  1292. stop = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
  1293. dl = 1;
  1294. }
  1295. else
  1296. {
  1297. start = (scanLineMax - _data->minY) / _data->linesInBuffer;
  1298. stop = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
  1299. dl = -1;
  1300. }
  1301. //
  1302. // Create a task group for all line buffer tasks. When the
  1303. // task group goes out of scope, the destructor waits until
  1304. // all tasks are complete.
  1305. //
  1306. {
  1307. TaskGroup taskGroup;
  1308. //
  1309. // Add the line buffer tasks.
  1310. //
  1311. // The tasks will execute in the order that they are created
  1312. // because we lock the line buffers during construction and the
  1313. // constructors are called by the main thread. Hence, in order
  1314. // for a successive task to execute the previous task which
  1315. // used that line buffer must have completed already.
  1316. //
  1317. for (int l = start; l != stop; l += dl)
  1318. {
  1319. ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
  1320. _streamData,
  1321. _data, l,
  1322. scanLineMin,
  1323. scanLineMax,
  1324. _data->optimizationMode));
  1325. }
  1326. //
  1327. // finish all tasks
  1328. //
  1329. }
  1330. //
  1331. // Exeption handling:
  1332. //
  1333. // LineBufferTask::execute() may have encountered exceptions, but
  1334. // those exceptions occurred in another thread, not in the thread
  1335. // that is executing this call to ScanLineInputFile::readPixels().
  1336. // LineBufferTask::execute() has caught all exceptions and stored
  1337. // the exceptions' what() strings in the line buffers.
  1338. // Now we check if any line buffer contains a stored exception; if
  1339. // this is the case then we re-throw the exception in this thread.
  1340. // (It is possible that multiple line buffers contain stored
  1341. // exceptions. We re-throw the first exception we find and
  1342. // ignore all others.)
  1343. //
  1344. const string *exception = 0;
  1345. for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
  1346. {
  1347. LineBuffer *lineBuffer = _data->lineBuffers[i];
  1348. if (lineBuffer->hasException && !exception)
  1349. exception = &lineBuffer->exception;
  1350. lineBuffer->hasException = false;
  1351. }
  1352. if (exception)
  1353. throw IEX_NAMESPACE::IoExc (*exception);
  1354. }
  1355. catch (IEX_NAMESPACE::BaseExc &e)
  1356. {
  1357. REPLACE_EXC (e, "Error reading pixel data from image "
  1358. "file \"" << fileName() << "\". " << e.what());
  1359. throw;
  1360. }
  1361. }
  1362. void
  1363. ScanLineInputFile::readPixels (int scanLine)
  1364. {
  1365. readPixels (scanLine, scanLine);
  1366. }
  1367. void
  1368. ScanLineInputFile::rawPixelData (int firstScanLine,
  1369. const char *&pixelData,
  1370. int &pixelDataSize)
  1371. {
  1372. try
  1373. {
  1374. Lock lock (*_streamData);
  1375. if (firstScanLine < _data->minY || firstScanLine > _data->maxY)
  1376. {
  1377. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
  1378. "the image file's data window.");
  1379. }
  1380. int minY = lineBufferMinY
  1381. (firstScanLine, _data->minY, _data->linesInBuffer);
  1382. readPixelData
  1383. (_streamData, _data, minY, _data->lineBuffers[0]->buffer, pixelDataSize);
  1384. pixelData = _data->lineBuffers[0]->buffer;
  1385. }
  1386. catch (IEX_NAMESPACE::BaseExc &e)
  1387. {
  1388. REPLACE_EXC (e, "Error reading pixel data from image "
  1389. "file \"" << fileName() << "\". " << e.what());
  1390. throw;
  1391. }
  1392. }
  1393. void ScanLineInputFile::rawPixelDataToBuffer(int scanLine,
  1394. char *pixelData,
  1395. int &pixelDataSize) const
  1396. {
  1397. if (_data->memoryMapped) {
  1398. throw IEX_NAMESPACE::ArgExc ("Reading raw pixel data to a buffer "
  1399. "is not supported for memory mapped "
  1400. "streams." );
  1401. }
  1402. try
  1403. {
  1404. Lock lock (*_streamData);
  1405. if (scanLine < _data->minY || scanLine > _data->maxY)
  1406. {
  1407. throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
  1408. "the image file's data window.");
  1409. }
  1410. readPixelData
  1411. (_streamData, _data, scanLine, pixelData, pixelDataSize);
  1412. }
  1413. catch (IEX_NAMESPACE::BaseExc &e)
  1414. {
  1415. REPLACE_EXC (e, "Error reading pixel data from image "
  1416. "file \"" << fileName() << "\". " << e.what());
  1417. throw;
  1418. }
  1419. }
  1420. OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT