comparison Core/DicomParsing/Internals/DicomFrameIndex.cpp @ 3745:113a7b994a12

extracting the raw frame in the transcoder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Thu, 12 Mar 2020 21:48:35 +0100
parents 94f4a18a79cc
children
comparison
equal deleted inserted replaced
3744:accf1b60b108 3745:113a7b994a12
66 } 66 }
67 67
68 uint32_t length = item->getLength(); 68 uint32_t length = item->getLength();
69 if (length == 0) 69 if (length == 0)
70 { 70 {
71 table.clear(); 71 // Degenerate case: Empty offset table means only one frame
72 // that overlaps all the fragments
73 table.resize(1);
74 table[0] = 0;
72 return; 75 return;
73 } 76 }
74 77
75 if (length % 4 != 0) 78 if (length % 4 != 0)
76 { 79 {
143 if (offsetOfFrame.size() != countFrames || 146 if (offsetOfFrame.size() != countFrames ||
144 offsetOfFrame[0] != 0) 147 offsetOfFrame[0] != 0)
145 { 148 {
146 throw OrthancException(ErrorCode_BadFileFormat); 149 throw OrthancException(ErrorCode_BadFileFormat);
147 } 150 }
148
149 151
150 // Loop over the fragments (ignoring the offset table). This is 152 // Loop over the fragments (ignoring the offset table). This is
151 // an alternative, faster implementation to DCMTK's 153 // an alternative, faster implementation to DCMTK's
152 // "DcmCodec::determineStartFragment()". 154 // "DcmCodec::determineStartFragment()".
153 DcmObject* fragment = pixelSequence_->nextInContainer(NULL); 155 DcmObject* fragment = pixelSequence_->nextInContainer(NULL);
316 } 318 }
317 } 319 }
318 }; 320 };
319 321
320 322
321 323 unsigned int DicomFrameIndex::GetFramesCount(DcmDataset& dicom)
322 bool DicomFrameIndex::IsVideo(DcmFileFormat& dicom) 324 {
323 {
324 // Retrieve the transfer syntax from the DICOM header
325 const char* value = NULL;
326 if (!dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() ||
327 value == NULL)
328 {
329 return false;
330 }
331
332 const std::string transferSyntax(value);
333
334 // Video standards supported in DICOM 2016a
335 // http://dicom.nema.org/medical/dicom/2016a/output/html/part05.html
336 if (transferSyntax == "1.2.840.10008.1.2.4.100" || // MPEG2 MP@ML option of ISO/IEC MPEG2
337 transferSyntax == "1.2.840.10008.1.2.4.101" || // MPEG2 MP@HL option of ISO/IEC MPEG2
338 transferSyntax == "1.2.840.10008.1.2.4.102" || // MPEG-4 AVC/H.264 High Profile / Level 4.1 of ITU-T H.264
339 transferSyntax == "1.2.840.10008.1.2.4.103" || // MPEG-4 AVC/H.264 BD-compat High Profile / Level 4.1 of ITU-T H.264
340 transferSyntax == "1.2.840.10008.1.2.4.104" || // MPEG-4 AVC/H.264 High Profile / Level 4.2 of ITU-T H.264
341 transferSyntax == "1.2.840.10008.1.2.4.105" || // MPEG-4 AVC/H.264 High Profile / Level 4.2 of ITU-T H.264
342 transferSyntax == "1.2.840.10008.1.2.4.106") // MPEG-4 AVC/H.264 Stereo High Profile / Level 4.2 of the ITU-T H.264
343 {
344 return true;
345 }
346
347 return false;
348 }
349
350
351 unsigned int DicomFrameIndex::GetFramesCount(DcmFileFormat& dicom)
352 {
353 // Assume 1 frame for video transfer syntaxes
354 if (IsVideo(dicom))
355 {
356 return 1;
357 }
358
359 const char* tmp = NULL; 325 const char* tmp = NULL;
360 if (!dicom.getDataset()->findAndGetString(DCM_NumberOfFrames, tmp).good() || 326 if (!dicom.findAndGetString(DCM_NumberOfFrames, tmp).good() ||
361 tmp == NULL) 327 tmp == NULL)
362 { 328 {
363 return 1; 329 return 1;
364 } 330 }
365 331
376 { 342 {
377 throw OrthancException(ErrorCode_BadFileFormat); 343 throw OrthancException(ErrorCode_BadFileFormat);
378 } 344 }
379 else 345 else
380 { 346 {
381 return count; 347 return static_cast<unsigned int>(count);
382 } 348 }
383 } 349 }
384 350
385 351
386 DicomFrameIndex::DicomFrameIndex(DcmFileFormat& dicom) 352 DicomFrameIndex::DicomFrameIndex(DcmDataset& dicom)
387 { 353 {
388 countFrames_ = GetFramesCount(dicom); 354 countFrames_ = GetFramesCount(dicom);
389 if (countFrames_ == 0) 355 if (countFrames_ == 0)
390 { 356 {
391 // The image has no frame. No index is to be built. 357 // The image has no frame. No index is to be built.
392 return; 358 return;
393 } 359 }
394 360
395 DcmDataset& dataset = *dicom.getDataset();
396
397 // Test whether this image is composed of a sequence of fragments 361 // Test whether this image is composed of a sequence of fragments
398 DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dataset); 362 DcmPixelSequence* pixelSequence = FromDcmtkBridge::GetPixelSequence(dicom);
399 if (pixelSequence != NULL) 363 if (pixelSequence != NULL)
400 { 364 {
401 index_.reset(new FragmentIndex(pixelSequence, countFrames_)); 365 index_.reset(new FragmentIndex(pixelSequence, countFrames_));
402 return; 366 return;
403 } 367 }
404 368
405 // Extract information about the image structure 369 // Extract information about the image structure
406 DicomMap tags; 370 DicomMap tags;
407 FromDcmtkBridge::ExtractDicomSummary(tags, dataset); 371 FromDcmtkBridge::ExtractDicomSummary(tags, dicom);
408 372
409 DicomImageInformation information(tags); 373 DicomImageInformation information(tags);
410 374
411 // Access to the raw pixel data 375 // Access to the raw pixel data
412 if (DicomImageDecoder::IsPsmctRle1(dataset)) 376 if (DicomImageDecoder::IsPsmctRle1(dicom))
413 { 377 {
414 index_.reset(new PsmctRle1Index(dataset, countFrames_, information.GetFrameSize())); 378 index_.reset(new PsmctRle1Index(dicom, countFrames_, information.GetFrameSize()));
415 } 379 }
416 else 380 else
417 { 381 {
418 index_.reset(new UncompressedIndex(dataset, countFrames_, information.GetFrameSize())); 382 index_.reset(new UncompressedIndex(dicom, countFrames_, information.GetFrameSize()));
419 } 383 }
420 } 384 }
421 385
422 386
423 void DicomFrameIndex::GetRawFrame(std::string& frame, 387 void DicomFrameIndex::GetRawFrame(std::string& frame,