/* * Pure Data Packet system implementation. : 16 bit image packet implementation * Copyright (c) by Tom Schouten * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */ #include #include #include #include #include #include #include #include #include #include #include #include /* traverse a type description list */ #define CHECKNEXT(type) {if (!(a=a->next)) goto exit; if(a->t != type) goto exit;} /* the class object */ static pf_class_t* image_class; static pf_class_t* bitmap_class; /* bitmap fourcc mappings */ #define FMAP(fourcc, sym) case PF_FOURCC_##fourcc: return pf_symbol(sym) pf_symbol_t *bitmap_fourcc_to_symbol(u32 fourcc){ switch(fourcc){ FMAP(GREY, "grey"); FMAP(GREYA, "greya"); FMAP(BGR, "bgr"); FMAP(RGB, "rgb"); FMAP(RGBA, "rgba"); FMAP(UYVY, "uyvy"); FMAP(YV12, "yv12"); FMAP(I420, "i420"); FMAP(YUY2, "yuy2"); FMAP(GL_GREY, "gl-grey"); FMAP(GL_GREYA, "gl-greya"); FMAP(GL_RGB, "gl-rgb"); FMAP(GL_RGBA, "gl-rgba"); default: return 0; } } /* small hacks: bitmaps are images with a special encoding (that is not recognized by the processors) */ static pf_symbol_t *bitmap_get_description(int width, int height, int encoding){ pf_symbol_t *fourcc = bitmap_fourcc_to_symbol(encoding); if (!fourcc) return pf_symbol("invalid"); return pf_symbolf("bitmap/%s/%d/%d", fourcc->s_name, width, height); } /* get the high level description for a packet TEMPLATE: image//// */ static pf_symbol_t *image_get_description(int width, int height, int depth, int encoding) { int bitdepth = PF_IMAGE_ENCODING_BITDEPTH(encoding); switch(PF_IMAGE_ENCODING_LAYOUT(encoding)){ default: return pf_symbol("invalid"); case PF_IMAGE_LAYOUT_PLANAR: return pf_symbolf("image/s%d/%d/%d/%d", bitdepth, width, height, depth); case PF_IMAGE_LAYOUT_420: PF_ASSERT(depth == 3); PF_ASSERT(bitdepth == 16); // only backward compat: the s8 version is not supported return pf_symbolf("image/YCrCb/%d/%d", width, height); case PF_IMAGE_LAYOUT_MONO: PF_ASSERT(depth == 1); PF_ASSERT(bitdepth == 16); // only backward compat: the s8 version is not supported return pf_symbolf("image/grey/%d/%d", width, height); } } static pf_symbol_t *packet_image_get_description(pf_image_t *image) { PF_ASSERT(image); PF_ASSERT(image->super.type == PF_IMAGE); return image_get_description(image->width, image->height, image->depth, image->encoding); } static pf_symbol_t *packet_bitmap_get_description(pf_image_t *image) { PF_ASSERT(image); PF_ASSERT(image->super.type == PF_BITMAP); return bitmap_get_description(image->width, image->height, image->encoding); } static pf_packet_t new_image_packet(u32 w, u32 h, u32 d, u32 bitdepth, u32 layout) { int encoding = PF_IMAGE_MAKE_ENCODING(layout, bitdepth); u32 size = w*h*d; u32 totalnbpixels = size; u32 packet_size = ( totalnbpixels * bitdepth ) / 8; switch(layout){ case PF_IMAGE_LAYOUT_PLANAR: break; case PF_IMAGE_LAYOUT_MONO: if (d != 1) return 0; break; case PF_IMAGE_LAYOUT_420: if (d != 3) return 0; packet_size >>= 1; break; default: PF_ASSERT(0); return 0; } if ((w != pf_image_cropdim(w)) || (h != pf_image_cropdim(h))) { pf_post("ERROR: invalid dimensions %d x %d", w, h); return 0; } pf_image_t *image = (pf_image_t *)pf_packet_create(PF_IMAGE, sizeof(pf_image_t), packet_size); if (!image) return 0; image->encoding = encoding; image->width = w; image->height = h; image->depth = d; image->super.desc = packet_image_get_description(image); image->super.theclass = image_class; return (pf_packet_t)image; } static pf_packet_t new_bitmap_packet(u32 w, u32 h, u32 d, u32 encoding, u32 size) { pf_image_t *image = (pf_image_t *)pf_packet_create(PF_BITMAP, sizeof(pf_image_t), size); if (!image) return 0; image->encoding = encoding; image->width = w; image->height = h; image->depth = d; image->super.desc = packet_bitmap_get_description(image); image->super.theclass = bitmap_class; return (pf_packet_t)image; } static pf_packet_t check_type(pf_packet_t p, pf_symbol_t *type){ /* check if all went well */ PF_ASSERT(p); pf_header_t *h = pf_packet_header(p); /* if type is not exact, delete the packet this can happen when a constructor decides to be robust. we no play that here. */ if (type != h->desc) { //PF_ASSERT(0); pf_post("WARNING: type error in check_type()"); // pf_packet_delete(p); p = 0; } return p; } /* factory for 'standard' packets : the old bitmap type. this type is mainly for storage. operations need the internal data type (signed fixed point) */ static pf_packet_t pf_bitmap_factory(pf_list_t *l){ pf_packet_t p = 0; pf_atom_t *a = l->first; if (!a) goto exit; PF_ASSERT(a->t == a_symbol && a->w.w_symbol == pf_symbol("bitmap")); CHECKNEXT(a_symbol); pf_symbol_t *s = a->w.w_symbol; CHECKNEXT(a_int); int w = a->w.w_int; CHECKNEXT(a_int); int h = a->w.w_int; int d = 3; // overridden by grey / alpha int encoding = 0; int bytes = w * h; // ordinary 1-4 channel stuff if (s == pf_symbol("grey")) { encoding = PF_FOURCC_GREY; d = 1; } else if (s == pf_symbol("greya")) { encoding = PF_FOURCC_GREYA; bytes *= 2; d = 2; } else if (s == pf_symbol("rgb")) { encoding = PF_FOURCC_RGB; bytes *= 3; } else if (s == pf_symbol("rgba")) { encoding = PF_FOURCC_RGBA; bytes *= 4; d = 4;} // with components swapped else if (s == pf_symbol("bgr")) { encoding = PF_FOURCC_BGR; bytes *= 3;} // with top/bottom swapped else if (s == pf_symbol("gl-grey")) { encoding = PF_FOURCC_GL_GREY; d = 1; } else if (s == pf_symbol("gl-greya")) { encoding = PF_FOURCC_GL_GREYA; bytes *= 2; d = 2; } else if (s == pf_symbol("gl-rgb")) { encoding = PF_FOURCC_GL_RGB; bytes *= 3; } else if (s == pf_symbol("gl-rgba")) { encoding = PF_FOURCC_GL_RGBA; bytes *= 4; d = 4;} // luma/chroma else if (s == pf_symbol("yv12")) { encoding = PF_FOURCC_YV12; bytes = bytes + bytes/2; } else if (s == pf_symbol("i420")) { encoding = PF_FOURCC_I420; bytes = bytes + bytes/2; } else if (s == pf_symbol("uyvy")) { encoding = PF_FOURCC_UYVY; bytes *= 2; } else if (s == pf_symbol("yuy2")) { encoding = PF_FOURCC_YUY2; bytes *= 2; } else { goto exit; } p = new_bitmap_packet(w,h,d,encoding,bytes); exit: return p; } // to make things simple, this maps fourcc formats to bitmap pf_packet_t pf_factory_newbitmap(unsigned int fourcc, unsigned int width, unsigned int height){ pf_symbol_t *sfourcc = bitmap_fourcc_to_symbol(fourcc); if (!fourcc) { pf_post("pf_bitmap_from_fourcc(): unsupported fourcc %x", fourcc); return 0; } return pf_factory_newpacket(pf_symbolf("bitmap/%s/%d/%d", sfourcc->s_name, width, height)); } /* the factory method: this is called by the packet factory if there is no previous packet that can be reused */ static pf_packet_t pf_image_factory(pf_list_t *l) { pf_symbol_t *s; int t; int w = 0; int h = 0; int d = 0; pf_packet_t p = 0; int n = 0; int m = 0; char *garbage = 0; int bitdepth = 0; int layout = PF_IMAGE_LAYOUT_PLANAR; pf_atom_t *a = l->first; if (!a) goto exit; PF_ASSERT(a->t == a_symbol && a->w.w_symbol == pf_symbol("image")); /* get type + bitdepth */ CHECKNEXT(a_symbol); s = a->w.w_symbol; // libtile image formats if (s == pf_symbol("s8")) bitdepth = 8; else if (s == pf_symbol("s16")) bitdepth = 16; // old style pdp formats (backward compat) else if (s == pf_symbol("YCrCb")) { bitdepth = 16; layout = PF_IMAGE_LAYOUT_420; } else if (s == pf_symbol("grey")) { bitdepth = 16; layout = PF_IMAGE_LAYOUT_MONO; } else goto exit; /* get dimensions */ CHECKNEXT(a_int); w = a->w.w_int; if (w < 1) goto exit; CHECKNEXT(a_int); h = a->w.w_int; if (h < 1) goto exit; // depth is inferred for old style pdp packets if (layout == PF_IMAGE_LAYOUT_PLANAR){ CHECKNEXT(a_int); d = a->w.w_int; if (d < 1) goto exit; } else { if (layout == PF_IMAGE_LAYOUT_420) d = 3; else if (layout == PF_IMAGE_LAYOUT_MONO) d = 1; else goto exit; } /* create */ p = new_image_packet(w,h,d,bitdepth,layout); exit: return p; } void pf_image_setup(void) { /* setup the class object */ image_class = pf_class_new(pf_symbol("image"), pf_image_factory); bitmap_class = pf_class_new(pf_symbol("bitmap"), pf_bitmap_factory); } // stuf below this line is depreciated /* shortcut factory method */ pf_packet_t pf_factory_newimage(char *type, unsigned int width, unsigned int height, unsigned int depth) { return pf_factory_newpacket(pf_symbolf("image/%s/%d/%d/%d", type, width, height, depth)); }