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