source: trunk/liveimg.c @ 236

Revision 236, 21.7 KB checked in by reyalp, 14 months ago (diff)

work in progress live view matching chdk reyalp-ptp-live rev 1817

  • Property svn:eol-style set to native
Line 
1/*
2 *
3 * Copyright (C) 2010-2012 <reyalp (at) gmail dot com>
4 *
5 *  This program is free software; you can redistribute it and/or modify
6 *  it under the terms of the GNU General Public License as published by
7 *  the Free Software Foundation; either version 2 of the License, or
8 *  (at your option) any later version.
9 *
10 *  This program is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 *  GNU General Public License for more details.
14 *
15 *  You should have received a copy of the GNU General Public License
16 *  along with this program; if not, write to the Free Software
17 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19/*
20 * functions for handling remote camera display
21 *
22 */
23
24#if !defined(CHDKPTP_LIVEVIEW)
25#error "live view support not enabled"
26#endif
27
28#include <stdint.h>
29#include <string.h>
30#include <stdlib.h>
31#include <lua.h>
32#include <lualib.h>
33#include <lauxlib.h>
34#if defined(CHDKPTP_CD)
35#include <cd.h>
36#include <cdlua.h>
37#endif
38#include "core/live_view.h"
39#include "lbuf.h"
40#include "liveimg.h"
41/*
42planar img
43TODO would make sense to use a CD bitmap for this but not public
44also may want image handling without CD, but probably want packed rather than planar
45
46TODO if we do packed, might want to make planar and packed use same struct with type flag
47*/
48typedef struct {
49        unsigned width;
50        unsigned height;
51        uint8_t *data;
52        uint8_t *r;
53        uint8_t *g;
54        uint8_t *b;
55        uint8_t *a;
56} liveimg_pimg_t;
57
58typedef struct {
59        uint8_t r;
60        uint8_t g;
61        uint8_t b;
62        uint8_t a;
63} palette_entry_rgba_t;
64
65typedef struct {
66        uint8_t a;
67        uint8_t y;
68        int8_t u;
69        int8_t v;
70} palette_entry_ayuv_t;
71
72typedef struct {
73        int8_t v;
74        int8_t u;
75        uint8_t y;
76        uint8_t a;
77} palette_entry_vuya_t;
78
79typedef void (*yuv_palette_to_rgba_fn)(const char *pal_yuv, uint8_t pixel,palette_entry_rgba_t *pal_rgb);
80
81void palette_type1_to_rgba(const char *palette, uint8_t pixel, palette_entry_rgba_t *pal_rgb);
82void palette_type2_to_rgba(const char *palette, uint8_t pixel, palette_entry_rgba_t *pal_rgb);
83void palette_type3_to_rgba(const char *palette, uint8_t pixel, palette_entry_rgba_t *pal_rgb);
84
85void yuv_live_to_cd_rgb(const char *p_yuv,
86                                                unsigned buf_width, unsigned buf_height,
87                                                unsigned x_offset, unsigned y_offset,
88                                                unsigned width,unsigned height,
89                                                int skip,
90                                                uint8_t *r,uint8_t *g,uint8_t *b);
91
92// from a540, playback mode
93static const char palette_type1_default[]={
940x00, 0x00, 0x00, 0x00, 0xff, 0xe0, 0x00, 0x00, 0xff, 0x60, 0xee, 0x62, 0xff, 0xb9, 0x00, 0x00,
950x7f, 0x00, 0x00, 0x00, 0xff, 0x7e, 0xa1, 0xb3, 0xff, 0xcc, 0xb8, 0x5e, 0xff, 0x5f, 0x00, 0x00,
960xff, 0x94, 0xc5, 0x5d, 0xff, 0x8a, 0x50, 0xb0, 0xff, 0x4b, 0x3d, 0xd4, 0x7f, 0x28, 0x00, 0x00,
970x7f, 0x00, 0x7b, 0xe2, 0xff, 0x30, 0x00, 0x00, 0xff, 0x69, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00,
98};
99
100typedef struct {
101        yuv_palette_to_rgba_fn to_rgba;
102        unsigned num_entries;
103} palette_convert_t;
104
105// type implied from index
106// TODO only one function for now
107palette_convert_t palette_funcs[] = {
108        {NULL,0},                                       // type 0 - no palette, we could have a default func here
109        {palette_type1_to_rgba,16},     // type 1 - ayuv, 16 entries double 4 bit index
110        {palette_type2_to_rgba,16},     // type 2 - like type 1, but with 2 bit alpha lookup - UNTESTED
111        {palette_type3_to_rgba,256},    // type 3 - vuya, 256 entries, 2 bit alpha lookup
112};
113
114#define N_PALETTE_FUNCS (sizeof(palette_funcs)/sizeof(palette_funcs[0]))
115
116static palette_convert_t* get_palette_convert(unsigned type) {
117        if(type<N_PALETTE_FUNCS) {
118                return &(palette_funcs[type]);
119        }
120        return NULL;
121}
122
123static unsigned get_palette_size(unsigned type) {
124        palette_convert_t* convert = get_palette_convert(type);
125        if(convert) {
126                return convert->num_entries*4;
127        }
128        return 0;
129}
130
131static uint8_t clip_yuv(int v) {
132        if (v<0) return 0;
133        if (v>255) return 255;
134        return v;
135}
136
137static uint8_t yuv_to_r(uint8_t y, int8_t v) {
138        return clip_yuv(((y<<12) +          v*5743 + 2048)>>12);
139}
140
141static uint8_t yuv_to_g(uint8_t y, int8_t u, int8_t v) {
142        return clip_yuv(((y<<12) - u*1411 - v*2925 + 2048)>>12);
143}
144
145static uint8_t yuv_to_b(uint8_t y, int8_t u) {
146        return clip_yuv(((y<<12) + u*7258          + 2048)>>12);
147}
148
149static uint8_t clamp_uint8(unsigned v) {
150        return (v>255)?255:v;
151}
152
153static int8_t clamp_int8(int v) {
154        if(v>127) {
155                return 127;
156        }
157        if(v<-128) {
158                return -128;
159        }
160        return v;
161}
162
163void palette_type1_to_rgba(const char *palette, uint8_t pixel,palette_entry_rgba_t *pal_rgb) {
164        const palette_entry_ayuv_t *pal = (const palette_entry_ayuv_t *)palette;
165        unsigned i1 = pixel & 0xF;
166        unsigned i2 = (pixel & 0xF0)>>4;
167        int8_t u,v;
168        uint8_t y;
169        pal_rgb->a = (pal[i1].a + pal[i2].a)>>1;
170        // TODO not clear if these should be /2 or not
171        y = clamp_uint8(pal[i1].y + pal[i2].y);
172        u = clamp_int8(pal[i1].u + pal[i2].u);
173        v = clamp_int8(pal[i1].v + pal[i2].v);
174        pal_rgb->r = yuv_to_r(y,v);
175        pal_rgb->g = yuv_to_g(y,u,v);
176        pal_rgb->b = yuv_to_b(y,u);
177}
178
179static const uint8_t alpha2_lookup[] = {128,171,214,255};
180// like above, but with alpha lookup
181void palette_type2_to_rgba(const char *palette, uint8_t pixel,palette_entry_rgba_t *pal_rgb) {
182        const palette_entry_ayuv_t *pal = (const palette_entry_ayuv_t *)palette;
183        unsigned i1 = pixel & 0xF;
184        unsigned i2 = (pixel & 0xF0)>>4;
185        int8_t u,v;
186        uint8_t y;
187        uint8_t a = (pal[i1].a + pal[i2].a)>>1;
188        pal_rgb->a = alpha2_lookup[a&3];
189        // TODO not clear if these should be /2 or not
190        y = clamp_uint8(pal[i1].y + pal[i2].y);
191        u = clamp_int8(pal[i1].u + pal[i2].u);
192        v = clamp_int8(pal[i1].v + pal[i2].v);
193        pal_rgb->r = yuv_to_r(y,v);
194        pal_rgb->g = yuv_to_g(y,u,v);
195        pal_rgb->b = yuv_to_b(y,u);
196}
197
198void palette_type3_to_rgba(const char *palette, uint8_t pixel,palette_entry_rgba_t *pal_rgb) {
199        const palette_entry_vuya_t *pal = (const palette_entry_vuya_t *)palette;
200        // special case for index 0
201        if(pixel == 0) {
202                pal_rgb->a = pal_rgb->r = pal_rgb->g = pal_rgb->b = 0;
203                return;
204        }
205        pal_rgb->a = alpha2_lookup[pal[pixel].a&3];
206        pal_rgb->r = yuv_to_r(pal[pixel].y,pal[pixel].v);
207        pal_rgb->g = yuv_to_g(pal[pixel].y,pal[pixel].u,pal[pixel].v);
208        pal_rgb->b = yuv_to_b(pal[pixel].y,pal[pixel].u);
209}
210
211void yuv_live_to_cd_rgb(const char *p_yuv,
212                                                unsigned buf_width, unsigned buf_height,
213                                                unsigned x_offset, unsigned y_offset,
214                                                unsigned width,unsigned height,
215                                                int skip,
216                                                uint8_t *r,uint8_t *g,uint8_t *b) {
217        unsigned x,row;
218        unsigned row_inc = (buf_width*12)/8;
219        const char *p;
220        // start at end to flip for CD
221        const char *p_row = p_yuv + (height + y_offset - 1) * row_inc + (x_offset*12)/8;
222        for(row=0;row<height;row++,p_row -= row_inc) {
223                for(x=0,p=p_row;x<width;x+=4,p+=6) {
224                        *r++ = yuv_to_r(p[1],p[2]);
225                        *g++ = yuv_to_g(p[1],p[0],p[2]);
226                        *b++ = yuv_to_b(p[1],p[0]);
227
228                        *r++ = yuv_to_r(p[3],p[2]);
229                        *g++ = yuv_to_g(p[3],p[0],p[2]);
230                        *b++ = yuv_to_b(p[3],p[0]);
231                        if(!skip) {
232                                // TODO it might be better to use the next pixels U and V values
233                                *r++ = yuv_to_r(p[4],p[2]);
234                                *g++ = yuv_to_g(p[4],p[0],p[2]);
235                                *b++ = yuv_to_b(p[4],p[0]);
236
237                                *r++ = yuv_to_r(p[5],p[2]);
238                                *g++ = yuv_to_g(p[5],p[0],p[2]);
239                                *b++ = yuv_to_b(p[5],p[0]);
240                        }
241                }
242        }
243}
244
245static void pimg_destroy(liveimg_pimg_t *im) {
246        free(im->data);
247        im->width = im->height = 0;
248        im->data = im->r = im->g = im->b = im->a = NULL;
249}
250
251static int pimg_gc(lua_State *L) {
252        liveimg_pimg_t *im = (liveimg_pimg_t *)luaL_checkudata(L,1,LIVEIMG_PIMG_META);
253        pimg_destroy(im);
254        return 0;
255}
256
257static int pimg_get_width(lua_State *L) {
258        liveimg_pimg_t *im = (liveimg_pimg_t *)luaL_checkudata(L,1,LIVEIMG_PIMG_META);
259        if(!im->data) {
260                return luaL_error(L,"dead pimg");
261        }
262        lua_pushnumber(L,im->width);
263        return 1;
264}
265
266static int pimg_get_height(lua_State *L) {
267        liveimg_pimg_t *im = (liveimg_pimg_t *)luaL_checkudata(L,1,LIVEIMG_PIMG_META);
268        if(!im->data) {
269                return luaL_error(L,"dead pimg");
270        }
271        lua_pushnumber(L,im->height);
272        return 1;
273}
274
275static int pimg_kill(lua_State *L) {
276        liveimg_pimg_t *im = (liveimg_pimg_t *)luaL_checkudata(L,1,LIVEIMG_PIMG_META);
277        pimg_destroy(im);
278        return 0;
279}
280
281/*
282create a new pimg and push it on the stack
283TODO might want to pass in width, height or data, but need to handle rgb vs rgba
284*/
285int pimg_create(lua_State *L) {
286        liveimg_pimg_t *im = (liveimg_pimg_t *)lua_newuserdata(L,sizeof(liveimg_pimg_t));
287        if(!im) {
288                return 0;
289        }
290        im->width = im->height = 0;
291        im->data = im->r = im->g = im->b = im->a = NULL;
292        luaL_getmetatable(L, LIVEIMG_PIMG_META);
293        lua_setmetatable(L, -2);
294
295        return 1;
296}
297
298int pimg_init_rgb(liveimg_pimg_t *im,unsigned width,unsigned height) {
299        unsigned size = width*height;
300        if(!size) {
301                return 0;
302        }
303        im->data=malloc(size*3);
304        if(!im->data) {
305                return 0;
306        }
307        im->width = width;
308        im->height = height;
309        im->r=im->data;
310        im->g=im->r+size;
311        im->b=im->g+size;
312        im->a=NULL;
313        return 1;
314}
315
316/*
317TODO stupid copy/paste
318*/
319int pimg_init_rgba(liveimg_pimg_t *im,unsigned width,unsigned height) {
320        unsigned size = width*height;
321        if(!size) {
322                return 0;
323        }
324        im->data=malloc(size*4);
325        if(!im->data) {
326                return 0;
327        }
328        im->width = width;
329        im->height = height;
330        im->r=im->data;
331        im->g=im->r+size;
332        im->b=im->g+size;
333        im->a=im->b+size;
334        return 1;
335}
336
337/*
338check whether given stack index is an pimg, and if so, return it
339*/
340liveimg_pimg_t * pimg_get(lua_State *L,int i) {
341        if(!lua_isuserdata(L,i)) {
342                return NULL;
343        }
344        if(lua_islightuserdata(L,i)) {
345                return NULL;
346        }
347        if(!lua_getmetatable(L,i)) {
348                return NULL;
349        }
350        lua_getfield(L,LUA_REGISTRYINDEX,LIVEIMG_PIMG_META);
351        int r = lua_rawequal(L,-1,-2);
352        lua_pop(L,2);
353        if(r) {
354                return lua_touserdata(L,i);
355        }
356        return NULL;
357}
358
359/*
360convert viewport data to RGB pimg
361pimg=liveimg.get_viewport_pimg(pimg,base_info,vid_info,skip)
362pimg: pimg to re-use, created if nil, replaced if size doesn't match
363vid_info, base_info: from handler
364skip: boolean - if true, each U Y V Y Y Y is converted to 2 pixels, otherwise 4
365returns nil if info does not contain a live view
366*/
367static int liveimg_get_viewport_pimg(lua_State *L) {
368        lv_vid_info *vi;
369        lv_base_info *bi;
370        liveimg_pimg_t *im = pimg_get(L,1);
371        lBuf_t *base_lb = luaL_checkudata(L,2,LBUF_META);
372        lBuf_t *vi_lb = luaL_checkudata(L,3,LBUF_META);
373        int skip = lua_toboolean(L,4);
374        // pixel aspect ratio
375        int par = (skip == 1)?2:1;
376
377        bi = (lv_base_info *)base_lb->bytes;
378        vi = (lv_vid_info *)vi_lb->bytes;
379
380        // this is not currently an error, if sent live data without viewport selected, just return nil image
381        if(!vi->vp_buffer_start) {
382                lua_pushnil(L);
383                return 1;
384        }
385
386        unsigned vwidth = vi->vp_width/par;
387        unsigned dispsize = vwidth*vi->vp_height;
388
389        // sanity checks - TODO might want to have this standalone somewhere
390        if(vi->vp_buffer_start + (bi->vp_buffer_width*bi->vp_max_height*12)/8 > vi_lb->len) {
391                return luaL_error(L,"data < buffer_width*max_height");
392        }
393
394        if(vi->vp_height + vi->vp_yoffset > bi->vp_max_height) {
395                return luaL_error(L,"vp_height + vp_yoffset > vp_max_height");
396        }
397
398        if(vi->vp_width + vi->vp_xoffset > bi->vp_buffer_width) {
399                return luaL_error(L,"vp_width + vp_xoffset > vp_buffer_width");
400        }
401
402        if(im && dispsize != im->width*im->height) {
403                pimg_destroy(im);
404                im = NULL;
405        }
406        if(im) {
407                lua_pushvalue(L, 1); // copy im onto top for return
408        } else { // create an new im
409                pimg_create(L);
410                im = luaL_checkudata(L,-1,LIVEIMG_PIMG_META);
411                if(!pimg_init_rgb(im,vwidth,vi->vp_height)) {
412                        return luaL_error(L,"failed to create image");
413                }
414        }
415
416        yuv_live_to_cd_rgb(vi_lb->bytes+vi->vp_buffer_start,
417                                                bi->vp_buffer_width,
418                                                bi->vp_max_height,
419                                                vi->vp_xoffset,
420                                                vi->vp_yoffset,
421                                                vi->vp_width,
422                                                vi->vp_height,
423                                                skip,
424                                                im->r,im->g,im->b);
425        return 1;
426}
427
428/*
429check framebuffer desc values, and return a descriptive error or NULL
430TODO can't check total size without bpp
431*/
432static const char * check_fb_desc(lv_framebuffer_desc *desc) {
433        if(desc->visible_height + desc->visible_buffer_yoffset > desc->buffer_height) {
434                return "height + yoffset > buffer_height";
435        }
436
437        if(desc->visible_width + desc->visible_buffer_xoffset > desc->buffer_width) {
438                return "vp_width + vp_xoffset > vp_buffer_width";
439        }
440        // sanity check, this should actually be harmless
441        if(desc->visible_width > desc->logical_width) {
442                return "visible_width > logical_width";
443        }
444        if(desc->visible_height > desc->logical_height) {
445                return "visible_height > logical_height";
446        }
447        return NULL;
448}
449
450/*
451convert viewport data to RGB pimg
452pimg=liveimg.get_viewport2_pimg(pimg,live_frame,skip)
453pimg: pimg to re-use, created if nil, replaced if size doesn't match
454live_fream: from get_live_data
455skip: boolean - if true, each U Y V Y Y Y is converted to 2 pixels, otherwise 4
456returns nil if info does not contain a live view
457*/
458static int liveimg_get_viewport2_pimg(lua_State *L) {
459        lv_data_header *frame;
460        liveimg_pimg_t *im = pimg_get(L,1);
461        lBuf_t *frame_lb = luaL_checkudata(L,2,LBUF_META);
462        int skip = lua_toboolean(L,3);
463        // pixel aspect ratio
464        int par = (skip == 1)?2:1;
465
466        frame = (lv_data_header *)frame_lb->bytes;
467
468        // this is not currently an error, if sent live data without viewport selected, just return nil image
469        if(!frame->vp.data_start) {
470                lua_pushnil(L);
471                return 1;
472        }
473
474        unsigned vwidth = frame->vp.visible_width/par;
475        unsigned dispsize = vwidth*frame->vp.visible_height;
476
477        // sanity check size - depends on type
478        if(frame->vp.data_start + (frame->vp.buffer_width*frame->vp.buffer_height*12)/8 > frame_lb->len) {
479                return luaL_error(L,"data < buffer_width*buffer_height");
480        }
481        const char *fb_desc_err = check_fb_desc(&frame->vp);
482        if(fb_desc_err) {
483                return luaL_error(L,fb_desc_err);
484        }
485
486        if(im && dispsize != im->width*im->height) {
487                pimg_destroy(im);
488                im = NULL;
489        }
490        if(im) {
491                lua_pushvalue(L, 1); // copy im onto top for return
492                // set width and height, could have changed without changing byte count
493                im->width = vwidth;
494                im->height = frame->vp.visible_height;
495        } else { // create an new im
496                pimg_create(L);
497                im = luaL_checkudata(L,-1,LIVEIMG_PIMG_META);
498                if(!pimg_init_rgb(im,vwidth,frame->vp.visible_height)) {
499                        return luaL_error(L,"failed to create image");
500                }
501        }
502
503        yuv_live_to_cd_rgb(frame_lb->bytes+frame->vp.data_start,
504                                                frame->vp.buffer_width,
505                                                frame->vp.buffer_height,
506                                                frame->vp.visible_buffer_xoffset,
507                                                frame->vp.visible_buffer_yoffset,
508                                                frame->vp.visible_width,
509                                                frame->vp.visible_height,
510                                                skip,
511                                                im->r,im->g,im->b);
512        return 1;
513}
514
515static void convert_palette(palette_entry_rgba_t *pal_rgba,lv_vid_info *vi) {
516        const char *pal=NULL;
517        palette_convert_t *convert=get_palette_convert(vi->palette_type);
518        if(!convert || !vi->palette_buffer_start) {
519                convert = get_palette_convert(1);
520                pal = palette_type1_default;
521        } else {
522                pal = ((char *)vi + vi->palette_buffer_start);
523        }
524        yuv_palette_to_rgba_fn fn = convert->to_rgba;
525        int i;
526        for(i=0;i<256;i++) {
527                fn(pal,i,&pal_rgba[i]);
528        }
529}
530
531/*
532convert bitmap data to RGBA pimg
533pimg=liveimg.get_bitmap_pimg(pimg,base_info,vid_info,skip)
534pimg: pimg to re-use, created if nil, replaced if size doesn't match
535vid_info, base_info: from handler
536skip: boolean - if true, every other pixel in the x axis is discarded (for viewports with a 1:2 par)
537returns nil if info does not contain a bitmap
538*/
539static int liveimg_get_bitmap_pimg(lua_State *L) {
540        palette_entry_rgba_t pal_rgba[256];
541
542        lv_vid_info *vi;
543        lv_base_info *bi;
544        liveimg_pimg_t *im = pimg_get(L,1);
545        lBuf_t *base_lb = luaL_checkudata(L,2,LBUF_META);
546        lBuf_t *vi_lb = luaL_checkudata(L,3,LBUF_META);
547        int skip = lua_toboolean(L,4);
548        // pixel aspect ratio
549        int par = (skip == 1)?2:1;
550
551        bi = (lv_base_info *)base_lb->bytes;
552        vi = (lv_vid_info *)vi_lb->bytes;
553
554        if(!vi->bm_buffer_start) {
555                lua_pushnil(L);
556                return 1;
557        }
558
559        if(bi->bm_max_height*bi->bm_max_width + vi->bm_buffer_start > vi_lb->len) {
560                return luaL_error(L,"data < max_height*max_width");
561        }
562
563        if(get_palette_size(vi->palette_type) + vi->palette_buffer_start > vi_lb->len) {
564                return luaL_error(L,"data < palette size");
565        }
566
567        convert_palette(pal_rgba,vi);
568
569        unsigned vwidth = bi->bm_max_width/par;
570        unsigned dispsize = vwidth*bi->bm_max_height;
571
572
573        if(im && dispsize != im->width*im->height) {
574                pimg_destroy(im);
575                im = NULL;
576        }
577        if(im) {
578                lua_pushvalue(L, 1); // copy im onto top for return
579        } else { // create an new im
580                pimg_create(L);
581                im = luaL_checkudata(L,-1,LIVEIMG_PIMG_META);
582                if(!pimg_init_rgba(im,vwidth,bi->bm_max_height)) {
583                        return luaL_error(L,"failed to create image");
584                }
585        }
586
587        int y_inc = bi->bm_buffer_width;
588        int x_inc = par;
589        int x,y;
590        int height = bi->bm_max_height;
591
592        uint8_t *p=((uint8_t *)vi + vi->bm_buffer_start) + (height-1)*y_inc;
593
594        uint8_t *r = im->r;
595        uint8_t *g = im->g;
596        uint8_t *b = im->b;
597        uint8_t *a = im->a;
598
599        for(y=0;y<height;y++,p-=y_inc) {
600                for(x=0;x<bi->bm_max_width;x+=x_inc) {
601                        palette_entry_rgba_t *c =&pal_rgba[*(p+x)];
602                        *r++ = c->r;
603                        *g++ = c->g;
604                        *b++ = c->b;
605                        *a++ = c->a;
606                }
607        }
608        return 1;
609}
610
611static void convert_palette2(palette_entry_rgba_t *pal_rgba,lv_data_header *frame) {
612        const char *pal=NULL;
613        palette_convert_t *convert=get_palette_convert(frame->palette_type);
614        if(!convert || !frame->palette_data_start) {
615                convert = get_palette_convert(1);
616                pal = palette_type1_default;
617        } else {
618                pal = ((char *)frame + frame->palette_data_start);
619        }
620        yuv_palette_to_rgba_fn fn = convert->to_rgba;
621        int i;
622        for(i=0;i<256;i++) {
623                fn(pal,i,&pal_rgba[i]);
624        }
625}
626
627/*
628convert bitmap data to RGBA pimg
629pimg=liveimg.get_bitmap2_pimg(pimg,frame,skip)
630pimg: pimg to re-use, created if nil, replaced if size doesn't match
631frame: from live_get_data
632skip: boolean - if true, every other pixel in the x axis is discarded (for viewports with a 1:2 par)
633returns nil if info does not contain a bitmap
634*/
635static int liveimg_get_bitmap2_pimg(lua_State *L) {
636        palette_entry_rgba_t pal_rgba[256];
637
638        lv_data_header *frame;
639        liveimg_pimg_t *im = pimg_get(L,1);
640        lBuf_t *frame_lb = luaL_checkudata(L,2,LBUF_META);
641        int skip = lua_toboolean(L,3);
642        // pixel aspect ratio
643        int par = (skip == 1)?2:1;
644
645        frame = (lv_data_header *)frame_lb->bytes;
646
647        if(!frame->bm.data_start) {
648                lua_pushnil(L);
649                return 1;
650        }
651
652        // sanity check size - depends on type
653        if(frame->bm.data_start + frame->bm.buffer_width*frame->bm.buffer_height > frame_lb->len) {
654                return luaL_error(L,"data < buffer_width*buffer_height");
655        }
656
657        const char *fb_desc_err = check_fb_desc(&frame->bm);
658        if(fb_desc_err) {
659                return luaL_error(L,fb_desc_err);
660        }
661
662        if(get_palette_size(frame->palette_type) + frame->palette_data_start > frame_lb->len) {
663                return luaL_error(L,"data < palette size");
664        }
665
666        convert_palette2(pal_rgba,frame);
667
668        unsigned vwidth = frame->bm.visible_width/par;
669        unsigned dispsize = vwidth*frame->bm.visible_height;
670
671
672        if(im && dispsize != im->width*im->height) {
673                pimg_destroy(im);
674                im = NULL;
675        }
676        if(im) {
677                lua_pushvalue(L, 1); // copy im onto top for return
678        } else { // create an new im
679                pimg_create(L);
680                im = luaL_checkudata(L,-1,LIVEIMG_PIMG_META);
681                if(!pimg_init_rgba(im,vwidth,frame->bm.visible_height)) {
682                        return luaL_error(L,"failed to create image");
683                }
684        }
685
686        int y_inc = frame->bm.buffer_width;
687        int x_inc = par;
688        int x,y;
689        int height = frame->bm.visible_height;
690
691        uint8_t *p=((uint8_t *)frame_lb->bytes + frame->bm.data_start) + (height-1)*y_inc;
692
693        uint8_t *r = im->r;
694        uint8_t *g = im->g;
695        uint8_t *b = im->b;
696        uint8_t *a = im->a;
697
698        // TODO we don't actually check the various offsets
699        for(y=0;y<height;y++,p-=y_inc) {
700                for(x=0;x<frame->bm.visible_width;x+=x_inc) {
701                        palette_entry_rgba_t *c =&pal_rgba[*(p+x)];
702                        *r++ = c->r;
703                        *g++ = c->g;
704                        *b++ = c->b;
705                        *a++ = c->a;
706                }
707        }
708        return 1;
709}
710
711#if defined(CHDKPTP_CD)
712/*
713pimg:put_to_cd_canvas(canvas, x, y, width, height, xmin, xmax, ymin, ymax)
714*/
715static int pimg_put_to_cd_canvas(lua_State *L) {
716        liveimg_pimg_t *im = (liveimg_pimg_t *)luaL_checkudata(L,1,LIVEIMG_PIMG_META);
717        cdCanvas *cnv = cdlua_checkcanvas(L,2);
718        if(!im->data) {
719                return luaL_error(L,"dead pimg");
720        }
721        // left, bottom
722        int x=luaL_optint(L,3,0);
723        int y=luaL_optint(L,4,0);
724        // target width, height. 0 = default
725        int width=luaL_optint(L,5,0);
726        int height=luaL_optint(L,6,0);
727        // sub image
728        int xmin=luaL_optint(L,7,0);
729        int xmax=luaL_optint(L,8,0);
730        int ymin=luaL_optint(L,9,0);
731        int ymax=luaL_optint(L,10,0);
732        cdCanvasPutImageRectRGB(cnv,
733                                                        im->width,im->height, // image size
734                                                        im->r,im->g,im->b, // data
735                                                        x,y,
736                                                        width,height,
737                                                        xmin,xmax,ymin,ymax);
738        return 0;
739}
740
741/*
742as above, but with alpha
743*/
744static int pimg_blend_to_cd_canvas(lua_State *L) {
745        liveimg_pimg_t *im = (liveimg_pimg_t *)luaL_checkudata(L,1,LIVEIMG_PIMG_META);
746        cdCanvas *cnv = cdlua_checkcanvas(L,2);
747        if(!im->data) {
748                return luaL_error(L,"dead pimg");
749        }
750        if(!im->a) {
751                return luaL_error(L,"pimg has no alpha channel");
752        }
753        // left, bottom
754        int x=luaL_optint(L,3,0);
755        int y=luaL_optint(L,4,0);
756        // target width, height. 0 = default
757        int width=luaL_optint(L,5,0);
758        int height=luaL_optint(L,6,0);
759        // sub image
760        int xmin=luaL_optint(L,7,0);
761        int xmax=luaL_optint(L,8,0);
762        int ymin=luaL_optint(L,9,0);
763        int ymax=luaL_optint(L,10,0);
764        cdCanvasPutImageRectRGBA(cnv,
765                                                        im->width,im->height, // image size
766                                                        im->r,im->g,im->b,im->a, // data
767                                                        x,y,
768                                                        width,height,
769                                                        xmin,xmax,ymin,ymax);
770        return 0;
771}
772
773#endif
774
775static const luaL_Reg liveimg_funcs[] = {
776  {"get_bitmap_pimg", liveimg_get_bitmap_pimg},
777  {"get_bitmap2_pimg", liveimg_get_bitmap2_pimg},
778  {"get_viewport_pimg", liveimg_get_viewport_pimg},
779  {"get_viewport2_pimg", liveimg_get_viewport2_pimg},
780  {NULL, NULL}
781};
782
783static const luaL_Reg pimg_methods[] = {
784#if defined(CHDKPTP_CD)
785  {"put_to_cd_canvas", pimg_put_to_cd_canvas},
786  {"blend_to_cd_canvas", pimg_blend_to_cd_canvas},
787#endif
788  {"width", pimg_get_width},
789  {"height", pimg_get_height},
790  {"kill", pimg_kill},
791  {NULL, NULL}
792};
793
794static const luaL_Reg pimg_meta_methods[] = {
795  {"__gc", pimg_gc},
796  {NULL, NULL}
797};
798
799// TODO based on lbuf,
800// would be nice to have a way to extend lbuf with additional custom bindings
801void liveimg_open(lua_State *L) {
802        luaL_newmetatable(L,LIVEIMG_PIMG_META);
803        luaL_register(L, NULL, pimg_meta_methods); 
804
805        /* use a table of methods for the __index method */
806        lua_newtable(L);
807        luaL_register(L, NULL, pimg_methods); 
808        lua_setfield(L,-2,"__index");
809
810        /* global lib */
811        lua_newtable(L);
812        luaL_register(L, "liveimg", liveimg_funcs); 
813        lua_pop(L,3);
814}
815
Note: See TracBrowser for help on using the repository browser.