![JAR search and dependency download from the Maven repository](/logo.png)
org.jcodec.movtool.streaming.ConcurrentMovieRangeService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jcodec Show documentation
Show all versions of jcodec Show documentation
Pure Java implementation of video/audio codecs and formats
package org.jcodec.movtool.streaming;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import org.jcodec.common.NIOUtils;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed
* under FreeBSD License
*
* Retrieves chunks for the range concurrently allowing for concurrent
* transcode-on-the-fly
*
* @author The JCodec project
*
*/
public class ConcurrentMovieRangeService {
private ExecutorService exec;
private VirtualMovie movie;
public ConcurrentMovieRangeService(VirtualMovie movie, int nThreads) {
this.exec = Executors.newFixedThreadPool(nThreads, new ThreadFactory() {
public Thread newThread(Runnable runnable) {
Thread thread = Executors.defaultThreadFactory().newThread(runnable);
thread.setDaemon(true);
return thread;
}
});
this.movie = movie;
}
public void shutdown() {
exec.shutdown();
}
public InputStream getRange(long from, long to) throws IOException {
return new ConcurrentMovieRange(from, to);
}
static class GetCallable implements Callable {
private MovieSegment segment;
public GetCallable(MovieSegment segment) {
this.segment = segment;
}
public ByteBuffer call() throws Exception {
return segment.getData().duplicate();
}
}
public class ConcurrentMovieRange extends InputStream {
private static final int READ_AHEAD_SEGMENTS = 10;
private List> segments = new ArrayList>();
private int nextReadAheadNo;
private long remaining;
private long to;
public ConcurrentMovieRange(long from, long to) throws IOException {
if (to < from)
throw new IllegalArgumentException("from < to");
this.remaining = to - from + 1;
this.to = to;
MovieSegment segment = movie.getPacketAt(from);
if (segment != null) {
nextReadAheadNo = segment.getNo();
scheduleSegmentRetrieve(segment);
for (int i = 0; i < READ_AHEAD_SEGMENTS; i++)
tryReadAhead();
ByteBuffer data = segmentData();
NIOUtils.skip(data, (int) (from - segment.getPos()));
}
}
@Override
public int read(byte[] b, int from, int len) throws IOException {
if (segments.size() == 0 || remaining == 0)
return -1;
len = (int) Math.min(len, remaining);
int totalRead = 0;
while (len > 0 && segments.size() > 0) {
ByteBuffer segmentData = segmentData();
int toRead = Math.min(segmentData.remaining(), len);
segmentData.get(b, from, toRead);
totalRead += toRead;
len -= toRead;
from += toRead;
disposeReadAhead(segmentData);
}
remaining -= totalRead;
return totalRead;
}
private void disposeReadAhead(ByteBuffer segmentData) {
if (!segmentData.hasRemaining()) {
segments.remove(0);
tryReadAhead();
}
}
private void tryReadAhead() {
MovieSegment segment = movie.getPacketByNo(nextReadAheadNo);
if (segment != null && segment.getPos() < to) {
scheduleSegmentRetrieve(segment);
}
}
private void scheduleSegmentRetrieve(MovieSegment segment) {
Future submit = exec.submit(new GetCallable(segment));
segments.add(submit);
nextReadAheadNo++;
}
private ByteBuffer segmentData() throws IOException {
ByteBuffer segmentData;
try {
segmentData = segments.get(0).get();
} catch (InterruptedException e) {
throw new IOException(e);
} catch (ExecutionException e) {
throw new IOException(e);
}
return segmentData;
}
@Override
public void close() throws IOException {
for (Future future : segments) {
future.cancel(false);
}
}
@Override
public int read() throws IOException {
if (segments.size() == 0 || remaining == 0)
return -1;
ByteBuffer segmentData = segmentData();
int ret = segmentData.get() & 0xff;
disposeReadAhead(segmentData);
--remaining;
return ret;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy