package org.jcodec.movtool.streaming.tracks;
import java.lang.IllegalStateException;
import java.lang.System;
import java.lang.IllegalArgumentException;
import org.jcodec.movtool.streaming.CodecMeta;
import org.jcodec.movtool.streaming.VirtualPacket;
import org.jcodec.movtool.streaming.VirtualTrack;
import java.io.IOException;
import java.lang.Runnable;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* A proxy track that maintains in-memory cache of recently read packets
*
* @author The JCodec project
*
*/
public class CachingTrack implements VirtualTrack {
private VirtualTrack src;
private List<CachingPacket> cachedPackets;
private ScheduledFuture<?> policyFuture;
public CachingTrack(VirtualTrack src, final int policy, ScheduledExecutorService policyExecutor) {
this.cachedPackets = Collections.synchronizedList(new ArrayList<CachingPacket>());
if (policy < 1)
throw new IllegalArgumentException("Caching track with less then 1 entry.");
this.src = src;
final CachingTrack self = this;
policyFuture = policyExecutor.scheduleAtFixedRate(new Runnable() {
public void run() {
while (self.cachedPackets.size() > policy) {
self.cachedPackets.get(0).wipe();
}
}
}, 200, 200, TimeUnit.MILLISECONDS);
}
@Override
public CodecMeta getCodecMeta() {
return src.getCodecMeta();
}
@Override
public VirtualPacket nextPacket() throws IOException {
VirtualPacket pkt = src.nextPacket();
if (pkt == null)
return null;
return new CachingPacket(this, pkt);
}
public static class CachingPacket extends VirtualPacketWrapper {
private ByteBuffer cache;
private CachingTrack track;
public CachingPacket(CachingTrack track, VirtualPacket src) {
super(src);
this.track = track;
}
public synchronized void wipe() {
if (track.cachedPackets.indexOf(this) == 0) {
track.cachedPackets.remove(0);
cache = null;
}
}
public synchronized ByteBuffer getData() throws IOException {
// This packet will receive new place _in the queue
track.cachedPackets.remove(this);
if (cache == null) {
cache = src.getData();
}
track.cachedPackets.add(this);
return cache == null ? null : cache.duplicate();
}
}
@Override
public void close() throws IOException {
if (policyFuture != null)
policyFuture.cancel(false);
cachedPackets.clear();
src.close();
}
@Override
public VirtualEdit[] getEdits() {
return src.getEdits();
}
@Override
public int getPreferredTimescale() {
return src.getPreferredTimescale();
}
}