Mercurial > hg > orthanc
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, |