4 * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33 #include "bcpbuffer.h"
34 #include "bcresources.h"
35 #include "bcsignals.h"
36 #include "bcsynchronous.h"
37 #include "bctexture.h"
38 #include "bcwindowbase.h"
40 #include "bccmodels.h"
46 static void png_read_function(png_structp png_ptr,
47 png_bytep data, png_size_t length)
49 VFrame *frame = (VFrame*)png_get_io_ptr(png_ptr);
50 if(frame->image_size - frame->image_offset < (long)length)
52 printf("PngReadFunction::png_read_function %d: overrun\n", __LINE__);
53 length = frame->image_size - frame->image_offset;
56 memcpy(data, &frame->image[frame->image_offset], length);
57 frame->image_offset += length;
67 VFrameScene::VFrameScene()
71 VFrameScene::~VFrameScene()
81 //static BCCounter counter;
83 VFramePng::VFramePng(unsigned char *png_data, double s)
86 ((long)png_data[0] << 24) | ((long)png_data[1] << 16) |
87 ((long)png_data[2] << 8) | (long)png_data[3];
88 if( !s ) s = BC_WindowBase::get_resources()->icon_scale;
89 read_png(png_data+4, image_size, s, s);
92 VFramePng::VFramePng(unsigned char *png_data, long image_size, double xs, double ys)
94 if( !xs ) xs = BC_WindowBase::get_resources()->icon_scale;
95 if( !ys ) ys = BC_WindowBase::get_resources()->icon_scale;
96 read_png(png_data, image_size, xs, ys);
99 VFramePng::~VFramePng()
103 VFrame *VFramePng::vframe_png(int fd, double xs, double ys)
106 if( fstat(fd, &st) ) return 0;
107 long len = st.st_size;
110 unsigned char *bfr = (unsigned char *)
111 ::mmap (NULL, len, PROT_READ, MAP_SHARED, fd, 0);
112 if( bfr == MAP_FAILED ) return 0;
113 VFrame *vframe = new VFramePng(bfr, len, xs, ys);
114 if( (w=vframe->get_w()) <= 0 || (h=vframe->get_h()) <= 0 ||
115 vframe->get_data() == 0 ) { delete vframe; vframe = 0; }
119 VFrame *VFramePng::vframe_png(const char *png_path, double xs, double ys)
122 int fd = ::open(png_path, O_RDONLY);
124 vframe = vframe_png(fd, xs, ys);
130 VFrame::VFrame(VFrame &frame)
133 params = new BC_Hash;
134 use_shm = frame.use_shm;
135 allocate_data(0, -1, 0, 0, 0, frame.w, frame.h,
136 frame.color_model, frame.bytes_per_line);
141 VFrame::VFrame(int w, int h, int color_model, long bytes_per_line)
144 // use bytes_per_line == 0 to allocate default unshared
145 if( !bytes_per_line ) { bytes_per_line = -1; use_shm = 0; }
146 params = new BC_Hash;
147 allocate_data(data, -1, 0, 0, 0, w, h,
148 color_model, bytes_per_line);
151 VFrame::VFrame(unsigned char *data, int shmid, int w, int h,
152 int color_model, long bytes_per_line)
155 params = new BC_Hash;
156 allocate_data(data, shmid, 0, 0, 0, w, h,
157 color_model, bytes_per_line);
160 VFrame::VFrame(unsigned char *data, int shmid,
161 long y_offset, long u_offset, long v_offset,
162 int w, int h, int color_model, long bytes_per_line)
165 params = new BC_Hash;
166 allocate_data(data, shmid, y_offset, u_offset, v_offset, w, h,
167 color_model, bytes_per_line);
170 VFrame::VFrame(BC_Bitmap *bitmap, int w, int h,
171 int color_model, long bytes_per_line)
174 params = new BC_Hash;
176 unsigned char *data = 0;
177 if( bitmap->is_shared() )
178 shmid = bitmap->get_shmid();
180 data = bitmap->get_data();
181 allocate_data(data, shmid,
182 bitmap->get_y_offset(),
183 bitmap->get_u_offset(),
184 bitmap->get_v_offset(),
185 w, h, color_model, bytes_per_line);
191 params = new BC_Hash;
192 this->color_model = BC_COMPRESSED;
200 // Delete effect stack
201 prev_effects.remove_all_objects();
202 next_effects.remove_all_objects();
207 int VFrame::equivalent(VFrame *src, int test_stacks)
209 return (src->get_color_model() == get_color_model() &&
210 src->get_w() == get_w() &&
211 src->get_h() == get_h() &&
212 src->bytes_per_line == bytes_per_line &&
213 (!test_stacks || equal_stacks(src)));
216 int VFrame::data_matches(VFrame *frame)
218 if(data && frame->get_data() &&
219 frame->params_match(get_w(), get_h(), get_color_model()) &&
220 get_data_size() == frame->get_data_size())
222 int data_size = get_data_size();
223 unsigned char *ptr1 = get_data();
224 unsigned char *ptr2 = frame->get_data();
225 for(int i = 0; i < data_size; i++)
227 if(*ptr1++ != *ptr2++) return 0;
234 // long VFrame::set_shm_offset(long offset)
236 // shm_offset = offset;
240 // long VFrame::get_shm_offset()
242 // return shm_offset;
245 int VFrame::get_memory_type()
250 int VFrame::params_match(int w, int h, int color_model)
252 return (this->w == w &&
254 this->color_model == color_model);
258 int VFrame::reset_parameters(int do_opengl)
263 memory_type = VFrame::PRIVATE;
271 compressed_allocated = 0;
272 compressed_size = 0; // Size of current image
279 sequence_number = -1;
283 pixel_rgb = 0x000000; // BLACK
284 pixel_yuv = 0x008080;
289 // By default, anything is going to be done in RAM
290 opengl_state = VFrame::RAM;
295 prev_effects.set_array_delete();
296 next_effects.set_array_delete();
300 int VFrame::clear_objects(int do_opengl)
313 if( memory_type != VFrame::SHARED )
314 printf("==del %p from %p\n", data, __builtin_return_address(0));
320 case VFrame::PRIVATE:
322 // if(this->w * this->h > 1500 * 1100)
323 // printf("VFrame::clear_objects 2 this=%p data=%p\n", this, data);
326 //printf("VFrame::clear_objects %d this=%p shmid=%p data=%p\n", __LINE__, this, shmid, data);
346 // Delete row pointers
371 int VFrame::get_field2_offset()
373 return field2_offset;
376 int VFrame::set_field2_offset(int value)
378 this->field2_offset = value;
382 void VFrame::set_keyframe(int value)
384 this->is_keyframe = value;
387 int VFrame::get_keyframe()
393 VFrameScene* VFrame::get_scene()
398 int VFrame::calculate_bytes_per_pixel(int color_model)
400 return BC_CModels::calculate_pixelsize(color_model);
403 long VFrame::get_bytes_per_line()
405 return bytes_per_line;
408 long VFrame::get_data_size()
410 return calculate_data_size(w, h, bytes_per_line, color_model) - 4;
413 long VFrame::calculate_data_size(int w, int h, int bytes_per_line, int color_model)
415 return BC_CModels::calculate_datasize(w, h, bytes_per_line, color_model);
418 void VFrame::create_row_pointers()
421 switch(color_model) {
423 if( this->v_offset ) break;
426 this->v_offset = sz + w / 4 * h / 4;
432 if( this->v_offset ) break;
435 this->v_offset = sz + sz / 4;
439 if( this->v_offset ) break;
442 this->v_offset = sz + sz / 2;
445 if( this->v_offset ) break;
448 this->v_offset = sz + sz;
451 if( this->v_offset ) break;
453 this->u_offset = sz * sizeof(uint8_t);
454 this->v_offset = 2 * sz * sizeof(uint8_t);
457 if( this->v_offset || a ) break;
458 a = this->data + 3 * sz * sizeof(float);
460 if( this->v_offset ) break;
462 this->u_offset = sz * sizeof(float);
463 this->v_offset = 2 * sz * sizeof(float);
467 rows = new unsigned char*[h];
468 for(int i = 0; i < h; i++)
469 rows[i] = &this->data[i * this->bytes_per_line];
472 y = this->data + this->y_offset;
473 u = this->data + this->u_offset;
474 v = this->data + this->v_offset;
477 int VFrame::allocate_data(unsigned char *data, int shmid,
478 long y_offset, long u_offset, long v_offset, int w, int h,
479 int color_model, long bytes_per_line)
483 this->color_model = color_model;
484 this->bytes_per_pixel = calculate_bytes_per_pixel(color_model);
485 this->y_offset = this->u_offset = this->v_offset = 0;
487 // printf("VFrame::allocate_data %d shmid == 0\n", __LINE__, shmid);
490 this->bytes_per_line = bytes_per_line >= 0 ?
491 bytes_per_line : this->bytes_per_pixel * w;
493 // Allocate data + padding for MMX
495 //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
496 memory_type = VFrame::SHARED;
499 this->y_offset = y_offset;
500 this->u_offset = u_offset;
501 this->v_offset = v_offset;
503 else if(shmid >= 0) {
504 memory_type = VFrame::SHMGET;
505 this->data = (unsigned char*)shmat(shmid, NULL, 0);
506 //printf("VFrame::allocate_data %d shmid=%d data=%p\n", __LINE__, shmid, this->data);
508 this->y_offset = y_offset;
509 this->u_offset = u_offset;
510 this->v_offset = v_offset;
513 memory_type = VFrame::PRIVATE;
515 int size = calculate_data_size(this->w, this->h,
516 this->bytes_per_line, this->color_model);
517 if( use_shm && size >= SHM_MIN_SIZE &&
518 BC_WindowBase::get_resources()->use_vframe_shm() ) {
519 this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
520 if( this->shmid >= 0 ) {
521 this->data = (unsigned char*)shmat(this->shmid, NULL, 0);
522 //printf("VFrame::allocate_data %d %d %d %p\n", __LINE__, size, this->shmid, this->data);
523 // This causes it to automatically delete when the program exits.
524 shmctl(this->shmid, IPC_RMID, 0);
527 printf("VFrame::allocate_data %d could not allocate"
528 " shared memory, %dx%d (model %d) size=0x%08x\n",
529 __LINE__, w, h, color_model, size);
530 BC_Trace::dump_shm_stats(stdout);
533 // Have to use malloc for libpng
535 this->data = (unsigned char *)malloc(size);
539 // if(this->w * this->h > 1500 * 1100)
540 // printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n",
541 // this, this->w, this->h, this->data);
544 printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h);
546 printf("==new %p from %p sz %d\n", this->data, __builtin_return_address(0), size);
549 //printf("VFrame::allocate_data %d %p data=%p %d %d\n", __LINE__, this, this->data, this->w, this->h);
550 //if(size > 1000000) printf("VFrame::allocate_data %d\n", size);
553 // Create row pointers
554 create_row_pointers();
558 void VFrame::set_memory(unsigned char *data,
568 memory_type = VFrame::SHARED;
571 this->y_offset = y_offset;
572 this->u_offset = u_offset;
573 this->v_offset = v_offset;
578 memory_type = VFrame::SHMGET;
579 this->data = (unsigned char*)shmat(shmid, NULL, 0);
583 y = this->data + this->y_offset;
584 u = this->data + this->u_offset;
585 v = this->data + this->v_offset;
587 create_row_pointers();
590 void VFrame::set_memory(BC_Bitmap *bitmap)
593 unsigned char *data = 0;
594 if( bitmap->is_shared() && !bitmap->is_zombie() )
595 shmid = bitmap->get_shmid();
597 data = bitmap->get_data();
598 set_memory(data, shmid,
599 bitmap->get_y_offset(),
600 bitmap->get_u_offset(),
601 bitmap->get_v_offset());
604 void VFrame::set_compressed_memory(unsigned char *data,
613 memory_type = VFrame::SHARED;
620 memory_type = VFrame::SHMGET;
621 this->data = (unsigned char*)shmat(shmid, NULL, 0);
625 this->compressed_allocated = data_allocated;
626 this->compressed_size = data_size;
630 // Reallocate uncompressed buffer with or without alpha
631 int VFrame::reallocate(
642 // if(shmid == 0) printf("VFrame::reallocate %d shmid=%d\n", __LINE__, shmid);
644 // reset_parameters(0);
657 int VFrame::allocate_compressed_data(long bytes)
659 if(bytes < 1) return 1;
661 // Want to preserve original contents
662 if(data && compressed_allocated < bytes)
665 unsigned char *new_data = 0;
666 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
668 new_shmid = shmget(IPC_PRIVATE,
671 new_data = (unsigned char*)shmat(new_shmid, NULL, 0);
672 shmctl(new_shmid, IPC_RMID, 0);
676 // Have to use malloc for libpng
677 new_data = (unsigned char *)malloc(bytes);
680 bcopy(data, new_data, compressed_allocated);
683 if(memory_type == VFrame::PRIVATE)
693 if(memory_type == VFrame::SHMGET)
701 compressed_allocated = bytes;
706 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
708 shmid = shmget(IPC_PRIVATE,
711 data = (unsigned char*)shmat(shmid, NULL, 0);
712 shmctl(shmid, IPC_RMID, 0);
716 // Have to use malloc for libpng
717 data = (unsigned char *)malloc(bytes);
720 compressed_allocated = bytes;
727 int VFramePng::read_png(const unsigned char *data, long sz, double xscale, double yscale)
729 // Test for RAW format
730 if(data[0] == 'R' && data[1] == 'A' && data[2] == 'W' && data[3] == ' ') {
731 int new_color_model = BC_RGBA8888;
732 w = data[4] | (data[5] << 8) | (data[6] << 16) | (data[7] << 24);
733 h = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24);
734 int components = data[12];
735 new_color_model = components == 3 ? BC_RGB888 : BC_RGBA8888;
736 // This shares the data directly
737 // reallocate(data + 20, 0, 0, 0, w, h, new_color_model, -1);
739 // Can't use shared data for theme since button constructions overlay the
741 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
742 memcpy(get_data(), data + 16, w * h * components);
745 else if(data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
747 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
748 png_infop info_ptr = png_create_info_struct(png_ptr);
752 image = data; image_size = sz;
753 png_set_read_fn(png_ptr, this, PngReadFunction::png_read_function);
754 png_read_info(png_ptr, info_ptr);
756 w = png_get_image_width(png_ptr, info_ptr);
757 h = png_get_image_height(png_ptr, info_ptr);
759 int src_color_model = png_get_color_type(png_ptr, info_ptr);
761 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
762 png_set_strip_16(png_ptr);
764 /* extract multiple pixels with bit depths of 1, 2, and 4 from a single
765 * byte into separate bytes (useful for paletted and grayscale images).
767 png_set_packing(png_ptr);
769 /* expand paletted colors into true RGB triplets */
770 if (src_color_model == PNG_COLOR_TYPE_PALETTE)
771 png_set_expand(png_ptr);
773 /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
774 if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8)
775 png_set_expand(png_ptr);
777 if (src_color_model == PNG_COLOR_TYPE_GRAY ||
778 src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA)
779 png_set_gray_to_rgb(png_ptr);
781 /* expand paletted or RGB images with transparency to full alpha channels
782 * so the data will be available as RGBA quartets */
783 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){
785 png_set_expand(png_ptr);
788 switch(src_color_model)
790 case PNG_COLOR_TYPE_GRAY:
791 case PNG_COLOR_TYPE_RGB:
792 new_color_model = BC_RGB888;
795 case PNG_COLOR_TYPE_GRAY_ALPHA:
796 case PNG_COLOR_TYPE_RGB_ALPHA:
798 new_color_model = BC_RGBA8888;
801 case PNG_COLOR_TYPE_PALETTE:
803 new_color_model = BC_RGBA8888;
805 new_color_model = BC_RGB888;
808 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
810 //printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows());
811 png_read_image(png_ptr, get_rows());
812 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
815 printf("VFrame::read_png %d: unknown file format"
816 " 0x%02x 0x%02x 0x%02x 0x%02x\n",
817 __LINE__, data[4], data[5], data[6], data[7]);
820 int ww = w * xscale, hh = h * yscale;
821 if( ww != w || hh != h ) {
822 VFrame vframe(*this);
823 reallocate(NULL, -1, 0, 0, 0, ww, hh, color_model, -1);
824 transfer_from(&vframe);
829 int VFrame::write_png(const char *path)
831 VFrame *vframe = this;
832 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
833 png_infop info_ptr = png_create_info_struct(png_ptr);
834 FILE *out_fd = fopen(path, "w");
836 printf("VFrame::write_png %d %s %s\n", __LINE__, path, strerror(errno));
840 int png_cmodel = PNG_COLOR_TYPE_RGB;
841 int bc_cmodel = get_color_model();
842 switch( bc_cmodel ) {
843 case BC_RGB888: break;
844 case BC_RGBA8888: png_cmodel = PNG_COLOR_TYPE_RGB_ALPHA; break;
845 case BC_A8: png_cmodel = PNG_COLOR_TYPE_GRAY; break;
847 bc_cmodel = BC_RGB888;
848 if( BC_CModels::has_alpha(bc_cmodel) ) {
849 bc_cmodel = BC_RGBA8888;
850 png_cmodel = PNG_COLOR_TYPE_RGB_ALPHA;
852 vframe = new VFrame(get_w(), get_h(), bc_cmodel, 0);
853 vframe->transfer_from(this);
856 png_init_io(png_ptr, out_fd);
857 png_set_compression_level(png_ptr, 9);
858 png_set_IHDR(png_ptr, info_ptr, get_w(), get_h(), 8, png_cmodel,
859 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
860 png_write_info(png_ptr, info_ptr);
861 png_write_image(png_ptr, vframe->get_rows());
862 png_write_end(png_ptr, info_ptr);
863 png_destroy_write_struct(&png_ptr, &info_ptr);
865 if( vframe != this ) delete vframe;
870 #define ZERO_YUV(components, type, max) \
872 for(int i = 0; i < h; i++) \
874 type *row = (type*)get_rows()[i]; \
875 for(int j = 0; j < w; j++) \
877 row[j * components] = 0; \
878 row[j * components + 1] = (max + 1) / 2; \
879 row[j * components + 2] = (max + 1) / 2; \
880 if(components == 4) row[j * components + 3] = 0; \
885 int VFrame::clear_frame()
888 //printf("VFrame::clear_frame %d\n", __LINE__);
889 switch(color_model) {
895 memset(get_u(), 0x80, w / 4 * h / 4);
896 memset(get_v(), 0x80, w / 4 * h / 4);
903 memset(get_u(), 0x80, sz / 4);
904 memset(get_v(), 0x80, sz / 4);
909 memset(get_u(), 0x80, sz / 2);
910 memset(get_v(), 0x80, sz / 2);
919 case BC_RGBA_FLOATP: if( a ) {
920 float *ap = (float *)a;
921 for( int i=sz; --i>=0; ++ap ) *ap = 0.f; }
922 case BC_RGB_FLOATP: {
923 float *rp = (float *)y;
924 for( int i=sz; --i>=0; ++rp ) *rp = 0.f;
925 float *gp = (float *)u;
926 for( int i=sz; --i>=0; ++gp ) *gp = 0.f;
927 float *bp = (float *)v;
928 for( int i=sz; --i>=0; ++bp ) *bp = 0.f;
932 memset(get_u(), 0x80, sz);
933 memset(get_v(), 0x80, sz);
937 ZERO_YUV(3, unsigned char, 0xff);
941 ZERO_YUV(4, unsigned char, 0xff);
945 ZERO_YUV(3, uint16_t, 0xffff);
948 case BC_YUVA16161616:
949 ZERO_YUV(4, uint16_t, 0xffff);
953 bzero(data, calculate_data_size(w, h, bytes_per_line, color_model));
959 void VFrame::rotate90()
961 // Allocate new frame
962 int new_w = h, new_h = w;
963 VFrame new_frame(new_w, new_h, color_model);
964 unsigned char **new_rows = new_frame.get_rows();
966 for(int in_y = 0, out_x = new_w - 1; in_y < h; in_y++, out_x--)
968 for(int in_x = 0, out_y = 0; in_x < w; in_x++, out_y++)
970 for(int k = 0; k < bytes_per_pixel; k++)
972 new_rows[out_y][out_x * bytes_per_pixel + k] =
973 rows[in_y][in_x * bytes_per_pixel + k];
980 unsigned char *new_data = new_frame.data;
981 new_frame.data = data;
984 new_rows = new_frame.rows;
985 new_frame.rows = rows;
988 int new_shmid = new_frame.shmid;
989 new_frame.shmid = shmid;
991 // swap bytes_per_line
992 int new_bpl = new_frame.bytes_per_line;
993 new_frame.bytes_per_line = bytes_per_line;
994 bytes_per_line = new_bpl;
995 new_frame.clear_objects(0);
1001 void VFrame::rotate270()
1003 // Allocate new frame
1004 int new_w = h, new_h = w;
1005 VFrame new_frame(new_w, new_h, color_model);
1006 unsigned char **new_rows = new_frame.get_rows();
1008 for(int in_y = 0, out_x = 0; in_y < h; in_y++, out_x++)
1010 for(int in_x = 0, out_y = new_h - 1; in_x < w; in_x++, out_y--)
1012 for(int k = 0; k < bytes_per_pixel; k++)
1014 new_rows[out_y][out_x * bytes_per_pixel + k] =
1015 rows[in_y][in_x * bytes_per_pixel + k];
1022 unsigned char *new_data = new_frame.data;
1023 new_frame.data = data;
1026 new_rows = new_frame.rows;
1027 new_frame.rows = rows;
1030 int new_shmid = new_frame.shmid;
1031 new_frame.shmid = shmid;
1033 // swap bytes_per_line
1034 int new_bpl = new_frame.bytes_per_line;
1035 new_frame.bytes_per_line = bytes_per_line;
1036 bytes_per_line = new_bpl;
1037 new_frame.clear_objects(0);
1043 void VFrame::flip_vert()
1045 unsigned char temp[bytes_per_line];
1046 for( int i=0, j=h; --j>i; ++i ) {
1047 memcpy(temp, rows[j], bytes_per_line);
1048 memcpy(rows[j], rows[i], bytes_per_line);
1049 memcpy(rows[i], temp, bytes_per_line);
1053 void VFrame::flip_horiz()
1055 unsigned char temp[32];
1056 for(int i = 0; i < h; i++)
1058 unsigned char *row = rows[i];
1059 for(int j = 0; j < bytes_per_line / 2; j += bytes_per_pixel)
1061 memcpy(temp, row + j, bytes_per_pixel);
1062 memcpy(row + j, row + bytes_per_line - j - bytes_per_pixel, bytes_per_pixel);
1063 memcpy(row + bytes_per_line - j - bytes_per_pixel, temp, bytes_per_pixel);
1070 int VFrame::copy_from(VFrame *frame)
1072 if(this->w != frame->get_w() ||
1073 this->h != frame->get_h())
1075 printf("VFrame::copy_from %d sizes differ src %dx%d != dst %dx%d\n",
1084 int w = MIN(this->w, frame->get_w());
1085 int h = MIN(this->h, frame->get_h());
1086 timestamp = frame->timestamp;
1088 switch(frame->color_model)
1091 allocate_compressed_data(frame->compressed_size);
1092 memcpy(data, frame->data, frame->compressed_size);
1093 this->compressed_size = frame->compressed_size;
1097 memcpy(get_y(), frame->get_y(), w * h);
1098 memcpy(get_u(), frame->get_u(), w / 4 * h / 4);
1099 memcpy(get_v(), frame->get_v(), w / 4 * h / 4);
1105 //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());
1106 memcpy(get_y(), frame->get_y(), w * h);
1107 memcpy(get_u(), frame->get_u(), w * h / 4);
1108 memcpy(get_v(), frame->get_v(), w * h / 4);
1112 //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());
1113 memcpy(get_y(), frame->get_y(), w * h);
1114 memcpy(get_u(), frame->get_u(), w * h / 2);
1115 memcpy(get_v(), frame->get_v(), w * h / 2);
1119 //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());
1120 memcpy(get_y(), frame->get_y(), w * h);
1121 memcpy(get_u(), frame->get_u(), w * h);
1122 memcpy(get_v(), frame->get_v(), w * h);
1125 // printf("VFrame::copy_from %d\n", calculate_data_size(w,
1128 // frame->color_model));
1129 // Copy without extra 4 bytes in case the source is a hardware device
1130 memmove(data, frame->data, get_data_size());
1137 int VFrame::transfer_from(VFrame *that, int bg_color, int in_x, int in_y, int in_w, int in_h)
1139 timestamp = that->timestamp;
1142 if( this->get_color_model() == that->get_color_model() &&
1143 this->get_w() == that->get_w() && this->get_h() == that->get_h() &&
1144 this->get_bytes_per_line() == that->get_bytes_per_line() )
1145 return this->copy_from(that);
1148 BC_CModels::transfer(
1149 this->get_rows(), that->get_rows(), // Packed data out/in
1150 this->get_y(), this->get_u(), this->get_v(), // Planar data out/in
1151 that->get_y(), that->get_u(), that->get_v(),
1152 0, 0, that->get_w(), that->get_h(), // Dimensions in/out
1153 0, 0, this->get_w(), this->get_h(),
1154 that->get_color_model(), this->get_color_model(), // Color models in/out
1155 bg_color, // alpha blend bg_color
1156 that->get_bytes_per_line(),
1157 this->get_bytes_per_line()); // rowspans (of luma for YUV)
1159 unsigned char *in_ptrs[4], *out_ptrs[4];
1160 unsigned char **inp, **outp;
1161 if( BC_CModels::is_planar(that->get_color_model()) ) {
1162 in_ptrs[0] = that->get_y();
1163 in_ptrs[1] = that->get_u();
1164 in_ptrs[2] = that->get_v();
1165 in_ptrs[3] = that->get_a();
1169 inp = that->get_rows();
1170 if( BC_CModels::is_planar(this->get_color_model()) ) {
1171 out_ptrs[0] = this->get_y();
1172 out_ptrs[1] = this->get_u();
1173 out_ptrs[2] = this->get_v();
1174 out_ptrs[3] = this->get_a();
1178 outp = this->get_rows();
1179 BC_CModels::transfer(outp, this->get_color_model(),
1180 0, 0, this->get_w(), this->get_h(),
1181 this->get_bytes_per_line(),
1182 inp, that->get_color_model(),
1183 in_x, in_y, in_w, in_h,
1184 that->get_bytes_per_line(),
1191 int VFrame::get_scale_tables(int *column_table, int *row_table,
1192 int in_x1, int in_y1, int in_x2, int in_y2,
1193 int out_x1, int out_y1, int out_x2, int out_y2)
1196 float w_in = in_x2 - in_x1;
1197 float h_in = in_y2 - in_y1;
1198 int w_out = out_x2 - out_x1;
1199 int h_out = out_y2 - out_y1;
1201 float hscale = w_in / w_out;
1202 float vscale = h_in / h_out;
1204 for(i = 0; i < w_out; i++)
1206 column_table[i] = (int)(hscale * i);
1209 for(i = 0; i < h_out; i++)
1211 row_table[i] = (int)(vscale * i) + in_y1;
1216 void VFrame::push_prev_effect(const char *name)
1219 prev_effects.append(ptr = new char[strlen(name) + 1]);
1221 if(prev_effects.total > MAX_STACK_ELEMENTS) prev_effects.remove_object(0);
1224 void VFrame::pop_prev_effect()
1226 if(prev_effects.total)
1227 prev_effects.remove_object(prev_effects.last());
1230 void VFrame::push_next_effect(const char *name)
1233 next_effects.append(ptr = new char[strlen(name) + 1]);
1235 if(next_effects.total > MAX_STACK_ELEMENTS) next_effects.remove_object(0);
1238 void VFrame::pop_next_effect()
1240 if(next_effects.total)
1241 next_effects.remove_object(next_effects.last());
1244 const char* VFrame::get_next_effect(int number)
1246 if(!next_effects.total) return "";
1248 if(number > next_effects.total - 1) number = next_effects.total - 1;
1250 return next_effects.values[next_effects.total - number - 1];
1253 const char* VFrame::get_prev_effect(int number)
1255 if(!prev_effects.total) return "";
1257 if(number > prev_effects.total - 1) number = prev_effects.total - 1;
1259 return prev_effects.values[prev_effects.total - number - 1];
1262 BC_Hash* VFrame::get_params()
1267 void VFrame::clear_stacks()
1269 next_effects.remove_all_objects();
1270 prev_effects.remove_all_objects();
1275 void VFrame::copy_params(VFrame *src)
1277 status = src->status;
1278 params->copy_from(src->params);
1281 void VFrame::copy_stacks(VFrame *src)
1285 for( int i=0; i < src->next_effects.total; ++i )
1286 next_effects.append(cstrdup(src->next_effects[i]));
1287 for( int i=0; i < src->prev_effects.total; ++i )
1288 prev_effects.append(cstrdup(src->prev_effects[i]));
1293 int VFrame::copy_vframe(VFrame *frame)
1296 return copy_from(frame);
1299 int VFrame::equal_stacks(VFrame *src)
1301 for(int i = 0; i < src->next_effects.total && i < next_effects.total; i++)
1303 if(strcmp(src->next_effects.values[i], next_effects.values[i])) return 0;
1306 for(int i = 0; i < src->prev_effects.total && i < prev_effects.total; i++)
1308 if(strcmp(src->prev_effects.values[i], prev_effects.values[i])) return 0;
1311 if(!params->equivalent(src->params)) return 0;
1315 void VFrame::dump_stacks()
1317 printf("VFrame::dump_stacks\n");
1318 printf(" next_effects:\n");
1319 for(int i = next_effects.total - 1; i >= 0; i--)
1320 printf(" %s\n", next_effects.values[i]);
1321 printf(" prev_effects:\n");
1322 for(int i = prev_effects.total - 1; i >= 0; i--)
1323 printf(" %s\n", prev_effects.values[i]);
1326 void VFrame::dump_params()
1333 printf("VFrame::dump %d this=%p\n", __LINE__, this);
1334 printf(" w=%d h=%d colormodel=%d rows=%p use_shm=%d shmid=%d\n",
1335 w, h, color_model, rows, use_shm, shmid);
1339 int VFrame::get_memory_usage()
1341 if(get_compressed_allocated()) return get_compressed_allocated();
1342 return get_h() * get_bytes_per_line();
1345 void VFrame::set_pixel_color(int rgb)
1348 int ir = 0xff & (pixel_rgb >> 16);
1349 int ig = 0xff & (pixel_rgb >> 8);
1350 int ib = 0xff & (pixel_rgb >> 0);
1351 YUV::yuv.rgb_to_yuv_8(ir, ig, ib);
1352 pixel_yuv = (ir<<16) | (ig<<8) | (ib<<0);
1355 void VFrame::set_stiple(int mask)
1360 int VFrame::draw_pixel(int x, int y)
1362 if( x < 0 || y < 0 || x >= get_w() || y >= get_h() ) return 1;
1363 if( draw_point ) return (this->*draw_point)(x, y);
1365 #define DRAW_PIXEL(type, r, g, b) { \
1366 type **rows = (type**)get_rows(); \
1367 rows[y][x * components + 0] = r; \
1368 rows[y][x * components + 1] = g; \
1369 rows[y][x * components + 2] = b; \
1370 if( components == 4 ) \
1371 rows[y][x * components + 3] = mx; \
1373 int components = BC_CModels::components(color_model);
1374 int bch = BC_CModels::calculate_pixelsize(color_model) / components;
1375 int sz = 8*bch, mx = BC_CModels::is_float(color_model) ? 1 : (1<<sz)-1;
1376 int is_yuv = BC_CModels::is_yuv(color_model);
1377 int pixel_color = is_yuv ? pixel_yuv : pixel_rgb;
1378 int ir = 0xff & (pixel_color >> 16); float fr = 0;
1379 int ig = 0xff & (pixel_color >> 8); float fg = 0;
1380 int ib = 0xff & (pixel_color >> 0); float fb = 0;
1381 if( (x+y) & stipple ) {
1382 ir = 255 - ir; ig = 255 - ig; ib = 255 - ib;
1384 if( BC_CModels::is_float(color_model) ) {
1385 fr = ir / 255.; fg = ig / 255.; fb = ib / 255.;
1388 else if( (sz-=8) > 0 ) {
1389 ir <<= sz; ig <<= sz; ib <<= sz;
1392 switch(get_color_model()) {
1397 DRAW_PIXEL(uint8_t, ir, ig, ib);
1401 case BC_RGBA16161616:
1402 case BC_YUVA16161616:
1403 DRAW_PIXEL(uint16_t, ir, ig, ib);
1407 DRAW_PIXEL(float, fr, fg, fb);
1415 void VFrame::draw_line(int x1, int y1, int x2, int y2)
1418 int tx = x1; x1 = x2; x2 = tx;
1419 int ty = y1; y1 = y2; y2 = ty;
1423 int dx = x2-x1, dy = y2-y1;
1424 int dx2 = 2*dx, dy2 = 2*dy;
1425 if( dx < 0 ) dx = -dx;
1426 int r = dx > dy ? dx : dy, n = r;
1428 if( dx2 < 0 ) dir += 1;
1430 if( dx2 >= 0 ) do { /* +Y, +X */
1432 if( (r -= dx2) < 0 ) { r += dy2; ++x; }
1433 } while( --n >= 0 );
1434 else do { /* +Y, -X */
1436 if( (r += dx2) < 0 ) { r += dy2; --x; }
1437 } while( --n >= 0 );
1440 if( dx2 >= 0 ) do { /* +X, +Y */
1442 if( (r -= dy2) < 0 ) { r += dx2; ++y; }
1443 } while( --n >= 0 );
1444 else do { /* -X, +Y */
1446 if( (r -= dy2) < 0 ) { r -= dx2; ++y; }
1447 } while( --n >= 0 );
1451 // g++ -dD -E - < /dev/null | grep DBL_EPSILON
1452 #ifndef __DBL_EPSILON__
1453 #define __DBL_EPSILON__ ((double)2.22044604925031308085e-16L)
1455 // weakest fraction * graphics integer range
1456 #define RND_EPSILON (__DBL_EPSILON__*65536)
1459 int rnd(double v) { return round(v)+RND_EPSILON; }
1462 int sx, sy, ex, ey; /* current point, end point */
1463 int xs, ys; /* x/y quadrant sign -1/1 */
1464 int64_t A, B, C; /* quadratic coefficients */
1465 int64_t r, dx, dy; /* residual, dr/dx and dr/dy */
1466 int xmxx, xmxy; /* x,y at apex */
1469 void init0(int x1,int y1, int x2,int y2, int x3,int y3, int top);
1470 void init1(int x1,int y1, int x2,int y2, int x3,int y3);
1471 int64_t rx() { return r + xs*8*dx + 4*A; }
1472 void moveX(int64_t r) {
1473 dx += xs*A; dy -= xs*B;
1474 this->r = r; sx += xs;
1476 int64_t ry() { return r + 8*dy + 4*C; }
1477 void moveY(int64_t r) {
1483 smooth_line(VFrame *vframe) { this->vframe = vframe; this->done = 0; }
1487 void smooth_line::draw()
1490 if( abs(dy) >= abs(dx) ) {
1491 if( xs*(sx-xmxx) >= 0 ) {
1492 if( ys > 0 ) { done = 1; return; }
1493 if( dy < 0 || ry() < 0 ) { moveY(ry()); goto xit; }
1494 xmxx = ex; xmxy = ey;
1499 if( abs(rr) < abs(r) )
1504 if( ys > 0 ) { done = 1; return; }
1505 xmxx = ex; xmxy = ey;
1510 if( abs(rr) < abs(r) )
1513 xit: vframe->draw_pixel(sx, sy);
1516 void VFrame::draw_smooth(int x1, int y1, int x2, int y2, int x3, int y3)
1518 if( (x1 == x2 && y1 == y2) || (x2 == x3 && y2 == y3) )
1519 draw_line(x1,y1, x3,y3);
1520 else if( x1 == x3 && y1 == y3 )
1521 draw_line(x1,y1, x2,y2);
1522 else if( (x2-x1) * (y2-y3) == (x2-x3) * (y2-y1) ) {
1523 // co-linear, draw line from min to max
1525 if( x2 < x1 ) { x1 = x2; y1 = y2; }
1526 if( x2 > x3 ) { x3 = x2; y3 = y2; }
1529 if( x2 > x1 ) { x1 = x2; y1 = y2; }
1530 if( x2 < x3 ) { x3 = x2; y3 = y2; }
1532 draw_line(x1,y1, x3,y3);
1535 smooth_draw(x1, y1, x2, y2, x3, y3);
1539 Non-Parametric Smooth Curve Generation. Don Kelly 1984
1546 Let the starting point be P. the ending point R. and the tangent vertex Q.
1547 A general point Z on the curve is then
1548 Z = (P + R - Q) + (Q - P) sin t + (Q - R) cos t
1550 Expanding the Cartesian coordinates around (P + R - Q) gives
1551 [x y] = Z - (P + R - Q)
1554 x = a*sin(t) + b*cos(t)
1555 y = c*sin(t) + d*cos(t)
1557 from which t can now be eliminated via
1558 c*x - a*y = (c*b - a*d)*cos(t)
1559 d*x - b*y = (a*d - c*b)*sin(t)
1561 giving the Cartesian equation for the ellipse as
1562 f(x, y) = (c*x - a*y)**2 + (d*x - b*y)**2 - (a*d - c*b)**2 = 0
1564 or: f(x, y) = A*x**2 - 2*B*x*y + C*y**2 + B**2 - A*C = 0
1565 where: A = c**2 + d**2, B = a*c + b*d, C = a**2 + b**2
1567 The maximum y extent of the ellipse may now be derived as follows:
1568 let df/dx = 0, 2*A*x = 2*B*y, x = y*B/A
1569 f(x, y) == B**2 * y**2 / A - 2*B**2 * y**2 / A + C*y**2 + B**2 - A*C = 0
1570 (A*C - B**2)*y = (A*C - B**2)*A
1571 max x = sqrt(C), at y = B/sqrt(C)
1572 max y = sqrt(A), at x = B/sqrt(A)
1577 /* x1,y1 = P, x2,y2 = Q, x3,y3=R,
1578 * draw from P to Q to R if top=0
1579 * or from P to (x,ymax) if top>0
1580 * or from Q to (x,ymax) if top<0
1582 void smooth_line::init0(int x1,int y1, int x2,int y2, int x3,int y3, int top)
1584 int x0 = x1+x3-x2, y0 = y1+y3-y2; // Q'
1586 int a = x2-x1, c = y2-y1;
1587 int b = x2-x3, d = y2-y3;
1588 A = c*c + d*d; C = a*a + b*b; B = a*c + b*d;
1590 sx = top >= 0 ? x1 : x3;
1591 sy = top >= 0 ? y1 : y3;
1592 xs = x2 > sx || (x2==sx && (x1+x3-sx)>=x2) ? 1 : -1;
1593 int64_t px = sx-x0, py = sy-y0;
1594 dx = A*px - B*py; dy = C*py - B*px;
1598 double ymy = sqrt(A), ymx = B/ymy;
1606 ys = a*b > 0 && (!top || top*xs*(b*c - a*d) > 0) ? -1 : 1;
1608 double xmx = xs*sqrt(C), xmy = B/xmx;
1609 xmxx = x0 + rnd(xmx);
1610 xmxy = y0 + rnd(xmy);
1613 xmxx = ex; xmxy = ey;
1617 /* x1,y1 = P, x2,y2 = Q, x3,y3=R,
1618 * draw from (x,ymax) to P
1620 void smooth_line::init1(int x1,int y1, int x2,int y2, int x3,int y3)
1622 int x0 = x1+x3-x2, y0 = y1+y3-y2; // Q'
1624 int a = x2-x1, c = y2-y1;
1625 int b = x2-x3, d = y2-y3;
1626 A = c*c + d*d; C = a*a + b*b; B = a*c + b*d;
1628 double ymy = -sqrt(A), ymx = B/ymy;
1629 int64_t px = rnd(ymx), py = rnd(ymy);
1630 sx = x0 + px; ex = x1;
1631 sy = y0 + py; ey = y1;
1632 xs = x2 > x1 || (x2==x1 && x3>=x2) ? 1 : -1;
1633 dx = A*px - B*py; dy = C*py - B*px;
1634 r = 4 * (A*px*px - 2*B*px*py + C*py*py + B*B - A*C);
1636 ys = a*b > 0 && xs*(b*c - a*d) < 0 ? -1 : 1;
1638 double xmx = xs*sqrt(C), xmy = B/xmx;
1639 xmxx = x0 + rnd(xmx);
1640 xmxy = y0 + rnd(xmy);
1644 xmxx = ex; xmxy = ey;
1647 vframe->draw_pixel(sx, sy);
1648 while( xs*(sx-xmxx) < 0 && (xs*dx < 0 || rx() < 0) ) {
1650 vframe->draw_pixel(sx, sy);
1655 void VFrame::smooth_draw(int x1, int y1, int x2, int y2, int x3, int y3)
1657 //printf("p smooth_draw( %d,%d, %d,%d, %d,%d )\n", x1,y1,x2,y2,x3,y3);
1658 if( y1 > y3 ) { // make y3 >= y1
1659 int xt = x1; x1 = x3; x3 = xt;
1660 int yt = y1; y1 = y3; y3 = yt;
1662 if( y1 > y2 && y3 > y2 ) {
1663 smooth_line lt(this), rt(this); // Q on bottom
1664 lt.init1(x1, y1, x2, y2, x3, y3);
1665 rt.init1(x3, y3, x2, y2, x1, y1);
1666 while( !lt.done || !rt.done ) {
1671 else if( y1 < y2 && y3 < y2 ) {
1672 smooth_line lt(this), rt(this); // Q on top
1673 lt.init0(x1, y1, x2, y2, x3, y3, 1);
1674 draw_pixel(lt.sx, lt.sy);
1675 rt.init0(x1, y1, x2, y2, x3, y3, -1);
1676 draw_pixel(rt.sx, rt.sy);
1677 while( !lt.done || !rt.done ) {
1683 smooth_line pt(this); // Q in between
1684 pt.init0(x1, y1, x2, y2, x3, y3, 0);
1685 draw_pixel(pt.sx, pt.sy);
1693 void VFrame::draw_rect(int x1, int y1, int x2, int y2)
1695 draw_line(x1, y1, x2, y1);
1696 draw_line(x2, y1 + 1, x2, y2);
1697 draw_line(x2 - 1, y2, x1, y2);
1698 draw_line(x1, y2 - 1, x1, y1 + 1);
1702 void VFrame::draw_oval(int x1, int y1, int x2, int y2)
1706 int center_x = (x2 + x1) / 2;
1707 int center_y = (y2 + y1) / 2;
1710 //printf("VFrame::draw_oval %d %d %d %d %d\n", __LINE__, x1, y1, x2, y2);
1712 for(int i = 0; i < h / 2; i++) {
1713 // A^2 = -(B^2) + C^2
1714 x_table[i] = (int)(sqrt(-SQR(h / 2 - i) + SQR(h / 2)) * w / h);
1715 //printf("VFrame::draw_oval %d i=%d x=%d\n", __LINE__, i, x_table[i]);
1718 for(int i = 0; i < h / 2 - 1; i++) {
1719 int x3 = x_table[i];
1720 int x4 = x_table[i + 1];
1723 for(int j = x3; j < x4; j++) {
1724 draw_pixel(center_x + j, y1 + i);
1725 draw_pixel(center_x - j, y1 + i);
1726 draw_pixel(center_x + j, y2 - i - 1);
1727 draw_pixel(center_x - j, y2 - i - 1);
1731 draw_pixel(center_x + x3, y1 + i);
1732 draw_pixel(center_x - x3, y1 + i);
1733 draw_pixel(center_x + x3, y2 - i - 1);
1734 draw_pixel(center_x - x3, y2 - i - 1);
1738 draw_pixel(center_x, y1);
1739 draw_pixel(center_x, y2 - 1);
1740 draw_pixel(x1, center_y);
1741 draw_pixel(x2 - 1, center_y);
1742 draw_pixel(x1, center_y - 1);
1743 draw_pixel(x2 - 1, center_y - 1);
1747 void VFrame::draw_arrow(int x1, int y1, int x2, int y2, int sz)
1749 double angle = atan((float)(y2 - y1) / (float)(x2 - x1));
1750 double angle1 = angle + (float)145 / 360 * 2 * M_PI;
1751 double angle2 = angle - (float)145 / 360 * 2 * M_PI;
1752 int s = x2 < x1 ? -1 : 1;
1753 int x3 = x2 + s * (int)(sz * cos(angle1));
1754 int y3 = y2 + s * (int)(sz * sin(angle1));
1755 int x4 = x2 + s * (int)(sz * cos(angle2));
1756 int y4 = y2 + s * (int)(sz * sin(angle2));
1759 draw_line(x1, y1, x2, y2);
1760 // draw_line(x1, y1 + 1, x2, y2 + 1);
1763 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x3, y3);
1765 if(abs(y2 - y1) || abs(x2 - x1)) draw_line(x2, y2, x4, y4);
1768 void VFrame::draw_x(int x, int y, int sz)
1770 draw_line(x-sz,y-sz, x+sz,y+sz);
1771 draw_line(x+sz,y-sz, x-sz,y+sz);
1773 void VFrame::draw_t(int x, int y, int sz)
1775 draw_line(x,y-sz, x,y+sz);
1776 draw_line(x+sz,y, x-sz,y);