Skip to content

Commit

Permalink
Use vanilla FutureTask for file decoding loops
Browse files Browse the repository at this point in the history
  • Loading branch information
ultraq committed Jan 29, 2024
1 parent d024ba9 commit 5446c1f
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

package nz.net.ultraq.redhorizon.classic.filetypes

import nz.net.ultraq.redhorizon.async.ControlledLoop
import nz.net.ultraq.redhorizon.classic.codecs.IMAADPCM16bit
import nz.net.ultraq.redhorizon.classic.codecs.WSADPCM8bit
import nz.net.ultraq.redhorizon.events.EventTarget
import nz.net.ultraq.redhorizon.filetypes.FileExtensions
import nz.net.ultraq.redhorizon.filetypes.SoundFile
import nz.net.ultraq.redhorizon.filetypes.Streaming
Expand Down Expand Up @@ -122,7 +122,7 @@ class AudFile implements SoundFile, Streaming {
@Override
Worker getStreamingDataWorker() {

return new AudFileWorker()
return new Worker(new AudFileDecoder())
}

@Override
Expand All @@ -145,12 +145,9 @@ class AudFile implements SoundFile, Streaming {
}

/**
* A worker for decoding AUD file sound data.
* Decode AUD file sound data and emit as {@link StreamingSampleEvent}s.
*/
class AudFileWorker extends Worker {

@Delegate
private ControlledLoop workLoop
class AudFileDecoder implements Runnable, EventTarget {

@Override
void run() {
Expand All @@ -162,7 +159,7 @@ class AudFile implements SoundFile, Streaming {

// Decompress the aud file data by chunks
def headerSize = input.bytesRead
workLoop = new ControlledLoop({ input.bytesRead < headerSize + compressedSize }, { ->
while (input.bytesRead < headerSize + compressedSize && !Thread.interrupted()) {
def sample = average('Decoding sample', 1f, logger) { ->

// Chunk header
Expand All @@ -177,8 +174,8 @@ class AudFile implements SoundFile, Streaming {
)
}
trigger(new StreamingSampleEvent(sample))
})
workLoop.run()
Thread.sleep(20)
}

logger.debug('Decoding complete')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

package nz.net.ultraq.redhorizon.classic.filetypes

import nz.net.ultraq.redhorizon.async.ControlledLoop
import nz.net.ultraq.redhorizon.classic.codecs.IMAADPCM16bit
import nz.net.ultraq.redhorizon.classic.codecs.LCW
import nz.net.ultraq.redhorizon.classic.codecs.WSADPCM8bit
import nz.net.ultraq.redhorizon.events.EventTarget
import nz.net.ultraq.redhorizon.filetypes.ColourFormat
import nz.net.ultraq.redhorizon.filetypes.FileExtensions
import nz.net.ultraq.redhorizon.filetypes.Palette
Expand Down Expand Up @@ -215,7 +215,7 @@ class VqaFile implements VideoFile {
@Override
Worker getStreamingDataWorker() {

return new VqaFileWorker()
return new Worker(new VqaFileDecoder())
}

/**
Expand All @@ -234,9 +234,10 @@ class VqaFile implements VideoFile {
}

/**
* A worker for decoding VQA file video data.
* Decode VQA file frame and sound data and emit as {@link StreamingFrameEvent}s
* and {@link StreamingSampleEvent}s respectively.
*/
class VqaFileWorker extends Worker {
class VqaFileDecoder implements Runnable, EventTarget {

private final LCW lcw = new LCW()
private final Decoder audioDecoder
Expand All @@ -247,13 +248,10 @@ class VqaFile implements VideoFile {
private final int modifier
private final int numBlocks

@Delegate
private ControlledLoop workLoop

/**
* Constructor, create a new worker for decoding the VQA video data.
*/
VqaFileWorker() {
VqaFileDecoder() {

audioDecoder = bits == 16 ? new IMAADPCM16bit() : new WSADPCM8bit()

Expand Down Expand Up @@ -370,7 +368,7 @@ class VqaFile implements VideoFile {
}

// Header + Offsets
workLoop = new ControlledLoop({ input.bytesRead < formLength }, { ->
while (input.bytesRead < formLength && !Thread.interrupted()) {
def chunkHeader = new VqaChunkHeader(input)

switch (chunkHeader.name) {
Expand Down Expand Up @@ -439,8 +437,8 @@ class VqaFile implements VideoFile {
}

discardNullByte()
})
workLoop.run()
Thread.sleep(25)
}

logger.debug('Decoding complete')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@

package nz.net.ultraq.redhorizon.classic.filetypes

import nz.net.ultraq.redhorizon.async.ControlledLoop
import nz.net.ultraq.redhorizon.classic.codecs.LCW
import nz.net.ultraq.redhorizon.classic.codecs.XORDelta
import nz.net.ultraq.redhorizon.events.EventTarget
import nz.net.ultraq.redhorizon.filetypes.AnimationFile
import nz.net.ultraq.redhorizon.filetypes.ColourFormat
import nz.net.ultraq.redhorizon.filetypes.FileExtensions
Expand Down Expand Up @@ -138,7 +138,7 @@ class WsaFile implements AnimationFile, Streaming {
@Override
Worker getStreamingDataWorker() {

return new WsaFileWorker()
return new Worker(new WsaFileDecoder())
}

/**
Expand All @@ -156,12 +156,9 @@ class WsaFile implements AnimationFile, Streaming {
}

/**
* A worker for decoding WSA file frame data.
* Decode WSA file frame data and emit as {@link StreamingFrameEvent}s.
*/
class WsaFileWorker extends Worker {

@Delegate
private ControlledLoop workLoop
class WsaFileDecoder implements Runnable, EventTarget {

@Override
void run() {
Expand All @@ -175,7 +172,7 @@ class WsaFile implements AnimationFile, Streaming {

// Decode frame by frame
def frame = 0
workLoop = new ControlledLoop({ frame < numFrames }, { ->
while (frame < numFrames && !Thread.interrupted()) {
def colouredFrame = average('Decoding frame', 1f, logger) { ->
def indexedFrame = xorDelta.decode(
lcw.decode(
Expand All @@ -188,8 +185,8 @@ class WsaFile implements AnimationFile, Streaming {
}
trigger(new StreamingFrameEvent(colouredFrame))
frame++
})
workLoop.run()
Thread.sleep(50)
}

logger.debug('Decoding complete')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class Animation implements GraphicsElement, Playable, SceneElement<Animation>, T
animationFile.frameRate as int,
animationFile instanceof Streaming ? animationFile.streamingDataWorker : null)

Executors.newSingleThreadExecutor().execute(animationDataWorker)
Executors.newVirtualThreadPerTaskExecutor().execute(animationDataWorker)
}

/**
Expand Down Expand Up @@ -129,7 +129,7 @@ class Animation implements GraphicsElement, Playable, SceneElement<Animation>, T
@Override
void delete(GraphicsRenderer renderer) {

animationDataWorker.stop()
animationDataWorker.cancel(true)
frames.drain()
renderer.deleteMesh(mesh)
textures.each { texture ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
/*
* Copyright 2007, Emanuel Rabina (http://www.ultraq.net.nz/)
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand Down Expand Up @@ -70,7 +70,7 @@ class SoundTrack implements AudioElement, Playable, SceneElement, Temporal {
this(soundFile.bits, soundFile.channels, soundFile.frequency,
soundFile instanceof Streaming ? soundFile.streamingDataWorker : null)

Executors.newSingleThreadExecutor().execute(soundDataWorker)
Executors.newVirtualThreadPerTaskExecutor().execute(soundDataWorker)
}

/**
Expand Down Expand Up @@ -107,7 +107,7 @@ class SoundTrack implements AudioElement, Playable, SceneElement, Temporal {
@Override
void delete(AudioRenderer renderer) {

soundDataWorker.stop()
soundDataWorker.cancel(true)
samples.drain()
renderer.deleteSource(sourceId)
renderer.deleteBuffers(bufferIds as int[])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import nz.net.ultraq.redhorizon.engine.input.KeyEvent
import nz.net.ultraq.redhorizon.engine.media.AnimationLoader
import nz.net.ultraq.redhorizon.engine.media.ImageLoader
import nz.net.ultraq.redhorizon.engine.media.ImagesLoader
import nz.net.ultraq.redhorizon.engine.media.MediaLoader
import nz.net.ultraq.redhorizon.engine.media.Playable
import nz.net.ultraq.redhorizon.engine.media.ResourceLoader
import nz.net.ultraq.redhorizon.engine.media.SoundLoader
import nz.net.ultraq.redhorizon.engine.media.VideoLoader
import nz.net.ultraq.redhorizon.filetypes.AnimationFile
Expand Down Expand Up @@ -64,7 +64,7 @@ class Explorer extends Application {
private File currentDirectory
private InputStream selectedFileInputStream
private Object selectedFile
private ResourceLoader selectedLoader
private MediaLoader selectedLoader
private Palette palette

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
/*
* Copyright 2019, Emanuel Rabina (http://www.ultraq.net.nz/)
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -18,11 +18,11 @@ package nz.net.ultraq.redhorizon.filetypes

/**
* Certain files are better read by streaming their data out rather than
* obtaining it all in one go, usually for the purpose of saving memory that
* will be freed-up anyway. This interface provides the ability for files to
* expose that streaming data through {@link Worker} classes that can be started
* and listened to from the by the consuming thread.
*
* obtaining it all in one go, usually for the purpose of saving memory. This
* interface provides the ability for files to expose that streaming data
* through {@link Worker} classes that can be started and listened to by a
* consuming thread.
*
* @author Emanuel Rabina
*/
interface Streaming {
Expand All @@ -31,7 +31,7 @@ interface Streaming {
* Returns a worker that can be used for streaming file data. Workers can be
* listened to for events that contain data in useful portions that are usable
* by some kind of consumer.
*
*
* @return
* A worker that can be executed as its own thread for generating the
* streaming data.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
/*
/*
* Copyright 2019, Emanuel Rabina (http://www.ultraq.net.nz/)
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Expand All @@ -16,15 +16,28 @@

package nz.net.ultraq.redhorizon.filetypes

import nz.net.ultraq.redhorizon.async.RunnableWorker
import nz.net.ultraq.redhorizon.events.Event
import nz.net.ultraq.redhorizon.events.EventTarget

import java.util.concurrent.FutureTask

/**
* A special {@link Runnable} for decoding file data and emitting the results as
* events. Workers can be stopped using the standard {@code Future.cancel}
* method, and worker implementations must respect these controls.
*
* A special kind of {@code RunnableFuture} for decoding file data and emitting
* the results as events. Workers can be stopped using the standard
* {@code Future.cancel} method, and worker implementations must respect these
* controls.
*
* @author Emanuel Rabina
*/
abstract class Worker implements EventTarget, RunnableWorker {
class Worker extends FutureTask<Void> implements EventTarget {

/**
* Constructor, set the work loop.
*/
Worker(Runnable runnable) {

super(runnable, null)
assert runnable instanceof EventTarget
runnable.relay(Event, this)
}
}

0 comments on commit 5446c1f

Please sign in to comment.