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