package invalid.lena.scrcpy;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
// Bounded encoded-video queue. It never leaves delta frames queued without
// the keyframe that starts their decoder generation.
final class VideoQueue {
static final class Frame {
final byte[] data;
final long ptsUs;
final boolean config;
final boolean keyframe;
Frame(byte[] data, long ptsUs, boolean config, boolean keyframe) {
this.data = data;
this.ptsUs = ptsUs;
this.config = config;
this.keyframe = keyframe;
}
}
private final int maxFrames;
private final int maxBytes;
private final Deque frames;
private int bytes;
private boolean needsKeyframe = true;
VideoQueue(int maxFrames, int maxBytes) {
if (maxFrames < 1 || maxBytes < 1) throw new IllegalArgumentException();
this.maxFrames = maxFrames;
this.maxBytes = maxBytes;
frames = new ArrayDeque<>(maxFrames);
}
boolean offer(Frame frame) {
if (frame.config) {
clear();
return append(frame);
}
if (frame.keyframe) {
removeMediaFrames();
needsKeyframe = false;
if (append(frame)) return true;
needsKeyframe = true;
return false;
}
if (needsKeyframe) return false;
if (append(frame)) return true;
needsKeyframe = true;
return false;
}
Frame poll() {
Frame frame = frames.pollFirst();
if (frame != null) bytes -= frame.data.length;
return frame;
}
boolean isEmpty() {
return frames.isEmpty();
}
boolean needsKeyframe() {
return needsKeyframe;
}
void clear() {
frames.clear();
bytes = 0;
needsKeyframe = true;
}
private boolean append(Frame frame) {
if (frames.size() >= maxFrames || frame.data.length > maxBytes - bytes) {
return false;
}
frames.offerLast(frame);
bytes += frame.data.length;
return true;
}
private void removeMediaFrames() {
for (Iterator it = frames.iterator(); it.hasNext(); ) {
Frame frame = it.next();
if (!frame.config) {
it.remove();
bytes -= frame.data.length;
}
}
}
}