sketcher add alpha/fill, add alpha to vframe draw_pixel, crikey tweaks
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / filelist.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2012 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 "asset.h"
23 #include "bcsignals.h"
24 #include "cstrdup.h"
25 #include "file.h"
26 #include "filelist.h"
27 #include "guicast.h"
28 #include "interlacemodes.h"
29 #include "mutex.h"
30 #include "mwindow.inc"
31 #include "render.h"
32 #include "renderfarmfsserver.inc"
33 #include "vframe.h"
34 #include "mainerror.h"
35
36 #include <ctype.h>
37 #include <errno.h>
38 #include <fcntl.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43
44
45 FileList::FileList(Asset *asset,
46         File *file,
47         const char *list_prefix,
48         const char *file_extension,
49         int frame_type,
50         int list_type)
51  : FileBase(asset, file)
52 {
53         reset_parameters();
54         path_list.set_array_delete();
55         asset->video_data = 1;
56         this->list_prefix = list_prefix;
57         this->file_extension = file_extension;
58         this->frame_type = frame_type;
59         this->list_type = list_type;
60         table_lock = new Mutex("FileList::table_lock");
61 }
62
63 FileList::~FileList()
64 {
65         close_file();
66         delete table_lock;
67 }
68
69 int FileList::reset_parameters_derived()
70 {
71         data = 0;
72         writer = 0;
73         temp = 0;
74         first_number = 0;
75         return 0;
76 }
77
78 int FileList::open_file(int rd, int wr)
79 {
80         int result = 1;
81
82 // skip header for write
83         if(file->wr)
84         {
85                 int fd = open(asset->path, O_CREAT+O_TRUNC+O_RDWR, 0777);
86                 if( fd >= 0 ) {
87                         close(fd);
88                         result = 0;
89 // Frame files are created in write_frame and list index is created when
90 // file is closed.
91 // Look for the starting number in the path but ignore the starting character
92 // and total digits since these are used by the header.
93                         Render::get_starting_number(asset->path,
94                                 first_number, number_start, number_digits);
95                         path_list.remove_all_objects();
96                         writer = new FrameWriter(this,
97                         asset->format == list_type ? file->cpus : 1);
98                 }
99                 else
100                         eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
101         }
102         else
103         if(file->rd)
104         {
105 // Determine type of file.
106 // Header isn't used for background rendering, in which case everything known
107 // by the file encoder is known by the decoder.
108 //printf("FileList::open_file %d %d\n", __LINE__, asset->use_header);
109                 if(asset->use_header)
110                 {
111                         FILE *stream = fopen(asset->path, "rb");
112 //printf("FileList::open_file %d asset->path=%s\n", __LINE__, asset->path);
113                         if(stream)
114                         {
115                                 char string[BCTEXTLEN];
116                                 (void)fread(string, strlen(list_prefix), 1, stream);
117                                 fclose(stream);
118
119                                 if(!strncasecmp(string, list_prefix, strlen(list_prefix)))
120                                 {
121
122 //printf("FileList::open_file %d\n", __LINE__);
123                                         asset->format = list_type;
124
125 // Open index here or get frame size from file.
126                                         result = read_list_header();
127 //printf("FileList::open_file %d %s\n", __LINE__, path_list.values[0]);
128                                         if(!result) result = read_frame_header(path_list.values[0]);
129                                 }
130                                 else
131                                 {
132 //printf("FileList::open_file 2\n", asset->use_header);
133 //printf("FileList::open_file %d\n", __LINE__);
134                                         asset->format = frame_type;
135                                         int width = asset->width;
136                                         int height = asset->height;
137                                         result = read_frame_header(asset->path);
138                                         asset->actual_width = asset->width;
139                                         if( width ) asset->width = width;
140                                         asset->actual_height = asset->height;
141                                         if( height ) asset->height = height;
142                                         asset->layers = 1;
143                                         if( !asset->frame_rate )
144                                                 asset->frame_rate = 1;
145                                         asset->video_length = -1;
146                                 }
147                                 result = 0;
148                         }
149                         else
150                                 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
151                 }
152                 else
153                 {
154                         Render::get_starting_number(asset->path,
155                                 first_number, number_start, number_digits, 6);
156                         result = 0;
157                 }
158         }
159
160         file->current_frame = 0;
161 // Compressed data storage
162         data = new VFrame;
163
164         return result;
165 }
166
167
168 int FileList::close_file()
169 {
170 //      path_list.total, asset->format, list_type, wr);
171         if(asset->format == list_type && path_list.total)
172         {
173                 if(file->wr && asset->use_header) write_list_header();
174                 path_list.remove_all_objects();
175         }
176         if(data) delete data;
177         if(writer) delete writer;
178         if(temp) delete temp;
179         reset_parameters();
180
181         FileBase::close_file();
182         return 0;
183 }
184
185 int FileList::write_list_header()
186 {
187         FILE *stream = fopen(asset->path, "w");
188         if( !stream ) return 1;
189 // Use sprintf instead of fprintf for VFS.
190         fprintf(stream, "%s\n", list_prefix);
191         fprintf(stream, "# First line is always %s\n", list_prefix);
192         fprintf(stream, "# Frame rate:\n");
193         fprintf(stream, "%f\n", asset->frame_rate);
194         fprintf(stream, "# Width:\n");
195         fprintf(stream, "%d\n", asset->width);
196         fprintf(stream, "# Height:\n");
197         fprintf(stream, "%d\n", asset->height);
198         fprintf(stream, "# List of image files follows\n");
199
200         char *cp = strrchr(asset->path, '/');
201         int dir_len = !cp ? 0 : cp - asset->path;
202
203         for(int i = 0; i < path_list.total; i++) {
204                 const char *path = path_list.values[i];
205 // Fix path for VFS but leave leading slash
206                 if( !strncmp(path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)) )
207                         path += strlen(RENDERFARM_FS_PREFIX);
208 // ./path for relative list access
209                 else if( dir_len > 0 && !strncmp(path, asset->path, dir_len) ) {
210                         fprintf(stream, ".");  path += dir_len;
211                 }
212                 fprintf(stream, "%s\n", path);
213         }
214         fclose(stream);
215         return 0;
216 }
217
218 int FileList::read_list_header()
219 {
220         char string[BCTEXTLEN];
221
222         FILE *stream = fopen(asset->path, "r");
223         if( !stream ) return 1;
224 // Get information about the frames
225         do {
226                 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
227         } while(string[0] == '#' || string[0] == ' ' || isalpha(string[0]));
228
229 // Don't want a user configured frame rate to get destroyed
230         if(asset->frame_rate == 0)
231                 asset->frame_rate = atof(string);
232
233         do {
234                 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
235         } while(string[0] == '#' || string[0] == ' ');
236         if( (asset->width = atol(string)) <= 0 ) return 1;
237
238         do {
239                 if( feof(stream) || !fgets(string, BCTEXTLEN, stream) ) return 1;
240         } while(string[0] == '#' || string[0] == ' ');
241         if( (asset->height = atol(string)) <= 0 ) return 1;
242
243         asset->interlace_mode = ILACE_MODE_UNDETECTED;
244         asset->layers = 1;
245         asset->audio_data = 0;
246         asset->video_data = 1;
247
248         char prefix[BCTEXTLEN], *bp = prefix, *cp = strrchr(asset->path, '/');
249         for( int i=0, n=!cp ? 0 : cp-asset->path; i<n; ++i ) *bp++ = asset->path[i];
250         *bp = 0;
251
252 // Get all the paths, expand relative paths
253         int missing = 0;
254         while( !feof(stream) && fgets(string, BCTEXTLEN, stream) ) {
255                 int len = strlen(string);
256                 if( !len || string[0] == '#' || string[0] == ' ' ) continue;
257                 if( string[len-1] == '\n' ) string[len-1] = 0;
258                 char path[BCTEXTLEN], *pp = path, *ep = pp + sizeof(path)-1;
259                 if( string[0] == '.' && string[1] == '/' && prefix[0] )
260                         pp += snprintf(pp, ep-pp, "%s/", prefix);
261                 snprintf(pp, ep-pp, "%s", string);
262                 if( access(path, R_OK) && !missing++ )
263                         eprintf(_("%s:no such file"), path);
264                 path_list.append(cstrdup(path));
265         }
266
267 //for(int i = 0; i < path_list.total; i++) printf("%s\n", path_list.values[i]);
268         fclose(stream);
269         if( !(asset->video_length = path_list.total) )
270                 eprintf(_("%s:\nlist empty"), asset->path);
271         if( missing )
272                 eprintf(_("%s:\n%d files not found"), asset->path, missing);
273         return 0;
274 }
275
276 int FileList::read_frame(VFrame *frame)
277 {
278         int result = 0;
279
280 //      PRINT_TRACE
281 // printf("FileList::read_frame %d %d use_header=%d current_frame=%d total=%d\n",
282 // __LINE__,
283 // result,
284 // asset->use_header,
285 // file->current_frame,
286 // path_list.total);
287
288         if(file->current_frame < 0 ||
289                 (asset->use_header && file->current_frame >= path_list.total &&
290                         asset->format == list_type))
291                 return 1;
292
293         if(asset->format == list_type)
294         {
295                 char string[BCTEXTLEN];
296                 char *path;
297                 if(asset->use_header)
298                 {
299                         path = path_list.values[file->current_frame];
300                 }
301                 else
302                 {
303                         path = calculate_path(file->current_frame, string);
304                 }
305
306                 FILE *in;
307
308 // Fix path for VFS.  Not used anymore.
309                 if(!strncmp(asset->path, RENDERFARM_FS_PREFIX, strlen(RENDERFARM_FS_PREFIX)))
310                         sprintf(string, "%s%s", RENDERFARM_FS_PREFIX, path);
311                 else
312                         strcpy(string, path);
313
314
315
316                 if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
317                 {
318                         if(!(in = fopen(string, "rb"))) {
319                                 eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), string);
320                         }
321                         else
322                         {
323                                 struct stat ostat;
324                                 stat(string, &ostat);
325
326                                 switch(frame->get_color_model())
327                                 {
328                                         case BC_COMPRESSED:
329                                                 frame->allocate_compressed_data(ostat.st_size);
330                                                 frame->set_compressed_size(ostat.st_size);
331                                                 (void)fread(frame->get_data(), ostat.st_size, 1, in);
332                                                 break;
333                                         default:
334                                                 data->allocate_compressed_data(ostat.st_size);
335                                                 data->set_compressed_size(ostat.st_size);
336                                                 (void)fread(data->get_data(), ostat.st_size, 1, in);
337                                                 result = read_frame(frame, data);
338                                                 break;
339                                 }
340
341                                 fclose(in);
342                         }
343                 }
344                 else
345                 {
346 //printf("FileList::read_frame %d %s\n", __LINE__, string);
347                         result = read_frame(frame, string);
348                 }
349         }
350         else
351         {
352                 asset->single_frame = 1;
353 // Allocate and decompress single frame into new temporary
354 //printf("FileList::read_frame %d\n", frame->get_color_model());
355                 if(!temp || temp->get_color_model() != frame->get_color_model())
356                 {
357                         if(temp) delete temp;
358                         temp = 0;
359
360
361                         if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
362                         {
363                                 FILE *fd = fopen(asset->path, "rb");
364                                 if(fd)
365                                 {
366                                         struct stat ostat;
367                                         stat(asset->path, &ostat);
368
369                                         switch(frame->get_color_model())
370                                         {
371                                                 case BC_COMPRESSED:
372                                                         frame->allocate_compressed_data(ostat.st_size);
373                                                         frame->set_compressed_size(ostat.st_size);
374                                                         (void)fread(frame->get_data(), ostat.st_size, 1, fd);
375                                                         break;
376                                                 default:
377                                                         data->allocate_compressed_data(ostat.st_size);
378                                                         data->set_compressed_size(ostat.st_size);
379                                                         (void)fread(data->get_data(), ostat.st_size, 1, fd);
380                                                         temp = new VFrame(asset->actual_width, asset->actual_height,
381                                                                         frame->get_color_model(), 0);
382                                                         read_frame(temp, data);
383                                                         break;
384                                         }
385
386                                         fclose(fd);
387                                 }
388                                 else
389                                 {
390                                         eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
391                                         result = 1;
392                                 }
393                         }
394                         else
395                         {
396                                 temp = new VFrame(asset->actual_width, asset->actual_height,
397                                         frame->get_color_model(), 0);
398                                 read_frame(temp, asset->path);
399                         }
400                 }
401
402                 if(!temp) return result;
403
404 //printf("FileList::read_frame frame=%d temp=%d\n",
405 // frame->get_color_model(), // temp->get_color_model());
406                 frame->transfer_from(temp);
407         }
408
409
410 // printf("FileList::read_frame %d %d\n", __LINE__, result);
411 //
412 // if(frame->get_y())
413 // for(int i = 0; i < 100000; i++)
414 // {
415 //      frame->get_y()[i] = 0xff;
416 // }
417 // if(frame->get_rows())
418 // for(int i = 0; i < 100000; i++)
419 // {
420 //      frame->get_rows()[0][i] = 0xff;
421 // }
422
423
424         return result;
425 }
426
427 int FileList::write_frames(VFrame ***frames, int len)
428 {
429         return_value = 0;
430
431 //printf("FileList::write_frames 1\n");
432         if(frames[0][0]->get_color_model() == BC_COMPRESSED)
433         {
434                 for(int i = 0; i < asset->layers && !return_value; i++)
435                 {
436                         for(int j = 0; j < len && !return_value; j++)
437                         {
438                                 VFrame *frame = frames[i][j];
439                                 char *path = create_path(frame->get_number());
440 //printf("FileList::write_frames %d %jd\n", __LINE__, frame->get_number());
441
442
443                                 FILE *fd = fopen(path, "wb");
444                                 if(fd)
445                                 {
446                                         return_value = !fwrite(frames[i][j]->get_data(),
447                                                 frames[i][j]->get_compressed_size(),
448                                                 1,
449                                                 fd);
450
451                                         fclose(fd);
452                                 }
453                                 else
454                                 {
455                                         eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
456                                         return_value++;
457                                 }
458                         }
459                 }
460         }
461         else
462         {
463 //printf("FileList::write_frames 2\n");
464                 writer->write_frames(frames, len);
465 //printf("FileList::write_frames 100\n");
466         }
467         return return_value;
468 }
469
470
471
472
473
474
475
476
477
478 void FileList::add_return_value(int amount)
479 {
480         table_lock->lock("FileList::add_return_value");
481         return_value += amount;
482         table_lock->unlock();
483 }
484
485 char* FileList::calculate_path(int number, char *string)
486 {
487 // Synthesize filename.
488 // If a header is used, the filename number must be in a different location.
489         if(asset->use_header)
490         {
491                 int k;
492                 strcpy(string, asset->path);
493                 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
494                         ;
495                 if(k <= 0) k = strlen(string);
496
497                 sprintf(&string[k], "%06d%s",
498                         number,
499                         file_extension);
500         }
501         else
502 // Without a header, the original filename can be altered.
503         {
504                 Render::create_filename(string,
505                         asset->path,
506                         number,
507                         number_digits,
508                         number_start);
509         }
510
511         return string;
512 }
513
514 char* FileList::create_path(int number_override)
515 {
516         if(asset->format != list_type) return asset->path;
517
518         table_lock->lock("FileList::create_path");
519
520
521
522         char *path = 0;
523         char output[BCTEXTLEN];
524         if(file->current_frame >= path_list.total || !asset->use_header)
525         {
526                 int number;
527                 if(number_override < 0)
528                         number = file->current_frame++;
529                 else
530                 {
531                         number = number_override;
532                         file->current_frame++;
533                 }
534
535                 if(!asset->use_header)
536                 {
537                         number += first_number;
538                 }
539
540                 calculate_path(number, output);
541
542                 path = new char[strlen(output) + 1];
543                 strcpy(path, output);
544                 path_list.append(path);
545         }
546         else
547         {
548 // Overwrite an old path
549                 path = path_list.values[file->current_frame];
550         }
551
552
553         table_lock->unlock();
554
555         return path;
556 }
557
558 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
559 {
560         return new FrameWriterUnit(writer);
561 }
562
563 int64_t FileList::get_memory_usage()
564 {
565         int64_t result = 0;
566         if(data) result += data->get_compressed_allocated();
567         if(temp) result += temp->get_data_size();
568 // printf("FileList::get_memory_usage %d %p %s %jd\n",
569 // __LINE__,
570 // this,
571 // file->asset->path,
572 // result);
573         return result;
574 }
575
576 int FileList::get_units()
577 {
578         return !writer ? 0 : writer->get_total_clients();
579 }
580
581 FrameWriterUnit* FileList::get_unit(int number)
582 {
583         return !writer ? 0 : (FrameWriterUnit*)writer->get_client(number);
584 }
585
586 int FileList::use_path()
587 {
588         return 0;
589 }
590
591
592
593
594
595
596 FrameWriterPackage::FrameWriterPackage()
597 {
598 }
599
600 FrameWriterPackage::~FrameWriterPackage()
601 {
602 }
603
604
605
606
607
608
609
610
611
612
613
614 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
615  : LoadClient(server)
616 {
617 // Don't use server here since subclasses call this with no server.
618         this->server = server;
619         output = new VFrame;
620 }
621
622 FrameWriterUnit::~FrameWriterUnit()
623 {
624         delete output;
625 }
626
627 void FrameWriterUnit::process_package(LoadPackage *package)
628 {
629 //printf("FrameWriterUnit::process_package 1\n");
630         FrameWriterPackage *ptr = (FrameWriterPackage*)package;
631
632         FILE *file;
633
634 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
635         if(!(file = fopen(ptr->path, "wb")))
636         {
637                 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), ptr->path);
638                 return;
639         }
640 //printf("FrameWriterUnit::process_package 3");
641
642
643         int result = server->file->write_frame(ptr->input, output, this);
644
645 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
646         if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
647 //TRACE("FrameWriterUnit::process_package 4");
648         fclose(file);
649 //TRACE("FrameWriterUnit::process_package 5");
650
651         server->file->add_return_value(result);
652 //TRACE("FrameWriterUnit::process_package 6");
653 }
654
655
656
657
658
659
660
661
662
663
664
665 FrameWriter::FrameWriter(FileList *file, int cpus)
666  : LoadServer(cpus, 0)
667 {
668         this->file = file;
669 }
670
671
672 FrameWriter::~FrameWriter()
673 {
674 }
675
676 void FrameWriter::init_packages()
677 {
678         for(int i = 0, layer = 0, number = 0;
679                 i < get_total_packages();
680                 i++)
681         {
682                 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
683                 package->input = frames[layer][number];
684                 package->path = file->create_path(package->input->get_number());
685 // printf("FrameWriter::init_packages 1 %p %d %s\n",
686 // package->input,
687 // package->input->get_number(),
688 // package->path);
689                 number++;
690                 if(number >= len)
691                 {
692                         layer++;
693                         number = 0;
694                 }
695         }
696 }
697
698 void FrameWriter::write_frames(VFrame ***frames, int len)
699 {
700         this->frames = frames;
701         this->len = len;
702         set_package_count(len * file->asset->layers);
703
704         process_packages();
705 }
706
707 LoadClient* FrameWriter::new_client()
708 {
709         return file->new_writer_unit(this);
710 }
711
712 LoadPackage* FrameWriter::new_package()
713 {
714         return new FrameWriterPackage;
715 }
716
717
718