Mercurial > hg > orthanc-dicomweb
changeset 676:6ae0e07512b8
Optimized the retrieval of single frame in WADO-RS when no transcoding is required
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Wed, 09 Oct 2024 15:52:24 +0200 (7 months ago) |
parents | c302094b719e |
children | a5241defb36f |
files | NEWS Plugin/WadoRsRetrieveFrames.cpp TODO |
diffstat | 3 files changed, 59 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/NEWS Wed Sep 04 12:56:30 2024 +0200 +++ b/NEWS Wed Oct 09 15:52:24 2024 +0200 @@ -5,6 +5,8 @@ * Fixed parsing of numerical values in QIDO-RS response that prevented, amongst other, the retrieval of NumberOfStudyRelatedInstances, NumberOfStudyRelatedSeries, ... * Fixed non latin PatientName values that were empty in some QIDO-RS responses. +* Optimized the retrieval of single frame in WADO-RS when no transcoding is required. + This greatly improve download time of multi-frame images in OHIF. Version 1.17 (2024-06-05)
--- a/Plugin/WadoRsRetrieveFrames.cpp Wed Sep 04 12:56:30 2024 +0200 +++ b/Plugin/WadoRsRetrieveFrames.cpp Wed Oct 09 15:52:24 2024 +0200 @@ -433,6 +433,43 @@ } +static void AnswerFrame(OrthancPluginRestOutput* output, + const OrthancPluginHttpRequest* request, + const OrthancPlugins::MemoryBuffer& instanceContent, + const std::string& studyInstanceUid, + const std::string& seriesInstanceUid, + const std::string& sopInstanceUid, + unsigned int frame, + Orthanc::DicomTransferSyntax outputSyntax) +{ + if (OrthancPluginStartMultipartAnswer( + OrthancPlugins::GetGlobalContext(), + output, "related", GetMimeType(outputSyntax)) != OrthancPluginErrorCode_Success) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_Plugin, + "Cannot start a multipart answer"); + } + + OrthancPluginErrorCode error; + +#if HAS_SEND_MULTIPART_ITEM_2 == 1 + const std::string base = OrthancPlugins::Configuration::GetBasePublicUrl(request); + std::string location = ( + OrthancPlugins::Configuration::GetWadoUrl(base, studyInstanceUid, seriesInstanceUid, sopInstanceUid) + + "frames/" + boost::lexical_cast<std::string>(frame)); + const char *keys[] = { "Content-Location" }; + const char *values[] = { location.c_str() }; + error = OrthancPluginSendMultipartItem2(OrthancPlugins::GetGlobalContext(), output, instanceContent.GetData(), instanceContent.GetSize(), 1, keys, values); +#else + error = OrthancPluginSendMultipartItem(OrthancPlugins::GetGlobalContext(), instanceContent.GetData(), instanceContent.GetSize(), size); +#endif + + if (error != OrthancPluginErrorCode_Success) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } +} + static void RetrieveFrames(OrthancPluginRestOutput* output, const OrthancPluginHttpRequest* request, bool allFrames, @@ -499,9 +536,25 @@ { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DICOMWeb: Unable to get transcoded file for instance " + orthancId); } + + // TODO-OPTI: this takes a huge amount of time; e.g: 1.5s for a 600MB file while the DicomInstance usually already exists in the Orthanc core + // call /instances/../frames/../transcoded (to be implemented in future Orthanc release) instance.reset(new OrthancPlugins::DicomInstance(content.GetData(), content.GetSize())); } - else // pre 1.12.2 code (or no transcoding needed) + else if (!allFrames && frames.size() == 1 && !transcodeThisInstance) // no transcoding needed, let's retrieve the raw frame directly from the core to avoid Orthanc to recreate a DicomInstance for every frame + { + if (!content.RestApiGet("/instances/" + orthancId + "/frames/" + boost::lexical_cast<std::string>(frames.front()) + "/raw", false)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "DICOMWeb: Unable to get file for instance " + orthancId); + } + + LOG(INFO) << "DICOMweb RetrieveFrames, before AnswerFrame"; + AnswerFrame(output, request, content, studyInstanceUid, seriesInstanceUid, + sopInstanceUid, frames.front(), targetSyntax); + LOG(INFO) << "DICOMweb RetrieveFrame, leaving"; + return; + } + else { if (!content.RestApiGet("/instances/" + orthancId + "/file", false)) {
--- a/TODO Wed Sep 04 12:56:30 2024 +0200 +++ b/TODO Wed Oct 09 15:52:24 2024 +0200 @@ -10,6 +10,8 @@ curl -H "Accept: multipart/related; type=application/octet-stream" http://localhost:8043/dicom-web/studies/1.2.156.112536.1.2143.25015081191207.14610300430.5/series/1.2.156.112536.1.2143.25015081191207.14610300430.6/instances/1.2.156.112536.1.2143.25015081191207.14610309990.44/frames/3 --output /tmp/out.bin check for these logs: DICOMweb RetrieveFrames: Transcoding instance a7aec17a-e296e51f-2abe8ad8-bc95d57b-4de269d0 to transfer syntax 1.2.840.10008.1.2.1 + Note: this has been partialy handled in 1.18: if no transcoding is needed, we avoid download the full instance from Orthanc + We should very likely implement a cache in the DicomWEB plugin and make sure that, if 3 clients are requesting the same instance at the same time, we only request one transcoding. @@ -18,6 +20,7 @@ https://discourse.orthanc-server.org/t/possible-memory-leak-with-multiframe-dicom-orthanc-ohif/3988/12 + * Implement capabilities: https://www.dicomstandard.org/using/dicomweb/capabilities/ from https://groups.google.com/d/msgid/orthanc-users/c60227f2-c6da-4fd9-9b03-3ce9bf7d1af5n%40googlegroups.com?utm_medium=email&utm_source=footer