comparison OrthancServer/Sources/ServerContext.cpp @ 5743:8bb3f2fca242

refactored ServerContext::DecodeDicomFrame to have a single implementation
author Alain Mazy <am@orthanc.team>
date Thu, 29 Aug 2024 13:46:49 +0200
parents 078b724dcbf8
children 9d6167ddcb35 796cb17db15c b4fbd9d2c907
comparison
equal deleted inserted replaced
5742:078b724dcbf8 5743:8bb3f2fca242
1344 accessor_.reset(NULL); 1344 accessor_.reset(NULL);
1345 1345
1346 // Throttle to avoid loading several large DICOM files simultaneously 1346 // Throttle to avoid loading several large DICOM files simultaneously
1347 largeDicomLocker_.reset(new Semaphore::Locker(context.largeDicomThrottler_)); 1347 largeDicomLocker_.reset(new Semaphore::Locker(context.largeDicomThrottler_));
1348 1348
1349 std::string content; 1349 context_.ReadDicom(buffer_, instancePublicId_);
1350 context_.ReadDicom(content, instancePublicId);
1351 1350
1352 // Release the throttle if loading "small" DICOM files (under 1351 // Release the throttle if loading "small" DICOM files (under
1353 // 50MB, which is an arbitrary value) 1352 // 50MB, which is an arbitrary value)
1354 if (content.size() < 50 * 1024 * 1024) 1353 if (buffer_.size() < 50 * 1024 * 1024)
1355 { 1354 {
1356 largeDicomLocker_.reset(NULL); 1355 largeDicomLocker_.reset(NULL);
1357 } 1356 }
1358 1357
1359 dicom_.reset(new ParsedDicomFile(content)); 1358 dicom_.reset(new ParsedDicomFile(buffer_));
1360 dicomSize_ = content.size(); 1359 dicomSize_ = buffer_.size();
1361 } 1360 }
1362 1361
1363 assert(accessor_.get() != NULL || 1362 assert(accessor_.get() != NULL ||
1364 dicom_.get() != NULL); 1363 dicom_.get() != NULL);
1365 } 1364 }
1391 assert(accessor_.get() != NULL); 1390 assert(accessor_.get() != NULL);
1392 return accessor_->GetDicom(); 1391 return accessor_->GetDicom();
1393 } 1392 }
1394 } 1393 }
1395 1394
1395 const std::string& ServerContext::DicomCacheLocker::GetBuffer()
1396 {
1397 if (buffer_.size() > 0)
1398 {
1399 return buffer_;
1400 }
1401 else
1402 {
1403 context_.ReadDicom(buffer_, instancePublicId_);
1404 return buffer_;
1405 }
1406 }
1396 1407
1397 void ServerContext::SetStoreMD5ForAttachments(bool storeMD5) 1408 void ServerContext::SetStoreMD5ForAttachments(bool storeMD5)
1398 { 1409 {
1399 LOG(INFO) << "Storing MD5 for attachments: " << (storeMD5 ? "yes" : "no"); 1410 LOG(INFO) << "Storing MD5 for attachments: " << (storeMD5 ? "yes" : "no");
1400 storeMD5_ = storeMD5; 1411 storeMD5_ = storeMD5;
1845 1856
1846 return NULL; 1857 return NULL;
1847 } 1858 }
1848 1859
1849 1860
1861
1862
1863
1850 ImageAccessor* ServerContext::DecodeDicomFrame(const std::string& publicId, 1864 ImageAccessor* ServerContext::DecodeDicomFrame(const std::string& publicId,
1851 unsigned int frameIndex) 1865 unsigned int frameIndex)
1852 { 1866 {
1867 ServerContext::DicomCacheLocker locker(*this, publicId);
1868 std::unique_ptr<ImageAccessor> decoded(DecodeDicomFrame(locker.GetDicom(), locker.GetBuffer().c_str(), locker.GetBuffer().size(), frameIndex));
1869
1870 if (decoded.get() == NULL)
1871 {
1872 OrthancConfiguration::ReaderLock configLock;
1873 if (configLock.GetConfiguration().IsWarningEnabled(Warnings_003_DecoderFailure))
1874 {
1875 LOG(WARNING) << "W003: Unable to decode frame " << frameIndex << " from instance " << publicId;
1876 }
1877 return NULL;
1878 }
1879
1880 return decoded.release();
1881 }
1882
1883
1884 ImageAccessor* ServerContext::DecodeDicomFrame(const ParsedDicomFile& parsedDicom,
1885 const void* buffer, // actually the buffer that is the source of the ParsedDicomFile
1886 size_t size,
1887 unsigned int frameIndex)
1888 {
1889 std::unique_ptr<ImageAccessor> decoded;
1890
1853 if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) 1891 if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before)
1854 { 1892 {
1855 // Use Orthanc's built-in decoder, using the cache to speed-up 1893 // Use Orthanc's built-in decoder
1856 // things on multi-frame images 1894
1857
1858 std::unique_ptr<ImageAccessor> decoded;
1859 try 1895 try
1860 { 1896 {
1861 ServerContext::DicomCacheLocker locker(*this, publicId); 1897 decoded.reset(parsedDicom.DecodeFrame(frameIndex));
1862 decoded.reset(locker.GetDicom().DecodeFrame(frameIndex)); 1898 if (decoded.get() != NULL)
1899 {
1900 return decoded.release();
1901 }
1863 } 1902 }
1864 catch (OrthancException& e) 1903 catch (OrthancException& e)
1865 { 1904 { // ignore, we'll try other alternatives
1866 }
1867
1868 if (decoded.get() != NULL)
1869 {
1870 return decoded.release();
1871 } 1905 }
1872 } 1906 }
1873 1907
1874 #if ORTHANC_ENABLE_PLUGINS == 1 1908 #if ORTHANC_ENABLE_PLUGINS == 1
1875 if (HasPlugins() && 1909 if (HasPlugins() &&
1876 GetPlugins().HasCustomImageDecoder()) 1910 GetPlugins().HasCustomImageDecoder())
1877 { 1911 {
1878 // TODO: Store the raw buffer in the DicomCacheLocker
1879 std::string dicomContent;
1880 ReadDicom(dicomContent, publicId);
1881
1882 std::unique_ptr<ImageAccessor> decoded;
1883 try 1912 try
1884 { 1913 {
1885 decoded.reset(GetPlugins().Decode(dicomContent.c_str(), dicomContent.size(), frameIndex)); 1914 decoded.reset(GetPlugins().Decode(buffer, size, frameIndex));
1886 } 1915 }
1887 catch (OrthancException& e) 1916 catch (OrthancException& e)
1888 { 1917 {
1889 } 1918 }
1890 1919
1900 } 1929 }
1901 #endif 1930 #endif
1902 1931
1903 if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After) 1932 if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After)
1904 { 1933 {
1905 ServerContext::DicomCacheLocker locker(*this, publicId);
1906 try 1934 try
1907 { 1935 {
1908 std::unique_ptr<ImageAccessor> decoded(locker.GetDicom().DecodeFrame(frameIndex)); 1936 decoded.reset(parsedDicom.DecodeFrame(frameIndex));
1909
1910 if (decoded.get() != NULL) 1937 if (decoded.get() != NULL)
1911 { 1938 {
1912 return decoded.release(); 1939 return decoded.release();
1913 } 1940 }
1914 } 1941 }
1918 } 1945 }
1919 } 1946 }
1920 1947
1921 if (HasPlugins() && GetPlugins().HasCustomTranscoder()) 1948 if (HasPlugins() && GetPlugins().HasCustomTranscoder())
1922 { 1949 {
1923 // TODO: Store the raw buffer in the DicomCacheLocker
1924 std::string dicomContent;
1925 ReadDicom(dicomContent, publicId);
1926
1927 LOG(INFO) << "The plugins and built-in image decoders failed to decode a frame, " 1950 LOG(INFO) << "The plugins and built-in image decoders failed to decode a frame, "
1928 << "trying to transcode the file to LittleEndianExplicit using the plugins."; 1951 << "trying to transcode the file to LittleEndianExplicit using the plugins.";
1929 DicomImage explicitTemporaryImage; 1952 DicomImage explicitTemporaryImage;
1930 DicomImage source; 1953 DicomImage source;
1931 std::set<DicomTransferSyntax> allowedSyntaxes; 1954 std::set<DicomTransferSyntax> allowedSyntaxes;
1932 1955
1933 source.AcquireBuffer(dicomContent); 1956 source.SetExternalBuffer(buffer, size);
1934 allowedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit); 1957 allowedSyntaxes.insert(DicomTransferSyntax_LittleEndianExplicit);
1935 1958
1936 if (Transcode(explicitTemporaryImage, source, allowedSyntaxes, true)) 1959 if (Transcode(explicitTemporaryImage, source, allowedSyntaxes, true))
1937 { 1960 {
1938 std::unique_ptr<ParsedDicomFile> file(explicitTemporaryImage.ReleaseAsParsedDicomFile()); 1961 std::unique_ptr<ParsedDicomFile> file(explicitTemporaryImage.ReleaseAsParsedDicomFile());
1939 return file->DecodeFrame(frameIndex); 1962 return file->DecodeFrame(frameIndex);
1940 } 1963 }
1941
1942 }
1943
1944 OrthancConfiguration::ReaderLock lock;
1945 if (lock.GetConfiguration().IsWarningEnabled(Warnings_003_DecoderFailure))
1946 {
1947 LOG(WARNING) << "W003: Unable to decode frame " << frameIndex << " from instance " << publicId;
1948 } 1964 }
1949 1965
1950 return NULL; 1966 return NULL;
1951 } 1967 }
1952 1968
1953 1969
1954 ImageAccessor* ServerContext::DecodeDicomFrame(const DicomInstanceToStore& dicom, 1970 ImageAccessor* ServerContext::DecodeDicomFrame(const DicomInstanceToStore& dicom,
1955 unsigned int frameIndex) 1971 unsigned int frameIndex)
1956 { 1972 {
1957 if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_Before) 1973 return DecodeDicomFrame(dicom.GetParsedDicomFile(),
1958 { 1974 dicom.GetBufferData(),
1959 std::unique_ptr<ImageAccessor> decoded; 1975 dicom.GetBufferSize(),
1960 try 1976 frameIndex);
1961 { 1977
1962 decoded.reset(dicom.DecodeFrame(frameIndex));
1963 }
1964 catch (OrthancException& e)
1965 {
1966 }
1967
1968 if (decoded.get() != NULL)
1969 {
1970 return decoded.release();
1971 }
1972 }
1973
1974 #if ORTHANC_ENABLE_PLUGINS == 1
1975 if (HasPlugins() &&
1976 GetPlugins().HasCustomImageDecoder())
1977 {
1978 std::unique_ptr<ImageAccessor> decoded;
1979 try
1980 {
1981 decoded.reset(GetPlugins().Decode(dicom.GetBufferData(), dicom.GetBufferSize(), frameIndex));
1982 }
1983 catch (OrthancException& e)
1984 {
1985 }
1986
1987 if (decoded.get() != NULL)
1988 {
1989 return decoded.release();
1990 }
1991 else if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After)
1992 {
1993 LOG(INFO) << "The installed image decoding plugins cannot handle an image, "
1994 << "fallback to the built-in DCMTK decoder";
1995 }
1996 }
1997 #endif
1998
1999 if (builtinDecoderTranscoderOrder_ == BuiltinDecoderTranscoderOrder_After)
2000 {
2001 return dicom.DecodeFrame(frameIndex);
2002 }
2003 else
2004 {
2005 return NULL;
2006 }
2007 } 1978 }
2008 1979
2009 1980
2010 ImageAccessor* ServerContext::DecodeDicomFrame(const void* dicom, 1981 ImageAccessor* ServerContext::DecodeDicomFrame(const void* dicom,
2011 size_t size, 1982 size_t size,
2012 unsigned int frameIndex) 1983 unsigned int frameIndex)
2013 { 1984 {
2014 std::unique_ptr<DicomInstanceToStore> instance(DicomInstanceToStore::CreateFromBuffer(dicom, size)); 1985 std::unique_ptr<ParsedDicomFile> instance(new ParsedDicomFile(dicom, size));
2015 return DecodeDicomFrame(*instance, frameIndex); 1986 return DecodeDicomFrame(*instance, dicom, size, frameIndex);
2016 } 1987 }
2017 1988
2018 1989
2019 void ServerContext::StoreWithTranscoding(std::string& sopClassUid, 1990 void ServerContext::StoreWithTranscoding(std::string& sopClassUid,
2020 std::string& sopInstanceUid, 1991 std::string& sopInstanceUid,