1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 
19 #ifndef itkVideoFileReader_hxx
20 #define itkVideoFileReader_hxx
21 
22 #include "itkConvertPixelBuffer.h"
23 
24 #include "itkVideoFileReader.h"
25 
26 namespace itk
27 {
28 
29 template< typename TOutputVideoStream >
30 VideoFileReader< TOutputVideoStream >
VideoFileReader()31 ::VideoFileReader()
32 {
33   // Initialize members
34   m_FileName = "";
35   m_VideoIO = nullptr;
36   m_PixelConversionNeeded = false;
37   m_IFrameSafe = true;
38 
39   // TemporalProcessObject inherited members
40   this->SetUnitOutputNumberOfFrames(1);
41   this->SetFrameSkipPerOutput(1);
42   this->SetInputStencilCurrentFrameIndex(0);
43 }
44 
45 template< typename TOutputVideoStream >
46 void
47 VideoFileReader< TOutputVideoStream >
UpdateOutputInformation()48 ::UpdateOutputInformation()
49 {
50   //
51   // Use the VideoIOFactory to generate a VideoIOBase if needed
52   //
53   if (m_VideoIO.IsNull())
54     {
55     this->InitializeVideoIO();
56     }
57 
58   //
59   // Check that the desired dimension mateches that read from the file
60   //
61   if (m_VideoIO->GetNumberOfDimensions() != FrameDimension)
62     {
63     itkExceptionMacro(<< "Output dimension doesn't match dimension of read "
64                       << "data. Expected " << FrameDimension << " but the IO "
65                       << "method has " << m_VideoIO->GetNumberOfDimensions()
66                       << ".");
67     }
68 
69   //
70   // Set up the largest possible temporal region for the output
71   //
72   TemporalRegion largestPossibleTemporalRegion;
73   largestPossibleTemporalRegion.SetFrameStart(0);
74   if (m_IFrameSafe)
75     {
76     largestPossibleTemporalRegion.SetFrameDuration(m_VideoIO->GetLastIFrame()+1);
77     }
78   else
79     {
80     largestPossibleTemporalRegion.SetFrameDuration(m_VideoIO->GetFrameTotal());
81     }
82   this->GetOutput()->SetLargestPossibleTemporalRegion(largestPossibleTemporalRegion);
83 
84   //
85   // Set up the information for the output frames
86   //
87 
88   // Set up largest possible spatial region
89   RegionType region;
90   SizeType size;
91   IndexType start;
92   PointType origin;
93   SpacingType spacing;
94   DirectionType direction;
95   for (unsigned int i = 0; i < FrameDimension; ++i)
96     {
97     size[i] = m_VideoIO->GetDimensions(i);
98     origin[i] = m_VideoIO->GetOrigin(i);
99     spacing[i] = m_VideoIO->GetSpacing(i);
100     std::vector< double > directionInI = m_VideoIO->GetDirection(i);
101     for (unsigned int j = 0; j < FrameDimension; ++j)
102       {
103       direction[j][i] = directionInI[j];
104       }
105     }
106   start.Fill(0);
107   region.SetSize(size);
108   region.SetIndex(start);
109 
110   VideoStreamPointer output = this->GetOutput();
111 
112   output->SetAllLargestPossibleSpatialRegions(region);
113   output->SetAllBufferedSpatialRegions(region);
114   output->SetAllRequestedSpatialRegions(region);
115 
116   output->SetAllFramesSpacing(spacing);
117   output->SetAllFramesOrigin(origin);
118   output->SetAllFramesDirection(direction);
119 }
120 
121 template< typename TOutputVideoStream >
122 typename VideoFileReader<TOutputVideoStream>::FrameOffsetType
123 VideoFileReader< TOutputVideoStream >
GetCurrentPositionFrame()124 ::GetCurrentPositionFrame()
125 {
126   if(m_VideoIO.IsNull())
127     {
128     this->InitializeVideoIO();
129     }
130   return m_VideoIO->GetCurrentFrame();
131 }
132 
133 template< typename TOutputVideoStream >
134 typename VideoFileReader<TOutputVideoStream>::TemporalRatioType
135 VideoFileReader< TOutputVideoStream >
GetCurrentPositionRatio()136 ::GetCurrentPositionRatio()
137 {
138   if(m_VideoIO.IsNull())
139     {
140     this->InitializeVideoIO();
141     }
142   return m_VideoIO->GetRatio();
143 }
144 
145 template< typename TOutputVideoStream >
146 typename VideoFileReader<TOutputVideoStream>::TemporalRatioType
147 VideoFileReader< TOutputVideoStream >
GetCurrentPositionMSec()148 ::GetCurrentPositionMSec()
149 {
150   if(m_VideoIO.IsNull())
151     {
152     this->InitializeVideoIO();
153     }
154   return m_VideoIO->GetPositionInMSec();
155 }
156 
157 template< typename TOutputVideoStream >
158 typename VideoFileReader<TOutputVideoStream>::FrameOffsetType
159 VideoFileReader< TOutputVideoStream >
GetNumberOfFrames()160 ::GetNumberOfFrames()
161 {
162   if(m_VideoIO.IsNull())
163     {
164     this->InitializeVideoIO();
165     }
166   return m_VideoIO->GetFrameTotal();
167 }
168 
169 template< typename TOutputVideoStream >
170 typename VideoFileReader<TOutputVideoStream>::TemporalRatioType
171 VideoFileReader< TOutputVideoStream >
GetFramesPerSecond()172 ::GetFramesPerSecond()
173 {
174   if(m_VideoIO.IsNull())
175     {
176     this->InitializeVideoIO();
177     }
178   return m_VideoIO->GetFramesPerSecond();
179 }
180 
181 template< typename TOutputVideoStream >
182 void
183 VideoFileReader< TOutputVideoStream >
InitializeVideoIO()184 ::InitializeVideoIO()
185 {
186   m_VideoIO = itk::VideoIOFactory::CreateVideoIO(
187                                 itk::VideoIOFactory::ReadFileMode,
188                                 m_FileName.c_str());
189   m_VideoIO->SetFileName(m_FileName.c_str());
190   m_VideoIO->ReadImageInformation();
191 
192   // Make sure the input video has the same number of dimensions as the desired
193   // output
194   //
195   // Note: This may be changed with the implementation of the Image
196   //       Interpretation Layer
197   if (m_VideoIO->GetNumberOfDimensions() != FrameType::ImageDimension)
198     {
199     itkExceptionMacro("Cannot convert " << m_VideoIO->GetNumberOfDimensions() << "D "
200       "image set to " << FrameType::ImageDimension << "D");
201     }
202 
203   // See if a buffer conversion is needed
204   ImageIOBase::IOComponentType ioType = ImageIOBase
205     ::MapPixelType< typename ConvertPixelTraits::ComponentType >::CType;
206   if ( m_VideoIO->GetComponentType() != ioType ||
207        m_VideoIO->GetNumberOfComponents() != ConvertPixelTraits::GetNumberOfComponents() )
208     {
209     // the pixel types don't match so a type conversion needs to be
210     // performed
211     itkDebugMacro( << "Buffer conversion required from: "
212                    << m_VideoIO->GetComponentTypeAsString(m_VideoIO->GetComponentType())
213                    << " to: "
214                    << m_VideoIO->GetComponentTypeAsString(ioType)
215                    << " ConvertPixelTraits::NumComponents "
216                    << ConvertPixelTraits::GetNumberOfComponents()
217                    << " m_VideoIO->NumComponents "
218                    << m_VideoIO->GetNumberOfComponents() );
219     m_PixelConversionNeeded = true;
220     }
221   else
222     {
223     m_PixelConversionNeeded = false;
224     }
225 }
226 
227 template< typename TOutputVideoStream >
228 void
229 VideoFileReader< TOutputVideoStream >
TemporalStreamingGenerateData()230 ::TemporalStreamingGenerateData()
231 {
232   // Allocate the output frames
233   this->AllocateOutputs();
234 
235   // Get the frame number for the frame we're reading
236   typename VideoStreamType::Pointer output;
237   typename VideoStreamType::TemporalRegionType requestedTemporalRegion;
238   output = this->GetOutput();
239   requestedTemporalRegion = output->GetRequestedTemporalRegion();
240   FrameOffsetType frameNum = requestedTemporalRegion.GetFrameStart();
241 
242   // Figure out if we need to skip frames
243   FrameOffsetType currentIOFrame = m_VideoIO->GetCurrentFrame();
244   if (frameNum != currentIOFrame)
245     {
246     m_VideoIO->SetNextFrameToRead(frameNum);
247     }
248 
249   // Read a single frame
250   if (this->m_PixelConversionNeeded)
251     {
252     // Set up temporary buffer for reading
253     size_t bufferSize = m_VideoIO->GetImageSizeInBytes();
254     auto * loadBuffer = new char[bufferSize];
255 
256     // Read into a temporary buffer
257     this->m_VideoIO->Read(static_cast<void*>(loadBuffer));
258 
259     // Convert the buffer into the output buffer location
260     this->DoConvertBuffer(static_cast<void*>(loadBuffer), frameNum);
261     delete[] loadBuffer;
262     }
263   else
264     {
265     FrameType* frame = this->GetOutput()->GetFrame(frameNum);
266     m_VideoIO->Read(reinterpret_cast<void*>(frame->GetBufferPointer()));
267     }
268 
269   // Mark ourselves modified
270   this->Modified();
271 }
272 
273 template< typename TOutputVideoStream >
274 void
275 VideoFileReader< TOutputVideoStream >::
DoConvertBuffer(void * inputData,FrameOffsetType frameNumber)276 DoConvertBuffer(void* inputData, FrameOffsetType frameNumber)
277 {
278   PixelType* outputData =
279     this->GetOutput()->GetFrame(frameNumber)->GetPixelContainer()->GetBufferPointer();
280   unsigned int numberOfPixels =
281     this->GetOutput()->GetFrame(frameNumber)->GetPixelContainer()->Size();
282   bool isVectorImage(strcmp(this->GetOutput()->GetFrame(frameNumber)->GetNameOfClass(),
283                             "VectorImage") == 0);
284 #define ITK_CONVERT_BUFFER_IF_BLOCK(_CType,type)                        \
285   else if(m_VideoIO->GetComponentType() == _CType)                      \
286     {                                                                   \
287     if (isVectorImage)                                                  \
288       {                                                                 \
289       ConvertPixelBuffer<type,                                          \
290                          PixelType,                                     \
291                          ConvertPixelTraits                             \
292                          >                                              \
293         ::ConvertVectorImage(static_cast< type * >( inputData ),        \
294                              m_VideoIO->GetNumberOfComponents(),        \
295                              outputData,                                \
296                              numberOfPixels);                           \
297       }                                                                 \
298     else                                                                \
299       {                                                                 \
300       ConvertPixelBuffer<type,                                          \
301                          PixelType,                                     \
302                          ConvertPixelTraits                             \
303                          >                                              \
304         ::Convert(static_cast< type * >( inputData ),                   \
305                   m_VideoIO->GetNumberOfComponents(),                   \
306                   outputData,                                           \
307                   numberOfPixels);                                      \
308       }                                                                 \
309     }
310 
311   if(false) {}
312   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::UCHAR,unsigned char)
313   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::CHAR,char)
314   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::USHORT,unsigned short)
315   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::SHORT,short)
316   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::UINT,unsigned int)
317   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::INT,int)
318   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::ULONG,unsigned long)
319   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::LONG,long)
320   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::ULONGLONG,unsigned long long)
321   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::LONGLONG,long long)
322   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::FLOAT,float)
323   ITK_CONVERT_BUFFER_IF_BLOCK(ImageIOBase::DOUBLE,double)
324   else
325     {
326 #define TYPENAME_VideoFileReader(x)                                     \
327     m_VideoIO->GetComponentTypeAsString                 \
328       (ImageIOBase::MapPixelType<x>::CType)
329 
330     ExceptionObject e(__FILE__, __LINE__);
331     std::ostringstream       msg;
332     msg << "Couldn't convert component type: "
333         << std::endl << "    "
334         << m_VideoIO->GetComponentTypeAsString( m_VideoIO->GetComponentType() )
335         << std::endl << "to one of: "
336         << std::endl << "    " << TYPENAME_VideoFileReader( unsigned char )
337         << std::endl << "    " << TYPENAME_VideoFileReader( char )
338         << std::endl << "    " << TYPENAME_VideoFileReader( unsigned short )
339         << std::endl << "    " << TYPENAME_VideoFileReader( short )
340         << std::endl << "    " << TYPENAME_VideoFileReader( unsigned int )
341         << std::endl << "    " << TYPENAME_VideoFileReader( int )
342         << std::endl << "    " << TYPENAME_VideoFileReader( FrameOffsetType )
343         << std::endl << "    " << TYPENAME_VideoFileReader( long )
344         << std::endl << "    " << TYPENAME_VideoFileReader( float )
345         << std::endl << "    " << TYPENAME_VideoFileReader( double )
346         << std::endl;
347     e.SetDescription( msg.str().c_str() );
348     e.SetLocation(ITK_LOCATION);
349     throw e;
350     return;
351     }
352 #undef ITK_CONVERT_BUFFER_IF_BLOCK
353 
354 }
355 
356 template< typename TOutputVideoStream >
357 void
358 VideoFileReader< TOutputVideoStream >
PrintSelf(std::ostream & os,Indent indent) const359 ::PrintSelf(std::ostream &os, Indent indent) const
360 {
361   Superclass::PrintSelf(os, indent);
362 
363   os << indent << "FileName: " << this->m_FileName << std::endl;
364   if (m_VideoIO)
365     {
366     os << indent << "VideoIO:" << std::endl;
367     this->m_VideoIO->Print(os, indent.GetNextIndent());
368     }
369 }
370 
371 } // end namespace itk
372 
373 #endif
374