/*******************************************************************************
* Copyright (c) 2016 Weasis Team and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nicolas Roduit - initial API and implementation
*******************************************************************************/
package org.weasis.dicom.codec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import org.dcm4che3.data.BulkData;
import org.dcm4che3.data.Fragments;
import org.dcm4che3.data.Tag;
import org.dcm4che3.data.VR;
import org.dcm4che3.util.StreamUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.weasis.core.api.gui.util.AppProperties;
import org.weasis.core.api.media.data.Series;
import org.weasis.core.api.media.data.TagW;
import org.weasis.core.api.util.FileUtil;
import org.weasis.core.api.util.StringUtil;
import org.weasis.dicom.codec.TagD.Level;
public class DicomVideoSeries extends Series<DicomVideoElement> implements FilesExtractor {
private static final Logger LOGGER = LoggerFactory.getLogger(DicomVideoSeries.class);
private int width = 256;
private int height = 256;
public DicomVideoSeries(String subseriesInstanceUID) {
super(TagW.SubseriesInstanceUID, subseriesInstanceUID, DicomSeries.defaultTagView);
}
public DicomVideoSeries(DicomSeries dicomSeries) {
super(TagD.getUID(Level.SERIES), dicomSeries.getTagValue(TagW.SubseriesInstanceUID),
DicomSeries.defaultTagView);
Iterator<Entry<TagW, Object>> iter = dicomSeries.getTagEntrySetIterator();
while (iter.hasNext()) {
Entry<TagW, Object> e = iter.next();
setTag(e.getKey(), e.getValue());
}
}
@Override
public void addMedia(DicomVideoElement media) {
if (media != null && media.getMediaReader() instanceof DicomMediaIO) {
DicomMediaIO dicomImageLoader = (DicomMediaIO) media.getMediaReader();
width = TagD.getTagValue(dicomImageLoader, Tag.Columns, Integer.class);
height = TagD.getTagValue(dicomImageLoader, Tag.Rows, Integer.class);
VR.Holder holder = new VR.Holder();
Object pixdata = dicomImageLoader.getDicomObject().getValue(Tag.PixelData, holder);
if (pixdata instanceof Fragments) {
Fragments fragments = (Fragments) pixdata;
// Should have only 2 fragments: 1) compression marker 2) video stream
// One fragment shall contain the whole video stream.
// see http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_8.2.5.html
for (Object data : fragments) {
if (data instanceof BulkData) {
BulkData bulkData = (BulkData) data;
FileInputStream in = null;
FileOutputStream out = null;
try {
File videoFile = File.createTempFile("video_", ".mpg", AppProperties.FILE_CACHE_DIR); //$NON-NLS-1$ //$NON-NLS-2$
in = new FileInputStream(media.getFile());
out = new FileOutputStream(videoFile);
StreamUtils.skipFully(in, bulkData.offset());
StreamUtils.copy(in, out, bulkData.length());
media.setVideoFile(videoFile);
this.add(media);
return;
} catch (Exception e) {
LOGGER.error("Cannot extract video stream", e); //$NON-NLS-1$
} finally {
FileUtil.safeClose(out);
FileUtil.safeClose(in);
}
}
}
}
}
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
@Override
public String getToolTips() {
StringBuilder toolTips = new StringBuilder("<html>"); //$NON-NLS-1$
addToolTipsElement(toolTips, Messages.getString("DicomSeries.pat"), TagD.get(Tag.PatientName)); //$NON-NLS-1$
addToolTipsElement(toolTips, Messages.getString("DicomSeries.mod"), TagD.get(Tag.Modality)); //$NON-NLS-1$
addToolTipsElement(toolTips, Messages.getString("DicomSeries.series_nb"), TagD.get(Tag.SeriesNumber)); //$NON-NLS-1$
addToolTipsElement(toolTips, Messages.getString("DicomSeries.study"), TagD.get(Tag.StudyDescription)); //$NON-NLS-1$
addToolTipsElement(toolTips, Messages.getString("DicomSeries.series"), TagD.get(Tag.SeriesDescription)); //$NON-NLS-1$
addToolTipsElement(toolTips, Messages.getString("DicomSeries.date"), TagD.get(Tag.SeriesDate)); //$NON-NLS-1$
toolTips.append(Messages.getString("DicomVideo.video_l")); //$NON-NLS-1$
toolTips.append(StringUtil.COLON_AND_SPACE);
Integer speed = TagD.getTagValue(this, Tag.CineRate, Integer.class);
if (speed == null) {
speed = TagD.getTagValue(this, Tag.RecommendedDisplayFrameRate, Integer.class);
if (speed == null) {
speed = 25;
}
}
Integer frames = TagD.getTagValue(this, Tag.NumberOfFrames, Integer.class);
if (frames != null) {
toolTips.append(convertSecondsInTime(frames / speed));
}
toolTips.append("<br>"); //$NON-NLS-1$
toolTips.append("</html>"); //$NON-NLS-1$
return toolTips.toString();
}
private static String convertSecondsInTime(int totalSecs) {
int hours = totalSecs / 3600;
int minutes = (totalSecs % 3600) / 60;
int seconds = totalSecs % 60;
return String.format("%02d:%02d:%02d", hours, minutes, seconds); //$NON-NLS-1$
}
@Override
public String toString() {
return (String) getTagValue(TagW.SubseriesInstanceUID);
}
@Override
public String getMimeType() {
return DicomMediaIO.SERIES_VIDEO_MIMETYPE;
}
@Override
public List<File> getExtractFiles() {
// Should have only one file as all the DicomVideoElement items are split in sub-series
List<File> files = new ArrayList<>();
getMedias(null, null).forEach(dcm -> files.add(dcm.getExtractFile())); // Synchronized iteration with forEach
return files;
}
}