asset drag/drop to viewers, bluebanana bug, listbox fontlist highlight
[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 = 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                 asset->single_frame = 1;
343 // Allocate and decompress single frame into new temporary
344 //printf("FileList::read_frame %d\n", frame->get_color_model());
345                 if(!temp || temp->get_color_model() != frame->get_color_model())
346                 {
347                         if(temp) delete temp;
348                         temp = 0;
349
350
351                         if(!use_path() || frame->get_color_model() == BC_COMPRESSED)
352                         {
353                                 FILE *fd = fopen(asset->path, "rb");
354                                 if(fd)
355                                 {
356                                         struct stat ostat;
357                                         stat(asset->path, &ostat);
358
359                                         switch(frame->get_color_model())
360                                         {
361                                                 case BC_COMPRESSED:
362                                                         frame->allocate_compressed_data(ostat.st_size);
363                                                         frame->set_compressed_size(ostat.st_size);
364                                                         (void)fread(frame->get_data(), ostat.st_size, 1, fd);
365                                                         break;
366                                                 default:
367                                                         data->allocate_compressed_data(ostat.st_size);
368                                                         data->set_compressed_size(ostat.st_size);
369                                                         (void)fread(data->get_data(), ostat.st_size, 1, fd);
370                                                         temp = new VFrame(0,
371                                                                 -1,
372                                                                 asset->width,
373                                                                 asset->height,
374                                                                 frame->get_color_model(),
375                                                                 -1);
376                                                         read_frame(temp, data);
377                                                         break;
378                                         }
379
380                                         fclose(fd);
381                                 }
382                                 else
383                                 {
384                                         eprintf(_("Error while opening \"%s\" for reading. \n%m\n"), asset->path);
385                                         result = 1;
386                                 }
387                         }
388                         else
389                         {
390                                 temp = new VFrame(0,
391                                         -1,
392                                         asset->width,
393                                         asset->height,
394                                         frame->get_color_model(),
395                                         -1);
396                                 read_frame(temp, asset->path);
397                         }
398                 }
399
400                 if(!temp) return result;
401
402 // printf("FileList::read_frame frame=%d temp=%d\n",
403 // frame->get_color_model(),
404 // temp->get_color_model());
405                 if(frame->get_color_model() == temp->get_color_model())
406                 {
407                         frame->copy_from(temp);
408                 }
409                 else
410                 {
411 // Never happens
412                         BC_CModels::transfer(frame->get_rows(), /* Leave NULL if non existent */
413                                 temp->get_rows(),
414                                 frame->get_y(), /* Leave NULL if non existent */
415                                 frame->get_u(),
416                                 frame->get_v(),
417                                 temp->get_y(), /* Leave NULL if non existent */
418                                 temp->get_u(),
419                                 temp->get_v(),
420                                 0,        /* Dimensions to capture from input frame */
421                                 0,
422                                 asset->width,
423                                 asset->height,
424                                 0,       /* Dimensions to project on output frame */
425                                 0,
426                                 asset->width,
427                                 asset->height,
428                                 temp->get_color_model(),
429                                 frame->get_color_model(),
430                                 0,         /* When transfering BC_RGBA8888 to non-alpha this is the background color in 0xRRGGBB hex */
431                                 temp->get_w(),       /* For planar use the luma rowspan */
432                                 frame->get_w());
433                 }
434         }
435
436
437 // printf("FileList::read_frame %d %d\n", __LINE__, result);
438 //
439 // if(frame->get_y())
440 // for(int i = 0; i < 100000; i++)
441 // {
442 //      frame->get_y()[i] = 0xff;
443 // }
444 // if(frame->get_rows())
445 // for(int i = 0; i < 100000; i++)
446 // {
447 //      frame->get_rows()[0][i] = 0xff;
448 // }
449
450
451         return result;
452 }
453
454 int FileList::write_frames(VFrame ***frames, int len)
455 {
456         return_value = 0;
457
458 //printf("FileList::write_frames 1\n");
459         if(frames[0][0]->get_color_model() == BC_COMPRESSED)
460         {
461                 for(int i = 0; i < asset->layers && !return_value; i++)
462                 {
463                         for(int j = 0; j < len && !return_value; j++)
464                         {
465                                 VFrame *frame = frames[i][j];
466                                 char *path = create_path(frame->get_number());
467 //printf("FileList::write_frames %d %jd\n", __LINE__, frame->get_number());
468
469
470                                 FILE *fd = fopen(path, "wb");
471                                 if(fd)
472                                 {
473                                         return_value = !fwrite(frames[i][j]->get_data(),
474                                                 frames[i][j]->get_compressed_size(),
475                                                 1,
476                                                 fd);
477
478                                         fclose(fd);
479                                 }
480                                 else
481                                 {
482                                         eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), asset->path);
483                                         return_value++;
484                                 }
485                         }
486                 }
487         }
488         else
489         {
490 //printf("FileList::write_frames 2\n");
491                 writer->write_frames(frames, len);
492 //printf("FileList::write_frames 100\n");
493         }
494         return return_value;
495 }
496
497
498
499
500
501
502
503
504
505 void FileList::add_return_value(int amount)
506 {
507         table_lock->lock("FileList::add_return_value");
508         return_value += amount;
509         table_lock->unlock();
510 }
511
512 char* FileList::calculate_path(int number, char *string)
513 {
514 // Synthesize filename.
515 // If a header is used, the filename number must be in a different location.
516         if(asset->use_header)
517         {
518                 int k;
519                 strcpy(string, asset->path);
520                 for(k = strlen(string) - 1; k > 0 && string[k] != '.'; k--)
521                         ;
522                 if(k <= 0) k = strlen(string);
523
524                 sprintf(&string[k], "%06d%s",
525                         number,
526                         file_extension);
527         }
528         else
529 // Without a header, the original filename can be altered.
530         {
531                 Render::create_filename(string,
532                         asset->path,
533                         number,
534                         number_digits,
535                         number_start);
536         }
537
538         return string;
539 }
540
541 char* FileList::create_path(int number_override)
542 {
543         if(asset->format != list_type) return asset->path;
544
545         table_lock->lock("FileList::create_path");
546
547
548
549         char *path = 0;
550         char output[BCTEXTLEN];
551         if(file->current_frame >= path_list.total || !asset->use_header)
552         {
553                 int number;
554                 if(number_override < 0)
555                         number = file->current_frame++;
556                 else
557                 {
558                         number = number_override;
559                         file->current_frame++;
560                 }
561
562                 if(!asset->use_header)
563                 {
564                         number += first_number;
565                 }
566
567                 calculate_path(number, output);
568
569                 path = new char[strlen(output) + 1];
570                 strcpy(path, output);
571                 path_list.append(path);
572         }
573         else
574         {
575 // Overwrite an old path
576                 path = path_list.values[file->current_frame];
577         }
578
579
580         table_lock->unlock();
581
582         return path;
583 }
584
585 FrameWriterUnit* FileList::new_writer_unit(FrameWriter *writer)
586 {
587         return new FrameWriterUnit(writer);
588 }
589
590 int64_t FileList::get_memory_usage()
591 {
592         int64_t result = 0;
593         if(data) result += data->get_compressed_allocated();
594         if(temp) result += temp->get_data_size();
595 // printf("FileList::get_memory_usage %d %p %s %jd\n",
596 // __LINE__,
597 // this,
598 // file->asset->path,
599 // result);
600         return result;
601 }
602
603 int FileList::get_units()
604 {
605         return !writer ? 0 : writer->get_total_clients();
606 }
607
608 FrameWriterUnit* FileList::get_unit(int number)
609 {
610         return !writer ? 0 : (FrameWriterUnit*)writer->get_client(number);
611 }
612
613 int FileList::use_path()
614 {
615         return 0;
616 }
617
618
619
620
621
622
623 FrameWriterPackage::FrameWriterPackage()
624 {
625 }
626
627 FrameWriterPackage::~FrameWriterPackage()
628 {
629 }
630
631
632
633
634
635
636
637
638
639
640
641 FrameWriterUnit::FrameWriterUnit(FrameWriter *server)
642  : LoadClient(server)
643 {
644 // Don't use server here since subclasses call this with no server.
645         this->server = server;
646         output = new VFrame;
647 }
648
649 FrameWriterUnit::~FrameWriterUnit()
650 {
651         delete output;
652 }
653
654 void FrameWriterUnit::process_package(LoadPackage *package)
655 {
656 //printf("FrameWriterUnit::process_package 1\n");
657         FrameWriterPackage *ptr = (FrameWriterPackage*)package;
658
659         FILE *file;
660
661 //printf("FrameWriterUnit::process_package 2 %s\n", ptr->path);
662         if(!(file = fopen(ptr->path, "wb")))
663         {
664                 eprintf(_("Error while opening \"%s\" for writing. \n%m\n"), ptr->path);
665                 return;
666         }
667 //printf("FrameWriterUnit::process_package 3");
668
669
670         int result = server->file->write_frame(ptr->input, output, this);
671
672 //printf("FrameWriterUnit::process_package 4 %s %d\n", ptr->path, output->get_compressed_size());
673         if(!result) result = !fwrite(output->get_data(), output->get_compressed_size(), 1, file);
674 //TRACE("FrameWriterUnit::process_package 4");
675         fclose(file);
676 //TRACE("FrameWriterUnit::process_package 5");
677
678         server->file->add_return_value(result);
679 //TRACE("FrameWriterUnit::process_package 6");
680 }
681
682
683
684
685
686
687
688
689
690
691
692 FrameWriter::FrameWriter(FileList *file, int cpus)
693  : LoadServer(cpus, 0)
694 {
695         this->file = file;
696 }
697
698
699 FrameWriter::~FrameWriter()
700 {
701 }
702
703 void FrameWriter::init_packages()
704 {
705         for(int i = 0, layer = 0, number = 0;
706                 i < get_total_packages();
707                 i++)
708         {
709                 FrameWriterPackage *package = (FrameWriterPackage*)get_package(i);
710                 package->input = frames[layer][number];
711                 package->path = file->create_path(package->input->get_number());
712 // printf("FrameWriter::init_packages 1 %p %d %s\n",
713 // package->input,
714 // package->input->get_number(),
715 // package->path);
716                 number++;
717                 if(number >= len)
718                 {
719                         layer++;
720                         number = 0;
721                 }
722         }
723 }
724
725 void FrameWriter::write_frames(VFrame ***frames, int len)
726 {
727         this->frames = frames;
728         this->len = len;
729         set_package_count(len * file->asset->layers);
730
731         process_packages();
732 }
733
734 LoadClient* FrameWriter::new_client()
735 {
736         return file->new_writer_unit(this);
737 }
738
739 LoadPackage* FrameWriter::new_package()
740 {
741         return new FrameWriterPackage;
742 }
743
744
745