Catch up on video faster

Previously every (internal) update the decoder would advance 0 or 1 frame. Now
it will advance until it catches up. Like before, if it takes too many steps
(5) before catching up, it seeks instead. This should mostly mean seeking
forwards has less latency.

--HG--
branch : minor
This commit is contained in:
Bart van Strien
2017-10-12 15:20:38 +02:00
parent 52ae68b288
commit de945a528b
2 changed files with 56 additions and 59 deletions
+56 -58
View File
@@ -40,7 +40,6 @@ TheoraVideoStream::TheoraVideoStream(love::filesystem::File *file)
, frameReady(false)
, lastFrame(0)
, nextFrame(0)
, lagCounter(0)
{
if (demuxer.findStream() != OggDemuxer::TYPE_THEORA)
throw love::Exception("Invalid video file, video is not theora");
@@ -214,66 +213,65 @@ void TheoraVideoStream::threadedFillBackBuffer(double dt)
if (position < lastFrame)
seekDecoder(position);
// If we're at the end of the stream, or if we're displaying the right frame
// stop here
if (demuxer.isEos() || position < nextFrame)
return;
th_ycbcr_buffer bufferinfo;
th_decode_ycbcr_out(decoder, bufferinfo);
ogg_int64_t granulePosition;
do
// Until we are at the end of the stream, or we are displaying the right frame
unsigned int lagCounter = 0;
while (!demuxer.isEos() && position >= nextFrame)
{
if (demuxer.readPacket(packet))
return;
} while (th_decode_packetin(decoder, &packet, &granulePosition) != 0);
lastFrame = nextFrame;
nextFrame = th_granule_time(decoder, granulePosition);
{
// Don't swap whilst we're writing to the backbuffer
love::thread::Lock l(bufferMutex);
frameReady = false;
}
for (int y = 0; y < backBuffer->yh; ++y)
{
memcpy(backBuffer->yplane+backBuffer->yw*y,
bufferinfo[0].data+
bufferinfo[0].stride*(y+yPlaneYOffset)+yPlaneXOffset,
backBuffer->yw);
}
for (int y = 0; y < backBuffer->ch; ++y)
{
memcpy(backBuffer->cbplane+backBuffer->cw*y,
bufferinfo[1].data+
bufferinfo[1].stride*(y+cPlaneYOffset)+cPlaneXOffset,
backBuffer->cw);
}
for (int y = 0; y < backBuffer->ch; ++y)
{
memcpy(backBuffer->crplane+backBuffer->cw*y,
bufferinfo[2].data+
bufferinfo[2].stride*(y+cPlaneYOffset)+cPlaneXOffset,
backBuffer->cw);
}
// Seeking forwards:
// If we're still not on the right frame, either we're lagging or we're seeking
// After 5 frames, go for a seek. This is not ideal.. but what is
if (position > nextFrame)
{
if (++lagCounter > 5)
// If we can't catch up, seek
if (lagCounter++ > 5)
{
seekDecoder(position);
}
else
lagCounter = 0;
lagCounter = 0;
}
love::thread::Lock l(bufferMutex);
frameReady = true;
th_ycbcr_buffer bufferinfo;
th_decode_ycbcr_out(decoder, bufferinfo);
ogg_int64_t granulePosition;
do
{
if (demuxer.readPacket(packet))
return;
} while (th_decode_packetin(decoder, &packet, &granulePosition) != 0);
lastFrame = nextFrame;
nextFrame = th_granule_time(decoder, granulePosition);
// Don't swap whilst we're writing to the backbuffer
{
love::thread::Lock l(bufferMutex);
frameReady = false;
}
for (int y = 0; y < backBuffer->yh; ++y)
{
memcpy(backBuffer->yplane+backBuffer->yw*y,
bufferinfo[0].data+
bufferinfo[0].stride*(y+yPlaneYOffset)+yPlaneXOffset,
backBuffer->yw);
}
for (int y = 0; y < backBuffer->ch; ++y)
{
memcpy(backBuffer->cbplane+backBuffer->cw*y,
bufferinfo[1].data+
bufferinfo[1].stride*(y+cPlaneYOffset)+cPlaneXOffset,
backBuffer->cw);
}
for (int y = 0; y < backBuffer->ch; ++y)
{
memcpy(backBuffer->crplane+backBuffer->cw*y,
bufferinfo[2].data+
bufferinfo[2].stride*(y+cPlaneYOffset)+cPlaneXOffset,
backBuffer->cw);
}
// Re-enable swapping
{
love::thread::Lock l(bufferMutex);
frameReady = true;
}
}
}
void TheoraVideoStream::fillBackBuffer()
@@ -83,7 +83,6 @@ private:
double lastFrame;
double nextFrame;
unsigned int lagCounter;
void parseHeader();
void seekDecoder(double target);