Stream Loader Theory
part of Media Player 128
Copyright (c) Robert Willie, 2010, 2011


Overview:
The file demultiplexer (demuxer) is an interface co-ordinator,
primarily between a device driver and one or more codecs.
The demuxer must also interface with a generic IRQ and main thread.
Its main function is to ensure file data is accurately loaded
into the correct memory area(s), at the correct time, and that
the codec(s) are notified of completion.

Each memory region is referred to as a buffer in system memory
and as a stream in the file data.  Packet headers in the file data
are normally used to identify which stream the following data belongs,
and thus where to load the data and which codec is responsible for it.

The demuxer natively supports two types of streams, those for linear
buffers (often not called a buffer), and those for circular buffers.
It also defines two default streams: the demux stream (linear type),
and the junk stream (circular type).  The demux stream is used for packet headers,
and the junk stream is for any data the file codec does not want to process.

The demuxer is generic, so is not as fast as possible,
but is simpler than writting and debugging every possible
combination of hardware + codec(s).  Thus it makes new device drivers
and codecs easy to add.  As long as stream splitting is not
very frequent (is < 1 / 256 bytes), the generic penalty is negligable.
There are a couple of options to choose when this is not the case.
The generic approach also means the demuxer can be used to
load a file that is not composed of multiple streams, or that
has multiple streams that are not identified by packet headers.

Flowchart (simplified):
	Demux init (parser) >----------->----------------->-----+
                                                                |
        Play init (file codec) >-------->-----------------+     |
                                                          |     |
+-----> Multi-packet ? (demux) >-------->(no)-------------+     |
|               |                                         |     |
|             (yes)                                       V     V
|               |                                         |     |
|               V                                         |     |
|       Bump packet index (demux)                         |     |
^               |                                         |     |
|               V                                         |     |
|   +-- More packets ? (demux)                            V     V
|   |           |                                         |     |
|  (yes)       (no)                                       |     |
|   |           |                                         |     |
|   |           V                                         |     |
^   |   Reset packet index (demux)                        |     |
|   |           |                                         |     |
|   |           V                                         |     |
|   |   Stream = 0 to get packet header (demux) <---------+     V
|   |           |                                               |
|   |           V                                               |
^   |   Packet stream init (demux)      <-----------------+--<--+
|   |           |                                         |
|   |           V                                         ^
|   +-> Packet loader init (demux)                        |
|               |                                         |
|               +---> Check Start (codec) * <-------------|-----+
|                     /       |     \                     |     |
^                    /        |      \                    ^     ^
|                   /         |       \                   |     |
|                 |/          V        \|                 |     |
|       Linear check    Circular check  Custom check      |     |
|                  \          |        /                  |     |
|                   \         |       /                   |     |
^                    \        |      /                    ^     ^
|                     \|      V    |/                     |     |
|                       Run Mode (loader) **              |     |
|                             |                           |     |
|                             V                           |     |
|               +---->  Get data (loader)                 |     |
|               |             |                           |     |
^               +--(no)---   all?                         ^     ^
|                             |                           |     |
|                             V                           |     |
|                       Halt Mode (loader)                |     |
|                             |                           |     |
|                             V                           |     |
^                       Got packet (codec)                ^     ^
|                     /       |     \                     |     |
|                    /        |      \                    |     |
|                   /         |       \                   |     |
|                 |/          V        \|                 |     |
|       Linear Got     Circular Got  Custom Got           |     |
|               |             |         |                 ^     ^
+----------<----+------<------+      (demux example)      |     |
                                        |                 |     |
                                        V                 |     |
                                     Identify stream >----+     |
                                                                |
        * Check start fail (codec)                              ^
                |                                               |
                V                                               |
        Wait Mode (loader)                                      |
                |                                               |
                V                                               |
        CommonRTI (demux)                                       ^
                ^                                               |
                |                                               |
               (no)                                             |
                |                                               |
        Check pause (loader) ----------->(yes)------------------+
                ^
                |
        (IRQ or file codec)

	** Note that Run Mode (loader) normally does not directly jump to next routine
        as shown in the diagram, but instead sets flags for loader IRQ
        and then jumps to CommonRTI (demux)


Stream Interface Parameters:
stream		ID	Start		Packet		tail		end		start
-----------------------------------------------------------------------------------------------------
0 (demux)	(none)	ldrOn		demuxHdrTest	MuxBuf(always)	MuxBuf+size	MuxBuf
2 (junk)	(other)	demuxWrapTest	gotGenericWrap	JunkBuf(init)	JunkBuf+size	JunkBuf
4 codec s1	custom	custom		custom		buf s1(init)	buf s1 end+1	buf s1 start
6 codec s2	custom	custom		custom		buf s2(init)	buf s2 end+1	buf s2 start
...

File Codec Interface:
Setup Loader and IRQ. Set LoaderOn vector and stream parameters (4, 6, etc.) for demuxer.
If custom packet headers, replace 'demuxTest' vector for stream 0.  Jump to demuxGetPktHdr.

For file header parsing (before file codec is known):
Setup generic loader, IRQ should be off.  Set desired data size <= junkBuf into pkt.siz,
setup junk.packetGot vector, ldx #2 (junk buffer), jump demux.ReadStream


Demux/Loader Psudo Code:

demuxTest: (generic)
	note 'muxBuf+2' <-> 'pkt.siz'
la != ea
	a=err_logic; jump TheEnd
ldx #4
demuxTestLoop:
lda muxBuf
cmp streamID,x
bne demuxNext
lda muxBuf+1
cmp streamID+1,x
beq demuxFound
demuxNext:
inx
inx
cpx strmLim
bcc demuxTestLoop
ldx #2	;junk
bne demuxFound

gotPacket: (e.g.)
demux.part == 0
	set flags / vars based on 'la'...
jmp gotGenericWrap

gotGeneric:
la != ea
	a=err_logic; jump TheEnd
else
	jmp demuxMore

gotGenericWrap:
la != ea
	a=err_logic; jump TheEnd
tail[strm] == end[strm]
	start[strm] -> la
la -> tail[strm]
demux.part != 0
	jmp demuxLoop

demuxMore:
jmp demuxGetPktHdr	(disable for multi-packet)
muxIndex += 4
muxIndex < muxEnd
	muxBuf[muxIndex+2] -> pkt.siz
	muxBuf[muxIndex] -> la
	jmp demuxLoop
4 -> muxEnd
0 -> muxIndex

demuxGetPktHdr:
4 -> pkt.siz
0 -> .x

DemuxFound: (.x = stream index)
tail[strm]->la (tail[0] always muxBuff+0 for demuxer)
codecStart[strm] -> testStart
codecPacket[strm] -> gotPacket
stx strm
jmp demuxLoop


demuxLoop:
pk.siz->len
la+len->ea
ea - end[strm] -> pk.siz
demux.part = pk.siz > 0
jmp (testStart)
{e.g.,
	la > head[strm] || ea <= head[strm] 
		jmp demuxWrapTest
	jmp ldrPause -> ... jmp demuxRTI
}
demuxWrapTest:
demux.part == 1
	end[strm]->ea
	ea-la -> len
jmp ldrOn

demuxNoWrap:
demux.part == 1
	a=data_err; jmp TheEnd
jmp ldrOn
	
ldrOn: (e.g.)
la -> code
ldrOn2:
ldr.len = max(ldr.sectRemain,len)
len -= ldr.len
ldr.sectRemain -= ldr.len
ldr.state = run
jmp demuxRTI

ldrFin: (e.g.)
ldr.state = stop
ldr.sectRemain == 0
	sect.remain = max
len > 0
	jmp ldrOn2
code -> la
jmp (gotPacket)


------------------------
compare old:
	stx pckTyp+1	;set packet type
	lda tails-2,x	;get current tail (load address) low
	sta sAdr
	lda tails-2+1,x	;load address high
	sta sAdr+1
	lda bLimit-2,x	;buff #pages
	sta bSize
	lda bLimit-2+1,x
	sta bEnd	;buffer end page
	cpx #PCKT_JUNK
	beq okSize	;no size checking of junk
	sec
	sbc bStart	;less buff start = buff size
	cmp muxBuff+3	;test payload size
	bcc CirErr	;buffer to small

		;Circular buffer -- calc end adrs so on next pass we can
		; 1. update buffer tail
		; 2. continue loading (if buffer wrap)
	lda packLen	;len low
	adc sAdr	;calc end low
	sta eAdr	;next pass len low, if needed
	lda packLen+1	;len high
	adc sAdr+1	;calc end high
;	rol wFlag	;overflow
	sec
	sbc bEnd	;limit high
;	sta eAdr+1	;remainder high, if needed
;	lda wFlag	;overflow plus junk
;	and #1		;overflow
;	sbc #0
	bcc setWflag
	sta eAdr+1	;remainder high, if needed
;	ora eAdr+1
	ora eAdr	;remainder low
	cmp #1		;test any remainder (wrap needed)
setWflg	ror wFlag	
	bpl ChkMndx	;no wrap, continue
	sec
.)
fixWrap		;change length so data ends at buffer limit
		;also update end address to match
		;update muxBuff so we get remainder on next pass
	lda #0		;page-aligned buffer
	sbc sAdr	;this start adrs low
	sta packLen	;this length low
	lda bEnd	;end of buffer
	sbc sAdr+1	;this start adrs high
	sta packLen+1	;this length high
		;note Carry Set so we re-use muxBuff next pass

ChkMndx		;update muxBuff index, unless packet split
	bcs muxEnd	;split packet, so index will be re-used next pass
	txa		;normal (unsplit)... update index to loader packets
	adc #4		;size of loader packet (also file packet headers)
	sta muxHead

-----
	lda m3o2t,x	;4
	sta bra+1	;4
	sta bra2+1	;4
	bne tab		;3
	jmp xxx		;3
	
	