                    ARMovie Colour Services
                    =======================

Introduction
------------

To allow for direct upgrade to the source colour model of ARMovie files, there
is an interface between the Player program and the colour mapping programs.
This means that the colour mapping programs can be upgraded in (say) speed or
memory allocation method, or new colour spaces can be added.

A colour service provides mapping resources for various screen modes:

1, 2, 4, 8, 16 and 32 bits per pixel

with the following pixel shapes:

1x1, 2x1 packed, 2x1 unpacked, 2x2

(the output is spread over 1, 2 or 4 pixels which comprise at most 1 word of
table space)

the output screen mode is the current one. A global flag (ARMovie$4Colour)
defines whether 4 bit per pixel screen modes are to be processed in colour - 1
and 2 bit per pixel ones never are.

In 32 bit per pixel destination screen modes, two methods of operation are
possible: to generate a colour map which is a simple table as for the other
screen modes, or to make a colour map which must be summed to produce the
RGB value.

The interface as seen by the Player program
===========================================

The Player program has read the source ARMovie file and thus is aware of:

- the declared source bits per pixel value (8, 16, 24)

- the declared source colour space (e.g. RGB, YUV or [xxx])
  - if creating your own colour space, please register the name with Acorn
    to prevent clashes...

- a PALETTE entry - currently only specified when the pixel depth is 8

- the destination bits per pixel and pixel shape

It will call a colour service program by using the source colour space and
source bits per pixel value to call a program with destination characteristics
as parameters. The source colour space and bits per pixel value are resolved to
a file within a directory inside the ARMovie resource:

<ARMovie$Dir>.MovingLine.ColourMap.<colour space><source bits per pixel>

For a typical Moving Blocks movie, this would result in:

<ARMovie$Dir>.MovingLine.ColourMap.YUV16

being the called program.

Player passes to this program the values/addresses of interest, either as
parameter strings or as decimal addresses - in the case of the PALETTE type,
Player provides the address of a 256*3 block of RGB byte values.

The parameter string is:

mag value (pixels of output) (1, 2 or 4): m<pix>

number of colours in destination -1: n<bpp>
(values: 1, 3, 15, 63, 255, 65535, -1)

destination palette: d<decimal address>
(only in the return parameter string - Player will never give this)

interpolation: interp
(will only be given with number of colours=65535 or -1)

source palette (only for files with a PALETTE value): s<decimal address>

For example

<ARMovie$Dir>.MovingLine.ColourMap.YUV16 m4 n255 s7654321

The program makes the appropriate colour table and sets a system variable.
This system variable is used to prevent the colour service program being
called again. It contains all the things needed to identify the colour table
and use it: the base address, the number of the dynamic area, the total size
of the map, the black index value (b<number>) and the white index value
(w<number>), the original parameters, the name of the program.

ARMovie$ColourMapN <address>,<number>;<size> b<n> w<n> <parameters> '<colour program>' <usage>

The value N ranges from 0 to 9 and is constrained by the ARMovie$ColourMapMax
value (if this does not exist, then the maximum value is 0, allowing just one
colourmap). The usage is a unary count (e.g. 11) of the number of simulataneous
uses of this colour table - in searching to replace a ColourMapN value, the
colour service program must avoid any with a non-zero usage count (i.e. no
trailing 1 characters) - and is initially null (no trailing 1 characters at
all). Any original parameter strings which resolve to (decimal) addresses are
replaced with new ones which point into values beyond the end of the created
table. If the value of <number> is 'RMA', then the area is on the RMA, else it
is a dynamic area (with that <number>). RMA *must* only be used if a dynamic
area cannot be created. The <size> value is how large the area was; if it was a
dynamic area this is irrelevant. The dynamic area is named 'ARMovie Colour
Map'.

If the address is -1 it signals that no translation of colour is needed.

If the address is -2 it signals that no translation of colour is needed, but
the colour needs to be duplicated across 16 bit words (ORR rd,rs,rs,LSL #16).
(note that tripling or quadrupling the value must be done by using a colour
table).

The address *must* be quad-word aligned. (apart from -1 and -2).

The black index will be assumed to be zero if not present - it allows the
Player program to access a guaranteed "black" (note that its the index, and
thus may get shifted, not the relative address).

The white index will be assumed to be 32767 if not present - it allows the
Player program to access a guaranteed "white" (note that its the index, and
thus may get shifted, not the relative address).


For example, the above call on YUV16 might result in:

ARMovie$ColourMap0 345678900,42;132608 m4 n255 d345809972 s345810740 'YUV16'

while 6Y5UV16 might give a:

ARMovie$ColourMap1 161480704,261;262144 w65535 m4 n65535 '6Y5UV16'

and RGB16 a:

ARMovie$ColourMap2 -1,0,0 m1 n65535 'RGB16' 

Note the relocation of the colour tables (in this case, to immediately after
the main colour map) and the creation of the d value: d returns should only
be made when number of colours is 1, 3, 15 or 255. Player checks all
ARMovie$ColourMapN values, starting at 0 up to the ARMovie$ColourMapMax
value. If it finds one which matches the colour space program it would call,
then it does not call the program, otherwise it does. This check is case
insensitive. (decimal) Address are followed and the contents checked.

A last example would be using CYUV24 (say):

ARMovie$ColourMap3 67256320,259;3072 w255 m1 n-1 'CYUV24'

The xxx24 tables provide a means for additively converting between colour
spaces which obey a CCIR601-like set of equations (R=aY+bV, G=cY+dU+eV, B=fY+gU
for any a-f (and a-f can be functions, not simple constants...)) and do not
give a particular colour. They are most useful for high precision conversion in
32bpp screen modes - see below. Player will call CYUV24 for a movie with colour
space CYUV, a FastDec24 or FastDec21 decompressor and in a 32bpp screen mode.


Player will signify that it has begun using a ColourMapN by adding a '1' to
it (elongating the string) as playing starts and removing the last character
when it ends.

What is YUV? What is 6Y5UV? What is CYUV? What is CYCC?
-------------------------------------------------------

YUV is Replay's name for the colour space spanned by Y 0..31, U -16..+15 and V
-16..+15 (5 bits per component). In common with most hardware designs U and V
need to be sign extended (for example by (U<<(31-5))>>(31-5)) to produce the
correct value for colour equations (the alternative being to subtract a value,
in this case 16, in order to produce a signed value). The colour equations are
those of CCIR601:

r=v*.701+y
g=y-.299*.701/.587*v-.114*.886/.587*u
b=u*.886+y

where r/g/b/y are in the range 0..1, and u and v are in the range -1..0..1.
y=Y/31, u=U/15 for U in 0..15 and u=-(31-U)/15 for U in 16..31 (similarly v).

6Y5UV is a very similar colour space where Y has 6 bits.

CYUV is a 5 bit colour space corresponding to YUV, but where the Y, U and V
encoding ranges are restricted to the five bit equivalents of CCIR601 ranges
(Y is 16..235, U and V are -112 to 112). C6Y5UV is a similar one. The colour
equations are idential (its only the ranges that have changed).

CYCC is a 5 bit colour space corresponding to CCIR601 *where the colour
coefficients have been coded excess 128* (Y is 16..235, CC are +32 to +240).
C6Y5CC is similarly defined.

Note that YUV24 and 6Y5UV24 are identical. CYUV24 and C6Y5UV24 are also
identical (and perform the conversion for CCIR601 values).

The system variable
-------------------

Some colour map programs have cached on disc the results of popular palette
sets, in particular the results for the standard 256 colour palette. However,
its not always efficient to access this cached information. A system variable,
ARMovie$FileTime gives the number of seconds to load 128KBytes on the current
system. If this is greater than the algorithmic generation time, then the
cached palette should not be used. A side effect of this is that setting
ARMovie$FileTime to some large number should result in the colour map programs
always generating colour tables algorithmically and never referring to cached
results. If ARMovie$FileTime does not exist, then the file system should be
assumed to be capable of loading 128KByte in 0.1 seconds.

Cleaning up
-----------

The programs <ARMovie$Dir>.MovingLine.ColourMap.Tidy and
<ARMovie$Dir>.MovingLine.ColourMap.Delete will clear the system of cached
colour maps. Tidy removes all unused maps. Delete removes all maps -
dangerous if some program is using them...

Replay API for clients
----------------------

A table may be claimed by using -claimtable in the !ARMovie.Player API -
see the ProgIf document - and release of the table (as well as its correct
use) is then the responsibility of the client program: it will need to
remove the last character from te ARMovie$ColourMapN.

The details of a simple table entry
-----------------------------------

    n1, m1:      byte containing 0000000a
    n1, m2:      byte containing 000000ba
    n1, m4:      byte containing 0000dcba

    n3, m1:      byte containing 000000aa
    n3, m2:      byte containing 0000bbaa
    n3, m4:      byte containing ddccbbaa

   n15, m1:      byte containing 0000aaaa
   n15, m2:      byte containing bbbbaaaa
   n15, m4: half word containing ddddcccc bbbbaaaa

  n255, m1:      byte containing aaaaaaaa
  n255, m2: half word containing bbbbbbbb aaaaaaaa
  n255, m4:      word containing dddddddd cccccccc bbbbbbbb aaaaaaaa

n65535, m1: half word containing aaaaaaaa aaaaaaaa
                                 0BBBBBGG GGGRRRRR
                                  4321043 21043210

n65535, m2, 4:   word containing bbbbbbbb bbbbbbbb aaaaaaaa aaaaaaaa
                                 0BBBBBGG GGGRRRRR 0BBBBBGG GGGRRRRR
                                  4321043 21043210  4321043 21043210
n65535, m2,4 in: word containing 000000aaaaaa00000 0aaaaa00 000aaaaa
                                       GG GGG       BBBBB      RRRRR
                                       43 210       43210      43210

n-1, m1, 2, 4:   word containing aaaaaaaa aaaaaaaa aaaaaaaa aaaaaaaa
                                 00000000 BBBBBBBB GGGGGGGG RRRRRRRR
                                          76543210 76543210 76543210
n-1, m2,4 inter: word containing aaaaaaa0 aaaaaaa0 aaaaaaa0 aaaaaaa0
                                 00000000 BBBBBBB0 GGGGGGG0 RRRRRRR0 
                                          7654321  7654321  7654321 

where a, b, c, d are pixels. R, G, B are Red, Green and Blue. 0 is 'must be
zero'. The bits of R, G and B are little endian ordered (i.e. as RISC
OS/VIDC).

If the generation program takes a noticeable time, it should use
Hourglass_Percentage (the hourglass has been turned on by Player) to
reassure the user...

The details of an additive conversion table entry
-------------------------------------------------

An additive table colour map such as CYUV24 provides 3 tables. The tables are
indexed by each of the bytes of the source colour space (for CYUV, they are
indexed by Y, U and V (in that order), but any naming of the three components
is possible) and the results added together. A constant is then used to detect
the prescence of under or overflow and the decoding program must then branch of
to a fixup routine which saturates the answers to 255 or 0.

The tables are designed such that the most common base register is for Y - for
U and V other base values must be calculated (or stored in extra registers if
several conversion of U and V are being done at once). Given that R=aY+bV,
G=cY+dU+eV, B=fY+gU for any a-f (and a-f can be functions, not simple
constants...) the tables are broken down as follows:

each Y table entry contains: aY<<0 OR fY<<10 OR cY*4<<20

each U table entry contains: 0<<0 OR gU<<10 OR dU*4<<20

each V table entry contains: bV<<0 OR  0<<10 OR eV*4<<20

By adding the Y, U and V entries together, the value R<<0 OR B<<10 OR G*4<<20
is produced. The extra *4 in the G tables gives more precision for the greater
number of adds it requires and the generally smaller values of dU and eV (and,
of course, green is the colour component the eye is most sensitve to). The
tables are in the order Y, U and V each of 1024 bytes (256 entries).

Saturation of under and overflow
--------------------------------

Many compression algorithms produce distorted values of Y, U and V such that
the conversion equations occaisionally yield out of range products (either
below 0 or above 255). The table entries are preset with padding bits to allow
out of range situations to be detected (with an inline routine) and corrected
(with an out of line routine). (it is permissable to omit the detection and
correction in a decoder if it is known somehow that out of range values cannot
occur - but don't assume that a source of (say) CCIR601 values such as a
digitiser will not generate out of range values! Note also that it is possible
for the values of Y, U and V to be known to be constrained, but out of range
values may still be produced if e.g. V is larger than expected (but in range)
when being added to a Y which is larger than expected (but again in range) to
produce R).

In the case of the R and B sums, the padding bits are 00 for Y contributions
(and aY and fY must yield positive numbers) and they are 01 for negative U or V
contributions and 10 for positive U and V contributions (i.e. those produced by
gU and bV). On summation, the padding bits will take three possible values: 01
means underflow, 10 means in range and 11 means overflow. There will be no
carry out beyond the padding bits (i.e. 011 is the biggest possible value,
there can't be 111) so it won't affect the next component along.

In the case of the G sum, the values are held as sign extended two's complement
numbers (i.e. the padding is 11 for negative values and 00 for positive ones).
Any of cY*4, dU*4 and eV*4 may be negative or positive. On summation, the
padding bits will take three possible values: 11 means underflow, 00 means OK,
and 01 means overflow. There can be a carry out from the sum, but it can be
ignored since the padding bits already identify the possibilities.

This means that out of range detection may be performed by checking that any of
bits 30, 18 and 8 are set. This is done by TST reg,constant - NE means that the
result has an out of range value in one or may places. The constant is 1<<8 OR
1<<18 OR 1<<30.

After having performed detection of out of range, saturation of each of the
values can be done in an out of line routine which checks each pair of padding
bits (using a TEQ constant,reg,LSL #31-position; this moves the out of range
bit to N and the sense bit to C) and either ORRs with 255 or BICs with 255. For
red and blue the relevant code is to ORRMI (i.e. the out of range bit is set,
so assume overflow) and then to BICCC (i.e. there is an underflow to zero). For
green the code is to ORRMI and then BICCS.

Going faster
------------

It is not necessary to perform all the operations for each pixel. Generally U
and V are sampled less often than Y and thus the U and V values can be looked
up and added together once for (say) four pixels, while the Y value is
processed each time.

Similarly it is not necessary to perform each out of range detection and
conditional branch on each Y sum: one can perform TST, TSTEQ, BNE to save a
cycle. See the example in the CodecIf document on FastDec24 or read the Acorn
provided source for Decomp8, 9, 10 and 11's FastDec24 and FastDec21.
