From de945a528be7b2b1dd7f082d1d540f07f06bb9fe Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Thu, 12 Oct 2017 15:20:38 +0200 Subject: [PATCH] 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 --- .../video/theora/TheoraVideoStream.cpp | 114 +++++++++--------- src/modules/video/theora/TheoraVideoStream.h | 1 - 2 files changed, 56 insertions(+), 59 deletions(-) diff --git a/src/modules/video/theora/TheoraVideoStream.cpp b/src/modules/video/theora/TheoraVideoStream.cpp index 4410ecb34..3cffa12cc 100644 --- a/src/modules/video/theora/TheoraVideoStream.cpp +++ b/src/modules/video/theora/TheoraVideoStream.cpp @@ -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() diff --git a/src/modules/video/theora/TheoraVideoStream.h b/src/modules/video/theora/TheoraVideoStream.h index 63e494a84..587342ae9 100644 --- a/src/modules/video/theora/TheoraVideoStream.h +++ b/src/modules/video/theora/TheoraVideoStream.h @@ -83,7 +83,6 @@ private: double lastFrame; double nextFrame; - unsigned int lagCounter; void parseHeader(); void seekDecoder(double target);