X-Git-Url: https://git.cinelerra-gg.org/git/?p=goodguy%2Fcinelerra.git;a=blobdiff_plain;f=cinelerra-5.1%2Fguicast%2Fvframe.C;h=44d7f97e6284a3f5f2c333902cc3dfceef930afe;hp=4960ff26834951df49a502ecb9532b506e10c61d;hb=eb9df615719cf3afe2bc08035900e5d3451034e1;hpb=8fd64d1d3770c95e2a7cba1049e909cadb4e1fbf diff --git a/cinelerra-5.1/guicast/vframe.C b/cinelerra-5.1/guicast/vframe.C index 4960ff26..44d7f97e 100644 --- a/cinelerra-5.1/guicast/vframe.C +++ b/cinelerra-5.1/guicast/vframe.C @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -73,11 +74,6 @@ VFrameScene::~VFrameScene() } - - - - - //static BCCounter counter; VFramePng::VFramePng(unsigned char *png_data, double s) @@ -281,6 +277,8 @@ int VFrame::reset_parameters(int do_opengl) is_keyframe = 0; pixel_rgb = 0x000000; // BLACK pixel_yuv = 0x008080; + draw_alpha = 1.f; + draw_flags = ALIAS_OFF; stipple = 0; clear_color = 0x000000; clear_alpha = 0x00; @@ -336,7 +334,7 @@ if( memory_type != VFrame::SHARED ) shmid = -1; break; - case VFrame::SHMGET: + case VFrame::SHM_GET: if(data) shmdt(data); data = 0; @@ -418,7 +416,7 @@ long VFrame::get_bytes_per_line() long VFrame::get_data_size() { - return calculate_data_size(w, h, bytes_per_line, color_model) - 4; + return calculate_data_size(w, h, bytes_per_line, color_model) - BC_COLOR_ALIGN; } long VFrame::calculate_data_size(int w, int h, int bytes_per_line, int color_model) @@ -502,7 +500,7 @@ int VFrame::allocate_data(unsigned char *data, int shmid, bytes_per_line : this->bytes_per_pixel * w; // Allocate data + padding for MMX - if(data) { + if( data ) { //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data); memory_type = VFrame::SHARED; this->data = data; @@ -511,9 +509,16 @@ int VFrame::allocate_data(unsigned char *data, int shmid, this->u_offset = u_offset; this->v_offset = v_offset; } - else if(shmid >= 0) { - memory_type = VFrame::SHMGET; + else if( shmid >= 0 ) { + memory_type = VFrame::SHM_GET; this->data = (unsigned char*)shmat(shmid, NULL, 0); + if( this->data == (unsigned char*)-1 ) { + printf("VFrame::allocate_data %d could not attach" + " shared memory, %dx%d (model %d) shmid=0x%08x\n", + __LINE__, w, h, color_model, shmid); + BC_Trace::dump_shm_stats(stdout); + exit(1); + } //printf("VFrame::allocate_data %d shmid=%d data=%p\n", __LINE__, shmid, this->data); this->shmid = shmid; this->y_offset = y_offset; @@ -530,20 +535,24 @@ int VFrame::allocate_data(unsigned char *data, int shmid, this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777); if( this->shmid >= 0 ) { this->data = (unsigned char*)shmat(this->shmid, NULL, 0); -//printf("VFrame::allocate_data %d %d %d %p\n", __LINE__, size, this->shmid, this->data); -// This causes it to automatically delete when the program exits. - shmctl(this->shmid, IPC_RMID, 0); + if( this->data == (unsigned char *)-1 ) this->data = 0; } - else { + if( !this->data ) { printf("VFrame::allocate_data %d could not allocate" " shared memory, %dx%d (model %d) size=0x%08x\n", __LINE__, w, h, color_model, size); BC_Trace::dump_shm_stats(stdout); + exit(1); } +// This causes it to automatically delete when the program exits. + shmctl(this->shmid, IPC_RMID, 0); } -// Have to use malloc for libpng - if( !this->data ) { + else { this->data = (unsigned char *)malloc(size); + if( !this->data ) { + printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h); + exit(1); + } this->shmid = -1; } // Memory check @@ -551,8 +560,6 @@ int VFrame::allocate_data(unsigned char *data, int shmid, // printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n", // this, this->w, this->h, this->data); - if(!this->data) - printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h); #ifdef LEAKER printf("==new %p from %p sz %d\n", this->data, __builtin_return_address(0), size); #endif @@ -586,7 +593,7 @@ void VFrame::set_memory(unsigned char *data, else if(shmid >= 0) { - memory_type = VFrame::SHMGET; + memory_type = VFrame::SHM_GET; this->data = (unsigned char*)shmat(shmid, NULL, 0); this->shmid = shmid; } @@ -628,7 +635,7 @@ void VFrame::set_compressed_memory(unsigned char *data, else if(shmid >= 0) { - memory_type = VFrame::SHMGET; + memory_type = VFrame::SHM_GET; this->data = (unsigned char*)shmat(shmid, NULL, 0); this->shmid = shmid; } @@ -667,65 +674,76 @@ int VFrame::reallocate( int VFrame::allocate_compressed_data(long bytes) { - if(bytes < 1) return 1; + if( bytes < 1 ) return 1; // Want to preserve original contents - if(data && compressed_allocated < bytes) - { + if( data && compressed_allocated < bytes ) { int new_shmid = -1; unsigned char *new_data = 0; - if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm) - { - new_shmid = shmget(IPC_PRIVATE, - bytes, - IPC_CREAT | 0777); - new_data = (unsigned char*)shmat(new_shmid, NULL, 0); + if( BC_WindowBase::get_resources()->use_vframe_shm() && use_shm ) { + new_shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777); + if( new_shmid >= 0 ) { + new_data = (unsigned char *) shmat(new_shmid, NULL, 0); + if( new_data == (unsigned char *)-1 ) new_data = 0; + } + if( !new_data ) { + printf("VFrame::allocate_compressed_data %d could not allocate" + " shared memory, %ld\n", __LINE__, bytes); + BC_Trace::dump_shm_stats(stdout); + exit(1); + } shmctl(new_shmid, IPC_RMID, 0); } - else - { + else { // Have to use malloc for libpng new_data = (unsigned char *)malloc(bytes); + if( !new_data ) { + printf("VFrame::allocate_compressed_data %ld: memory exhausted.\n", bytes); + exit(1); + } } bcopy(data, new_data, compressed_allocated); UNBUFFER(data); - if(memory_type == VFrame::PRIVATE) - { - if(shmid > 0) { - if(data) - shmdt(data); + if( memory_type == VFrame::PRIVATE ) { + if( shmid > 0 ) { + if( data ) shmdt(data); } else free(data); } - else - if(memory_type == VFrame::SHMGET) - { - if(data) - shmdt(data); + else if( memory_type == VFrame::SHM_GET ) { + if( data ) shmdt(data); } data = new_data; shmid = new_shmid; compressed_allocated = bytes; } - else - if(!data) - { - if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm) - { - shmid = shmget(IPC_PRIVATE, - bytes, - IPC_CREAT | 0777); - data = (unsigned char*)shmat(shmid, NULL, 0); + else if( !data ) { + if( BC_WindowBase::get_resources()->use_vframe_shm() && use_shm ) { + shmid = shmget(IPC_PRIVATE, bytes, IPC_CREAT | 0777); + if( shmid >= 0 ) { + data = (unsigned char *)shmat(shmid, NULL, 0); + if( data == (unsigned char *)-1 ) data = 0; + } + if( !data ) { + printf("VFrame::allocate_compressed_data %d: could not allocate" + " shared memory, %ld\n", __LINE__, bytes); + BC_Trace::dump_shm_stats(stdout); + exit(1); + } shmctl(shmid, IPC_RMID, 0); } - else - { + else { // Have to use malloc for libpng data = (unsigned char *)malloc(bytes); + if( !data ) { + printf("VFrame::allocate_compressed_data %d: memory exhausted, %ld\n", + __LINE__, bytes); + exit(1); + } } compressed_allocated = bytes; @@ -785,8 +803,7 @@ int VFramePng::read_png(const unsigned char *data, long sz, double xscale, doubl if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8) png_set_expand(png_ptr); - if (src_color_model == PNG_COLOR_TYPE_GRAY || - src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA) + if (src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); /* expand paletted or RGB images with transparency to full alpha channels @@ -796,26 +813,22 @@ int VFramePng::read_png(const unsigned char *data, long sz, double xscale, doubl png_set_expand(png_ptr); } - switch(src_color_model) - { - case PNG_COLOR_TYPE_GRAY: - case PNG_COLOR_TYPE_RGB: - new_color_model = BC_RGB888; - break; - - case PNG_COLOR_TYPE_GRAY_ALPHA: - case PNG_COLOR_TYPE_RGB_ALPHA: - default: - new_color_model = BC_RGBA8888; - break; - - case PNG_COLOR_TYPE_PALETTE: - if(have_alpha) - new_color_model = BC_RGBA8888; - else - new_color_model = BC_RGB888; + switch(src_color_model) { + case PNG_COLOR_TYPE_GRAY: + new_color_model = BC_GREY8; + break; + case PNG_COLOR_TYPE_RGB: + new_color_model = BC_RGB888; + break; + case PNG_COLOR_TYPE_PALETTE: + new_color_model = have_alpha ? BC_RGBA8888 : BC_RGB888; + break; + case PNG_COLOR_TYPE_GRAY_ALPHA: + case PNG_COLOR_TYPE_RGB_ALPHA: + default: + new_color_model = BC_RGBA8888; + break; } - reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1); //printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows()); @@ -829,6 +842,8 @@ int VFramePng::read_png(const unsigned char *data, long sz, double xscale, doubl return 1; } int ww = w * xscale, hh = h * yscale; + if( ww < 1 ) ww = 1; + if( hh < 1 ) hh = 1; if( ww != w || hh != h ) { VFrame vframe(*this); reallocate(NULL, -1, 0, 0, 0, ww, hh, color_model, -1); @@ -998,12 +1013,12 @@ int VFrame::get_clear_alpha() { return clear_alpha; } void VFrame::clear_frame() { - if( clear_color >= 0 ) { - BC_CModels::init_color(clear_color, clear_alpha, get_rows(), get_color_model(), - get_y(), get_u(), get_v(), 0,0, get_w(),get_h(), get_bytes_per_line()); - } - else - black_frame(); + if( clear_color >= 0 && + !BC_CModels::init_color(clear_color, clear_alpha, + get_rows(), get_color_model(), get_y(), get_u(), get_v(), + 0,0, get_w(),get_h(), get_bytes_per_line()) ) + return; + black_frame(); } void VFrame::rotate90() @@ -1119,15 +1134,10 @@ void VFrame::flip_horiz() int VFrame::copy_from(VFrame *frame) { - if(this->w != frame->get_w() || - this->h != frame->get_h()) - { + if( this->w != frame->get_w() || + this->h != frame->get_h() ) { printf("VFrame::copy_from %d sizes differ src %dx%d != dst %dx%d\n", - __LINE__, - frame->get_w(), - frame->get_h(), - get_w(), - get_h()); + __LINE__, frame->get_w(), frame->get_h(), get_w(), get_h()); return 1; } @@ -1135,50 +1145,46 @@ int VFrame::copy_from(VFrame *frame) int h = MIN(this->h, frame->get_h()); timestamp = frame->timestamp; - switch(frame->color_model) - { - case BC_COMPRESSED: - allocate_compressed_data(frame->compressed_size); - memcpy(data, frame->data, frame->compressed_size); - this->compressed_size = frame->compressed_size; - break; + switch( frame->color_model ) { + case BC_COMPRESSED: + allocate_compressed_data(frame->compressed_size); + memcpy(data, frame->data, frame->compressed_size); + this->compressed_size = frame->compressed_size; + break; - case BC_YUV410P: - memcpy(get_y(), frame->get_y(), w * h); - memcpy(get_u(), frame->get_u(), w / 4 * h / 4); - memcpy(get_v(), frame->get_v(), w / 4 * h / 4); - break; + case BC_YUV410P: + memcpy(get_y(), frame->get_y(), w * h); + memcpy(get_u(), frame->get_u(), w / 4 * h / 4); + memcpy(get_v(), frame->get_v(), w / 4 * h / 4); + break; - case BC_YUV420P: - case BC_YUV420PI: - case BC_YUV411P: + case BC_YUV420P: + case BC_YUV420PI: + case BC_YUV411P: //printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v()); - memcpy(get_y(), frame->get_y(), w * h); - memcpy(get_u(), frame->get_u(), w * h / 4); - memcpy(get_v(), frame->get_v(), w * h / 4); - break; + memcpy(get_y(), frame->get_y(), w * h); + memcpy(get_u(), frame->get_u(), w * h / 4); + memcpy(get_v(), frame->get_v(), w * h / 4); + break; - case BC_YUV422P: + case BC_YUV422P: //printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v()); - memcpy(get_y(), frame->get_y(), w * h); - memcpy(get_u(), frame->get_u(), w * h / 2); - memcpy(get_v(), frame->get_v(), w * h / 2); - break; + memcpy(get_y(), frame->get_y(), w * h); + memcpy(get_u(), frame->get_u(), w * h / 2); + memcpy(get_v(), frame->get_v(), w * h / 2); + break; - case BC_YUV444P: + case BC_YUV444P: //printf("%d %d %p %p %p %p %p %p\n", w, h, get_y(), get_u(), get_v(), frame->get_y(), frame->get_u(), frame->get_v()); - memcpy(get_y(), frame->get_y(), w * h); - memcpy(get_u(), frame->get_u(), w * h); - memcpy(get_v(), frame->get_v(), w * h); - break; - default: -// printf("VFrame::copy_from %d\n", calculate_data_size(w, -// h, -// -1, -// frame->color_model)); + memcpy(get_y(), frame->get_y(), w * h); + memcpy(get_u(), frame->get_u(), w * h); + memcpy(get_v(), frame->get_v(), w * h); + break; + default: +// printf("VFrame::copy_from %d\n", calculate_data_size(w, h, -1, frame->color_model)); // Copy without extra 4 bytes in case the source is a hardware device - memmove(data, frame->data, get_data_size()); - break; + memmove(data, frame->data, get_data_size()); + break; } return 0; @@ -1397,109 +1403,120 @@ int VFrame::get_memory_usage() // a (~alpha) transparency, 0x00==solid .. 0xff==transparent void VFrame::set_pixel_color(int rgb, int a) { - pixel_rgb = (rgb&0xffffff) | ~a<<24; + pixel_rgb = (~a<<24) | (rgb&0xffffff); int ir = 0xff & (pixel_rgb >> 16); int ig = 0xff & (pixel_rgb >> 8); int ib = 0xff & (pixel_rgb >> 0); YUV::yuv.rgb_to_yuv_8(ir, ig, ib); - pixel_yuv = (~a<<24) | (ir<<16) | (ig<<8) | (ib<<0); + pixel_yuv = (~a<<24) | (ir<<16) | (ig<<8) | (ib<<0); } void VFrame::set_stiple(int mask) { stipple = mask; } - -int VFrame::draw_pixel(int x, int y) +void VFrame::set_draw_alpha(float alpha) { - if( x < 0 || y < 0 || x >= get_w() || y >= get_h() ) return 1; - -#define DRAW_PIXEL(type, r, g, b, comps, a) { \ - type **rows = (type**)get_rows(); \ - type *rp = rows[y], *bp = rp + x*comps; \ - bp[0] = r; \ - if( comps > 1 ) { bp[1] = g; bp[2] = b; } \ - if( comps == 4 ) bp[3] = a; \ + draw_alpha = alpha; +} +void VFrame::set_draw_flags(int flags) +{ + draw_flags = flags; } + +int VFrame::draw_pixel(float x, float y, float a) +{ + int ix = x, iy = y; + if( ix < 0 || iy < 0 || ix >= get_w() || iy >= get_h() ) return 1; + if( a <= 0 ) return 0; + if( a > 1 ) a = 1; + int color = BC_CModels::is_yuv(color_model) ? pixel_yuv : pixel_rgb; float fr = 0, fg = 0, fb = 0, fa = 0; - int pixel_color = BC_CModels::is_yuv(color_model) ? pixel_yuv : pixel_rgb; - int ir = (0xff & (pixel_color >> 16)); - int ig = (0xff & (pixel_color >> 8)); - int ib = (0xff & (pixel_color >> 0)); - int ia = (0xff & (pixel_color >> 24)) ^ 0xff; // transparency, not opacity - if( (x+y) & stipple ) { + int ir = (0xff & (color >> 16)); + int ig = (0xff & (color >> 8)); + int ib = (0xff & (color >> 0)); + int ia = (0xff & ~(color >> 24)); // transparency, not opacity + if( (ix+iy) & stipple ) { ir = 255 - ir; ig = 255 - ig; ib = 255 - ib; } int rr = (ir<<8) | ir, gg = (ig<<8) | ig, bb = (ib<<8) | ib, aa = (ia<<8) | ia; + float fmax = 65535.f; fa = aa/fmax; if( BC_CModels::is_float(color_model) ) { - fr = rr/65535.f; fg = gg/65535.f; fb = bb/65535.f; fa = aa/65535.f; + fr = rr/fmax; fg = gg/fmax; fb = bb/fmax; } +#define DRAW_PIXEL(cmdl, type, r, g, b, ofs, max, comps) \ +case cmdl: { \ + float src_a = fa*draw_alpha, src_1a = 1 - src_a; \ + type **rows = (type**)get_rows(); \ + type *rp = rows[iy], *bp = rp + ix*comps; \ + bp[0] = src_a * r + src_1a * bp[0]; \ + if( comps > 1 ) { \ + bp[1] = src_a * (g-ofs) + src_1a * (bp[1]-ofs) + ofs; \ + bp[2] = src_a * (b-ofs) + src_1a * (bp[2]-ofs) + ofs; \ + } \ + if( comps == 4 ) \ + bp[3] = src_a * max + src_1a * bp[3]; \ + break;\ +} + switch(get_color_model()) { - case BC_A8: - DRAW_PIXEL(uint8_t, ib, 0, 0, 1, 0); - break; - case BC_RGB888: - case BC_YUV888: - DRAW_PIXEL(uint8_t, ir, ig, ib, 3, 0); - break; - case BC_RGBA8888: - case BC_YUVA8888: - DRAW_PIXEL(uint8_t, ir, ig, ib, 4, ia); - break; - case BC_RGB161616: - case BC_YUV161616: - DRAW_PIXEL(uint16_t, rr, gg, bb, 3, 0); - break; - case BC_RGBA16161616: - case BC_YUVA16161616: - DRAW_PIXEL(uint16_t, rr, gg, bb, 4, aa); - break; - case BC_RGB_FLOAT: - DRAW_PIXEL(float, fr, fg, fb, 3, 0); - break; - case BC_RGBA_FLOAT: - DRAW_PIXEL(float, fr, fg, fb, 4, fa); - break; + DRAW_PIXEL(BC_A8, uint8_t, ib, 0, 0, 0x00, 0xff, 1); + DRAW_PIXEL(BC_RGB888, uint8_t, ir, ig, ib, 0x00, 0xff, 3); + DRAW_PIXEL(BC_YUV888, uint8_t, ir, ig, ib, 0x80, 0xff, 3); + DRAW_PIXEL(BC_RGBA8888, uint8_t, ir, ig, ib, 0x00, 0xff, 4); + DRAW_PIXEL(BC_YUVA8888, uint8_t, ir, ig, ib, 0x80, 0xff, 4); + DRAW_PIXEL(BC_RGB161616, uint16_t, rr, gg, bb, 0x0000, 0xffff, 3); + DRAW_PIXEL(BC_YUV161616, uint16_t, rr, gg, bb, 0x8000, 0xffff, 3); + DRAW_PIXEL(BC_RGBA16161616, uint16_t, rr, gg, bb, 0x0000, 0xffff, 4); + DRAW_PIXEL(BC_YUVA16161616, uint16_t, rr, gg, bb, 0x8000, 0xffff, 4); + DRAW_PIXEL(BC_RGB_FLOAT, float, fr, fg, fb, 0., 1., 3); + DRAW_PIXEL(BC_RGBA_FLOAT, float, fr, fg, fb, 0., 1., 4); } return 0; } +int VFrame::draw_pixel(float x, float y, float frac, int axis) +{ + if( draw_flags ) { + int xs = axis, ys = 1-axis; + if( draw_flags & ALIAS_TOP ) draw_pixel(x-xs, y-ys, 1-frac); + draw_pixel(x, y, draw_flags & ALIAS_CTR ? 1-frac : 1); + if( draw_flags & ALIAS_BOT ) draw_pixel(x+xs, y+ys, frac); + } + else + draw_pixel(x, y); + return 0; +} -// Bresenham's -void VFrame::draw_line(int x1, int y1, int x2, int y2) +void VFrame::draw_line(float x1, float y1, float x2, float y2) { if( y1 > y2 ) { int tx = x1; x1 = x2; x2 = tx; int ty = y1; y1 = y2; y2 = ty; } - - int x = x1, y = y1; - int dx = x2-x1, dy = y2-y1; - int dx2 = 2*dx, dy2 = 2*dy; - if( dx < 0 ) dx = -dx; - int r = dx > dy ? dx : dy, n = r; - int dir = 0; - if( dx2 < 0 ) dir += 1; - if( dy >= dx ) { - if( dx2 >= 0 ) do { /* +Y, +X */ - draw_pixel(x, y++); - if( (r -= dx2) < 0 ) { r += dy2; ++x; } - } while( --n >= 0 ); - else do { /* +Y, -X */ - draw_pixel(x, y++); - if( (r += dx2) < 0 ) { r += dy2; --x; } - } while( --n >= 0 ); + float dx = x2-x1, dy = y2-y1; + float s = dx ? dy/dx : 1; + float t = dy ? dx/dy : 0; + int xs = dx < 0 ? -1 : 1; + dx *= xs; + int idx = (int)x2 - (int)x1; + int idy = (int)y2 - (int)y1; + int d = dx >= dy ? abs(idx) : idy; + float x = x1, y = y1; + if( dx > dy ) { + draw_pixel(x, y, y-(int)y, 0); + while( --d >= 0 ) { + y = y1 + ((x += xs) - x1) * s; + draw_pixel(x, y, y-(int)y, 0); + } } else { - if( dx2 >= 0 ) do { /* +X, +Y */ - draw_pixel(x++, y); - if( (r -= dy2) < 0 ) { r += dx2; ++y; } - } while( --n >= 0 ); - else do { /* -X, +Y */ - draw_pixel(x--, y); - if( (r -= dy2) < 0 ) { r -= dx2; ++y; } - } while( --n >= 0 ); + draw_pixel(x, y, x-(int)x, 1); + while( --d >= 0 ) { + x = x1 + (++y - y1) * t; + draw_pixel(x, y, x-(int)x, 1); + } } } @@ -1565,7 +1582,15 @@ void smooth_line::draw() if( abs(rr) < abs(r) ) moveX(rr); } -xit: vframe->draw_pixel(sx, sy); +xit: +// vframe->draw_pixel(sx, sy); + float vx = abs(dx), vy = abs(dy); + float vv = 4*(vx > vy ? dx : dy); + float frac = vv ? -r / vv : 0; + frac = (1+frac) / 2; + bclamp(frac, 0, 1); + int axis = abs(dx) >= abs(dy) ? 1 : 0; + vframe->draw_pixel(sx, sy, frac, axis); } void VFrame::draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3) @@ -1699,10 +1724,10 @@ void smooth_line::init1(int x1,int y1, int x2,int y2, int x3,int y3) xmxx = ex; xmxy = ey; } if( xs > 0 ) - vframe->draw_pixel(sx, sy); + vframe->draw_pixel(sx, sy, 0, 0); while( xs*(sx-xmxx) < 0 && (xs*dx < 0 || rx() < 0) ) { moveX(rx()); - vframe->draw_pixel(sx, sy); + vframe->draw_pixel(sx, sy, 0, 0); } } @@ -1726,9 +1751,9 @@ void VFrame::smooth_draw(int x1, int y1, int x2, int y2, int x3, int y3) else if( y1 < y2 && y3 < y2 ) { smooth_line lt(this), rt(this); // Q on top lt.init0(x1, y1, x2, y2, x3, y3, 1); - draw_pixel(lt.sx, lt.sy); + draw_pixel(lt.sx, lt.sy, 0, 0); rt.init0(x1, y1, x2, y2, x3, y3, -1); - draw_pixel(rt.sx, rt.sy); + draw_pixel(rt.sx, rt.sy, 0, 0); while( !lt.done || !rt.done ) { lt.draw(); rt.draw(); @@ -1737,7 +1762,7 @@ void VFrame::smooth_draw(int x1, int y1, int x2, int y2, int x3, int y3) else { smooth_line pt(this); // Q in between pt.init0(x1, y1, x2, y2, x3, y3, 0); - draw_pixel(pt.sx, pt.sy); + draw_pixel(pt.sx, pt.sy, 0, 1); while( !pt.done ) { pt.draw(); } @@ -1832,3 +1857,255 @@ void VFrame::draw_t(int x, int y, int sz) } +// jpeg decompress +class jpeg_err : public jpeg_error_mgr +{ + static void s_error_exit(j_common_ptr cp); + static void s_output_message(j_common_ptr cp); +public: + jpeg_err() { + jpeg_std_error((jpeg_error_mgr *)this); + error_exit = s_error_exit; + output_message = s_output_message; + } + ~jpeg_err() {} +}; + +class jpeg_src : public jpeg_source_mgr +{ + static void s_init_source(j_decompress_ptr jp); + static boolean s_fill_input_buffer(j_decompress_ptr jp); + static void s_skip_input_data(j_decompress_ptr jp, long len); + static void s_term_source(j_decompress_ptr jp); + static boolean s_resync_to_restart(j_decompress_ptr jp, int v); +public: + jpeg_src(); + ~jpeg_src(); + int jpeg_file(int fd); + int jpeg_mem(const unsigned char *bfr, long len); + + int fd; + unsigned char *mbfr; + long mlen; + enum { buffer_sz=0x10000, file_sz=0x100000, }; + unsigned char *buffer; + boolean fill_buffer(); + void skip_data(long len); +}; + +class JpegVFrame : public jpeg_decompress_struct +{ +public: + JpegVFrame(); + ~JpegVFrame(); + int read_jpeg(VFrame *vfrm, double xs, double ys, int jpeg_model); + + jpeg_err jerr; + jpeg_src jsrc; + int debug, ret; +}; + + +void jpeg_err:: s_error_exit(j_common_ptr cp) +{ + JpegVFrame *jpeg = (JpegVFrame *)cp; + jpeg->ret = 1; + if( !jpeg->debug ) return; + printf("s_error_exit()\n"); +} + +void jpeg_err:: +s_output_message(j_common_ptr cp) +{ + JpegVFrame *jpeg = (JpegVFrame *)cp; + if( !jpeg->debug ) return; + char msg[JMSG_LENGTH_MAX]; + (*cp->err->format_message)(cp, msg); + printf("s_output_message() = %s\n",&msg[0]); +} + + +jpeg_src::jpeg_src() +{ + init_source = s_init_source; + fill_input_buffer = s_fill_input_buffer; + skip_input_data = s_skip_input_data; + resync_to_restart = s_resync_to_restart; + term_source = s_term_source; + + fd = -1; + buffer = 0; + mbfr = 0; + mlen = -1; +} + +jpeg_src::~jpeg_src() +{ + if( mbfr ) ::munmap(mbfr, mlen); + delete [] buffer; +} + +int jpeg_src::jpeg_file(int fd) +{ + this->fd = fd; + struct stat st; + if( fstat(fd, &st) || !st.st_size ) return 0; + if( st.st_size < file_sz ) { + mbfr = (unsigned char *)::mmap(0, mlen = st.st_size, + PROT_READ, MAP_SHARED, fd, 0); + if( mbfr == MAP_FAILED ) return 0; + next_input_byte = mbfr; + bytes_in_buffer = mlen; + } + else { + buffer = new unsigned char[buffer_sz]; + next_input_byte = &buffer[0]; + bytes_in_buffer = 0; + } + return 1; +} +int jpeg_src::jpeg_mem(const unsigned char *bfr, long len) +{ + next_input_byte = bfr; + bytes_in_buffer = len; + return 1; +} + +void jpeg_src::s_init_source(j_decompress_ptr jp) {} +void jpeg_src::s_term_source(j_decompress_ptr jp) {} + +boolean jpeg_src::s_resync_to_restart(j_decompress_ptr jp, int v) +{ + return jpeg_resync_to_restart(jp, v); +} + +boolean jpeg_src::s_fill_input_buffer(j_decompress_ptr jp) +{ + JpegVFrame *jpeg = (JpegVFrame *)jp; + return jpeg->jsrc.fill_buffer(); +} + +boolean jpeg_src::fill_buffer() +{ + if( mbfr || fd < 0 ) return 0; + long n = ::read(fd, buffer, buffer_sz); + if( n < 0 ) perror("jpeg read"); + if( !n ) return 0; + next_input_byte = buffer; + bytes_in_buffer = n; + return 1; +} + +void jpeg_src::s_skip_input_data(j_decompress_ptr jp, long len) +{ + JpegVFrame *jpeg = (JpegVFrame *)jp; + jpeg->jsrc.skip_data(len); +} + +void jpeg_src::skip_data(long len) +{ + while( len > (long) bytes_in_buffer ) { + len -= (long) bytes_in_buffer; + if( !fill_buffer() ) return; + } + next_input_byte += len; + bytes_in_buffer -= len; +} + + +JpegVFrame::JpegVFrame() +{ + jpeg_create_decompress(this); + debug = 1; ret = 0; + err = &jerr; src = &jsrc; +} +JpegVFrame::~JpegVFrame() +{ + jpeg_destroy_decompress(this); +} + +int JpegVFrame::read_jpeg(VFrame *vfrm, double xs, double ys, int jpeg_model) +{ + VFrame *xfrm = vfrm; + int color_model = xfrm->get_color_model(); + if( color_model == BC_COMPRESSED ) color_model = jpeg_model; + jpeg_abort((jpeg_common_struct *)this); + if( jpeg_read_header(this, TRUE) != JPEG_HEADER_OK ) return 0; + jpeg_calc_output_dimensions(this); + quantize_colors = FALSE; + out_color_space = + jpeg_model == BC_YUV888 ? JCS_YCbCr : + jpeg_model == BC_GREY8 ? JCS_GRAYSCALE : JCS_RGB; + jpeg_calc_output_dimensions(this); + int w = bmax(image_width*xs, 1.); + int h = bmax(image_height*ys, 1.); + vfrm->reallocate(0, -1, 0, 0, 0, w, h, color_model, -1); + if( w != (int)image_width || h != (int)image_height || + color_model != jpeg_model ) + xfrm = new VFrame(image_width, image_height, jpeg_model); + unsigned char *pic = xfrm->get_data(); + int linesz = xfrm->get_bytes_per_line(); + jpeg_start_decompress(this); + while( !ret && output_scanline < image_height ) { + JSAMPROW rowptr = (JSAMPROW) &pic[output_scanline * linesz]; + jpeg_read_scanlines(this, &rowptr, (JDIMENSION) 1); + } + jpeg_finish_decompress(this); + if( vfrm != xfrm ) { + vfrm->transfer_from(xfrm); + delete xfrm; + } + return 1; +} + +int VFrameJpeg::read_jpeg(const unsigned char *data, long sz, + double xscale, double yscale, int jpeg_model) +{ + JpegVFrame jpeg; + jpeg.jsrc.jpeg_mem(data, sz); + return jpeg.read_jpeg(this, xscale, yscale, jpeg_model); +} + +VFrameJpeg::VFrameJpeg(const unsigned char *jpeg_data, double s) +{ + long image_size = + ((long)jpeg_data[0] << 24) | ((long)jpeg_data[1] << 16) | + ((long)jpeg_data[2] << 8) | (long)jpeg_data[3]; + if( !s ) s = BC_WindowBase::get_resources()->icon_scale; + read_jpeg(jpeg_data+4, image_size, s, s, BC_RGB888); +} + +VFrameJpeg::VFrameJpeg(const unsigned char *jpeg_data, long image_size, double xs, double ys) +{ + if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale; + if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale; + read_jpeg(jpeg_data, image_size, xs, ys, BC_RGB888); +} + +VFrameJpeg::~VFrameJpeg() +{ +} + + +VFrame *VFrameJpeg::vframe_jpeg(int fd, double xs, double ys, int jpeg_model) +{ + JpegVFrame jpeg; + jpeg.jsrc.jpeg_file(fd); + VFrame *vfrm = new VFrame(); + if( !jpeg.read_jpeg(vfrm, xs, ys, jpeg_model) ) { + delete vfrm; vfrm = 0; + } + return vfrm; +} + +VFrame *VFrameJpeg::vframe_jpeg(const char *jpeg_path, double xs, double ys, int jpeg_model) +{ + VFrame *vframe = 0; + int fd = ::open(jpeg_path, O_RDONLY); + if( fd >= 0 ) { + vframe = vframe_jpeg(fd, xs, ys, jpeg_model); + ::close(fd); + } + return vframe; +} +