comparison OrthancServer/ServerJobs/ArchiveJob.cpp @ 3913:6ddad3e0b569 transcoding

transcoding ZIP archive and media
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 08 May 2020 19:15:28 +0200
parents 56f2397f027a
children b99acc213937
comparison
equal deleted inserted replaced
3912:7610af1532c3 3913:6ddad3e0b569
35 #include "ArchiveJob.h" 35 #include "ArchiveJob.h"
36 36
37 #include "../../Core/Cache/SharedArchive.h" 37 #include "../../Core/Cache/SharedArchive.h"
38 #include "../../Core/Compression/HierarchicalZipWriter.h" 38 #include "../../Core/Compression/HierarchicalZipWriter.h"
39 #include "../../Core/DicomParsing/DicomDirWriter.h" 39 #include "../../Core/DicomParsing/DicomDirWriter.h"
40 #include "../../Core/DicomParsing/FromDcmtkBridge.h"
40 #include "../../Core/Logging.h" 41 #include "../../Core/Logging.h"
41 #include "../../Core/OrthancException.h" 42 #include "../../Core/OrthancException.h"
42 #include "../OrthancConfiguration.h" 43 #include "../OrthancConfiguration.h"
43 #include "../ServerContext.h" 44 #include "../ServerContext.h"
44 45
53 54
54 static const char* const MEDIA_IMAGES_FOLDER = "IMAGES"; 55 static const char* const MEDIA_IMAGES_FOLDER = "IMAGES";
55 static const char* const KEY_DESCRIPTION = "Description"; 56 static const char* const KEY_DESCRIPTION = "Description";
56 static const char* const KEY_INSTANCES_COUNT = "InstancesCount"; 57 static const char* const KEY_INSTANCES_COUNT = "InstancesCount";
57 static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB"; 58 static const char* const KEY_UNCOMPRESSED_SIZE_MB = "UncompressedSizeMB";
59 static const char* const KEY_TRANSCODE = "Transcode";
58 60
59 61
60 namespace Orthanc 62 namespace Orthanc
61 { 63 {
62 static bool IsZip64Required(uint64_t uncompressedSize, 64 static bool IsZip64Required(uint64_t uncompressedSize,
397 } 399 }
398 400
399 void Apply(HierarchicalZipWriter& writer, 401 void Apply(HierarchicalZipWriter& writer,
400 ServerContext& context, 402 ServerContext& context,
401 DicomDirWriter* dicomDir, 403 DicomDirWriter* dicomDir,
402 const std::string& dicomDirFolder) const 404 const std::string& dicomDirFolder,
405 bool transcode,
406 DicomTransferSyntax transferSyntax) const
403 { 407 {
404 switch (type_) 408 switch (type_)
405 { 409 {
406 case Type_OpenDirectory: 410 case Type_OpenDirectory:
407 writer.OpenDirectory(filename_.c_str()); 411 writer.OpenDirectory(filename_.c_str());
424 LOG(WARNING) << "An instance was removed after the job was issued: " << instanceId_; 428 LOG(WARNING) << "An instance was removed after the job was issued: " << instanceId_;
425 return; 429 return;
426 } 430 }
427 431
428 //boost::this_thread::sleep(boost::posix_time::milliseconds(300)); 432 //boost::this_thread::sleep(boost::posix_time::milliseconds(300));
433
434 writer.OpenFile(filename_.c_str());
435
436 bool transcodeSuccess = false;
437
438 std::unique_ptr<ParsedDicomFile> parsed;
429 439
430 writer.OpenFile(filename_.c_str()); 440 if (transcode)
431 writer.Write(content);
432
433 if (dicomDir != NULL)
434 { 441 {
435 ParsedDicomFile parsed(content); 442 // New in Orthanc 1.7.0
436 dicomDir->Add(dicomDirFolder, filename_, parsed); 443 std::set<DicomTransferSyntax> syntaxes;
444 syntaxes.insert(transferSyntax);
445
446 parsed.reset(new ParsedDicomFile(content));
447 const char* data = content.empty() ? NULL : content.c_str();
448
449 std::unique_ptr<IDicomTranscoder::TranscodedDicom> transcodedDicom(
450 context.GetTranscoder().TranscodeToParsed(
451 parsed->GetDcmtkObject(), data, content.size(),
452 syntaxes, true /* allow new SOP instance UID */));
453
454 if (transcodedDicom.get() != NULL &&
455 transcodedDicom->GetDicom().getDataset() != NULL)
456 {
457 std::string transcoded;
458 FromDcmtkBridge::SaveToMemoryBuffer(
459 transcoded, *transcodedDicom->GetDicom().getDataset());
460
461 writer.Write(transcoded);
462
463 if (dicomDir != NULL)
464 {
465 std::unique_ptr<ParsedDicomFile> tmp(
466 ParsedDicomFile::AcquireDcmtkObject(transcodedDicom->ReleaseDicom()));
467 dicomDir->Add(dicomDirFolder, filename_, *tmp);
468 }
469
470 transcodeSuccess = true;
471 }
472 else
473 {
474 LOG(INFO) << "Cannot transcode instance " << instanceId_
475 << " to transfer syntax: " << GetTransferSyntaxUid(transferSyntax);
476 }
477 }
478
479 if (!transcodeSuccess)
480 {
481 writer.Write(content);
482
483 if (dicomDir != NULL)
484 {
485 if (parsed.get() == NULL)
486 {
487 parsed.reset(new ParsedDicomFile(content));
488 }
489
490 dicomDir->Add(dicomDirFolder, filename_, *parsed);
491 }
437 } 492 }
438 493
439 break; 494 break;
440 } 495 }
441 496
452 507
453 void ApplyInternal(HierarchicalZipWriter& writer, 508 void ApplyInternal(HierarchicalZipWriter& writer,
454 ServerContext& context, 509 ServerContext& context,
455 size_t index, 510 size_t index,
456 DicomDirWriter* dicomDir, 511 DicomDirWriter* dicomDir,
457 const std::string& dicomDirFolder) const 512 const std::string& dicomDirFolder,
513 bool transcode,
514 DicomTransferSyntax transferSyntax) const
458 { 515 {
459 if (index >= commands_.size()) 516 if (index >= commands_.size())
460 { 517 {
461 throw OrthancException(ErrorCode_ParameterOutOfRange); 518 throw OrthancException(ErrorCode_ParameterOutOfRange);
462 } 519 }
463 520
464 commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder); 521 commands_[index]->Apply(writer, context, dicomDir, dicomDirFolder, transcode, transferSyntax);
465 } 522 }
466 523
467 public: 524 public:
468 ZipCommands() : 525 ZipCommands() :
469 uncompressedSize_(0), 526 uncompressedSize_(0),
494 uint64_t GetUncompressedSize() const 551 uint64_t GetUncompressedSize() const
495 { 552 {
496 return uncompressedSize_; 553 return uncompressedSize_;
497 } 554 }
498 555
556 // "media" flavor (with DICOMDIR)
499 void Apply(HierarchicalZipWriter& writer, 557 void Apply(HierarchicalZipWriter& writer,
500 ServerContext& context, 558 ServerContext& context,
501 size_t index, 559 size_t index,
502 DicomDirWriter& dicomDir, 560 DicomDirWriter& dicomDir,
503 const std::string& dicomDirFolder) const 561 const std::string& dicomDirFolder,
504 { 562 bool transcode,
505 ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder); 563 DicomTransferSyntax transferSyntax) const
506 } 564 {
507 565 ApplyInternal(writer, context, index, &dicomDir, dicomDirFolder, transcode, transferSyntax);
566 }
567
568 // "archive" flavor (without DICOMDIR)
508 void Apply(HierarchicalZipWriter& writer, 569 void Apply(HierarchicalZipWriter& writer,
509 ServerContext& context, 570 ServerContext& context,
510 size_t index) const 571 size_t index,
511 { 572 bool transcode,
512 ApplyInternal(writer, context, index, NULL, ""); 573 DicomTransferSyntax transferSyntax) const
574 {
575 ApplyInternal(writer, context, index, NULL, "", transcode, transferSyntax);
513 } 576 }
514 577
515 void AddOpenDirectory(const std::string& filename) 578 void AddOpenDirectory(const std::string& filename)
516 { 579 {
517 commands_.push_back(new Command(Type_OpenDirectory, filename)); 580 commands_.push_back(new Command(Type_OpenDirectory, filename));
738 size_t GetStepsCount() const 801 size_t GetStepsCount() const
739 { 802 {
740 return commands_.GetSize() + 1; 803 return commands_.GetSize() + 1;
741 } 804 }
742 805
743 void RunStep(size_t index) 806 void RunStep(size_t index,
807 bool transcode,
808 DicomTransferSyntax transferSyntax)
744 { 809 {
745 if (index > commands_.GetSize()) 810 if (index > commands_.GetSize())
746 { 811 {
747 throw OrthancException(ErrorCode_ParameterOutOfRange); 812 throw OrthancException(ErrorCode_ParameterOutOfRange);
748 } 813 }
762 else 827 else
763 { 828 {
764 if (isMedia_) 829 if (isMedia_)
765 { 830 {
766 assert(dicomDir_.get() != NULL); 831 assert(dicomDir_.get() != NULL);
767 commands_.Apply(*zip_, context_, index, *dicomDir_, MEDIA_IMAGES_FOLDER); 832 commands_.Apply(*zip_, context_, index, *dicomDir_,
833 MEDIA_IMAGES_FOLDER, transcode, transferSyntax);
768 } 834 }
769 else 835 else
770 { 836 {
771 assert(dicomDir_.get() == NULL); 837 assert(dicomDir_.get() == NULL);
772 commands_.Apply(*zip_, context_, index); 838 commands_.Apply(*zip_, context_, index, transcode, transferSyntax);
773 } 839 }
774 } 840 }
775 } 841 }
776 842
777 unsigned int GetInstancesCount() const 843 unsigned int GetInstancesCount() const
793 archive_(new ArchiveIndex(ResourceType_Patient)), // root 859 archive_(new ArchiveIndex(ResourceType_Patient)), // root
794 isMedia_(isMedia), 860 isMedia_(isMedia),
795 enableExtendedSopClass_(enableExtendedSopClass), 861 enableExtendedSopClass_(enableExtendedSopClass),
796 currentStep_(0), 862 currentStep_(0),
797 instancesCount_(0), 863 instancesCount_(0),
798 uncompressedSize_(0) 864 uncompressedSize_(0),
865 transcode_(false),
866 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit)
799 { 867 {
800 } 868 }
801 869
802 870
803 ArchiveJob::~ArchiveJob() 871 ArchiveJob::~ArchiveJob()
849 } 917 }
850 else 918 else
851 { 919 {
852 ResourceIdentifiers resource(context_.GetIndex(), publicId); 920 ResourceIdentifiers resource(context_.GetIndex(), publicId);
853 archive_->Add(context_.GetIndex(), resource); 921 archive_->Add(context_.GetIndex(), resource);
922 }
923 }
924
925
926 void ArchiveJob::SetTranscode(DicomTransferSyntax transferSyntax)
927 {
928 if (writer_.get() != NULL) // Already started
929 {
930 throw OrthancException(ErrorCode_BadSequenceOfCalls);
931 }
932 else
933 {
934 transcode_ = true;
935 transferSyntax_ = transferSyntax;
854 } 936 }
855 } 937 }
856 938
857 939
858 void ArchiveJob::Reset() 940 void ArchiveJob::Reset()
952 FinalizeTarget(); 1034 FinalizeTarget();
953 return JobStepResult::Success(); 1035 return JobStepResult::Success();
954 } 1036 }
955 else 1037 else
956 { 1038 {
957 writer_->RunStep(currentStep_); 1039 writer_->RunStep(currentStep_, transcode_, transferSyntax_);
958 1040
959 currentStep_ ++; 1041 currentStep_ ++;
960 1042
961 if (currentStep_ == writer_->GetStepsCount()) 1043 if (currentStep_ == writer_->GetStepsCount())
962 { 1044 {
1004 value = Json::objectValue; 1086 value = Json::objectValue;
1005 value[KEY_DESCRIPTION] = description_; 1087 value[KEY_DESCRIPTION] = description_;
1006 value[KEY_INSTANCES_COUNT] = instancesCount_; 1088 value[KEY_INSTANCES_COUNT] = instancesCount_;
1007 value[KEY_UNCOMPRESSED_SIZE_MB] = 1089 value[KEY_UNCOMPRESSED_SIZE_MB] =
1008 static_cast<unsigned int>(uncompressedSize_ / MEGA_BYTES); 1090 static_cast<unsigned int>(uncompressedSize_ / MEGA_BYTES);
1091
1092 if (transcode_)
1093 {
1094 value[KEY_TRANSCODE] = GetTransferSyntaxUid(transferSyntax_);
1095 }
1009 } 1096 }
1010 1097
1011 1098
1012 bool ArchiveJob::GetOutput(std::string& output, 1099 bool ArchiveJob::GetOutput(std::string& output,
1013 MimeType& mime, 1100 MimeType& mime,