VRAM segments with image data (YUV 422)[]
Those numbers are not 100% correct. A more elegant method (suggested by AJ) is to find a structure which contains the size of the VRAM buffers, and read the image size directly from there.
0x40D07800 / 4c233800 / 4f11d800[]
LiveView buffer maybe
- each buffer updates at 10fps (does not change when NTSC is selected) => 30fps liveview
- buffer address can be found at 0x246c (updates at 30fps)
- see the table struct vram_info vram_info[3]; at RAM:0008194C
- 1440 pitch, 720x480 image size, (3:2)
- RCA monitor connected: 540x540 with black borders
- HDMI monitor connected:
- 1920x1080 (16:9) standby (not recording)
- 720x486? while recording /* zebra already works in this mode */
0x44000080 / 0x46000080[]
- each buffer is updated at 12.5 fps (PAL) or 15fps (NTSC)
- they are updated alternatively according to AJ's guess => 25 or 30 fps
- it seems not to change its size when external display is connected
- in LiveView, idle, PHOTO mode: 2112 pitch, 1056*704 (3:2)
- when NOT recording:
resolution can be found at (0x1300ce, 0x1300d0)- full HD: 1056x704
- 720p:
1024x680sometimes work, sometimes not - 480p non-crop: garbage
- 480p crop: 640x480
- when recording:
- full HD: 3440 pitch, 1720x974 (approx. 16:9)
- 720p: 2560 pitch, 1280 x 580
- 480p: 1280 pitch, 640 x 480
- zoom x5, x10: 2048 pitch, 1024x680 (3:2)
ASM Zedbra: segments in 5D2.
LV-Sizes:[]
Dimensions can be found at 0x3787c(x) and 0x37880(y) (FW 1.0.9)
Local Display:[]
Always 720x480
HDMI:[]
Standby:
- Disp 1x/2x: 1320x880
- Disp 3x: 1620x1080
Recording: Always 640x388
A/V-Out (Standby + Recording):[]
- PAL: 640x464
- NTSC: 640x388
BMP overlay (where ML writes stuff on screen)[]
8-bit palette: see Cropmarks
- normal: 720x480 (3:2)
- hdmi monitor: 960*540 (16:9)
- SD monitor: 720x480 stretched?
How to find segments[]
Some ideas:
- Scan for contiguous areas of memory which change like mad (AJ's method)
- Dump some memory twice (while in LiveView or Recording) and plot the difference between them. Use pylab, octave or whatever numerical analysis program you like. Downsample them (e.g. x[0:-1:100] in pylab) if you have huge dumps.
- Reading from Cxxxxxxx (and maybe from other addresses) may freeze the camera. Be careful.
- Use FFT to guess the pitch, and then tweak it by hand
def guesspitch(s): F,f = fft(s), fftfreq(len(s)) for i in range(100): F[i] = 0 a = argmax(abs(F[:10000])) print 1/f[a]
- Use these functions for reading and splitting YUV data:
def readseg(file, start, size): f = open(file) f.seek(start) d = f.read(size) f.close() return [ord(x) for x in d]
def img(s,i,off,step,name,signed,pitch): nl = len(s)/pitch print nl s = s[off:] a = resize(s,nl*pitch).reshape(nl,pitch) a = a[:,0:pitch:step] fname = '%03d-%s.png' % (i,name) print a.min(), a.max() if signed: a = (a.astype(uint8).astype(int32) + 128).astype(uint8) else: a = a.astype(uint8) b = Image.fromarray(a) b.save(fname)
def imgseq(s, pitch, i=0, off=0): img(s,i,0+off,1,"full",0,pitch); img(s,i,1+off,2,"odd",0,pitch); img(s,i,0+off,2,"even",1,pitch); img(s,i,0+off,4,"even-even",1,pitch); img(s,i,2+off,4,"even-odd",1,pitch);
e.g.
s = readseg("4.BIN", 0x04000080, 1056*704*2) guesspitch(s) 2112.0 imgseq(s, 2112)
Code: GPL
Code for running on the camera[]
static FILE * g_aj_logfile = INVALID_PTR; unsigned int aj_create_log_file( char * name) { g_aj_logfile = FIO_CreateFile( name ); if ( g_aj_logfile == INVALID_PTR ) { bmp_printf( FONT_SMALL, 120, 40, "FCreate: Err %s", name ); return( 0 ); // FAILURE } return( 1 ); // SUCCESS }
void aj_close_log_file( void ) { if (g_aj_logfile == INVALID_PTR) return; FIO_CloseFile( g_aj_logfile ); g_aj_logfile = INVALID_PTR; }
void dump_seg(uint32_t start, uint32_t size, char* filename) { DEBUG(); aj_create_log_file(filename); FIO_WriteFile( g_aj_logfile, (const void *) start, size ); aj_close_log_file(); DEBUG(); }
void dump_big_seg(int k, char* filename) { DEBUG(); aj_create_log_file(filename); int i; for (i = 0; i < 16; i++) { DEBUG(); uint32_t start = (k << 28 | i << 24); bmp_printf(FONT_LARGE, 50, 50, "DUMP %x %8x ", i, start); FIO_WriteFile( g_aj_logfile, (const void *) start, 0x1000000 ); } aj_close_log_file(); DEBUG(); }
static void dump_vram() { dump_big_seg(1, "B:/1.bin"); dump_big_seg(4, "B:/4.bin"); }
Step-by-step example[]
Run ipython
- Load the code (img.py) from the mailing list
In [1]: run -i img.py
- Read the file downsampled by 100, 'cause the dumps are large:
In [2]: a = readsampled("./0.BIN")
And second file:
In [3]: b = readsampled("./1.BIN")
Find a difference...
In [4]: d = array(a) - array(b)
Do this to get a nice plot:
In [5]: d[d != 0] = 1
Notice one of the blocks starting around 1000000:
In [6]: plot(d); show() Out[6]: [<matplotlib.lines.Line2D object at 0x9c93c2c>]
Remember downsampling factor:
In [7]: x = 1000000*100
Read 1MB from there:
In [8]: s = readseg("./0.BIN", x, 1000000)
Guess pitch with FFT:
In [9]: guesspitch(s) 2114.16490486
Starts to look like an image!
In [10]: imgseq(s, 2114)
And... Perfect sync!
In [11]: imgseq(s, 2112)
Image data starts from line 316; from 550d we know buffer is 1056*704
In [12]: s = readseg("./0.BIN", x+316*2112, 2112*704)
Almost there...
In [13]: imgseq(s, 2112)
In [14]: hex(x+316*2112) Out[14]: '0x6001000'
From 550D, Alex guess it should end in 0080
In [15]: s = readseg("./0.BIN", 0x6000080, 2112*704)
Bingo!
In [16]: imgseq(s, 2112)
Final result: 0x46000080 (with the caching bit from 550D).
References: