Starting from the
latest discovery from g3gg0, I've looked into some routines that appeared to do raw additions and subtractions (EekoAddRawPath). They seem to work, you can also do some scaling, compute min/max, and they are fairly fast (about 60 ms for a full-size raw buffer, enough for stacking some photos in the camera).
Problem: these functions are only available on DIGIC 5 cameras. However, g3gg0 found out they use the TWOADD module (present on all cameras), so there might be some hope.
5D3 stubs:
/* 1.2.3 */
void (*EekoAddRawPath)(void *a, void *b, void *out, int op, int off_a, int gain_a, int black_a, int gain_b, int black_b, int div8, int out_off, void (*cbr)(void*), void* cbr_arg) = 0xFF32C538;
void (*EekoAddRawPath_cleanup_engio)() = 0xFF5127F0;
void (*EekoAddRawPath_cleanup_reslock)() = 0xFF512698;
/* 1.1.3 */
FF327A54 (called after "%s Addsub Count:%d")
FF507CE8 (called after "stsCompleteMultiExp", after BEQ)
FF507B90 (called next)
Basic call to add two images:
EekoAddRawPath(image_a, image_b, image_out, 0, 0, 4096, 2048, 4096, 2048, 0, 0, (void(*)(void*))give_semaphore, eeko_sem);
take_semaphore(eeko_sem, 5000);
EekoAddRawPath_cleanup_engio();
EekoAddRawPath_cleanup_reslock();
Operations:
To figure them out, I've created two gradients (raw image buffers with fake data), horizontal and vertical, with values from 0 to 16383, and used them as operands for the Eeko routine. The third image is the result.
0: a + b

1: a - b

2: max(a, b)

3: min(a, b)

Octave code of what it does (incomplete, doesn't model all overflows):
function out = eeko(a, b, op, off_a, gain_a, black_a, gain_b, black_b, div8, out_off)
% valid range for the parameters
op = bitand(op, 3);
gain_a = bitand(gain_a, 8191);
gain_b = bitand(gain_b, 8191);
% offset image A
a = a + off_a;
a = max(a, -2048);
if gain_a ~= 4096,
% scale image A, relative to black level
a = round(max((a - black_a) * gain_a / 4096, -2048) + black_a);
% note: without the "if", clamping to 16383 here will fail some tests
a = min(a, 16383);
end
if black_a > 4096
% some strange overflow
a = min(a + 8192, 16383);
end
if gain_b ~= 4096,
% scale image B, relative to black level
b = round(max((b - black_b) * gain_b / 4096, -2048) + black_b);
% note: without the "if", clamping to 16383 here will fail some tests
b = min(b, 16383);
end
% perform some operation between A and B
switch op
case 0
out = a + b;
case 1
out = a - b;
case 2
out = max(a, b);
case 3
out = min(a, b);
end
out = coerce(out, 0, 16383);
if div8
% darken image by 3 stops (not adjustable)
% optionally offset by image; for some reason, the offset is multiplied by 7/8 (why?)
out = round((out + out_off*7) / 8);
end
out = coerce(out, 0, 16383);
end
function y = coerce(x, lo, hi)
y = min(max(x, lo), hi);
end
Notes:
- image_out buffer can be reused (you may use either image_a or image_b)
- to change resolution, one has to call some lower-level routines, with uglier syntax
To figure out the meaning of the parameters, I've started from the basic call and changed the values (one or two at a time). Then, by trial and error, I've adjusted the octave code (eeko.m) until it matched the images saved from camera.
Test data, camera code and octave scripts can be found here:
https://www.dropbox.com/sh/k037ulitl3kkf0t/AABXZYcTQYDqvqMQ-bNrHRtpa?dl=0