initial commit
[goodguy/history.git] / cinelerra-5.0 / guicast / vframe.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
5  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #include <errno.h>
23 #include <png.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <stdint.h>
27 #include <sys/shm.h>
28
29 #include "bcbitmap.h"
30 #include "bchash.h"
31 #include "bcpbuffer.h"
32 #include "bcresources.h"
33 #include "bcsignals.h"
34 #include "bcsynchronous.h"
35 #include "bctexture.h"
36 #include "bcwindowbase.h"
37 #include "clip.h"
38 #include "bccmodels.h"
39 #include "vframe.h"
40
41 class PngReadFunction
42 {
43 public:
44         static void png_read_function(png_structp png_ptr,
45                    png_bytep data, png_size_t length)
46         {
47                 VFrame *frame = (VFrame*)png_get_io_ptr(png_ptr);
48                 if(frame->image_size - frame->image_offset < (long)length)
49                 {
50                         printf("PngReadFunction::png_read_function %d: overrun\n", __LINE__);
51                         length = frame->image_size - frame->image_offset;
52                 }
53
54                 memcpy(data, &frame->image[frame->image_offset], length);
55                 frame->image_offset += length;
56         };
57 };
58
59
60
61
62
63
64
65 VFrameScene::VFrameScene()
66 {
67 }
68
69 VFrameScene::~VFrameScene()
70 {
71 }
72
73
74
75
76
77
78
79 //static BCCounter counter;
80
81
82 VFrame::VFrame(unsigned char *png_data)
83 {
84         reset_parameters(1);
85         params = new BC_Hash;
86         read_png(png_data);
87 }
88
89 VFrame::VFrame(unsigned char *png_data, long image_size)
90 {
91         reset_parameters(1);
92         params = new BC_Hash;
93         read_png(png_data, image_size);
94 }
95
96 VFrame::VFrame(VFrame &frame)
97 {
98         reset_parameters(1);
99         params = new BC_Hash;
100         allocate_data(0, -1, 0, 0, 0, frame.w, frame.h,
101                 frame.color_model, frame.bytes_per_line);
102         memcpy(data, frame.data, bytes_per_line * h);
103         copy_stacks(&frame);
104 }
105
106 VFrame::VFrame(int w, int h, int color_model, long bytes_per_line)
107 {
108         reset_parameters(1);
109         params = new BC_Hash;
110         allocate_data(data, -1, 0, 0, 0, w, h,
111                 color_model, bytes_per_line);
112 }
113
114 VFrame::VFrame(unsigned char *data, int shmid, int w, int h,
115         int color_model, long bytes_per_line)
116 {
117         reset_parameters(1);
118         params = new BC_Hash;
119         allocate_data(data, shmid, 0, 0, 0, w, h,
120                 color_model, bytes_per_line);
121 }
122
123 VFrame::VFrame(unsigned char *data, int shmid,
124                 long y_offset, long u_offset, long v_offset,
125                 int w, int h, int color_model, long bytes_per_line)
126 {
127         reset_parameters(1);
128         params = new BC_Hash;
129         allocate_data(data, shmid, y_offset, u_offset, v_offset, w, h,
130                 color_model, bytes_per_line);
131 }
132
133 VFrame::VFrame(BC_Bitmap *bitmap, int w, int h,
134                  int color_model, long bytes_per_line)
135 {
136         reset_parameters(1);
137         params = new BC_Hash;
138         int shmid = 0;
139         unsigned char *data = 0;
140         if( bitmap->is_shared() )
141                 shmid = bitmap->get_shmid();
142         else
143                 data = bitmap->get_data();
144         allocate_data(data, shmid,
145                 bitmap->get_y_offset(),
146                 bitmap->get_u_offset(),
147                 bitmap->get_v_offset(),
148                 w, h, color_model, bytes_per_line);
149 }
150
151 VFrame::VFrame()
152 {
153         reset_parameters(1);
154         params = new BC_Hash;
155         this->color_model = BC_COMPRESSED;
156 }
157
158
159
160 VFrame::~VFrame()
161 {
162         clear_objects(1);
163 // Delete effect stack
164         prev_effects.remove_all_objects();
165         next_effects.remove_all_objects();
166         delete params;
167         delete scene;
168 }
169
170 int VFrame::equivalent(VFrame *src, int test_stacks)
171 {
172         return (src->get_color_model() == get_color_model() &&
173                 src->get_w() == get_w() &&
174                 src->get_h() == get_h() &&
175                 src->bytes_per_line == bytes_per_line &&
176                 (!test_stacks || equal_stacks(src)));
177 }
178
179 int VFrame::data_matches(VFrame *frame)
180 {
181         if(data && frame->get_data() &&
182                 frame->params_match(get_w(), get_h(), get_color_model()) &&
183                 get_data_size() == frame->get_data_size())
184         {
185                 int data_size = get_data_size();
186                 unsigned char *ptr1 = get_data();
187                 unsigned char *ptr2 = frame->get_data();
188                 for(int i = 0; i < data_size; i++)
189                 {
190                         if(*ptr1++ != *ptr2++) return 0;
191                 }
192                 return 1;
193         }
194         return 0;
195 }
196
197 // long VFrame::set_shm_offset(long offset)
198 // {
199 //      shm_offset = offset;
200 //      return 0;
201 // }
202 //
203 // long VFrame::get_shm_offset()
204 // {
205 //      return shm_offset;
206 // }
207 //
208 int VFrame::get_memory_type()
209 {
210         return memory_type;
211 }
212
213 int VFrame::params_match(int w, int h, int color_model)
214 {
215         return (this->w == w &&
216                 this->h == h &&
217                 this->color_model == color_model);
218 }
219
220
221 int VFrame::reset_parameters(int do_opengl)
222 {
223         scene = 0;
224         field2_offset = -1;
225         memory_type = VFrame::PRIVATE;
226 //      shm_offset = 0;
227         shmid = -1;
228         use_shm = 1;
229         bytes_per_line = 0;
230         data = 0;
231         rows = 0;
232         color_model = 0;
233         compressed_allocated = 0;
234         compressed_size = 0;   // Size of current image
235         w = 0;
236         h = 0;
237         y = u = v = a = 0;
238         y_offset = 0;
239         u_offset = 0;
240         v_offset = 0;
241         sequence_number = -1;
242         timestamp = -1.;
243         is_keyframe = 0;
244
245         if(do_opengl)
246         {
247 // By default, anything is going to be done in RAM
248                 opengl_state = VFrame::RAM;
249                 pbuffer = 0;
250                 texture = 0;
251         }
252
253         prev_effects.set_array_delete();
254         next_effects.set_array_delete();
255         return 0;
256 }
257
258 int VFrame::clear_objects(int do_opengl)
259 {
260 // Remove texture
261         if(do_opengl)
262         {
263                 delete texture;
264                 texture = 0;
265
266                 delete pbuffer;
267                 pbuffer = 0;
268         }
269
270 // Delete data
271         switch(memory_type)
272         {
273                 case VFrame::PRIVATE:
274 // Memory check
275 // if(this->w * this->h > 1500 * 1100)
276 // printf("VFrame::clear_objects 2 this=%p data=%p\n", this, data);
277                         if(data)
278                         {
279 //printf("VFrame::clear_objects %d this=%p shmid=%p data=%p\n", __LINE__, this, shmid, data);
280                                 if(shmid >= 0)
281                                         shmdt(data);
282                                 else
283                                         free(data);
284 //PRINT_TRACE
285                         }
286
287                         data = 0;
288                         shmid = -1;
289                         break;
290
291                 case VFrame::SHMGET:
292                         if(data)
293                                 shmdt(data);
294                         data = 0;
295                         shmid = -1;
296                         break;
297         }
298
299 // Delete row pointers
300         switch(color_model)
301         {
302                 case BC_COMPRESSED:
303                 case BC_YUV410P:
304                 case BC_YUV411P:
305                 case BC_YUV420P:
306                 case BC_YUV422P:
307                 case BC_YUV444P:
308                 case BC_RGB_FLOATP:
309                 case BC_RGBA_FLOATP:
310                         break;
311
312                 default:
313                         delete [] rows;
314                         rows = 0;
315                         break;
316         }
317
318
319         return 0;
320 }
321
322 int VFrame::get_field2_offset()
323 {
324         return field2_offset;
325 }
326
327 int VFrame::set_field2_offset(int value)
328 {
329         this->field2_offset = value;
330         return 0;
331 }
332
333 void VFrame::set_keyframe(int value)
334 {
335         this->is_keyframe = value;
336 }
337
338 int VFrame::get_keyframe()
339 {
340         return is_keyframe;
341 }
342
343
344 VFrameScene* VFrame::get_scene()
345 {
346         return scene;
347 }
348
349 int VFrame::calculate_bytes_per_pixel(int color_model)
350 {
351         return BC_CModels::calculate_pixelsize(color_model);
352 }
353
354 long VFrame::get_bytes_per_line()
355 {
356         return bytes_per_line;
357 }
358
359 long VFrame::get_data_size()
360 {
361         return calculate_data_size(w, h, bytes_per_line, color_model) - 4;
362 }
363
364 long VFrame::calculate_data_size(int w, int h, int bytes_per_line, int color_model)
365 {
366         return BC_CModels::calculate_datasize(w, h, bytes_per_line, color_model);
367 }
368
369 void VFrame::create_row_pointers()
370 {
371         int sz = w * h;
372         switch(color_model) {
373         case BC_YUV410P:
374                 if( this->v_offset ) break;
375                 this->y_offset = 0;
376                 this->u_offset = sz;
377                 this->v_offset = sz + w / 4 * h / 4;
378                 break;
379
380         case BC_YUV420P:
381         case BC_YUV411P:
382                 if( this->v_offset ) break;
383                 this->y_offset = 0;
384                 this->u_offset = sz;
385                 this->v_offset = sz + sz / 4;
386                 break;
387
388         case BC_YUV422P:
389                 if( this->v_offset ) break;
390                 this->y_offset = 0;
391                 this->u_offset = sz;
392                 this->v_offset = sz + sz / 2;
393                 break;
394         case BC_YUV444P:
395                 if( this->v_offset ) break;
396                 this->y_offset = 0;
397                 this->u_offset = sz;
398                 this->v_offset = sz + sz;
399                 break;
400         case BC_RGBA_FLOATP:
401                 if( this->v_offset || a ) break;
402                 a = this->data + 3 * sz * sizeof(float);
403         case BC_RGB_FLOATP:
404                 if( this->v_offset ) break;
405                 this->y_offset = 0;
406                 this->u_offset = sz * sizeof(float);
407                 this->v_offset = 2 * sz * sizeof(float);
408                 break;
409
410         default:
411                 rows = new unsigned char*[h];
412                 for(int i = 0; i < h; i++)
413                         rows[i] = &this->data[i * this->bytes_per_line];
414                 return;
415         }
416         y = this->data + this->y_offset;
417         u = this->data + this->u_offset;
418         v = this->data + this->v_offset;
419 }
420
421 int VFrame::allocate_data(unsigned char *data, int shmid,
422                 long y_offset, long u_offset, long v_offset, int w, int h,
423                 int color_model, long bytes_per_line)
424 {
425         this->w = w;
426         this->h = h;
427         this->color_model = color_model;
428         this->bytes_per_pixel = calculate_bytes_per_pixel(color_model);
429         this->y_offset = this->u_offset = this->v_offset = 0;
430 //      if(shmid == 0) {
431 //              printf("VFrame::allocate_data %d shmid == 0\n", __LINE__, shmid);
432 //      }
433
434         this->bytes_per_line = bytes_per_line >= 0 ?
435                 bytes_per_line : this->bytes_per_pixel * w;
436
437 // Allocate data + padding for MMX
438         if(data) {
439 //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
440                 memory_type = VFrame::SHARED;
441                 this->data = data;
442                 this->shmid = -1;
443                 this->y_offset = y_offset;
444                 this->u_offset = u_offset;
445                 this->v_offset = v_offset;
446         }
447         else if(shmid >= 0) {
448                 memory_type = VFrame::SHMGET;
449                 this->data = (unsigned char*)shmat(shmid, NULL, 0);
450 //printf("VFrame::allocate_data %d shmid=%d data=%p\n", __LINE__, shmid, this->data);
451                 this->shmid = shmid;
452                 this->y_offset = y_offset;
453                 this->u_offset = u_offset;
454                 this->v_offset = v_offset;
455         }
456         else {
457                 memory_type = VFrame::PRIVATE;
458                 int size = calculate_data_size(this->w, this->h,
459                         this->bytes_per_line, this->color_model);
460                 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm) {
461                         this->shmid = shmget(IPC_PRIVATE, size, IPC_CREAT | 0777);
462                         if(this->shmid < 0) {
463                                 printf("VFrame::allocate_data %d could not allocate shared memory\n", __LINE__);
464                         }
465
466                         this->data = (unsigned char*)shmat(this->shmid, NULL, 0);
467 //printf("VFrame::allocate_data %d %d %d\n", __LINE__, size, this->shmid);
468
469 //printf("VFrame::allocate_data %d %p\n", __LINE__, this->data);
470 // This causes it to automatically delete when the program exits.
471                         shmctl(this->shmid, IPC_RMID, 0);
472                 }
473                 else {
474 // Have to use malloc for libpng
475                         this->data = (unsigned char *)malloc(size);
476                 }
477
478 // Memory check
479 // if(this->w * this->h > 1500 * 1100)
480 // printf("VFrame::allocate_data 2 this=%p w=%d h=%d this->data=%p\n",
481 // this, this->w, this->h, this->data);
482
483                 if(!this->data)
484                         printf("VFrame::allocate_data %dx%d: memory exhausted.\n", this->w, this->h);
485
486 //printf("VFrame::allocate_data %d %p data=%p %d %d\n", __LINE__, this, this->data, this->w, this->h);
487 //if(size > 1000000) printf("VFrame::allocate_data %d\n", size);
488         }
489
490 // Create row pointers
491         create_row_pointers();
492         return 0;
493 }
494
495 void VFrame::set_memory(unsigned char *data,
496         int shmid,
497         long y_offset,
498         long u_offset,
499         long v_offset)
500 {
501         clear_objects(0);
502
503         if(data)
504         {
505                 memory_type = VFrame::SHARED;
506                 this->data = data;
507                 this->shmid = -1;
508                 this->y_offset = y_offset;
509                 this->u_offset = u_offset;
510                 this->v_offset = v_offset;
511         }
512         else
513         if(shmid >= 0)
514         {
515                 memory_type = VFrame::SHMGET;
516                 this->data = (unsigned char*)shmat(shmid, NULL, 0);
517                 this->shmid = shmid;
518         }
519
520         y = this->data + this->y_offset;
521         u = this->data + this->u_offset;
522         v = this->data + this->v_offset;
523
524         create_row_pointers();
525 }
526
527 void VFrame::set_memory(BC_Bitmap *bitmap)
528 {
529         int shmid = 0;
530         unsigned char *data = 0;
531         if( bitmap->is_shared() )
532                 shmid = bitmap->get_shmid();
533         else
534                 data = bitmap->get_data();
535         set_memory(data, shmid,
536                 bitmap->get_y_offset(),
537                 bitmap->get_u_offset(),
538                 bitmap->get_v_offset());
539 }
540
541 void VFrame::set_compressed_memory(unsigned char *data,
542         int shmid,
543         int data_size,
544         int data_allocated)
545 {
546         clear_objects(0);
547
548         if(data)
549         {
550                 memory_type = VFrame::SHARED;
551                 this->data = data;
552                 this->shmid = -1;
553         }
554         else
555         if(shmid >= 0)
556         {
557                 memory_type = VFrame::SHMGET;
558                 this->data = (unsigned char*)shmat(shmid, NULL, 0);
559                 this->shmid = shmid;
560         }
561
562         this->compressed_allocated = data_allocated;
563         this->compressed_size = data_size;
564 }
565
566
567 // Reallocate uncompressed buffer with or without alpha
568 int VFrame::reallocate(
569         unsigned char *data,
570         int shmid,
571         long y_offset,
572         long u_offset,
573         long v_offset,
574         int w,
575         int h,
576         int color_model,
577         long bytes_per_line)
578 {
579 //      if(shmid == 0) printf("VFrame::reallocate %d shmid=%d\n", __LINE__, shmid);
580         clear_objects(0);
581 //      reset_parameters(0);
582         allocate_data(data,
583                 shmid,
584                 y_offset,
585                 u_offset,
586                 v_offset,
587                 w,
588                 h,
589                 color_model,
590                 bytes_per_line);
591         return 0;
592 }
593
594 int VFrame::allocate_compressed_data(long bytes)
595 {
596         if(bytes < 1) return 1;
597
598 // Want to preserve original contents
599         if(data && compressed_allocated < bytes)
600         {
601                 int new_shmid = -1;
602                 unsigned char *new_data = 0;
603                 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
604                 {
605                         new_shmid = shmget(IPC_PRIVATE,
606                                 bytes,
607                                 IPC_CREAT | 0777);
608                         new_data = (unsigned char*)shmat(new_shmid, NULL, 0);
609                         shmctl(new_shmid, IPC_RMID, 0);
610                 }
611                 else
612                 {
613 // Have to use malloc for libpng
614                         new_data = (unsigned char *)malloc(bytes);
615                 }
616
617                 bcopy(data, new_data, compressed_allocated);
618 UNBUFFER(data);
619
620                 if(memory_type == VFrame::PRIVATE)
621                 {
622                         if(shmid > 0) {
623                                 if(data)
624                                         shmdt(data);
625                         }
626                         else
627                                 free(data);
628                 }
629                 else
630                 if(memory_type == VFrame::SHMGET)
631                 {
632                         if(data)
633                                 shmdt(data);
634                 }
635
636                 data = new_data;
637                 shmid = new_shmid;
638                 compressed_allocated = bytes;
639         }
640         else
641         if(!data)
642         {
643                 if(BC_WindowBase::get_resources()->use_vframe_shm() && use_shm)
644                 {
645                         shmid = shmget(IPC_PRIVATE,
646                                 bytes,
647                                 IPC_CREAT | 0777);
648                         data = (unsigned char*)shmat(shmid, NULL, 0);
649                         shmctl(shmid, IPC_RMID, 0);
650                 }
651                 else
652                 {
653 // Have to use malloc for libpng
654                         data = (unsigned char *)malloc(bytes);
655                 }
656
657                 compressed_allocated = bytes;
658                 compressed_size = 0;
659         }
660
661         return 0;
662 }
663
664 int VFrame::read_png(const unsigned char *data, long img_sz)
665 {
666 // Test for RAW format
667         if(data[0] == 'R' && data[1] == 'A' && data[2] == 'W' && data[3] == ' ') {
668                 int new_color_model = BC_RGBA8888;
669                 w = data[4] | (data[5] << 8) | (data[6]  << 16) | (data[7]  << 24);
670                 h = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24);
671                 int components = data[12];
672                 new_color_model = components == 3 ? BC_RGB888 : BC_RGBA8888;
673 // This shares the data directly
674 //              reallocate(data + 20, 0, 0, 0, w, h, new_color_model, -1);
675
676 // Can't use shared data for theme since button constructions overlay the
677 // images directly.
678                 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
679                 memcpy(get_data(), data + 16, w * h * components);
680
681         }
682         else if(data[0] == 0x89 && data[1] == 'P' && data[2] == 'N' && data[3] == 'G') {
683                 int have_alpha = 0;
684                 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
685                 png_infop info_ptr = png_create_info_struct(png_ptr);
686                 int new_color_model;
687
688                 image_offset = 0;
689                 image = data;  image_size = img_sz;
690                 png_set_read_fn(png_ptr, this, PngReadFunction::png_read_function);
691                 png_read_info(png_ptr, info_ptr);
692
693                 w = png_get_image_width(png_ptr, info_ptr);
694                 h = png_get_image_height(png_ptr, info_ptr);
695
696                 int src_color_model = png_get_color_type(png_ptr, info_ptr);
697
698                 /* tell libpng to strip 16 bit/color files down to 8 bits/color */
699                 png_set_strip_16(png_ptr);
700
701                 /* extract multiple pixels with bit depths of 1, 2, and 4 from a single
702                  * byte into separate bytes (useful for paletted and grayscale images).
703                  */
704                 png_set_packing(png_ptr);
705
706                 /* expand paletted colors into true RGB triplets */
707                 if (src_color_model == PNG_COLOR_TYPE_PALETTE)
708                         png_set_expand(png_ptr);
709
710                 /* expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
711                 if (src_color_model == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8)
712                         png_set_expand(png_ptr);
713
714                 if (src_color_model == PNG_COLOR_TYPE_GRAY ||
715                     src_color_model == PNG_COLOR_TYPE_GRAY_ALPHA)
716                         png_set_gray_to_rgb(png_ptr);
717
718                 /* expand paletted or RGB images with transparency to full alpha channels
719                  * so the data will be available as RGBA quartets */
720                 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)){
721                         have_alpha = 1;
722                         png_set_expand(png_ptr);
723                 }
724
725                 switch(src_color_model)
726                 {
727                         case PNG_COLOR_TYPE_GRAY:
728                         case PNG_COLOR_TYPE_RGB:
729                                 new_color_model = BC_RGB888;
730                                 break;
731
732                         case PNG_COLOR_TYPE_GRAY_ALPHA:
733                         case PNG_COLOR_TYPE_RGB_ALPHA:
734                         default:
735                                 new_color_model = BC_RGBA8888;
736                                 break;
737
738                         case PNG_COLOR_TYPE_PALETTE:
739                                 if(have_alpha)
740                                         new_color_model = BC_RGBA8888;
741                                 else
742                                         new_color_model = BC_RGB888;
743                 }
744
745                 reallocate(NULL, -1, 0, 0, 0, w, h, new_color_model, -1);
746
747 //printf("VFrame::read_png %d %d %d %p\n", __LINE__, w, h, get_rows());
748                 png_read_image(png_ptr, get_rows());
749                 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
750         }
751         else {
752                 printf("VFrame::read_png %d: unknown file format"
753                         " 0x%02x 0x%02x 0x%02x 0x%02x\n",
754                         __LINE__, data[4], data[5], data[6], data[7]);
755         }
756         return 0;
757 }
758
759 int VFrame::read_png(const unsigned char *data)
760 {
761         long img_sz =
762                 ((long)data[0] << 24) | ((long)data[1] << 16) |
763                 ((long)data[2] << 8)  |  (long)data[3];
764         return read_png(data+4, img_sz);
765 }
766
767 int VFrame::write_png(const char *path)
768 {
769         png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
770         png_infop info_ptr = png_create_info_struct(png_ptr);
771         FILE *out_fd = fopen(path, "w");
772         if(!out_fd)
773         {
774                 printf("VFrame::write_png %d %s %s\n", __LINE__, path, strerror(errno));
775                 return 1;
776         }
777
778         int png_cmodel = PNG_COLOR_TYPE_RGB;
779         switch(get_color_model())
780         {
781                 case BC_RGB888:
782                 case BC_YUV888:
783                         png_cmodel = PNG_COLOR_TYPE_RGB;
784                         break;
785
786                 case BC_A8:
787                         png_cmodel = PNG_COLOR_TYPE_GRAY;
788                         break;
789         }
790
791         png_init_io(png_ptr, out_fd);
792         png_set_compression_level(png_ptr, 9);
793         png_set_IHDR(png_ptr,
794                 info_ptr,
795                 get_w(),
796                 get_h(),
797         8,
798                 png_cmodel,
799                 PNG_INTERLACE_NONE,
800                 PNG_COMPRESSION_TYPE_DEFAULT,
801                 PNG_FILTER_TYPE_DEFAULT);
802         png_write_info(png_ptr, info_ptr);
803         png_write_image(png_ptr, get_rows());
804         png_write_end(png_ptr, info_ptr);
805         png_destroy_write_struct(&png_ptr, &info_ptr);
806         fclose(out_fd);
807         return 0;
808 }
809
810
811 #define ZERO_YUV(components, type, max) \
812 { \
813         for(int i = 0; i < h; i++) \
814         { \
815                 type *row = (type*)get_rows()[i]; \
816                 for(int j = 0; j < w; j++) \
817                 { \
818                         row[j * components] = 0; \
819                         row[j * components + 1] = (max + 1) / 2; \
820                         row[j * components + 2] = (max + 1) / 2; \
821                         if(components == 4) row[j * components + 3] = 0; \
822                 } \
823         } \
824 }
825
826 int VFrame::clear_frame()
827 {
828         int sz = w * h;
829 //printf("VFrame::clear_frame %d\n", __LINE__);
830         switch(color_model) {
831         case BC_COMPRESSED:
832                 break;
833
834         case BC_YUV410P:
835                 bzero(get_y(), sz);
836                 bzero(get_u(), w / 4 * h / 4);
837                 bzero(get_v(), w / 4 * h / 4);
838                 break;
839
840         case BC_YUV411P:
841         case BC_YUV420P:
842                 bzero(get_y(), sz);
843                 bzero(get_u(), sz / 4);
844                 bzero(get_v(), sz / 4);
845                 break;
846
847         case BC_YUV422P:
848                 bzero(get_y(), sz);
849                 bzero(get_u(), sz / 2);
850                 bzero(get_v(), sz / 2);
851                 break;
852
853         case BC_RGBA_FLOATP: if( a ) {
854                 float *ap = (float *)a;
855                 for( int i=sz; --i>=0; ++ap ) *ap = 1.f; }
856         case BC_RGB_FLOATP: {
857                 float *rp = (float *)y;
858                 for( int i=sz; --i>=0; ++rp ) *rp = 0.f;
859                 float *gp = (float *)u;
860                 for( int i=sz; --i>=0; ++gp ) *gp = 0.f;
861                 float *bp = (float *)v;
862                 for( int i=sz; --i>=0; ++bp ) *bp = 0.f;
863                 break; }
864         case BC_YUV444P:
865                 bzero(get_y(), sz);
866                 bzero(get_u(), sz);
867                 bzero(get_v(), sz);
868                 break;
869
870         case BC_YUV888:
871                 ZERO_YUV(3, unsigned char, 0xff);
872                 break;
873
874         case BC_YUVA8888:
875                 ZERO_YUV(4, unsigned char, 0xff);
876                 break;
877
878         case BC_YUV161616:
879                 ZERO_YUV(3, uint16_t, 0xffff);
880                 break;
881
882         case BC_YUVA16161616:
883                 ZERO_YUV(4, uint16_t, 0xffff);
884                 break;
885
886         default:
887                 bzero(data, calculate_data_size(w, h, bytes_per_line, color_model));
888                 break;
889         }
890         return 0;
891 }
892
893 void VFrame::rotate90()
894 {
895 // Allocate new frame
896         int new_w = h, new_h = w, new_bytes_per_line = bytes_per_pixel * new_w;
897         unsigned char *new_data = new unsigned char[calculate_data_size(new_w, new_h, new_bytes_per_line, color_model)];
898         unsigned char **new_rows = new unsigned char*[new_h];
899         for(int i = 0; i < new_h; i++)
900                 new_rows[i] = &new_data[new_bytes_per_line * i];
901
902 // Copy data
903         for(int in_y = 0, out_x = new_w - 1; in_y < h; in_y++, out_x--)
904         {
905                 for(int in_x = 0, out_y = 0; in_x < w; in_x++, out_y++)
906                 {
907                         for(int k = 0; k < bytes_per_pixel; k++)
908                         {
909                                 new_rows[out_y][out_x * bytes_per_pixel + k] =
910                                         rows[in_y][in_x * bytes_per_pixel + k];
911                         }
912                 }
913         }
914
915 // Swap frames
916         clear_objects(0);
917         data = new_data;
918         rows = new_rows;
919         bytes_per_line = new_bytes_per_line;
920         w = new_w;
921         h = new_h;
922 }
923
924 void VFrame::rotate270()
925 {
926 // Allocate new frame
927         int new_w = h, new_h = w, new_bytes_per_line = bytes_per_pixel * new_w;
928         unsigned char *new_data = new unsigned char[calculate_data_size(new_w, new_h, new_bytes_per_line, color_model)];
929         unsigned char **new_rows = new unsigned char*[new_h];
930         for(int i = 0; i < new_h; i++)
931                 new_rows[i] = &new_data[new_bytes_per_line * i];
932
933 // Copy data
934         for(int in_y = 0, out_x = 0; in_y < h; in_y++, out_x++)
935         {
936                 for(int in_x = 0, out_y = new_h - 1; in_x < w; in_x++, out_y--)
937                 {
938                         for(int k = 0; k < bytes_per_pixel; k++)
939                         {
940                                 new_rows[out_y][out_x * bytes_per_pixel + k] =
941                                         rows[in_y][in_x * bytes_per_pixel + k];
942                         }
943                 }
944         }
945
946 // Swap frames
947         clear_objects(0);
948         data = new_data;
949         rows = new_rows;
950         bytes_per_line = new_bytes_per_line;
951         w = new_w;
952         h = new_h;
953 }
954
955 void VFrame::flip_vert()
956 {
957         unsigned char *temp = new unsigned char[bytes_per_line];
958         for(int i = 0, j = h - 1; i < j; i++, j--)
959         {
960                 memcpy(temp, rows[j], bytes_per_line);
961                 memcpy(rows[j], rows[i], bytes_per_line);
962                 memcpy(rows[i], temp, bytes_per_line);
963         }
964         delete [] temp;
965 }
966
967 void VFrame::flip_horiz()
968 {
969         unsigned char temp[32];
970         for(int i = 0; i < h; i++)
971         {
972                 unsigned char *row = rows[i];
973                 for(int j = 0; j < bytes_per_line / 2; j += bytes_per_pixel)
974                 {
975                         memcpy(temp, row + j, bytes_per_pixel);
976                         memcpy(row + j, row + bytes_per_line - j - bytes_per_pixel, bytes_per_pixel);
977                         memcpy(row + bytes_per_line - j - bytes_per_pixel, temp, bytes_per_pixel);
978                 }
979         }
980 }
981
982
983
984 int VFrame::copy_from(VFrame *frame)
985 {
986         int w = MIN(this->w, frame->get_w());
987         int h = MIN(this->h, frame->get_h());
988         timestamp = frame->timestamp;
989
990         switch(frame->color_model)
991         {
992                 case BC_COMPRESSED:
993                         allocate_compressed_data(frame->compressed_size);
994                         memcpy(data, frame->data, frame->compressed_size);
995                         this->compressed_size = frame->compressed_size;
996                         break;
997
998                 case BC_YUV410P:
999                         memcpy(get_y(), frame->get_y(), w * h);
1000                         memcpy(get_u(), frame->get_u(), w / 4 * h / 4);
1001                         memcpy(get_v(), frame->get_v(), w / 4 * h / 4);
1002                         break;
1003
1004                 case BC_YUV420P:
1005                 case BC_YUV411P:
1006 //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());
1007                         memcpy(get_y(), frame->get_y(), w * h);
1008                         memcpy(get_u(), frame->get_u(), w * h / 4);
1009                         memcpy(get_v(), frame->get_v(), w * h / 4);
1010                         break;
1011
1012                 case BC_YUV422P:
1013 //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());
1014                         memcpy(get_y(), frame->get_y(), w * h);
1015                         memcpy(get_u(), frame->get_u(), w * h / 2);
1016                         memcpy(get_v(), frame->get_v(), w * h / 2);
1017                         break;
1018
1019                 case BC_YUV444P:
1020 //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());
1021                         memcpy(get_y(), frame->get_y(), w * h);
1022                         memcpy(get_u(), frame->get_u(), w * h);
1023                         memcpy(get_v(), frame->get_v(), w * h);
1024                         break;
1025                 default:
1026 // printf("VFrame::copy_from %d\n", calculate_data_size(w,
1027 //                              h,
1028 //                              -1,
1029 //                              frame->color_model));
1030 // Copy without extra 4 bytes in case the source is a hardware device
1031                         memmove(data, frame->data, get_data_size());
1032                         break;
1033         }
1034
1035         return 0;
1036 }
1037
1038 int VFrame::transfer_from(VFrame *that, int bg_color)
1039 {
1040         if( this->get_color_model() == that->get_color_model() &&
1041             this->get_w() == that->get_w() && this->get_h() == that->get_h() )
1042                 return this->copy_from(that);
1043
1044         timestamp = that->timestamp;
1045         BC_CModels::transfer(
1046                 this->get_rows(), that->get_rows(),          // Packed data out/in
1047                 this->get_y(), this->get_u(), this->get_v(), // Planar data out/in
1048                 that->get_y(), that->get_u(), that->get_v(),
1049                 0, 0, that->get_w(), that->get_h(),          // Dimensions in/out
1050                 0, 0, this->get_w(), this->get_h(),
1051                 that->get_color_model(), this->get_color_model(), // Color models in/out
1052                 bg_color,                                    // alpha blend bg_color
1053                 that->get_w(), this->get_w());               // rowspans (of luma for YUV)
1054         return 0;
1055 }
1056
1057
1058
1059
1060
1061
1062 #define OVERLAY(type, max, components) \
1063 { \
1064         type **in_rows = (type**)src->get_rows(); \
1065         type **out_rows = (type**)get_rows(); \
1066         int in_w = src->get_w(); \
1067         int in_h = src->get_h(); \
1068  \
1069         for(int i = 0; i < in_h; i++) \
1070         { \
1071                 if(i + out_y1 >= 0 && i + out_y1 < h) \
1072                 { \
1073                         type *src_row = in_rows[i]; \
1074                         type *dst_row = out_rows[i + out_y1] + out_x1 * components; \
1075  \
1076                         for(int j = 0; j < in_w; j++) \
1077                         { \
1078                                 if(j + out_x1 >= 0 && j + out_x1 < w) \
1079                                 { \
1080                                         int opacity = src_row[3]; \
1081                                         int transparency = dst_row[3] * (max - src_row[3]) / max; \
1082                                         dst_row[0] = (transparency * dst_row[0] + opacity * src_row[0]) / max; \
1083                                         dst_row[1] = (transparency * dst_row[1] + opacity * src_row[1]) / max; \
1084                                         dst_row[2] = (transparency * dst_row[2] + opacity * src_row[2]) / max; \
1085                                         dst_row[3] = MAX(dst_row[3], src_row[3]); \
1086                                 } \
1087  \
1088                                 dst_row += components; \
1089                                 src_row += components; \
1090                         } \
1091                 } \
1092         } \
1093 }
1094
1095
1096 void VFrame::overlay(VFrame *src,
1097                 int out_x1,
1098                 int out_y1)
1099 {
1100         switch(get_color_model())
1101         {
1102                 case BC_RGBA8888:
1103                         OVERLAY(unsigned char, 0xff, 4);
1104                         break;
1105         }
1106 }
1107
1108
1109
1110 int VFrame::get_scale_tables(int *column_table, int *row_table,
1111                         int in_x1, int in_y1, int in_x2, int in_y2,
1112                         int out_x1, int out_y1, int out_x2, int out_y2)
1113 {
1114         int i;
1115         float w_in = in_x2 - in_x1;
1116         float h_in = in_y2 - in_y1;
1117         int w_out = out_x2 - out_x1;
1118         int h_out = out_y2 - out_y1;
1119
1120         float hscale = w_in / w_out;
1121         float vscale = h_in / h_out;
1122
1123         for(i = 0; i < w_out; i++)
1124         {
1125                 column_table[i] = (int)(hscale * i);
1126         }
1127
1128         for(i = 0; i < h_out; i++)
1129         {
1130                 row_table[i] = (int)(vscale * i) + in_y1;
1131         }
1132         return 0;
1133 }
1134
1135 void VFrame::push_prev_effect(const char *name)
1136 {
1137         char *ptr;
1138         prev_effects.append(ptr = new char[strlen(name) + 1]);
1139         strcpy(ptr, name);
1140         if(prev_effects.total > MAX_STACK_ELEMENTS) prev_effects.remove_object(0);
1141 }
1142
1143 void VFrame::pop_prev_effect()
1144 {
1145         if(prev_effects.total)
1146                 prev_effects.remove_object(prev_effects.last());
1147 }
1148
1149 void VFrame::push_next_effect(const char *name)
1150 {
1151         char *ptr;
1152         next_effects.append(ptr = new char[strlen(name) + 1]);
1153         strcpy(ptr, name);
1154         if(next_effects.total > MAX_STACK_ELEMENTS) next_effects.remove_object(0);
1155 }
1156
1157 void VFrame::pop_next_effect()
1158 {
1159         if(next_effects.total)
1160                 next_effects.remove_object(next_effects.last());
1161 }
1162
1163 const char* VFrame::get_next_effect(int number)
1164 {
1165         if(!next_effects.total) return "";
1166         else
1167         if(number > next_effects.total - 1) number = next_effects.total - 1;
1168
1169         return next_effects.values[next_effects.total - number - 1];
1170 }
1171
1172 const char* VFrame::get_prev_effect(int number)
1173 {
1174         if(!prev_effects.total) return "";
1175         else
1176         if(number > prev_effects.total - 1) number = prev_effects.total - 1;
1177
1178         return prev_effects.values[prev_effects.total - number - 1];
1179 }
1180
1181 BC_Hash* VFrame::get_params()
1182 {
1183         return params;
1184 }
1185
1186 void VFrame::clear_stacks()
1187 {
1188         next_effects.remove_all_objects();
1189         prev_effects.remove_all_objects();
1190         delete params;
1191         params = new BC_Hash;
1192 }
1193
1194 void VFrame::copy_params(VFrame *src)
1195 {
1196         params->copy_from(src->params);
1197 }
1198
1199 void VFrame::copy_stacks(VFrame *src)
1200 {
1201         clear_stacks();
1202
1203         for(int i = 0; i < src->next_effects.total; i++)
1204         {
1205                 char *ptr;
1206                 next_effects.append(ptr = new char[strlen(src->next_effects.values[i]) + 1]);
1207                 strcpy(ptr, src->next_effects.values[i]);
1208         }
1209         for(int i = 0; i < src->prev_effects.total; i++)
1210         {
1211                 char *ptr;
1212                 prev_effects.append(ptr = new char[strlen(src->prev_effects.values[i]) + 1]);
1213                 strcpy(ptr, src->prev_effects.values[i]);
1214         }
1215
1216         params->copy_from(src->params);
1217 }
1218
1219 int VFrame::equal_stacks(VFrame *src)
1220 {
1221         for(int i = 0; i < src->next_effects.total && i < next_effects.total; i++)
1222         {
1223                 if(strcmp(src->next_effects.values[i], next_effects.values[i])) return 0;
1224         }
1225
1226         for(int i = 0; i < src->prev_effects.total && i < prev_effects.total; i++)
1227         {
1228                 if(strcmp(src->prev_effects.values[i], prev_effects.values[i])) return 0;
1229         }
1230
1231         if(!params->equivalent(src->params)) return 0;
1232         return 1;
1233 }
1234
1235 void VFrame::dump_stacks()
1236 {
1237         printf("VFrame::dump_stacks\n");
1238         printf("        next_effects:\n");
1239         for(int i = next_effects.total - 1; i >= 0; i--)
1240                 printf("                %s\n", next_effects.values[i]);
1241         printf("        prev_effects:\n");
1242         for(int i = prev_effects.total - 1; i >= 0; i--)
1243                 printf("                %s\n", prev_effects.values[i]);
1244 }
1245
1246 void VFrame::dump_params()
1247 {
1248         params->dump();
1249 }
1250
1251 void VFrame::dump()
1252 {
1253         printf("VFrame::dump %d this=%p\n", __LINE__, this);
1254         printf("    w=%d h=%d colormodel=%d rows=%p use_shm=%d shmid=%d\n",
1255                 w, h, color_model, rows, use_shm, shmid);
1256 }
1257
1258 int VFrame::filefork_size()
1259 {
1260         return sizeof(int) * 12 + sizeof(long);
1261 }
1262
1263
1264 void VFrame::to_filefork(unsigned char *buffer)
1265 {
1266         *(int*)(buffer + 0) = shmid;
1267         *(int*)(buffer + 4) = y_offset;
1268         *(int*)(buffer + 8) = u_offset;
1269         *(int*)(buffer + 12) = v_offset;
1270         *(int*)(buffer + 16) = w;
1271         *(int*)(buffer + 20) = h;
1272         *(int*)(buffer + 24) = color_model;
1273         *(int*)(buffer + 28) = bytes_per_line;
1274         *(int*)(buffer + 32) = compressed_allocated;
1275         *(int*)(buffer + 36) = compressed_size;
1276         *(int*)(buffer + 40) = is_keyframe;
1277         *(long*)(buffer + 44) = sequence_number;
1278
1279
1280 //printf("VFrame::to_filefork %d %lld\n", __LINE__, sequence_number);
1281 // printf("VFrame::to_filefork %d", __LINE__);
1282 // for(int i = 0; i < 40; i++)
1283 // {
1284 // printf(" %02x", buffer[i]);
1285 // }
1286 // printf("\n");
1287 // dump();
1288 }
1289
1290
1291 void VFrame::from_filefork(unsigned char *buffer)
1292 {
1293 // This frame will always be preallocated shared memory
1294 //printf("VFrame::from_filefork %d %d\n", __LINE__, *(int*)(buffer + 24));
1295         if(*(int*)(buffer + 24) == BC_COMPRESSED)
1296         {
1297                 set_compressed_memory(0,
1298                         *(int*)(buffer + 0), // shmid
1299                         *(int*)(buffer + 36), // compressed_size
1300                         *(int*)(buffer + 32)); // compressed_allocated
1301                 color_model = BC_COMPRESSED;
1302 //printf("VFrame::from_filefork %d %d\n", __LINE__, get_compressed_size());
1303
1304         }
1305         else
1306         {
1307 // printf("VFrame::from_filefork %d", __LINE__);
1308 // for(int i = 0; i < 40; i++)
1309 // {
1310 // printf(" %02x", buffer[i]);
1311 // }
1312 // printf("\n");
1313                 reallocate(0,
1314                         *(int*)(buffer + 0), // shmid
1315                         *(int*)(buffer + 4), // y_offset
1316                         *(int*)(buffer + 8), // u_offset
1317                         *(int*)(buffer + 12), // v_offset
1318                         *(int*)(buffer + 16), // w
1319                         *(int*)(buffer + 20), // h
1320                         *(int*)(buffer + 24), // colormodel
1321                         *(int*)(buffer + 28)); // bytes per line
1322 //dump();
1323         }
1324
1325         is_keyframe = *(int*)(buffer + 40);
1326         sequence_number = *(long*)(buffer + 44);
1327 //printf("VFrame::from_filefork %d %lld\n", __LINE__, sequence_number);
1328 }
1329
1330 int VFrame::get_memory_usage()
1331 {
1332         if(get_compressed_allocated()) return get_compressed_allocated();
1333         return get_h() * get_bytes_per_line();
1334 }
1335
1336
1337
1338
1339