diff --git a/source/net/filebot/format/MediaBindingBean.java b/source/net/filebot/format/MediaBindingBean.java index a205380a..9f1ef84b 100644 --- a/source/net/filebot/format/MediaBindingBean.java +++ b/source/net/filebot/format/MediaBindingBean.java @@ -29,7 +29,6 @@ import java.util.Scanner; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; -import java.util.WeakHashMap; import java.util.concurrent.TimeUnit; import java.util.regex.Pattern; @@ -45,6 +44,7 @@ import net.filebot.mediainfo.MediaInfo; import net.filebot.mediainfo.MediaInfo.StreamKind; import net.filebot.similarity.SimilarityComparator; import net.filebot.util.FileUtilities; +import net.filebot.util.WeakValueHashMap; import net.filebot.web.AudioTrack; import net.filebot.web.Episode; import net.filebot.web.EpisodeListProvider; @@ -65,7 +65,6 @@ public class MediaBindingBean { private final File mediaFile; private final Map context; - private String mediaInfoKey; private MediaInfo mediaInfo; private Object metaInfo; @@ -878,7 +877,7 @@ public class MediaBindingBean { } } - private static final Map sharedMediaInfoObjects = new WeakHashMap(64); + private static final Map sharedMediaInfoObjects = new WeakValueHashMap(64); private synchronized MediaInfo getMediaInfo() { // make sure media file is defined @@ -886,25 +885,17 @@ public class MediaBindingBean { // lazy initialize if (mediaInfo == null) { - // lazy initialize - if (mediaInfoKey == null) { - // use inferred media file (e.g. actual movie file instead of subtitle file) - try { - // make sure to create a new String object which can be garbage collected as soon the binding object not used anymore - mediaInfoKey = new String(getInferredMediaFile().getCanonicalPath()); - } catch (IOException e) { - throw new IllegalStateException(e); - } - } + // use inferred media file (e.g. actual movie file instead of subtitle file) + File inferredMediaFile = getInferredMediaFile(); synchronized (sharedMediaInfoObjects) { - mediaInfo = sharedMediaInfoObjects.get(mediaInfoKey); + mediaInfo = sharedMediaInfoObjects.get(inferredMediaFile); if (mediaInfo == null) { MediaInfo mi = new MediaInfo(); - if (!mi.open(new File(new String(mediaInfoKey)))) { - throw new RuntimeException("Cannot open media file: " + mediaInfoKey); + if (!mi.open(inferredMediaFile)) { + throw new RuntimeException("Cannot open media file: " + inferredMediaFile); } - sharedMediaInfoObjects.put(mediaInfoKey, mi); + sharedMediaInfoObjects.put(inferredMediaFile, mi); mediaInfo = mi; } } diff --git a/source/net/filebot/mediainfo/MediaInfo.java b/source/net/filebot/mediainfo/MediaInfo.java index 5053a2ff..2b45ba48 100644 --- a/source/net/filebot/mediainfo/MediaInfo.java +++ b/source/net/filebot/mediainfo/MediaInfo.java @@ -158,6 +158,9 @@ public class MediaInfo implements Closeable { if (handle == null) return; + // DEBUG + // System.out.println("Dispose " + this); + // delete handle MediaInfoLibrary.INSTANCE.Delete(handle); handle = null; diff --git a/source/net/filebot/util/WeakValueHashMap.java b/source/net/filebot/util/WeakValueHashMap.java new file mode 100644 index 00000000..e1424d7c --- /dev/null +++ b/source/net/filebot/util/WeakValueHashMap.java @@ -0,0 +1,128 @@ +package net.filebot.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Set; + +public class WeakValueHashMap extends AbstractMap { + + private HashMap> references; + private ReferenceQueue referenceQueue; + + public WeakValueHashMap(int capacity) { + references = new HashMap>(capacity); + referenceQueue = new ReferenceQueue(); + } + + @Override + public V put(K key, V value) { + processQueue(); + + WeakValue valueRef = new WeakValue(key, value, referenceQueue); + return getReferenceValue(references.put(key, valueRef)); + }; + + @Override + public V get(Object key) { + processQueue(); + + return getReferenceValue(references.get(key)); + } + + @Override + public V remove(Object key) { + return getReferenceValue(references.get(key)); + } + + @Override + public void clear() { + references.clear(); + } + + @Override + public boolean containsKey(Object key) { + processQueue(); + + return references.containsKey(key); + } + + @Override + public boolean containsValue(Object value) { + processQueue(); + + for (Entry> entry : references.entrySet()) { + if (value == getReferenceValue(entry.getValue())) { + return true; + } + } + return false; + } + + @Override + public Set keySet() { + processQueue(); + + return references.keySet(); + } + + @Override + public int size() { + processQueue(); + + return references.size(); + } + + @Override + public Set> entrySet() { + processQueue(); + + Set> entries = new LinkedHashSet>(); + for (Entry> entry : references.entrySet()) { + entries.add(new SimpleImmutableEntry(entry.getKey(), getReferenceValue(entry.getValue()))); + } + + return entries; + } + + public Collection values() { + processQueue(); + + Collection values = new ArrayList(); + for (WeakValue valueRef : references.values()) { + values.add(getReferenceValue(valueRef)); + } + + return values; + } + + private V getReferenceValue(WeakValue valueRef) { + return valueRef == null ? null : valueRef.get(); + } + + private void processQueue() { + WeakValue valueRef; + while ((valueRef = (WeakValue) referenceQueue.poll()) != null) { + references.remove(valueRef.getKey()); + } + } + + private class WeakValue extends WeakReference { + + private final K key; + + private WeakValue(K key, T value, ReferenceQueue queue) { + super(value, queue); + this.key = key; + } + + private K getKey() { + return key; + } + } + +}