Commit 480f992e authored by Gregory Maxwell's avatar Gregory Maxwell Committed by ogg.k.ogg.k
Browse files

Completes handling of drop frames; preserves timing.

Avoids displaying duplicate frames, except once per second.
parent e08167a4
......@@ -65,45 +65,47 @@ public class State
pbi.DecoderErrorCode = 0;
pbi.opb.readinit(op.packet_base, op.packet, op.bytes);
/* verify that this is a video frame */
ret = pbi.opb.readB(1);
if (ret==0) {
try {
ret=dec.loadAndDecode();
} catch(Exception e) {
/* If lock onto the bitstream is lost all sort of Exceptions can occur.
* The bitstream damage may be local, so the next packet may be okay. */
e.printStackTrace();
return Result.BADPACKET;
}
if (op.bytes>0) {
pbi.opb.readinit(op.packet_base, op.packet, op.bytes);
/* verify that this is a video frame */
ret = pbi.opb.readB(1);
if (ret==0) {
try {
ret=dec.loadAndDecode();
} catch(Exception e) {
/* If lock onto the bitstream is lost all sort of Exceptions can occur.
* The bitstream damage may be local, so the next packet may be okay. */
e.printStackTrace();
return Result.BADPACKET;
}
if(ret != 0)
return (int) ret;
if(ret != 0)
return (int) ret;
if(op.granulepos>-1)
granulepos=op.granulepos;
else{
if(granulepos==-1){
granulepos=0;
}
else {
if (pbi.FrameType == Constants.BASE_FRAME){
long frames= granulepos & ((1<<pbi.keyframe_granule_shift)-1);
granulepos>>=pbi.keyframe_granule_shift;
granulepos+=frames+1;
granulepos<<=pbi.keyframe_granule_shift;
}else
granulepos++;
}
} else {
return Result.BADPACKET;
}
return(0);
}
}
if(op.granulepos>-1)
granulepos=op.granulepos;
else{
if(granulepos==-1){
granulepos=0;
}
else {
if ((op.bytes>0) && (pbi.FrameType == Constants.BASE_FRAME)){
long frames= granulepos & ((1<<pbi.keyframe_granule_shift)-1);
granulepos>>=pbi.keyframe_granule_shift;
granulepos+=frames+1;
granulepos<<=pbi.keyframe_granule_shift;
}else
granulepos++;
}
}
return Result.BADPACKET;
return(0);
}
public int decodeYUVout (YUVBuffer yuv)
......
......@@ -38,6 +38,7 @@ public class Buffer {
public long time_offset;
public long timestamp;
public long timestampEnd;
public boolean duplicate = false;
public static Buffer create() {
Buffer result;
......
......@@ -34,8 +34,10 @@ public class TheoraDec extends Element implements OggPayload
private Packet op;
private int packet;
private YUVBuffer yuv;
private java.lang.Object last_yuv_obj;
private long lastTs;
private long lastnondupe = -1;
private boolean needKeyframe;
private boolean haveBOS = false;
private boolean haveDecoder = false;
......@@ -197,18 +199,6 @@ public class TheoraDec extends Element implements OggPayload
return OK;
}
else {
if (op.bytes == 0) {
Debug.log(Debug.DEBUG, "duplicate frame");
return OK;
}
if ((op.packet_base[op.packet] & 0x80) == 0x80) {
Debug.log(Debug.INFO, "ignoring header");
return OK;
}
if (needKeyframe && ts.isKeyframe(op)) {
needKeyframe = false;
}
if (timestamp != -1) {
lastTs = timestamp;
}
......@@ -220,18 +210,41 @@ public class TheoraDec extends Element implements OggPayload
timestamp = lastTs;
}
if (op.bytes > 0) {
if ((op.packet_base[op.packet] & 0x80) == 0x80) {
Debug.log(Debug.INFO, "ignoring header");
return OK;
}
if (needKeyframe && ts.isKeyframe(op)) {
needKeyframe = false;
}
} else {
Debug.log(Debug.DEBUG, "duplicate frame");
}
if (!needKeyframe) {
try{
if (ts.decodePacketin(op) != 0) {
Debug.log(Debug.ERROR, "Bad Theora packet. Most likely not fatal, hoping for better luck next packet.");
}
if (ts.decodeYUVout(yuv) != 0) {
buf.free();
postMessage (Message.newError (this, "Error getting the Theora picture"));
Debug.log(Debug.ERROR, "Error getting the picture.");
return ERROR;
if (op.bytes > 0 ) {
if (ts.decodeYUVout(yuv) != 0) {
buf.free();
postMessage (Message.newError (this, "Error getting the Theora picture"));
Debug.log(Debug.ERROR, "Error getting the picture.");
return ERROR;
}
buf.duplicate = false;
lastnondupe = timestamp;
last_yuv_obj = yuv.getObject(ti.offset_x, ti.offset_y, ti.frame_width, ti.frame_height);
} else {
if (timestamp-lastnondupe>=Clock.SECOND) {
buf.duplicate = false;
lastnondupe = timestamp;
} else
buf.duplicate = true;
}
buf.object = yuv.getObject(ti.offset_x, ti.offset_y, ti.frame_width, ti.frame_height);
buf.object = last_yuv_obj;
buf.caps = caps;
buf.timestamp = timestamp;
Debug.log( Debug.DEBUG, parent.getName() + " >>> " + buf );
......
......@@ -83,64 +83,65 @@ public class VideoSink extends Sink
Image image;
int x, y, w, h;
Debug.log( Debug.DEBUG, this.getName() + " starting buffer " + buf );
if (!buf.duplicate) {
Debug.log( Debug.DEBUG, this.getName() + " starting buffer " + buf );
if (buf.object instanceof ImageProducer) {
image = component.createImage((ImageProducer)buf.object);
}
else if (buf.object instanceof Image) {
image = (Image)buf.object;
}
else {
System.out.println(this+": unknown buffer received "+buf);
return Pad.ERROR;
}
if (!component.isVisible())
return Pad.NOT_NEGOTIATED;
Graphics graphics = component.getGraphics();
if (keepAspect) {
double src_ratio, dst_ratio;
if (bounds == null) {
bounds = new Rectangle(component.getSize());
if (buf.object instanceof ImageProducer) {
image = component.createImage((ImageProducer)buf.object);
}
else if (buf.object instanceof Image) {
image = (Image)buf.object;
}
else {
System.out.println(this+": unknown buffer received "+buf);
return Pad.ERROR;
}
src_ratio = (double) width / height;
dst_ratio = (double) bounds.width / bounds.height;
if (src_ratio > dst_ratio) {
w = bounds.width;
h = (int) (bounds.width / src_ratio);
x = bounds.x;
y = bounds.y + (bounds.height - h) / 2;
} else if (src_ratio < dst_ratio) {
w = (int) (bounds.height * src_ratio);
h = bounds.height;
if (!component.isVisible())
return Pad.NOT_NEGOTIATED;
Graphics graphics = component.getGraphics();
if (keepAspect) {
double src_ratio, dst_ratio;
if (bounds == null) {
bounds = new Rectangle(component.getSize());
}
src_ratio = (double) width / height;
dst_ratio = (double) bounds.width / bounds.height;
if (src_ratio > dst_ratio) {
w = bounds.width;
h = (int) (bounds.width / src_ratio);
x = bounds.x;
y = bounds.y + (bounds.height - h) / 2;
} else if (src_ratio < dst_ratio) {
w = (int) (bounds.height * src_ratio);
h = bounds.height;
x = bounds.x + (bounds.width - w) / 2;
y = bounds.y;
} else {
x = bounds.x;
y = bounds.y;
w = bounds.width;
h = bounds.height;
}
} else if (!scale) {
w = Math.min (width, bounds.width);
h = Math.min (height, bounds.height);
x = bounds.x + (bounds.width - w) / 2;
y = bounds.y;
y = bounds.y + (bounds.height - h) / 2;
} else {
x = bounds.x;
y = bounds.y;
/* draw in available area */
w = bounds.width;
h = bounds.height;
x = 0;
y = 0;
}
} else if (!scale) {
w = Math.min (width, bounds.width);
h = Math.min (height, bounds.height);
x = bounds.x + (bounds.width - w) / 2;
y = bounds.y + (bounds.height - h) / 2;
} else {
/* draw in available area */
w = bounds.width;
h = bounds.height;
x = 0;
y = 0;
graphics.drawImage (image, x, y, w, h, null);
Debug.log( Debug.DEBUG, this.getName() + " done with buffer " + buf );
}
graphics.drawImage (image, x, y, w, h, null);
Debug.log( Debug.DEBUG, this.getName() + " done with buffer " + buf );
return Pad.OK;
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment