Blame IlmImf/ImfDeepScanLineInputFile.cpp

Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
//
Packit 0d464f
// Copyright (c) 2011, Industrial Light & Magic, a division of Lucas
Packit 0d464f
// Digital Ltd. LLC
Packit 0d464f
//
Packit 0d464f
// All rights reserved.
Packit 0d464f
//
Packit 0d464f
// Redistribution and use in source and binary forms, with or without
Packit 0d464f
// modification, are permitted provided that the following conditions are
Packit 0d464f
// met:
Packit 0d464f
// *       Redistributions of source code must retain the above copyright
Packit 0d464f
// notice, this list of conditions and the following disclaimer.
Packit 0d464f
// *       Redistributions in binary form must reproduce the above
Packit 0d464f
// copyright notice, this list of conditions and the following disclaimer
Packit 0d464f
// in the documentation and/or other materials provided with the
Packit 0d464f
// distribution.
Packit 0d464f
// *       Neither the name of Industrial Light & Magic nor the names of
Packit 0d464f
// its contributors may be used to endorse or promote products derived
Packit 0d464f
// from this software without specific prior written permission.
Packit 0d464f
//
Packit 0d464f
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
Packit 0d464f
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
Packit 0d464f
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
Packit 0d464f
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
Packit 0d464f
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
Packit 0d464f
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
Packit 0d464f
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
Packit 0d464f
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
Packit 0d464f
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
Packit 0d464f
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Packit 0d464f
//
Packit 0d464f
///////////////////////////////////////////////////////////////////////////
Packit 0d464f
Packit 0d464f
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
//
Packit 0d464f
//      class DeepScanLineInputFile
Packit 0d464f
//
Packit 0d464f
//-----------------------------------------------------------------------------
Packit 0d464f
Packit 0d464f
#include <ImfDeepScanLineInputFile.h>
Packit 0d464f
#include <ImfChannelList.h>
Packit 0d464f
#include <ImfMisc.h>
Packit 0d464f
#include <ImfStdIO.h>
Packit 0d464f
#include <ImfCompressor.h>
Packit 0d464f
#include <ImfXdr.h>
Packit 0d464f
#include <ImfConvert.h>
Packit 0d464f
#include <ImfThreading.h>
Packit 0d464f
#include <ImfPartType.h>
Packit 0d464f
#include <ImfVersion.h>
Packit 0d464f
#include "ImfMultiPartInputFile.h"
Packit 0d464f
#include "ImfDeepFrameBuffer.h"
Packit 0d464f
#include "ImfInputStreamMutex.h"
Packit 0d464f
#include "ImfInputPartData.h"
Packit 0d464f
Packit 0d464f
Packit 0d464f
#include "ImathBox.h"
Packit 0d464f
#include "ImathFun.h"
Packit 0d464f
Packit 0d464f
Packit 0d464f
#include "IlmThreadPool.h"
Packit 0d464f
#include "IlmThreadSemaphore.h"
Packit 0d464f
#include "IlmThreadMutex.h"
Packit 0d464f
Packit 0d464f
#include "Iex.h"
Packit 0d464f
Packit 0d464f
#include <string>
Packit 0d464f
#include <vector>
Packit 0d464f
#include <assert.h>
Packit 0d464f
#include <limits>
Packit 0d464f
#include <algorithm>
Packit 0d464f
Packit 0d464f
Packit 0d464f
#include "ImfNamespace.h"
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_ENTER
Packit 0d464f
Packit 0d464f
using IMATH_NAMESPACE::Box2i;
Packit 0d464f
using IMATH_NAMESPACE::divp;
Packit 0d464f
using IMATH_NAMESPACE::modp;
Packit 0d464f
using std::string;
Packit 0d464f
using std::vector;
Packit 0d464f
using std::ifstream;
Packit 0d464f
using std::min;
Packit 0d464f
using std::max;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Mutex;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Lock;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Semaphore;
Packit 0d464f
using ILMTHREAD_NAMESPACE::Task;
Packit 0d464f
using ILMTHREAD_NAMESPACE::TaskGroup;
Packit 0d464f
using ILMTHREAD_NAMESPACE::ThreadPool;
Packit 0d464f
Packit 0d464f
namespace {
Packit 0d464f
Packit 0d464f
struct InSliceInfo
Packit 0d464f
{
Packit 0d464f
    PixelType           typeInFrameBuffer;
Packit 0d464f
    PixelType           typeInFile;
Packit 0d464f
    char *              base;
Packit 0d464f
    char*               pointerArrayBase;
Packit 0d464f
    size_t              xPointerStride;
Packit 0d464f
    size_t              yPointerStride;
Packit 0d464f
    size_t              sampleStride;
Packit 0d464f
    int                 xSampling;
Packit 0d464f
    int                 ySampling;
Packit 0d464f
    bool                fill;
Packit 0d464f
    bool                skip;
Packit 0d464f
    double              fillValue;
Packit 0d464f
Packit 0d464f
    InSliceInfo (PixelType typeInFrameBuffer = HALF,
Packit 0d464f
                 char * base = NULL,
Packit 0d464f
                 PixelType typeInFile = HALF,
Packit 0d464f
                 size_t xPointerStride = 0,
Packit 0d464f
                 size_t yPointerStride = 0,
Packit 0d464f
                 size_t sampleStride = 0,
Packit 0d464f
                 int xSampling = 1,
Packit 0d464f
                 int ySampling = 1,
Packit 0d464f
                 bool fill = false,
Packit 0d464f
                 bool skip = false,
Packit 0d464f
                 double fillValue = 0.0);
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
InSliceInfo::InSliceInfo (PixelType tifb,
Packit 0d464f
                          char * b,
Packit 0d464f
                          PixelType tifl,
Packit 0d464f
                          size_t xpst,
Packit 0d464f
                          size_t ypst,
Packit 0d464f
                          size_t spst,
Packit 0d464f
                          int xsm, int ysm,
Packit 0d464f
                          bool f, bool s,
Packit 0d464f
                          double fv)
Packit 0d464f
:
Packit 0d464f
    typeInFrameBuffer (tifb),
Packit 0d464f
    typeInFile (tifl),
Packit 0d464f
    base(b),
Packit 0d464f
    xPointerStride (xpst),
Packit 0d464f
    yPointerStride (ypst),
Packit 0d464f
    sampleStride (spst),
Packit 0d464f
    xSampling (xsm),
Packit 0d464f
    ySampling (ysm),
Packit 0d464f
    fill (f),
Packit 0d464f
    skip (s),
Packit 0d464f
    fillValue (fv)
Packit 0d464f
{
Packit 0d464f
    // empty
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct LineBuffer
Packit 0d464f
{
Packit 0d464f
    const char *        uncompressedData;
Packit 0d464f
    char *              buffer;
Packit 0d464f
    Int64               packedDataSize;
Packit 0d464f
    Int64               unpackedDataSize;
Packit 0d464f
Packit 0d464f
    int                 minY;
Packit 0d464f
    int                 maxY;
Packit 0d464f
    Compressor *        compressor;
Packit 0d464f
    Compressor::Format  format;
Packit 0d464f
    int                 number;
Packit 0d464f
    bool                hasException;
Packit 0d464f
    string              exception;
Packit 0d464f
Packit 0d464f
    LineBuffer ();
Packit 0d464f
    ~LineBuffer ();
Packit 0d464f
Packit 0d464f
    inline void         wait () {_sem.wait();}
Packit 0d464f
    inline void         post () {_sem.post();}
Packit 0d464f
Packit 0d464f
  private:
Packit 0d464f
Packit 0d464f
    Semaphore           _sem;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
LineBuffer::LineBuffer ():
Packit 0d464f
    uncompressedData (0),
Packit 0d464f
    buffer (0),
Packit 0d464f
    packedDataSize (0),
Packit 0d464f
    compressor (0),
Packit 0d464f
    format (defaultFormat(compressor)),
Packit 0d464f
    number (-1),
Packit 0d464f
    hasException (false),
Packit 0d464f
    exception (),
Packit 0d464f
    _sem (1)
Packit 0d464f
{
Packit 0d464f
    // empty
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LineBuffer::~LineBuffer ()
Packit 0d464f
{
Packit 0d464f
    if (compressor != 0)
Packit 0d464f
        delete compressor;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
struct DeepScanLineInputFile::Data: public Mutex
Packit 0d464f
{
Packit 0d464f
    Header                      header;             // the image header
Packit 0d464f
    int                         version;            // file's version
Packit 0d464f
    DeepFrameBuffer             frameBuffer;        // framebuffer to write into
Packit 0d464f
    LineOrder                   lineOrder;          // order of the scanlines in file
Packit 0d464f
    int                         minX;               // data window's min x coord
Packit 0d464f
    int                         maxX;               // data window's max x coord
Packit 0d464f
    int                         minY;               // data window's min y coord
Packit 0d464f
    int                         maxY;               // data window's max x coord
Packit 0d464f
    vector<Int64>               lineOffsets;        // stores offsets in file for
Packit 0d464f
                                                    // each line
Packit 0d464f
    bool                        fileIsComplete;     // True if no scanlines are missing
Packit 0d464f
                                                    // in the file
Packit 0d464f
    int                         nextLineBufferMinY; // minimum y of the next linebuffer
Packit 0d464f
    vector<size_t>              bytesPerLine;       // combined size of a line over all
Packit 0d464f
                                                    // channels
Packit 0d464f
    vector<size_t>              offsetInLineBuffer; // offset for each scanline in its
Packit 0d464f
                                                    // linebuffer
Packit 0d464f
    vector<InSliceInfo*>        slices;             // info about channels in file
Packit 0d464f
Packit 0d464f
    vector<LineBuffer*>         lineBuffers;        // each holds one line buffer
Packit 0d464f
    int                         linesInBuffer;      // number of scanlines each buffer
Packit 0d464f
                                                    // holds
Packit 0d464f
    int                         partNumber;         // part number
Packit 0d464f
    int                         numThreads;         // number of threads
Packit 0d464f
    
Packit 0d464f
    bool                        multiPartBackwardSupport;       // if we are reading a multipart file using single file API
Packit 0d464f
    MultiPartInputFile*         multiPartFile;      // for multipart files opened as single part
Packit 0d464f
    bool                        memoryMapped;       // if the stream is memory mapped
Packit 0d464f
Packit 0d464f
    Array2D<unsigned int>       sampleCount;        // the number of samples
Packit 0d464f
                                                    // in each pixel
Packit 0d464f
Packit 0d464f
    Array<unsigned int>         lineSampleCount;    // the number of samples
Packit 0d464f
                                                    // in each line
Packit 0d464f
Packit 0d464f
    Array<bool>                 gotSampleCount;     // for each scanline, indicating if
Packit 0d464f
                                                    // we have got its sample count table
Packit 0d464f
Packit 0d464f
    char*                       sampleCountSliceBase; // pointer to the start of
Packit 0d464f
                                                      // the sample count array
Packit 0d464f
    int                         sampleCountXStride; // x stride of the sample count array
Packit 0d464f
    int                         sampleCountYStride; // y stride of the sample count array
Packit 0d464f
    bool                        frameBufferValid;   // set by setFrameBuffer: excepts if readPixelSampleCounts if false
Packit 0d464f
Packit 0d464f
    Array<char>                 sampleCountTableBuffer;
Packit 0d464f
                                                    // the buffer for sample count table
Packit 0d464f
Packit 0d464f
    Compressor*                 sampleCountTableComp;
Packit 0d464f
                                                    // the decompressor for sample count table
Packit 0d464f
Packit 0d464f
    int                         combinedSampleSize; // total size of all channels combined: used to sanity check sample table size
Packit 0d464f
Packit 0d464f
    int                         maxSampleCountTableSize;
Packit 0d464f
                                                    // the max size in bytes for a pixel
Packit 0d464f
                                                    // sample count table
Packit 0d464f
    InputStreamMutex*   _streamData;
Packit 0d464f
    bool                _deleteStream;
Packit 0d464f
                                                    
Packit 0d464f
Packit 0d464f
    Data (int numThreads);
Packit 0d464f
    ~Data ();
Packit 0d464f
Packit 0d464f
    inline LineBuffer * getLineBuffer (int number); // hash function from line
Packit 0d464f
                                                    // buffer indices into our
Packit 0d464f
                                                    // vector of line buffers
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepScanLineInputFile::Data::Data (int numThreads):
Packit 0d464f
        partNumber(-1),
Packit 0d464f
        numThreads(numThreads),
Packit 0d464f
        multiPartBackwardSupport(false),
Packit 0d464f
        multiPartFile(NULL),
Packit 0d464f
        memoryMapped(false),
Packit 0d464f
        frameBufferValid(false),
Packit 0d464f
        _streamData(NULL),
Packit 0d464f
        _deleteStream(false)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // We need at least one lineBuffer, but if threading is used,
Packit 0d464f
    // to keep n threads busy we need 2*n lineBuffers
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    lineBuffers.resize (max (1, 2 * numThreads));
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < lineBuffers.size(); i++)
Packit 0d464f
        lineBuffers[i] = 0;
Packit 0d464f
Packit 0d464f
    sampleCountTableComp = 0;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepScanLineInputFile::Data::~Data ()
Packit 0d464f
{
Packit 0d464f
    for (size_t i = 0; i < lineBuffers.size(); i++)
Packit 0d464f
        if (lineBuffers[i] != 0)
Packit 0d464f
            delete lineBuffers[i];
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < slices.size(); i++)
Packit 0d464f
        delete slices[i];
Packit 0d464f
Packit 0d464f
    if (sampleCountTableComp != 0)
Packit 0d464f
        delete sampleCountTableComp;
Packit 0d464f
    
Packit 0d464f
    if (multiPartBackwardSupport)
Packit 0d464f
        delete multiPartFile;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
inline LineBuffer *
Packit 0d464f
DeepScanLineInputFile::Data::getLineBuffer (int lineBufferNumber)
Packit 0d464f
{
Packit 0d464f
    return lineBuffers[lineBufferNumber % lineBuffers.size()];
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
namespace {
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
reconstructLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
Packit 0d464f
                        LineOrder lineOrder,
Packit 0d464f
                        vector<Int64> &lineOffsets)
Packit 0d464f
{
Packit 0d464f
    Int64 position = is.tellg();
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        for (unsigned int i = 0; i < lineOffsets.size(); i++)
Packit 0d464f
        {
Packit 0d464f
            Int64 lineOffset = is.tellg();
Packit 0d464f
Packit 0d464f
            int y;
Packit 0d464f
            OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, y);
Packit 0d464f
            
Packit 0d464f
            Int64 packed_offset;
Packit 0d464f
            Int64 packed_sample;
Packit 0d464f
            OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_offset);
Packit 0d464f
            OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, packed_sample);
Packit 0d464f
            //next is unpacked sample table size - skip this too
Packit 0d464f
            Xdr::skip <StreamIO> (is, packed_offset+packed_sample+8);
Packit 0d464f
Packit 0d464f
            if (lineOrder == INCREASING_Y)
Packit 0d464f
                lineOffsets[i] = lineOffset;
Packit 0d464f
            else
Packit 0d464f
                lineOffsets[lineOffsets.size() - i - 1] = lineOffset;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Suppress all exceptions.  This functions is
Packit 0d464f
        // called only to reconstruct the line offset
Packit 0d464f
        // table for incomplete files, and exceptions
Packit 0d464f
        // are likely.
Packit 0d464f
        //
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    is.clear();
Packit 0d464f
    is.seekg (position);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
readLineOffsets (OPENEXR_IMF_INTERNAL_NAMESPACE::IStream &is,
Packit 0d464f
                 LineOrder lineOrder,
Packit 0d464f
                 vector<Int64> &lineOffsets,
Packit 0d464f
                 bool &complete)
Packit 0d464f
{
Packit 0d464f
    for (unsigned int i = 0; i < lineOffsets.size(); i++)
Packit 0d464f
    {
Packit 0d464f
        OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (is, lineOffsets[i]);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    complete = true;
Packit 0d464f
Packit 0d464f
    for (unsigned int i = 0; i < lineOffsets.size(); i++)
Packit 0d464f
    {
Packit 0d464f
        if (lineOffsets[i] <= 0)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Invalid data in the line offset table mean that
Packit 0d464f
            // the file is probably incomplete (the table is
Packit 0d464f
            // the last thing written to the file).  Either
Packit 0d464f
            // some process is still busy writing the file,
Packit 0d464f
            // or writing the file was aborted.
Packit 0d464f
            //
Packit 0d464f
            // We should still be able to read the existing
Packit 0d464f
            // parts of the file.  In order to do this, we
Packit 0d464f
            // have to make a sequential scan over the scan
Packit 0d464f
            // line data to reconstruct the line offset table.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            complete = false;
Packit 0d464f
            reconstructLineOffsets (is, lineOrder, lineOffsets);
Packit 0d464f
            break;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
readPixelData (InputStreamMutex *streamData,
Packit 0d464f
               DeepScanLineInputFile::Data *ifd,
Packit 0d464f
               int minY,
Packit 0d464f
               char *&buffer,
Packit 0d464f
               Int64 &packedDataSize,
Packit 0d464f
               Int64 &unpackedDataSize)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Read a single line buffer from the input file.
Packit 0d464f
    //
Packit 0d464f
    // If the input file is not memory-mapped, we copy the pixel data into
Packit 0d464f
    // into the array pointed to by buffer.  If the file is memory-mapped,
Packit 0d464f
    // then we change where buffer points to instead of writing into the
Packit 0d464f
    // array (hence buffer needs to be a reference to a char *).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int lineBufferNumber = (minY - ifd->minY) / ifd->linesInBuffer;
Packit 0d464f
Packit 0d464f
    Int64 lineOffset = ifd->lineOffsets[lineBufferNumber];
Packit 0d464f
Packit 0d464f
    if (lineOffset == 0)
Packit 0d464f
        THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Seek to the start of the scan line in the file,
Packit 0d464f
    // if necessary.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (!isMultiPart(ifd->version))
Packit 0d464f
    {
Packit 0d464f
        if (ifd->nextLineBufferMinY != minY)
Packit 0d464f
            streamData->is->seekg (lineOffset);
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // In a multi-part file, the file pointer may have been moved by
Packit 0d464f
        // other parts, so we have to ask tellg() where we are.
Packit 0d464f
        //
Packit 0d464f
        if (streamData->is->tellg() != ifd->lineOffsets[lineBufferNumber])
Packit 0d464f
            streamData->is->seekg (lineOffset);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the data block's header.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int yInFile;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the part number when we are dealing with a multi-part file.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (isMultiPart(ifd->version))
Packit 0d464f
    {
Packit 0d464f
        int partNumber;
Packit 0d464f
        OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
Packit 0d464f
        if (partNumber != ifd->partNumber)
Packit 0d464f
        {
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
Packit 0d464f
                   << ", should be " << ifd->partNumber << ".");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, yInFile);
Packit 0d464f
Packit 0d464f
    if (yInFile != minY)
Packit 0d464f
        throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
Packit 0d464f
Packit 0d464f
    Int64 sampleCountTableSize;
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, sampleCountTableSize);
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, packedDataSize);
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, unpackedDataSize);
Packit 0d464f
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // We make a check on the data size requirements here.
Packit 0d464f
    // Whilst we wish to store 64bit sizes on disk, not all the compressors
Packit 0d464f
    // have been made to work with such data sizes and are still limited to
Packit 0d464f
    // using signed 32 bit (int) for the data size. As such, this version
Packit 0d464f
    // insists that we validate that the data size does not exceed the data
Packit 0d464f
    // type max limit.
Packit 0d464f
    // @TODO refactor the compressor code to ensure full 64-bit support.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int compressorMaxDataSize = std::numeric_limits<int>::max();
Packit 0d464f
    if (packedDataSize   > Int64(compressorMaxDataSize) ||
Packit 0d464f
        unpackedDataSize > Int64(compressorMaxDataSize))
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not support "
Packit 0d464f
              << "the allocation of data with size  > " << compressorMaxDataSize
Packit 0d464f
              << " file unpacked size :" << unpackedDataSize
Packit 0d464f
              << " file packed size   :" << packedDataSize << ".\n");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Skip the pixel sample count table because we have read this data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    Xdr::skip <StreamIO> (*streamData->is, sampleCountTableSize);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Read the pixel data.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (streamData->is->isMemoryMapped ())
Packit 0d464f
        buffer = streamData->is->readMemoryMapped (packedDataSize);
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        // (TODO) check if the packed data size is too big?
Packit 0d464f
        // (TODO) better memory management. Don't delete buffer all the time.
Packit 0d464f
        if (buffer != 0) delete[] buffer;
Packit 0d464f
        buffer = new char[packedDataSize];
Packit 0d464f
        streamData->is->read (buffer, packedDataSize);
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Keep track of which scan line is the next one in
Packit 0d464f
    // the file, so that we can avoid redundant seekg()
Packit 0d464f
    // operations (seekg() can be fairly expensive).
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (ifd->lineOrder == INCREASING_Y)
Packit 0d464f
        ifd->nextLineBufferMinY = minY + ifd->linesInBuffer;
Packit 0d464f
    else
Packit 0d464f
        ifd->nextLineBufferMinY = minY - ifd->linesInBuffer;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
//
Packit 0d464f
// A LineBufferTask encapsulates the task uncompressing a set of
Packit 0d464f
// scanlines (line buffer) and copying them into the frame buffer.
Packit 0d464f
//
Packit 0d464f
Packit 0d464f
class LineBufferTask : public Task
Packit 0d464f
{
Packit 0d464f
  public:
Packit 0d464f
Packit 0d464f
    LineBufferTask (TaskGroup *group,
Packit 0d464f
                    DeepScanLineInputFile::Data *ifd,
Packit 0d464f
                    LineBuffer *lineBuffer,
Packit 0d464f
                    int scanLineMin,
Packit 0d464f
                    int scanLineMax);
Packit 0d464f
Packit 0d464f
    virtual ~LineBufferTask ();
Packit 0d464f
Packit 0d464f
    virtual void                execute ();
Packit 0d464f
Packit 0d464f
  private:
Packit 0d464f
Packit 0d464f
    DeepScanLineInputFile::Data *   _ifd;
Packit 0d464f
    LineBuffer *                _lineBuffer;
Packit 0d464f
    int                         _scanLineMin;
Packit 0d464f
    int                         _scanLineMax;
Packit 0d464f
};
Packit 0d464f
Packit 0d464f
Packit 0d464f
LineBufferTask::LineBufferTask
Packit 0d464f
    (TaskGroup *group,
Packit 0d464f
     DeepScanLineInputFile::Data *ifd,
Packit 0d464f
     LineBuffer *lineBuffer,
Packit 0d464f
     int scanLineMin,
Packit 0d464f
     int scanLineMax)
Packit 0d464f
:
Packit 0d464f
    Task (group),
Packit 0d464f
    _ifd (ifd),
Packit 0d464f
    _lineBuffer (lineBuffer),
Packit 0d464f
    _scanLineMin (scanLineMin),
Packit 0d464f
    _scanLineMax (scanLineMax)
Packit 0d464f
{
Packit 0d464f
    // empty
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LineBufferTask::~LineBufferTask ()
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Signal that the line buffer is now free
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _lineBuffer->post ();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
LineBufferTask::execute ()
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Uncompress the data, if necessary
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (_lineBuffer->uncompressedData == 0)
Packit 0d464f
        {
Packit 0d464f
            Int64 uncompressedSize = 0;
Packit 0d464f
            int maxY = min (_lineBuffer->maxY, _ifd->maxY);
Packit 0d464f
Packit 0d464f
            for (int i = _lineBuffer->minY - _ifd->minY;
Packit 0d464f
                 i <= maxY - _ifd->minY;
Packit 0d464f
                 ++i)
Packit 0d464f
            {
Packit 0d464f
                uncompressedSize += (int) _ifd->bytesPerLine[i];
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Create the compressor everytime when we want to use it,
Packit 0d464f
            // because we don't know maxBytesPerLine beforehand.
Packit 0d464f
            // (TODO) optimize this. don't do this every time.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            if (_lineBuffer->compressor != 0)
Packit 0d464f
                delete _lineBuffer->compressor;
Packit 0d464f
            Int64 maxBytesPerLine = 0;
Packit 0d464f
            for (int i = _lineBuffer->minY - _ifd->minY;
Packit 0d464f
                 i <= maxY - _ifd->minY;
Packit 0d464f
                 ++i)
Packit 0d464f
            {
Packit 0d464f
                if (_ifd->bytesPerLine[i] > maxBytesPerLine)
Packit 0d464f
                    maxBytesPerLine = _ifd->bytesPerLine[i];
Packit 0d464f
            }
Packit 0d464f
            _lineBuffer->compressor = newCompressor(_ifd->header.compression(),
Packit 0d464f
                                                    maxBytesPerLine,
Packit 0d464f
                                                    _ifd->header);
Packit 0d464f
Packit 0d464f
            if (_lineBuffer->compressor &&
Packit 0d464f
                _lineBuffer->packedDataSize < uncompressedSize)
Packit 0d464f
            {
Packit 0d464f
                _lineBuffer->format = _lineBuffer->compressor->format();
Packit 0d464f
Packit 0d464f
                _lineBuffer->packedDataSize = _lineBuffer->compressor->uncompress
Packit 0d464f
                    (_lineBuffer->buffer, _lineBuffer->packedDataSize,
Packit 0d464f
                     _lineBuffer->minY, _lineBuffer->uncompressedData);
Packit 0d464f
            }
Packit 0d464f
            else
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // If the line is uncompressed, it's in XDR format,
Packit 0d464f
                // regardless of the compressor's output format.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                _lineBuffer->format = Compressor::XDR;
Packit 0d464f
                _lineBuffer->uncompressedData = _lineBuffer->buffer;
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        int yStart, yStop, dy;
Packit 0d464f
Packit 0d464f
        if (_ifd->lineOrder == INCREASING_Y)
Packit 0d464f
        {
Packit 0d464f
            yStart = _scanLineMin;
Packit 0d464f
            yStop = _scanLineMax + 1;
Packit 0d464f
            dy = 1;
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            yStart = _scanLineMax;
Packit 0d464f
            yStop = _scanLineMin - 1;
Packit 0d464f
            dy = -1;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        for (int y = yStart; y != yStop; y += dy)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Convert one scan line's worth of pixel data back
Packit 0d464f
            // from the machine-independent representation, and
Packit 0d464f
            // store the result in the frame buffer.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            const char *readPtr = _lineBuffer->uncompressedData +
Packit 0d464f
                                  _ifd->offsetInLineBuffer[y - _ifd->minY];
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Iterate over all image channels.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            for (unsigned int i = 0; i < _ifd->slices.size(); ++i)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Test if scan line y of this channel contains any data
Packit 0d464f
                // (the scan line contains data only if y % ySampling == 0).
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                InSliceInfo &slice = *_ifd->slices[i];
Packit 0d464f
Packit 0d464f
                if (modp (y, slice.ySampling) != 0)
Packit 0d464f
                    continue;
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Find the x coordinates of the leftmost and rightmost
Packit 0d464f
                // sampled pixels (i.e. pixels within the data window
Packit 0d464f
                // for which x % xSampling == 0).
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // Fill the frame buffer with pixel data.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                if (slice.skip)
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // The file contains data for this channel, but
Packit 0d464f
                    // the frame buffer contains no slice for this channel.
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    skipChannel (readPtr, slice.typeInFile,
Packit 0d464f
                                 _ifd->lineSampleCount[y - _ifd->minY]);
Packit 0d464f
                }
Packit 0d464f
                else
Packit 0d464f
                {
Packit 0d464f
                    //
Packit 0d464f
                    // The frame buffer contains a slice for this channel.
Packit 0d464f
                    //
Packit 0d464f
Packit 0d464f
                    int width = (_ifd->maxX - _ifd->minX + 1);
Packit 0d464f
Packit 0d464f
                    copyIntoDeepFrameBuffer (readPtr, slice.base,
Packit 0d464f
                                             (char*) (&_ifd->sampleCount[0][0]
Packit 0d464f
                                                      - _ifd->minX
Packit 0d464f
                                                      - _ifd->minY * width),
Packit 0d464f
                                             sizeof(unsigned int) * 1,
Packit 0d464f
                                             sizeof(unsigned int) * width,
Packit 0d464f
                                             y, _ifd->minX, _ifd->maxX,
Packit 0d464f
                                             0, 0,
Packit 0d464f
                                             0, 0,
Packit 0d464f
                                             slice.sampleStride, 
Packit 0d464f
                                             slice.xPointerStride,
Packit 0d464f
                                             slice.yPointerStride,
Packit 0d464f
                                             slice.fill,
Packit 0d464f
                                             slice.fillValue, _lineBuffer->format,
Packit 0d464f
                                             slice.typeInFrameBuffer,
Packit 0d464f
                                             slice.typeInFile);
Packit 0d464f
                }
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (std::exception &e)
Packit 0d464f
    {
Packit 0d464f
        if (!_lineBuffer->hasException)
Packit 0d464f
        {
Packit 0d464f
            _lineBuffer->exception = e.what();
Packit 0d464f
            _lineBuffer->hasException = true;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (!_lineBuffer->hasException)
Packit 0d464f
        {
Packit 0d464f
            _lineBuffer->exception = "unrecognized exception";
Packit 0d464f
            _lineBuffer->hasException = true;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
LineBufferTask *
Packit 0d464f
newLineBufferTask
Packit 0d464f
    (TaskGroup *group,
Packit 0d464f
     DeepScanLineInputFile::Data *ifd,
Packit 0d464f
     int number,
Packit 0d464f
     int scanLineMin,
Packit 0d464f
     int scanLineMax)
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // Wait for a line buffer to become available, fill the line
Packit 0d464f
    // buffer with raw data from the file if necessary, and create
Packit 0d464f
    // a new LineBufferTask whose execute() method will uncompress
Packit 0d464f
    // the contents of the buffer and copy the pixels into the
Packit 0d464f
    // frame buffer.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    LineBuffer *lineBuffer = ifd->getLineBuffer (number);
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        lineBuffer->wait ();
Packit 0d464f
Packit 0d464f
        if (lineBuffer->number != number)
Packit 0d464f
        {
Packit 0d464f
            lineBuffer->minY = ifd->minY + number * ifd->linesInBuffer;
Packit 0d464f
            lineBuffer->maxY = lineBuffer->minY + ifd->linesInBuffer - 1;
Packit 0d464f
Packit 0d464f
            lineBuffer->number = number;
Packit 0d464f
            lineBuffer->uncompressedData = 0;
Packit 0d464f
Packit 0d464f
            readPixelData (ifd->_streamData, ifd, lineBuffer->minY,
Packit 0d464f
                           lineBuffer->buffer,
Packit 0d464f
                           lineBuffer->packedDataSize,
Packit 0d464f
                           lineBuffer->unpackedDataSize);
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    catch (std::exception &e)
Packit 0d464f
    {
Packit 0d464f
        if (!lineBuffer->hasException)
Packit 0d464f
        {
Packit 0d464f
            lineBuffer->exception = e.what();
Packit 0d464f
            lineBuffer->hasException = true;
Packit 0d464f
        }
Packit 0d464f
        lineBuffer->number = -1;
Packit 0d464f
        lineBuffer->post();
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // Reading from the file caused an exception.
Packit 0d464f
        // Signal that the line buffer is free, and
Packit 0d464f
        // re-throw the exception.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        lineBuffer->exception = "unrecognized exception";
Packit 0d464f
        lineBuffer->hasException = true;
Packit 0d464f
        lineBuffer->number = -1;
Packit 0d464f
        lineBuffer->post();
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    scanLineMin = max (lineBuffer->minY, scanLineMin);
Packit 0d464f
    scanLineMax = min (lineBuffer->maxY, scanLineMax);
Packit 0d464f
Packit 0d464f
    return new LineBufferTask (group, ifd, lineBuffer,
Packit 0d464f
                               scanLineMin, scanLineMax);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
Packit 0d464f
void DeepScanLineInputFile::initialize(const Header& header)
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        if (header.type() != DEEPSCANLINE)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc("Can't build a DeepScanLineInputFile from "
Packit 0d464f
            "a type-mismatched part.");
Packit 0d464f
        
Packit 0d464f
        if(header.version()!=1)
Packit 0d464f
        {
Packit 0d464f
            THROW(IEX_NAMESPACE::ArgExc, "Version " << header.version() << " not supported for deepscanline images in this version of the library");
Packit 0d464f
        }
Packit 0d464f
        
Packit 0d464f
        _data->header = header;
Packit 0d464f
Packit 0d464f
        _data->lineOrder = _data->header.lineOrder();
Packit 0d464f
Packit 0d464f
        const Box2i &dataWindow = _data->header.dataWindow();
Packit 0d464f
Packit 0d464f
        _data->minX = dataWindow.min.x;
Packit 0d464f
        _data->maxX = dataWindow.max.x;
Packit 0d464f
        _data->minY = dataWindow.min.y;
Packit 0d464f
        _data->maxY = dataWindow.max.y;
Packit 0d464f
Packit 0d464f
        _data->sampleCount.resizeErase(_data->maxY - _data->minY + 1,
Packit 0d464f
                                       _data->maxX - _data->minX + 1);
Packit 0d464f
        _data->lineSampleCount.resizeErase(_data->maxY - _data->minY + 1);
Packit 0d464f
Packit 0d464f
        Compressor* compressor = newCompressor(_data->header.compression(),
Packit 0d464f
                                               0,
Packit 0d464f
                                               _data->header);
Packit 0d464f
Packit 0d464f
        _data->linesInBuffer = numLinesInBuffer (compressor);
Packit 0d464f
Packit 0d464f
        delete compressor;
Packit 0d464f
Packit 0d464f
        _data->nextLineBufferMinY = _data->minY - 1;
Packit 0d464f
Packit 0d464f
        int lineOffsetSize = (dataWindow.max.y - dataWindow.min.y +
Packit 0d464f
                              _data->linesInBuffer) / _data->linesInBuffer;
Packit 0d464f
Packit 0d464f
        _data->lineOffsets.resize (lineOffsetSize);
Packit 0d464f
Packit 0d464f
        for (size_t i = 0; i < _data->lineBuffers.size(); i++)
Packit 0d464f
            _data->lineBuffers[i] = new LineBuffer ();
Packit 0d464f
Packit 0d464f
        _data->gotSampleCount.resizeErase(_data->maxY - _data->minY + 1);
Packit 0d464f
        for (int i = 0; i < _data->maxY - _data->minY + 1; i++)
Packit 0d464f
            _data->gotSampleCount[i] = false;
Packit 0d464f
Packit 0d464f
        _data->maxSampleCountTableSize = min(_data->linesInBuffer, _data->maxY - _data->minY + 1) *
Packit 0d464f
                                        (_data->maxX - _data->minX + 1) *
Packit 0d464f
                                        sizeof(unsigned int);
Packit 0d464f
Packit 0d464f
        _data->sampleCountTableBuffer.resizeErase(_data->maxSampleCountTableSize);
Packit 0d464f
Packit 0d464f
        _data->sampleCountTableComp = newCompressor(_data->header.compression(),
Packit 0d464f
                                                    _data->maxSampleCountTableSize,
Packit 0d464f
                                                    _data->header);
Packit 0d464f
Packit 0d464f
        _data->bytesPerLine.resize (_data->maxY - _data->minY + 1);
Packit 0d464f
        
Packit 0d464f
        const ChannelList & c=header.channels();
Packit 0d464f
        
Packit 0d464f
        _data->combinedSampleSize=0;
Packit 0d464f
        for(ChannelList::ConstIterator i=c.begin();i!=c.end();i++)
Packit 0d464f
        {
Packit 0d464f
            switch(i.channel().type)
Packit 0d464f
            {
Packit 0d464f
                case OPENEXR_IMF_INTERNAL_NAMESPACE::HALF  :
Packit 0d464f
                    _data->combinedSampleSize+=Xdr::size<half>();
Packit 0d464f
                    break;
Packit 0d464f
                case OPENEXR_IMF_INTERNAL_NAMESPACE::FLOAT :
Packit 0d464f
                    _data->combinedSampleSize+=Xdr::size<float>();
Packit 0d464f
                    break;
Packit 0d464f
                case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT  :
Packit 0d464f
                    _data->combinedSampleSize+=Xdr::size<unsigned int>();
Packit 0d464f
                    break;
Packit 0d464f
                default :
Packit 0d464f
                    THROW(IEX_NAMESPACE::ArgExc, "Bad type for channel " << i.name() << " initializing deepscanline reader");
Packit 0d464f
                    
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
        
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        delete _data;
Packit 0d464f
        _data=NULL;
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepScanLineInputFile::DeepScanLineInputFile(InputPartData* part)
Packit 0d464f
    
Packit 0d464f
{
Packit 0d464f
Packit 0d464f
    _data = new Data(part->numThreads);
Packit 0d464f
    _data->_deleteStream=false;
Packit 0d464f
    _data->_streamData = part->mutex;
Packit 0d464f
    _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
Packit 0d464f
    _data->version = part->version;
Packit 0d464f
Packit 0d464f
    initialize(part->header);
Packit 0d464f
Packit 0d464f
    _data->lineOffsets = part->chunkOffsets;
Packit 0d464f
Packit 0d464f
    _data->partNumber = part->partNumber;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepScanLineInputFile::DeepScanLineInputFile
Packit 0d464f
    (const char fileName[], int numThreads)
Packit 0d464f
:
Packit 0d464f
     _data (new Data (numThreads))
Packit 0d464f
{
Packit 0d464f
    _data->_streamData = new InputStreamMutex();
Packit 0d464f
    _data->_deleteStream = true;
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::IStream* is = 0;
Packit 0d464f
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        is = new StdIFStream (fileName);
Packit 0d464f
        readMagicNumberAndVersionField(*is, _data->version);
Packit 0d464f
        //
Packit 0d464f
        // Backward compatibility to read multpart file.
Packit 0d464f
        //
Packit 0d464f
        if (isMultiPart(_data->version))
Packit 0d464f
        {
Packit 0d464f
            compatibilityInitialize(*is);
Packit 0d464f
            return;
Packit 0d464f
        }
Packit 0d464f
        _data->_streamData->is = is;
Packit 0d464f
        _data->memoryMapped = is->isMemoryMapped();
Packit 0d464f
        _data->header.readFrom (*_data->_streamData->is, _data->version);
Packit 0d464f
        _data->header.sanityCheck (isTiled (_data->version));
Packit 0d464f
Packit 0d464f
        initialize(_data->header);
Packit 0d464f
Packit 0d464f
        readLineOffsets (*_data->_streamData->is,
Packit 0d464f
                         _data->lineOrder,
Packit 0d464f
                         _data->lineOffsets,
Packit 0d464f
                         _data->fileIsComplete);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        if (is)          delete is;
Packit 0d464f
        if (_data && _data->_streamData) delete _data->_streamData;
Packit 0d464f
        if (_data)       delete _data;
Packit 0d464f
Packit 0d464f
        REPLACE_EXC (e, "Cannot read image file "
Packit 0d464f
                        "\"" << fileName << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
    catch (...)
Packit 0d464f
    {
Packit 0d464f
        if (is)          delete is;
Packit 0d464f
        if (_data && _data->_streamData) delete _data->_streamData;
Packit 0d464f
        if (_data)       delete _data;
Packit 0d464f
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepScanLineInputFile::DeepScanLineInputFile
Packit 0d464f
    (const Header &header,
Packit 0d464f
     OPENEXR_IMF_INTERNAL_NAMESPACE::IStream *is,
Packit 0d464f
     int version,
Packit 0d464f
     int numThreads)
Packit 0d464f
:
Packit 0d464f
    _data (new Data (numThreads))
Packit 0d464f
{
Packit 0d464f
    _data->_streamData=new InputStreamMutex();
Packit 0d464f
    _data->_deleteStream=false;
Packit 0d464f
    _data->_streamData->is = is;
Packit 0d464f
    
Packit 0d464f
    _data->memoryMapped = is->isMemoryMapped();
Packit 0d464f
Packit 0d464f
    _data->version =version;
Packit 0d464f
    
Packit 0d464f
    initialize (header);
Packit 0d464f
Packit 0d464f
    readLineOffsets (*_data->_streamData->is,
Packit 0d464f
                     _data->lineOrder,
Packit 0d464f
                     _data->lineOffsets,
Packit 0d464f
                     _data->fileIsComplete);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
DeepScanLineInputFile::~DeepScanLineInputFile ()
Packit 0d464f
{
Packit 0d464f
    if (_data->_deleteStream)
Packit 0d464f
        delete _data->_streamData->is;
Packit 0d464f
Packit 0d464f
    if (_data)
Packit 0d464f
    {
Packit 0d464f
        if (!_data->memoryMapped)
Packit 0d464f
            for (size_t i = 0; i < _data->lineBuffers.size(); i++)
Packit 0d464f
                delete [] _data->lineBuffers[i]->buffer;
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Unless this file was opened via the multipart API, delete the streamdata
Packit 0d464f
        // object too.
Packit 0d464f
        // (TODO) it should be "isMultiPart(data->version)", but when there is only
Packit 0d464f
        // single part,
Packit 0d464f
        // (see the above constructor) the version field is not set.
Packit 0d464f
        //
Packit 0d464f
        // (TODO) we should have a way to tell if the stream data is owned by this
Packit 0d464f
        // file or by a parent multipart file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        if (_data->partNumber == -1 && _data->_streamData)
Packit 0d464f
            delete _data->_streamData;
Packit 0d464f
Packit 0d464f
        delete _data;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::compatibilityInitialize(OPENEXR_IMF_INTERNAL_NAMESPACE::IStream& is)
Packit 0d464f
{
Packit 0d464f
    is.seekg(0);
Packit 0d464f
    //
Packit 0d464f
    // Construct a MultiPartInputFile, initialize TiledInputFile
Packit 0d464f
    // with the part 0 data.
Packit 0d464f
    // (TODO) maybe change the third parameter of the constructor of MultiPartInputFile later.
Packit 0d464f
    //
Packit 0d464f
    _data->multiPartBackwardSupport = true;
Packit 0d464f
    _data->multiPartFile = new MultiPartInputFile(is, _data->numThreads);
Packit 0d464f
    InputPartData* part = _data->multiPartFile->getPart(0);
Packit 0d464f
    
Packit 0d464f
    multiPartInitialize(part);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
void DeepScanLineInputFile::multiPartInitialize(InputPartData* part)
Packit 0d464f
{
Packit 0d464f
    
Packit 0d464f
    _data->_streamData = part->mutex;
Packit 0d464f
    _data->memoryMapped = _data->_streamData->is->isMemoryMapped();
Packit 0d464f
    _data->version = part->version;
Packit 0d464f
    
Packit 0d464f
    initialize(part->header);
Packit 0d464f
    
Packit 0d464f
    _data->lineOffsets = part->chunkOffsets;
Packit 0d464f
    
Packit 0d464f
    _data->partNumber = part->partNumber;
Packit 0d464f
    
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const char *
Packit 0d464f
DeepScanLineInputFile::fileName () const
Packit 0d464f
{
Packit 0d464f
    return _data->_streamData->is->fileName();
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const Header &
Packit 0d464f
DeepScanLineInputFile::header () const
Packit 0d464f
{
Packit 0d464f
    return _data->header;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepScanLineInputFile::version () const
Packit 0d464f
{
Packit 0d464f
    return _data->version;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::setFrameBuffer (const DeepFrameBuffer &frameBuffer)
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Check if the new frame buffer descriptor is
Packit 0d464f
    // compatible with the image file header.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const ChannelList &channels = _data->header.channels();
Packit 0d464f
Packit 0d464f
    for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
Packit 0d464f
         j != frameBuffer.end();
Packit 0d464f
         ++j)
Packit 0d464f
    {
Packit 0d464f
        ChannelList::ConstIterator i = channels.find (j.name());
Packit 0d464f
Packit 0d464f
        if (i == channels.end())
Packit 0d464f
            continue;
Packit 0d464f
Packit 0d464f
        if (i.channel().xSampling != j.slice().xSampling ||
Packit 0d464f
            i.channel().ySampling != j.slice().ySampling)
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "X and/or y subsampling factors "
Packit 0d464f
                                "of \"" << i.name() << "\" channel "
Packit 0d464f
                                "of input file \"" << fileName() << "\" are "
Packit 0d464f
                                "not compatible with the frame buffer's "
Packit 0d464f
                                "subsampling factors.");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Store the pixel sample count table.
Packit 0d464f
    // (TODO) Support for different sampling rates?
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    const Slice& sampleCountSlice = frameBuffer.getSampleCountSlice();
Packit 0d464f
    if (sampleCountSlice.base == 0)
Packit 0d464f
    {
Packit 0d464f
        throw IEX_NAMESPACE::ArgExc ("Invalid base pointer, please set a proper sample count slice.");
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        _data->sampleCountSliceBase = sampleCountSlice.base;
Packit 0d464f
        _data->sampleCountXStride = sampleCountSlice.xStride;
Packit 0d464f
        _data->sampleCountYStride = sampleCountSlice.yStride;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Initialize the slice table for readPixels().
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    vector<InSliceInfo*> slices;
Packit 0d464f
    ChannelList::ConstIterator i = channels.begin();
Packit 0d464f
Packit 0d464f
    for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
Packit 0d464f
         j != frameBuffer.end();
Packit 0d464f
         ++j)
Packit 0d464f
    {
Packit 0d464f
        while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Channel i is present in the file but not
Packit 0d464f
            // in the frame buffer; data for channel i
Packit 0d464f
            // will be skipped during readPixels().
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            slices.push_back (new InSliceInfo (i.channel().type,
Packit 0d464f
                                               NULL,
Packit 0d464f
                                               i.channel().type,
Packit 0d464f
                                               0,
Packit 0d464f
                                               0,
Packit 0d464f
                                               0, // sampleStride
Packit 0d464f
                                               i.channel().xSampling,
Packit 0d464f
                                               i.channel().ySampling,
Packit 0d464f
                                               false,  // fill
Packit 0d464f
                                               true, // skip
Packit 0d464f
                                               0.0)); // fillValue
Packit 0d464f
            ++i;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        bool fill = false;
Packit 0d464f
Packit 0d464f
        if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // Channel i is present in the frame buffer, but not in the file.
Packit 0d464f
            // In the frame buffer, slice j will be filled with a default value.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            fill = true;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        slices.push_back (new InSliceInfo (j.slice().type,
Packit 0d464f
                                           j.slice().base,
Packit 0d464f
                                           fill? j.slice().type:
Packit 0d464f
                                                 i.channel().type,
Packit 0d464f
                                           j.slice().xStride,
Packit 0d464f
                                           j.slice().yStride,
Packit 0d464f
                                           j.slice().sampleStride,
Packit 0d464f
                                           j.slice().xSampling,
Packit 0d464f
                                           j.slice().ySampling,
Packit 0d464f
                                           fill,
Packit 0d464f
                                           false, // skip
Packit 0d464f
                                           j.slice().fillValue));
Packit 0d464f
Packit 0d464f
Packit 0d464f
        if (i != channels.end() && !fill)
Packit 0d464f
            ++i;
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Client may want data to be filled in multiple arrays,
Packit 0d464f
    // so we reset gotSampleCount and bytesPerLine.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    for (long i = 0; i < _data->gotSampleCount.size(); i++)
Packit 0d464f
        _data->gotSampleCount[i] = false;
Packit 0d464f
    for (size_t i = 0; i < _data->bytesPerLine.size(); i++)
Packit 0d464f
        _data->bytesPerLine[i] = 0;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Store the new frame buffer.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    _data->frameBuffer = frameBuffer;
Packit 0d464f
Packit 0d464f
    for (size_t i = 0; i < _data->slices.size(); i++)
Packit 0d464f
        delete _data->slices[i];
Packit 0d464f
    _data->slices = slices;
Packit 0d464f
    _data->frameBufferValid = true;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
const DeepFrameBuffer &
Packit 0d464f
DeepScanLineInputFile::frameBuffer () const
Packit 0d464f
{
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
    return _data->frameBuffer;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
bool
Packit 0d464f
DeepScanLineInputFile::isComplete () const
Packit 0d464f
{
Packit 0d464f
    return _data->fileIsComplete;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::readPixels (int scanLine1, int scanLine2)
Packit 0d464f
{
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
        if (_data->slices.size() == 0)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("No frame buffer specified "
Packit 0d464f
                               "as pixel data destination.");
Packit 0d464f
Packit 0d464f
        int scanLineMin = min (scanLine1, scanLine2);
Packit 0d464f
        int scanLineMax = max (scanLine1, scanLine2);
Packit 0d464f
Packit 0d464f
        if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("Tried to read scan line outside "
Packit 0d464f
                               "the image file's data window.");
Packit 0d464f
Packit 0d464f
        for (int i = scanLineMin; i <= scanLineMax; i++)
Packit 0d464f
        {
Packit 0d464f
            if (_data->gotSampleCount[i - _data->minY] == false)
Packit 0d464f
                throw IEX_NAMESPACE::ArgExc ("Tried to read scan line without "
Packit 0d464f
                                   "knowing the sample counts, please"
Packit 0d464f
                                   "read the sample counts first.");
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
 
Packit 0d464f
        //
Packit 0d464f
        // We impose a numbering scheme on the lineBuffers where the first
Packit 0d464f
        // scanline is contained in lineBuffer 1.
Packit 0d464f
        //
Packit 0d464f
        // Determine the first and last lineBuffer numbers in this scanline
Packit 0d464f
        // range. We always attempt to read the scanlines in the order that
Packit 0d464f
        // they are stored in the file.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        int start, stop, dl;
Packit 0d464f
Packit 0d464f
        if (_data->lineOrder == INCREASING_Y)
Packit 0d464f
        {
Packit 0d464f
            start = (scanLineMin - _data->minY) / _data->linesInBuffer;
Packit 0d464f
            stop  = (scanLineMax - _data->minY) / _data->linesInBuffer + 1;
Packit 0d464f
            dl = 1;
Packit 0d464f
        }
Packit 0d464f
        else
Packit 0d464f
        {
Packit 0d464f
            start = (scanLineMax - _data->minY) / _data->linesInBuffer;
Packit 0d464f
            stop  = (scanLineMin - _data->minY) / _data->linesInBuffer - 1;
Packit 0d464f
            dl = -1;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Create a task group for all line buffer tasks.  When the
Packit 0d464f
        // task group goes out of scope, the destructor waits until
Packit 0d464f
        // all tasks are complete.
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        {
Packit 0d464f
            TaskGroup taskGroup;
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Add the line buffer tasks.
Packit 0d464f
            //
Packit 0d464f
            // The tasks will execute in the order that they are created
Packit 0d464f
            // because we lock the line buffers during construction and the
Packit 0d464f
            // constructors are called by the main thread.  Hence, in order
Packit 0d464f
            // for a successive task to execute the previous task which
Packit 0d464f
            // used that line buffer must have completed already.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            for (int l = start; l != stop; l += dl)
Packit 0d464f
            {
Packit 0d464f
                ThreadPool::addGlobalTask (newLineBufferTask (&taskGroup,
Packit 0d464f
                                                              _data, l,
Packit 0d464f
                                                              scanLineMin,
Packit 0d464f
                                                              scanLineMax));
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // finish all tasks
Packit 0d464f
            //
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // Exeption handling:
Packit 0d464f
        //
Packit 0d464f
        // LineBufferTask::execute() may have encountered exceptions, but
Packit 0d464f
        // those exceptions occurred in another thread, not in the thread
Packit 0d464f
        // that is executing this call to ScanLineInputFile::readPixels().
Packit 0d464f
        // LineBufferTask::execute() has caught all exceptions and stored
Packit 0d464f
        // the exceptions' what() strings in the line buffers.
Packit 0d464f
        // Now we check if any line buffer contains a stored exception; if
Packit 0d464f
        // this is the case then we re-throw the exception in this thread.
Packit 0d464f
        // (It is possible that multiple line buffers contain stored
Packit 0d464f
        // exceptions.  We re-throw the first exception we find and
Packit 0d464f
        // ignore all others.)
Packit 0d464f
        //
Packit 0d464f
Packit 0d464f
        const string *exception = 0;
Packit 0d464f
Packit 0d464f
        for (size_t i = 0; i < _data->lineBuffers.size(); ++i)
Packit 0d464f
        {
Packit 0d464f
            LineBuffer *lineBuffer = _data->lineBuffers[i];
Packit 0d464f
Packit 0d464f
            if (lineBuffer->hasException && !exception)
Packit 0d464f
                exception = &lineBuffer->exception;
Packit 0d464f
Packit 0d464f
            lineBuffer->hasException = false;
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        if (exception)
Packit 0d464f
            throw IEX_NAMESPACE::IoExc (*exception);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error reading pixel data from image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::readPixels (int scanLine)
Packit 0d464f
{
Packit 0d464f
    readPixels (scanLine, scanLine);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::rawPixelData (int firstScanLine,
Packit 0d464f
                                     char *pixelData,
Packit 0d464f
                                     Int64 &pixelDataSize)
Packit 0d464f
{
Packit 0d464f
   
Packit 0d464f
    
Packit 0d464f
    int minY = lineBufferMinY
Packit 0d464f
    (firstScanLine, _data->minY, _data->linesInBuffer);
Packit 0d464f
    int lineBufferNumber = (minY - _data->minY) / _data->linesInBuffer;
Packit 0d464f
    
Packit 0d464f
    Int64 lineOffset = _data->lineOffsets[lineBufferNumber];
Packit 0d464f
    
Packit 0d464f
    if (lineOffset == 0)
Packit 0d464f
        THROW (IEX_NAMESPACE::InputExc, "Scan line " << minY << " is missing.");
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    // enter the lock here - prevent another thread reseeking the file during read
Packit 0d464f
    Lock lock (*_data->_streamData);
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Seek to the start of the scan line in the file,
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    if (_data->_streamData->is->tellg() != _data->lineOffsets[lineBufferNumber])
Packit 0d464f
        _data->_streamData->is->seekg (lineOffset);
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Read the data block's header.
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    int yInFile;
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Read the part number when we are dealing with a multi-part file.
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    if (isMultiPart(_data->version))
Packit 0d464f
    {
Packit 0d464f
        int partNumber;
Packit 0d464f
        OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, partNumber);
Packit 0d464f
        if (partNumber != _data->partNumber)
Packit 0d464f
        {
Packit 0d464f
            THROW (IEX_NAMESPACE::ArgExc, "Unexpected part number " << partNumber
Packit 0d464f
            << ", should be " << _data->partNumber << ".");
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, yInFile);
Packit 0d464f
    
Packit 0d464f
    if (yInFile != minY)
Packit 0d464f
        throw IEX_NAMESPACE::InputExc ("Unexpected data block y coordinate.");
Packit 0d464f
    
Packit 0d464f
    Int64 sampleCountTableSize;
Packit 0d464f
    Int64 packedDataSize;
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, sampleCountTableSize);
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*_data->_streamData->is, packedDataSize);
Packit 0d464f
    
Packit 0d464f
    // total requirement for reading all the data
Packit 0d464f
    
Packit 0d464f
    Int64 totalSizeRequired=28+sampleCountTableSize+packedDataSize;
Packit 0d464f
    
Packit 0d464f
    bool big_enough = totalSizeRequired<=pixelDataSize;
Packit 0d464f
    
Packit 0d464f
    pixelDataSize = totalSizeRequired;
Packit 0d464f
    
Packit 0d464f
    // was the block we were given big enough?
Packit 0d464f
    if(!big_enough || pixelData==NULL)
Packit 0d464f
    {        
Packit 0d464f
        // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
Packit 0d464f
        // in single part files)
Packit 0d464f
        if(!isMultiPart(_data->version))
Packit 0d464f
        {
Packit 0d464f
          if (_data->nextLineBufferMinY == minY)
Packit 0d464f
              _data->_streamData->is->seekg (lineOffset);
Packit 0d464f
        }
Packit 0d464f
        // leave lock here - bail before reading more data
Packit 0d464f
        return;
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    // copy the values we have read into the output block
Packit 0d464f
    *(int *) pixelData = yInFile;
Packit 0d464f
    *(Int64 *) (pixelData+4) =sampleCountTableSize;
Packit 0d464f
    *(Int64 *) (pixelData+12) = packedDataSize;
Packit 0d464f
    
Packit 0d464f
    // didn't read the unpackedsize - do that now
Packit 0d464f
    Xdr::read<StreamIO> (*_data->_streamData->is, *(Int64 *) (pixelData+20));
Packit 0d464f
    
Packit 0d464f
    // read the actual data
Packit 0d464f
    _data->_streamData->is->read(pixelData+28, sampleCountTableSize+packedDataSize);
Packit 0d464f
    
Packit 0d464f
    // special case: seek stream back to start if we are at the beginning (regular reading pixels assumes it doesn't need to seek
Packit 0d464f
    // in single part files)
Packit 0d464f
    if(!isMultiPart(_data->version))
Packit 0d464f
    {
Packit 0d464f
        if (_data->nextLineBufferMinY == minY)
Packit 0d464f
            _data->_streamData->is->seekg (lineOffset);
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    // leave lock here
Packit 0d464f
    
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
void DeepScanLineInputFile::readPixels (const char* rawPixelData, 
Packit 0d464f
                                        const DeepFrameBuffer& frameBuffer, 
Packit 0d464f
                                        int scanLine1, 
Packit 0d464f
                                        int scanLine2) const
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // read header from block - already converted from Xdr to native format
Packit 0d464f
    //
Packit 0d464f
    int data_scanline = *(int *) rawPixelData;
Packit 0d464f
    Int64 sampleCountTableDataSize=*(Int64 *) (rawPixelData+4);
Packit 0d464f
    Int64 packedDataSize = *(Int64 *) (rawPixelData+12);
Packit 0d464f
    Int64 unpackedDataSize = *(Int64 *) (rawPixelData+20);
Packit 0d464f
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // Uncompress the data, if necessary
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    Compressor * decomp = NULL;
Packit 0d464f
    const char * uncompressed_data;
Packit 0d464f
    Compressor::Format format = Compressor::XDR;
Packit 0d464f
    if(packedDataSize 
Packit 0d464f
    {
Packit 0d464f
        decomp = newCompressor(_data->header.compression(),
Packit 0d464f
                                             unpackedDataSize,
Packit 0d464f
                                             _data->header);
Packit 0d464f
                                             
Packit 0d464f
        decomp->uncompress(rawPixelData+28+sampleCountTableDataSize,
Packit 0d464f
                           packedDataSize,
Packit 0d464f
                           data_scanline, uncompressed_data);
Packit 0d464f
        format = decomp->format();
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        //
Packit 0d464f
        // If the line is uncompressed, it's in XDR format,
Packit 0d464f
        // regardless of the compressor's output format.
Packit 0d464f
        //
Packit 0d464f
        
Packit 0d464f
        format = Compressor::XDR;
Packit 0d464f
        uncompressed_data = rawPixelData+28+sampleCountTableDataSize;
Packit 0d464f
    }
Packit 0d464f
  
Packit 0d464f
    
Packit 0d464f
    int yStart, yStop, dy;
Packit 0d464f
    
Packit 0d464f
    if (_data->lineOrder == INCREASING_Y)
Packit 0d464f
    {
Packit 0d464f
        yStart = scanLine1;
Packit 0d464f
        yStop = scanLine2 + 1;
Packit 0d464f
        dy = 1;
Packit 0d464f
    }
Packit 0d464f
    else
Packit 0d464f
    {
Packit 0d464f
        yStart = scanLine2;
Packit 0d464f
        yStop = scanLine1 - 1;
Packit 0d464f
        dy = -1;
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    const char* samplecount_base = frameBuffer.getSampleCountSlice().base;
Packit 0d464f
    int samplecount_xstride = frameBuffer.getSampleCountSlice().xStride;
Packit 0d464f
    int samplecount_ystride = frameBuffer.getSampleCountSlice().yStride;
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // For each line within the block, get the count of bytes.
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    int minYInLineBuffer = data_scanline;
Packit 0d464f
    int maxYInLineBuffer = min(minYInLineBuffer + _data->linesInBuffer - 1, _data->maxY);
Packit 0d464f
    
Packit 0d464f
    vector<size_t> bytesPerLine(1+_data->maxY-_data->minY);
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    bytesPerDeepLineTable (_data->header,
Packit 0d464f
                           minYInLineBuffer,
Packit 0d464f
                           maxYInLineBuffer,
Packit 0d464f
                           samplecount_base,
Packit 0d464f
                           samplecount_xstride,
Packit 0d464f
                           samplecount_ystride,
Packit 0d464f
                           bytesPerLine);
Packit 0d464f
                           
Packit 0d464f
    //
Packit 0d464f
    // For each scanline within the block, get the offset.
Packit 0d464f
    //
Packit 0d464f
      
Packit 0d464f
    vector<size_t> offsetInLineBuffer;
Packit 0d464f
    offsetInLineBufferTable (bytesPerLine,
Packit 0d464f
                             minYInLineBuffer - _data->minY,
Packit 0d464f
                             maxYInLineBuffer - _data->minY,
Packit 0d464f
                             _data->linesInBuffer,
Packit 0d464f
                             offsetInLineBuffer);
Packit 0d464f
                             
Packit 0d464f
                             
Packit 0d464f
    const ChannelList & channels=header().channels();    
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    for (int y = yStart; y != yStop; y += dy)
Packit 0d464f
    {
Packit 0d464f
        
Packit 0d464f
        const char *readPtr =uncompressed_data +
Packit 0d464f
        offsetInLineBuffer[y - _data->minY];
Packit 0d464f
Packit 0d464f
        //
Packit 0d464f
        // need to know the total number of samples on a scanline to skip channels
Packit 0d464f
        // compute on demand: -1 means uncomputed
Packit 0d464f
        //
Packit 0d464f
        int lineSampleCount = -1;
Packit 0d464f
        
Packit 0d464f
        
Packit 0d464f
        //
Packit 0d464f
        // Iterate over all image channels in frame buffer
Packit 0d464f
        //
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
        ChannelList::ConstIterator i = channels.begin();
Packit 0d464f
                             
Packit 0d464f
        for (DeepFrameBuffer::ConstIterator j = frameBuffer.begin();
Packit 0d464f
                                            j != frameBuffer.end();
Packit 0d464f
             ++j)
Packit 0d464f
        {
Packit 0d464f
            while (i != channels.end() && strcmp (i.name(), j.name()) < 0)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Channel i is present in the file but not
Packit 0d464f
                // in the frame buffer; skip
Packit 0d464f
                    
Packit 0d464f
                if(lineSampleCount==-1)
Packit 0d464f
                {
Packit 0d464f
                     lineSampleCount=0;
Packit 0d464f
                     const char * ptr = (samplecount_base+y*samplecount_ystride + samplecount_xstride*_data->minX);
Packit 0d464f
                     for(int x=_data->minX;x<=_data->maxX;x++)
Packit 0d464f
                     { 
Packit 0d464f
                         
Packit 0d464f
                          lineSampleCount+=*(const unsigned int *) ptr;
Packit 0d464f
                          ptr+=samplecount_xstride;
Packit 0d464f
                     }
Packit 0d464f
                }
Packit 0d464f
Packit 0d464f
               skipChannel (readPtr, i.channel().type, lineSampleCount );
Packit 0d464f
        
Packit 0d464f
                ++i;
Packit 0d464f
            }
Packit 0d464f
                                 
Packit 0d464f
            bool fill = false;
Packit 0d464f
                                 
Packit 0d464f
            if (i == channels.end() || strcmp (i.name(), j.name()) > 0)
Packit 0d464f
            {
Packit 0d464f
                //
Packit 0d464f
                // Channel i is present in the frame buffer, but not in the file.
Packit 0d464f
                // In the frame buffer, slice j will be filled with a default value.
Packit 0d464f
                //
Packit 0d464f
                                     
Packit 0d464f
               fill = true;
Packit 0d464f
            }
Packit 0d464f
            if (modp (y, i.channel().ySampling) == 0)
Packit 0d464f
            {        
Packit 0d464f
                
Packit 0d464f
                copyIntoDeepFrameBuffer (readPtr, j.slice().base,
Packit 0d464f
                                         samplecount_base,
Packit 0d464f
                                         samplecount_xstride,
Packit 0d464f
                                         samplecount_ystride,
Packit 0d464f
                                         y, _data->minX, _data->maxX,
Packit 0d464f
                                         0, 0,
Packit 0d464f
                                         0, 0,
Packit 0d464f
                                         j.slice().sampleStride, 
Packit 0d464f
                                         j.slice().xStride,
Packit 0d464f
                                         j.slice().yStride,
Packit 0d464f
                                         fill,
Packit 0d464f
                                         j.slice().fillValue, 
Packit 0d464f
                                         format,
Packit 0d464f
                                         j.slice().type,
Packit 0d464f
                                         i.channel().type);
Packit 0d464f
                                         
Packit 0d464f
                ++i;
Packit 0d464f
                                         
Packit 0d464f
            }
Packit 0d464f
        }//next slice in framebuffer
Packit 0d464f
    }//next row in image
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // clean up
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    delete decomp;    
Packit 0d464f
}
Packit 0d464f
        
Packit 0d464f
      
Packit 0d464f
Packit 0d464f
void DeepScanLineInputFile::readPixelSampleCounts (const char* rawPixelData, 
Packit 0d464f
                                                   const DeepFrameBuffer& frameBuffer, 
Packit 0d464f
                                                   int scanLine1, 
Packit 0d464f
                                                   int scanLine2) const
Packit 0d464f
{
Packit 0d464f
    //
Packit 0d464f
    // read header from block - already converted from Xdr to native format
Packit 0d464f
    //
Packit 0d464f
    int data_scanline = *(int *) rawPixelData;
Packit 0d464f
    Int64 sampleCountTableDataSize=*(Int64 *) (rawPixelData+4);
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    int maxY;
Packit 0d464f
    maxY = min(data_scanline + _data->linesInBuffer - 1, _data->maxY);
Packit 0d464f
    
Packit 0d464f
    if(scanLine1 != data_scanline)
Packit 0d464f
    {
Packit 0d464f
        THROW(IEX_NAMESPACE::ArgExc,"readPixelSampleCounts(rawPixelData,frameBuffer,"<< scanLine1 << ',' << scanLine2 << ") called with incorrect start scanline - should be " << data_scanline );
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    if(scanLine2 != maxY)
Packit 0d464f
    {
Packit 0d464f
        THROW(IEX_NAMESPACE::ArgExc,"readPixelSampleCounts(rawPixelData,frameBuffer,"<< scanLine1 << ',' << scanLine2 << ") called with incorrect end scanline - should be " << maxY );
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // If the sample count table is compressed, we'll uncompress it.
Packit 0d464f
    //
Packit 0d464f
    
Packit 0d464f
    Int64 rawSampleCountTableSize = (maxY - data_scanline + 1) * (_data->maxX - _data->minX + 1) *
Packit 0d464f
    Xdr::size <unsigned int> ();
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    Compressor * decomp=NULL;
Packit 0d464f
    const char* readPtr;
Packit 0d464f
    if (sampleCountTableDataSize < rawSampleCountTableSize)
Packit 0d464f
    {
Packit 0d464f
        decomp = newCompressor(_data->header.compression(),
Packit 0d464f
                               rawSampleCountTableSize,
Packit 0d464f
                               _data->header);
Packit 0d464f
                                                    
Packit 0d464f
        decomp->uncompress(rawPixelData+28,
Packit 0d464f
                                               sampleCountTableDataSize,
Packit 0d464f
                                               data_scanline,
Packit 0d464f
                                               readPtr);
Packit 0d464f
    }
Packit 0d464f
    else readPtr = rawPixelData+28;
Packit 0d464f
    
Packit 0d464f
    char* base = frameBuffer.getSampleCountSlice().base;
Packit 0d464f
    int xStride = frameBuffer.getSampleCountSlice().xStride;
Packit 0d464f
    int yStride = frameBuffer.getSampleCountSlice().yStride;
Packit 0d464f
    
Packit 0d464f
   
Packit 0d464f
    
Packit 0d464f
    for (int y = scanLine1; y <= scanLine2; y++)
Packit 0d464f
    {
Packit 0d464f
        int lastAccumulatedCount = 0;
Packit 0d464f
        for (int x = _data->minX; x <= _data->maxX; x++)
Packit 0d464f
        {
Packit 0d464f
            int accumulatedCount, count;
Packit 0d464f
            
Packit 0d464f
            //
Packit 0d464f
            // Read the sample count for pixel (x, y).
Packit 0d464f
            //
Packit 0d464f
            
Packit 0d464f
            Xdr::read <CharPtrIO> (readPtr, accumulatedCount);
Packit 0d464f
            if (x == _data->minX)
Packit 0d464f
                count = accumulatedCount;
Packit 0d464f
            else
Packit 0d464f
                count = accumulatedCount - lastAccumulatedCount;
Packit 0d464f
            lastAccumulatedCount = accumulatedCount;
Packit 0d464f
            
Packit 0d464f
            //
Packit 0d464f
            // Store the data in both internal and external data structure.
Packit 0d464f
            //
Packit 0d464f
            
Packit 0d464f
            sampleCount(base, xStride, yStride, x, y) = count;
Packit 0d464f
        }
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    if(decomp)
Packit 0d464f
    {
Packit 0d464f
       delete decomp;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
Packit 0d464f
namespace
Packit 0d464f
{
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
readSampleCountForLineBlock(InputStreamMutex* streamData,
Packit 0d464f
                            DeepScanLineInputFile::Data* data,
Packit 0d464f
                            int lineBlockId)
Packit 0d464f
{
Packit 0d464f
    streamData->is->seekg(data->lineOffsets[lineBlockId]);
Packit 0d464f
Packit 0d464f
    if (isMultiPart(data->version))
Packit 0d464f
    {
Packit 0d464f
        int partNumber;
Packit 0d464f
        OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, partNumber);
Packit 0d464f
Packit 0d464f
        if (partNumber != data->partNumber)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc("Unexpected part number.");
Packit 0d464f
    }
Packit 0d464f
Packit 0d464f
    int minY;
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, minY);
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // Check the correctness of minY.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    if (minY != data->minY + lineBlockId * data->linesInBuffer)
Packit 0d464f
        throw IEX_NAMESPACE::ArgExc("Unexpected data block y coordinate.");
Packit 0d464f
Packit 0d464f
    int maxY;
Packit 0d464f
    maxY = min(minY + data->linesInBuffer - 1, data->maxY);
Packit 0d464f
Packit 0d464f
    Int64 sampleCountTableDataSize;
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, sampleCountTableDataSize);
Packit 0d464f
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    if(sampleCountTableDataSize>data->maxSampleCountTableSize)
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "Bad sampleCountTableDataSize read from chunk "<< lineBlockId << ": expected " << data->maxSampleCountTableSize << " or less, got "<< sampleCountTableDataSize);
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    Int64 packedDataSize;
Packit 0d464f
    Int64 unpackedDataSize;
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, packedDataSize);
Packit 0d464f
    OPENEXR_IMF_INTERNAL_NAMESPACE::Xdr::read <OPENEXR_IMF_INTERNAL_NAMESPACE::StreamIO> (*streamData->is, unpackedDataSize);
Packit 0d464f
Packit 0d464f
    
Packit 0d464f
    
Packit 0d464f
    //
Packit 0d464f
    // We make a check on the data size requirements here.
Packit 0d464f
    // Whilst we wish to store 64bit sizes on disk, not all the compressors
Packit 0d464f
    // have been made to work with such data sizes and are still limited to
Packit 0d464f
    // using signed 32 bit (int) for the data size. As such, this version
Packit 0d464f
    // insists that we validate that the data size does not exceed the data
Packit 0d464f
    // type max limit.
Packit 0d464f
    // @TODO refactor the compressor code to ensure full 64-bit support.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
    int compressorMaxDataSize = std::numeric_limits<int>::max();
Packit 0d464f
    if (sampleCountTableDataSize > Int64(compressorMaxDataSize))
Packit 0d464f
    {
Packit 0d464f
        THROW (IEX_NAMESPACE::ArgExc, "This version of the library does not "
Packit 0d464f
              << "support the allocation of data with size  > "
Packit 0d464f
              << compressorMaxDataSize
Packit 0d464f
              << " file table size    :" << sampleCountTableDataSize << ".\n");
Packit 0d464f
    }
Packit 0d464f
    streamData->is->read(data->sampleCountTableBuffer, sampleCountTableDataSize);
Packit 0d464f
    
Packit 0d464f
    const char* readPtr;
Packit 0d464f
Packit 0d464f
    //
Packit 0d464f
    // If the sample count table is compressed, we'll uncompress it.
Packit 0d464f
    //
Packit 0d464f
Packit 0d464f
Packit 0d464f
    if (sampleCountTableDataSize < data->maxSampleCountTableSize)
Packit 0d464f
    {
Packit 0d464f
        if(!data->sampleCountTableComp)
Packit 0d464f
        {
Packit 0d464f
            THROW(IEX_NAMESPACE::ArgExc,"Deep scanline data corrupt at chunk " << lineBlockId << " (sampleCountTableDataSize error)");
Packit 0d464f
        }
Packit 0d464f
        data->sampleCountTableComp->uncompress(data->sampleCountTableBuffer,
Packit 0d464f
                                               sampleCountTableDataSize,
Packit 0d464f
                                               minY,
Packit 0d464f
                                               readPtr);
Packit 0d464f
    }
Packit 0d464f
    else readPtr = data->sampleCountTableBuffer;
Packit 0d464f
Packit 0d464f
    char* base = data->sampleCountSliceBase;
Packit 0d464f
    int xStride = data->sampleCountXStride;
Packit 0d464f
    int yStride = data->sampleCountYStride;
Packit 0d464f
Packit 0d464f
    // total number of samples in block: used to check samplecount table doesn't
Packit 0d464f
    // reference more data than exists
Packit 0d464f
    
Packit 0d464f
    size_t cumulative_total_samples=0;
Packit 0d464f
    
Packit 0d464f
    for (int y = minY; y <= maxY; y++)
Packit 0d464f
    {
Packit 0d464f
        int yInDataWindow = y - data->minY;
Packit 0d464f
        data->lineSampleCount[yInDataWindow] = 0;
Packit 0d464f
Packit 0d464f
        int lastAccumulatedCount = 0;
Packit 0d464f
        for (int x = data->minX; x <= data->maxX; x++)
Packit 0d464f
        {
Packit 0d464f
            int accumulatedCount, count;
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Read the sample count for pixel (x, y).
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            Xdr::read <CharPtrIO> (readPtr, accumulatedCount);
Packit 0d464f
            
Packit 0d464f
            // sample count table should always contain monotonically
Packit 0d464f
            // increasing values.
Packit 0d464f
            if (accumulatedCount < lastAccumulatedCount)
Packit 0d464f
            {
Packit 0d464f
                THROW(IEX_NAMESPACE::ArgExc,"Deep scanline sampleCount data corrupt at chunk " << lineBlockId << " (negative sample count detected)");
Packit 0d464f
            }
Packit 0d464f
Packit 0d464f
            count = accumulatedCount - lastAccumulatedCount;
Packit 0d464f
            lastAccumulatedCount = accumulatedCount;
Packit 0d464f
Packit 0d464f
            //
Packit 0d464f
            // Store the data in both internal and external data structure.
Packit 0d464f
            //
Packit 0d464f
Packit 0d464f
            data->sampleCount[yInDataWindow][x - data->minX] = count;
Packit 0d464f
            data->lineSampleCount[yInDataWindow] += count;
Packit 0d464f
            sampleCount(base, xStride, yStride, x, y) = count;
Packit 0d464f
        }
Packit 0d464f
        cumulative_total_samples+=data->lineSampleCount[yInDataWindow];
Packit 0d464f
        if(cumulative_total_samples*data->combinedSampleSize > unpackedDataSize)
Packit 0d464f
        {
Packit 0d464f
            THROW(IEX_NAMESPACE::ArgExc,"Deep scanline sampleCount data corrupt at chunk " << lineBlockId << ": pixel data only contains " << unpackedDataSize 
Packit 0d464f
            << " bytes of data but table references at least " << cumulative_total_samples*data->combinedSampleSize << " bytes of sample data" );            
Packit 0d464f
        }
Packit 0d464f
        data->gotSampleCount[y - data->minY] = true;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
fillSampleCountFromCache(int y, DeepScanLineInputFile::Data* data)
Packit 0d464f
{
Packit 0d464f
    int yInDataWindow = y - data->minY;
Packit 0d464f
    char* base = data->sampleCountSliceBase;
Packit 0d464f
    int xStride = data->sampleCountXStride;
Packit 0d464f
    int yStride = data->sampleCountYStride;
Packit 0d464f
    
Packit 0d464f
    for (int x = data->minX; x <= data->maxX; x++)
Packit 0d464f
    {
Packit 0d464f
        unsigned int count = data->sampleCount[yInDataWindow][x - data->minX];    
Packit 0d464f
        sampleCount(base, xStride, yStride, x, y) = count;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
} // namespace
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::readPixelSampleCounts (int scanline1, int scanline2)
Packit 0d464f
{
Packit 0d464f
    Int64 savedFilePos = 0;
Packit 0d464f
Packit 0d464f
    if(!_data->frameBufferValid)
Packit 0d464f
    {
Packit 0d464f
        throw IEX_NAMESPACE::ArgExc("readPixelSampleCounts called with no valid frame buffer");
Packit 0d464f
    }
Packit 0d464f
    
Packit 0d464f
    try
Packit 0d464f
    {
Packit 0d464f
        Lock lock (*_data->_streamData);
Packit 0d464f
Packit 0d464f
        savedFilePos = _data->_streamData->is->tellg();
Packit 0d464f
Packit 0d464f
        int scanLineMin = min (scanline1, scanline2);
Packit 0d464f
        int scanLineMax = max (scanline1, scanline2);
Packit 0d464f
Packit 0d464f
        if (scanLineMin < _data->minY || scanLineMax > _data->maxY)
Packit 0d464f
            throw IEX_NAMESPACE::ArgExc ("Tried to read scan line sample counts outside "
Packit 0d464f
                               "the image file's data window.");
Packit 0d464f
Packit 0d464f
        for (int i = scanLineMin; i <= scanLineMax; i++)
Packit 0d464f
        {
Packit 0d464f
            //
Packit 0d464f
            // if scanline is already read, it'll be in the cache
Packit 0d464f
            // otherwise, read from file, store in cache and in caller's framebuffer
Packit 0d464f
            //
Packit 0d464f
            if (_data->gotSampleCount[i - _data->minY])
Packit 0d464f
            {
Packit 0d464f
                fillSampleCountFromCache(i,_data);
Packit 0d464f
                                         
Packit 0d464f
            }else{
Packit 0d464f
Packit 0d464f
                int lineBlockId = ( i - _data->minY ) / _data->linesInBuffer;
Packit 0d464f
Packit 0d464f
                readSampleCountForLineBlock ( _data->_streamData, _data, lineBlockId );
Packit 0d464f
Packit 0d464f
                int minYInLineBuffer = lineBlockId * _data->linesInBuffer + _data->minY;
Packit 0d464f
                int maxYInLineBuffer = min ( minYInLineBuffer + _data->linesInBuffer - 1, _data->maxY );
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // For each line within the block, get the count of bytes.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                bytesPerDeepLineTable ( _data->header,
Packit 0d464f
                                        minYInLineBuffer,
Packit 0d464f
                                        maxYInLineBuffer,
Packit 0d464f
                                        _data->sampleCountSliceBase,
Packit 0d464f
                                        _data->sampleCountXStride,
Packit 0d464f
                                        _data->sampleCountYStride,
Packit 0d464f
                                        _data->bytesPerLine );
Packit 0d464f
Packit 0d464f
                //
Packit 0d464f
                // For each scanline within the block, get the offset.
Packit 0d464f
                //
Packit 0d464f
Packit 0d464f
                offsetInLineBufferTable ( _data->bytesPerLine,
Packit 0d464f
                                          minYInLineBuffer - _data->minY,
Packit 0d464f
                                          maxYInLineBuffer - _data->minY,
Packit 0d464f
                                          _data->linesInBuffer,
Packit 0d464f
                                          _data->offsetInLineBuffer );
Packit 0d464f
            }
Packit 0d464f
        }
Packit 0d464f
Packit 0d464f
        _data->_streamData->is->seekg(savedFilePos);
Packit 0d464f
    }
Packit 0d464f
    catch (IEX_NAMESPACE::BaseExc &e)
Packit 0d464f
    {
Packit 0d464f
        REPLACE_EXC (e, "Error reading sample count data from image "
Packit 0d464f
                        "file \"" << fileName() << "\". " << e);
Packit 0d464f
Packit 0d464f
        _data->_streamData->is->seekg(savedFilePos);
Packit 0d464f
Packit 0d464f
        throw;
Packit 0d464f
    }
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
void
Packit 0d464f
DeepScanLineInputFile::readPixelSampleCounts(int scanline)
Packit 0d464f
{
Packit 0d464f
    readPixelSampleCounts(scanline, scanline);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
int 
Packit 0d464f
DeepScanLineInputFile::firstScanLineInChunk(int y) const
Packit 0d464f
{
Packit 0d464f
    return int((y-_data->minY)/_data->linesInBuffer)*_data->linesInBuffer + _data->minY;
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
int
Packit 0d464f
DeepScanLineInputFile::lastScanLineInChunk(int y) const
Packit 0d464f
{
Packit 0d464f
    int minY = firstScanLineInChunk(y);
Packit 0d464f
    return min(minY+_data->linesInBuffer-1,_data->maxY);
Packit 0d464f
}
Packit 0d464f
Packit 0d464f
Packit 0d464f
OPENEXR_IMF_INTERNAL_NAMESPACE_SOURCE_EXIT